diff --git a/ethportal-api/src/beacon.rs b/ethportal-api/src/beacon.rs index 8e07b6a81..21ed130fc 100644 --- a/ethportal-api/src/beacon.rs +++ b/ethportal-api/src/beacon.rs @@ -1,11 +1,13 @@ use crate::{ types::{ - beacon::{ContentInfo, PaginateLocalContentInfo, TraceContentInfo}, content_key::beacon::BeaconContentKey, enr::Enr, - portal::{AcceptInfo, DataRadius, FindNodesInfo, PongInfo, TraceGossipInfo}, + portal::{ + AcceptInfo, ContentInfo, DataRadius, FindNodesInfo, PaginateLocalContentInfo, PongInfo, + TraceContentInfo, TraceGossipInfo, + }, }, - BeaconContentValue, RoutingTableInfo, + RawContentValue, RoutingTableInfo, }; use alloy_primitives::B256; use discv5::enr::NodeId; @@ -82,7 +84,7 @@ pub trait BeaconNetworkApi { &self, offset: u64, limit: u64, - ) -> RpcResult; + ) -> RpcResult>; /// Send the provided content value to interested peers. Clients may choose to send to some or /// all peers. Return the number of peers that the content was gossiped to. @@ -90,7 +92,7 @@ pub trait BeaconNetworkApi { async fn gossip( &self, content_key: BeaconContentKey, - content_value: BeaconContentValue, + content_value: RawContentValue, ) -> RpcResult; /// Send the provided content value to interested peers. Clients may choose to send to some or @@ -99,7 +101,7 @@ pub trait BeaconNetworkApi { async fn trace_gossip( &self, content_key: BeaconContentKey, - content_value: BeaconContentValue, + content_value: RawContentValue, ) -> RpcResult; /// Send an OFFER request with given ContentKey, to the designated peer and wait for a response. @@ -111,7 +113,7 @@ pub trait BeaconNetworkApi { &self, enr: Enr, content_key: BeaconContentKey, - content_value: BeaconContentValue, + content_value: RawContentValue, ) -> RpcResult; /// Send an OFFER request with given ContentKey, to the designated peer. @@ -123,7 +125,7 @@ pub trait BeaconNetworkApi { &self, enr: Enr, content_key: BeaconContentKey, - content_value: BeaconContentValue, + content_value: RawContentValue, ) -> RpcResult; /// Send an OFFER request with given ContentKeys, to the designated peer and wait for a @@ -142,10 +144,10 @@ pub trait BeaconNetworkApi { async fn store( &self, content_key: BeaconContentKey, - content_value: BeaconContentValue, + content_value: RawContentValue, ) -> RpcResult; /// Get a content from the local database #[method(name = "beaconLocalContent")] - async fn local_content(&self, content_key: BeaconContentKey) -> RpcResult; + async fn local_content(&self, content_key: BeaconContentKey) -> RpcResult; } diff --git a/ethportal-api/src/history.rs b/ethportal-api/src/history.rs index 50fe42915..43886612a 100644 --- a/ethportal-api/src/history.rs +++ b/ethportal-api/src/history.rs @@ -2,10 +2,12 @@ use crate::{ types::{ content_key::history::HistoryContentKey, enr::Enr, - history::{ContentInfo, PaginateLocalContentInfo, TraceContentInfo}, - portal::{AcceptInfo, DataRadius, FindNodesInfo, PongInfo, TraceGossipInfo}, + portal::{ + AcceptInfo, ContentInfo, DataRadius, FindNodesInfo, PaginateLocalContentInfo, PongInfo, + TraceContentInfo, TraceGossipInfo, + }, }, - HistoryContentValue, RoutingTableInfo, + RawContentValue, RoutingTableInfo, }; use discv5::enr::NodeId; use jsonrpsee::{core::RpcResult, proc_macros::rpc}; @@ -78,7 +80,7 @@ pub trait HistoryNetworkApi { &self, offset: u64, limit: u64, - ) -> RpcResult; + ) -> RpcResult>; /// Send the provided content value to interested peers. Clients may choose to send to some or /// all peers. Return the number of peers that the content was gossiped to. @@ -86,7 +88,7 @@ pub trait HistoryNetworkApi { async fn gossip( &self, content_key: HistoryContentKey, - content_value: HistoryContentValue, + content_value: RawContentValue, ) -> RpcResult; /// Send the provided content value to interested peers. Clients may choose to send to some or @@ -95,7 +97,7 @@ pub trait HistoryNetworkApi { async fn trace_gossip( &self, content_key: HistoryContentKey, - content_value: HistoryContentValue, + content_value: RawContentValue, ) -> RpcResult; /// Send an OFFER request with given ContentKey, to the designated peer and wait for a response. @@ -107,7 +109,7 @@ pub trait HistoryNetworkApi { &self, enr: Enr, content_key: HistoryContentKey, - content_value: HistoryContentValue, + content_value: RawContentValue, ) -> RpcResult; /// Send an OFFER request with given ContentKey, to the designated peer. @@ -119,7 +121,7 @@ pub trait HistoryNetworkApi { &self, enr: Enr, content_key: HistoryContentKey, - content_value: HistoryContentValue, + content_value: RawContentValue, ) -> RpcResult; /// Send an OFFER request with given ContentKeys, to the designated peer and wait for a @@ -138,11 +140,10 @@ pub trait HistoryNetworkApi { async fn store( &self, content_key: HistoryContentKey, - content_value: HistoryContentValue, + content_value: RawContentValue, ) -> RpcResult; /// Get a content value from the local database #[method(name = "historyLocalContent")] - async fn local_content(&self, content_key: HistoryContentKey) - -> RpcResult; + async fn local_content(&self, content_key: HistoryContentKey) -> RpcResult; } diff --git a/ethportal-api/src/lib.rs b/ethportal-api/src/lib.rs index 827a02ee9..f44356813 100644 --- a/ethportal-api/src/lib.rs +++ b/ethportal-api/src/lib.rs @@ -12,43 +12,42 @@ mod dashboard; pub mod discv5; mod eth; mod history; -pub mod state; +mod state; #[cfg(test)] mod test_utils; pub mod types; pub mod utils; mod web3; -pub use crate::discv5::{Discv5ApiClient, Discv5ApiServer}; pub use beacon::{BeaconNetworkApiClient, BeaconNetworkApiServer}; +pub use discv5::{Discv5ApiClient, Discv5ApiServer}; pub use eth::{EthApiClient, EthApiServer}; pub use history::{HistoryNetworkApiClient, HistoryNetworkApiServer}; pub use state::{StateNetworkApiClient, StateNetworkApiServer}; pub use web3::{Web3ApiClient, Web3ApiServer}; -pub use types::content_key::{ - beacon::{BeaconContentKey, LightClientBootstrapKey, LightClientUpdatesByRangeKey}, - error::ContentKeyError, - history::{ - BlockBodyKey, BlockHeaderKey, BlockReceiptsKey, EpochAccumulatorKey, HistoryContentKey, - RawContentKey, - }, - overlay::{IdentityContentKey, OverlayContentKey}, - state::StateContentKey, -}; - pub use types::{ consensus, consensus::light_client, + content_key::{ + beacon::{BeaconContentKey, LightClientBootstrapKey, LightClientUpdatesByRangeKey}, + error::ContentKeyError, + history::{ + BlockBodyKey, BlockHeaderKey, BlockReceiptsKey, EpochAccumulatorKey, HistoryContentKey, + }, + overlay::{IdentityContentKey, OverlayContentKey}, + state::StateContentKey, + }, content_value::{ beacon::BeaconContentValue, error::ContentValueError, history::HistoryContentValue, - state::StateContentValue, + state::StateContentValue, ContentValue, }, + discv5::*, + enr::*, execution::{block_body::*, header::*, receipts::*}, + node_id::*, + portal::{RawContentKey, RawContentValue}, }; // Re-exports jsonrpsee crate pub use jsonrpsee; -pub use types::content_value::ContentValue; - -pub use types::{discv5::*, enr::*, node_id::*}; diff --git a/ethportal-api/src/state.rs b/ethportal-api/src/state.rs index 7943b41c3..1e38b4424 100644 --- a/ethportal-api/src/state.rs +++ b/ethportal-api/src/state.rs @@ -2,10 +2,12 @@ use crate::{ types::{ content_key::state::StateContentKey, enr::Enr, - portal::{AcceptInfo, DataRadius, FindNodesInfo, PongInfo, TraceGossipInfo}, - state::{ContentInfo, PaginateLocalContentInfo, TraceContentInfo}, + portal::{ + AcceptInfo, ContentInfo, DataRadius, FindNodesInfo, PaginateLocalContentInfo, PongInfo, + TraceContentInfo, TraceGossipInfo, + }, }, - RoutingTableInfo, StateContentValue, + RawContentValue, RoutingTableInfo, }; use discv5::enr::NodeId; use jsonrpsee::{core::RpcResult, proc_macros::rpc}; @@ -71,7 +73,7 @@ pub trait StateNetworkApi { &self, offset: u64, limit: u64, - ) -> RpcResult; + ) -> RpcResult>; /// Send the provided content value to interested peers. Clients may choose to send to some or /// all peers. Return the number of peers that the content was gossiped to. @@ -79,7 +81,7 @@ pub trait StateNetworkApi { async fn gossip( &self, content_key: StateContentKey, - content_value: StateContentValue, + content_value: RawContentValue, ) -> RpcResult; /// Send the provided content value to interested peers. Clients may choose to send to some or @@ -88,7 +90,7 @@ pub trait StateNetworkApi { async fn trace_gossip( &self, content_key: StateContentKey, - content_value: StateContentValue, + content_value: RawContentValue, ) -> RpcResult; /// Send an OFFER request with given ContentKey, to the designated peer and wait for a response. @@ -100,7 +102,7 @@ pub trait StateNetworkApi { &self, enr: Enr, content_key: StateContentKey, - content_value: StateContentValue, + content_value: RawContentValue, ) -> RpcResult; /// Send an OFFER request with given ContentKey, to the designated peer. @@ -112,7 +114,7 @@ pub trait StateNetworkApi { &self, enr: Enr, content_key: StateContentKey, - content_value: StateContentValue, + content_value: RawContentValue, ) -> RpcResult; /// Store content key with a content data to the local database. @@ -120,10 +122,10 @@ pub trait StateNetworkApi { async fn store( &self, content_key: StateContentKey, - content_value: StateContentValue, + content_value: RawContentValue, ) -> RpcResult; /// Get a content from the local database #[method(name = "stateLocalContent")] - async fn local_content(&self, content_key: StateContentKey) -> RpcResult; + async fn local_content(&self, content_key: StateContentKey) -> RpcResult; } diff --git a/ethportal-api/src/types/beacon.rs b/ethportal-api/src/types/beacon.rs deleted file mode 100644 index 07cec7fe5..000000000 --- a/ethportal-api/src/types/beacon.rs +++ /dev/null @@ -1,39 +0,0 @@ -use super::query_trace::QueryTrace; -use crate::{types::enr::Enr, BeaconContentKey, BeaconContentValue}; -use serde::{Deserialize, Serialize}; - -/// Response for FindContent & RecursiveFindContent endpoints -#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] -#[serde(untagged)] -#[allow(clippy::large_enum_variant)] -pub enum ContentInfo { - #[serde(rename_all = "camelCase")] - ConnectionId { connection_id: u16 }, - #[serde(rename_all = "camelCase")] - Content { - content: BeaconContentValue, - utp_transfer: bool, - }, - #[serde(rename_all = "camelCase")] - Enrs { enrs: Vec }, -} - -/// Parsed response for TraceRecursiveFindContent endpoint -/// -/// This struct represents the content info, and is only used -/// when the content is found locally or on the network. -#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct TraceContentInfo { - pub content: BeaconContentValue, - pub utp_transfer: bool, - pub trace: QueryTrace, -} - -/// Response for PaginateLocalContentKeys endpoint -#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct PaginateLocalContentInfo { - pub content_keys: Vec, - pub total_entries: u64, -} diff --git a/ethportal-api/src/types/content_key/history.rs b/ethportal-api/src/types/content_key/history.rs index c5d985f5b..7658e0d35 100644 --- a/ethportal-api/src/types/content_key/history.rs +++ b/ethportal-api/src/types/content_key/history.rs @@ -18,9 +18,6 @@ pub const HISTORY_BLOCK_BODY_KEY_PREFIX: u8 = 0x01; pub const HISTORY_BLOCK_RECEIPTS_KEY_PREFIX: u8 = 0x02; pub const HISTORY_BLOCK_EPOCH_ACCUMULATOR_KEY_PREFIX: u8 = 0x03; -/// SSZ encoded overlay content key as bytes -pub type RawContentKey = Vec; - /// A content key in the history overlay network. #[derive(Clone, Debug, Eq, PartialEq)] pub enum HistoryContentKey { diff --git a/ethportal-api/src/types/content_value/beacon.rs b/ethportal-api/src/types/content_value/beacon.rs index 4db506c81..302098b6a 100644 --- a/ethportal-api/src/types/content_value/beacon.rs +++ b/ethportal-api/src/types/content_value/beacon.rs @@ -4,6 +4,7 @@ use crate::{ optimistic_update::LightClientOptimisticUpdateDeneb, update::LightClientUpdateDeneb, }, types::{ + cli::BEACON_NETWORK, consensus::{ fork::{ForkDigest, ForkName}, historical_summaries::HistoricalSummariesWithProof, @@ -26,9 +27,9 @@ use crate::{ content_value::ContentValue, }, utils::bytes::hex_encode, - ContentValueError, + BeaconContentKey, ContentValueError, RawContentValue, }; -use serde::{Deserialize, Deserializer, Serialize, Serializer}; +use serde::{Serialize, Serializer}; use ssz::{Decode, DecodeError, Encode}; use ssz_types::{typenum::U128, VariableList}; use std::ops::Deref; @@ -496,83 +497,77 @@ pub enum BeaconContentValue { } impl ContentValue for BeaconContentValue { - fn encode(&self) -> Vec { + type TContentKey = BeaconContentKey; + + fn encode(&self) -> RawContentValue { match self { - Self::HistoricalSummariesWithProof(value) => value.as_ssz_bytes(), - Self::LightClientBootstrap(value) => value.as_ssz_bytes(), - Self::LightClientUpdatesByRange(value) => value.as_ssz_bytes(), - Self::LightClientOptimisticUpdate(value) => value.as_ssz_bytes(), - Self::LightClientFinalityUpdate(value) => value.as_ssz_bytes(), + Self::HistoricalSummariesWithProof(value) => value.as_ssz_bytes().into(), + Self::LightClientBootstrap(value) => value.as_ssz_bytes().into(), + Self::LightClientUpdatesByRange(value) => value.as_ssz_bytes().into(), + Self::LightClientOptimisticUpdate(value) => value.as_ssz_bytes().into(), + Self::LightClientFinalityUpdate(value) => value.as_ssz_bytes().into(), } } - fn decode(buf: &[u8]) -> Result { - if let Ok(value) = ForkVersionedHistoricalSummariesWithProof::from_ssz_bytes(buf) { - return Ok(Self::HistoricalSummariesWithProof(value)); - } - if let Ok(value) = ForkVersionedLightClientBootstrap::from_ssz_bytes(buf) { - return Ok(Self::LightClientBootstrap(value)); - } - if let Ok(value) = LightClientUpdatesByRange::from_ssz_bytes(buf) { - return Ok(Self::LightClientUpdatesByRange(value)); - } - if let Ok(value) = ForkVersionedLightClientOptimisticUpdate::from_ssz_bytes(buf) { - return Ok(Self::LightClientOptimisticUpdate(value)); - } - if let Ok(value) = ForkVersionedLightClientFinalityUpdate::from_ssz_bytes(buf) { - return Ok(Self::LightClientFinalityUpdate(value)); + fn decode(key: &Self::TContentKey, buf: &[u8]) -> Result { + match key { + BeaconContentKey::LightClientBootstrap(_) => { + if let Ok(value) = ForkVersionedLightClientBootstrap::from_ssz_bytes(buf) { + return Ok(Self::LightClientBootstrap(value)); + } + } + BeaconContentKey::LightClientUpdatesByRange(_) => { + if let Ok(value) = LightClientUpdatesByRange::from_ssz_bytes(buf) { + return Ok(Self::LightClientUpdatesByRange(value)); + } + } + BeaconContentKey::LightClientFinalityUpdate(_) => { + if let Ok(value) = ForkVersionedLightClientFinalityUpdate::from_ssz_bytes(buf) { + return Ok(Self::LightClientFinalityUpdate(value)); + } + } + BeaconContentKey::LightClientOptimisticUpdate(_) => { + if let Ok(value) = ForkVersionedLightClientOptimisticUpdate::from_ssz_bytes(buf) { + return Ok(Self::LightClientOptimisticUpdate(value)); + } + } + BeaconContentKey::HistoricalSummariesWithProof(_) => { + if let Ok(value) = ForkVersionedHistoricalSummariesWithProof::from_ssz_bytes(buf) { + return Ok(Self::HistoricalSummariesWithProof(value)); + } + } } - Err(ContentValueError::UnknownContent { bytes: hex_encode(buf), - network: "beacon".to_string(), + network: BEACON_NETWORK.to_string(), }) } } -impl Serialize for BeaconContentValue { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - serializer.serialize_str(&self.to_hex()) - } -} - -impl<'de> Deserialize<'de> for BeaconContentValue { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - let s = String::deserialize(deserializer)?; - Self::from_hex(&s).map_err(serde::de::Error::custom) - } -} - #[cfg(test)] mod test { - use crate::{ - consensus::fork::ForkName, utils::bytes::hex_decode, BeaconContentValue, ContentValue, - }; - use serde_json::Value; use std::fs; + use serde::Deserialize; + + use super::*; + #[test] fn light_client_bootstrap_encode_decode() { let file = fs::read_to_string( "../test_assets/portalnet/content/beacon/light_client_bootstrap.json", ) .unwrap(); - let json: Value = serde_json::from_str(&file).unwrap(); + let json: serde_json::Value = serde_json::from_str(&file).unwrap(); let json = json.as_object().unwrap(); for (slot_num, obj) in json { let slot_num: u64 = slot_num.parse().unwrap(); - let content_hexstr = obj.get("content_value").unwrap().as_str().unwrap(); - let content_bytes = hex_decode(content_hexstr).unwrap(); - let beacon_content = BeaconContentValue::decode(&content_bytes).unwrap(); + let content_key = BeaconContentKey::deserialize(&obj["content_key"]).unwrap(); + let content_bytes = RawContentValue::deserialize(&obj["content_value"]).unwrap(); + let beacon_content = BeaconContentValue::decode(&content_key, &content_bytes).unwrap(); - match beacon_content { - BeaconContentValue::LightClientBootstrap(ref value) => { + match &beacon_content { + BeaconContentValue::LightClientBootstrap(value) => { assert_eq!( slot_num, value.bootstrap.header_capella().unwrap().beacon.slot @@ -583,7 +578,7 @@ mod test { assert_eq!(content_bytes, beacon_content.encode()); - assert_possible_content_value_roundtrip(beacon_content); + assert_str_roundtrip(content_key, beacon_content); } } @@ -593,16 +588,16 @@ mod test { "../test_assets/portalnet/content/beacon/light_client_updates_by_range.json", ) .unwrap(); - let json: Value = serde_json::from_str(&file).unwrap(); + let json: serde_json::Value = serde_json::from_str(&file).unwrap(); let json = json.as_object().unwrap(); for (slot_num, obj) in json { let slot_num: u64 = slot_num.parse().unwrap(); - let content_hexstr = obj.get("content_value").unwrap().as_str().unwrap(); - let content_bytes = hex_decode(content_hexstr).unwrap(); - let beacon_content = BeaconContentValue::decode(&content_bytes).unwrap(); + let content_key = BeaconContentKey::deserialize(&obj["content_key"]).unwrap(); + let content_bytes = RawContentValue::deserialize(&obj["content_value"]).unwrap(); + let beacon_content = BeaconContentValue::decode(&content_key, &content_bytes).unwrap(); - match beacon_content { - BeaconContentValue::LightClientUpdatesByRange(ref updates) => { + match &beacon_content { + BeaconContentValue::LightClientUpdatesByRange(updates) => { assert_eq!( slot_num, updates[0] @@ -619,7 +614,7 @@ mod test { assert_eq!(content_bytes, beacon_content.encode()); - assert_possible_content_value_roundtrip(beacon_content); + assert_str_roundtrip(content_key, beacon_content); } } @@ -629,16 +624,16 @@ mod test { "../test_assets/portalnet/content/beacon/light_client_optimistic_update.json", ) .unwrap(); - let json: Value = serde_json::from_str(&file).unwrap(); + let json: serde_json::Value = serde_json::from_str(&file).unwrap(); let json = json.as_object().unwrap(); for (slot_num, obj) in json { let slot_num: u64 = slot_num.parse().unwrap(); - let content_hexstr = obj.get("content_value").unwrap().as_str().unwrap(); - let content_bytes = hex_decode(content_hexstr).unwrap(); - let beacon_content = BeaconContentValue::decode(&content_bytes).unwrap(); + let content_key = BeaconContentKey::deserialize(&obj["content_key"]).unwrap(); + let content_bytes = RawContentValue::deserialize(&obj["content_value"]).unwrap(); + let beacon_content = BeaconContentValue::decode(&content_key, &content_bytes).unwrap(); - match beacon_content { - BeaconContentValue::LightClientOptimisticUpdate(ref value) => { + match &beacon_content { + BeaconContentValue::LightClientOptimisticUpdate(value) => { assert_eq!( slot_num, value.update.attested_header_capella().unwrap().beacon.slot @@ -649,7 +644,7 @@ mod test { assert_eq!(content_bytes, beacon_content.encode()); - assert_possible_content_value_roundtrip(beacon_content); + assert_str_roundtrip(content_key, beacon_content); } } @@ -659,16 +654,16 @@ mod test { "../test_assets/portalnet/content/beacon/light_client_finality_update.json", ) .unwrap(); - let json: Value = serde_json::from_str(&file).unwrap(); + let json: serde_json::Value = serde_json::from_str(&file).unwrap(); let json = json.as_object().unwrap(); for (slot_num, obj) in json { let slot_num: u64 = slot_num.parse().unwrap(); - let content_hexstr = obj.get("content_value").unwrap().as_str().unwrap(); - let content_bytes = hex_decode(content_hexstr).unwrap(); - let beacon_content = BeaconContentValue::decode(&content_bytes).unwrap(); + let content_key = BeaconContentKey::deserialize(&obj["content_key"]).unwrap(); + let content_bytes = RawContentValue::deserialize(&obj["content_value"]).unwrap(); + let beacon_content = BeaconContentValue::decode(&content_key, &content_bytes).unwrap(); - match beacon_content { - BeaconContentValue::LightClientFinalityUpdate(ref value) => { + match &beacon_content { + BeaconContentValue::LightClientFinalityUpdate(value) => { assert_eq!( slot_num, value.update.attested_header_capella().unwrap().beacon.slot @@ -679,7 +674,7 @@ mod test { assert_eq!(content_bytes, beacon_content.encode()); - assert_possible_content_value_roundtrip(beacon_content); + assert_str_roundtrip(content_key, beacon_content); } } @@ -687,14 +682,13 @@ mod test { fn historical_summaries_with_proof_encode_decode() { let file = fs::read_to_string("./../portal-spec-tests/tests/mainnet/beacon_chain/historical_summaries_with_proof/deneb/historical_summaries_with_proof.yaml").unwrap(); let value: serde_yaml::Value = serde_yaml::from_str(&file).unwrap(); - let content_value = value.get("content_value").unwrap().as_str().unwrap(); - let historical_summaries_with_proof_bytes = hex_decode(content_value).unwrap(); - let historical_summaries_with_proof = - BeaconContentValue::decode(&historical_summaries_with_proof_bytes).unwrap(); - let expected_epoch = value.get("epoch").unwrap().as_u64().unwrap(); - - match historical_summaries_with_proof { - BeaconContentValue::HistoricalSummariesWithProof(ref content) => { + let content_key = BeaconContentKey::deserialize(&value["content_key"]).unwrap(); + let content_bytes = RawContentValue::deserialize(&value["content_value"]).unwrap(); + let beacon_content = BeaconContentValue::decode(&content_key, &content_bytes).unwrap(); + let expected_epoch = ::deserialize(&value["epoch"]).unwrap(); + + match &beacon_content { + BeaconContentValue::HistoricalSummariesWithProof(content) => { assert_eq!( expected_epoch, content.historical_summaries_with_proof.epoch @@ -704,16 +698,17 @@ mod test { _ => panic!("Invalid beacon content type!"), } - assert_eq!( - historical_summaries_with_proof_bytes, - historical_summaries_with_proof.encode() - ); - } + assert_eq!(content_bytes, beacon_content.encode()); - fn assert_possible_content_value_roundtrip(beacon_content: BeaconContentValue) { - let json_str = serde_json::to_string(&beacon_content).unwrap(); - let possible_content_value: BeaconContentValue = serde_json::from_str(&json_str).unwrap(); + assert_str_roundtrip(content_key, beacon_content); + } - assert_eq!(beacon_content, possible_content_value); + fn assert_str_roundtrip(content_key: BeaconContentKey, content_value: BeaconContentValue) { + let hex_str = content_value.to_hex(); + assert_eq!( + BeaconContentValue::from_hex(&content_key, &hex_str).unwrap(), + content_value, + "to_hex() + from_hex() doesn't match: {hex_str}" + ); } } diff --git a/ethportal-api/src/types/content_value/history.rs b/ethportal-api/src/types/content_value/history.rs index 3b5d4c5ad..2fd53b61a 100644 --- a/ethportal-api/src/types/content_value/history.rs +++ b/ethportal-api/src/types/content_value/history.rs @@ -1,12 +1,12 @@ use crate::{ types::{ + cli::HISTORY_NETWORK, content_value::ContentValue, execution::{accumulator::EpochAccumulator, header_with_proof::HeaderWithProof}, }, utils::bytes::hex_encode, - BlockBody, ContentValueError, Receipts, + BlockBody, ContentValueError, HistoryContentKey, RawContentValue, Receipts, }; -use serde::{Deserialize, Deserializer, Serialize, Serializer}; use ssz::{Decode, Encode}; /// A Portal History content value. @@ -20,57 +20,48 @@ pub enum HistoryContentValue { } impl ContentValue for HistoryContentValue { - fn encode(&self) -> Vec { + type TContentKey = HistoryContentKey; + + fn encode(&self) -> RawContentValue { match self { - Self::BlockHeaderWithProof(value) => value.as_ssz_bytes(), - Self::BlockBody(value) => value.as_ssz_bytes(), - Self::Receipts(value) => value.as_ssz_bytes(), - Self::EpochAccumulator(value) => value.as_ssz_bytes(), + Self::BlockHeaderWithProof(value) => value.as_ssz_bytes().into(), + Self::BlockBody(value) => value.as_ssz_bytes().into(), + Self::Receipts(value) => value.as_ssz_bytes().into(), + Self::EpochAccumulator(value) => value.as_ssz_bytes().into(), } } - fn decode(buf: &[u8]) -> Result { - if let Ok(value) = HeaderWithProof::from_ssz_bytes(buf) { - return Ok(Self::BlockHeaderWithProof(value)); - } - - if let Ok(value) = BlockBody::from_ssz_bytes(buf) { - return Ok(Self::BlockBody(value)); - } - - if let Ok(value) = Receipts::from_ssz_bytes(buf) { - return Ok(Self::Receipts(value)); + fn decode(key: &Self::TContentKey, buf: &[u8]) -> Result { + match key { + HistoryContentKey::BlockHeaderWithProof(_) => { + if let Ok(value) = HeaderWithProof::from_ssz_bytes(buf) { + return Ok(Self::BlockHeaderWithProof(value)); + } + } + HistoryContentKey::BlockBody(_) => { + if let Ok(value) = BlockBody::from_ssz_bytes(buf) { + return Ok(Self::BlockBody(value)); + } + } + HistoryContentKey::BlockReceipts(_) => { + if let Ok(value) = Receipts::from_ssz_bytes(buf) { + return Ok(Self::Receipts(value)); + } + } + HistoryContentKey::EpochAccumulator(_) => { + if let Ok(value) = EpochAccumulator::from_ssz_bytes(buf) { + return Ok(Self::EpochAccumulator(value)); + } + } } - if let Ok(value) = EpochAccumulator::from_ssz_bytes(buf) { - return Ok(Self::EpochAccumulator(value)); - } Err(ContentValueError::UnknownContent { bytes: hex_encode(buf), - network: "history".to_string(), + network: HISTORY_NETWORK.to_string(), }) } } -impl Serialize for HistoryContentValue { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - serializer.serialize_str(&self.to_hex()) - } -} - -impl<'de> Deserialize<'de> for HistoryContentValue { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - let s = String::deserialize(deserializer)?; - Self::from_hex(&s).map_err(serde::de::Error::custom) - } -} - #[cfg(test)] mod test { use super::*; @@ -115,8 +106,9 @@ mod test { #[test] fn content_value_deserialization_failure_displays_debuggable_data() { + let key = HistoryContentKey::random().unwrap(); let data = vec![1, 2, 3, 4, 5, 6, 7, 8, 9]; - let item_result = HistoryContentValue::decode(&data); + let item_result = HistoryContentValue::decode(&key, &data); let error = item_result.unwrap_err(); // Test the error Debug representation assert_eq!( diff --git a/ethportal-api/src/types/content_value/mod.rs b/ethportal-api/src/types/content_value/mod.rs index 7785340b2..5028edf93 100644 --- a/ethportal-api/src/types/content_value/mod.rs +++ b/ethportal-api/src/types/content_value/mod.rs @@ -1,6 +1,6 @@ use crate::{ utils::bytes::{hex_decode, hex_encode}, - ContentValueError, + ContentValueError, OverlayContentKey, RawContentValue, }; pub mod beacon; @@ -11,17 +11,20 @@ pub mod state; /// An encodable portal network content value. pub trait ContentValue: Sized { + /// The content key type associated with this content value. + type TContentKey: OverlayContentKey; + /// Encodes the content value into a byte vector. - fn encode(&self) -> Vec; + fn encode(&self) -> RawContentValue; /// Decodes `buf` into a content value. - fn decode(buf: &[u8]) -> Result; + fn decode(key: &Self::TContentKey, buf: &[u8]) -> Result; /// Encodes the content as "0x"-prefixed hex string. fn to_hex(&self) -> String { hex_encode(self.encode()) } /// Decodes the "0x"-prefixed hex string as a content value. - fn from_hex(data: &str) -> anyhow::Result { - Ok(Self::decode(&hex_decode(data)?)?) + fn from_hex(key: &Self::TContentKey, data: &str) -> anyhow::Result { + Ok(Self::decode(key, &hex_decode(data)?)?) } } diff --git a/ethportal-api/src/types/content_value/state.rs b/ethportal-api/src/types/content_value/state.rs index 593094f47..c340ce519 100644 --- a/ethportal-api/src/types/content_value/state.rs +++ b/ethportal-api/src/types/content_value/state.rs @@ -1,12 +1,14 @@ use alloy_primitives::B256; -use serde::{Deserialize, Serialize}; use ssz::{Decode, Encode}; use ssz_derive::{Decode, Encode}; use crate::{ - types::state_trie::{ByteCode, EncodedTrieNode, TrieProof}, + types::{ + cli::STATE_NETWORK, + state_trie::{ByteCode, EncodedTrieNode, TrieProof}, + }, utils::bytes::hex_encode, - ContentValue, ContentValueError, + ContentValue, ContentValueError, RawContentValue, StateContentKey, }; /// A Portal State content value. @@ -25,52 +27,49 @@ pub enum StateContentValue { } impl ContentValue for StateContentValue { - fn encode(&self) -> Vec { + type TContentKey = StateContentKey; + + fn encode(&self) -> RawContentValue { match self { - Self::TrieNode(value) => value.as_ssz_bytes(), - Self::AccountTrieNodeWithProof(value) => value.as_ssz_bytes(), - Self::ContractStorageTrieNodeWithProof(value) => value.as_ssz_bytes(), - Self::ContractBytecode(value) => value.as_ssz_bytes(), - Self::ContractBytecodeWithProof(value) => value.as_ssz_bytes(), + Self::TrieNode(value) => value.as_ssz_bytes().into(), + Self::AccountTrieNodeWithProof(value) => value.as_ssz_bytes().into(), + Self::ContractStorageTrieNodeWithProof(value) => value.as_ssz_bytes().into(), + Self::ContractBytecode(value) => value.as_ssz_bytes().into(), + Self::ContractBytecodeWithProof(value) => value.as_ssz_bytes().into(), } } - fn decode(buf: &[u8]) -> Result { - if let Ok(value) = TrieNode::from_ssz_bytes(buf) { - Ok(Self::TrieNode(value)) - } else if let Ok(value) = AccountTrieNodeWithProof::from_ssz_bytes(buf) { - Ok(Self::AccountTrieNodeWithProof(value)) - } else if let Ok(value) = ContractStorageTrieNodeWithProof::from_ssz_bytes(buf) { - Ok(Self::ContractStorageTrieNodeWithProof(value)) - } else if let Ok(value) = ContractBytecode::from_ssz_bytes(buf) { - Ok(Self::ContractBytecode(value)) - } else if let Ok(value) = ContractBytecodeWithProof::from_ssz_bytes(buf) { - Ok(Self::ContractBytecodeWithProof(value)) - } else { - Err(ContentValueError::UnknownContent { - bytes: hex_encode(buf), - network: "state".to_string(), - }) + fn decode(key: &Self::TContentKey, buf: &[u8]) -> Result { + match key { + StateContentKey::AccountTrieNode(_) => { + if let Ok(value) = AccountTrieNodeWithProof::from_ssz_bytes(buf) { + return Ok(Self::AccountTrieNodeWithProof(value)); + } + if let Ok(value) = TrieNode::from_ssz_bytes(buf) { + return Ok(Self::TrieNode(value)); + } + } + StateContentKey::ContractStorageTrieNode(_) => { + if let Ok(value) = ContractStorageTrieNodeWithProof::from_ssz_bytes(buf) { + return Ok(Self::ContractStorageTrieNodeWithProof(value)); + } + if let Ok(value) = TrieNode::from_ssz_bytes(buf) { + return Ok(Self::TrieNode(value)); + } + } + StateContentKey::ContractBytecode(_) => { + if let Ok(value) = ContractBytecodeWithProof::from_ssz_bytes(buf) { + return Ok(Self::ContractBytecodeWithProof(value)); + } + if let Ok(value) = ContractBytecode::from_ssz_bytes(buf) { + return Ok(Self::ContractBytecode(value)); + } + } } - } -} - -impl Serialize for StateContentValue { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - serializer.serialize_str(&self.to_hex()) - } -} - -impl<'de> Deserialize<'de> for StateContentValue { - fn deserialize(deserializer: D) -> Result - where - D: serde::Deserializer<'de>, - { - let s = String::deserialize(deserializer)?; - Self::from_hex(&s).map_err(serde::de::Error::custom) + Err(ContentValueError::UnknownContent { + bytes: hex_encode(buf), + network: STATE_NETWORK.to_string(), + }) } } @@ -118,13 +117,15 @@ pub struct ContractBytecodeWithProof { #[cfg(test)] mod test { - use std::{path::PathBuf, str::FromStr}; + use std::path::PathBuf; + use alloy_primitives::Bytes; use anyhow::Result; use rstest::rstest; + use serde::Deserialize; use serde_yaml::Value; - use crate::{test_utils::read_file_from_tests_submodule, utils::bytes::hex_decode}; + use crate::test_utils::read_file_from_tests_submodule; use super::*; @@ -133,13 +134,14 @@ mod test { #[test] fn trie_node() -> Result<()> { let value = read_yaml_file("trie_node.yaml")?; - let value = value.as_mapping().unwrap(); - let expected_content_value = StateContentValue::TrieNode(TrieNode { - node: EncodedTrieNode::from(yaml_as_hex(&value["trie_node"])), + node: yaml_to_bytes(&value["trie_node"]).into(), }); - assert_content_value(&value["content_value"], expected_content_value); + assert_eq!( + expected_content_value.encode(), + RawContentValue::deserialize(&value["content_value"])?, + ); Ok(()) } @@ -147,15 +149,17 @@ mod test { #[test] fn account_trie_node_with_proof() -> Result<()> { let value = read_yaml_file("account_trie_node_with_proof.yaml")?; - let value = value.as_mapping().unwrap(); let expected_content_value = StateContentValue::AccountTrieNodeWithProof(AccountTrieNodeWithProof { proof: yaml_as_proof(&value["proof"]), - block_hash: yaml_as_b256(&value["block_hash"]), + block_hash: B256::deserialize(&value["block_hash"])?, }); - assert_content_value(&value["content_value"], expected_content_value); + assert_eq!( + expected_content_value.encode(), + RawContentValue::deserialize(&value["content_value"])?, + ); Ok(()) } @@ -163,16 +167,18 @@ mod test { #[test] fn contract_storage_trie_node_with_proof() -> Result<()> { let value = read_yaml_file("contract_storage_trie_node_with_proof.yaml")?; - let value = value.as_mapping().unwrap(); let expected_content_value = StateContentValue::ContractStorageTrieNodeWithProof(ContractStorageTrieNodeWithProof { storage_proof: yaml_as_proof(&value["storage_proof"]), account_proof: yaml_as_proof(&value["account_proof"]), - block_hash: yaml_as_b256(&value["block_hash"]), + block_hash: B256::deserialize(&value["block_hash"])?, }); - assert_content_value(&value["content_value"], expected_content_value); + assert_eq!( + expected_content_value.encode(), + RawContentValue::deserialize(&value["content_value"])?, + ); Ok(()) } @@ -180,13 +186,15 @@ mod test { #[test] fn contract_bytecode() -> Result<()> { let value = read_yaml_file("contract_bytecode.yaml")?; - let value = value.as_mapping().unwrap(); let expected_content_value = StateContentValue::ContractBytecode(ContractBytecode { - code: ByteCode::from(yaml_as_hex(&value["bytecode"])), + code: yaml_to_bytes(&value["bytecode"]).into(), }); - assert_content_value(&value["content_value"], expected_content_value); + assert_eq!( + expected_content_value.encode(), + RawContentValue::deserialize(&value["content_value"])?, + ); Ok(()) } @@ -194,56 +202,74 @@ mod test { #[test] fn contract_bytecode_with_proof() -> Result<()> { let value = read_yaml_file("contract_bytecode_with_proof.yaml")?; - let value = value.as_mapping().unwrap(); let expected_content_value = StateContentValue::ContractBytecodeWithProof(ContractBytecodeWithProof { - code: ByteCode::from(yaml_as_hex(&value["bytecode"])), + code: yaml_to_bytes(&value["bytecode"]).into(), account_proof: yaml_as_proof(&value["account_proof"]), - block_hash: yaml_as_b256(&value["block_hash"]), + block_hash: B256::deserialize(&value["block_hash"])?, }); - assert_content_value(&value["content_value"], expected_content_value); + assert_eq!( + expected_content_value.encode(), + RawContentValue::deserialize(&value["content_value"])?, + ); Ok(()) } #[rstest] - #[case::trie_node("trie_node.yaml")] - #[case::account_trie_node_with_proof("account_trie_node_with_proof.yaml")] - #[case::contract_storage_trie_node_with_proof("contract_storage_trie_node_with_proof.yaml")] - #[case::contract_bytecode("contract_bytecode.yaml")] - #[case::contract_bytecode_with_proof("contract_bytecode_with_proof.yaml")] - fn encode_decode(#[case] filename: &str) -> Result<()> { - let value = read_yaml_file(filename)?; - let value = value.as_mapping().unwrap(); - - let content_value_bytes = yaml_as_hex(&value["content_value"]); - - let content_value = StateContentValue::decode(&content_value_bytes)?; + #[case::trie_node("account_trie_node_key.yaml", "trie_node.yaml")] + #[case::account_trie_node_with_proof( + "account_trie_node_key.yaml", + "account_trie_node_with_proof.yaml" + )] + #[case::contract_storage_trie_node_with_proof( + "contract_storage_trie_node_key.yaml", + "contract_storage_trie_node_with_proof.yaml" + )] + #[case::contract_bytecode("contract_bytecode_key.yaml", "contract_bytecode.yaml")] + #[case::contract_bytecode_with_proof( + "contract_bytecode_key.yaml", + "contract_bytecode_with_proof.yaml" + )] + fn encode_decode(#[case] key_filename: &str, #[case] value_filename: &str) -> Result<()> { + let key_file = read_yaml_file(key_filename)?; + let key = StateContentKey::deserialize(&key_file["content_key"])?; + + let value = read_yaml_file(value_filename)?; + + let content_value_bytes = RawContentValue::deserialize(&value["content_value"])?; + let content_value = StateContentValue::decode(&key, &content_value_bytes)?; assert_eq!(content_value.encode(), content_value_bytes); - Ok(()) } #[rstest] - #[case::trie_node("trie_node.yaml")] - #[case::account_trie_node_with_proof("account_trie_node_with_proof.yaml")] - #[case::contract_storage_trie_node_with_proof("contract_storage_trie_node_with_proof.yaml")] - #[case::contract_bytecode("contract_bytecode.yaml")] - #[case::contract_bytecode_with_proof("contract_bytecode_with_proof.yaml")] - fn serde(#[case] filename: &str) -> Result<()> { - let value = read_yaml_file(filename)?; - let value = value.as_mapping().unwrap(); - - let content_value = StateContentValue::deserialize(&value["content_value"])?; - - assert_eq!( - serde_yaml::to_value(content_value).unwrap(), - value["content_value"] - ); - + #[case::trie_node("account_trie_node_key.yaml", "trie_node.yaml")] + #[case::account_trie_node_with_proof( + "account_trie_node_key.yaml", + "account_trie_node_with_proof.yaml" + )] + #[case::contract_storage_trie_node_with_proof( + "contract_storage_trie_node_key.yaml", + "contract_storage_trie_node_with_proof.yaml" + )] + #[case::contract_bytecode("contract_bytecode_key.yaml", "contract_bytecode.yaml")] + #[case::contract_bytecode_with_proof( + "contract_bytecode_key.yaml", + "contract_bytecode_with_proof.yaml" + )] + fn hex_str(#[case] key_filename: &str, #[case] value_filename: &str) -> Result<()> { + let key_file = read_yaml_file(key_filename)?; + let key = StateContentKey::deserialize(&key_file["content_key"])?; + + let value = read_yaml_file(value_filename)?; + let content_value_str = String::deserialize(&value["content_value"])?; + let content_value = StateContentValue::from_hex(&key, &content_value_str)?; + + assert_eq!(content_value.to_hex(), content_value_str); Ok(()) } @@ -253,35 +279,20 @@ mod test { Ok(serde_yaml::from_str(&file)?) } - fn yaml_as_b256(value: &Value) -> B256 { - B256::from_str(value.as_str().unwrap()).unwrap() - } - - fn yaml_as_hex(value: &Value) -> Vec { - hex_decode(value.as_str().unwrap()).unwrap() + fn yaml_to_bytes(value: &Value) -> Vec { + Bytes::deserialize(value).unwrap().to_vec() } fn yaml_as_proof(value: &Value) -> TrieProof { - TrieProof::from( + TrieProof::new( value .as_sequence() .unwrap() .iter() - .map(|v| EncodedTrieNode::from(yaml_as_hex(v))) - .collect::>(), + .map(yaml_to_bytes) + .map(EncodedTrieNode::from) + .collect(), ) - } - - fn assert_content_value(value: &Value, expected_content_value: StateContentValue) { - assert_eq!( - StateContentValue::decode(&yaml_as_hex(value)).unwrap(), - expected_content_value, - "decoding from bytes {value:?} didn't match expected value {expected_content_value:?}" - ); - - assert_eq!( - StateContentValue::deserialize(value).unwrap(), - expected_content_value, - "deserialization from string {value:?} didn't match expected value {expected_content_value:?}"); + .unwrap() } } diff --git a/ethportal-api/src/types/history.rs b/ethportal-api/src/types/history.rs deleted file mode 100644 index b5accce57..000000000 --- a/ethportal-api/src/types/history.rs +++ /dev/null @@ -1,38 +0,0 @@ -use super::query_trace::QueryTrace; -use crate::{types::enr::Enr, HistoryContentKey, HistoryContentValue}; -use serde::{Deserialize, Serialize}; - -/// Response for FindContent & RecursiveFindContent endpoints -#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] -#[serde(untagged)] -pub enum ContentInfo { - #[serde(rename_all = "camelCase")] - ConnectionId { connection_id: u16 }, - #[serde(rename_all = "camelCase")] - Content { - content: HistoryContentValue, - utp_transfer: bool, - }, - #[serde(rename_all = "camelCase")] - Enrs { enrs: Vec }, -} - -/// Parsed response for TraceRecursiveFindContent endpoint -/// -/// This struct represents the content info, and is only used -/// when the content is found locally or on the network. -#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct TraceContentInfo { - pub content: HistoryContentValue, - pub utp_transfer: bool, - pub trace: QueryTrace, -} - -/// Response for PaginateLocalContentKeys endpoint -#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct PaginateLocalContentInfo { - pub content_keys: Vec, - pub total_entries: u64, -} diff --git a/ethportal-api/src/types/mod.rs b/ethportal-api/src/types/mod.rs index 88885db2d..6c422a157 100644 --- a/ethportal-api/src/types/mod.rs +++ b/ethportal-api/src/types/mod.rs @@ -1,4 +1,3 @@ -pub mod beacon; pub mod bootnodes; pub mod bytes; pub mod cli; @@ -9,11 +8,9 @@ pub mod discv5; pub mod distance; pub mod enr; pub mod execution; -pub mod history; pub mod jsonrpc; pub mod node_id; pub mod portal; pub mod portal_wire; pub mod query_trace; -pub mod state; pub mod state_trie; diff --git a/ethportal-api/src/types/portal.rs b/ethportal-api/src/types/portal.rs index 4f61788f0..1a81329fc 100644 --- a/ethportal-api/src/types/portal.rs +++ b/ethportal-api/src/types/portal.rs @@ -1,8 +1,15 @@ -use alloy_primitives::U256; +use alloy_primitives::{Bytes, U256}; use serde::{Deserialize, Serialize}; use ssz_types::{typenum, BitList}; -use crate::types::enr::Enr; +use crate::{types::enr::Enr, OverlayContentKey}; + +use super::query_trace::QueryTrace; + +/// The SSZ encoded representation of content key. +pub type RawContentKey = Vec; +/// The SSZ encoded representation of content value. +pub type RawContentValue = Bytes; pub type DataRadius = U256; pub type Distance = U256; @@ -43,3 +50,39 @@ pub struct TraceGossipInfo { // List of all ENRs to whom the content was successfully transferred pub transferred: Vec, } + +/// Response for FindContent & RecursiveFindContent endpoints +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +#[serde(untagged)] +#[allow(clippy::large_enum_variant)] +pub enum ContentInfo { + #[serde(rename_all = "camelCase")] + ConnectionId { connection_id: u16 }, + #[serde(rename_all = "camelCase")] + Content { + content: RawContentValue, + utp_transfer: bool, + }, + #[serde(rename_all = "camelCase")] + Enrs { enrs: Vec }, +} + +/// Parsed response for TraceRecursiveFindContent endpoint +/// +/// This struct represents the content info, and is only used +/// when the content is found locally or on the network. +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct TraceContentInfo { + pub content: RawContentValue, + pub utp_transfer: bool, + pub trace: QueryTrace, +} + +/// Response for PaginateLocalContentKeys endpoint +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct PaginateLocalContentInfo { + pub content_keys: Vec, + pub total_entries: u64, +} diff --git a/ethportal-api/src/types/state.rs b/ethportal-api/src/types/state.rs deleted file mode 100644 index a0e056419..000000000 --- a/ethportal-api/src/types/state.rs +++ /dev/null @@ -1,38 +0,0 @@ -use super::query_trace::QueryTrace; -use crate::{types::enr::Enr, StateContentKey, StateContentValue}; -use serde::{Deserialize, Serialize}; - -/// Response for FindContent & RecursiveFindContent endpoints -#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] -#[serde(untagged)] -pub enum ContentInfo { - #[serde(rename_all = "camelCase")] - ConnectionId { connection_id: u16 }, - #[serde(rename_all = "camelCase")] - Content { - content: StateContentValue, - utp_transfer: bool, - }, - #[serde(rename_all = "camelCase")] - Enrs { enrs: Vec }, -} - -/// Parsed response for TraceRecursiveFindContent endpoint -/// -/// This struct represents the content info, and is only used -/// when the content is found locally or on the network. -#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct TraceContentInfo { - pub content: StateContentValue, - pub utp_transfer: bool, - pub trace: QueryTrace, -} - -/// Response for PaginateLocalContentKeys endpoint -#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct PaginateLocalContentInfo { - pub content_keys: Vec, - pub total_entries: u64, -} diff --git a/ethportal-peertest/src/scenarios/basic.rs b/ethportal-peertest/src/scenarios/basic.rs index d5f599db9..1222c8509 100644 --- a/ethportal-peertest/src/scenarios/basic.rs +++ b/ethportal-peertest/src/scenarios/basic.rs @@ -2,7 +2,7 @@ use crate::{utils::fixture_header_with_proof, Peertest, PeertestNode}; use alloy_primitives::{B256, U256}; use ethportal_api::{ types::{distance::Distance, portal_wire::ProtocolId}, - BeaconNetworkApiClient, BlockHeaderKey, Discv5ApiClient, HistoryContentKey, + BeaconNetworkApiClient, BlockHeaderKey, ContentValue, Discv5ApiClient, HistoryContentKey, HistoryNetworkApiClient, StateNetworkApiClient, Web3ApiClient, }; use jsonrpsee::async_client::Client; @@ -176,7 +176,7 @@ pub async fn test_find_nodes_zero_distance( pub async fn test_history_store(target: &Client) { info!("Testing portal_historyStore"); let (content_key, content_value) = fixture_header_with_proof(); - let result = HistoryNetworkApiClient::store(target, content_key, content_value) + let result = HistoryNetworkApiClient::store(target, content_key, content_value.encode()) .await .unwrap(); assert!(result); diff --git a/ethportal-peertest/src/scenarios/bridge.rs b/ethportal-peertest/src/scenarios/bridge.rs index c74dc6331..0ddc8e2f4 100644 --- a/ethportal-peertest/src/scenarios/bridge.rs +++ b/ethportal-peertest/src/scenarios/bridge.rs @@ -2,13 +2,17 @@ use crate::{ utils::{fixture_header_with_proof_1000010, wait_for_beacon_content, wait_for_history_content}, Peertest, }; -use ethportal_api::{jsonrpsee::http_client::HttpClient, BeaconContentKey, BeaconContentValue}; +use ethportal_api::{ + jsonrpsee::http_client::HttpClient, BeaconContentKey, BeaconContentValue, ContentValue, + RawContentValue, +}; use portal_bridge::{ api::{consensus::ConsensusApi, execution::ExecutionApi}, bridge::{beacon::BeaconBridge, history::HistoryBridge}, constants::DEFAULT_GOSSIP_LIMIT, types::mode::BridgeMode, }; +use serde::Deserialize; use serde_json::Value; use tokio::time::{sleep, Duration}; use trin_validation::oracle::HeaderOracle; @@ -59,10 +63,9 @@ pub async fn test_beacon_bridge(peertest: &Peertest, portal_client: &HttpClient) let value = std::fs::read_to_string("./test_assets/portalnet/beacon_bridge_data.yaml") .expect("cannot find test asset"); let value: Value = serde_yaml::from_str(&value).unwrap(); - let content_key: BeaconContentKey = - serde_json::from_value(value[0].get("content_key").unwrap().clone()).unwrap(); - let content_value: BeaconContentValue = - serde_json::from_value(value[0].get("content_value").unwrap().clone()).unwrap(); + let content_key = BeaconContentKey::deserialize(&value[0]["content_key"]).unwrap(); + let content_value = RawContentValue::deserialize(&value[0]["content_value"]).unwrap(); + let content_value = BeaconContentValue::decode(&content_key, &content_value).unwrap(); // Check if the stored content value in bootnode's DB matches the offered let received_content_value = diff --git a/ethportal-peertest/src/scenarios/find.rs b/ethportal-peertest/src/scenarios/find.rs index 7ff689152..b1ba1bd66 100644 --- a/ethportal-peertest/src/scenarios/find.rs +++ b/ethportal-peertest/src/scenarios/find.rs @@ -6,9 +6,10 @@ use tracing::info; use crate::{utils::fixture_header_with_proof, Peertest}; use ethportal_api::{ - types::{history::ContentInfo, portal_wire::ProtocolId}, + types::{portal::ContentInfo, portal_wire::ProtocolId}, utils::bytes::hex_decode, - BeaconNetworkApiClient, Enr, HistoryNetworkApiClient, OverlayContentKey, StateNetworkApiClient, + BeaconNetworkApiClient, ContentValue, Enr, HistoryNetworkApiClient, OverlayContentKey, + StateNetworkApiClient, }; pub async fn test_recursive_find_nodes_self(protocol: ProtocolId, peertest: &Peertest) { @@ -86,7 +87,7 @@ pub async fn test_trace_recursive_find_content(peertest: &Peertest) { let store_result = HistoryNetworkApiClient::store( &peertest.bootnode.ipc_client, content_key.clone(), - content_value.clone(), + content_value.encode(), ) .await .unwrap(); @@ -105,7 +106,7 @@ pub async fn test_trace_recursive_find_content(peertest: &Peertest) { let content = trace_content_info.content; let trace = trace_content_info.trace; - assert_eq!(content, content_value); + assert_eq!(content, content_value.encode()); let query_origin_node: NodeId = peertest.nodes[0].enr.node_id(); let node_with_content: NodeId = peertest.bootnode.enr.node_id(); @@ -155,7 +156,7 @@ pub async fn test_trace_recursive_find_content_local_db(peertest: &Peertest) { let store_result = HistoryNetworkApiClient::store( &peertest.bootnode.ipc_client, content_key.clone(), - content_value.clone(), + content_value.encode(), ) .await .unwrap(); @@ -169,7 +170,7 @@ pub async fn test_trace_recursive_find_content_local_db(peertest: &Peertest) { .await .unwrap(); assert!(!trace_content_info.utp_transfer); - assert_eq!(trace_content_info.content, content_value); + assert_eq!(trace_content_info.content, content_value.encode()); let origin = trace_content_info.trace.origin; assert_eq!(trace_content_info.trace.received_from.unwrap(), origin); diff --git a/ethportal-peertest/src/scenarios/gossip.rs b/ethportal-peertest/src/scenarios/gossip.rs index f0e6ea11c..e7b5e7a05 100644 --- a/ethportal-peertest/src/scenarios/gossip.rs +++ b/ethportal-peertest/src/scenarios/gossip.rs @@ -10,7 +10,7 @@ use crate::{ Peertest, }; use ethportal_api::{ - jsonrpsee::async_client::Client, types::cli::TrinConfig, Discv5ApiClient, + jsonrpsee::async_client::Client, types::cli::TrinConfig, ContentValue, Discv5ApiClient, HistoryNetworkApiClient, }; pub async fn test_gossip_with_trace(peertest: &Peertest, target: &Client) { @@ -19,7 +19,7 @@ pub async fn test_gossip_with_trace(peertest: &Peertest, target: &Client) { let _ = target.ping(peertest.bootnode.enr.clone()).await.unwrap(); let (content_key, content_value) = fixture_header_with_proof(); let result = target - .trace_gossip(content_key.clone(), content_value.clone()) + .trace_gossip(content_key.clone(), content_value.encode()) .await .unwrap(); @@ -49,7 +49,7 @@ pub async fn test_gossip_with_trace(peertest: &Peertest, target: &Client) { // send new trace gossip request let result = target - .trace_gossip(content_key.clone(), content_value.clone()) + .trace_gossip(content_key.clone(), content_value.encode()) .await .unwrap(); @@ -66,7 +66,7 @@ pub async fn test_gossip_with_trace(peertest: &Peertest, target: &Client) { // test trace gossip without any expected accepts let result = target - .trace_gossip(content_key, content_value) + .trace_gossip(content_key, content_value.encode()) .await .unwrap(); @@ -93,7 +93,7 @@ pub async fn test_gossip_dropped_with_offer(peertest: &Peertest, target: &Client // Store accumulator_1 locally in client that is not connected to the network let (acc_key_1, acc_value_1) = fixture_epoch_acc_1(); let store_result = - HistoryNetworkApiClient::store(&fresh_target, acc_key_1.clone(), acc_value_1.clone()) + HistoryNetworkApiClient::store(&fresh_target, acc_key_1.clone(), acc_value_1.encode()) .await .unwrap(); assert!(store_result); @@ -143,7 +143,7 @@ pub async fn test_gossip_dropped_with_offer(peertest: &Peertest, target: &Client // doesn't store the content locally in target let (acc_key_2, acc_value_2) = fixture_epoch_acc_2(); target - .offer(fresh_enr, acc_key_2.clone(), acc_value_2.clone()) + .offer(fresh_enr, acc_key_2.clone(), acc_value_2.encode()) .await .unwrap(); @@ -205,7 +205,7 @@ pub async fn test_gossip_dropped_with_find_content(peertest: &Peertest, target: // Store accumulator_1 locally in client that is not connected to the network let (acc_key_1, acc_value_1) = fixture_epoch_acc_1(); let store_result = - HistoryNetworkApiClient::store(&fresh_target, acc_key_1.clone(), acc_value_1.clone()) + HistoryNetworkApiClient::store(&fresh_target, acc_key_1.clone(), acc_value_1.encode()) .await .unwrap(); assert!(store_result); @@ -213,7 +213,7 @@ pub async fn test_gossip_dropped_with_find_content(peertest: &Peertest, target: // Store accumulator_2 locally in target let (acc_key_2, acc_value_2) = fixture_epoch_acc_2(); let store_result = - HistoryNetworkApiClient::store(target, acc_key_2.clone(), acc_value_2.clone()) + HistoryNetworkApiClient::store(target, acc_key_2.clone(), acc_value_2.encode()) .await .unwrap(); assert!(store_result); diff --git a/ethportal-peertest/src/scenarios/offer_accept.rs b/ethportal-peertest/src/scenarios/offer_accept.rs index 53e7361b9..ca5317e06 100644 --- a/ethportal-peertest/src/scenarios/offer_accept.rs +++ b/ethportal-peertest/src/scenarios/offer_accept.rs @@ -10,8 +10,8 @@ use crate::{ Peertest, }; use ethportal_api::{ - jsonrpsee::async_client::Client, types::enr::Enr, utils::bytes::hex_encode, Discv5ApiClient, - HistoryNetworkApiClient, + jsonrpsee::async_client::Client, types::enr::Enr, utils::bytes::hex_encode, ContentValue, + Discv5ApiClient, HistoryNetworkApiClient, }; pub async fn test_unpopulated_offer(peertest: &Peertest, target: &Client) { @@ -20,7 +20,7 @@ pub async fn test_unpopulated_offer(peertest: &Peertest, target: &Client) { let (content_key, content_value) = fixture_header_with_proof(); // Store content to offer in the testnode db let store_result = target - .store(content_key.clone(), content_value.clone()) + .store(content_key.clone(), content_value.encode()) .await .unwrap(); @@ -78,7 +78,7 @@ pub async fn test_populated_offer(peertest: &Peertest, target: &Client) { .offer( Enr::from_str(&peertest.bootnode.enr.to_base64()).unwrap(), content_key.clone(), - content_value.clone(), + content_value.encode(), ) .await .unwrap(); @@ -101,7 +101,7 @@ pub async fn test_populated_offer_with_trace(peertest: &Peertest, target: &Clien let store_result = peertest .bootnode .ipc_client - .store(content_key.clone(), content_value.clone()) + .store(content_key.clone(), content_value.encode()) .await .unwrap(); assert!(store_result); @@ -112,7 +112,7 @@ pub async fn test_populated_offer_with_trace(peertest: &Peertest, target: &Clien .trace_offer( Enr::from_str(&peertest.bootnode.enr.to_base64()).unwrap(), content_key.clone(), - content_value.clone(), + content_value.encode(), ) .await .unwrap(); @@ -137,7 +137,7 @@ pub async fn test_offer_propagates_gossip(peertest: &Peertest, target: &Client) .offer( peertest.bootnode.enr.clone(), content_key.clone(), - content_value.clone(), + content_value.encode(), ) .await .unwrap(); @@ -164,7 +164,7 @@ pub async fn test_offer_propagates_gossip_with_large_content(peertest: &Peertest // Store content to offer in the testnode db let store_result = target - .store(content_key.clone(), content_value.clone()) + .store(content_key.clone(), content_value.encode()) .await .unwrap(); assert!(store_result); @@ -208,7 +208,7 @@ pub async fn test_offer_propagates_gossip_multiple_content_values( .offer( peertest.bootnode.enr.clone(), header_key.clone(), - header_value.clone(), + header_value.encode(), ) .await .unwrap(); @@ -229,17 +229,17 @@ pub async fn test_offer_propagates_gossip_multiple_content_values( // Store content to offer in the testnode db let store_result = target - .store(body_key.clone(), body_value.clone()) + .store(body_key.clone(), body_value.encode()) .await .unwrap(); assert!(store_result); let store_result = target - .store(receipts_key.clone(), receipts_value.clone()) + .store(receipts_key.clone(), receipts_value.encode()) .await .unwrap(); assert!(store_result); let store_result = target - .store(acc_key_1.clone(), acc_value_1.clone()) + .store(acc_key_1.clone(), acc_value_1.encode()) .await .unwrap(); assert!(store_result); @@ -308,12 +308,12 @@ pub async fn test_offer_propagates_gossip_multiple_large_content_values( // Store content to offer in the testnode db let store_result = target - .store(acc_key_1.clone(), acc_value_1.clone()) + .store(acc_key_1.clone(), acc_value_1.encode()) .await .unwrap(); assert!(store_result); let store_result = target - .store(acc_key_2.clone(), acc_value_2.clone()) + .store(acc_key_2.clone(), acc_value_2.encode()) .await .unwrap(); assert!(store_result); diff --git a/ethportal-peertest/src/scenarios/paginate.rs b/ethportal-peertest/src/scenarios/paginate.rs index 38f4e79f4..ac0e0bae3 100644 --- a/ethportal-peertest/src/scenarios/paginate.rs +++ b/ethportal-peertest/src/scenarios/paginate.rs @@ -1,4 +1,4 @@ -use ethportal_api::{BlockHeaderKey, HistoryContentKey, HistoryNetworkApiClient}; +use ethportal_api::{BlockHeaderKey, ContentValue, HistoryContentKey, HistoryNetworkApiClient}; use crate::{utils::fixture_header_with_proof, Peertest}; @@ -23,7 +23,7 @@ pub async fn test_paginate_local_storage(peertest: &Peertest) { let store_result = ipc_client .store( serde_json::from_str(&content_key).unwrap(), - content_value.clone(), + content_value.encode(), ) .await .unwrap(); diff --git a/ethportal-peertest/src/scenarios/state.rs b/ethportal-peertest/src/scenarios/state.rs index 5c9374ecf..e66aeb73b 100644 --- a/ethportal-peertest/src/scenarios/state.rs +++ b/ethportal-peertest/src/scenarios/state.rs @@ -8,7 +8,8 @@ use crate::{ use ethportal_api::{ jsonrpsee::async_client::Client, types::execution::header_with_proof::{BlockHeaderProof, HeaderWithProof, SszNone}, - HistoryContentKey, HistoryNetworkApiClient, StateNetworkApiClient, + ContentValue, HistoryContentKey, HistoryContentValue, HistoryNetworkApiClient, + StateNetworkApiClient, }; use tracing::info; @@ -44,13 +45,16 @@ pub async fn test_state_gossip_contract_bytecode(peertest: &Peertest, target: &C async fn test_state_offer(fixture: &StateFixture, target: &Client, peer: &PeertestNode) { // Make sure that peer has block header + let history_content_key = + HistoryContentKey::BlockHeaderWithProof(fixture.block_header.hash().into()); + let history_content_value = HistoryContentValue::BlockHeaderWithProof(HeaderWithProof { + header: fixture.block_header.clone(), + proof: BlockHeaderProof::None(SszNone::default()), + }); HistoryNetworkApiClient::store( &peer.ipc_client, - HistoryContentKey::BlockHeaderWithProof(fixture.block_header.hash().into()), - ethportal_api::HistoryContentValue::BlockHeaderWithProof(HeaderWithProof { - header: fixture.block_header.clone(), - proof: BlockHeaderProof::None(SszNone::default()), - }), + history_content_key, + history_content_value.encode(), ) .await .unwrap(); @@ -60,12 +64,12 @@ async fn test_state_offer(fixture: &StateFixture, target: &Client, peer: &Peerte target, peer.enr.clone(), fixture.key.clone(), - fixture.offer_value.clone(), + fixture.raw_offer_value.clone(), ) .await .unwrap(); // Check that peer has state content let lookup_content_value = wait_for_state_content(&peer.ipc_client, fixture.key.clone()).await; - assert_eq!(lookup_content_value, fixture.lookup_value); + assert_eq!(lookup_content_value, fixture.lookup_value()); } diff --git a/ethportal-peertest/src/scenarios/utp.rs b/ethportal-peertest/src/scenarios/utp.rs index dcf34ca85..395ee31ce 100644 --- a/ethportal-peertest/src/scenarios/utp.rs +++ b/ethportal-peertest/src/scenarios/utp.rs @@ -4,8 +4,8 @@ use crate::{ }; use discv5::enr::NodeId; use ethportal_api::{ - types::history::{ContentInfo, TraceContentInfo}, - HistoryNetworkApiClient, + types::portal::{ContentInfo, TraceContentInfo}, + ContentValue, HistoryNetworkApiClient, }; use tracing::info; @@ -16,7 +16,7 @@ pub async fn test_recursive_utp(peertest: &Peertest) { let (content_key, content_value) = fixture_header_with_proof(); let store_result = peertest.nodes[0] .ipc_client - .store(content_key.clone(), content_value.clone()) + .store(content_key.clone(), content_value.encode()) .await .unwrap(); assert!(store_result); @@ -26,7 +26,7 @@ pub async fn test_recursive_utp(peertest: &Peertest) { let store_result = peertest .bootnode .ipc_client - .store(content_key.clone(), content_value.clone()) + .store(content_key.clone(), content_value.encode()) .await .unwrap(); @@ -43,7 +43,7 @@ pub async fn test_recursive_utp(peertest: &Peertest) { utp_transfer, } = content_info { - assert_eq!(content, content_value); + assert_eq!(content, content_value.encode()); assert!(utp_transfer); } else { panic!("Error: Unexpected content info response"); @@ -57,7 +57,7 @@ pub async fn test_trace_recursive_utp(peertest: &Peertest) { let (content_key, content_value) = fixture_header_with_proof(); let store_result = peertest.nodes[0] .ipc_client - .store(content_key.clone(), content_value.clone()) + .store(content_key.clone(), content_value.encode()) .await .unwrap(); @@ -68,7 +68,7 @@ pub async fn test_trace_recursive_utp(peertest: &Peertest) { let store_result = peertest .bootnode .ipc_client - .store(content_key.clone(), content_value.clone()) + .store(content_key.clone(), content_value.encode()) .await .unwrap(); @@ -83,7 +83,7 @@ pub async fn test_trace_recursive_utp(peertest: &Peertest) { let content = trace_content_info.content; let trace = trace_content_info.trace; - assert_eq!(content, content_value); + assert_eq!(content, content_value.encode()); let query_origin_node: NodeId = peertest.nodes[0].enr.node_id(); let node_with_content: NodeId = peertest.bootnode.enr.node_id(); diff --git a/ethportal-peertest/src/scenarios/validation.rs b/ethportal-peertest/src/scenarios/validation.rs index 1b59dd20e..8b57fdf0c 100644 --- a/ethportal-peertest/src/scenarios/validation.rs +++ b/ethportal-peertest/src/scenarios/validation.rs @@ -5,8 +5,8 @@ use crate::{ use alloy_primitives::B256; use ethportal_api::{ jsonrpsee::async_client::Client, - types::{content_key::history::BlockHeaderKey, enr::Enr, history::ContentInfo}, - HistoryContentKey, HistoryNetworkApiClient, + types::{content_key::history::BlockHeaderKey, enr::Enr, portal::ContentInfo}, + ContentValue, HistoryContentKey, HistoryNetworkApiClient, }; use std::str::FromStr; use tracing::info; @@ -20,7 +20,7 @@ pub async fn test_validate_pre_merge_header_with_proof(peertest: &Peertest, targ let store_result = peertest .bootnode .ipc_client - .store(content_key.clone(), content_value.clone()) + .store(content_key.clone(), content_value.encode()) .await .unwrap(); @@ -40,7 +40,7 @@ pub async fn test_validate_pre_merge_header_with_proof(peertest: &Peertest, targ content, utp_transfer, } => { - assert_eq!(content, content_value); + assert_eq!(content, content_value.encode()); assert!(!utp_transfer); } _ => panic!("Content values should match"), @@ -59,7 +59,7 @@ pub async fn test_invalidate_header_by_hash(peertest: &Peertest, target: &Client let store_result = peertest .bootnode .ipc_client - .store(invalid_content_key.clone(), content_value.clone()) + .store(invalid_content_key.clone(), content_value.encode()) .await .unwrap(); assert!(store_result); @@ -82,7 +82,10 @@ pub async fn test_validate_pre_merge_block_body(peertest: &Peertest, target: &Cl info!("Test validating a pre-merge block body"); // store header_with_proof to validate block body let (content_key, content_value) = fixture_header_with_proof(); - let store_result = target.store(content_key, content_value).await.unwrap(); + let store_result = target + .store(content_key, content_value.encode()) + .await + .unwrap(); assert!(store_result); // store block body @@ -91,7 +94,7 @@ pub async fn test_validate_pre_merge_block_body(peertest: &Peertest, target: &Cl let store_result = peertest .bootnode .ipc_client - .store(content_key.clone(), content_value.clone()) + .store(content_key.clone(), content_value.encode()) .await .unwrap(); @@ -111,7 +114,7 @@ pub async fn test_validate_pre_merge_block_body(peertest: &Peertest, target: &Cl content, utp_transfer, } => { - assert_eq!(content, content_value); + assert_eq!(content, content_value.encode()); assert!(utp_transfer); } _ => panic!("Content values should match"), @@ -122,7 +125,10 @@ pub async fn test_validate_pre_merge_receipts(peertest: &Peertest, target: &Clie info!("Test validating pre-merge receipts"); // store header_with_proof to validate block body let (content_key, content_value) = fixture_header_with_proof(); - let store_result = target.store(content_key, content_value).await.unwrap(); + let store_result = target + .store(content_key, content_value.encode()) + .await + .unwrap(); assert!(store_result); // store receipts @@ -131,7 +137,7 @@ pub async fn test_validate_pre_merge_receipts(peertest: &Peertest, target: &Clie let store_result = peertest .bootnode .ipc_client - .store(content_key.clone(), content_value.clone()) + .store(content_key.clone(), content_value.encode()) .await .unwrap(); @@ -151,7 +157,7 @@ pub async fn test_validate_pre_merge_receipts(peertest: &Peertest, target: &Clie content, utp_transfer, } => { - assert_eq!(content, content_value); + assert_eq!(content, content_value.encode()); assert!(utp_transfer); } _ => panic!("Content values should match"), diff --git a/ethportal-peertest/src/utils.rs b/ethportal-peertest/src/utils.rs index 6fdfb68da..829928ca5 100644 --- a/ethportal-peertest/src/utils.rs +++ b/ethportal-peertest/src/utils.rs @@ -12,8 +12,8 @@ use ureq::serde::Deserialize; use ethportal_api::{ BeaconContentKey, BeaconContentValue, BeaconNetworkApiClient, ContentValue, Header, - HistoryContentKey, HistoryContentValue, HistoryNetworkApiClient, StateContentKey, - StateContentValue, StateNetworkApiClient, + HistoryContentKey, HistoryContentValue, HistoryNetworkApiClient, RawContentValue, + StateContentKey, StateContentValue, StateNetworkApiClient, }; pub async fn wait_for_successful_result(f: impl Fn() -> Fut) -> O @@ -43,9 +43,13 @@ pub async fn wait_for_history_content HistoryContentValue { wait_for_successful_result(|| { + let content_key = content_key.clone(); ipc_client .local_content(content_key.clone()) .map_err(anyhow::Error::from) + .and_then(|content| async move { + HistoryContentValue::decode(&content_key, &content).map_err(anyhow::Error::from) + }) }) .await } @@ -56,9 +60,13 @@ pub async fn wait_for_beacon_content BeaconContentValue { wait_for_successful_result(|| { + let content_key = content_key.clone(); ipc_client .local_content(content_key.clone()) .map_err(anyhow::Error::from) + .and_then(|content| async move { + BeaconContentValue::decode(&content_key, &content).map_err(anyhow::Error::from) + }) }) .await } @@ -69,9 +77,13 @@ pub async fn wait_for_state_content StateContentValue { wait_for_successful_result(|| { + let content_key = content_key.clone(); ipc_client .local_content(content_key.clone()) .map_err(anyhow::Error::from) + .and_then(|content| async move { + StateContentValue::decode(&content_key, &content).map_err(anyhow::Error::from) + }) }) .await } @@ -83,10 +95,9 @@ fn read_history_content_key_value( let value: Value = serde_yaml::from_str(&yaml_content)?; - let content_key: HistoryContentKey = - serde_yaml::from_value(value.get("content_key").unwrap().clone())?; - let content_value: HistoryContentValue = - serde_yaml::from_value(value.get("content_value").unwrap().clone())?; + let content_key = HistoryContentKey::deserialize(&value["content_key"])?; + let content_value = RawContentValue::deserialize(&value["content_value"])?; + let content_value = HistoryContentValue::decode(&content_key, &content_value)?; Ok((content_key, content_value)) } @@ -142,7 +153,7 @@ fn read_epoch_acc(hash: &str) -> (HistoryContentKey, HistoryContentValue) { ethportal_api::HistoryContentKey::EpochAccumulator(ethportal_api::EpochAccumulatorKey { epoch_hash: alloy_primitives::B256::from_slice(&epoch_acc_hash), }); - let content_value = ethportal_api::HistoryContentValue::decode(&epoch_acc).unwrap(); + let content_value = HistoryContentValue::decode(&content_key, &epoch_acc).unwrap(); (content_key, content_value) } @@ -153,9 +164,21 @@ pub struct StateFixture { #[serde(rename = "content_key")] pub key: StateContentKey, #[serde(rename = "content_value_offer")] - pub offer_value: StateContentValue, + pub raw_offer_value: RawContentValue, #[serde(rename = "content_value_retrieval")] - pub lookup_value: StateContentValue, + pub raw_lookup_value: RawContentValue, +} + +impl StateFixture { + pub fn offer_value(&self) -> StateContentValue { + StateContentValue::decode(&self.key, &self.raw_offer_value) + .expect("Error decoding state offer content value") + } + + pub fn lookup_value(&self) -> StateContentValue { + StateContentValue::decode(&self.key, &self.raw_lookup_value) + .expect("Error decoding state lookup content value") + } } fn de_header<'de, D>(deserializer: D) -> Result diff --git a/light-client/src/consensus/rpc/portal_rpc.rs b/light-client/src/consensus/rpc/portal_rpc.rs index 3fe4c011c..57658ed95 100644 --- a/light-client/src/consensus/rpc/portal_rpc.rs +++ b/light-client/src/consensus/rpc/portal_rpc.rs @@ -53,7 +53,7 @@ impl ConsensusRpc for PortalRpc { let (tx, rx) = oneshot::channel(); let overlay_command = OverlayCommand::FindContentQuery { - target: bootstrap_key, + target: bootstrap_key.clone(), callback: tx, is_trace: false, }; @@ -70,7 +70,7 @@ impl ConsensusRpc for PortalRpc { match rx.await { Ok(result) => { let bootstrap = match result { - Ok(result) => BeaconContentValue::decode(&result.0)?, + Ok(result) => BeaconContentValue::decode(&bootstrap_key, &result.0)?, Err(err) => { bail!("LightClientBootstrap content not found on the network: {err}") } @@ -110,7 +110,7 @@ impl ConsensusRpc for PortalRpc { let (tx, rx) = oneshot::channel(); let overlay_command = OverlayCommand::FindContentQuery { - target: updates_key, + target: updates_key.clone(), callback: tx, is_trace: false, }; @@ -127,7 +127,7 @@ impl ConsensusRpc for PortalRpc { match rx.await { Ok(result) => { let content_value = match result { - Ok(result) => BeaconContentValue::decode(&result.0)?, + Ok(result) => BeaconContentValue::decode(&updates_key, &result.0)?, Err(err) => { return Err(anyhow!("LightClientUpdatesByRange period={period}, count={count} not found on the network: {err}")); } @@ -181,7 +181,7 @@ impl ConsensusRpc for PortalRpc { let (tx, rx) = oneshot::channel(); let overlay_command = OverlayCommand::FindContentQuery { - target: finality_update_key, + target: finality_update_key.clone(), callback: tx, is_trace: false, }; @@ -198,7 +198,7 @@ impl ConsensusRpc for PortalRpc { match rx.await { Ok(result) => { let finality_update = match result { - Ok(result) => BeaconContentValue::decode(&result.0)?, + Ok(result) => BeaconContentValue::decode(&finality_update_key, &result.0)?, Err(err) => { return Err(anyhow!("LightClientFinalityUpdate content with finalized slot 0 not found on the network: {err}")); } @@ -242,7 +242,7 @@ impl ConsensusRpc for PortalRpc { let (tx, rx) = oneshot::channel(); let overlay_command = OverlayCommand::FindContentQuery { - target: optimistic_update_key, + target: optimistic_update_key.clone(), callback: tx, is_trace: false, }; @@ -259,7 +259,7 @@ impl ConsensusRpc for PortalRpc { match rx.await { Ok(result) => { let optimistic_update = match result { - Ok(result) => BeaconContentValue::decode(&result.0)?, + Ok(result) => BeaconContentValue::decode(&optimistic_update_key, &result.0)?, Err(err) => { return Err(anyhow!("LightClientOptimisticUpdate content with signature slot {expected_current_slot} not found on the network: {err}")); } diff --git a/portal-bridge/src/bridge/beacon.rs b/portal-bridge/src/bridge/beacon.rs index 9750e9be9..e58b5dee8 100644 --- a/portal-bridge/src/bridge/beacon.rs +++ b/portal-bridge/src/bridge/beacon.rs @@ -111,8 +111,8 @@ impl BeaconBridge { for asset in assets.0.into_iter() { gossip_beacon_content( self.portal_client.clone(), - asset.content_key, - asset.content_value, + asset.content_key.clone(), + asset.content_value().expect("Error getting content value"), slot_stats.clone(), ) .await diff --git a/portal-bridge/src/bridge/era1.rs b/portal-bridge/src/bridge/era1.rs index d8fca752c..35ce6064c 100644 --- a/portal-bridge/src/bridge/era1.rs +++ b/portal-bridge/src/bridge/era1.rs @@ -33,7 +33,7 @@ use crate::{ }; use ethportal_api::{ jsonrpsee::http_client::HttpClient, - types::{execution::accumulator::EpochAccumulator, history::ContentInfo}, + types::{execution::accumulator::EpochAccumulator, portal::ContentInfo}, BlockBodyKey, BlockHeaderKey, BlockReceiptsKey, EpochAccumulatorKey, HistoryContentKey, HistoryContentValue, HistoryNetworkApiClient, }; diff --git a/portal-bridge/src/bridge/history.rs b/portal-bridge/src/bridge/history.rs index 38905e85d..15da61b71 100644 --- a/portal-bridge/src/bridge/history.rs +++ b/portal-bridge/src/bridge/history.rs @@ -91,7 +91,7 @@ impl HistoryBridge { let _ = gossip_history_content( self.portal_client.clone(), asset.content_key.clone(), - asset.content_value, + asset.content_value().expect("Error getting content value"), block_stats.clone(), ) .await; diff --git a/portal-bridge/src/gossip.rs b/portal-bridge/src/gossip.rs index 27b70710b..af4222611 100644 --- a/portal-bridge/src/gossip.rs +++ b/portal-bridge/src/gossip.rs @@ -6,9 +6,11 @@ use tracing::{debug, warn, Instrument}; use crate::stats::{BeaconSlotStats, HistoryBlockStats, StatsReporter}; use ethportal_api::{ - jsonrpsee::core::Error, types::portal::TraceGossipInfo, BeaconContentKey, BeaconContentValue, - BeaconNetworkApiClient, HistoryContentKey, HistoryContentValue, HistoryNetworkApiClient, - OverlayContentKey, StateContentKey, StateContentValue, StateNetworkApiClient, + jsonrpsee::core::Error, + types::portal::{ContentInfo, TraceGossipInfo}, + BeaconContentKey, BeaconContentValue, BeaconNetworkApiClient, ContentValue, HistoryContentKey, + HistoryContentValue, HistoryNetworkApiClient, OverlayContentKey, StateContentKey, + StateContentValue, StateNetworkApiClient, }; const GOSSIP_RETRY_COUNT: u64 = 3; @@ -45,7 +47,7 @@ async fn beacon_trace_gossip( let result = BeaconNetworkApiClient::trace_gossip( &client, content_key.clone(), - content_value.clone(), + content_value.encode(), ) .await; // check if content was successfully transferred to at least one peer on network @@ -62,7 +64,7 @@ async fn beacon_trace_gossip( // if not, make rfc request to see if data is available on network let result = BeaconNetworkApiClient::recursive_find_content(&client, content_key.clone()).await; - if let Ok(ethportal_api::types::beacon::ContentInfo::Content { .. }) = result { + if let Ok(ContentInfo::Content { .. }) = result { debug!("Found content on network, after failing to gossip, aborting gossip. content key={:?}", content_key.to_hex()); found = true; return Ok(GossipReport { @@ -118,7 +120,7 @@ async fn history_trace_gossip( let result = HistoryNetworkApiClient::trace_gossip( &client, content_key.clone(), - content_value.clone(), + content_value.encode(), ) .await; // check if content was successfully transferred to at least one peer on network @@ -135,7 +137,7 @@ async fn history_trace_gossip( // if not, make rfc request to see if data is available on network let result = HistoryNetworkApiClient::recursive_find_content(&client, content_key.clone()).await; - if let Ok(ethportal_api::types::history::ContentInfo::Content { .. }) = result { + if let Ok(ContentInfo::Content { .. }) = result { debug!("Found content on network, after failing to gossip, aborting gossip. content key={:?}", content_key.to_hex()); found = true; return Ok(GossipReport { @@ -186,7 +188,7 @@ async fn state_trace_gossip( let result = StateNetworkApiClient::trace_gossip( &client, content_key.clone(), - content_value.clone(), + content_value.encode(), ) .await; // check if content was successfully transferred to at least one peer on network @@ -203,7 +205,7 @@ async fn state_trace_gossip( // if not, make rfc request to see if data is available on network let result = StateNetworkApiClient::recursive_find_content(&client, content_key.clone()).await; - if let Ok(ethportal_api::types::state::ContentInfo::Content { .. }) = result { + if let Ok(ContentInfo::Content { .. }) = result { debug!("Found content on network, after failing to gossip, aborting gossip. content key={:?}", content_key.to_hex()); found = true; return Ok(GossipReport { diff --git a/portal-bridge/src/utils.rs b/portal-bridge/src/utils.rs index 3ec1b3159..f57582620 100644 --- a/portal-bridge/src/utils.rs +++ b/portal-bridge/src/utils.rs @@ -5,14 +5,14 @@ use std::{ }; use alloy_primitives::B256; -use anyhow::bail; +use anyhow::{anyhow, bail}; use chrono::Duration; use discv5::enr::{CombinedKey, Enr, NodeId}; use serde::{Deserialize, Serialize}; use ethportal_api::{ - utils::bytes::hex_encode, BeaconContentKey, BeaconContentValue, HistoryContentKey, - HistoryContentValue, + utils::bytes::hex_encode, BeaconContentKey, BeaconContentValue, ContentValue, + HistoryContentKey, HistoryContentValue, RawContentValue, }; /// Generates a set of N private keys, with node ids that are equally spaced @@ -108,13 +108,35 @@ impl TestAssets { #[derive(Debug, Clone, Serialize, Deserialize)] pub struct HistoryAsset { pub content_key: HistoryContentKey, - pub content_value: HistoryContentValue, + content_value: RawContentValue, +} + +impl HistoryAsset { + pub fn content_value(&self) -> anyhow::Result { + HistoryContentValue::decode(&self.content_key, &self.content_value).map_err(|err| { + anyhow!( + "Unable to parse history content value: {}. Error: {err}", + self.content_value + ) + }) + } } #[derive(Debug, Clone, Serialize, Deserialize)] pub struct BeaconAsset { pub content_key: BeaconContentKey, - pub content_value: BeaconContentValue, + content_value: RawContentValue, +} + +impl BeaconAsset { + pub fn content_value(&self) -> anyhow::Result { + BeaconContentValue::decode(&self.content_key, &self.content_value).map_err(|err| { + anyhow!( + "Unable to parse beacon content value: {}. Error: {err}", + self.content_value + ) + }) + } } pub fn read_test_assets_from_file(test_path: PathBuf) -> TestAssets { @@ -210,10 +232,10 @@ mod tests { read_test_assets_from_file(PathBuf::from("../test_assets/portalnet/bridge_data.json")) .into_history_assets() .unwrap(); - let content_key: HistoryContentKey = - serde_json::from_value(json!(HEADER_WITH_PROOF_CONTENT_KEY)).unwrap(); - let content_value: HistoryContentValue = - serde_json::from_value(json!(HEADER_WITH_PROOF_CONTENT_VALUE)).unwrap(); + let content_key = + HistoryContentKey::deserialize(json!(HEADER_WITH_PROOF_CONTENT_KEY)).unwrap(); + let content_value = + RawContentValue::deserialize(json!(HEADER_WITH_PROOF_CONTENT_VALUE)).unwrap(); assert_eq!(assets[0].content_key, content_key); assert_eq!(assets[0].content_value, content_value); @@ -225,10 +247,10 @@ mod tests { read_test_assets_from_file(PathBuf::from("../test_assets/portalnet/bridge_data.yaml")) .into_history_assets() .unwrap(); - let content_key: HistoryContentKey = - serde_json::from_value(json!(HEADER_WITH_PROOF_CONTENT_KEY)).unwrap(); - let content_value: HistoryContentValue = - serde_json::from_value(json!(HEADER_WITH_PROOF_CONTENT_VALUE)).unwrap(); + let content_key = + HistoryContentKey::deserialize(json!(HEADER_WITH_PROOF_CONTENT_KEY)).unwrap(); + let content_value = + RawContentValue::deserialize(json!(HEADER_WITH_PROOF_CONTENT_VALUE)).unwrap(); assert_eq!(assets[0].content_key, content_key); assert_eq!(assets[0].content_value, content_value); diff --git a/rpc/src/beacon_rpc.rs b/rpc/src/beacon_rpc.rs index 23698debe..e5cd81083 100644 --- a/rpc/src/beacon_rpc.rs +++ b/rpc/src/beacon_rpc.rs @@ -4,15 +4,19 @@ use tokio::sync::mpsc; use ethportal_api::{ types::{ - beacon::{ContentInfo, PaginateLocalContentInfo, TraceContentInfo}, enr::Enr, jsonrpc::{endpoints::BeaconEndpoint, request::BeaconJsonRpcRequest}, - portal::{AcceptInfo, DataRadius, FindNodesInfo, PongInfo, TraceGossipInfo}, + portal::{ + AcceptInfo, ContentInfo, DataRadius, FindNodesInfo, PaginateLocalContentInfo, PongInfo, + TraceContentInfo, TraceGossipInfo, + }, }, - BeaconContentKey, BeaconContentValue, BeaconNetworkApiServer, RoutingTableInfo, + BeaconContentKey, BeaconContentValue, BeaconNetworkApiServer, ContentValue, RawContentValue, + RoutingTableInfo, }; use crate::{ + errors::RpcServeError, fetch::proxy_to_subnet, jsonrpsee::core::{async_trait, RpcResult}, }; @@ -130,7 +134,7 @@ impl BeaconNetworkApiServer for BeaconNetworkApi { &self, offset: u64, limit: u64, - ) -> RpcResult { + ) -> RpcResult> { let endpoint = BeaconEndpoint::PaginateLocalContentKeys(offset, limit); Ok(proxy_to_subnet(&self.network, endpoint).await?) } @@ -140,8 +144,10 @@ impl BeaconNetworkApiServer for BeaconNetworkApi { async fn gossip( &self, content_key: BeaconContentKey, - content_value: BeaconContentValue, + content_value: RawContentValue, ) -> RpcResult { + let content_value = BeaconContentValue::decode(&content_key, &content_value) + .map_err(RpcServeError::from)?; let endpoint = BeaconEndpoint::Gossip(content_key, content_value); Ok(proxy_to_subnet(&self.network, endpoint).await?) } @@ -151,8 +157,10 @@ impl BeaconNetworkApiServer for BeaconNetworkApi { async fn trace_gossip( &self, content_key: BeaconContentKey, - content_value: BeaconContentValue, + content_value: RawContentValue, ) -> RpcResult { + let content_value = BeaconContentValue::decode(&content_key, &content_value) + .map_err(RpcServeError::from)?; let endpoint = BeaconEndpoint::TraceGossip(content_key, content_value); Ok(proxy_to_subnet(&self.network, endpoint).await?) } @@ -165,8 +173,10 @@ impl BeaconNetworkApiServer for BeaconNetworkApi { &self, enr: Enr, content_key: BeaconContentKey, - content_value: BeaconContentValue, + content_value: RawContentValue, ) -> RpcResult { + let content_value = BeaconContentValue::decode(&content_key, &content_value) + .map_err(RpcServeError::from)?; let endpoint = BeaconEndpoint::Offer(enr, content_key, content_value); Ok(proxy_to_subnet(&self.network, endpoint).await?) } @@ -179,8 +189,10 @@ impl BeaconNetworkApiServer for BeaconNetworkApi { &self, enr: Enr, content_key: BeaconContentKey, - content_value: BeaconContentValue, + content_value: RawContentValue, ) -> RpcResult { + let content_value = BeaconContentValue::decode(&content_key, &content_value) + .map_err(RpcServeError::from)?; let endpoint = BeaconEndpoint::TraceOffer(enr, content_key, content_value); Ok(proxy_to_subnet(&self.network, endpoint).await?) } @@ -202,14 +214,16 @@ impl BeaconNetworkApiServer for BeaconNetworkApi { async fn store( &self, content_key: BeaconContentKey, - content_value: BeaconContentValue, + content_value: RawContentValue, ) -> RpcResult { + let content_value = BeaconContentValue::decode(&content_key, &content_value) + .map_err(RpcServeError::from)?; let endpoint = BeaconEndpoint::Store(content_key, content_value); Ok(proxy_to_subnet(&self.network, endpoint).await?) } /// Get a content from the local database. - async fn local_content(&self, content_key: BeaconContentKey) -> RpcResult { + async fn local_content(&self, content_key: BeaconContentKey) -> RpcResult { let endpoint = BeaconEndpoint::LocalContent(content_key); Ok(proxy_to_subnet(&self.network, endpoint).await?) } diff --git a/rpc/src/errors.rs b/rpc/src/errors.rs index 75cc7cb36..a27f51f9e 100644 --- a/rpc/src/errors.rs +++ b/rpc/src/errors.rs @@ -6,7 +6,7 @@ use crate::{ rpc_server::ServerKind, PortalRpcModule, }; -use ethportal_api::types::query_trace::QueryTrace; +use ethportal_api::{types::query_trace::QueryTrace, ContentValueError}; use serde::{Deserialize, Serialize}; use std::io; @@ -99,6 +99,12 @@ impl From for RpcServeError { } } +impl From for RpcServeError { + fn from(err: ContentValueError) -> Self { + RpcServeError::Message(format!("Error decoding content value: {err}")) + } +} + /// Errors when trying to launch ws and http server on the same port. #[derive(Debug, thiserror::Error)] pub enum WsHttpSamePortError { diff --git a/rpc/src/fetch.rs b/rpc/src/fetch.rs index 5741b557c..2d38e238d 100644 --- a/rpc/src/fetch.rs +++ b/rpc/src/fetch.rs @@ -8,14 +8,14 @@ use tokio::sync::mpsc; use ethportal_api::{ types::{ execution::{block_body::BlockBody, header::Header}, - history::ContentInfo, jsonrpc::{ endpoints::{HistoryEndpoint, SubnetworkEndpoint}, request::{HistoryJsonRpcRequest, JsonRpcRequest}, }, + portal::ContentInfo, query_trace::QueryTrace, }, - HistoryContentKey, HistoryContentValue, + ContentValue, HistoryContentKey, HistoryContentValue, }; use crate::{ @@ -106,7 +106,7 @@ async fn find_content_by_hash( network: &mpsc::UnboundedSender, content_key: HistoryContentKey, ) -> Result { - let endpoint = HistoryEndpoint::RecursiveFindContent(content_key); + let endpoint = HistoryEndpoint::RecursiveFindContent(content_key.clone()); let response: ContentInfo = proxy_to_subnet(network, endpoint).await?; let ContentInfo::Content { content, .. } = response else { return Err(RpcServeError::Message(format!( @@ -114,5 +114,5 @@ async fn find_content_by_hash( ))); }; - Ok(content) + Ok(HistoryContentValue::decode(&content_key, &content)?) } diff --git a/rpc/src/history_rpc.rs b/rpc/src/history_rpc.rs index 1e4789d01..3476de2c5 100644 --- a/rpc/src/history_rpc.rs +++ b/rpc/src/history_rpc.rs @@ -4,14 +4,18 @@ use tokio::sync::mpsc; use ethportal_api::{ types::{ enr::Enr, - history::{ContentInfo, PaginateLocalContentInfo, TraceContentInfo}, jsonrpc::{endpoints::HistoryEndpoint, request::HistoryJsonRpcRequest}, - portal::{AcceptInfo, DataRadius, FindNodesInfo, PongInfo, TraceGossipInfo}, + portal::{ + AcceptInfo, ContentInfo, DataRadius, FindNodesInfo, PaginateLocalContentInfo, PongInfo, + TraceContentInfo, TraceGossipInfo, + }, }, - HistoryContentKey, HistoryContentValue, HistoryNetworkApiServer, RoutingTableInfo, + ContentValue, HistoryContentKey, HistoryContentValue, HistoryNetworkApiServer, RawContentValue, + RoutingTableInfo, }; use crate::{ + errors::RpcServeError, fetch::proxy_to_subnet, jsonrpsee::core::{async_trait, RpcResult}, }; @@ -116,7 +120,7 @@ impl HistoryNetworkApiServer for HistoryNetworkApi { &self, offset: u64, limit: u64, - ) -> RpcResult { + ) -> RpcResult> { let endpoint = HistoryEndpoint::PaginateLocalContentKeys(offset, limit); Ok(proxy_to_subnet(&self.network, endpoint).await?) } @@ -126,8 +130,10 @@ impl HistoryNetworkApiServer for HistoryNetworkApi { async fn gossip( &self, content_key: HistoryContentKey, - content_value: HistoryContentValue, + content_value: RawContentValue, ) -> RpcResult { + let content_value = HistoryContentValue::decode(&content_key, &content_value) + .map_err(RpcServeError::from)?; let endpoint = HistoryEndpoint::Gossip(content_key, content_value); Ok(proxy_to_subnet(&self.network, endpoint).await?) } @@ -137,8 +143,10 @@ impl HistoryNetworkApiServer for HistoryNetworkApi { async fn trace_gossip( &self, content_key: HistoryContentKey, - content_value: HistoryContentValue, + content_value: RawContentValue, ) -> RpcResult { + let content_value = HistoryContentValue::decode(&content_key, &content_value) + .map_err(RpcServeError::from)?; let endpoint = HistoryEndpoint::TraceGossip(content_key, content_value); Ok(proxy_to_subnet(&self.network, endpoint).await?) } @@ -151,8 +159,10 @@ impl HistoryNetworkApiServer for HistoryNetworkApi { &self, enr: Enr, content_key: HistoryContentKey, - content_value: HistoryContentValue, + content_value: RawContentValue, ) -> RpcResult { + let content_value = HistoryContentValue::decode(&content_key, &content_value) + .map_err(RpcServeError::from)?; let endpoint = HistoryEndpoint::Offer(enr, content_key, content_value); Ok(proxy_to_subnet(&self.network, endpoint).await?) } @@ -165,8 +175,10 @@ impl HistoryNetworkApiServer for HistoryNetworkApi { &self, enr: Enr, content_key: HistoryContentKey, - content_value: HistoryContentValue, + content_value: RawContentValue, ) -> RpcResult { + let content_value = HistoryContentValue::decode(&content_key, &content_value) + .map_err(RpcServeError::from)?; let endpoint = HistoryEndpoint::TraceOffer(enr, content_key, content_value); Ok(proxy_to_subnet(&self.network, endpoint).await?) } @@ -188,17 +200,16 @@ impl HistoryNetworkApiServer for HistoryNetworkApi { async fn store( &self, content_key: HistoryContentKey, - content_value: HistoryContentValue, + content_value: RawContentValue, ) -> RpcResult { + let content_value = HistoryContentValue::decode(&content_key, &content_value) + .map_err(RpcServeError::from)?; let endpoint = HistoryEndpoint::Store(content_key, content_value); Ok(proxy_to_subnet(&self.network, endpoint).await?) } /// Get a content from the local database. - async fn local_content( - &self, - content_key: HistoryContentKey, - ) -> RpcResult { + async fn local_content(&self, content_key: HistoryContentKey) -> RpcResult { let endpoint = HistoryEndpoint::LocalContent(content_key); Ok(proxy_to_subnet(&self.network, endpoint).await?) } diff --git a/rpc/src/state_rpc.rs b/rpc/src/state_rpc.rs index 4183a2691..94bd0dbd9 100644 --- a/rpc/src/state_rpc.rs +++ b/rpc/src/state_rpc.rs @@ -5,13 +5,17 @@ use ethportal_api::{ types::{ enr::Enr, jsonrpc::{endpoints::StateEndpoint, request::StateJsonRpcRequest}, - portal::{AcceptInfo, DataRadius, FindNodesInfo, PongInfo, TraceGossipInfo}, - state::{ContentInfo, PaginateLocalContentInfo, TraceContentInfo}, + portal::{ + AcceptInfo, ContentInfo, DataRadius, FindNodesInfo, PaginateLocalContentInfo, PongInfo, + TraceContentInfo, TraceGossipInfo, + }, }, - RoutingTableInfo, StateContentKey, StateContentValue, StateNetworkApiServer, + ContentValue, RawContentValue, RoutingTableInfo, StateContentKey, StateContentValue, + StateNetworkApiServer, }; use crate::{ + errors::RpcServeError, fetch::proxy_to_subnet, jsonrpsee::core::{async_trait, RpcResult}, }; @@ -109,7 +113,7 @@ impl StateNetworkApiServer for StateNetworkApi { &self, offset: u64, limit: u64, - ) -> RpcResult { + ) -> RpcResult> { let endpoint = StateEndpoint::PaginateLocalContentKeys(offset, limit); Ok(proxy_to_subnet(&self.network, endpoint).await?) } @@ -119,8 +123,10 @@ impl StateNetworkApiServer for StateNetworkApi { async fn gossip( &self, content_key: StateContentKey, - content_value: StateContentValue, + content_value: RawContentValue, ) -> RpcResult { + let content_value = + StateContentValue::decode(&content_key, &content_value).map_err(RpcServeError::from)?; let endpoint = StateEndpoint::Gossip(content_key, content_value); Ok(proxy_to_subnet(&self.network, endpoint).await?) } @@ -130,8 +136,10 @@ impl StateNetworkApiServer for StateNetworkApi { async fn trace_gossip( &self, content_key: StateContentKey, - content_value: StateContentValue, + content_value: RawContentValue, ) -> RpcResult { + let content_value = + StateContentValue::decode(&content_key, &content_value).map_err(RpcServeError::from)?; let endpoint = StateEndpoint::TraceGossip(content_key, content_value); Ok(proxy_to_subnet(&self.network, endpoint).await?) } @@ -144,8 +152,10 @@ impl StateNetworkApiServer for StateNetworkApi { &self, enr: Enr, content_key: StateContentKey, - content_value: StateContentValue, + content_value: RawContentValue, ) -> RpcResult { + let content_value = + StateContentValue::decode(&content_key, &content_value).map_err(RpcServeError::from)?; let endpoint = StateEndpoint::Offer(enr, content_key, content_value); Ok(proxy_to_subnet(&self.network, endpoint).await?) } @@ -158,8 +168,10 @@ impl StateNetworkApiServer for StateNetworkApi { &self, enr: Enr, content_key: StateContentKey, - content_value: StateContentValue, + content_value: RawContentValue, ) -> RpcResult { + let content_value = + StateContentValue::decode(&content_key, &content_value).map_err(RpcServeError::from)?; let endpoint = StateEndpoint::TraceOffer(enr, content_key, content_value); Ok(proxy_to_subnet(&self.network, endpoint).await?) } @@ -168,14 +180,16 @@ impl StateNetworkApiServer for StateNetworkApi { async fn store( &self, content_key: StateContentKey, - content_value: StateContentValue, + content_value: RawContentValue, ) -> RpcResult { + let content_value = + StateContentValue::decode(&content_key, &content_value).map_err(RpcServeError::from)?; let endpoint = StateEndpoint::Store(content_key, content_value); Ok(proxy_to_subnet(&self.network, endpoint).await?) } /// Get a content from the local database. - async fn local_content(&self, content_key: StateContentKey) -> RpcResult { + async fn local_content(&self, content_key: StateContentKey) -> RpcResult { let endpoint = StateEndpoint::LocalContent(content_key); Ok(proxy_to_subnet(&self.network, endpoint).await?) } diff --git a/src/bin/poll_latest.rs b/src/bin/poll_latest.rs index 1b7899df1..1da71fab8 100644 --- a/src/bin/poll_latest.rs +++ b/src/bin/poll_latest.rs @@ -5,7 +5,7 @@ use ethers::prelude::*; use ethers_providers::Ws; use ethportal_api::{ jsonrpsee::http_client::{HttpClient, HttpClientBuilder}, - types::{content_key::overlay::OverlayContentKey, history::ContentInfo}, + types::{content_key::overlay::OverlayContentKey, portal::ContentInfo}, BlockBodyKey, BlockHeaderKey, BlockReceiptsKey, HistoryContentKey, HistoryNetworkApiClient, }; use std::{ diff --git a/test_assets/portalnet/content/beacon/light_client_bootstrap.json b/test_assets/portalnet/content/beacon/light_client_bootstrap.json index d6bbdd76d..b2b77e4ea 100644 --- a/test_assets/portalnet/content/beacon/light_client_bootstrap.json +++ b/test_assets/portalnet/content/beacon/light_client_bootstrap.json @@ -1,6 +1,6 @@ { "6718368": { - "content_key": "0x00bd9f42d9a42d972bdaf4dee84e5b419dd432b52867258acb7bcc7f567b6e3af1", + "content_key": "0x10bd9f42d9a42d972bdaf4dee84e5b419dd432b52867258acb7bcc7f567b6e3af1", "content_value": "0xbba4da96d4600000814453665c4b46dad568d69d0a3d211c70829ce7c5c17549713ed0996c8743e6b55b3797ea19c0eebac07b0e163fae9aa71bc2561705e492dd206730e8d7e731e621d2d7039ded027d9910bd41b23f642c609986a33f46fb3187faf6a0abc1809811c919b69e9ecbe5c129e3bc6cc6811de879149bf856984cc2a5162aed445600abaccb10a1b48694f150de473b893184c8200c822abc86d3d8d3bab7918b55963553bf9be9d2144a36827db66449e2302a49c72837b3e793666321ffa0a45089cb5f6af2380686485c4a85aa460dafff2c2681ffc4dd2a57ad488e53e904734908fa7759d18edb7e58d54ae6565774b607fd7488f013b6d02cd13beb3ed2a41d983f02f7eeac4b7f4222474252ef4538b5b09c3fe7ba6899412839fb79588387fd75faf7225e9dfd65bb46a795929d1a6a83113cc89c390ef293f9b73f336157e2f4abd6867a7a3aad6cb0472e1f17a73f913822642688fb28944b9df775593ac8a77bac24608066588ffc11a91b0c85d3f078be13ff586f7cdc20a23473f7a8c800c039edaa2ea42e15be9dbd47638ff4389b0a4e7daebe365aaf47ddbc16d3737ef8f4ed64da4ff89064056a794f9232ab744f72c5ae7fc674890d07027dc5541eaaf8dc1edc8d8fb4d5c763053a53697d9e5100ad9afa1e9fc888cf1197ad56d34d0f290b5d73dcb191ca444671fa433332f9d451efa4623ccaa1ca061827b86eafc6f771e184c48f4a3ab88c44829cb86aa86516cddcbe07bb52957e926dbb7bea95e9adb19ab3f99ff83279b5e41dd5cab1b5ee617340c8b46536a4e0b60d7235423760c2a72910dc838457a5a6c2d96bb1fe3c8b1cc292af040bcc5fb030d407a283dab7cf28b5fc8f651afb812b2b138c2dc05c2606320fd82ebe8ca7843ab0058ccdbdac8395bd65df3327fcbe1d8ac52b5e8e8970acf53a46d1ffa4ef16a472e24746a05f13399a7613a2b483855e7d67348cc8b51afec047355d3ba2a1f19d1e2fe3ee7b5137b4d0d257942118700ce0b506ee1b8b0c542ac600ffa734a960b60c13e89d3f60c5de14e3a557159326ae0eaa2328ee3d57ee2406ae9dae30d2bda566d5e22a2bf051a5ca0485b32edb939b949a967d315c0b771ae169433c6b683e0f58e5a4d874e4577d8ec74ee5466491a61cbd96f3d8ae11bb3d5818fda22b5f7914e82ff54d868983315df52ed8ce53b438b6f147343af4508813063e68b6416ddeb0eb0de1c494f0b40211bdf757919a28ef984ca6091f15f5953e0c8250fa5cfe4f1f5e54acd9faa8b5efe29a5daaf0494151b73f6dcc9f8b08558535b1b4887d275cd3feac9424be96efd63191c6fadebe8825917b58a7a286cbdba16cb3df97f1a94c1e41260bc4980ec4ed34032e8c714fe1ff769f8a79217a4a25c1efc38714c68eee4b7f8088e75fc044349471caa4b7fe94793d82e46e81f7bcac3ee933c043bcafb97882ee20d9d45d7c459934926b3079411afea06ae8cba6f092824313ca9998e067051b638b77ea5b90fb69af4ccc66218945554d9b78c3a5ea25d7e4eb9d68bbb40cb99176dd8ced6478af77e10570e5329683d66a2dcddfbcfac27f44ca51e7eb5ebe686e3bfae17a8415a2a13b29149c4392e4226a31225ba4af8df06e20d34c0a0b50376c28e0ff61f55588f8d77e481a3bda3eafb6af54015a2fe2b85c1292d883e4b074123a873f7bace327f77b37239841b1849e87fcd9f1f4c0b5e02ebaac21e3fda7c1f6e5c0bbde58071ff0101cb20fd117b265a8e87063f0b4c0ae6342af61107c2c2d0c9a68b39e8e609dcaea876bb2257d5c5a1e09c0451782ad560b8be7489a4c1e446b1fefe710d1b5d5fb2960d05e931f6fe0b6b85d4a9d4609370308774952614e889827eb7fa6017d5ab5285494620d2a3ead19245e4b6d389d503e7fb3faa7d71eaebd63d106bddee15ccbf80221a12d4cdee182fdabfcb8bd84db3e84cfa6b67d20ba17b7f96f2c9a5206dbdb251094ea01b174f664e3ecd145b876db7b5f900e23ff823e32cd19ee8a2dd30265e196615c6ce66d688fd344d68ffa7a7ad53e1570e5849d06a9d35c26cd41edfeaba7c0fffa5e2e017876d4a10453c906ac9f569ebe129692d49e6d4bfa42a4fe8f0838fcba8107576fa0b970433e1930c575f5827593bacbf77162a8187f7befbfc427bfca2273d24ddc67d7dea6116a1f25a02baf10460040120b6570c01b69a742d260351e64c1911daa80a4c8ca60e2c94b275c864f76a27f8edd99ae770d666f359cd4596978bbc50151ef313955cd867e9b1d4a76d501bc9999c1a5390cdc76333912ed4a3dd34290669a44392917052b1867d68f5ddd332f64e380d4631ded0ebecb92d09bcd7ac2a6f5f39e251f6b1070d614f716e2fb95d9f26aa8b1f8f201e6d473b2ea2624eca1cf297934720ce8e708b2cd1b992a9296232cda34f470a6d79f0ae5f2025f893bd15028988e14dd8074ce97010091de70685584e28bee1963f58a262c85df328377cb0c5cb3f39fe568684439916ec121766afe27abe8fd25ed47c06700b8629f27be989ae3e439aefec3861d3ddc2eab0281868e35001e26f98d7bff81c63c22ecbfb48060d0d8d1235ce28d9080dd2de2ac0408d583b8567309c4dbb0318dadfdeca8b8815fb08dd266955a05101c8a2432530535333ecdfb4f428eed385fb25a101c10a1f06e0d921978f3ea9f999459c488dde6035c1a6eca88998528f8e144b36320d6bb688450c9d394c3089d509cc8a906abb6c43a8b0537707c5bf7b1a9a7e573829fa3c9a415fb0001ffa4b4227e15f1e1f22d65996933cdf20ce49ceff76834f690caf6e012e209e34a4e814ed62d25b66424d5a788a4efc7aae897eb12ae3e51665f478332181fd04a995696afa831ebd6056629bc066cf36ddc88381d3c88fffd68e3cdc1fd9b06105066119994ae81040503f1f0a10c4153a11d1e609adfb9018431c31c1ff2807faab0e7af0239488bc063dec1190981964affee89ab22faaf23e3c24cbcc7d769e7102208d576bd26a640878650ca345aa680befa367dd105b3ebfd99391d53c66afd6154cfe7dd8813fe39059e8dc5027924e25cf94d13a9fa4ba1f16cfb442c8a8d3f898d141d9efae49249fab1d05cb3f9fb900aa0ee6aa232911822e0c17998201c896ee15deff92aab0c34413d132ab731c682c9f3b3d745e6c5e18e673c16a56c4646ec0c2ca04654bab28bb7a5ca579a9170ba9ff3e5363bce737acfdb1eac18377e33978ae4a82dba9bbd4419221e58a10ae80f91067754051ad9c16606b72752f43ecaeeefd9f0af140d0d4461a3d890cb07cbe2a9b001571001fefcc7f0e1b92abaa097e1566d5340853515a15fe4256b83ffe2b723e60e206b75f27ca1b99b1164484197d115a93f85aada209f8ab8a31ce3a66f23c820698febb8e95ba96ac28fca74bca0d504dca4cdba7e85bdaf7fef7b0f17d4b6fafe4c3e9810ee9fc1a83466fc3875eb8e22b2ad6e068b9b18bd9f60f9e66f823cc52a2ea0eea5a1c3e7756d82811c9da030bbc3a51c1150ca8cbf5ba38b106b185e0ac4331e8a0d653a66cad60427efc8b7dbdb817999e346152c197e1b2d61a5a9d7f2ed328aecab1ffee39b76c17dd3577cc399ac7c7e1cc48e4fac0aacc1451793db4f91b593f0ca06236425417238ea6d40e1837a9928af864d8b34fde1cee5bc2bc7e69bb9908c8de49df8c821f0fd6b497657b4ed5cde9502e86ae3e6f7c15189a96b31d30f59faa760de83831397c7f99cfc7e23f2687aaf2ae64deba1902f491299ae927ed9c10ff485f576cef160dd32c11e33003c9eaf468db444bdb715d97acc8df5e08e6aec88d91f747e897fffad73af7e05b0c5cfe23deb931f489763e876088841e9d7358c94619229ef27149b51f0a322200c103e80588e1f6f31a47f40b3b858d0995af11b99d7baa4c7cc145d58e14c240954234e32691001e9cdcde67429cad3962f37fd84a7c61857540799b8ff3d3cda254ba05880e680230712a0618054dd0c89b862e419172a0282277865a2dd45e14a49e31e73db870d70f238a29546e54eb601cc76b8837ceea671faa84f096bfb4b7eded007e12d2efc4f9ff8a421b2000a75c5a01695ab33f027429361fc9f46d0bd883d96a1f9b4b329a9c7256e45f13a298590c0ad15e3c16c73b541bef836e81ba5e18c844c1165fa23932c40287257bedeea72af52893990bd5a6bb57df63a2b6a1565680945f87326e38508918c0020e7f8cc2a26e381e34d8197cc45e0dfe975331d65494aeabece73b741ac9b192e930439dab6b62b91a9dac9f909d78111dd62a5f0561f5f47a9a60c5d55f309ddd4b7b94efc87dfab8effaba010041abafb8757d0f681e1a25939cc5ecf764bd83f2832653feaa0a18d86336aed2c73c84199afdd03171e74fc96b865d0bf7f4f5a54c15c823f27b209b5d34b64cedc5baeb0184b2d9524b012a2e4fd70dd539db32f6964c34d16399a16c5499597423149a97723cdf5b5deb33693d456213793adbe52ec75ea8934e38ecd9299ff8d57ef12e9b4e14806d103954b86321ea42aad93daf0ea876befa5bc2a7659b3608e9efff93a7b5201478798d65d892aeae9ded2fad2ea4007c0cfd35727d44f8ca4c7a52b4e331621e7dab1aa1f7aec02c7e7c3ae36489b421042a9f331cc609990c589f1048c10d1ff1873e9a871477ec91acfbdedcec1cc83e70447a117325ab16b1a69389f4f786acd857064e82ad1da1257e3ed9820be84d6972a5f90ccd96c6409124c845a3feb23a7b862dd28e094e2620ecc39fb590e6cb7444e66f202cf8922ccc47b807776a672aa35e4434e27ba331d0666ee19b472556951fa250b021dce47ac13a33264fcb87597ce6a7d66391d19da9758ef1ee7d19e1f774ce54c5e92a487735cbffd941210fcfc8c42b7af9fcbe376863e4e919916f0d0ccf8fd05d1d7b3b41401864f4c179bcbdfff434dfc4dc4171d35ce0887a0ac8e3d17f150411a09a74e02e47fb8f537f3add4377e0381015a79a5fc12fd86b521dde790030f0ddc7cc34305c0bc5e9e3b22460d405a3cf28761c0e7ada75fc69d11430c04bf856870b689e40491f49f76d18b6c62ee4a4937d2506e5658b2e71adf7fc9aefe03e6fedc0251a99760209fdad863928ff8050c39c8abeced80ecdb13fe10f0f65045f2e2d41958e49bbb4c4fc1c5fc15fddc7644e5366cb4e4416bb1a6afda3a8bcc5f7c51ff01135f7643dabe355f4cc241943521cfd15ea8c2e51bf44e17354353436ea6059f90e393790af9a011bda79f84675f83d3e4ab18a7530369a953490c20ebf4430a5398bf4738abe51a6e43974999d316259501c60c8d3a4efcbe8177833c67658921351d44588c2339704b9d6bcbe30f95b94328cf423be2fd387321e447dd5571a0c1992d091f4397fc47a835e25c6355488cbf4e2a06984410a8df4fb8bf596927531d59bb74f72e147453de54b4b82c99b836fe255878b4156eca6caac99209c9f0054f32c2138c9ecc834a2640d8ea4d6cb521bdc12f12d055774414ab86f995032ef0bf03ad45f1403161b848bd4ef4400e1778f32f5cba7274ffa117a1f3c96fcd6f0e387af6302ce40ed69cdb50b88c76388a3b80c3954c710f6617e44a986cd65909ed542614c1c6f80da78461192553d6e077e9bf8ea20b6016cdc0c995ae07bf473df39af8d0dafa160f252d58d394930d46ef2b2f0a7d1e48d8ef2aaac8a9ec0b7f00145922883de52436598fdf1fba9f1283d31b70ce0ae4daf3db610d970ec2582863e40458de4bc082dfaca451d756ef83a93baa3fa37b3f82ab8cdaa487087eb9175d846a789099e344b2ec58eac67185e6305a81f5f691330fad31715f8fef45e835a9da43a571a016a35bae46b3415ac704c66bc651fe079c797786e047187eb8c3eac665b521beff69db528d5a49568f2eb0030ccd6d5e19ad4adfb271ed46d44024356808f77e16573c4f0aa225694857c34c5f00bcae4ff15c91bc5917502dcb84b78f04e2627794268b54d9a670f0b97d9cb3a5ec637c0eb9f0922a70ba445fcc20710c56b7b05b902262c081958163c0036ddd7aca4daf4814ca4fb003b3f59a76adb7390155e0dd635b8c04ca59be1a0768463d94f49a021efb43645da70770e4b2f4d00bacaa91df4572fdc8903ff47df32da286a5f14a3ed8717e537b640aa123f6b64e5db9ea7e3abe9907fca059493075091e10815eb342b85326d35a5d978515882b8258c71ad6eaf9eebac6ef8284e4d7925d40b48fb1c4ed93ab6b4bc06411cc178e8ecea37cb50a7bea428417ab63dfa931f0885ac82f5330764294d0297003418e70fdc994adf9d0f23486520b8caa560e8c78251fe9c95861a45050797db4586e18d968f6104dc18c6dcb6652ba7f5f8504a76cdbd56c2fd9bb5c3b33384ff6718e9cf70fd97b62a4a2384807a6d5e9151e890ebf9e797c61b0eef785cf25b6e1f930320cf1ed97cc43490f3318d74cb4a5835e742f8ff9abba5562e791eac25fd8450b4f5458fab279ba50b06e2902d04d1f63dd6d08f515a87b1f13822f7fd88e464e384b2ebc91c2ff0a834655c632b5b7e3099132fe6adae081fa6d756e57949bdfaf00a3474b5b4b47442d160c66ad76d9bb755b144f49553feac5e772dfcaa944a31f4ecfe989ff4dc092525d7e95eeb938c87e22de2e18de8891db8fa0aff02dc0c936ee1c5846f454e6dd5a2a8a84111f213242ca48ec4a0ca42de208114b425884bf754f9891a511b6e149009346e2978a89df0394777a636bd6d6cc91cd06cd1395d9c42cd5f278e1ed46ec4799910d6ac90fa9fc346a09a83a27a096602b4269da59eddd4ae1c2f3f30cdb05131399cf3c50c913c683ee1a95ae748b674ccd3ae95b037aef9c98bc4693eeb2c68ec35bad4dfe85ff73b1df1584d3c99ca62f44bde2d01b4a1a20ed9e8309042005d373d3b93bfdc4ac7899a2f4fa9498275caa522098e7ac5d756414e3acbd875643c2525229105cd82a32669590f23573755c92518134dc29ed20ff7391a7d809a4a90d4f3ccd98417306079861565f24088c9f7145f44093f6dc62ed87b0b877110d22048df35d11a9c55f0242a1a4671ec29a9089afd2f394cba94281f8c21f56ae82332b7b04a61d99762498993fef839a27bcc305b47f0746f24394920e5ecb28ec54e49e6a6207c63fdf445b561ae777a5af4717bf84bbcbfd27b47f5a72308e46589dc13056956be4ae308bedd8e7e8f0e796679de5855aca48d26dad61e97f1b66681ab7d3277c7f77e1d69643db6ef966831fec812c326dca60b33f317a1cd6d055aecdc40bd5bd2199ab738595dc59d4fa794d63d7758c06a4aac989686cc8abd3c63122f089cbf5398e933313ccdd960903eb597954b2749b848056b996f5949ed81acead2823d11de1925c547b07fdd7a0764e65d42ba4cfa5277424bd750b6dd6a446752b4b8821949fdd4460c3ef0340de7e9687f468a9b77105354b55bc5eeffba2a27d845f79b7396446353efa313d4422bea82d8bcf95897b3f15aba174e91059115e5e0bd02dd9aa92397f35a424e925c297d70be682f17c470035b58ea2f17703c86333e5790dd1630559e4d4a0313cf7b069bb2467ed1a53f4ec4e2587c49d582a4b21ea988e620b91bd4647297050d64aec86b628bcbafc2106ce8c6e8f52101c0fbce580b18b309d3fafef0c81a3f1c7ffc66585b007270b3868a45bf9168ecbf82489324ca7c1feb0f99b27f9d9a294481c95d5ccfe1dbc888d1e2c4c506d375cbc89925113d25c47ffdf60818744c832a7abc4ab36dfb4a13dff1d2830e9e6fe3fb843a442303b1eb8cb8778ba9b3fbb273a8a91f5e19e09fd2a37738aa63fd26a0b630bb3b36c219b79831562877b484273e72c8b4320ab00d328c3bb1854c99b6aa8e2ee69d767cd5a205c8982ff75ce1a7a46cdde1651e3f8f1bd79ed3eb595e9efe010d59ee3c3fa9470bb03c285389790f8ab442884e4d64b0a479066e1f62f2a1561e0012e44def9309af5566e94d68e4f5ce455ba4f9afb0e662287f87b5b96e0b215a1b9baeb8fb46a52e711afacd1ba7bdfc50e1ff7305ab07264186c83ceb77cacf008b6c10d56fe1f4610cd05844f7e44af4f08e7d7d0e8f55d0f3734956fc9287e2a8294102c2d97ac21f9d741b32c3eb9086bde7712e164865bbf1a84f14d48e0b38f98ef54f06af33c916db45e6abbe3370c9e47c5a5f5cf73b4b784e47bc3f5574155c804c18ee4954f7e89c50ae9ba4d03123093a6500ded8a6118f7dca1fcf62614e68f38d2e598c54a065f228eef188cb7aaf1f41df6f3d4d788a88d204e9e285034a0c6c5b6b894e232b844a4696a3ef7d8f0811e32f6bbfffd557dab2b588eb918d8443d0a9f4a7c82b42c275bca9865e7ac38ca3e49dd150fe2f01fa8df60d6f581f050b3bbe0ef416ff657db803c0c4995b9b871a38a5fab90bb90732766d35452dd0ac64971d75a65d744baf6ca2340c26934f6527c29665ef128f17c20d8c1fcca12fac9d898893a664c600896a922ad526c6283050ae67863d2ec2f47eb01b1a3e19531a2213078edcbb953b57fe701f0445e95b6a78e45d1ba06e3b9077847e1017f6085f75d3bf0223c98fd32000d555b73e6c51ab57246e15d22531693894f793cd27d8fb68355030b0f7a357ab43192956b96afc377de9b07c41d30a6a23f461c47f40d5e2a023795c06fda75737e2a5143d325b86d62aee8500d1a76c1a96269817f465ed46b40140b7d892b68ab40d3430cea6f598b8279625deabc631a7114e99e43a36c83fb7d37a70d742d297b973fa7e0caf2b47ac62f0750e0c22a59ca5952ea74f0b59e16a1e3ce1b391f1a9f28345da7a5f0b37064ab736772f7941bc9b7c758a4c56f1fb5455ee551f5e9e02e8de051e339bf90ffbfa75c45319cad15e2c5aa87b98b604568dd1eb46c9b92d553c5c4268a1a2e44707b3e6538ebdfb5f504e73fd80b0d971a6c280fbf80a35a4723b9e1db4566ae59354322f6a6a2ef45c60ac12ea88edb34c90fbdf7b8bd8708cab7bd1a0b29be454c3479f2629c5018fea8285f03390c355e0accd89f6824d449a38e6d0a2ff8690da806ee42530867b3f363b3d49e738df1563c5600702ecb5bab1726ba55fd0d4ace1581d4f4108368b24fe4d4090b371052098c4974faa7e46e82cf07589822a39aba6b03c2f19746827fc4d2f2ba82df5923d5e2876872d840b657bb2646c9713cd61a83510e5d00a754fd43eaa7fa3a2509a74bc7076096b720b73ea207b4ca9aa638b78f4c0d4a4257fa3d3de17c30507af0a058d99db8706820cd18dad632b954374503edff3191fcbfc5b2b55be2b0b7504de5fe097d97147f788b55f6332331101ad4204cf5b18173d4d0809c7d9eec152c5cacc981b25c8aab74e3adfc472fa13e6f6b3212bf2293f96a2482ada1f4ef9dc524c2499e970eb4496da67b6948958f998dcd398b3aed89d5943d1529ffe74cb7a7c2df90043a24ec03fb8adfd9ed6cbec980b54d199f665e755060c796c9351353a23aa988ceedc8cee0d73be4ed1e3fc765edbf7d8dd5e102cab4181e53ad02a5fdcca3c534f9110e4e7f292f5f4aa5c3fa49ab9877cd3b1c6196f62ccc3f8fd616e08eb364faee03e79b96212a1f1887b85b3502ab1cc20df3480d71aa3db7f60ee2a3167ca7a530698c998ac2352f5043b632650175dd345a3bb805c2fb200eca4612732d72fca8a5501d73777b3bba9cc398f16ef01998e922d41ba8b0bac453b80d453b7ec869bd0d79e9a87cbe0fcbaf47a11849c6695f3b877ec1df5cd248bfb2296192da2af337d4767bc3008ae01b8228d94efd3b1adec17a5f9b2a12ab50175246356edd18bd8d5b363d1bdb7f58943d8bd84d91f1f324a74c654c6307450612e94635ff12c03f08ac4d9602e231bc81eeed25901c51e8c786f66448774e8d79492af9721ddf0e37a9c168287307f2b519864c2f897fea1d8a4b53bcc9b2c5ddc91c84b8c8b090a09da8fee5f148abef2304a840444bc005dd7652b89ba5576f6481891a8a71397348ac7829bf53e3c58e5e095567ebbc9848aca8f2b8d3b6c09af750a10f6a47bcc6a45480820742de945173cf4655d93916154597d1b8de6b5b01f18db2ff6176f0cb89b68f62a1bd48bf7ffb44274c599670ae58084d57d85f244811901762194be0023975a453bb177f136ad9495e9f24b0a781da39ab7832855952722ed031fd1820aab81752d67f23f30a6e3301f3729f6cb068ec65e1ceddeec8b2c163e8624f574a65cf8e7b81570277a08e035407611bc2b136459c96dc986f140dcca94d6c69784c79ee9100ec11d240f95c7920652b63d056b35fba4582471c23a9e5dfbd717a689d9776fe49d1f8ef8fc43b530597b6cc734edec8aaf1c19138f7c65b21766ba935b11ae420d2fd0945cf46e15868805dcbd39a9223c32176cdcc19f49db6ee857aa5b6ec01185255871c4f65edd837e51082cf069fbaf7c841f13eb91cf801ad1de660a0acd43fa5b2a7c49bcc61b744b05d25cc605c81fbfd829032ac6bfb8f328685938eedc8919de180badaf8980ca0745b79e18bfaf31ca778080ea486602c2f9b80db583b32c07353f23b31130770b37863f310ac5c5a9560b57430fbf5fc37359e66735c5867012f7059418714a76fa7c5cabb914f3f9531e4c8a0ff7f8bb5bc7b263660982be7e50e565c0ade5633d94f5de6c71ceb4af1ca4ac2137bb7c02f34d88860e312681e195320727fde90f17f982d04076ab3fdd2357fdc2037db0ed17506f194426e43b065b70ff8460a6234a93d0a5c54024e1c7593815c108cf6d545718b06178fdd7dffdafd222c94f649948e1290cb85f8b166d82b7ae97b3e3dfbf3d0f381318b0a15eee35bb3877e3b966181b5b521aeb4ce1bb11554e7f56d9065e4c849e2046ab6470bb9aa3fc407b0b676e60a60ea7570b3260c7a987a5b2e949ca039f3db17608b6586c169099482869b07f7325720e27f56d07a4656914b5328648296fb66bf95b76578a8fa4fdb83daa7a395008149fd3cdf6fdcf1c80a236b3a1a96e511898cb24b631cc56aa7c7173c36162bf4c2e4f5afac8da6c4385ae6405e88b25c719a464b9a6eb2a3453ed21f62728750af1ebe768c7205e8bbbbad32f61e1ddb6bdd2556b5b21bdaa11dd85717b5eb28d995889ab0b839d8c4a6183d3804cb4403c361b0b1d27bd0cdfb98631ada8be88e17ac77f2a697ba4fb4d98d96c01400454e9d80ef89d29139079ed143e50151bda9ff1f43eeadc6cea6e693d74f4cb1cfe09696d396c25ff629064aa2d8fe449bf9702b19634605d66471b2f74f6daada1d0528fbe4c76c5ac2918e48f0428f0d4388073784e68fc2c0cfa83bd1787849fd849762ad5bafe0ee3ebf8b0599b5a98a520a5be01732d5031bf92ad9ef0c235c582f4f970a502dc4e38ef8bd6e7963731a8e1fb1f2d8bda64d5989d9b8e8971140d5fc36ca356330ae603795e61ef15758b603b9cc62fc0fd03adc9988a7f62b6a18b60eccd1bccc3b27f03dea73d9300f38d7dc40123b365264b04aad43e6857ce22584d3ddd0646e318e204412350dced56e02bb8f30ad1cc553be2c11c989ad8969ebff9c3be0db0ba9cbfca59e7b053463a5fa16ef00c33c308df36f2a8d994e1d1d12297eca66ebf0295772d0e9ba8e6fc8d6fb36d74b86c4459ebc2001110da0b6273d04f8b0c23a16f64e405d72515578b0f2111a7e9c438fec08c60e21b42e396bd9cbc1eeff6e374978fe3e39d75e8fb3eb96a6fd485e4ce9361875470a5c3ff43a2efa1a00a78fc104bed02130fb180409ff8d2a8472285a0016c50a9a41901a4902c19f21e2c120044eacb6c48d3ca1ee79780370d47f296d8cf2b8d473b0e0dcd5feabe4d1d42ae77e7264cba987404969dbe514d2b1ef5b95e06b09d2688f2503ceefb50d21fdc4a897dd6deb6c4ca27eca219c58c1182383a04f500798a3a714802a2fd33cf2cfecc8719d925705e4fd8c491932131413b9f5498acd0463b02d4e6345a4f5ccb2c95a9ec60ca4f6acdd6ae0f2ab1c1f78ba945fd1c8d0d77b374281b49ecf0fae9b27afd520e577c01460bdd07ac1c521f94f3d21c4a87871ea9dd103323ace0bfd122a4993cde5584b69f58f2ecce55e424232db799bf2441aae86c51d22c8c9f4d17b94f786157a07dd8701a1dbb2878c3e6b3911a1d716160e45f83e7565d364d4b3ada1374b7696061d42552dbcb7647c8e4d91ad3e1846cb902c373b5b36e5a09b8ef95628c6c5f846e954d6c02e446210ae89385453948fe1669e52e185f7104efca5b505b14d17c0e6f9719ce4b22f71da941caff7827a8311a0a366afd8d274c76ccaf108626260bcee8f9c0f1d8bd5f979b6b8282103c2af61aded55e0f5a80b2b192f12c42b6929364648d9b4b5680b0ed1a77a21086910bb0c041ab86fc2b25aa395ecfd5d255413eac364998a091181ecc091c64050fdce03e6484815e580f21eb07e6267719a0d88b2291648fc9ae9ab444a5de7e5aedab55d27ce3f400c7dcb57bafcc24a30daac9eae10503b52054ccc8b18220418a850392bc20ec3f768b3a6a236fc237e0a197df2a164a3e49d4133423226783f49c7dd07cb840d128eba5316878e0f85c3ef30bad7ca5ea8a681ac8f6a216abb0d90ace55f37c7179797e8715c5640a0daa39981fa48ff73125f2e1ab1591402515f7ab7b533948d7987b3f237acb2821f2746099d4b714fa228fffa92f42d0c9929e912ca5eae07e07fdd35e62de79ab35f49543eb0a03ac1acc99570289106966173fbc2d594cef0da9da3ce46c046802c1716b380a307c10496b2bc330c2d146f62ca8d5dd254e58fb846bd1a3e50a1faf580735a473f6e40ce67a4696a4612098ef832ef13a82e756bf9b6431a598a12ca8fd80e1c1c52b6e66ca01f6331ff5bcd1821cf35df7e1288e3d72ce727ded3ad0ffee267e28737607c70aa57f72dc4aff85027dd2095866d46b070b26eb4cfaf5b2e5591e9898acd7be659d7780f9de34fd04aad926dc2cf06cbf7992965e7db0ff906029eb798f09924500a6ea5454425783a4f8f6cf623753e36f13f1487d4909bf552f60b64467def6ba257ffc25aa955b46ae2378025acce6a65e90f2ad6474c09ddb1f24ed893baba3facfe0033fe4e5649357d59a4077684a69df61933829bdd84909ab6d684ba7bccc57b5d4b67aec5a1ccfa2c858017c579cbed366c29b6cd1ce009d5879ffba0c650dc18e683b9610e651586954365d8dc567dd0a80f7785b3359e6371e699d57c61c08b9f65be0a23be376f5241a6688b918bf67f32e4576d58a6af7851edcb66b6b8745fbecf1064cc60ee6bc3de69b18cc411733e9a6af08115c2049018342146a9e518299b1e1631d9a2bcda23078ad50fcd658666cc7573031dc837d59df6836f02583ff70950c495b82c8ac1c7c1e15d9c4c83ac8fd9dcbdb44c81120f1f94695aa903ce6db48950003a556b7dc06627069806e71398860c3b619f1060a774e16f4b6dbba5c6c831a8a95f290e17b178dfe3f935fa9e897559e2539e4ba3eea81c61218b26c931c8a1224895f1de6468c97a89d14e5cd400845900af012b4d4d6e29f8a79215b052092c0a9e158e43cdb839c176d75e6e39ee6083494547cf175408d7d2effe17cc862f1246be9434d9e12b490f186be8f6ad7d3c7b5bd068ec6ef7962f49207b05af20eb5aaf7e99f80408556177c7a186b7c7432bdb577d7bfcdf3f485b91a57b60780d4dc41def326e3915a319aabf3e82a6b9708245648314723d2a331974f2a6bf02cd1af9dbbba3ebc42cd8d743724a4cf20eceed48902d52b9ab9f3c3e18f2377970a3fc5c194bd4cdf57c51e2278187b0e9a57f77ccbb39b15d7bcb76a84b0defeae1cd30b59f1c1e41f78f665e6d0a1de233b6d37a8bea9a3bb7fccfc9b102ca6fd636e48a71473c867893ce71f783c3659650266911965ad2ceb2003457a5016281f672f94644c5b58d285f9784e53a64021f3f48c949db5940e9153bf0c34d4ac8ec2628eb792535dbbe5d4547f97606e8d0811a4a342fcd95040371af516303c686793e16b51c8c107b6d1f22b60fc13ec118307aa1bec5041f5d0a9d6c7ac570632a609dae75d58a9b8004873b5f805a0e08482834477a8a9562482c88a9288b48afc8b2624b975f7a0637a5da4851cba6e5a751b891c46f2e2d818f4dbd516b7e6b46c83e8246d0aff2459703d9376138858c08d86ef6d6f3228d44218eb94244698a0bc448c70c340bfe857d4f27e988fa7467820742d641d5fe2679602bb5a146549e0e3e67fb6726d85834950e5c53dede23e0240ee9e3b26ca6cbd9c74562d77cfcf94b4269bd5cf892698a91c3ae42726ee9e07c69e6e38803f6631fd69c2de4a20c4f214a774a8b99eb737b4e8da5727b9dc0d0915c7eee78b1bfb42b9825b1d2c4c9442c952213d17cef7c181c23487149b5b681d7159ea45450e0f25e71aee4b9b50032f86ffc9f36ed9bd7ce63d688b9d8c1f084639bbc7c5262e9e0bb9eed8f7ddba446ecdca3984cde5d0e6bd1195226ddf47c895a64b44f27ba82218c48eafa271502f0705ff2e6f2cd291479c623b3477d67712c94902cca20f4d6dd7e09b1d252effa7c3800e1739f1fc220b91ff440bcd4500176a509889a104944318fd4bb4805d748b8a5a09656e497b46e4ad5ee6bd9477fc41cca86b66014c4dabbdd2825ec7256082774a6fe9ecef481b98ecb3237adeab1f476efe315fedc0d82356f60cc17f8ec26d9f565b16380f4d93f273c26c22f2a2c25c2b03e6ab418cae19711b2cf47a297f51dadab1dd129b0cbf9883553eb7f3f052a18a010f802c2d4d0fb40d891e4256476799d7e11ba0efda9aad41939a1498cc7db0198b09411d1760388527bf4a972a7a06cdc7d211bf85248cd0b783624e5c836c2cf3e1406d8427001ed79a8663fb9174d20d2a6c7adf02b5a0e1d4f7446252e082a0cb1bc524cef2dd07a9d5ffa7bee2f58d8579add29521a9ddc944532622424725bed49f2a6f047a1c770ea9bcbd8b9bf99e3e7ab09e8289b495780a2eb48ec0c45430942e7778dcdccb1de1411d40ba7de1f29cd3270d63ad58951f58275db500eb7c7781843cbef8360837a200b9dae2ef916de0c7c5c5e4c99bce7c2b0f4ac3491bbbe14c01f9e09717e7813beaf694768b53ff3e10dd2bf72ed87d239d8a7c9be4b0e4cb05e08bcb8d93819e197a462ca20b84ddfc071566f4124668c6c0f3f821fb2fc49d1587b58c87f56d3bf1aefee1868abcf44968cb526b7d572e9524bda19d38b57d55a13e529f457e1e2b2f8141396d01461774e350c1155320997151e870cc57dcea9dba96ae9962b0da0e26f21a55e8feafb8ab6383620d01c2b5564bcbdff7f79cd43034846f6a2b20b3da0717f99d394ed1e89349ca3d08a91e5f9595cb8ede82e07bffa174a1c99bd34887850917f10af5ade7e2bb7b1676b86d80e68492b838d6aab7f3f38f7463f2b944c8c2e8f050f93dd47b1ad02e3d7d3b4bcff207f6607eaac83aac5c5aab88cef53f6cc9c25ebcf8e4dbb0027ee977265e85dad4d35a70af240e1714eafe427ed99e7df48dd99c16e9e9a4ec56b0ef79b829d26590cbcf396bf41e06952a3ed7594837b434f5b90c166508aac0b6ebe8141e177e60caf14fd1acdce80c56cdea4182fca2da0b30ab58cff9b80a73302027f19aed6655fd9a86f236bcf134917ed8d7525c3447aec2d2207cb6c4b6761e885b59fb113824188068c32cdf08e973e0fc623e67fbd5bccecbf1ed00a0012df83dc254ebad178b28601d8f8eab90fcf97ff9d0189f9588fbddc7a1a7ba27f1c20427c61a46bdc2873bc8ef8c546503bdced0742951e3dc2a1755f1b0f042c14d5374d68310f10a87fd66287409129ca260d1e9aa34c0976f8cb5bd8d2daaf2761b36a5d3001bcf5fbe1c9b2b3c2b59013d6249a97f1708eead3eef3958ff9086e58e027aa039887b743eb03e02af6d465935df9605072207b6c595f0d9ad56896f010c8f7014cb9eac8f2187ecbe589010cc6563c2d9799ce3e10b66c546e9ee22e814c80d911ea853de53e83190286a87cf262d96441825ddfa696368214fa6dc5658e2c7aefdfa1644376b467bd295c9f1ac597c3a9e8011f03b02adda1cb0f77705a068d6ca6de5eace04fd4240d7972c777453e4f502f0f8d6f7861748250e448baf04f53ed5192ca782d008ed4159215c1031c37876e15a28988071384783d0983bb111940b9881f9c3b4864d2d220d742f9f1dddcaefc58bb9a27d30142b67fb074df8e9324c7bd3452377b6b761e2ff614c6f00e476fefd5396e6305101926fe8d6d48ce6da776b839ed7e1e6e64ac6bfd4dc597c221bb813c741912ec952a1611285b0a001adc61e51b05715129f9682252cbc8d40228401e5b8da773a3b44b23115d908ed8864b6632e95b676914634f4e779b76c4d920b0ac381bc348f2a7b496b90a4306b53a4ae2b8ddcc99b5fe0a10eeb9dc2081649237d24d52095f388f0baf408eaa1075ec09da6eed829ea2031cf95ab4365c9b73fd3b37305aa3a08964c995fd3da9badb11751d98163778a02abc1a08e1d52a4f315224371a8e582bde2ca33c0515d238927e1ed7712f03724b6280ec30f71fa84a30974a54bc0fd48215b6f062216407db840ed952379fc0a8a8c8a24bb1cad4c6f25d00e0f5a84252c3b9d11c2646de4b17cbf2c1cc6d651d3d479014258da22d75789291c510d28f2289b947309a42a0d8ae0f44a173c4c9eaa09893a271d8d7461a774027c234344c4c230ddaa857e1bf4dcd3ad3735f5b4d3448edf90c062e85055588062916434db91a0032c35b6d031425ea9eba1fbe4b3149591c90b5aa94338f5538dccd2654acfabf47daa81da2909f0988ddd16a61b2d4f6565ca852d94a1332f0d0c87c036ac4a9c867ad26030f216e054c9402a49fa5b406eb658e5f0ae9652c0c4575f0872d6065c0264afe7320ac52c3bac84b7285d0c07bac6eab329fdc8131604afd108707080e8df0375dffbc5dd180a798a327d50fd7e2279521b2899888504b9a33dcdb71f89e61093e5f128b5515f00eba90b8f0123f4edb0a485bc1e754e706b7aadc93d89e72e37df01ddcfe622a9ac8e33a4c30bfb7ebcd14296bff62d931007e62c97690636242af6d9875e260faa1d1aa4de4d906c679281d298ac932818fcdbf1ffef2ab9287cdf8662b6a6870f46c497d2364c0cedc1001f3d3ef7b34843f74a1e573a15d91e00ddbf851b3802f171288e0f2fde77937efcc50c2526c5cce34ade8478b148ef19f9454610c2fa62d8cc3983163be291b748dc4ed563b853fdd82b45d0533f5d5585b8d25f6c08f2ab378b803cb0e7802575fbbfd7ebe91c429db8766bd825f3b8ff98c76cee1a76105e2ff7685f4705499108d920dfe2389c2c65222f4ad435c78fa86ad94bcb34a168328161f74c445c8df82f296c5a6fe90d40c0b58d67dd0a07890eba26e2e3ea159ee0265067cc64a364eaaab228a60a9d4a153327cea5267f0aa7d6767ba2109727c244db2ac2d428e1442c200061d33e714976203a663913cc343b973a81b47c0a6832f5e36810c31f2e5fb9726a2a2c8bc7eb2c052125b5c287cefc7362c646c50427b721781d5fb006d018683ec7cc115ed664284748147adec635fb1d8d7e2f355239cfc55a325865523b44b795d389b21e93698eebc368e175b69a5f5faecfb58b96759b7164f193bbd5d2ecf5abfa2602cc23697cfddc6cca661ec574ca2993393ff985fb918fac4435f8177f1c84b8b51b98ec2c0a3e4c36fb09a181b89d93ff4082c9bdaae020a647728ed02ca1fffd408817e63f6d6f0d588873a25a3b8c84b6b6e9d1890ec888aa75eb293463848db0856e34a92be0183e2eb6b06e9ae045d7b9bf9714649fe70a1a4a0d348dab35962e42989d9c2ae38f92224d020ed5f851a3753b581261da8e2ac9511fe1ec0bfa29d3dfebf7a52cafc86ca47c3d25b89d850b20dba9818b375648562e28f93efbba12cf14b7a4203eb946d497b2db4ac73952e72064a48d6e894a35e5f2a82713b81eee2a2c754bc6ee9fa3ebb180c6bb438b9148c53f40c5076098a89a97be4952690c1f5635671f6917c34fa089850b77eb0a4b323ffe8abe46d9f16feb3fcfd7f40f2ded29ff70a9debe2531f343d0e1af3b0764bf5969d8b9fa03429759c29d22701a66bd246c6ddf5939136ad5eae6fa8775dcfcd28cd4e42ff7c8e05a5cdb1d99577a28a4b37aafc0d3f1553e2d2f3a31ffd3a1179e0b0d4dcc248b3b0ad89e3379aa1e404a85a9d33e4d332b970391c22d72c0c128e8c60103cf9a1ebdeee02843e03db59e1e9b8b007dae8a5f12ba87744bde58a11a1c5fa8e137dae0615b7ba3f2b0edc6697141c4b5e4d2e2c00bdb091907501ff54277e541ddf29897d3b90b45de171a78f54f25d7888bff7d0c5b0e3b061a463a093042a9026cf5112142cb504f9906f35cf99ba6726f366315c01dfbfe99d7ef249132b0c3a687dfaf7da86dff39929ab822328798f52de6d546632bb5b866598868a8cb3bb366fd9da63845e2c893d992201349e422e5c912956f2c21ec96db9a7c27c9829f1c7096dc2685ef66294f47023bddc418f91a211e23b25ad2991bf3cd62a81c4511494fbe06f7cca4c5281e14307e52f9da671e7627de5cc5c089697437bb683dfc9e0dac291d47e18586e0578e1d5365961b44451e282f6a54b928b514ec459c54c96e18f98851ab7e15348e34f47b932ae50078019f5d45f42d36f0b76fa4a8f7bb57952374c8e9ce09020053f97e818e2097212edd14bc23e7a165296c4e7b6939fd0720a865e05029bb7590f213541f05cb8edb197e6532b88741eb78ffa6c1103e7be4565111ac12e5c3d34cf595df0700d2ec64d312dbba5018218cf5a2b3e571c79d89f066c538ce63c1049de02982e7e2589da2eb5276a751aef35a676702a8033d4b491e03edf1a70d9fb16c9808a67474dccabc91981d6a6824f26441118059f1f60c72c0ee2225fcf7acb78229101f02b6b8421c9def1306a9f452e304ccfc0f715de13d48ac05a3684a130da6440838a789e946dbe6c7f44c44ffc7fd7c77b9497229052882ecfd0898168232cb4d796781d1054973dddf04e09577481baf23b5468b95a5416c76f28396411e7aad4cea8046591f664dfaa3af8985727ddcd8e8e4b87308ad0328ca4294e8b94fa41b4c2d0b137f93e4d9fa24a301804f5338ee5661eaea06be44df99db421712a1e6bf81713548807beb5aed4a1d78ad06f5c245564d377be61744d0a6db264741d50560469a055a1b8593fbf80ca2f99f819290043d4a68248d47f02432a6cad46b49b945835b230ad0630bf1fa12f698804cb07fafaac84ef483affffda64d7d23edfee1e35955111d1147682c9be955ffdc21298acab5c5b297e7d8e590db6f7a45e4b574cbbf30287fb72eca1a791319a4fd9b9dd8e3dd180d9ad7bbefcc28ab181d65ee89902c71ddcabe414cbfec469e8c6e7b11a2888d858cab007de7df4cd209354468918cd9196663192dd46b732e31235c603c46b00175bae3f536003a21eba94080cf5598533d633b5ba4aceee3d935aff8c6b960ab1f1f21f490c2b7d886377ef1f63d171f4b595e4001ea94a332c292fd6adc7870803e60a0f8a9d50607a2d35acef61f285ebc72479c4d4f7b73487caebddc99c65072eca60ec01543722e6423b02ebb527fbd4392ab3f3a617c89917813fe0f13de5712f80026acec24f31162b61da0a2781bc2676ef17c0eb9571c8b83b5669f22041134dc6574447832ec580337852fbe60a707747e4d4120050805fec5b36aef8d51729da48518bb27750752e7f7636d582edc45bb7cc45c6875fb80da53cdefcc845c4de6d75f593d59d06657dad71e7190551a471130215458df3b789228ab6530a8ab03af0f807228bb454ad9426e0b9dba26abcde8c2ce080b3c708e702057587db6e3078f1053ada7cb26bf2cad2c3cd54df2045b575b0f7a8925689d0344bb4655937c35fb3cfa8204a704cf7c0c8d74bfe5ba6c9e15ec26e38e46d44ef37da3466b28469a79828a99f08a4b2acb5b53b6ac6eaae47ff32d31f25b94d88aeb042b477c63e0f3bd414dd7dec80c23b22fb7f68cfeee7f2cc8e9d7d2638055aabcc033d7b563111f7fc746990f1f9bcba5a2c02dfa6fda46c53e19b150f6d7811d32d464bd76be286a36025679e47ab8cc83d79e08cfe97058872adc80e9bfd4ecad14cc948125ea34778ee0660f22bd7f6b4cdfc18f61eca9987ee73a1dde815cbd79f3e9e8bdc7ae1a03460c72326690e3ab6d68892e80ef0b28e7d7d1051031bdc8aac92f4f17b8abe7485c0dd9c4543e9ad148d7884d4bfe630f7b15d084f375d3c2246ab48992d8b251eb12af12b0fd75e07bfe05bc483b3d3c521b12206f223b24d0513faf45656fd70c4e40a2d85b06c14e633807463d35440c6e6ff9c90782677f1de6f8099f2e97cf700d04add6f380b772ff656a372f8bfe91bc16b8151fdef80d3482f7752adcc9f82c10f582f261ccc647958b3a1b34226972dde904d9ea698c2faf61adab492e3bb492060e2c2af0102e77de5bbfcc2dd0da70c87046be6e089a1be8ecd532b60d9581fcc9a75a9f97361290d2db5d2e4e5d216e8aae0851d8e3c5914b034206b99acd3627c23cc0e726c3da152529c0d0aeb2516b0375096af1da6e3e6ef8baf4bdc5285bc84ae41c351716d0252f073f149fa1e00bf834d44fb62b55f240c4cc22200144cf1b443e55e65d53af7ca9efc873f6040d98c571e5c010d88e20b85b804afdb1d42dbe07853e9934ff798f0c8f26190d28e5b3c1598ebf63781b49f1b5f5b944ef56ffff52b6565c5b96667ac49cc9536d1e7513024328350033b9a8a102aaaa49e9ecd0d0c142dc42c8faaab741240dddf76b02071c58deb5704324a5febe3709b9a87a3bd388d4376ece76ec4fa996f07618fecbb57e1a55c9cc6e5a63143d323003e935243c49552f83975569a59306521a267d826b1abc22f0db3b5db89a367f69c17053e309758a791a147408705182587226df276e11aeb6979114d6e6ea61bb45f68209215ffdc5a8c9d6fb7e775600e3710f3dd532a195a893a86a9324e7e1f5f2bf5bfe9383d6857a3243cbd1b8f726af46ab93ad06fba88b192ad46a15068027dc42131b0f482d146387b0b261a54664c81d41587a196963b55526d56e7317eff6f9859a9f580330bc37ba95be2bc8eabc45a50fe63929bd8b37f7ed3f4cb072272f50f61a66c2b25d676ecfc200a67b015a7255554d8633ec9a0025e249a4c746167c2a1060cc09d6bd69057cde004e8eafbfc6bd4574992ece5a5f6d03b9eaee48a75c72da57395e169e26041d6ed3b65b9c306254b06b09f394fda392e26d911e2f1ced495a2347e9c68138d96e1d84fb26f7e284626fcf756fbc9a4575305555b099f6832a2193c9eb6b5abb95fab25703852be6ff25ec40bbe0c8bfd118aa38f0e9554e00ba3bc7eef0213060d25b23cd6c32e5ff461d82124b519220b115b6f2f18cd3371cd837ced26b69814f0f09027cf1338dc424e9da44d1ffd5c3e0625bb2b8936d36f9430345af3e119f92994899174a0df8c0e4aefb3dd69119b7b957902caf98b1174df0e3b6e7eaf365178511f0ed1b31157730a389c558dfb71105d985c5ddf6e60588431d8adff58f0b5b6fb92ec73b16a6abafe862001f559c85850cffa583c07f0bb766af7d1a11d91bd1c51d4b2e760703b0868df98c4c79093782d7caef607b330a44e31281a812a80dd1ca1df8232a7eb9c7b12decc2ad8c1273051620fee9ba58de4b2879394a701880f75a372f50f25afaa95c4bd2318007851e1c7b04898446c8e792c9f467f169978fe22b4ff6d7f86573631ebf795e5c1ab8fe85b76022ae4b1ed6a5efc02ecfae8b8c96875a101670ec783394b3388b6bb2e49d93f35570fea9f66cb5aa13bf7c211ad307df3f270a4de667759673c4c0c8c70a740abbbf866d3ce9758c92732e8316cab0fd7b44083adda52db9206455dc03020d62863541165a35cc77dec1ff2f610d35d41e16841d87a4f2cb1a8b0e9f048c2c69649052bc798e91b8f7b1650707ebf7fd0b24509ce0e83c5d622bd0d4427262cd09752c22f3156e400fb256402f06603d1ca839ee8754f408603c21b35dffafa3ef07270f1014352be11744d77e1c365110e52cd516ec3d7258cb23037f35f963bf2eeee1ed77caaa2618444fdc739b0624540ceb791d912d077de3386641f2a1463aee3c73f61457b2d51ff1e18d5256da064a7cb04fd1682a48d26f6dc4be147e682957815d1e1c31ab208f79c254681bd008b01d9bbfd6df63fbd59a03dba903d39cb51dec5a38fd27e740310d70cfd2cd4d0839ef24e27725293f2af1d2b728dcda6fc444e3e35145c4cac1affce73b7b99181881ecbad24e47775d475fbb4869e216782ada651ce95af7ea1820f71baf1956f4cc4a487e33e1b284077e4a30509cd068d13b0aa146532ce8e10feb52e71bf2bf0476d99b634d198a1b85c4a7b8001a39d05ed4413ad53c1fc242e58a834d8d2c2c537ad6ba9d6b7e87373568b42cc3b8df4717812092c6f5ea91dbd72b59c827623bafe3999ca7fec5f1c4af8b66b305c9b138d6d79af07d0c780a27dad35ef50a711fc23a1bb70567a6754f3253090147984215275787afd2bb2c12787942e7dc7ec996f90be2173d3984206a6594899c181464fad9b78b718fdbca1ff0db5bf9720c1fceea2ebd62f0b81d943e2986eb204b6d7c64a0502c9f60458c349a1da820c25ff4341a72fea8f66251ee97f8f5721a4e691465f8f24c8454f7aa05a1f339581ca88fee21f5b27874a662eba05b2a28a8d10d17a1d8b5eb8d62386b74d8e87557137272619fbd3520c47ffb0371b04a88e548edf1e85657e912b658ecacdfc63cf007c2e3636575514ce402ea217756bc74d2f1fd8f57824d7718b7b80a27aa5bd9dd9f6375a28e009794cc8ea671e01e3c76a190f86d0647b941e779da687d1a47cefa9c52e85e4d715107e1c4e42ad65a834b403245dee643c2f7b0c355bc2aabc3e5502f6c3395899df540ff194bb0f614441b1104776e549634f217912aaf56fe539cf52436be520e49c6413af7be5f2bc567ce0b0030888491aaadcf5048e4be5534318b63ca18d24ae22ea8b84c534bb16b5e89be9a97df5f26bf9c196cbda125380ace6283f5ca1138096adc4cbfabef87ec0a214e489765302f5ba8d22d175f4c44a60f071c4a4cd70c72df3d3b679b80e8adb29f506a352b95f4a047cade72c49c8cf57f7256fc4bd2a80a76ce25bb2f69c56ef539a6fbfa5771f5b524d7c9668b9bdcf36b42f4972262f9620fd16623dcd7a01163972135544e28c7d7b3ba773eb4fc19a9f356147e87ceef0fae8239cd9af066e786b7e36f207bac0c99ca40c3fa8d174506bde6daada87881bab469fba3f374ce4d28a88b93c40275b4313f58a042bbd3661d67562b97fa0de72ddd9d3489b02508854e4496caffce26df866a25ec7e13e2402bb690d973ba0b0ace987a979de8e3c2b897018962203ffbe2cec697960adac97aa6d5789062eee3d39cba18c42c1aa6af4f22b20f1dddc734f611324debe43d44d2c349e45f16323ef62133aec203d3f3315f98377002665086077e31e210b49ac5a263cc58e55dffe61dcb46fde9b3254309d314e9aa8cdb7a578c46a797521760d51a565ca0d45d6dced98e7d215d1373d135088f434f9732b3a606548b4bbd6356c3cd6aa3d7bd785e3983016a4d81ad153813d24010ba8672d8060f538b759ec30bd1cad9e82fdd7da0a8b381603e9325978c0a466d1aadb59a29d3c71b1bcd1a9b3b0bedb29c3364e0e8ef26b85484fa43f6a37a3215fe6e3c12207cc8bb9c94b96e92b260e33e91cf90f21fb31083632b316424b7b19f2f5213fbca06f53b5091c3173b5fc94c1045e2e73f57ead0fcdb4458a35fdce2c0575225955d2f5939981731d22b33cff03fe767a013da0b22388ccf168a134b3a353513b7c2a6c4b529761a2838fddf68dfbd0a1abe473eace950cac266671f7857955fb84121e0a505a51f024bc94007a21354cdb48e884a4960c1ad204b6b55eaf941fc57fbfed7aa8af71fa142e9fb1746deacdaf0ef81a13e51d98525673b977ad737ad4fba87b7c3af16be2ca81a6b0b73040259380e99939bbf1074c47adf2990204d39101cf9449a7c29f4e21c583b7c40eca3aa0d3cb7e9f5566cb2114a70630df071375d7966eb0b79483698a170b21881c775ba624b80b668f70d714a6d87a0a051f7679852db65fb78ea5df2b5787cec29244eaaf1528b08d65169d6b9699a5598e76d9eb0390863c9ff2b96ea6991c7448c66a651474086a04d9f28b7a72e8bfb35a7eb575c1b9771d21863eaee37c14975c8826ab99b6d4d8a11ea511b60740dddcc6bd8a49b252814ad7512375cd966aed0ba3478a7ae1b3b3ffb0ca843f05160354c7c2afd4ac2ffd164f9b80c60ef761af30a2f379582d4cc9f94bd2df255983378295d436d0eb2bf3739f38eaa1577f9061662825c51cc09bf576b71ba4975b9a4a66ea37205ecb930f83327238518757ab2dfc9d25b63be8abf4d67657d5d98f9bdd7799183f9679443873a1a99160e5f1f66d2257c90baa19505fa70cec3335943bcb3dcca3028f9b34aef83f5e4355fef3790df44b4763aa7ddb5cbba7c04b08edf545e38316663b838302d412cbafb0fa14d633a3dabf53ffbcebf4f08844d5d8c333bff147af758fe9ceab7cfaeccf1fbe95cb6d96465a0bf8d6aa80cb96992fc7545f0b1098c426ddb2fed5ac2975ec6045e44b4025bc9d6c8a4a861758b92f30e5fb57f00dbe89dc7a5c6e0cd4b18ad48df4b359c814d1d7b9aa1b46cec8731ee5b519059934190fa2f7251db9d013dc3318c20aefbb428c6945360d32a598265e95d4512377c38d985bcd1b1ed0dc6a4e82173218eed37e922bfbbf00d9d5eea08abc367903b57fda42539fe2b6abca9670b23e3ce2866d7a0f0bd916551b93a0ab8c96b9a3cbe87a17fe600d691a9bd3e2d587efaedc2820060461a8b2dc3a1a178f0f7056503991b02e3e3ca5d98063d203dcc507faf5d902789acd973464bcf39e57907253c5cf18325d33a1e4b7b52c566aad61b2dd133368b1d892e904d012653fcc3bb7f8217b6cb912271a904764cc049f66a7ca75076ad6e88d7069ed7afd58e74fab8afc8eb34ada73e99d1f6657064e1396d91d7aa190e06502631f738a095baa076ba395dc989f9134b9b2cf562b344e1af1de8990c117e5423a93fbf2c6e18220fd5af039b5c40f87c05b969290d582e602e98abd58ee80e152f74c3094378722c31453e60a9167b2a6c10beba701d623d3f83fa4e77de477ee8dff968977c281f7df560e7d0cabc8ce1df034667d86b8613e8dc26268726ed726618f84e95aa27717d0a15f1c1aa21e7f7a19622df62fe68c8f539ccd858288250c23695bac0d7c97e4f4994cf2aa929edc0b13315f047ad463709dd2679023d79b06ae0deded9888c0a2a56389086c44ced7872fef9d7b6032f79be609d5009f94c89f35a31497d781aceacf77de80108cd70b72cdd70a0a96e03cb48bf429d7b8605e0cbb5e4af9ca117c509bd366ed7c6fe1244571acb410bc6f8d176426abcc73de789285187e0522a17a80aee5a7ec1f0e3ab1f7fde3e66e014b42f28e6590a56fb4d6162aa9e395ec4cf2cf54b4fa779674edc7ea49d6e837a783ea8488ff03f5d603490d1558393bcdfdfca159ea1c207885f2fa5fda4f16587238b18c45e2d83dfaa028ca2d67f0b7acb1c9935fc2301f7f4ba9bcbc06b9af3a326f611e1e9e6d93c93c11758c8092681d371bd85f25f00dcc46c1015d15d0911fa9f4b4db06e604e070bc64fb6169caf17a4844e39d3ca4ccd0efa930f91617d14bc64b2c915ab7d158bfd1a3edf99562af377bb50f371b38c6feac8424e8a034d1471d92a188478a7e41ef947052a0f2c1685a5ec2b1a66c08e5eb9d163d8e7201400a98a0ffd38ba2c917f07bb114ee0250eb2524f09abbcde8d7855bfcf44cf6430236bcb265571f1455e03c29909c9faf61bbc181120b72574627262e70792cc8149c015b475bfb19a6865aa98127ad20ce29306d624b5f1f9bf26ded991f6659a40f2f5d17b46514efb11f90afa868b03bf498392453f2e2bce86727f5eb77124e05ca41704640d5429f1d4aa3ef19661a8ad650e34f177ece60c059080d4d8149c39ab686569ce2aaff7943d992730a830f7584578fdbd3ebc98401a137e6cdeefe363838b3a2a56ea2ca66bdff94a20ef39affb210329181b356beb70545520cd5d9b4b6fcbb2407f97252acea3ed87f4218266291b9238c2a4eeda12f7ae2ef634e104c769d998216ca7392c91a65f7559e0108a636fbdc33a8eab7b545e4ff3da4a6f32fdb804f5c4c431ba0ed780d5214bc68399232a83774582743c696b89cc0ebd110ee1cb72fbf85991e0c2bd055801ae4d9484ec3c94ccf8c3f85190e64826fe955b55e4b04efe3e4cf406c0bea84c992a18af6d3640e88ab34ec92e69f4b51b7a715d2212dd768a019690f655d68d19a0805a7a53939124ee6f5b5e48b7de6bc3f9098fdb5facab6f973b5a1477c397aefe691c2099efb4fbdfbe99509f43c2f3f8452dfe1f63df92e7a0dbeecad2f2ee6012ccf33a627b33c7e2b70aae4bb7bef47dc6935ca79b085fb3094773b2367eb3b0e8d95c5a8c987fbc72d15170a3f966cd6308729a4a6e032033c781680641a0accab1e2682f7e0c19bbc3831d1b97efa0fba00b8bb99ece27370f16a6b4bd3926d4f98017d8b7a23584b34964dcc7602b368d82d2555a346b96677addc77573bed662d7862b576e7334a6223b6f36e141d06bf658bb5e47f405760322b46d37f63955bea7555f6065ac17a580d2eda371309d48759aa462bfd4067aac6730ea6391a9bdb0aaf00d7a5311c5e52a32259dc49466b2e5945f063ba34388c1b15b6900e8c1d8d6c90bb3b4e64e596024919bd4b331eb98fdf08e22b31dd59f9a791ef24c276fe1561a07f89666bee2ebc9916e94475150f9bc3e240db6a803f1ae34ad8efa474b9ffc8178a68e0ab05192f2b7a73389d47088c4a450b85838997a1404afec5cfcf9ad604a49203d1581048d1d8fa1d55a74c0da87171a6e1ed2f0f9f112460a7117a6aa267f4015f3406ff9cc475197d879e0301de7b2abe50b0cbf6cf55d3548f6104705be4b5216784db2effcd539a7956498ba4a2bcde46eaf08cc8baa5316d993b54599bd3b79201880e233c1473b196abc3d15da0b9cf5e51a82052bbf09af7c0e02290ebc360b63e713102ace0446810e80936f234af849dd6d5783cceaffbcc7e493d695c943787b51ff33a7d9ccbd2008ba86035673c8e8670d543ff3b2ba40387de9d7bc0419ebfa88e34058fdf39cf650c8a291446da83f976ee9bfbbe48385601dd0bcb5f2d85834fabe0fc0957338b04576ddd9d1c2fb8e65a36968d7c0e80d797b096603ab4436c3e980553c94808b4dc74e2e66afe93786afa9f2b7e521fae7730084b6ab8777fbfe6b7ba34a0504806f44ce87d02b9abe856a24baac924e6b1e9b0e4f666dfa8aee90d07135503bf628a3a8578b702673f98a8a81cd7833ccff398d692363c82a845516efd2ae4b9a74b72dd0ee69950113c59e61b31203d618882d73a7eba59f932a7b2aadcc971b743a65daed8b0c8d61d146358220844e4eb32302fe5ea871259374c57bb0f62195918a954ea74519530a6e960f38cfc57fe7dc575dc33697fef0ae3173bf23f359dab53fb25741ad295f2ced8924fb1902894e94e195920ea5596e49e05b3783abc3b946faae16c8ba8b3f9b1aa7aeebade70a9fd0b52ead76f176f355d7de239f77e63b038526144e1b49f6299c89fa3e18db1b3b0fbcccc40d0028c043e9783524c4b85fc6338fae6973f5293a55d9c118339777be91bfaa3932eae0f8d7525109a19bab187ca814a484ffce65f413a8ea22ea627f6ecc03a149f9254d45f9d5956e2083493e6f8aa874aeff7c6429d1a18335175c294377694438d3037b96e4aab9454f7dffef76b5813d31a5f377dddcc01e1ec860b88b5b67be6abb889d82da155739dd4860339d33e7ed7d2aa309646bef3390f43f8e1b8ee75468f9c89c8b798febe1acdd493858c3121e9d1e0c4887d9eccc200b7b6492656fd6e22786b6adbf49a0e11456da10afb1d3e896d10ff2c637c0add4e44b9d0156f599b4495ead0c91574cba37c422e5b67d3857e9b035c232ffe1173a387544f1d3735193e00d52bcd0a08402691955c0ec3576209bdb30d4b3dab09d2cf1731e9f36820ffafe6f1e958239fe606a4adde758c5a2fabd59f2a143aa9ff8e5f9b4b8e06eff7750c4d3b2e9f785f332ee74db963c0aad8565fb8f43852a2bba1c04c401f6ab2cbd33beef28da3d399ee4ef17bc8ec2edfb5a6d666e70a6038b6c92c3501c901b1e56510d9059d2f94b7c3e098f9237f62839dcea1dfd1df8daa3919321cdf69efa80b3c2c1b106dbf0bd644323911b0ecfacada1cb3ced99dc03a21781699af040c49cd45dd6292840951e0171922275a557720613e73638a7f0867090293a965081048cb13d17b76f5136ce638c70646157ee7e447a33ca6019d0d778f773ac2d14df176dd1f497cb0e8b7a97e4f71da1874db722b19dec913732aebac806c797798cbe1feec74a86c2f538e8125407db0b2e6edfd2f1b02d05c43e508641338204e633f278a92d1e4baa33db9b892d0c42e509ffba299949cfeb39d47220e65c0b47505d2639c92fa91afaaa31a11bc5d31db74782e1595ceed4b699e259df053642cb27feae1a5a6883c54ca9b5efbe8b802f94a14343ef10a1040649e29b9b886475942b32c57f68e7434d8756641d3d5b101dd36e09483e93bfcb4f25fc7c515779489b8c0a000a9980f21a50dd14c9b2c5d8c396dbde7a69d6d20e95f114996bbab845ac2944f9a81fc5ac476cbccda30e85acfc5c04b84f566b47dac340206744e800a7f4f54c4a7ff3b2f9af933d57ce277b334ad22f686d5603632bb7e2f08a8258ae75eff36b0d97f3d3613ff39f8730936513b8cd07542da0763942b20e66cc32fbf91600cdf92e7fc5255a6adbc1a3bfb6707d19a4c9f61261ce12387ec59d44ea032d10a282f038aa4907eb6fe8f317a89ae74ea6c1489dc3afa1d7d770e1d57d3db0a154ae981469129646f31821e1dd4cdd32d9bbb53044a9a84a52a97cccd41ac38d56075472104c6041a0776fcb067037f3a9117a7ad4c0e08210a35540aab1fe1c3d27535b8d0453ecbc2467a67d9b70b1a8006b7968a776532b04e6f688082651ad296d0b302c7908fdefe09320a67be5775025929120a509dc7dec726c8a0e82aa664a40972ade66cef98ada9cd14c77a11ff055d136c7fe89d3df498973dd5464586c80eb0e53e0e48370eef6faef20dcc95ae3b449920005194bc928290b0bacfc49e12a676f1f23c4cc1bc33dc6cbd86358fa9a30aa89eb2483c3cd6b83cca79891d0160de91d4ce57d5904007ef581d439586c80bbf1ae709f57f55db82553ae0bc18e6d47c2fcae7afd536b90ff52675d0133120dd85612fd7555cbc558343ea08806b1bcf3b7787f2c613080c4e2841489bfb180deb1b60cbc8119699b036dc0f1194c1a4070e8b91d30b7c47ec61e0bb6da86eb29c3ec1ad236aa1232a6c9abd2a1cc47c82b75c9f54b2b8956e9ba3aa11f82c98c1465d2108d0ceb71f527047a1a8160b84aa5fd28eb6f4f477964c3361cc1a20f5f9d0b66b5a8ced1f1fa37f868c513e6da1abe9fff7fe66434276703f6cc0612af0bf5f60f248735019c3140f05281e269d7f002ea6928ec0e8c18eb725b5351134a9ae9f7a6b067b2308a48145576b9019586725c23a80cbc830800c9ad1b9232f6ca0358eaeb361ffff7846fd261068ad6baed747b3dc550b416835fe3ce67ddfc698ef683804c227cb2302f6d82e85c5512f88539404f613a0ff0d438354ef7e52a28a36b98f66a805dd74484d6f3f73f0dc28edf76f3a7430a6130315154cf2550d953ca377bd83fc5df978058357fc6b714a52bf116c630b485916cfecc2b9bbf1b5ab4ccf26da8d1fa2a115ce51e09ae1c07596027f971273d977d42a8bce76daa6649e31da51709cb1cc5bdf9f7a8d25904f8f384531cd881e57b93cfee106e48f53946be9de00526872b46a40ec0abe3a6992b4f52c12643dcf8c0f4d4185eddad2f9d257eed1f49c18340871ff32de637892c5fa825e1227edad6f21dc5f808e08ffb44ac4e275f100925456630effb7e03f091cc7860c9698abd34b56171541edb31bb515a34b84a8d89ea0fbfbe7b2b8c88ddc963f8fa39da45aa99f3aa5693210f20cd848808dcbced3f730f0336b338456233bf5ec5b21df1a2a09f2379a8595ea637fcba01c7f6b765e330554e1966ab7219d004e855df754f5f0f1df247b8e9be7a1aae56a3fea12b3c4f376625b3c1bd50acf0da503314c38bf2c6cef380265fb62879c94d97a552f24fa431ca2a44f6c9c9c4baa2ad1169d3e95c75b29ef3c2922609cd4e08d7f38c3f996f79ce3353a6b79291b3490983a6b54126935b683f1e85e384909f2611f7f127149251b84c741700dc09372ee75bd35cabe2f4d78613d190d84b950159e0136fde672b03a1a3819679202df50d2e72a780e18bd1941bdd9d5284e0f3ad5ed2bfb8fabe287ca2f17267ca7a91cd73f15d2f7b4b9e40a0642c9c03adf2b2d276a2fd0e17991e6f9de0f7258e2a47c69f2544cb02aa8248f320f5967fc5a27cfdd3e1ab7887f2cac10640e1c872d29d01118aa37ceff8b9c7ce4522338891f168bf5c0b5322e003c57d679d9b5f4328f69a05c8fae75e1c7d893a96d759285341473fda21d0e33df6e7e01fd7f8b8fee4b6a3f168bb18e97175f19dbcf56a70bd985612d8e545b6c006c80202e53a1a2742bec72b68c03b36e7a08e9fff36973cb7888cbddc139d3bcff7f9bfb24fabf5de213c293790a9f878e43df13a17dc5828188f51b750bb7373cb932d85da51f8b23b37258e1c2fdb2a823986fcd4149e0d90b8a81b8fd59029b28d27e207e0cf2d4597c1ad425ccc655809a5e6bb1d6345509ed6c8af83685cd76b20de12c3a8dd23f6fb30263553f86d481f91f3c1d43b596ddf7eda69f5897a8ce6b2d080a9380bbb5af7eb3285fcb23d28eafb7648fb2065da3e52c8dbd0fd2bb195e87c2ebeaf72183e521347c2d69ce72ca4bef390868bec18586fd0d77282a92d7ac9f75b3bf58944485a236632f7d22b93984eae51fcff4f452829ea085fcc3fed18399f67240a8028fc578f8fc99b3e896fb845dd593a493e9706a174d89c0136e51df4e04b5a04c4cfca4130a830264fc3f3b7519bb81ccebccccf3a50a666006b264db55c68efd0a03e3c821b4e0aceed5eaea23a70d14956dabb9596674f2caba60f70e50d2733d8c1da23c7c6508eb6e16058377a07abb5056220bc98597969e33ce10d12cbc07cbea15f0195849a22629163755f829fad8227edc54c0a10039680330e490803ad441b8195afdd1ee7f9915f0b6daf48e8d88f46697ea697857a209d8b2c36a8dd89537b9454f23cef2d20258c08cb519dcf557d163a938db68e7058b6c6251380e69da1e751640fa32c12351aa0fd67b7662a65a3ce96f18b417bd6730a57bedc6c020fb2d9f39b2476afca83e7ac3eef594bdbc842b12f2838effa939b2952371af51144b1fd836bb63594501869dccd34f516f26f5251a3b05172eab489da8b4102b69276cc72c4a35502bdf92ad5d857616cf4dc9f919af32c2885aa928b9a8f432316f80101611772def843dd4be19d7bdaf083599b2a9a792bda771f4f4f646d9504fd3c29f8564c616e8820c48bb41898fa309168dde2ca94a0d45c84f950e632cd658c04fde9fb4b8c5ad242713137a21ece27c0fe739c197268e6a6528a158ae88a7eafc34f8ae4fe0f7cd04ec2e33dfe7b042a965e0f05fe2e3ac30f9f33698912aff56edf5756ec081b01b2816cdf34169b6064e69486e87fa0cdc7ecf330a65334fc7d7f7bbf08164466d956b0cc62cfe798fb4d6bd3bc4a429d5eb1d196177aa2ae5f31ae21dd3e7cc524da63a556858c0ccf6b3e0616be091f585b318f4f0c2a8622d0d9684dda67c3d28808495e8efd62b1f0fdae157e961c6c5bee6ee63b90cc61f612088800418609c3b197b7409d7bcd8a53369b4a9bc962548ec50fd3b752c88c6ae41785545617b49da4052fe9ed173899f98271e065ea8cf4d70400128a08c99e153a78efd9a24075b531e71ad876854bb22c3108229a55704627927535b43cdf4a438f046fe1785811347acc2004a91e9c60aa87ed660228f145f29e65e0f774d674a6869262aa14ade1588c4be8f198bf8e7df619b0e4331a5931a2e8b1246bde1938685266c8d6c4913cd5c6d5a278587c789176dde4bcd4390246123c8eaf7230b954f15d7b3ad89df310271a52276afe7a875509432a7658e6b96206d93e5b28056df1f10c9c4a35f40c1131f30290e7798e61d197ca0ea29d9edfa23bd269cc68b022a0236e2bf6d49f288641edd012ba7bb40c130ed612154f0ff101d43a924d06f9199f55b9dbf5a834d251957537db3d7d817be1de33bff93a56d72c9b3fb6f8a9050ec425bcd7666dc4677e954295c61d47743991acee7e796bd682080daa5fa12e314287337674ea0c0394b1e3660d8a3aec378fc8e2e1a159bab309bc2e3dc4a32744c9bb7672d2cc8f193059797683c8614abd3f9f8be9d255fba4cb3fbcd5023a3ab1118590b6b93c65d2440fee25409e92a246622edac62103c7bfaaf22feff70e956d64528b7c4f91e84197524a77807e68bd0a3933a96b488f8f02e5220b6577dc672b9a8b7d6ddf90ff6b585bef46708062b14438a4f3e950239e533a6313fa39afd4952307c996e359629da872755c30fc16b39a6a94cfd862ca86fe13b979b0ac6735ece74be12072ac15941fe6b0337f0ccc2e57c38a764390141847b855015c8b02bfd97fe79ba4a90a58d5ee2a17a734772ce4131d9323b4d5ce1d8df2c339489d7f862320c62357ff37c1b09f627f6f116599b51905402812a45651aad8e420bfc1ca5c31d9046a48bde485f2d326f1c775904afa48790dbc0ad56e1062fdaf4c88dd82645ff648baa453deadbcc18be9f94a8539650df746d13a85db47d45c8268a7c1ccc7c3a4245fa8eebdfdc0b172dc360201002afa077fa07fa5543960a82f81d81417f8d7c3070c3bb5dab0128a47838f2c43ac7ea4bc75b73afbab9fa42ee0deb10b93aaea0059bc38468e3e2b511833e5ebb0062645048c6106044866ed52d331a21fd90e9d2918d1e2b9e60110c6d1dfed8cab1a7e913ac3c4bd681493d398a0fc64108f7971c30184b5b202e69750f1d53140c0809a974341550e5faef1392a266c18333a19e48eafc6252138c7bf610aa440efee6ada47e619a1be9b9e89dbef8df1aab0446daa2e7f3ac9ceeed93886be8b63f56295bd43bde11be741238fb5754ef749df2962088c089adcb47612f1cf5a868e4c0a0c2437ecb5759da41989899951f96261d31343dc131de60243f48384e06faa87baac8da66ac6323a104f3c1b9013f79d9712befaf860c639739de3ab7f6f1376dd99cb7f6c8aa42fb0d0f2dc586b708bf2b8af0e681350663125e913f7c8f2cf03d566acc35f09bf46680fbb699bdbc06d2af725cebcca87caba9553d5fde4248360dde795a78dad54241cce04425902deab8aa6de34fea7ec003a8b9e94a1c82eb83ff19cf2ae9a5ddf59d6f5e0e96ade83eb8a07072fe4b497b26c09843f98a89d10719a4899c886240f395a527055b3b6a8f208bba4cf495dd8b04c5c4f684331929d638400cb8b4927368e7a2365753cdd5f206545a022cb412ae27176214efaaecc0578b9dc9b87610aea8dbe799a94c6ea88bf5ab3945534addd3f63d76856a0360a1eb505abb4be88ef6b571e8a692453f7b3c6e6051d5cc27bf7715af743dd6b6067ec7fb3e13219833198286ea8315faa6f367a606d8148972617d044f9af75f9f62e7db95fcf329273a8d3a328047cf1d25686cf6a696f5127ec71cdc7d5e1ecb212d8fa94f38a7c84d5cb5730f0a4ff8f70b4f41996092cff2ddd991ab30e22ba1ac0144ca776facd476ca07cb50d9289a234e9faf84926e322d271368682f3a0d403c7c80a04c48788742fd29c567806640b7f1bd8d1dd961d92edd846aead2d9f4ad6c6363b35ed5e7f872c32194fa6ff03d3696f2bf78f055e4019146b144ed1ad63be7c3022dec556cd8d2f3a0bbfe725ae304de8affffa097e7f8e2a91bbe59eb6cdeaa4246cff640dcf9824768418535effe74534331242e689734fc393ff38a8f3e88b450112ef26eb58df6d45d4c677aed1e7cfe1e5a681bb5f72aeace6b762cc72408cb004ec049c1cf4a31701068a1c7058cd2f0e98df911627bd791a85817cc503906256240fe4f830ebcc290ce216dfe5b6331d3cc612098e39b821e314b37858a40d1268f31f23bdb75ea64a5bfe3cbbd9284ea4caa57bc27ed3501e2419aa407e5f7b7a5dc7c64566f4abeaffb54d094357eaab85314c953a520eede2f4bbf2784b3cee19c5420e2d5a6a8b86c313605f16731ab67db8c8310290332d36e5db455da9a7c72de8a95c3794eb85614ba70eb39cddf29dc8971f253c73b14c073bda91d88f8acf246aaedbec7e3baa71bd7dbb6a9e2e610340374fd4f9a0e9ca8f3326126e07545f7ec6e32826f96837657dddbed096f2e9b488fe98165f70d23d3e8602ffdad9480a7dcec031ef6b62061c3121f284b609fa8c8f06c7a4a53324338e65db9af2a4607d2e2977ab4ef41ff93304539c9c0aa831dbbac328a5484a08366000000000037b10700000000002a7315c8ddfc25dc2266a6b221cb8f9fdf641970ab1f65a2754df4e14c432b9c446c604131913bed45976c4a8ea27df843a72d622f80ef15da622f0d56ec1ffe3021190177b0405c4fa1a0311a493c4dd095f24d386be6a03f5838a6b1008665f4000000f5c98fc152bf40e1ce216c8839b8ddd42ea5b355f0b5c700fc9b2cb7c802e1c8336488033fe5f3ef4ccc12af07b9370b92e553e35ecb4a337a1b1c0e4afe1e0edb56114e00fdd4c1f85c892bf35ac9a89289aaecb1ebd0a96cde606a748b5d71a533e05d648cb9635382f38b778dc3c76b18e4eab2d017fdb24c1c0e32d2991707a45ce3f26e443dafa697a76bf24122c9b19b57eebe798668dbd1a0da7c900795222290dd7278aa3ddd389cc1e1d165cc4bafe5c658153cdef5850f97c4d4fb6706b82310414a00fe7dc34b3043e0c7a8a24e810e3cec9de3e1dd7ce06bc191efd2273a357da4436fc4bf82069f6cb87d3d605aeda1336ac513f358b4296b8da51232896ad271063d93404eaa6b80960fa2d4b41d74a544eef94731f0b83ba2701e33b49e3191098c3369bc4658d82f536cb9d38285c51c7844292ced06dd2e8148f0bcd585dc1104e64aa930045e83d828ab436a0e587637e5ef83044d1c2918da284d7072847132885d443640979907485847368e32501345b0dc24c904c06732cc17d944b26181b0c05c6461bccbe4f7b2180a282b6871aa6472fa36cdc49ec50cf69d3eee4b26fe02bf48f39efb549d3963d19e4112c7250c580543516204ff1b0675680cfea02ac09f0b23d6e28c14b08421b3a10a9788442457d732b120c5c466c54ad938dedd3cd3701d9b32fa15dc8db3d6b1ea5d8495732477a72b34efcaf8c349aa40d8e1f21f226ca11182cff00921930b010000000080c3c901000000009104e90000000000d75b9464000000003802000076ab1c8604000000000000000000000000000000000000000000000000000000844f7a7e7585362114fc88a70654146215ab4eaad65ad54b64975840b78d365e8b75e78616a92294e747589c3ee4a845c2962e1cf6cd7fe8bfbd09439e5e6d5e4d4efdf181473803e734d97891388e1b50628658ac818599cf2cb069c8e6b38b6265617665726275696c642e6f7267" } } diff --git a/test_assets/portalnet/content/beacon/light_client_finality_update.json b/test_assets/portalnet/content/beacon/light_client_finality_update.json index e47e5164d..af1d2b9bb 100644 --- a/test_assets/portalnet/content/beacon/light_client_finality_update.json +++ b/test_assets/portalnet/content/beacon/light_client_finality_update.json @@ -1,6 +1,6 @@ { "6718463": { - "content_key": "0x020000000000000000", + "content_key": "0x120000000000000000", "content_value": "0xbba4da9670010000b30400001d34030000000000000000000000000000000000000000000000000000000000a4f8b2415bbca66d73597343afead504bd8282523df27153543b2de8973b7474ace652bb73991c3b63f7185a17333c8aea619a69b69863a5d79810dad6c363d3df460765de20d3c8f56bcd9490f15e2d9e122b3f6173cea76f6d0d16074ce0f0ecde5df1b81f36c08e91ce803c25add312bfd8cb759a81b7cfd158d724959cf22e83908e043f77bdc5992806617ef1fa0a4f1985d9aa1b67371d3580be8c2c64ffffffffffffffffffffffffffffbfffff7fffffffffffffffffffffffffffffffffffffffffffffffffffdefffffffffffffffffffeffffffffffffffffefffa480f81d481c5aa8439f8c65f86c69d3b1570cfd95b61300f7e29c5b0954c0c0fb080bba0e8ba60dead40c45355332ed06982fcaf53ad1ad4a7e6e39091ee7e5602d4a30b6d46e12047c31451f246bf43c4a3fbdb1d1de2f2180a776ef71fc3d0084660000000000ff83660000000000e5f4020000000000007b8211614b9c5331a1de2691ad7cdde1ca113b4e51b9f2757a4b502833f9234a06eb807d82b9175dd085748ade76aaa86fb4eca48bc8deb01b9c56a267a896d98469820ef7d34f8610e134c6eaf8d379e83cf6c3ab0663fba828edab344dc5f40000008e2a532cfdfdce86b27b26f611f1df0e2b00a54d18c6980e69ad28a4b70bf480336488033fe5f3ef4ccc12af07b9370b92e553e35ecb4a337a1b1c0e4afe1e0edb56114e00fdd4c1f85c892bf35ac9a89289aaecb1ebd0a96cde606a748b5d71b4c4e01065cd22a0d2f27a544ff8315b9e28f6270a63f543831778f32648ac3a15ecbea44f91b9b4a28ec8308a30a4b6252f554a2088bb1c73ea01013ba4963dfeebabe6b0418ec13b30aadf129f5dcdd4f70ceaa56499df0b3ba9d8fe6ca410132a29cf387371294137003adb139ce9f06b6f7dbf32ee01da91016a485a8aab5669168efc3d3a200b2ee0f25d937a413dfc38e44e211f02432a01a83088e700808c302002139aad8496010300cd220b14288429d8a6049945000a3b60f00f00109019341a0129a08906314848650817002cb98894a328084521a87e6d0a64e8080004ac0805000800e29808294016508a2004001304002a02320c4705501ac008a62848701040012a08e5c8b69010f1009f80408894857053e1b940e2c9004912860e26112080610d002098242000ca001420209a42c141d0c86087509344ced8a32e0204410a0196025a12106104e20008ad4449d5043208090008810201820209108607a0fa1004aa323410050222867024e0d172a82821b02c00020513152006484c800b10f0420802c0244d0850288c6541dc34cabc32f5d355aef4017425cab95c1de0474d483623e23c9bf13d9a18f1597e930b010000000080c3c901000000000ca88800000000004b6094640000000038020000ab9bf66d04000000000000000000000000000000000000000000000000000000797be971185ac699fa7288c87457c3611b443fb98483fddf282dfa7c5b4b27058eddbcd8b5de9b747c57c827ceba820d19e987ff6740eed38ccbc947696d71e3e2c3b96c9200d7d5c66fb4e8458067d6420e64647682ca2f0798ae817d2bc19468747470733a2f2f6574682d6275696c6465722e636f6da08366000000000037b10700000000002a7315c8ddfc25dc2266a6b221cb8f9fdf641970ab1f65a2754df4e14c432b9c446c604131913bed45976c4a8ea27df843a72d622f80ef15da622f0d56ec1ffe3021190177b0405c4fa1a0311a493c4dd095f24d386be6a03f5838a6b1008665f4000000f5c98fc152bf40e1ce216c8839b8ddd42ea5b355f0b5c700fc9b2cb7c802e1c8336488033fe5f3ef4ccc12af07b9370b92e553e35ecb4a337a1b1c0e4afe1e0edb56114e00fdd4c1f85c892bf35ac9a89289aaecb1ebd0a96cde606a748b5d71a533e05d648cb9635382f38b778dc3c76b18e4eab2d017fdb24c1c0e32d2991707a45ce3f26e443dafa697a76bf24122c9b19b57eebe798668dbd1a0da7c900795222290dd7278aa3ddd389cc1e1d165cc4bafe5c658153cdef5850f97c4d4fb6706b82310414a00fe7dc34b3043e0c7a8a24e810e3cec9de3e1dd7ce06bc191efd2273a357da4436fc4bf82069f6cb87d3d605aeda1336ac513f358b4296b8da51232896ad271063d93404eaa6b80960fa2d4b41d74a544eef94731f0b83ba2701e33b49e3191098c3369bc4658d82f536cb9d38285c51c7844292ced06dd2e8148f0bcd585dc1104e64aa930045e83d828ab436a0e587637e5ef83044d1c2918da284d7072847132885d443640979907485847368e32501345b0dc24c904c06732cc17d944b26181b0c05c6461bccbe4f7b2180a282b6871aa6472fa36cdc49ec50cf69d3eee4b26fe02bf48f39efb549d3963d19e4112c7250c580543516204ff1b0675680cfea02ac09f0b23d6e28c14b08421b3a10a9788442457d732b120c5c466c54ad938dedd3cd3701d9b32fa15dc8db3d6b1ea5d8495732477a72b34efcaf8c349aa40d8e1f21f226ca11182cff00921930b010000000080c3c901000000009104e90000000000d75b9464000000003802000076ab1c8604000000000000000000000000000000000000000000000000000000844f7a7e7585362114fc88a70654146215ab4eaad65ad54b64975840b78d365e8b75e78616a92294e747589c3ee4a845c2962e1cf6cd7fe8bfbd09439e5e6d5e4d4efdf181473803e734d97891388e1b50628658ac818599cf2cb069c8e6b38b6265617665726275696c642e6f7267" } } diff --git a/test_assets/portalnet/content/beacon/light_client_optimistic_update.json b/test_assets/portalnet/content/beacon/light_client_optimistic_update.json index 2dbfd282b..ecbe0c2be 100644 --- a/test_assets/portalnet/content/beacon/light_client_optimistic_update.json +++ b/test_assets/portalnet/content/beacon/light_client_optimistic_update.json @@ -1,6 +1,6 @@ { "6718463": { - "content_key": "0x030000000000000000", + "content_key": "0x130000000000000000", "content_value": "0xbba4da96ac000000ffffffffffffffffffffffffffffbfffff7fffffffffffffffffffffffffffffffffffffffffffffffffffdefffffffffffffffffffeffffffffffffffffefffa480f81d481c5aa8439f8c65f86c69d3b1570cfd95b61300f7e29c5b0954c0c0fb080bba0e8ba60dead40c45355332ed06982fcaf53ad1ad4a7e6e39091ee7e5602d4a30b6d46e12047c31451f246bf43c4a3fbdb1d1de2f2180a776ef71fc3d0084660000000000ff83660000000000e5f4020000000000007b8211614b9c5331a1de2691ad7cdde1ca113b4e51b9f2757a4b502833f9234a06eb807d82b9175dd085748ade76aaa86fb4eca48bc8deb01b9c56a267a896d98469820ef7d34f8610e134c6eaf8d379e83cf6c3ab0663fba828edab344dc5f40000008e2a532cfdfdce86b27b26f611f1df0e2b00a54d18c6980e69ad28a4b70bf480336488033fe5f3ef4ccc12af07b9370b92e553e35ecb4a337a1b1c0e4afe1e0edb56114e00fdd4c1f85c892bf35ac9a89289aaecb1ebd0a96cde606a748b5d71b4c4e01065cd22a0d2f27a544ff8315b9e28f6270a63f543831778f32648ac3a15ecbea44f91b9b4a28ec8308a30a4b6252f554a2088bb1c73ea01013ba4963dfeebabe6b0418ec13b30aadf129f5dcdd4f70ceaa56499df0b3ba9d8fe6ca410132a29cf387371294137003adb139ce9f06b6f7dbf32ee01da91016a485a8aab5669168efc3d3a200b2ee0f25d937a413dfc38e44e211f02432a01a83088e700808c302002139aad8496010300cd220b14288429d8a6049945000a3b60f00f00109019341a0129a08906314848650817002cb98894a328084521a87e6d0a64e8080004ac0805000800e29808294016508a2004001304002a02320c4705501ac008a62848701040012a08e5c8b69010f1009f80408894857053e1b940e2c9004912860e26112080610d002098242000ca001420209a42c141d0c86087509344ced8a32e0204410a0196025a12106104e20008ad4449d5043208090008810201820209108607a0fa1004aa323410050222867024e0d172a82821b02c00020513152006484c800b10f0420802c0244d0850288c6541dc34cabc32f5d355aef4017425cab95c1de0474d483623e23c9bf13d9a18f1597e930b010000000080c3c901000000000ca88800000000004b6094640000000038020000ab9bf66d04000000000000000000000000000000000000000000000000000000797be971185ac699fa7288c87457c3611b443fb98483fddf282dfa7c5b4b27058eddbcd8b5de9b747c57c827ceba820d19e987ff6740eed38ccbc947696d71e3e2c3b96c9200d7d5c66fb4e8458067d6420e64647682ca2f0798ae817d2bc19468747470733a2f2f6574682d6275696c6465722e636f6d" } } diff --git a/test_assets/portalnet/content/beacon/light_client_updates_by_range.json b/test_assets/portalnet/content/beacon/light_client_updates_by_range.json index 4132f2350..3e6ffbe2a 100644 --- a/test_assets/portalnet/content/beacon/light_client_updates_by_range.json +++ b/test_assets/portalnet/content/beacon/light_client_updates_by_range.json @@ -1,6 +1,6 @@ { "6684738": { - "content_key": "0x0130030000000000000400000000000000", + "content_key": "0x1130030000000000000400000000000000", "content_value": "0x10000000c16800007dd10000413a0100bba4da9640620000a02fcd95184de2d2e51bc4d160556c37f11e705440bae4d99a152d081b0c668ef64116481d8a1cb3f48196e1e36c073799e160cdbb10d253a3e14a16bc8e22f24458acf3d809aae7b9462533b70ea4952ba61c7e8cbb058a54c8e5be4de85c6f8883ea6bbc48894f21a06b72a110b32c25e805e9a693c1a40991c15094ba9830540d5dac8c618f87ca70d6c13bd22d84a1eef0952922fad56504efabe4e3b69fe522eb1aaa0c2b58ae4232cf81deb7a31036bc698b229df613f0babb92e6d18ba8b86ccd241ba4c6203a7ae14e9e4309acab9caaf4f3e860d0c1bcce89f65e4ad2df12a6f0c71f081910672d33c1114aa016c45828b42db508d66c781c9863c85b5187caff5c21b1bb65c42fc3955e1180a9bf49c471bca49e8660c3dd61c3878d1ddd95fdaa4b6308bbb3d235fd5a7380d4c4209bf625bed136f96f4e3750ac4e78030794fd26f32f8280ee8bcf64a2850c5c5bbbae51b02596560bb5cd2df0d699df530724ff44ad60c5566bfceda830d74471d82d921aa65d7c3f7414f3b9861371cc715f80656d06e0b6490db3f96e743db6b1354d23a39c9f614e9e72205c31ed1cc28f763524eefbc31b17d44db2dbc5d74ba8ec3fe6b5cb4e12d629f616de835c20aa7ad72f1d1ff03c9776bffaf555fe015623c2beaec8186aadb3d9a97df44b0959d4fe5b15521f490370ca61ae6b5a971660798aead1fc08285d03dd0fca7ce33742ae4c6ee121b8deb941a802fd8fd29323e4658b7f9c5625220e0e07ebf2220555ca9953e9208c36eef4a491b56bfc7e3dce6b8f84f5f98bbf64b1f5ce5712dbbd8579a294cf9e1448f7202b8803f8117ed23fbe561ed91ff3f1bc7f34349664544d6061a2d7a730b707b1552a115d79c79e9267a4cfc1240831f633c4ce50b6ac68408885d942423f846fa5e33555768af2d634c4c2543b4544a1f17a1c56b52db91a341695d5f6dbd430e0b4f44a2b8e782baf10aabe0300f1a283c4529c49cd84374d82ce23055099b76b3d5fdd3a0db2c517be48ad44a20fb948ba077052ddc92fe47f732317581b2c2af843f887d77e244b51d2d26d61a99827079061eea3aa0816427f0484b7262d0fa936d78f2c8881c8b385ba3d193f783a2792bffad5586263b5194ed9d6188c8dc90a2cd1f5c5807607c34a301ac551444d17003fa7fad4b49cc0ea209f98bf61062b826c39bb9ee484988adfe230a95d1f14887c48f0139cfa5104352db47aeffb555526f70841765d557026d22c3c39de331d93f1f2f7eeee28d70ec594848e4cbacdc253f2b3947def1f51a5fd359441b87f0307c541e75b76879b8387788397ca7c6e707a08efaa1dc531ea9c81b29ab01a5224f75d2786beb450a8049cc2ba8e04d53576177017fad0bd9f316daeabce7ae74007add71427d698e6fe880ec3a018d143c2cfd14913b10bfba77d4f8d988bd64a0e1af678227df22e9b67dd34b0254617e31326e06ff8e0362c988a5c6fa70155ceb2b945816b51d7270d54a4ad9acbc47dc4dd5595643c5152c8e413ea730d9ba31ea26c03666f0332a056690bab30b9edee92dc9c0ddc837db286370634ddcf2772142bf7161c2417fdb4c46de72e67d756c86eca1b9c79ca83462ceaad7cde0308f125d41ef4918bedf97c62b9d422645dbdbb91e9826bc0a2682a971170f605026ae4ddabb36f8a81f79aa612bb417be42f0465b37865f3484bfb3b0ff8c3a54f95f6e76e0d90f5c7a2aeb41e287a226da8a08c767e0c4e92506a20b94a34c0c9e93ea856b108911e748e0058d58984d69dee0040bcab4e4b38883bcd7762995ecf1822156e54bab46d29f718964222a1fcc22df2a6aa2d40cc82cf045dacb31504cf0c79f2bca9cc85e3b55c9dd93cc1dd90d75662c3eea0cf33f0b67d03ad92073b75dbdf7057edf9a4251ec13d4977b8786f1b86aa595e1a8fb1d4f35df6ebd6c0857f24e2bb8cb572059e676135bf49d778b16b6945ab69fd5cf8bb65cbe9b2a89f40e6f649431626231333d093fd1c2373ffd5c0b0afa376b5b8f71ab19877da4a49baeac594f2f3750bd2b72d72375c9fa82d265f1768ecaf268a02a2dc6ba4085ed8acfa94b158c7c0ef82d73e523e0bcb5f8538ae9192390faa6729179d33b6e89b367d6b51f96f694aa9e0a135b2afa1eb18d28d531e2d51d9bc4de29f07d874ee7d49ec8fffc540a6160f00041b73e48180cb53817c279ef2bb6f7635ce44a9a532a38a814a2f55c46da8461a877c7e734217e1a5ec3bac5e80b810be6a659684a04cd971ad470ef71a0c78566f94a4f2caafadcf5383fcd53c2efbdd4b39afc83dff21d36dd2ffa61cb868e2f307a433ab597e1ac8f3c8944de72249a2d34284bd59ad3ee335773381ca0cfa8526d0fecaf3f1499f037f74e2ddfdd75f2e5496132a8756a5625398a6f09be62348e320ccc49462d3edb5e795720d9581e9196154097251baba616b39173b58dd253eb43f0adae7253ffab765f0b4e0fdf26fed6358b8714880f253353a1395d05e1ee93e6782ab5c427084d77a39b142652ccf583063a176a03d43e67da347de182867eaada17e6e531da7c5321f07d27995301497999e44c80c1b8e4f43e7580caed6c12ed0d690254fa6c716e29ef9eb69d1d0948e8d71b66bb2b6a5409b54a0d6eb7230c4724430e14f68bd50fc86f0c89171d9369e0ebab6b3c61798aab5eb28076cb0a3e895c12afbc4c7af6ef696c86e30e371d9582eb4dd17c5f03c609b399c93419a0c9406cce61d52cb70dd6d636577e484714f3f18f6cc41369f2fce992187e4c8487874111bcd8926d5ce11cd3d79e425d82bec9cbce497edefcd5d4074c113b278af426fb75bfbf1630060f7fbc80c8c78ec32350d0c6ec5012813c935a2bd57c7c78e3f92a64f4b45db6c95635b48b17bdb59ac0a34bcdd702bdd0e738abc7ae91dbfb8878e1e471692341b9ea4da0f249c05ff89c3842d7fb0afd638ce15ac42794f7f625ec1066a21e5e20ecb8fb2b929f698184aa2b58c0ca2c11ea07b5c1c9f2ceca5a0d5d759c56f5a8c4ef1a9cead96aa3d858e2f17cb655807dd7442b0de2455eee6d5f3a0a4ab14d92a59c9442bd311370dbd9d616f8a6b1dc317a3764ce380e2818c62ff8fc1fcf16604f10e2c9367196ec7a9794275ee121651406e7feae5aa9affb5f23e7a58ce340a8a7066412e461931a071310695ee59769933feb86e3a4a4398274db1001bb2893a78cfc058f3583d4680c56829442bb4b150fc208cb6050478642650c2256550227b0e8e0a774bbb6f45308a9c3ca5bac64dbfc13dc8f723a2519a681320ad19862bd36b24f72cc9cd59c9c823fd372a7a36b353a1eea21e06ca7e149a06f786803021a11430c828cc3e7debb32e1cd1adc32105ef9a17e0baa289be7a7e73ea12fddf477aa6a4935767ed6285b5f22f5ee6e65e03247c341efbd489230abf1e82bc51c8b4a9d35f69039e04abeb0d908bd2501aaef7f70ade7f0f72a91b8228cd0b9a53abbf2cafd80335d03ccdea17aea88b9a90f5d84933f6fe779e7a70673a87555cc84102ac2f04cd705199675acaabb4616ef985a442f0e7918aa502509944d75cfcc0ed18645b4f2f1f51d92a2229b524ed9788dbc699f9cec1a8bd77b1b150a4247f82bcb01d1e217b2dc97db573e7b318924f4bdc8135e5c1eef9cf70464d5adc5ba03022e2750350d03290ef74ee46e1d60b04c620d91c5baa564f99341a53b5a3e3fbf420b6dd79ced99dbafb8ab464b281e763b5dee1ad61f34dedb0e84b0816ec21e5d41d9ea9e567f299e23a6f6ea978f45ab0d4ccce5c924ca25accc40ba7dff54c52f96a1d777804a31ef8e807e393110d189a4938587b1e85cca9975ffaf7e222d6a5d04f44bccac1fee3c340ab5d075b182915eace5e3dc087b36d8570bf6715bb952c63d9adedabe6fc29ba9da169286162d59109ff2dbef00824456ac6109032575ec4c1ac0bb446349b442149bd838455c7f1f49b2fac8b76117a0626b8fcfdf3a655d29a7019c18b05bcca0b2c094b7899c7d60d75be0b87bad28b31e4c2d5aaae016c2093930f3670860dc63248febfdebd8f47790a424f913d460f5c65d3033e579abb83d78cbe0dd7d1f17f1bd8ab2dfa22565ba39ce8a86df57a7f89c1f78e8017d326c3ccb61b159b86a2f8ab425cbfba7d2a05154fcc90fa5a372fcfa0b94cd292c1915a3d415adf437c07b1c94f42a965b82304b179db3335fac9f14538b4fab3f9e6c1399df9423fa16ff3b8e1356fc7dc9865027caf2f477733a525860c35502de873467f5c4cc85327594f985f00aa28c2608545b4f169347b54ac5e85c4ea90b5330fcead5862f025a93dc34161b2dda8ce0094091f21cc7e1ddc9ed4c9eafb4063d9e4524ac4a9b3ab124bdf1ef39bae7583713442460f4626f4513dae331305dc04ebae5b5b3ba8db650eac798f8ca4f4592e6832827b8a793eea6cd6bc88a8a524ff4caa2bad33cb34d689677de526b8103c31ba94c85dbd129ccf248a1ff8b352b1fd75ada2461ff2d67f88e23f92c8b76dc338ae5b9d049ea83b1a56d6f39767d50fb75fadfebb64f640f757ddfa59b1f774b034dd926af6fe17a95b88a534937429752a73c999ef9636151b542357216808738cdeeafc4977375f39cd10622ae77e92a0ba811ace515932babeb21903d0eab4c0352fd19d8c81dc4e3f63fb839a9c66f0a7533ce2c73bbeb6f38ace32e3fce208997f448aff2378e8d8b6e72821bc2a915e7138b8ca8b2b068892b541ec09fa55f0e991423f5dac5906d9c4f7ca711fab16f62eebdb63f5967785cd2a2d70c9ba96019a362aa2a826d737e376212b721f2b912dd0ab953342f2911698d70c98548b5927aadc3f26a730a2720cf355e5ba80eb1d588d5accbc8c0f9b768ef4c6c0093d852ee87f0d2a190bec647a07711e5ad1bf781a4b9e90b6aa4312ac799bea78c6d91d7f561b23e4eddc02066ea94d3a771e969147418f8001a4be459d0493aa1897faefbc4712278a590bb159deb222404bf459cd66c5258225b91f0e4a9b7450e380edb00a1cc9354b29fdc36f4bf76230ee0ceaed9799b5945ab72543bb5946605897a3135834de1c78e8b9f27a78e7eb2fb5db6f8a96c1ba32aa7e4e7126112935b8bea6608fb929f3a51ebc92d7de33afeb861ef0689c12d5f47528a48cd790f087e1da89d3d52a1975f47e84073f6b829bf165c0038f4a34925e931e89551c2c43c79dc399199ef1b3c3ced0a8a205536cd2a4e4e01d3883978aab681db88c5b9b02672d18b07d054cd47a9965bd3ddb672cea9b7f62d37712561ae3f903972f3c2a74702ec0426fd5cfd4972438bd3f418b9d22ac841b1c9ade100c9cf0b46809657119bd255b9e0763c3a540aaf5de61ef4618bfc78a0c3298bd44b6cf0f32783df4f3b5958027427030d2583bef3f7b6105aec9ac33e4f23fad8fe16385683fecdc2e957a1af4e9a3f3892122421870edc3d133929b138bf78494f74fdf7d7e76529f70f597e7619bf7cf8dc69fb0ce7c8f2dd8a9b50c02fb7fbdb0b533a7fecb14a3c3a91980d59aeb3f3a6eb0f000753051dc0d3d4060063ce408d2f025092e0495d0bac0e303e306a313f8a7dead7e2a09a58e91ba4e5ce2b3c06f4b4bca11fd322224e684c1b0ca9d38de4be8dd94974d0cfd4bb1e040d000c16f04291bd2b8e49b957c736dfdfa424cebf2d02677cee462924cd1e6516fa12e8cc118220678543c49f3a828e905b8e50f9f2d510626dceba0a256aa6a66e928d561bfc00fed0cfac979f95321ea7e5650107f09aa3b0ec68794f196b4252e7a33fb79bb669f2f6b85725cfb7b6347198f01ef8a8b68fdc159180e8e9dca4752575f8de301c53ce141212206fd416927974e2ed72be4ad6e84857f444c6b7a1bd475f5e0ce84c1d7f6de5b32ed201fa0b0888fa267efa725bc018f21c070cf6f77687e87dde53c16948d60bde2fc8903540afb8a0362beb5c1d4f243b9c625e6e4c0d13d63b66d6147b8fc10dd502e75b597b458fdef0f3386ea9e9dde040f23218f62b1e3ac328149f707904e70b11634c9d9b32a180ee2babb0daf43afe3d72366b125050ba99fa6a1bd5582ad1c591aedc31df1b94a480f35bca60c0a01fefcd464d20466a682b92ed81392f8d3c257dfc2f88f818f8083462f489b10f853d00474b85b487dcd638cb1ee279d5e10db3049d969e0c351346e7f65c5369234bcf94f71e9afaf06b874c0bda5faaf5f0631b180af5057aeabe207a10cf057fa750002fb0051a09a0ff11fcc9a27275f890f8cfa46f00b5c8fab9f0ce2f2b87f462cdfb8dbdcb709083f62adcc2f1535edbd5e195a6f0bfb12efac960bb071a98a4735104bedc4ec945103479ec5f554f4bcb27f44cc22393114cfdb351a7bea17e42acc1dd51c14c6140fa7b4097a6bbdbcb51fafb96008b4bec3971bc46f7cc2931cdc4dd8979be0b7c21ca413e35bdb4cdf18f77ffc5ce01a0b3f204d0106ecf93bd64b9f54208aad9386107f03c4cc0d079300c3ce1785ca7757e2f48669a4af624c9582c92615d86e42e214f05666a7bde242f48c4ea1a012ac3325f50e78db5ad7f309f46fcfaa49199888033698e9843c1e906b8c2c6bec6c3bff10445126534d208be4bd9917bae2bf7f7a60c56a34325895508115329a1bfa1e585b67b2f0a91f47eb6ae5695980dee1ae925797885c115a2b4fb62af17a6fddba58ec101d941bd8796233ed1337384a4599ed82b3d77408bdda9f57bfe1337955c5691ac71ff1e3e85ab3a9d7e071cc72b0b2518bf93796cff91a3434ebbccc89f23cd01ba1fa39e27f5e6c336b7c5e4aab254290f43dae16d0a11043f5416840fe8152fff6cb27aa7502f4b61426e0bc896bed04b8eb75c379c7d44f853a288d332c6d5527f6e4277e84aa8197648a711fe2f5f3e0f496f2cad4ecade603276d32c1edfdb9c7cb28ac2fa221a186162a18170198032f40c10cb7a970d9edf9128c0f64e6513b2b90696f48de91652fb168fc74782103fbaa65997987273d456fd85ad69543ac790306901638521b5f602ba4c17f4efd488c327e411e986b0b3b8961c3b8781395420103017503742f9da7c6751c7e536f1b3f8934e5ece5cc69e18b2bfc592e7d77e539ca8faecd9fe62a15e9eb09ee66859d83ea8f23b3b4f7bc75a2009720d353fe8f0fd771403b3fa3efe68c599a6682daade234f50289c71d7723c650ddcabfb7d8f56d589b3a92543548523dc5e65e10b7c1a9ece38c349d4d82010c2d87e61c8db8ea169ed196c5483fa21baad71664348c741c3befaaf492d6dde2970ed2ea9417871fbfe06fa029f5e574dade091c299283c5fec9f35515de79da0aa475e3e93018172dd6d552bf88878c2df4e3a5b40a8da682a717c9549f23fae8d1dbf71e840f1a4742c67e8f0afd9394fae2ea144bc46437001f269fdb0dd96967761e85e346b585427643bd3dc21123ca9d7372c84d0c35af7934a137c18206addb98f5085b20a755d7f8325fb56874144634b0bf2948e6b8b6b08c03ebe9c9cfb3e4cd3b0e42fed2ff85c9d6272d34f87a4740fbd48ba03008559be614d3f43a840a9669a97c461fc23ede8bd97f4f73473230dac2d3762a46b9f2bde6f34b37c11edc3426ea27f2d802604c0320280876ffb372e822195cab78f09cdd4d33be6c62004cb4a7738679febd1827b6a97ece3a1a39c7bb6f2947169bf7c4ecfb6c2ea7930be43cdf3e15332e51df8ddb959e6ea62b29289e4858838b4ad5513eea589d5e05e07c6c4a2bad5de7ba62382cc7cca95ffa9086558f1816d1f62d8201cfc1c8c2f69fb6abce44e3a5717db3e86c85b595f6b1794dc26fdd1b543df8e7d7b3a10b15e3e49ba48c28220d500754fdad3b0fd4deda34abe504428ccb32eefba7800487a7255563ea26f2f25da325e628acfaa6bbee7445f1082f688a0ba8ce54fc76a01a014a9d30518ad1bc63d6b8f1d8fbd62458366c8e93d2207353a84cfda30853ee4c38ffbe0f18431a27e19679d97772a6cd1d99bc3e3dfcbb1dbdbf4311ceff800bddf42cd3364bf3f2d15303aeea1f54852086ebe36e3127970c9f529cadcc3e085c764a00beb8eac187249cdb192ee5f8718a4ffde39ee4ed785e01b8fb3bcc214337de7f4444626893def8c090a8a9dd0e1ce370bf4ce923ec7e2287473c09b9ed0fbef868501ff8bc7418953cd57efcc4bb36bf9fc3559d9ef223b1f34dde87c9f8e27423a5b47bbd9a9df9665dd6d039ff541e9ae1a02343a7d19622f301b4e7f35a431f3b9ef02a0a8f10459c655eb7fb7ced2edc907961ec7949a8a72572830a4a53cfbe66b1e76417a84edeefb1c363191f34a8fc7d294cee87aac1bc976f31107327aa8b53a5e93864cc23f9e28bd36c8b9915b2b0eb1ff1887441da4200835cc552f5898cef63789fe596029f280fbf615496c894638e62ab4f573fe3837eb000be1b38598fb8e5b6ead0cd6ed4c33e4af93064ed6c4404c355397423d294cebca43032f1a45fc4c97efe0c5e7169f3d3b51aa8b43c9bed88480a9bf5bd6be442d52719608326a957b2c01743a61c319da07d7d38dfab7313f2a68990d7bec84861026b8ec16420abb969779137eb38f13c52eea6294020c2152e855821b836402b7f4746e023e67a72d249120c7b325b40e6083f1f8e528cbdfd4f823a71880567007f5b206456ad96be6975e7af8484b0c46b9ea111e6bbb1ce74d501b2f86767ec50c8860769939140ff6c80f4d4f1dcee5f2c45e92053600c1da27c27c4f686be53d93b7efaf78f6c5d02a06828c856cae0a485327ba1282cd184bec4911bd05ebac6821d52a83cc213259fab716974b9c55b284fd0f73ba77fea1b6414d1ffc3c0700cc60e90322bee7140e2f9eaec32994392fb7df3ef2f3447fc4bf6106f6dd2a38aacc29f3c6e3791d47e2238b652f72ded72d7b4f06ecc5b3bc5d84cb013f50ec1a33f5f258a700ec11d08cc237c1d2805a0285609990efef779818f21f61c1f0dadb682d69b64ab9c8bd47c614285a0efa3661b75bf02df5f1321fad07100f30835328bb8b7834ec22848cbc4b98c1023659ab471e4d1948fe3fc4620f41c1f75698a85ded3455d53549a676c1b357c7a9ea8f8def6c2cfc4a9e7e7e879c85e188687878fffa8641471fd131fcc02331fd4897ff6d34022fb5fad755b2a1354ad414f49a22041ac902592fe24aeb4e7ae13cdb0593768be42d80a41dcd757aadef357ed95d0cd4482e72960d2651d7355dc7e98f35ec0a25c17407a6d1fe05524e12c917b873f6d4a5d129cc0bff693e982dd9bfe4bfb450e4e2c88441ae88f39f29c5d1916ff4da3b7d7d042d75763cc0644acb698ddeec23ad1a6eb562dc23536b512462b26859c1e6b8222827498addecc085a014b79cc420523a28a2130549173b00a03b75e7963539f2be28b405d91cb72025b15539f003b6d55eb1dc0cea110765aeb74ada1ed163f91aca46cc5c011b41a8dfd800407efe23e6ddee32865e3bd64fa912baeaf344aad84f3af72b79e83c9c01b4d618a5b9cda07a48ff37928a3f6f7cf8d07769a3d863f1ef9a21d1a074ebe808bdc4842bae50cdeb7b7f68bffeaf387e56dc5cf2ef5ef3f9e552eb398802810502e0e3002e1172863df5f038ad950a673b255b17864f90e0a2f35e84dbb041dc3f1450036341772f3797dc6a0b711ac587755a58df3784812b541977adf4b8528da04f32f8d05749028391e8f23acb6c96f452fa359a5164609fc4b83306b1204e398352523efb616a2bba7e5136b26103cf99209e0a6b2a73b33d57128d881d9b4220b5853f7906258a8e6abd7c662d0f00bb82cb0a3902268a1a1e04bce389cd079ff1931bce834f256c1612ba793106a10ae8e58d331f66883a281b42a85880c202778e0ae285a31425dc263ba33070e5a58e5c361fafdbc148bf07a94cc0b85929693a0fc4656e0c2ad886329af66a4706ce2294fde79fbc3f69f22327e0c766021afbff1b57086f4d958c231de668b2973b714d6a9f75aed738040557f33298087fab2fae82cccecff47f5091a28724ad67a06e433da641f532a3ee19c10fd5c5494bc5af1ce5932dd8ebd675d4ea1332b2ca493aba40cacffbf9cbeb6365dcd8f5dae6b4668edd93972d7750420692690e15d0c96dd26158db08eac992c13ae782f1f19b1957451bdbb68239380618d0ffa9be5d5a22d7b214acd9f68bf6aa8740c0ee3b8c6a22809a20503b8cdee5cde4db5e01d8b38466a17977da2cfdbed2707b99a2a3a6ad5250996d91921524a2451da4251203472d38cd2f72304e7f08d2cbb812c86a52c9ce6488517b138f72b9ddd5ebb461a6b79a169e3572a376a3808f547bdbb877702832b441e0f386b13dbab529feb9fb55ff83291f9b79405c4148eea03aebc7a060fa7c6699ea7fc3423624e4bfb948dfa88e4c2dd5ca8f6113066ac3efed1e2ef6709317ac78a9c66b688039ee89e7c21509310f3848ad66c77897ce0ca86b92380ec3f7290bc218e6eb32f045317652f0f8e9983141a1d3b8d84d3fee52002ec2e4e9b6536a5c803175b811c795d33f6a3a7622fc7fa4024cea8bdc25bbf939a34133fc688fc1131695cf66eb77d76116007fa0d6013b446553501b601884675b69cde121814f62cefdc9a2a44a71bf4257a38a62c4fcc47e1008bbeab03bd3ecba7e8dc6b7cc26a23d5094efb4f97d1b943a2034ec9f5d71f3da2e3996f628aac72a662c74c8109996703894e0d8396c56e98fe5875e394a51cdd6c84805f81b3d41f312cc703af12fc55a79b179d19d587486b9df96e9fa46fba679d28248ca38a513bba7569f4dcded85065615fcaa042865b273828eec229efd7ce87a0a8e3847989e782cef966b3ef3edb7ddc04778690511a5c24c451c0251ce5ea0039afb04e4d44ed502ceecb1f039f008ca9a848185d67726734dc4d5f299baff17a43a01f3ddfb52fe5f22a7f4caefd3c96abbc8ed099ed93445e01510cea787e2640cea9ebc1c228948d2040c3359f24b7b20fa4843f02b5a6c93f3f2aa54a118893dce1b6a0b7a49841fce36a13f423c1ce19db228d15b8d097b1fdf23fda1b1002ea21f0c5980d921adcd1a044d28414b6c437254e55cbc98f97e60d07864b9efa5b8ee8100872dadd776010d97276e7ef91c1501a495cace101507df6f39bc48addbd80005cab6746126cb02dee3c79aea0da2c039c35111b715e8332634b4ba035e3bb6c2a1b5abc6349f8d8a9b542b506133cab0ea75f4b5a6c59f380caa9bc6efc580b515e664ea32fed5c2693b89e03b8150c6853ababe85d9990f17cdd8e3588ac8866816746154e309313a3766609dcf9704ce762e17e4c2e208c3a69a2f13230d7a9f5d9623ec568205e9b6ba872ad6ff2bd18b6ae8ede5773e7aface1c0f482cfd747459aebfe38035b09a0a77ddc93a446bca9fbf068bf24e5bce8aadff8c81054b8b76a47120169b1bbb979df664cbb7b446171121211709c7718c2c98ed0af217b0e8d00b1c7bbaf4f55ac65cc587ca0c26912b39609bb9b3374a791920af98390fe4f9d39960a8dcca29a8f5ab5011c570c89eea05d0ae1c24188539e693055c12edcf1f43e6f4bc69291e6a5785159a5198c64e7ab822315bfa11995a0ed94f9e821d0372cbc06a20bac2866a7f311253ca3314263cbb72183a9a395bcfa40bd7a3bd2476cdbc24dedea09024a97d22b3cd742fadd441d0b54abb3f9f45176cf799b337f83133a832328ef1683106efc19862a9d120e5e037cb1f4f35054b519c19fa04af2b793c030b3f60f0637124f82ac0017807c4272785b8f635ed5cd08b4d3fa1e71eb9e26eb17df7038fe8f1c708949c621d8c37208b2ee5866b080b1c6a043f36084f2335d93c43fdeb149aa60342f4ecbb12eb732570f3bd59caeb6efd36917e1a8152299995667da96d2752a2275e64c1033aa9f72115289c37656c5d0cc3da5126d5623e26209331572fb2504566d9884a0adfea13db397055dbe685be16a55ee7da1a0853a2f481ed422d52cb6497e1af59b3335558b3f10fdf7382af38102e76aeea6aa96a28bf4a752ea4614085725e4862640ea7826256078125603f88b0e5150782cc6644818063cf823fe12571647c1a394c874022913ea782a4da323b073ada87146c42ce9643611f88392536c84709d4abc1cf70bc8674cdbdb37430d737334929bf76a9bca76ec4876edd7c7139b63b4f07f7adc2f53e758842f7b223906ea08193522ab923a2b329ba0a2110e3dfbaa314f6fc635a0ceaac50a7c0c8bd83f5f100af1ec235f8a9d0af7a73550c0c0225e9b7df8ab484dba2808884938a0fd97a4008d7eafb1ce7ed35c69953dfb73a102638f58d63df06f703aa1e8fa68b1f8f5a4e91f44dad1f653b9473ad73173b0b642897278dd10bf2d627ef8f1041aeae096da73dda0d86bfe4e1a978f3cfd1633d7bdb8fe60990e7e8f5d59f90949a586dd6c4cf56cc020204a6f4fdb4567c4fa39600ca6cc162bf0e0ac458d55d20a815675550e6dc53924fde8e2d672889541d55ea74d099b250821c312fbeba27d7729f669bd073f10de7ab0cf1d11567bc416225e8ae4d0e06cc6159d485043a65e5625cb4088d7732c7a68daca19c74555934dbb837fc1f348f45cb1e246650760406e2d2b98d4e1a20a42daf52c67836a67c9e8859bd8f4901a273a67b3be4ae32efc7332fa8ba3f37587562733f7afb486cff7023287935a27467a654eb9ae2cce18a7103b352ecdeeb92b606930c91ae2a86a13ca51ceada5b9446591d63a14567ff435fc7197aec33880218c68a16b214c16e4d0fa4c85d3939bd40cb0b9bd7e49eef4dea32d6d40e29c2319156aa1b6eef6a4db95cd897b7ecc9210a9891360ca3cd272844c0f12c45d6c721a6ae69d7b75c7db652b27bd6aab7469b58d0261978f806a1c1ef3bf64a1f5049685144216e3def99256218396e1f62849f02d62f7d57ba804fcdcb3d3af241f28355fbb3cd35cbec44c1dbfab69831f9a8f22f8220e64f5d650a53950b61a40933db87269d4ee1327402325602e0f3c5e0e61420435b82360b651a98747562d64a048c3744a5f439e2afd11c5aecd62a162b1fefcd735bde8cb32624f35a51f2fcc033c0279010c4722ff3ded0167041dab5081c33fe1ddadc203747b35354e0ccb8dabf5596ddc1fea73e40a9effb19cee7e1b0e0ba727f2869dca820deb30c6995916458cff200aea1e8e01d845ac9e310d2ff5d1a639640882fd7f0ee60ca936419c6f49aecffefea7960a16b2204987397512e1aed2803984333061858ff63d935c1dca1c1244da88111296d42eba6593ec225560d289d055ea03feb93f2db35c363acc98d605e303fb0401cd76942216cc1acf4aea4e3676750e429f989763117af56fba9d11c23b4d616f1042d795606c1d4675c6d071e6c37676de2ca5505af3539cca8b7cc1105566c0218e51922c183538ddfbba1bdc94e14151baf7a6e8bd37d2dee1eecb5de0795d4a549bebebb074228b4865e36da1680a1f34e28fef99e45bd31e8822623c98bff8bfe48e8b7e502ddb362f7f0ae650ba7f026c134354cb00a8b4ee4f9256e61b0e9f10db9b17e27cd4698262316d4e6b2b5632b9bbd44c5835dd9b0c8fd7930a0ae5c1cb33c184f3a7f5f07d87a0a2e3891367c99cfab5444d21b91a82591c709837e7a4e2ed6f1637b0febbfc6596dcab6f37df82296ad68787ea878d8ceb82c973a1d6fa71971447f14d7ea0b1451565ef5d84f9f88596a04a028cce4ac442b404b571a658d57b8f1e3db934164bcd15600d078cc4b0dd12b0f1d0868396554dab4e99f48908621cd42932fa71827c63d17b5842e1ce159014b15a7ec09a7b369203ebd0fbaf539daefd7eea58718ab60b15a92edb36e3e5bd16e551c6f3add0a626c06dc0d0f12da97c0bc4e2bd284a0aaae21ac39a46bcaf1ecd6f20cc86e18223a62090c4b21af10ae396e30af277779c9317bd8017e4ba1f5585bb049f3c73b985d0bb5c64f2c02991fe1c0a21d048209433ec5bb94d7e5833457d38b403f8be4ec4fe0106b9a666f0db2753562713a0e53980ed6ede5d9e32dd998d64874abba665a040a3862214de712a40054a58db34b10d0f0c74995fe0319fde917f702dd29939b669f005d244ed23e5b22c1cb29163cf2cf927080c243d42637dd92cf97fc5b4c382729aec665a146c9c87fa3abb5bc5fdbd3a5eaef27d913e8a32b81f8e188f1871f4a8022ecbd4100c55a071adc41098f082220416fda91fd2a4a3db9bd8564db849b29bf4129f86aa41068e95b22a98b6e472710bdfdf66c7177ec74d241e78a4f5c97c21841506d88e01b36bf5979abf521d7837209aeed998847a8696f23825c8993ccf4da8e4667f262995f0a239bcc060b49f34eeeb32c4613f557143010bb8694d4d5c0d115054ca9fae9cb2491ff858798a069d9f37451323807c1d5b7e3b5468b8549195ad5fb9767bc8d1d0aafb4398774af6e7249817efab6e222a01ab0db1872d575ed6e6384980da95fd1b3b94b14b2179507ce37381ac5d2cd19416d14bd02d6e9e96123d22834bba5a90d3b9bbc4969b75aa049cf9d6cc454476fdd1c405d2648ecdb5ae7d799233d4b79727744226873a4c4314a5a4ded0162ea732105e13a1684f9d790696aebc53ff80d71fdfb1490fe2575c3509e19e6325945539a4439e7df7567e44ae1a4d5bf1d42356362fad6b1be59d4f85370657442ad06864d31eb1d1742fb56fe7618cbee0c3c620f065a98a86108e8a347e4dffa6dc4845f23a5e8ce744cb360a9e975b6ec55fa6ee979caeccd6f660ac36eb12cbd87621a7e4765562af6485b8631475f8332ba92086df0fb10465628d6d68e2aeea3b43b3349fcb9e4ea7680d751572376ff61e193df6d36a6a888267d586bd726a3c3ab419a1333f27ca86d838dc3b99364163389b3c03041d38fd23edda45e4a76535f1957b65bea88694c1abd78818c9966dd8546ea8af8ad807af8b74e798e3ac506b095c64f6d3f1b66267a873c45687eb0e2f75d24f00e38c03b25b658cd3ec5fe6d2cc15bcc86ef8a1d959b21b0a996e15ec8517731d61adc9a8c860e9e0790bddddf4d08587609886c06ac5a362175430fc84df1eb44e1ce697cca0628b2c7010b8cf00905065a80c742d0bb51b52d8e2bd677e0107f281022e1450a8e099354c5c933fda90762a064927ae53e16c4a63cf14403165c14edcf5d83b33ffeef76b495d94652be2a5be6336d83cf02a1acc388eb4cf483f6142fa46f60294aa98ad475b1cd11c4cd20c03a9903cd4abb82031116e968fee99fa1650a455f6d99579d9203138253712b4c6cef58ea1e1db5a059f6cd1a480a48f0f1edc1260e666330ab7327649b2b52d463a9f93627076abdc8497ae90053559f12237223d03c0e7dcb35da37a128549305836573f872da487309b7e093c819ea56eb394cfa2928610366d12a33a2353dfd26001353791ef9d7272bf6b48bacec642683f1e972bc20e4f9bacc01eb481a42efcd779e524e9a9f33e9dff975a50952659031918f5b4c87cd1a9d491b078473a9547ed692190609b6168f252987ed3439662878443762c324ef4afd79de1696fd96552f2f20628203d588b17980be2568d765d7b509894775ec05405a45dc4df4bf52149fcac97fdc0d1d9b55b310b9e6d44e3216f7eac5ae46a998c2f8947a2c63a22c4aacde07754321886a379eca135ada54d09a226dd57a5a089c3f6cfda9e93856d64e206d27faab6056989ad780ebfdf63b17986039f81e4b1b03b22e193c5f58d1327f2e6d50ddd0000b3ef67828c328a966e6e9d9c659bf104a32773ed252bc92fe5211b10ab869cb64292415902763bf1efbdccfbfdce50313ff70930703331cbbbfaa9484fa1ef4e66dddf5b68f1a4384a2155754633ccb6c43041cc8172b339b716d3eea560f16561af26e1ab6627d56746d5804054dd257b076d44a9b1c02cd7f1965dacd590ae6ef7523d288cdf1fe8af0e680741e280c7996fe8385f77daa7c563fd5d20123d2346891f361108825f47f45fb78197919eba711c2361e9ff28f309ff91fd2c46d097c8f32d815897d296f45681a5786a1cb9cb2b38da2b9e6722f409b9c2248c7e63a8f29b1825bd5a348031971a7cd04d3fd8f4b68b281101e1f69691512dbe1f29d2dfac606ecc6ec504fb0e2faa977c6bfce79a4a5f78cc84c05823e44eafadc03e0cac1710bbdf865939ce3692ff39a86ab7c17bc8a4a6faeabb66bc1ca30456c9f167724fb8bb51afbf9411bef7c1cbf64cb1fc901d928c4825e5c0d3d3629f98eaf8c442696987f90f4eaaaeb867c3487280769ded57fa17fd00ffac6eca879310bc76f8bf969baa4d0500a4bf93fbd4d565f2784d17e6090e209a96851b359d5f7a1aaabe20b8bc92658643f35a350a12b7bd1149fb166a35524bdeafc3d6667070083d483fe32bf5e3f0e3b92e3f85d1b43c90eb3bbad188fa243434cf2434e8c0d01b97bf560620d613b21baa429e7b236f0d74d7c247485f833d91c84e6083cab989e8189bfc1d6279a6a4772b452abd98769786bda8845efaaeee97e68b05eeeca9d53cf15f5ced17d794459b529d81109743908a0add5dea488841bd791287e8c013e0ff05e70472745b740693e5745d3390cdf3c0c5d89c34b82945f4b144fb25a09915eff80dafcd28933bc6e0b941b13382a4dade16ea7503bf4b32f878e16f42e68fb3d506bcc188ba8f17c99b1723597bf4e3926aaf6d9d08c114ad2329c6bb86c339267dbd4aedf7c5f88eb4f8ad24e52d4672502083a136087c294f85420d33b4fb75e884e9748058d617fbebc819adf0b2749a3e9a03a7ff519a994b473d0d2f6ac2535d688069968e491d68b934b27e91a355249b2b1999cfa2534b7cafb7adb7a333af7920ec7b628cc5725630c39462b967cb7bb1d562834b4c99ea6c54a7dde4a3a0f855540b8c17364b8f7691296909d34a116b0c5d12611b4b35ea9ea0e78cda73f28caca5985216b23eba02c2e9e755f29dd5316ab9e1f166efb0e3bb90aa93b5cc8ffef47b3bc703cc03db159d3c0c4bc782c6f951ba63b39e5da3533920a0522748f0c0d1b627ddf6c3db7eb10fa702a4905cabfa9078613b27c7c8c260c866faafe8019b34507f2e7c9b9a03b98bc2df51995e9f4d12a5f18fb3fd414cf8cee3870461589e59526fbd54a90c3760c4838b0740be6d74838dbcc1e850c96971f149776257de03ab53cd9a72ea0a7477027cd27eedf1277d417e19c48302b87d45a0cb98d7c7ac0e16d1bd06c3b73b8fd1225deb4f5148ce7ad3f7a20f815e099260cab984d031d93f8dd36e389f4a2d25aafd3f2feac1ffe23505f0893a15f6d7710030114b4cbac4c462e8afb0f7d06e70006178aaa83582da02b75cadab30cbb9bff792ec372de18d733788dac62ce7560d5aeb4718b59de6daaf1f7f098074ba273016344e56b4b6c602a23d8e2227a4d24bd3152eb8948b66896ec4d90d19ba14750e01c7a838c681a5cd547e8f0d60bc50a8ebbbe9b8e8376c1f89e332c395ff8f29ce0acac65e3028fc2f89e9fdc0cb5cb130c6247fb4ced171facb202ec0a1efe53764bb41802d7f883b12db55af6c03bd44a1fc8fe7310b5902a46b21826c5809b1dec4ca2e44e0b59bb3f7bf18a287bc32c56d73a328d5c5290c994c8c020978f440478e64bbabe5d1ee5260b42338c3a7e8f57c92f662c9162a6cb30fbbff7291a27c8a627958a717e55206873693b17cc62f9eaf7f35b106b70bffdb45045592ea09257d163d73e4fd276e6a6c7db3919167b1852444db4ae7e0a7a416fd2c04b902f2ebfcc7636a417a6e76b10fc4b4ee9cb28a7a9356060533876a7d2cec55a19a324b28a498b99a320eaf9c058e06e3b2ef9b041bab9c1c59b772f5c33cf3f7823754589bea3c5b83d0919be0b63bf1c956ff56fd3e2e54fa51b8a0f9817d26d7ec013b17b46ef0eb3bb4a5841c1ab4e09e9539459dfef60901e85cace2a4e9af6e19b271cdb576d941849cde94b4bc6c895ed590db92577a454577fcb2492aec26ca4df48a650b6252a69e7f43ed82ca920a81703e9f2f40a4b657ee49ebb9f7afc910f7b02fbeeaa55efae9525185af59350dff1e0a8a950d41cb506e5d0f130a25187e8a848df5a9ae0116073f53dbea8daf94ef017e619bc524b1f95a2a392beb57e364bfcc421e920c3cd959aec995e0e478435d66c397a0395f59f646da80035d589b1461da57abc197a9f1a900883c9c531a553124737455f6c09c519d1c700c456d2574cac092ac89408cad6acff72aaebb6c5aa625d0c68dd379ead27e40f0440bb41b44ed65d46ceaa7975778750ed65cb4fa5198b52b8e2c833428591561bf601c570645a01ea64ee6996822d7b7d32828e31a259a33d6f0c48b71d6a41b4e1007b72f3e958d323a43454683044cc01150bf805ca46e82d6a346eaa9a064d278a08f81c38324a1afbde7305739b14a21ff597699863aeff9cfb6d16304ac15d067a7a8db224dee7cd3657ecc89954c797774447547eeb3e12a9405dda59810327d0c4c9e8f4d7768093c1704a73ef3f0f1859beb132051cae9f28d9e26555f4f0eaefbabfbf37600e92e61fcc17e6a0616c765a08f92c5bbb926eef8eae80ca6f627804e749b8b77cdc281ece77ed49692288ee85a68242deefdbf86460f03bc0925abed8fef0ad0faf9b0f15512cf0bb80c2c7371a998e833fd244c6217d0b2006d818537ef661c916c89c32c126073669061b9a60c7db8fad2690d55efbb69392b9c6ce035f5efd7b4ad5a6b50e9fbb4837e38210a888fbf56b74ad5d19f38d2ea7cfd893d05de178c61242d665e23ff8951dda17983c932286a74a972bf088cc6b1917fcf024c2396ddbe1f3f414ecfd0042e8b573c01d4b9c5f39431a72dd88947382d55ea711ea01117918a8524be297ce9aa9a03d410486a2f03799428490251cab0e4cf0df6b423062e0662cb61807ffac3265ef27a7d364b8efc56981c86efd60fd9191662422c0ca86d96f721088379af7d72dd00854c1d2bbacf0ea8dbc1670f7d4a0392d9207d9c2877bf2b28839a612229edaca88d5a7461df1a1f21cb668de380a13af6bac56199d75e086ebf0ab561597fbf99d13a1a83af009c9fa6656973454f297b69684fd4550b3e3931c5a48a10c1ccb8e40c636f06e60ee77d8e6c7b3e633ba5db845ecfdcb4455171e79973d0949bb0e89338f588290097e063a541116e425ab70362886fa265b646612da2961e02fce36525cda6864c1a5bf191922984df3ae966e306778e710db11fb1c6ec9174179392f30080c40bbf845eb4715cdc54d89af5adbc8e1c8f1ab5d122fdc614aa9b21e8bd25a426619747b2a088205c45b70c34623b0cad96c8b51155a5530bc037c70d17f805f2c83171f80101d98c2c5dde182fe81806d5d0513e8ca626db0188a52049251a60c1cc04c91e326accfce227201b51a66d5532853e924cbd2465797f4bb1f521e6a04bb3e1b3c5b79eba5bf5855d634433880a1ac0552079971ae9c0a538ce9e321a227f42ab279313b764c87df889edc52c3b75bc816e2f145cf290be4de80a4b226a620348f36f0c249c15955ddca043701a983f13ca84a5a4b7f66734b9bdf8ece49c8894d4f75932dfea56d627faa709c7a4053c8b0a5e29e19d5316a95ce95ba4e3ace4ad0cfb09f6209365b220c50c94991ab45b8a25840d71e91a00a83d3e249c77f20d50812050a5d7bc7220304cc7d2d95b725dd0f7effe618a1e3d623cb0307282b864105b00fab12e8dd914e8ceec14a226bcb55e48298e3f98d89a8afac410aebb480e92a1f2ab759725a53cee1121b26516c7339c59e3d190c6aaa346ead9fa6f052a337a0dd93f891d5da9b418ed1a830f550503fd10554f613038804de0876bb65e9ab1e4a300c49251693adff74b8fc64a26de1b32e2eddffa40869488f384746124f88e222be84e35a534c945899b03471d8743f6018beee47502311986ba8f59a154ca0d88749fca4fbe30d3c58bad7e830d1b6c636fa91048c8ce48a2c8e9eaf646cbee938b17bb4842f85536094e72f662766f1445ad94a558e3fe334f0525b94b999521f4be3c5dcbcb4db266e1e2f941e6ebf299fecf814a207b4e8c03a65eef433f4d2598f2879d6e7e0b9a4ea480f25fb012e2efb5df292837a9eb21f2e69d396f9e00f9725d0975688b7c810502da275c308cc6e50c8bfc1361fde2cad9a59224c6663369d407d17f92cf8702a3dad2843e1f87702dceb029d99e19fb2af7b889887074ef3c0d759cb1a6735000e32a345697d5eb7322b29eb81c711ba560656ca3798c723a0f5234bc96e36804bbde0bcecbc461c6fbe52dba43ee98bab412c41bbd583d1df05b4ea1eb0a4acf11e5b29e6099d774f2bc5e5ad37a10baddfe37ebc350321ce07938a325323599fa4d7e1229fceee5f7f5d68bb67870c35d95742c878a40970f4f41c491c4c58980227dd28c2f4589298e90bd8acb7b1699b75c5da78f844557b282a995a28fa051687ad53fe76cc0667c76a143871d1b375ca3768ff8f25ab405611b50159d03a8a7e6cf8392337c4187908d9920825b0e28cb001020b8bb2a1dc5b58d7d17c716c24b2c2c43d02187e24a807396968dc0eaa4c3cd7459c2ba7186a35e7274bd7bc2b660c4b4471b93036bc13bce5a3959f2592b434ea4688c5f4d6c2c6c6cb0ead90614ebbb3a9b5d31b6a851660fcbbe5888e901d6e4f9195c4ed69d3a8f315d480be407a299afd33e0ac0ed46e63b5c266f7dc7eae464317a21a1fcad737aaeaeea3fd8693f7161732f9ed0dd3baeae1a985fd8e36f06cc56d66456e66d058bd1ad742ec62d5d4aa0d099ff3e023f38307652de335a0342918244cf8f52f08f3b5b32ea0b9edc9d9cf7c350ddf63dfff1fb4b001f2c7d5c86fb8c53937f0e663f981a07ff42440775f35c8bfc0d24c9c6e435ad4d2e65feb58c96a9ee381a0f90a203194bcf17b3e0d096d51a2e690862277aabdcacd11c31e4139882efe9119e28512390449c4a851b1fb48a6fe187f14b39a18823de494abbb80c831a395a1405fc1b1e1f5f223dc52a859057a745785d7ead17288bbb1f0c549d81a9e9b0ccb0122193023411286b86be3c70ec60f3ed24e433c24f1139fc627a8210b200a8f29ad03621ada70c329bc60e6544a86154ed033d278ec30d97a785b63b39bac14fada937ed96ef67e9535505da638007630d76a0eadea413a7b7eee9685da1b410f34fc64d8c658c50a1373b09f76cce409cdabc98dec2088229f823248bc475400a04d15d7f972e57ff0ac69d9720cb326ad620e945fbff919926a31d365afab2efbea9e6e6e6dbbd359f1ae61cd4f7ca020b89729bbcefdee36e1e075becb32a064e6fedfd7805ceb082a04f77d3314cd9dd65e5585262836259b6ad26f8b9ff50cfdb32af64c70c33dd1789753e58b6eebc792c54cad327b8371c06380a4d1c47eb8f8bbc671c0facb49bed681ef73e99ae13054188923907115cb6d9213d88189cba007be3d90bae1e452481e615c8fdefcdef640ce41bb12e618eb8e2598b579a03e620cb860c23e75dffa1fb3eadad7a2e79bb6f983aa906faab9916ac4039c4093525152fc206fc78d3944b3694ac460fbe8ee43e72aeb6f930a5c75890ba29ca99b5d72981b5d9dff12ec5bc73496e3c7be9b8777d33fb4816158515dc85f471d70c9bf3ebd2cd843c33eaa6a46e2bd7e0c000049babcd723e606e1f9473f604e4cb288203092bdbb8d111f31841d64e20cf02b13a50f623d3a76441f421325ecf01689b6d822b83034b5ffe85bcab7b756ae836668c7ab37ae6106c1bb34ca36c2d235ed896929a7534dc5f4f256af2a175887f6d81a5eb5162875d549619402d2a94e48d2a5805320563f72c0c72d9bc2ab4405f89569c2e3228d9de18a3895afdce1a9384349ac0410ae9e1060dbd42ad0d7306600f2f0317476fbd364a40dbe61e9946a6c88167a0516fa5763fab3140e9cdcaa3a1bb9cccca658304cc538bdc2051a2664ec649b7a2e5aa756c9d11234a608db6dc6db08676165a69788fde763d94fc9314030113aa9a2ff629ddc95514f184c7e7ce041afb295a17577409c9881554eab43528326af4545359b1f0d00dff1882890df40a536b7e95cfc14b77efce2102770f0b67fe29ae45d18985e19d105401533cbb0fa0bae576a7ac316a338dc2a50f4cdbe7ab037cc3d4053c2cb0a815e89b4d21e3dc339a2618f191fb5721e539976bc4fc6a3ec88e45d5981ff91673a61f06f16bc0aacb41b1cdab2f51fb31520389910599766002505164028b2fad528f695eeb35cc09ef6fc9c185ccc67185c6d62884199e80aefa63e9ba4f3383863603d2586be5b3c7b84a6846e2f02700c64b8f2c70e2f6f3a2c4124fa28c66b0337125853defca8376a2fae96b9c9f919eb762dc4af1abbe5ea21555f6c24c0f4731179d302276189055b593ef9ec686b2e67e5244027bc2d220298bf53b2d608121e3f4efea1e5fbb0c9746b79cd29a2f2d804b7e0470e6747ae0005031c68572f01caea800097e29474454ecaabeebb9d0414a69a166e3d1e5f86fdacf7331ddf3c10b38bd8b6fcc27cb792ed75da6d686172e7fd8e34df13378435fd04f5660998d2e65ffd41f51897e4badb5887b7a3477cf0566251f44b52abfc8de64ad1b7b0794e7aa935211d91180a60a540e65ad5001d8144664852401a44fa1c6673a6eb3508b222bba8f781d9cd86a6eb38923b9a1e6cfce80ac32428f6539805ecb578901fa8bf311bae2f6b311104cc548b085ee5ef217da8fc5d13c43ba6d98aa88d8654a0b1e5a579ba6230e50e4a176d38b5328151ed4c962a9a3ada05202fee23fae5a9b35707d8cb226d81699abfc545d99cb1e87993b15e0ccfd4cbdca6dab24209f060bd6dbd85c0f8614c651959bc3dafabfa2f09a6809c5bfe17b8ab7b244ffe8feac3d3122f91166cd976ffb6f23834af19f79a9fd5982af4879ccc6a38af50af199a471d55d83a72cd78b42aa7f621bafeae4532c9ee7f9fe82924671dd4875276c847d4eb3dbe8784298acc16656da77f2a02e872b5cf6c8b6a2ea530b38871f697a456c63bcd21d6a2951465c065ce7d8dd2a42f3637903306833d05aae8820e016b04723fc58781797d3c582b8342b63e82b2689a80465ca2dd116ecc4a3701bf3cccb00558f93236bed42ed0b7c8fad10db6245e9d7eb018cb8edd2658d56ee88345cd7ecd52515024771057fd4362b83ba8b10cb70ed0b297c8afd8df8b4d643bebe4d2066b40e867e730e28bccf5fd910b3697f52495ff972ca6e73b68993566c228c5b5cb5f8dc7bc4679368adc15c1222e04c4e13d2b6a7324dbaac041590d49295e0fd4506e5c9ba921e69720c08ec259f2a3649bb36937be07732f821ce1b7fed7a90cb10866021c77f836cc34b3e4d1433da1aa80db378ccb1352b8df90a3ba3ee57330ab5d3c0faee8ecfd74289944f6f8d4cbe95445c6c193ac3c4f124c9133bc27424d6809618903f361cea28c3d356c59669d9d0a673d2817a5a3a0053e757c5b294933dd9c3da1266630af4785f7c53f581a3e8ea8eff8ff01636da7e2664bad7b26a6e11cb8d53fe14fff1050e722af94b8c9e9a48b61766b78537ac0ff8d6bacfe1fc0d10cab7408abf1c6086a2a491c3933d0ae0d81c4dbf0905444dbc96d18e92b29cfc68a50ffaff0b69f54427928034b2e7b025a200798a706b1687ec745ac34244cde2598a24f85e11c604748f458caadbaf7a911404d97e63240139ff6a5d5d4a83554b736c0b3684a6cf9ff6f815f82f9083c25752498d248971fc19428187400373e24027e1348e5191f465133a798674ea682ea8e75e861848ed54839db38888306a3dea5d91d4a7859ec73480bcf50df032dd37151371710e72711d2dddc1cd47e4119ff551e3b5a4cc67c692967f42fb3ab2d782e10ab436982b7398dba6026f6ebc8326711de7e9fffd9b11f48793d6ecb08abd8e2b2175ca825c0dc2db7ce1d3b2e77c214ef829eba0fb82f05df4d2b335d923d9e475f567d93e62c3dece08636c5d8979b6fd62690b49e30f00df4f657602cdc534f80b7f0316a51ec94d76debfa60ea319890f2e1bd6c7817a80c83bf74ba6cf55b9bc77db5f0462e242ed63091dd6e109c19282d0bf99a717f5330a8a22fb0925163187c80ebac059e1f5c830a85e65fe07fc230e8861b9e68228ff568dcb4f53938e8af787905697337618311387f22becd4d3ffc69356d3e7f771a4ef3bd1d99ceb4bc0d0cf5b959820fc7b68c45545979535fa51b1161643d5e86b8a133846a15fb1071ccf38d41f1322e0bb6fa464534949056a8c3bf257e6170e55f66ff1a594b5d3aca666924f91a4ac1f4ef7b478ccef97e6628d444027a9e7782b7a240f24d1e19ea2fd216256f56b13d733bf05c68921b0af9ff1474ba17b983af47b249d86342be4a4be19d9fb266e0412cf0d95795cf6b2ff8a25b39744c4241f4caf156566d7b3df45f58779319e4652c237b6fd1bd6ab723ffbeba0ad1edc911cc1b21689d49341fb0b9d25b46aec4a2675e7e88ff283559c646ecc812a2741f718c4550f799255cb3a9c4c6df4365e725135623a9f1d550d750a35b35ba7eaab9a086a60daaff39df4409eadd6377c1dec954f95002e9002658eb31414a132606c5aa5a4d1071fd3a52975d0afec7da0057e23ea82989a73e0eb18f4d1a13d94549c7364e36d1e8f5a72feeee1e4934fe75b649f28fbd43b3cdc5b3c3b001959baed2cdda08efbfc3a09155cd784825d2e6fe4721fd69a1d736c36333361e5567243db7a3cd33c98afd079334477cb03603f4f9084944ac22f7540550eddbb7bbed6fa4570b52d0e10d46b1a633e1528f5fc6669e9c3ecd8a5ef415b5bb1a2401fdbdf45d1aba65ba24182e3a8a3a57aaa8cf9e66d2a8a34628332605c787592edca384a419ef7d589f492694ce39473def05381d5a6cff673718360207cff45e82d88046c79710094363e419ca037138dd09bf956ed9b02f7b718d92f6cc0fa03c13d13f3a0bf9b86d1cf2d091ce1a2c319a28cc2d178dfcff1d51bf8e96376aa936ddfa8ec0589f9cb3fcd6103704ba982c1ff428e426921b2b28ed5a3e65f239a4196cd1edd8d0e1702cd1ebe72a434545fa8710b9965c893ec4fcfefbbd4aa0c9c113f91368014ea0827edd4638a2b25c7b87c2c4bd84a62f205c1cd56e451aceb2e4acfd065e2776da244b44168d2e0de3e4998f4a93fe6f3cfaf9014f45cb4c945a8d669bb04f58c0b10bfe4b700733d8d78e6206d3de506ec06dcdcda7b6ce88770ac0579d8091e5273a6c2fdf39622e39effe80dec5fc74ff1e07283092da236687b0b9abc810d707a1d4a78712ac2c5e3af4eb51e497e60578102c67e9189c3b3ac276e096c8338ceda417020b80c56f633b6154c38df7467260aa4a09fc44e8c83f7cf9174a60704e57aab34397bdabc7b01c4ccf18a36d1c7e53ea5daec2039396a32be0966ce09c1294750b70c7bb6a79fcb73174bf7e37e1e0aed18d1977efd5e40a529eb47f9a5687b57e8ed25a64e0971a3df7b89187f510687fddd3b5babd2675a63983081e687a4ed4fe3cfa67195bac2f409458ede7291c435e4861466d03926c69cc3e21092e2759b62f9e18ac1fd3c7bde671e2efae4138476027cac131c846e650c9a8d0a866f35db101ff93465b5d3196850994c4204ab3e6fbaa02231b57249f4c2f7d8987e34d5835f455bc9e02f6a97f5494e1c5f5ecf2e2fbe481b63315063b7b64d65b836886f03afad6d1c1af0ec06f49eaf8776f8fb343e6094e50ebdc2292921116ef05f079e2f99ad31bf0b807606ab48abe4ae3e48a963d7d8b5e402564da2cdc47293e303ccc47d5ad658724a0d8c0a2c3695fb5b71f87a5025df6850b7b2e853eb05eb60a307ca25dcbd29808e51f7d10e0a6a43b3c6b0a660718060669008fd89e3f33b1bfc3b406a6c2c009240129b147f7ffd8f622463489aaced98989077b0b6b2949c7fdaa9f65db9c89c70af403d55c381b336f695782969c95d6787c8c165d975808d3c85242b62173ae19019bc735c1e5908a42851ce905f8130d0deca77eff4efa4869a89e9d9cb1ba21759234104e984036d528ef0ef51632feb85e37af26d263015ebbfce15ab81aba53e109acba5a14ea6a68f387baa3c95af6d355b0e678fc58d25df71048d9226e20026c722c97e3d1e8e473c94163d66a1b715e69865ed4c11a97f2574e8b6dd603d22231064b35404f8def2a019196ab6d0e8270b7e325369351510634150086f67945be2519616a001ccc9457bbcd6b38c6d3a9e0f875f9c1358e021c0df0d75d8d90cb2878e6eaba784a357a35bca2032225dc63a5ab707eeeb3a68c5479dc8e19165c81aa82edc8ff174d91a5c195a778aa265f35a4b7adb596caeddb566d86b15b4ad446ebc4a7c34889d0f69e6b820ae5ee2d1af24d3119da615aadb269acf4b52d51ea661a810cb61fad7e0320bc2954373d0829a31594bc99a2aaf640759aa6f6ab6afd524a29a4e10836398a91aab273a2d70ce4f1e6f1d5b7a135197b578caa79f3446d1a69e362c850a59d2dcec90907b88bd4c55b5e966849688709cca66bb4ec87ddbc13e763d2b6876ab66a39a381b05e81ebd67d981b5bc036b802fd129e1a68d349e0d6cf660c210298bc40ddee173b376edac7e977e029ed8552ea14c253bc3825855775653fc19af17fc74c6e98d85a6f5c2e07852dd641adbfb7c6b3aeee07da82d59a4fffd6d3a47524cb657369ce1ef819c449864c5ebb288f42dfc8fb2a298af5995ead97163836df7a97abe11fbee7e0baae774557b395d8b623b1f1ec1018327533e38f216f6c3cc44b28ac415ebb425720374f082c1f07a55c33186370c5592a63d47b74ead85d6689a2cf115fd1b276730fa141465f13b6f8aa00a6c59f7c889f7d5f5e5e4047646e360e88184f8edf765c6a7c1022de11cf54b09ab7a3118d6508ec96f4fc96b21618390e680311a13932924f5831629f334cbdd0bc92974300e997a210c8c258e164298526666c79b17123d501ee0fb7857a5d374e4957afe58a8faff3a13b796d15dd5c3199fca2025e2933c9ea5fafd3b58b8ff5714ed82babcd182663041a07c94504a8eb3ea24d387c1ba69fcd89f8eeae705d119aa53cb09676af6e1c9f87b429ef5d95c2abf7fdb48d68962b48fab9286febbcf7e82169866c555f8729272f217226fa26e853a9ef7562cd1d2dd6ad688370d848ba4b67b0efccae7becef78840386f6bcfdac20d2337e80adbb871a60ae6d666c091ed5df6930b0cfd9f460d2dcf40d91a5cc870e615b4956457f6af14b88e7dec7513d24d0167a277d2acd0c17b3fa23d524396e0396a499ec10436d9760c2a10b13690eaf144a6792e3f8c58c905a52dbd8c5b2a915a7d53a901e9e4ab69879faebea0d5e6a0c93b0ba582d990f4b37691e71fa7eecff2f46d6eb038cbbc6aebeef7e3c93a30a162b6fc013459afad7403915981fca67d6dc351c6d95ecef7327b1b42d24fb12063b239b21458810bf2e180feefd51bdbb0206050243313bd351d3fb5cc973137b0f8d1fdbdfe7aa2676ac7e1ab4c2d025b93abb8192aadb8aee09cbc0bccf21ba0ce528d30eb02282624483451aee0c9f3c78067f73263ac8d6a682a661d5ca6caf3d098fc10f69e9638cde29cf3910c91edcf7997ddca9ad4f5ab9f3e532889e2aa9d2f0a0cc25bd3023da0ec2a250ae3dfea81e6170d219b353a92134d325ade1b1c1b0703cfc8c4850cc4d86b17d7578a3bb238c84381f0d22bea80d1aa011131e68f19c65cb1e4bc624007b5447e27663b597d5dc8b5f8a65b9717eeaa16db01d9ae46f4403cbcda7d93913f95231f1179aba3c8eb2ec4d3afcaa5319bd28600ef4310ee0fc07c37eb7486c10b4646cc34b65556ba6ad2df755377c2ec030d08618db4c16390c02706ffb4091f5f7eeea71be8a0bccaf111b31e28dec0aef684167ce60157cd2f5c6ec681e1bb3be6e26fb2ad50db4c6af4555956e7d77260ddf77c66a1921ebac223801dc08209136c8f7f4b3eb7ae4c6c51328908179bcd1908a8c9367f6a624053467a4a529731d65fce6c0f58ff41ecfc863f4d6afd468f73a8ac6165f9ec0b81181703b5582e94e8aae699aa94206687e9a7bb99b2840c12cf7656459a75006f0eb3a851cfe1000ad2be3e05ef8e3ebe3ab2faec7b305b598c90577ab411dcdfb704dce0b4e4f6694e88895904f8100cc34c7787aadd4f98f2fd9def3e34dcde213adebae78403609312cb50c0bd11e5851132a0f0de633b3cd39b92c05ca2ec4d6ee506d67f5d5d6ff28b6b40cdf0580f079c7b3096077c8ce1e0204fdbd5e4eac8aae821b2e3fe61618a74299263a5ab0fd29e7255084144c3419f9adb5434578594fc5fb772cfb79be7030fe71b997b858083ed760c228f6cb4928fb3438822037da8f4712f9243de262adfb3a4364293bd50fb5470e488705695d4ab4b5e9edb9b64c8b69665cc68c42c8c3dc82875ba93d87c83dce83e6428af1abe244f540e4c89d0f00b2b86c79618401e30da0323c985f1f5e4ee788bcab3223e403be1af41c06d46266eb272c2be2ba5c0890ba77e04cc89a6488a900ab8a7a976dcd7a7382e36cd99aee74c6870c192c0832b4c4af1e644c11d23c4b1bd04632869cc8bfe415210b18180c266482f66662268b32ec2ea20bffe50127ca1ecf1db0ad1838acbeb91dff4e9186659a06ef70a41a85d1b3871c8be9262ea330d7c6e18f6a7870beae99e302e0a036fe9e3928c7f09648b18ef15bd6ff626d28639b6b6fd808b7536d36af7ac8a0b63c59163b2d65015f89d2e06657bd19a19927e3747c48209bec02078fb1d4e450e128cdc1dd14f570d13ea3958a19782fc3cd03ac74f52d03e9fd5551fc1d9ced4ebc29ff0b863c6989ee7d9661c3653700d01673dcfd504541b2aa8cd91e49a005ae270d5d1170abda56daa1004dea9a328630eee4695d40f83866e0e9ad5af4b14edca1ddc5d210e9dbb2a6e89d94b0754a23cd7671893a694ef2b63fd5be1fb918aab341d7e4eb5703fd04faa19627cf42df97f8e1730b9d7a444e8a64acf0a13de591767840ec39142e7e4e6ddaafa3c5d7fc0857a0a5370e89df339b23ffdd9b209c63430b68be69e375eadf9961c14056948dde9acee947fad1bda78de64180a92143ff4ddf8d90d38d1af41512b5c754430d84a0fa11f87356b95b1bc94615e7c0ae2da005e86529d6ad2255c43e8fb7fc7f0e4888132784b6e6750072dea3710705bab05b71c2a5d5fb567cebf4da4422cd27118eab5ab83badf2e31621fd74e899ea8583205e6e48c5ed0a32bf329ef9d3b91fd617ce4e51080c0c4ac8062ff2b74edeacd6a5a8130fbb19cb379cc30a84be52c0e692f2c3e061762e393c66f0677e553201669eeb28ecc54df42e1066614a9ff398c69905c485e937df258a28df3c5c5bc50953b8594b3d6a01396354627bb665c222b5b378c5af92db1eb29757eabfb31bd8961ba06ddad6d4d3b2cd74a5747f19438482f4ccee0d7549259283d239e3495e01586b5ca8b77ee2302bebf9051c71fecba9603c3aad39b239e000edb45f3b163110499995270b78c7c518ffa892a9b4886b59951f7d7576f3d58c84f950fb0c08e283b167d8b357a09c5efffddad9e6d00f1cd24b07c1f44a417bb323ef0760b0252aa34a5535484378f64729669db6b95123eabc91d70ebe1014cecd378ccc4575ad74dd49d312a403a3aca101b571e05e4835840c116a09b312490ca24a8765f1428e348d769c750a56779ce5a9706014c894b0ccb2b010ef84fafc03fea0fbb528080736d5a680d39b3812baaa39253f0a99ee71188486bd76d0351bbb62b3bd8fede8fce6a3a2ea4365aa1dca54fad038a91b0417e6b1a48c747af5a1b84865c20dd4ee1656a243fdad1e08fe9323e96c98266e6526fc282aa455720aa6b8d14adeee325a41c4ca4c626978d6ac24fac9648a48b96e63832e72bee3dbd60a4ac58b6f49d2d3e703f7da9dacc365bd2a789d3681b645d861e6c744a15c1b8f06fa44598c9bea97ef71886f83738bf2d098f4c0437e0034bf2f55522614a38a6f3b668e41c712a2abf93cb781fa53c7b16f87856c06719b946fbbff605cf571ce7df0ebfb91c49d5483be7d2a0437bc4c085fc79112e8621153ac5bb20ddedec8ec6c3d9290ba43a8299c79d89e384c55983a86d04e8ba52ecaca9cb65dc95705c9733acb92d01944ca807fc3bebca9771f0523384ab23f9791df8296e2c44a03adb4eb8f88d53d6a886c166bf17c2d30784674db11d42ed3900458133c6dc0f9a5613e7e5a78d3c42a15397166df8797a8a7b8c0d195e21f979e1921cf47636779548f5dc7a2e9a21fe33ec0ff6afdc6be097c3a3f02321e6d66d3883c1f9608a0702fa20490050f82d37703c58ced685b4b1f0bef920f96a6fcfa7810fefba487546b928d2c59ac8cb364059624ba1ce2de1c742a6ef5452cedee3e0f8e7cb1ead2c33a81e058bab9c06c32ecc0537ce874cf90af714db6918c5f224fd9bd9a2ffe5186cdb56458ec13500ec628a89a1a92d23535464ea59fa4887e6ab8a77de41e02d66206ded7838f2cc469f13bc532435d59fc631936ccc17dd64981286a094ae5bbf695a9cf5fd2384b7007abf5f44306d19e8890211d23b3eb3433ecd3df91032020d76c6e31dc8bd9e2c679f7a9900ddda35b6f6bfb0c64c68aeed8559dc223222a3860538d61cabcb633b7d0754322e70e04543738129b39e13edd7a7b261a329be0a5d9f8adb76a121461a123f8a739e469b804651a24f7194c00349c1a040407508be2aa0f4bff04b39dd39942ec35e889536de2aa585035883157cffe293eb149089766ad96a4a0f57af7d5384197c53877503345337e97b197bcd951767a86c6535bb47161058f9a331d487dd0065ef0d24823ac1b65dc0ef98610fb9f41020816ceb1be08078d7278ed4abaceb6fc3b794bdc71a7a574f32ede716cadbbc4b179578eda1e7a6005f66ffbadbd8e99d9f684ccf479eb60485fdf5b6cc3be747b65a44c68f9e59603881adc31128b62f1b32531aa96f8deb25f27cc21619f99a64e71f92f096e0255acc42a52062cc90ccbf9403912260fce0c3532d8966749d5245ea1bdce2b2e326f97322707fea0ac3eca59f02757fe3085dc0b55bf3679543f0ed7a13fd0286b39b4f938b5e7be98c0250cf1a65dcbcb27f06ff3176727e9075aac7088d3be86fc9ac84d223b89f96d3f929cc83adac2f79e372e5000e4ac5cf07531d26af2270c6caa5c1bf880264672b27333fdbb45398288702d7845a39f910fea972e41232bed4686f5f4808a695976b944be82824bbde5a82df0459f361eba52db16e5efb723db95326e89dec8c13ff4119e72bef2e2d48227d8ed0077084700d0a136443dd0d86b2c9c327feb1abcadc2f6d2f319b8aa5ba3c3ba327d7600b5c3ac6f4b14e5b4273c1a6d2bab4e2bd52ddcf5767866420f465e7f56b63e6e0e50d7b8937952485c8331b5757a4e5a84fe3f0d6fc85b95d182c4aac820095227706a2693d17faff900a494b6d640f1474b55bd92b733ab20a3cd2e299584030a7e07f64f6b1332757c960b5c5a02e3e4799c6de0d671407285d44ef5ca4be8ab042511af0afa7b4b7fe82421003e28c5aef6c27bd1555652b17910914439166d2729d87251d94977c97ba4f2433a9f163e120e55b64dbaf4bc9bccc578aaf732c3007eafa8d75507721e4f440185d8e632ecec13ed7c71ad9aa5e92161cdd92c9f6c1c8dced968454eca88284e8e2773c8ad5abeabcbe1a75b153f52f52a283b0cf2b3a1a3cf6545cf3b35dee4ade155b613a4b123ddcaec6a9e987f7bdfa772a985040651bb670cfd342577e50d2cd9ba618b4a6d70a21053a57de473eba8c3d78172272460fa35ab033069108063055641771102ac0b0c5cdde74946fada228a7b963ce3e675b8f48d1f1ea6a07d1ca4614d3bd13d1966e068c4bc29c709e9672012e78ce71facd3ba40e61a40607ac1b00105173b974d526f7f898ff9f30038630005ed29fb8d09cf8ac88bbb6ce0b0250edd959bb4ce4c54abcbb520b556af46550c27cddf0f6cd5eed138c1b7d225278d1d5f115848a02482587e925dc625a5cbe223b126d82f6682aeb833a5cc73a59f92dc369c4e4bc8272e1b08c34b243fbcd4d3526997b775c76013da42c6e3292a31ebcd87adbfb6543017f3ca4470a837ca0b9d50d3ce462284117271d42bb1b9284fcfba8573a60dce50d36d49a211175735ad505980b65ad46e4e1d57ca0ee47750d7d9f9aad3a6416b68d1add811c4ece80ed94645483de1d5049aa5c3c70192d8392e117fff0dfc98f48ae0b160cef3afbb843d36fdb6184905c8e94a3ad6dafdde084a6bb880f7ca7bba1f30210f4f930479c132d9c1a8a536e31cb2f23d2082bf96cb68a76af94302f429519166a3df86190c2999d97f86430c091b49dc82e1af44abd1d6d9e90df8ccb5e055dfa555f03ad955e0f688c812447b5e7d13ed6ac6ba90c1733dc264c6bec802d95168c17168d4d657914553ac8c6d6d44dd63f09a40466ce9cfe1a49d889de83a53cf42d118822ee27965754943db08584331ca9b03cc99da43b87f1c6991e395a157d5233a8003dadee4b675b1b3aaf0284f0534791af3c554a58aaf490ef8065b47af2a12c374a06a9a17354ce4d3ed2bc658ec99f222add692cf96cd72f23724a96314faed378fafde762c04931a3c61979663e69a606ffc5223d00f067463c560587afb4c1029831e43082caa6075a1a42d9f98dd59c0b1b25f5ec51b3badf3dc2066139cee7458534ee04f2605e740c54f66385e4a2d30fc4c5a7e8784e7c4862e362850354129632cd37477e5bae6f8e6d498a5b1bc22e12639d1fed3115b250e671f079b73d47117aaca902f8a05bc22bbc903565fa83944b3b21d3418b01f86ac3b4e63618c638f42959969d101df9c46b04e92de8c69a7a0a9c285c57b3c0061182d9dd9b0052615416f7a717f509460c78d8715d65328c400bd5636af419a8f7bfa426e30ffddc3a343ac5db3e7cea6da8af23c2e298597e8f159004e8ebad4858a78454147b69afb5f6bce691e20f89ef3c4ede28b3088534ddde06fbceacd0985a3bdace3d5ed3e94a809f047f54644e8e7d0f446a5c55bfac074280c6f9dd4323435f07b8d1a2af1f5391647fdd27b1360acd2d1f25b27f938470b770016f512fbd6d65bd706a3735140af428b9b58f877315fdb279380df9da8b430a1b4db2650d4612d026820dbbe809dc65ea82909c071ee87061a8ff9ae1e10fee856211552b3ca06a87422f173bc209d816ab8b9fdb60a875cf74de38adddb7ab38c75731388e2636a67ead29d3f8777f7e75daa2dadf65c1f93ddbb5351775e8eedf95b0ec8a908ef6b2c34d28df86e0ab1f83e9f3703bb3ecd6bd0b1f0610783aff82d0f78087278e8faa73122e08c51d90a06c15099176778ac162d7105216b5a6d700694a91c452e83ecddf2cb39c95e0a975cefa131c2ab9ec90d9a486c970d4a4c0bb80cd6b729956a62d893e8670cc7aa61c7ecc306f727e08abc50f188ec64d5d51ee2d33ec70d6e8c98a1f0d7419acc6fd9b9eae337dc0466305b34866d58055f95294780474d93b71d18c824dd7918803370791d694c54d041c7fb2ee2fa42bb586b8c1712bbbbe0e08f5e095e1a6fc61eff7b34230b9292937ba4556c9b8b7f0858d9dd7d0200e246ebfc46a33b3ded8474f9824607e2c17580c429b8f9e077ceea392902c0180fbbe9727ff7aba696b5db2f2b9504a232df3846cdbe4accd81fabd22d60bff6a7e3b8397d37735124b9c7f764e88f51f680b24b4d34cd615a9ebfaf176c785012d0b5dc3b7bc95295be4ec7c539511ed0327db998f41ad59c3687310d8739909977b25588330622e53e03cba7679f3b4ec73f5f0e8dfa8485640e9a03970f5dfc23f914b9a1099973ab2b2e8b5680f1d03f395dd26f38a06f3d9458de8d1c517e598d81eef5ea6640e97eec3b5c826480d93d05484038768349ca5d18ccdc8be246e648ee677f18dff05dc3890cc3e95120e60766edeab079bb786b28a5040cffe770521e19a19b27caa41953607819be6324838328afe7ffd91a7968ed63bb0c5c85f698c31833c5a234dc9d42dd49c5b4045af807c378b8d49656ee336ce7fb445b320d1038a9c0fc94be09b6566fd9c59849cb468895e9d0a5e5906be6b1f02b63b762c98c6e878b4458d9f64d68b530805ca20074ba34e8603346ae6c92a1212e4b10d1e977c962aa65b13b277d63e74f5b858e49ca1bf093b48b43933e9daf68e0878fedccc6bd928345e27393e6aa3b92d09b1a0926dcd61ea930200a4dcc55bce3aae63aa1096911663283d3d0f57287099a43f7213246640b08e821f63224b6311ecb58929dcb578ebb2499b2d6840253e1bf26bb075020418afb0897f19e3b61c6235784c2d90e0f345c1aa493e5ef7de00ada084cdbd3c411ef75a3caff105dc291e00eecb8c0c6416ab3bdf792467e5a92d7a609d50e5ec6655195b6ababa7bb192db743ae3178110edf076de0877180ba92c5fc78a3e97a914030d1d20080413738e9e30f4edc84b8b982cacc0108e2a983db7f23619b16252003ac480dfc201309d3d93e6771ee340de11859b988e19071676a7d733aa402772f5a3d5f2699f5f22e537d366354a46a37da4e6a33b077294ffaf3746dcbb8849dcd0f80f7a08370b1ace7c3079b6c83a1913729f68db5a4d2f7867f17b233c9e4ff6ed7fbc8cf0e9d4fa845a03a787fa08adab812c932ec6c359187bdf1d16c6619da3221eac0da810284352362a47ccdbccbcb2ff755361531d888091ef4ada0b696e1a69b96d87f53a51cd9631d172176eb0ff8bcce6982e0c834bec297a4ddc2b6e09e9657265000000300300000000000000000000000000000000000000000000000000000000000a8faad192f82ac636cd9497c9e458cd5b28cd923a722dbe97ecf98ab83c7b7466bf03eb0d089b1644a3b88838a627bce3754893c8cb44882a578470c0e07f4af0e9d4fa845a03a787fa08adab812c932ec6c359187bdf1d16c6619da3221eac0da810284352362a47ccdbccbcb2ff755361531d888091ef4ada0b696e1a69b96d87f53a51cd9631d172176eb0ff8bcce6982e0c834bec297a4ddc2b6e09e965ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff84add3c4fdea0b4443027a17ca585b8ce2f89dc69d42a0611c556c62b15187aea0c5b586c2b892d872fa5a038fe6171b0a433e5c524d5ae9d54994332c7b555eefe467af065208b25236cab7a59777534c1643247c0a4b3d7f42d8309f093b7843006600000000004200660000000000ff81040000000000a07bb4f7ebe54c991b8f8ac6f3570370f2f88525581c785a5d35f4195ee689b11415c3651a3247dbc5fb0b39a549f5656292f70bdf69be142c6d047e6aa0ab2400b13d98a9ca474bac23732f9e7489760d2e216ba5162ab01951309938634ebcf40000002656f143437cb74ea68865dd296c08ff122ab1f4de8417ef299950428af70b68336488033fe5f3ef4ccc12af07b9370b92e553e35ecb4a337a1b1c0e4afe1e0edb56114e00fdd4c1f85c892bf35ac9a89289aaecb1ebd0a96cde606a748b5d71384236da69d4956e929c3083769e658b44b41d4ed3005816d5fa327352a595dce679a48605be2310d874174b9d3cd298e529c3e0a73e407347b1ffecd30336885124fcc2b3f99f571ad67d075643c743f38f1c346e4430d2cab564dcc766fd25007fd563b2dc452a28b0467bd422c6aba71fa8feeadf933b4867ffd7e972b7d5411d1ab0f5179b2b1c9097a02bf8a1f1a8b65c8641210023ce64360230218020810d62a4106356085c1601a206a9010c22a00a00680423c902444818f851120c408019048a04000898103d2407601f123835a4e508884028040c1a4dc807c74e36188430611301400154384082d93444e9f61302e3420041533304270564110408021a2330581e1208f2140400010a5141182ad641312258a0c4089204e2409801064144000c0403e90020086026184fd03900a08aa4856008827400aa0229e01a3044028d400323442202239484224901c20ad14108109e112000008490000804ece28080804c05022821520b15000e0822e0002031a00801a0028000dc2688a00900010c101080d13800d052019a052301f14457c2dc79a839c731c04641317f30bac151a3bd6386297d05508f58527ba7adb529110b010000000080c3c90100000000a442a700000000006f338e6400000000380200001396143703000000000000000000000000000000000000000000000000000000a988adbd0bc071dffebc194167110290964aee087071da64118e555313c02f7c292edb3981f87eeb03704a232b476ce8fb3e73ff03a16264a45bd907485e59799218cb0b065205024eae84c79ede8f93127144c141a42840b1b77521b48d62906631622e696f000066000000000035620500000000003fd4154ebad20e5e48f5283a94444199024d004a04f2d021b8f1d34cd758fb4463c30e7f8ea4d29a514e6887a0ba301e0458835e7c5cee9d6f74a0a98fd3063fb3c289ec2781c918aa8aec0d30d49cca0bc5fe9cdb7b72775ec3aa6035778bc7f4000000f1f29da89ea6dd9d217034d581624e5863f183caad5227e7da582467b5e9c97a336488033fe5f3ef4ccc12af07b9370b92e553e35ecb4a337a1b1c0e4afe1e0edb56114e00fdd4c1f85c892bf35ac9a89289aaecb1ebd0a96cde606a748b5d710e549c6ccdaa45b7f4fbca7a4985682624416067bf12fb23197cf7ec6101a9aca20693c2c4c5333bffdcd97bb30df3e883af6905b042497d5a599e76afd00b7c690b9a9e9aa1c9db991c7721a92d351db4fac990ab24b482f3f90e6bf470b09129f26d0a48d16f4403c395a295a86d2bad594bf2b3df91768e08d546dd0a644b72dd50e508ef836c67e3a7f209f2c43a8cc8c40d3a71826eeb4993b41d0e1ab4a22562355028e03806007b51028124e0fea915095341214141081b4910521464a0b325761babb69888c4ee1003461916c16d17f0159c2018e6049a2c1bab66edca0ce4a404a751e0e1449b5b26315c149a20e29152ea44009702c3050e5038a0d4be2851c8d84641414c8503bf50afd2884dca156a424c500a204f73d7dca00d13031054c2bab5838b00db88fc35014c80b68c368e930365ec0a2b302a83d5ef9614ef563c604e10e48ba05643309e6356dc1a71009b18a3b116c4e20a01d8980cd21409810ec2ddc9da321614858862334c789a0dd3fc595884c09878d5ea83f56fefcecef39651bf6dd04c4cd81f1372202d178f5364b0cc2ca6012b6a890c45f9c558802429383be8ba0a1884064187848c32e7100b010000000080c3c90100000000c59fc9010000000057308e640000000038020000e3ca3af0020000000000000000000000000000000000000000000000000000007165cf8303190aa4432936e9fa946b2bb699f10b3dffc356abb1e772fe12ca3baec0190a3997996316d017a2496e5bb4ac498cb65ec8ce2e85d793c32fefcc6bb24fa895333d0b64158d1a3440297ae299b35164dee07917b12f9213b43de377627920406275696c64657230783639bba4da9640620000aaa0f5fb99365a057f50846de29bf97a6ea076bcae163e932a3883b1fa474d2532766dea028966fd22a6892ffeaeb95bb9a7194ad53d2ab8aadde71a7052c0906ea23e9d63eca689de525e8aeb8076abac3b5a59a7067652bab32d763b7e1be989ad3b2e3b028a6fe43997374c09c3ebda8dcfc45c7c06f0502fac1c87f7d42748736069c57e122ecb5aca6c39f2947e8258cab2a8b8d055b0df23e6a3005c0f8ee504e20d4d3318153ed63a850fe91bec02b554a4efec6733d2fcabbb9e097cae551030a2305655ff44b7c48b3b0dd56858471ef79a17c06bbd39b7e2519b884c8ab9304d53beb61956a1a547d1ae4d98c5c592201111444cf483460dd0f9ba620aa487f048f161c184e2c049eadce8dcbee40e6f9bd6dfab44a234576e4416a11cc55c4ebbc66a0894127a89ac466e72642df99fa4f1916e0504ccb269b9ef126f0499e5c1a2000dede666ff98643d810f7afe3f4d3ca05c794d1730dc386928008a67e52146c0a72b5b762cdf84d7f4771bcf00c250bde526c7408a892b7d86be5b7ccf9927d0a3871c51f5ab5811bcda4ebcfb4f0c3f2e0e75e2643f2645092bd07f3ddbaa9511dd4005d96da4638d0145d562a01f74a94a8ca1f75e828dbcec7c80339019435731c83c5d666543e4138c09e51cc13a17d11b7db6e979d78c2c46c7ea1c22a8cac34b060be8364b463a1c6dc213eacce183b76496cb9d8812f55c60f48e32ad3d087ad0965e53948a094a10bb067925adc6e43833db3fef88f4a9920eeec5b44e410fbc54faa295d50dbb68c395b7102a5779179f2960efa99601f186965e8744601d1b61b62e4d892261bef2a561aa8e6a130a7fe81a9f3a645c66ebb20ab2de1eae983a2a4a71b5046fd389ce659ee908ade8efb7d4936679eca753d3eaf407b261897504e16b030406435cee67eb5370ca4ccc8cd9229195a195d1ad572b5f5de24c0fe11709911a372a2fa5ef4f3e6d41d4a019af83dd0735e6e48d37581179f96b6d9a965cb06be41a8156ef52f04ec815904a34398b01db54952cf3cfe12548364381bfca52fa76197d31cf4229a6653a92bd6fe3b22b9aee26e65bcb7ac594aa90a735776be5bebe334cf5389176cb362482ddb88b88b77bf76f922b8b1e492d45ec5ebbb6611ebf11ea610f9c61b60fba283c5dd91f8814d00c790de042651eef58a2ba1931745a640ff3e59b95de9b7516b250809acc725ff646c78f254506c5f30c42309edf6daf638caa69ade09247ca3632abd89736f4b196fd34cd5f148c23ed66b0ca5f7bce314bdcf10a394261640c2382c242b9b00533b2a4b48a72a0c816f3c9afae20231b5f14482928736afb8adfb29afc6347e788b41bbe2d78cd6a7d66695adc227bdc4221e242fb764f4ff58dbcd0dc758cd7b4503edf6ed1a863f80e882ef26d04ee67ad86f789c220c76f4448cf717dbe694aba2d19dec909ce9988c2663b27d28c1f0f59fb6dfca1d5407fad309f546dda06d0c1eb1dfa6f626a5a6dc808679fa60e6316b41fa9f5a883dbe84588b67a46d7530533101e8985f732b790fbd72c18ba86d6b89cbb86c900ba8c94bcee20f8dc2fb8278541cf3374f8ab51eec725a6b4df5bafa86de784464ba32cf776f2a1d847f3e5683a940c710975a955328f3bcd69e2ef5d4f816e96d7912bae20dc038425d9c99158212768afab4da0c4a0a3a4ffd3dbd25bde327a51df8dd21df0e156f99d2b9826328461b5f07403d291274d5230bdf88872ade7a7a2fb61acb8ed39ab669a3f14e132ff06a22f2fc3cf37bf3b2df42f87c9d7fe79c75578ed9b900b4a7c006cde0aae2036967bc5342cb9eb29dfb282c13cf5fccb3288f29ae624d68a2824448278557e68d319d105314db58317b36c01b0f29c1aa789d485cb562923db763e1eb0b33d7f623e71c1a87bc364a61623cd2402cb87ec0f8132e0baabbdd5bf27ef1a726d6ea3d4e2353175bf9786ba894cbed149d79f2ebf9f3fe7198075b9ea1572cf830f3a73eb7197cc3b6b61f7e458b65128b588216292637b0a96e109da1daf030b79487d969240fdf15fac2152fbfd5583a78295920d0e8a39dadc5b43e3fc2c543395a4d578eb514ef104d5398a78b13b5ef398629d341735103079ccb10f871bf1a809961b3b4f8168226366596cea0249b174f1a5fd72ae57c9a3a01fc15790eb226d5422550ec9742049dd4ed2435253fc5d10253ade053962cb0621ad244ffb94bc96da87302b1c9234e62ecb03fe98ec4fd45234d942842cb3f1f0ff665fb13277dee1008ac9033d1e9064175dbc66a25f61de2ad170414c9ade0535524730ec110b9ea3762bd2d9db5a6bb607dcf100f2391cfa0a927319c2e6d3e849b1acb3fb6cf506e64e1d7f96f3b2d1fea33077dac16910b9653edc8a3ec054bc9371eb06935f640e781f95aa90e992dd43f4a9e4bcce8d71244878671de5be75761ad7b884a2be0de1aee687da9a56fc415f6dc1e2b32a1f0f950c6c5fd6f96236708e3f1ea8ea01ddfde6e1a8eaf9763a09cb080821ee61192ba4b63e2e714ad8d084faeeb5fa93f9fa39182536fe4b34ee800bafbd08e7226a90aaf653d17245f9abab98de658ed068e20e7c01ce584b01ea5770c3b1563f1fecce4e6dffe784109681cf4fe87c98fc7cd40a020c162db3b77ce18a68e612a4869be9dc06d75995384cdad04aaa26f83c75d2e303b481b0a12e2c00a54d1b613dbab7a3f6c71cc486446e2d2109f1ad2007c6bfbea3c01ed032200cd6b16959964325b75b814c76b4d5decc8be343ecac33e982191a8ce698ef5f71c81b8cf678bcaf1fec5087df17925ea71e8316bcc4a75cf6c33469a89193e80bc1a72abfff39f1ccab59b340134ac9e137efc8689dcd6c9682579731fbb0d403dfa4e3335199da90e044924ca073ac838a444da285421f690fc42dcbbc0f5b8d0c52c68a774bb94dcfb1ca293c8b4cf5f035fd4c7446b5c2957a7fdda7b5dceb387169b3924b8bcd07a1860b4ca5f3f1204fe7cd39d0babc579386cfa4283d6d40263c67c70b9b2d9e8facd18334b7ae33d9bbf5430cea1761000b7d52afa8ba0b46852f4a1fcb1bd65b16113e99ae752bb24b33770ac4a7dd4db6ae95c9823ccd3e287ec8e03ad032f6e1734b2cfeaaa61714b709985f4d24dce8d5d9b06cebc86483d3e05f07a0490ac3329610b882b2083008076ff386797985a2e16d4e58ace01743b8ff0920391a082c27c75c36d492ed88a198b8a8f5747f4a8903c0e04efb25844215c1db3fd148b43d1ad26c7ad2260ea20206e9038faa9091ee1f93acc26613bb87648d4e1f1dd08b09d5cf686dfe57e74ec517eac2621a77564ae86279709ce54bd55d7f7474b7098abe8d177012ea78ddfe5ef6f9fda0add9f35a921ca64ef8763533029bc79d02de21bdb47fdbc7ddef1058bfeddcd01f2ef2aac4b915eaea57070e7ca31b398213ee3365dcee6da2a1e200fa0f32e788b11137d34ce482a57ba71707e96d5a84b79891c57094db2984ce135f0d1fbcb41c427d65eda85aadc63e7e3cf285c809c16dbbbc1840ddfa7bb4aaf245daf99de4d885a1a42a0b42a3622bf03226d089e67c3f9d179651dd4cf39b1830a2ee274de603274dbf37adebd22257d2715e17b39b1989eec1ad159d86d5a8e87497a3d10f4b41e4684f42c69fed29cf3b08920afac98148e329fb9415baae8f94af8d738cbd8b79bb110c91c8ed90a803f8af7294cb1d4c00be9b81db44cb1e0a820b823ca686fd90341532e9eec3744d7d90d0eb8be411fc3b57b0c5d116a89204b36c28262000071d263897ce802a070829ced96c676ca49d671f4d2206df76f864a903960c6698c203990792dfdd34ff821b5b1f454fdac6f099e6804cbaaa552fcd5364f7f05c7fb0812b7f86b7ae2386b2edc446c6770cd4f329475bcf3c2795867f9525b0deefd82e6cd5e8dece7035f04be0df84507f2fc202c29b55e8d7cf3c5634678fdf6a8a8ae9e6ef8fc3aeb18fe852304cea4b38f7b8b98272a10a44e1baf4d9e3e684b48f4d5b8746ddcf7d1801b3a3e31a5909b4d610f88f8c5fb51cfb5593f05eaef9cbeb3c0e0c17e4b3da289e1c2e11754e1d414f9d81950e1553f06e689ca280e86f3606c35ca0e191adcc8c83ca51350a99188195ae0639e6419c1c08446a6755ed52a6e023d6d576e5afc5fc5e09233c9dbc975a4ba829a390deaf6d2258797ee68abea993a5f02e9c23ebdba5f9f2ae02b0aa8b23b3892ba39cbe354223f18952e4592d0958eeaaa3d4902511d0b22c9e43086e7761f73c9e9a9cd3d012e0f15c22d35d0ce082f36357e9cca8c34666421b0183613da7ac8cc6a4d5030a9916d34aae4b9034dc1fa13aae186c6790119b42c6df44afb87be3f98f5a5b721221dea0a0a78b8949ac77834ab615c4ea4796e6f63480e0882732c3f32eb71d2f2ced170a72a2b52458156f25050e5e4482bfef15680e802fa9e0079504a7068f176c6c30483095adc6da3b58c65a220393e596897561290ba7f3d44215b03fd3fcd2632f251b363292520674b07a4d7e589430bfbc38448e2e0b92a0d09c87ee111312175977ff0538805495ea4b1460474e676edfbd6ebdb2502df59b0cb3e39d5b569d833bbd61de57173963a18930d6b642beb0941e685a5007e923c249caf74260ea81f35b6f957b1307c4e7112c621eb0b16b94fffa9fb0d112118729225644bfc0f88f0a8769f84b3b327a84bf6b998472ac60cd898faa76887c10688a55eb733178f9202af568e272c4edce1601957b47e9340e38bb6debd5a7b772badbd37e0477131809994405f42590126ad3620b214e93309f4aab6830ac1ec5f2d6cf1185321696a7e92a3bc90c1ad27cbcd7ea86d08ed94280770569546ebfef0fc613990d25e450ccc729ab5bfb91a3a157379142b9627221c6b82e3c847dabe626289fceee6016b03fed83c9555c06ecc5229d3f0ae2fd62517b3549b0418810792ad512e1087586db6a421d2c272fc43c43311141f8ab912d6cc84e922a07f299f53c4b42e984418685db734df4dcdb01a074920615f2d975f10b39e6aec1ae70ee722ba3c90e86cfcd66c30be4b49a63e6469acf7a436093d48b9f580728ebb99e4a28d4255dd9b66e4c44bfc7aecbb88631ccb5f03caaef63f80c90a790c6b9c38c85ddfe673212e0191b9e1d237096203650bc69c38150ef976eca186f5904fde13ce4eed195023a59f1bb6c0401152db0503b72058db372a3fecc5e50d1e4c36b4cddfbd4af5925374a5bff6bb885591f34b5a23fa9be0bf847050a5b2c6d59f9293c03e8cd53e021fd8f945e2b4bd9f733976222803eace8895c1380152e13f3db2b3a9596e377999e1197ca914297bd4e1b66686bd320ea6c57d2ed6c861315cb84a34fc415a6065e49039039396ab585317ecea8afe2307bf55bc035d04a1c67da5f3e6deab4e9ffca6581706be3c6cb163faba8db5d82ccce796eadc94968c967377eb6f6c02a3043809ec87f62b35cae8c345898155be7356837ad62ef91198c81c47f04133828d26a562c1432dda68e95cc80952663ec0a8f07495cb9151044f0e19808e44572cd29bf07cdc21163cab418b4b11783d298b8694055b17e6693b59aac340faff24de8e3c8553466dbd4fb77ee3d82ebcc33c4e673480f590bd869c7537798cc069ee837fed07404fb83cbcd87c30246256a0220831a65aaf4f551e8612a16e54fe976012595cc28cd2a95587e97e6f2f1b11bd3f48d7b10d526ba55b63f11458af1ea18ec8a089e7515c0ab3f0b8c8be64aff577e3eb263b623b55067f8830f67f14b497a356ee162d2d1b2a6f686f8eed4de58b67e335a3c9ff6dd16de5679052515d51a75e4497a886757345809d74f53d875b498367abef74c80910a381b08a1a5737b31f605d42b90384e401a8711033e0a9336710e9ae8332df29ff06217e8ddae210649876fc1a2a980a0ce662a44c312c4ba974b3f69bca03f95d93fce42937adc2a59255ddfec6fc1633bccdac4dc4b9eb5c9802e84eb9186cdc9ccd16b108ec192a5334836f782c02f58459cb00b8bd29578f37bf1c4f68b1088c951485008c1213c581ec250598a25d435440c20d9327229d776e27b3bdd9f74a23d67c5641800a91cdc1209c55d14c73ebda4982e099d033df09a9bb5a5baf5761aa857ea25cc7d45a253ce8ca24ece40edac5cccd6d66f7e1f9f207aaf77f816db6094f49f5b279a06f06a4a917fb18793a4887b29ca771552dbaa157397d283bbafdaa21f49c77d5123568640cb3fb93676c4d1a351613937656802b905e1f8a945dc8879d66dda54a643985853709f266b03756d0d19c2c7b6c402835f0b980e7fa1b7ebf134011a9b6c52ae80e3243c16f91f03feb1bcde34abf929304d2a29a209e8ffa81e2ec13fa716fd7fc38d7e07193513a4607e0766eb9ca3c6df67179e92bf29a7031ca6ffa4955b304d7a081633eeff279e981d20f4b7b76c66370bb5c927ebc0ee9afba49e7a80585858cb2212e279d15506fe837c1dc9947b4adbe43f5c8cfe8589c646c27dc6d8bff614c3a22477b1ca41e6887c48a7ac3307165b725d963f556abe4b40556b7c1da0e88639e9515d75630053317cffa7f0f315ae4aa9f0bd5a247b4c972b8e3f89901da8ad18665e91f61f1b4b79559be7597fe905651da59fb903172ea9ecfca78b96637f80334fdd83f9bc90078aa88ea6c503c53d2842fdcce8626eccd5427c30f2fae2a606229503aba5f9b4191c79c60d17068d04c0693a4e5b397daf22977c8b5388473301e40b5ff0ff6b556c30403ef9b061c5de90f9e46e9ab7e960ba0499727153ed9581144bf78c66af201ae8a04a283dd877fb47909d899b5552f22d713ed938a0961e0be4667c840b1609cd65f1f00e0a3de9231910b103b79206234a96e5d2dfe2771330a387bb9ded5cb26897f02beee3a1c299a253daffff5f4b9b0bcc000e82f62192514c268e048805b5380594bb71fb4ec5a050b3c1d16c2734b27e946ca68a2d24bc83bce8e153a8c2b63e828c93c42015903af593a42bc524264f0402367b45cc95596109793d4c53f8c6b3f877aa8a04e1236187b0b7657b7aa43c702b4d82384afe3ab390ecadf144ed6ad906f320003074554e0473f805b1e6a3a0b6790525aca22021ab0af429ff74f7beabd138f00ae8728adf4a447f4ee304bb74f51bca38e64e0c0da93c473349ee4d95fc2003d4af9cc39a76e8ea9fea783aa8a37c12426319a86a1e0c6d5645ea81ad5d11f5f25954cff535da64ae898a7ea9c12e587d88f0af5ed5f23fe89f4f03c517bc71d1eb02b228038aef227dc70485941ec941d31a1a2e260ea8f2b5d18ed371085e44605a4dcffce43b9f17ef0c251177e2be9bfba01b3141638db6bcaf472130c870c794e8f7a5b614c885f5d0fba6a8bd56e61d6e67439ec1e965cc354c3644b231cd41a0f30ce298181d29da47c73ee163af3ed09766dca91944ac631756da05905db0ed18a1d9ad6cbc500385f12738216089b1126e1abbd28b3a111cedec1f850f51c573dbf56b8193fb78fd6ac724cd4d0d274d6c047e7e86622acda42873d0b2f1af09ee51e53c84bde61de255340ef23cd582f988398db2b8205df1f2056dcfcc3faa4b2b3351cbe6a2379f7ced624ccdb0aba2c3dc17d4ac1e81abec8965939801a15ebec68b4a62dcb0b9e3d7ef046dba8ef951db39a2282bbc2ebc93a8c7ca823bfe0182246b48b31a7b10bac08a2440d6fe47cbf3a4d82e28fd055ddb6f9f1fef4b71747725d955b05ddcd200edbdacd7727501cc66d5f4ce08f3cb2503aa77d92e61982ea037877f19fbab382489aad066e578c2ee754884deb92a141a01a20aa369a5b70f1880704fcbbae7191887b76e4a32d13529b8401244e504f713d99768b010cf9dd18a125e75c8743bbdb1b4e6d5726b8c9b0997b8c26897a23d0a37888ead66da68c2802652c96b74719c42af66e81b1f38436041358a9fe15e825841da1d81714240a61813d7db6bdd46c911f72885afd135d62bfaa2b4c7f8d5fbeee79928019ab8ede2aa454b73a5a28e6c0e9eccc62e47cdeba9468dce99140bbbad810d34957e1f16943d4bdbd00fe7ec9af78b236300e05b948c38c198b8aa396593f656d05a177eb9d87960c03242e9e7fac2f216e91b9b081aee9789137ebb611ec669f47ff8d6c5639ffb1db9f9dd0dbcd33df792164402cc111eef90b37c45584c674cf7998d537f83888156ee6f04cdc64ddefed76b2c337da6f2a4bd3faad92ad9cbc359efa71e88d5bcf1fda2a72189da796ec2868fa4a9b75e6ffbd7e9c37cf5e3f9e9d608f7abf82f879463c330e9ee63865694e7e9558985ffc16679f85be3a6d5a23036fb59b732939d9f4b73130f0e25c9e1d3bd0ca0d3a8268e52eaaa7ddcf122354ae2e9b72c2e3a49e9fba365c1c19f47f01c1e1406b5190ae357157750776331b6da2539ecaf5d6993ae63b35b7b4ca3685d300054ee18dbca259f0e9240522b074fa179c1b7ebe0c016046fc51822582d3043bc23818457864775b744274a88d457ec67dea375738aef40b00af9314684a014b6a37ee81ae41e120c7a6be98d5367c3d9c6978964580783908f8589b09ce1cf8113abe48f1565bf7a1a58f29b5ee117507ce1b43ec0361151cce1e9cc17ade7ebc3951bdfe6c7181c9d503265997d12dd74574e91e9f885a7d98119e90ee39e3ab0de787ee786337db447cac91ce86edae499fe9abb49c13ae9bf6060b5099c2a591ddb1180860cd5219f18605fa9ed2680748006aabe863ec2a9b3c47a4edec49498e5bdcf9db0c9d32b9ca1ea9a9efb10685056d2a8966903723e003c2f410a8680f832047882977d93e5b0159b6057628c50cf2fed2cf115290cfacf640602aa87f78d58151022dc4317a3dcb9213ee98ef3db0c011f14f703d368724999ca859075f469631dcea186e1ebb3ab77b38850bdf8e154ffa55be8ccc6de71a46810c4ab70e302cf03aed66350d85eb781f5a338e5f072ff41877ccbdc7602b6b2851b16eee9abfd8a41a452ce3db99b90f28e6f04a928bb3c454bc49476fdf5916286639e55a9eba7d7d24da7b4e42d59d422f11ee98bbed3bb7c5f61939452068cf292d70ac5e84ade7ddebd540153a45fa1f1fb45da59f351a36764bae46ea07b0bd646a1d163a05088a30fecff44a769ff62ce740cb6674d8ca4f7d94d133511a8dbb3cfcd146c0435a342e112c294b88d4dfda5dd6ee042840b7f7dd7571d29456feb549a86d8ec35b74c0047f0a80f93e0a94600eba8986cc8302b2dde6b37264b0725d5fd4ed9bd9688a84b0737d340a0126c9840bacea89d000d5e808152865a7eb967736c2bd2d9abd64b9f67c496f4a58d1c7c503d77b4cc8866741ea4436f71c26d0acc9d6d312165cd17405da969e573a2a9bc35b6f1173b713273ed739cd39a9d64f598a6227fb0cdfcde119efc101097ef92af4ddc9593599d382695205b1cf526409b38cda8da36fd1f7d1ef5f328523b47ee15e7a792cefa7b8cbc59e8e349725b219805af2971d247f8b3a90b03a1c5385b1a5f4195ea28a4efedf6f376cf2a00ef34badda545bba7fa665c92374f67c1f486c3e7551ed0c06c84dccde52abb4919ef9561e1174fe44ed3707b35f76e3eb1d5a2b9d73b499bcd9a5712117c90882329d5b39d23e06b46a1d82c66d5d807d2901eb09d91ea1f4e065f671757d458bed399ab3267abfe9d3426967530646ffe857a55b689b0f967875ba99f265176867036fdca486073d819e5594450b1adcbc300056e9a48d74a9c8cdd927a40c463797f47c3f431c0d98a2275ce7013991bb3c94d6e66dbf2fbf56e81b5623e4c092ae87a9948455423189b7bc946412e983e3d1cd6c6caa951b0ec683437db926d3f1c6aeebc79552ab387ffe7b6427f4b9277727e5ad5ba344f3e2d3dc2c9e955b3632fb51102eb95a140a0b1dd40457122871fe4aa14cbb905a2eba98a1a4ebecd8affdaa193c1ce5197d9d70111f4180be5fe8b8fde0d2da491c7e343ca60559d1632e5a3de5ef329c9084b2c67f5b8db1aa18a5573df567669e9741c8ca4257abc31e8cd6a283790be5a75ad5af857a61fd78f71b61e7816d8c2727b7fad5c4a1fac1549e20a698978c4db9374778354881a25b70cc06fab02fa74ff4c4cb454e0ac0643d2608bc126226bfcc32c1fcbf9608f7ccd1885f416c720985b89961f470a4e2576bb6ba486ac6f702a73c5fd7e0752d6e6962b5918962ff906ca64b450f658c95fbc48d59e727044e9405c9881b8a32ba1a93c8e9fa3ffa17cd80b5b2a064cfb049d121b6da4f3cc3c00b830273c7fbd549bacbfc078a6562fd3625f47474748e6146ea40a7a1f8a90d9172c698862848bb3f5e3dac5772cd1a2ca5e69ec59b711cd25529c36867c03446eadc5e824c1b1ede28268384c934cd5443af7ce3f80034e3eb6da4dc8ee47fed39acc613e2bf1eeb58a17e72a48aa65530f3ce3720bbab44299684727663c2349476299162c280e5cb6309be43e4dc697331c95b6c110da24dd6c283868a748f14f09e8b39afbd103893e41924d54b9b8f242c207de1598587ebfeb4dfebac33eb1c31ff8d98fbb0ba86de9b6f5ac41e0ef8b3959a703a1da856fd7e940692dd4c28363a83347d6e62fba77bfe8dd89ca2b61978301a70b9ad61789ca63f0160936a49f4de1991756b4e7876091788fc655d53dfb384dcf646257ede2773c27977112b4056675eec9d2cfab5476ec660fb850637343602cb88bf4ae2866ab572ac65532bd79f23c161a3b7b07492e3d011d0ed85df6808e1725e1e618fdaabd22981c743fbcdb523b9067222ebf0a3fa7ef004edcc4f72d2dd3a87cca93047b9eb99321b24d0bfe9e1eec4257dd9ad84a6c9de4706a0b3641876b8e4c3e682cf9b48da7f45efdfbdbed1286ab8bf42af5776e86e18f8a8fe8475eb70b1fd4269671adcc20b7e3558fb9544b9f6d2275a52849ca207d0d70ae31920ff3564e4a703747574c8a9d5df2bc4a79fc2025d6293877fe18a209db4d8adfa1a022ac7fe590d2fc5e6486de677deebc6417bdad839e5706ce33909d2620feef208de375d3df5cafc0da62b909b5c0778fece89e748d5b2edb67c2d1cad7463f2b15998f936d0a8145a04ea7f2b48ec77b37508acef0a6af854bc305118a170c3e53cecd028aa350697bb6ec2ea4b996148dcbb20b15d9d017629396c234348a9908eca19cc1ca5ee55401875b8f9e4f2114ba19b686623f9140c89184fd67ce51b6afbda94d0c0cfddc6918154cff5d34b5c24174d1fa6d93cee7a3bf957464fc3f4a884189848bd4946350321c3eb973d92914567aecfca75ca46be7c9341f15e4e22740e0275155eb124061a649faffd200701ab396f6213c2523bbca40cdef1b0ab992fd42c51fa3dd305e8fa72c67f1be3c629a0ec5c113f188afa109ca926628b149e35e6fc3d6e7755e4ad50e5f50b5c188819205ecd068d5601f5f34ecdcdb7bca88f2db0825039db7a30b6dcffdda7ca60db34f3d1db40248a984494f224f8dc3e87583a5db404b5fbb19877588af10f0f06a2303b38cbaff9793cd73b7db1173782d9e0fb74e34346730a1f086178fe5052241e836fa9c984f3bd2030bef96b605d79483d4834a7e836dea430de7bfe82205e220234262562fe7540c5928d078fcdf4a55949f36fd67752187b87742af7d9258f74879961a9316cb988be7b494e9af4a4961bb344719f710d06bd4d92852856009508937a69d4b48031097605fee5ab9a5580b81f49331eb24c7e6aa0366d8bb618dc4643b42c9a0d241a556ae609d85bcf5b71891e4f31ef6aef7ba5421c119ce210a8085916813948421818eaca37367b747d52813ce5cc079da881e540de4a4532809ec3d7cbea233eb65143676597836441cdf967fd8e168df406ae154225c6568d070815662d35f08db831016c10e483350325c7ff87a6391e95b221fb8a6a12200f1888903990e8d708921e594a1805ef2dca377e50462fb30e900add87830807559dcf807c35f638e0be15cdd88c46a1fc0b527deee5edffdf8f3c0bf5df29f8ebc99a6d561957a612aafb01e1dda4c2fa7e1ca6d285685047ce4d7d92dfd9f8aaab06d24c91e5515e10b26319b0f4cec78f70270a91f28654c0ad3e366b986a594b21433d4e6e9e5a3e0ead7478543624c8f3f0c61c55421b6b56de787b1a579377ece2d2a675cec9c67e7ed32a5eaffeda8372aebf75633c58899ca93a1312e0db85df34bdbd4666c83f00c4c2e5be1bceaca6ff8014006dbf5254bbd27ff6b5659e8df932a04d3e663e00d96bea61235b6558b8db1a3ed3ebc17d647e2a5ab21473b583d07ebcf5e7d909d20241530452ea0b7eca4ab53e0c7a5d275fb896ad889568504bd6bac7de1d9ac2b97c69e5f5d7d76766b63a1a533646cc04c37f4963e16da0980027b35b1bf080f00cb7489b6b61ff2644e259975a14efd6654f6c0ab638b163de782a7a4c75a890102e53a3e68713ca745844835fadaf5ba12023d90653a3381b774aba6833d4fed95cddd7d67ecbeb7b77976f537917c83889f5f8024e070c61a59cf9bf1c818148754e0b9dc1d5e0a0a48fb2d7ea1ea8e11be9045549bb6a76dd0d09ed1562e4c5cd9d9ba1683e89bc9010d8e97a70f1a94d1ea8976e2b1421c7d78b85f9af990c229bbad0d57937b3f13c5c5112f052572cd898b0944451a6b3ce55f0f4703f8b95955aa1692c97bdcb8d331eaa8f035eb6afe4af2443873c17b29892c527325cded324e86f839caa4c7578b0138b8bc1b4405a53199346b5653e1cbb63a47cf7ac07fe607de68c971aca1be88405c8375082fcb14801839bf1cfb0c9c95edb30e9ae6958a081e5264ce326b9342a45a6b69baf4f600ffb618a8bf896f3359cef8d1d1a124b5f50b2f962f5fc1f98dd5fcf27f96b53ce252087be5b91c3bbf5431910ac136ce4d0e6a58a7b63140cdc35bb5edad97ec2a550d56ee58a001631fab420d864e14e7cf26ff14bd3348f2137ffeedc0d36ade07de57f6c354306e1d948b1b02ef60216d20c44ff5bcec996095d217ab3ce07eb07fd639d57f799b48c9be74d48c33747c11cc89a3eb3688dabd1351873d391ca8d50a9a8d9b1ced1fc6c06a94b8146d9b4091556e2b9c91fa3447f6bb448a2d6126d140ca86b7da5ace76b66100c8e784a212a5acaf413a16985dc98d5020cd00f854312326532ff5e9e20f0612f468150ee230e40b2199d1314b691959c6ead79fc5f9b722dbcc4641464ea651b1e268b46a0c25687dfe8837cf354fa6caab67a08a5e6409a4e61230f5ad30cd1cb578a1eb04bb862811f06ae35297e2597d7804d78763d0683374ab39611bb6360d4100761a8b1e94d4b32ab7e35bd8add8568c2f44869f34124e5e68d9985dc7598414a730537c84fb00cd39fbdf5cc50411261b09f3b589f9caf345739c4d44cac089fbd9205652c685ceca33aed34a2f3a75138b35bb7a9611c1b2356be9cbdb1c61171fd74a9f5fe1f8df3347aba2a8390d43d6f253c331339d0151b54d834cae11df355222460dfb980f5038436d8ddf9fe4ca46d458382124447e9e960c7df208876c4fc90ccc91abb04fb5d49f3ddaea34274724256309d1b141517552373fa7a5811b447a59dbff7d5ed555702cace0257ff411b61871fb7a8d88204c0bf54a362311b22201d2247f9e8d192a42ac834676af8e3c9b8f851bf90417a8e19937955a4fa44f62127747918e4e453fb3388c30c17dda64c54a22f4ab9027d2ba0e35b217693ab9a87013d60114d01fbfddd2eaac9bee7dd25f9325a37cabce47907d73348dc980e511dd22b11b68a7deee85006279828b605898f050c8a08b3ddfaec0f93cd6577e0e7abea9a538ef7e4dc0f94a66dfed272d8560966042381aabfcab792d01cfddc620d57d258aa2c08ceb1617e35fa61c61f069961f29089898b72aeafaaf296d10067a04c79b7061e6ea6e5e718894a7b50d8210c9a150af8a8ba7a85a486c26e08f969195401a2ea33f9211fb96e14e9dccd455e05dc118dad2e9ef3419b3be651ba33775b6e0995d3b2ed6a3c021f039cfe8b78622f70a84c461af99f27ce3c1bdf571ce797e92f0bda2b399323ffc88ad2803fc939e7ae48becc716239fa514a252a6344ba947b529e89aaf6aaa54f04d32c427e822a5242c7ce9c2f71fd0071f81b32c7e7bf23b6df3158a183d15cdc03899c1a232463b92e09a77a355d5ee1446cc0bcd0437efb101bebb9d79eace65ab9667ef867da30f8d18849b37f55c128db949e69a884e0c9888364b90753578aacdd65b2a8babfbce5e05be153c3637f9d5ec155b8e1302ba6d75d7412cd4650b809d6a8fadf747a450de5c15d54164d413f6790847d435fb97c075b247e7b60afe54845c2cb2170d4addb0836b915c968a48d33db21e6d1b48ce65ca306fa1c2c231e40d3fd50db111f309fc6acf5fa8a2cdd30ade081a5c59eb5fdc18cb98a08d4be047df169fd4141e2e7fe35297bef9607d629420f0c29f806267d247462cad66ba90661f27bf8a7db6bb59c0561ab28410b2b802992d038e13047289b160a49815d45491d6884134ac1fbdb0e46125f8e9d0b2dc3e9ec6bf1095a8023f3a96554df158c3857799c26500da75d6f264b3e5c1492be6b6863b68397b6fb60d9c8487fc5f1f6b5b145462f8220a45dda3bffeff5a61be301eb84d8974666e0973bb39c05b5716dfc57e67a1e00b44f774118e0bcf52e51c9801f828f39ec061b7339220723ccf146aa63302836dae5feed843b90aed1fe05c3fc2920e7586429ee60fc8f44f772385ac04df0d6de178892fe787dc33a471614dcec97bf76098eaf8741972eff7fc94abf1fc0e9125435b35e0430f0d7c82362a804aca203f6ba0fd212aec1220cbe380d6ada46868a454e9d7ca9e6229435da163ca9689432177522ff349bb8c5d3f33dfeac7e860a3ae089147d581054f53164eaa2369fb045df5fbc9c731d36baecc6286b8758bec1ae943755a9ce9499dc76a4029d482949652f903375c9a6c14eb18db319c62a01d76abf9fd6307b2f5c22a4dcb408f47032d7ad64780ec2994bcfa2e13577e95aa8fc135d110e9c5d96fa96f158ac2076c47a576f8417556ee7399c9bc4a603cd5cbf7749fca586e59a519f50122a7b898a60fc44ae48df25c915ccfb86e9d163e0cc3ca50add36d383e73596fc58b9c6f92b85cf23bf035ef2f6422ca95158193d1d85b133ccca12e6497e8eb0af2dedf9f8c28356bd3165ddd6c54ebd218701bb434f0148f5e63f561405178e40fe78bdb0fc465edb72367f42f6c4a22d864562019e35c13dc48fe8f1969d4a36e484d3dc32acfb266a2940b0c82f6e5b7f4aa9690eeb5d94f0ea15ff5c863f5fef7660296305983d05f49801ffca2c01fbf60760d46f09b09eb013032077caa6afe89e9078755375e01e94769cb020f03437e87023bc005afcc3119b140f728ee48c86e5e6bee51ee2548258752182a92f086d5fc32fdf983329f12ee6abc707d731223053ab6ac0d32bf909bae85f61f0c53f8c7f978643a7dbbb859277a4a8f168ebdf864f271b758cbb7e3ef1c123d61e2015050e1ddee7dd09c511b3138a8d9d1749652b934255df73c33f09e060029b2a2cd2c2621430a890ad72fcf9aade38735d28bc1590c86624259830a2ca13db24fa94f1a91e62b5377f35018e1366e8ddd76a3d3cab0e7036d485236ddae0436c012fa616f6de4322b85091b080ae8646b8084e35457d700c4e0397424bfb4aa7966376cf95a2031a91308283d56daf7704265292f734d570dc67e0a280fa4c60aa776227ef16b36c4a0bfcefbd133a7f4e9a15e93b8d6d0d10e5a64e96fda17c5173dd244aea836c7cdf76aed5fc97cee9bc21cbfbaacfc3bc839fe694cc3861a752952050cda100c822e4f83347eff5b654e7f29b790ec164c24c5438fadb5fab0fa2b1ed26193a929b9d4f23fdaafc71249533450da407251acc297c8c51c8f5cbaf348eada30259966ccc49d5e6e794160191701bda15f594674f760298303f28be42749be57d66b384e64f7305b45bdc895a2f59c112af8133563a8b54e96b911c2c74fc612a0856b7d657811838ecdb209c88057812db1f3cf217de546a42a04f368654c11358f022eb2e1c1a413be6535b33f508d87059e4d7071bbb430cb74957a699c667e6d321b5616fe3d47587217519e23ae09e56992eb53e390630ff716d2cf3163868f79bdd6e9eca98fda7b6048f8e6c9a5e62e1fea6ff2273c7d2f9ff2634715c373796a8a8bbd13919a84e578a58ef86befe2cfe484358c2b07b2f6a5eae726792e9f5a8ffd17a6bf981274092c70b28db3ac5877d317b532bf32348484b7287335ea9f73ac1293d5f92b1d2b48d9cef86d33e404cf0a8c94fd6c89b993d7d789dd0c8e2603f179ae3127cc887dc754652f698b417bc6b5136bf71fd2fa96d738dea6a0f0ea7f28d5f3bc9c576c6ab8d7a7117f92dd28217c30d2742e6fd30920c3c6b6305666871df23587e3c4b641089bfe53d09dfc28e35e5f8c66b0c5996b899d946d9ce85fdb2219009ab5241b0f4013fc7986ac8a6b2445033b1205f1f27c0637730c55039f54c72d2021995967fa73b889b6b73dfad60cfbcd4f224592de78cfc61616ac8aa967bd9000b2e39551b145c489acc03bb1896159e44bd59b555eaf7046091781af9aab1c6e04d77f23d6eada864293f255fd0cfe75529e780daf4c9f584982c5c00742fb0880082e36683e6467f47ce00b896f1ec0825078a1ec6e8ec737b75f438f8d74b5cb94a9f19774fdd7ac4ae2e267ea43bd286c0de6a8b2419695dd2b6ccd85aaa1d7210a77103bf8b0f9af32e25012fc078feb9e172782825e78b247d1f3d23899171252a2d6a9eb605530cff8f13a11fdc9b05e8083c6eaf0c880563ebab693ceed21336e7adb14707635b9945847061524b424d8c231f1539de00957853569d716e892d260ad2ed14e9161775e87ff0acad940648e0e2fc33a0afde245334315a15a839cf1f54788b539683952aeb85fdd7fb97a9ead1bd26fa257d6c82a659f0d46bd9f47863c3663a1f3611a6e4caf30e2ef49a8664448f9965fdc5eac60edded089d859371e66458968d98923d882243e7268b22559b6bac13bef0ff70abed24f8ff9786924e7af339a7046356d35b9165da1f82036937692dc89b87810de87f3392df4da77b4e27b429f9c32a4e7d27dca64d6ee60b7089dd688da603a5d70ca78bc95ba2c97cb874040d93f26f3fe449fa2f19ba7031691df9f40d70f3cb867b96b6d03021d75a92b7a3eb143c77e9f14bfd961893e12891a4eb83b0f42d2256a852adc4baf470b9b41d09e071c8f325087be69279fdf8840ba6e74fea280858c03b0166b03388d0d811aa9b62be03ac9633e7f20fc608dcfe5ed5a5ea389bfaff35d5b77643a5ccbfc723f39cbaeac3bb3fe48972c2388ac1dc12e022535ba7e294559e28572acee94e122b69409a8a7b2b3c53c9b674b5ec1d224c1a8c25462cb6b8a53803b8db0677cc4380bd9954ce339897f6b4ede73b8f2fb3145ab2eb17b4f88be9c545b50fab509f7b6e2409ec6c8990f56218daf6321c6d48f747ec2122c3982b24354c0d3ead4d36d642f3f06669e51e200d71f544e6df00622d6a6baaff76ea022b3b732909764b4810000c4fd919c15f4853f148b32d1e075a562a8865a26f4af3c9dce9b7f2b26eb308867ae02e49a96a605ef157f088c1f7950fe835b07277d627959932269e48bca8bc97645d192d2411f0b021d78bbcc45f8b3e89ba4bf4489b74064ee5019a651a2a0bc0a9ed0037af4c5d208e8a7a75b2da6907cbb990e4f160173042a9844f6dd90674bad0ba5914f1906bc857e6446e67f3b4225b1daf5cf7910dba3f1c3c647faafedda053239cbd2ffaf75de3cba16eb7d474ed5a8b2c821b3d3ff35bb77f19b7a0eec92367005ceadaf153afe57def407dbd4dd67cc57f6dfdbfe2509d10bd350866fed909951eb216d76de26ce7f3524a88868f3656331a5a43491a5fba971c0d6ac047032078f69099e3c1f1e6f23ca187814399712a9a5cfeebc4c2775f2f124e62660192c97f89f74b5e109baf04fd975a379940dbb8bb4f02c028d1662d7898dc317995864ac47be1ed102515c18a7defd8b91a0c76fd0adadc10a1f2afd296a80d7bf2fa4c94a5bbdcc1eeb0e6519e8b6f5ad0310b628a62f8f4fe7e78fd8827aed5e5efc0dc345d4068c04f43402ad995e69bd1a375670ad8db86c25f7d7f9a68c985af13f15078129ed6e87f4013eda07bbb5ff6ff697c2058fc7395e9fe3ce30aff6735ff2133ea2ab956c6c90882a4baa7b9cca2aa939f3500b268ea9926cde24c8db6f709ad4b85c8d5bf90d2aa5e410f35a51b40f40336624ebb4ca52aa30b1381912628ddf0f1f96cd594456e822832ee7feab17aff635d9afa4162cec3ba2e213568661067822b987e9d75f7facb4bf9f826c27a32c0f72b69259e4fbf28d90a4bb3c74f48ce619f0094a2ff8d3f633a3e98ba8c9f9444f49fe0a577bf6a9dc3f189e9c2c2f560f689e082f5f04b923aba651db52a6d2b020789984f6f74d5af26c845361b97c1af10c3fb9b388a71d86b6963092fc3bb5fbfa5953315ea677bf56071e100c0fd5e604554cd4f97bc98b9ba26b7b1e372f30a740156e23aa881453e6fbacc800c69822203e57a33a07b7dcbcae039d60f9109c738d5dd6ce301591db5d8cf434d118e72462af0a8e645a088d7e369f76996af5427d1d22f2c7354ed06752a6ce0595393d1c2889fd2c11fcc3a6d17d749acc885d1724f8aa47da9bed0a98809cf3e7a600dbf9644989c6bb06a1635f16c51b8d8e12cb0a62678fb53935784d00626c21db52b55482dddf04124e285d23349237e778a9a622bfad3decebd8138fe892149c8c1d52670a72d405a84c8323e5495534934d3cad5792f96728eeceb5ca37d7fef6d0a04b6bbfe7a425d30626b9be901da734fa5f20f1d2d94c7107c7e1c318118eebda9964251f2499d3dd2be2a23fb2a122f66d0d1bdc355a3d584df25ea4b4042b7c00ea6878664b5677582a470e5789703585dd5739609e9872b8b76865628cb6ecf26ddaaf77844c397a1094bf4c78d42eee8370522ce273a27c6634d25d1d9dba9048ac14278250b6539d9f13b03516ba9f8fcb5eda736cdabec0611a58a98f82db148a9f15558ae694e935302f0d3dd88e278d675314f06905cbf393ef42fe1782920fc09ee5853def4db39e6231f475b43173423175800a9ba22d76efd0141c8de67ac449731f8466dfa4db2fb5154e3626f2ec7ee7972c9b2ca3a904badf2866f0f498182314ea2e53fbca118390a793862053dc654473b0776254dcaa167c7c0c8796a22d4aebf924f2049ad78e3d6a6f8fec3d6fbe3ac3d409e6990f2cb58e53c9f6fbae20c6c0f89a8d40c3268b5556a77885fda704a7633e3d03ecf32d8a5999af343c0acfe2ee1cc82400e061b51577b0b1bbc54aa170ee781e3c32d34737b4de238435081d8c91bee1e5505bfa40ecf2326bd84eb9c4cfc9bae1299c81ce72c9d3c239939de0d2267f22a34c21a1ad7d364b710502f9e8644ada2d9d559956e5fa8529553f7d915b729ae1da85ac2e0e0685a83687d01c1e58ad0078d762997be688f9ad651a0c82247d2b5408923a29585f5b3f0c660adf440338fb984f3538578ff2cf988655a706efaa92a14f3ef8b8e080567279256f70df8fcd76da14b937dc52a9504c6bbc6df436f18d211ca1f67e9e8d5335ec299bb77c22a06028f3516c5e8e8efb53051dcae9b5ff70fbc324c6c59567c5e5251f07012889e68c5ff6f1879de96902783a31815e87fd4f77baf277dac4a340781a03da22e3ba2634e82a3537a133d5b18ed4887aa6610e43fa9c29d586aae51c78964303b4ea7af87c3b6b66844e87988b793c720a922f8d7011f2d89fda783361ac079aa6cf69e80c0c70ebda0b25ecd315594359f96344a1c0929d1e44584aac370fcdca10d55b8ac02b52cb612a89bd8ff4dab90602d28dbb5cbdb13a2f803770bb78175cd319dfc929a5f779df2e764879b90ce248e56370d18fc623d65655303924a676dc24b887d8538c65c29de5546eda6ffc3ed39ed4e174169c0d1b2c2daf01e0e9afe0e236feb3263d7435b313efb4869f7db045128e5128d47e7b70cd33cec509d7b4b7b7b65b4163c004e9bdeb20bc6efda1fa1c1f6eaa08a97c81a9ed218cd45a8346b67dea93cc0742bd5f8f829c7446bcbed364234312d7b8c046982a28d7652b7cb16a5088142381327c835387d9a6f12cb8afc44b16e90fd09c34030171cc54779790d6671ffbc5920cb781d9ca0066b98581b03c1835d2c4cf97ddab9eaa05f005377727caf52c9026f8f402e97b8d1f55d7665061e2429234e15aa29311e47fb8fabfb8dde59e8162ab79ac9e9dd6c42182322d9c83fe41f8c80921d627d82ac2bb862200dfb09c415b84e78c029f94e3e41fa567d6c02e422421a04284fcdddf08d17c3175b35d33cfafa3a642876c1ef47fd126c7171417b3c8b467c7a82ff454c4b4ca4f5dedb93bb9b5916fbdfa22b7c08341d5e7cc29c4d50bac8ea8af8021aa3a8d77a15cffa36e351193ae29c0cc3a4d224aad11acc240a58b765e88e03b10a9cf32e00a1a627061d6b1819f0b2d93d82b05b68698a3a4c397e45da4424c4bcd1c2f620bd8d2da96c3f10321135c1375eb8586ff4a07481da5b50b8f8537e2d647e1270eb63f03245d8fb282561d2924e85c45c0b62f36a0722e2db90f76f8efc91d9cd5cc5d8454998da1253e52d48e7fd4720e0ca0a3c72c6735991e69df5a60c21ef1c9ada5b25a7ccd153ba4da0ec90884580c8e13d7275ac2b84106d20a8ff55e122cad7e6297f2a762374c709317a9dc1bbaf078a8c48f21bfe2b66e5b6b79f3c91f88689a19bf3116b8c7875eacd728db73b84b0602c6acada813ea9037076723d7731c97baf958d769207642e91193a3df8817988d993b067d4f297a09ef09840b86c41176cf1eb3dfd735fb02e5737d979990a9472b46c5ce538128d872ffce66e41426d8b465dd7c1a7f4ebe72f99462fd0a4dd41dd532c1f5481295c5116f5b70b98ec31a7d8465ca689a229a9180b60dbcd7bf05685cb209e90ccb2df4d28ecd2151c6b69153f533b2c35cda383b516cce9988791c350aa60093c08ded9e16e894b5c29ab891b89e734af40b90e474ef25560fac0e66381a4aeaa127518c98c9e8b80e710761056f66dd8b601ab70fbe5fcce5f1cc6a297ba8caa6c7b23a653a52f5302b33ddd02ce7253e39fe5d3818fbb67be6abb889d82da155739dd4860339d33e7ed7d2aa309646bef3390f43f8e1b8ee75468f9c89c8b798febe1acdd493b2d388c5e73d7aa686a437eb364430356c6b2c7fbd71b0a60e8e1d2189d245e393fcb1b54b6def004d77526b2ca2c30ba4c26be74eb81a737427a78fd7831c1042fb06fa6a499d239bb6fc15eee85d31d9d96964482f594a52ebdefaa9216da995feb8bb1dc3af26888f6c80db2f1cec47b94647da3022609c6e6c79069b4bee5844f43cb36b74b5d1c760a0969c40bf89b655ebefdf2d7a63f774161bdc482dabb5bfbf3f6899225273543c013c05200cd75aa0eba14926682f260bba92176780e835bf62a88c3f7ef4beda9db1c74f864199e071e83592c5a22e0d41354fde308622abb0860ccfb05464a2a394c3d4880f45982e0894e914863c8afb0ff80bc76dd3a83bc9be7d1aa0bb64d0d2cd49017e976dc1fc3bbdde3f2d49ffa720e0af2be056b8b1d75520c7245df0a9a0960a8ca60a19d2bd8ffd4861826627f7bfca11825fa83cd88308c323335794e910aae99a711fbb68d35e584c940efc26b64cefcd9e12e588b8603fd43137c080bff0411efb5f9092491b41dfa130ac4754a9f6ac4f89bfe51bdf32bc6adc213882a135da31a7a707e4545d14b3f7055c82772d6390861f67c0620b200dec7f95e6a7c49c69389b13affed6665f43d2eb4ca9c6f6f40bda3a09c1c472ada1b67c2a8268adc2fef9066e857be5c4b7fd9f4fb2835b61286b0fda9564c74cddc482c65432852c315ef09ac9484b1f4c6caf464d3e3e091090826bc95c563bd362521186aa5b759bbed802e2b19f8db337d9286268ed3e3167d5a2c877dec3499d305123d98b4eb9d4b37b4589b7408805ce9b8b98d98c70ea0fefdfabd127669f04da9f073405607f29e4ddd63125b2f72bb141fdd35590d307e1c0bb1c59f8280825b14d6d5b8b0e2de660f5bc968dbb963dba4a79d5a816f31dbba6454559948fee166b0492fda112b442ffc4036a65f2269701c93191eb0362ec2a382bf3761a2613e4f50abd6179c40d1e7c67fe1935dda74de86f87e0c3ee0c5108e0db7cd2f78aa7c3a5d812afaf021e638ea19db69cf70de0bef89611c1457db8d091a07514934eaee800f4ae7cbb068d236befb9c091a84701177352e19ba0e04a54e7f90f908cf5b0b05c69a252798680952d95e94f4a62d8d69cab44d56da5a1f7eccd35895b1b5855852419bcf41452f652b803b81e39b0692c42d0a50978a9c3b1f08fd6491377a01ed0e07ef76a4f3709d799a97a0882a9e1ffcdce620495758a63735391ff77439a0bf4b9b736d9926baffbbd635da329d8b68fba7b9e115746152aabc8bb8d91257ca93c28ea591ab8823a610b611d6c0c999dc3ad5635b542036a49bf1a3a7b9ee123c9e62a60427b1ccea603b04672c472f2085ed3d1b7415a8df44c6ac52d41b2bfe7aa5963d28fe89935d37ed6ecba11f08b842c41a64b00c2b69d461df9429aceb080313b87109b13e5975e1d789e6c90b9ad5d4d2d3b1b9ace7fb1997a2439fa2fba071f07e26db3b1f3aaf87ce2655c24e205a0c8300e06bd7717d9618700e2a1625df325ee22d31128594f5e78b57776035a9b7ee18e168826ad555febe7c258c24ace342e15fec053204defc21afc7412c9b1a55fe3a27569fb32c7d5cb464a335f137ea62c9fb4d70df4e9efce7b863928e68fe806fce2f581fd6e2cec5caf5d4c8234388d455068374a29f58a1225926ff49c95a60381061a1c87199fc1053edfbf7529b8e020c72f6676dc180ab562162a1325ccd4d56d47e36b97b6b1b7d27ba7bc416752aaf13a22dacd184849e28750345f0c517db683e3bfae1111e18ddc3dc5c2f2bc8f0ea8d0a7b24d424b95d91587165a1d964d0a03a15448f938958a4e03e7d6e447d99bf0d58ec2dc08ca3ea40efa59e4c1d1f29c220b372becbb28b0bcbc998788b4d84fa5e40ef9d9a935fe9a178075bfdd7ca69400b1d862f96b3b976ce803a69c1a1ec6511d53f78c81f620e16c0490a91725e2a740bfb8bde9c9626b7314060a43f77995caedaeb068149d79f282d375a5228eeda0d6ac61c1411975e6f9a99d571edfc54a14a88af394c8d7e000ea7fa792f86de6d41a1e6574a1c9bb9f9d517a76d8a4a5dc1bac4b4be1b8115ca59c0b516ca589efba558b8daead92d56961c7325e71e61f5b61de1f4750b3d943deb1ace2136c07c04d3772faf16dbb99aec41c2b72a88b8e868f50180bc971da0e191c79aff958f50e6237254a8ca9b40a3466de5081593539190daaa37c5fac4e81e3404892d77fc73c8e87290c8a98ef28c5a18f92f19f730298f5fe274a4dfd2891be9c2fee565ddbb2f672f6758edff5acf70189c01e79b2e0b93c2d6dda011128fd7a897cf86ce9724b0dac1b8deafe76e7b973f7fe3ccc8f615a07699759534d182cedb2fa0b836b7cd6d8eb7925faff6fbcc518e4cfda5d2516e4bdcfeebb22d6b1fd55e4dff9f004798ccd815af6677a730f2bf8f42b5744a2391e34819651b6353e66003949ebdbfca4daf205a0518cf0291e91b0544d30b01eb8aee86be9e5326a7fa6196d5679836b648aa4b34488658ed31fc3e4762ef912f376fcbadfd8119614518d441e75ad354aa0f9816f24c42b2d9ac2f29d4acaac363d59ad5c412e3baf0b5e0039c8ff6757f0b1b28a4d9789b23361841399015997a90b805bfa5dd3eebace0c74c3f27ad74a038e90905dd6ae356ef72e4f12a1ade4870bb47d2cad998f01918ba190430fb6b6534c601bf503bb8d4d74fe96d28297f544bdfdc7e213f74b287788f3fae6a184cd330ac6836980883befc54e3540a2f5c9c8913450280876f271abf87c163813355a80eab5e41ed87aaedffa10e94bfbfdf2b3836b5e4e909c456c64278f8d7a0dfe85495ec6cfc71581fd02a730abc9de06ac769b8e6b12bdbe840298569684e5872c77f5b5521b2f417aed3dd48ab7b244ffe8feac3d3122f91166cd976ffb6f23834af19f79a9fd5982af4879ccc6a38af50af199a471d55d83a72cd780b22a9f1879ff9538b3ca9737e2effa438a7702b07b28545afc8c5fbd67f1370c5c321bf4871e77c731d6a010fe93faa9c8037b26d0f27dd0d30d02112689b3f42675fb15b6e00a1824208ea46f0e5640995e0c722485c0c867db046e1c8a1caa223bfa92f9e20882d03d715fb9b42b65e64176a5ebceffe1f764f5feca108fc9f2cd9264bb81d7df7340cb73c6e8bbb8f5041ce955ce78fbc719214b104c4f9f6b39abbd6e806d5ed49d076f004e624dcf29db9549200908b868e5ac2ed7baa05f58a4da0b5c5b85ab07515507a937c9bcc16d3280fcbb8c81feaaf33a7c40feeeb6a9137d060d7cacbe67ffc24746830c6448f744b9e8406427f85ce26cd0affd9a57fb0bc5758cc51f341854805a8a20d2c9c399a1c85dcab2307f0383139871fcf0617cb3f5c37e7ad53341e4fb7a3fabd48a87c1b672c68c9e2160b0e10b5510b9eea839dedb4d50514bf23cebb052b11ba6926b77d7611ee51a8012f7f5329d5313381e7454e087259b9181295a312696191287752e6aad68234db85c87bc173fe755b3f79af01e3483c0834f3f3dd416fced2ee7c5efe83d098a7346ec37d60663e17c4cf602eb3335bf61be8383f17611a8df541487d22bfa8b7a3774d63e3e28963fe02a0891edf57b027d05d5181592cf834280d45e795b7784c1b3640263fa185bbcef7cccb27ef6fe078c45441011ada99dc30270a8c1669366e3fec1c50831e9ff1601fa8a06a8cc3c8e8af032552ee33cb42e44217fe0a6438ccde7b55df55bf8646c66f700ff6f0b29126b5e49aa07dc60f5081dcab413eb852902ef30a54cfef8fffcd32c5e34c0d54cca271da6a350aeb3d3b0dbc2698c3955e35b744cbb095c3b850d11e90b999865b61fd768b8067a916d70906e2caf50f0ef7f4da12e09dd21b3452218b2e80b5eb5bba753da8c8ef12a62d7a85c38996718d20879ca6da574f9783f5534414b58eafe5ae1c07b7ee2172e35bd6253a1970049aca45b083bd05d4ada68f087b8c0345c33e17588eecdc48bd8314c665ee092246b0ac490dcb24bf9291ada652dfa6eb0e603be48904de99eb3179c6da086113926a9688af5d8a25b6b5000f7cf6de44956b28266e293c15d69409b99a865694333d511e9b376885857f934a08b869316840da334c37e82c015c8a48f8f2d8707d730dea2829a32fa78a02721841517f0808aa4192f7d7d66af53bbb787dc5a63532a6459c34b9a6642a92fb920f01a3350a57913cd3d0ee9ddce7ea910fd6c874868b4075c064bbe132d5457a514bacf8052fe327e7cbce0eedbaa7d1d96fabe69879a279e35773c07032661302852806a81a7600164097ea2fe2ee7a59ffabfec316a0c29edd3112ae11f1ad61bf5af37dcec535beaef0a432226d1c221e9b99f95cff3822acf03959910b8a784e13c078ee808d502f5b70c91bf01e6eeac8abdcbe7fa3af1a6da3603b55f904c3a775502aaf6adcbf1870e42c85a8e65493db3292222bf14e688cd6e4fb4dd3037cc23edd9ba5840421bc86e62f3cf41b7de47d2690581ee7d33603542dea464021d466c2f60dbaa620ac571f7d19f4c846d0e6057e1c8dad75dcf9623b05d4b73ff9e58ea89bd7cc1f1da212a0ea8bb98c068c72077a17efd3a699e10d852c72609a038e71ebef071527d5904f304ea683bb6a13c38264dfe4248207131a17cbafd3f9e6dfc26a24224bfff5d0e93f469ab070cb8466c3130cbcc6570ec865793e274762704fcc2e14b75dfbffbb80cdf7703fce43d91342d19cc54b67507bd638798f70535052e7a14e1930e278deb66cca2800eec8759680a85763154906eced8080603aebe1a08733e5c1f3eb4d08a9bd2ea7b2ed174b3eab32e8a96777f7cb4c0a9602727e0f6533e02fb47adc415ba3b8464bf650a2e60f698ea925529dda2b544dff4d247e6d8f0fefa62d06338a59e520eb15b95f9c67bb8e124979113170776af37e8d42d3138a09248791ea5e5dc312984e67710a82716227504db1a4501fbb1de8ee5146dbe665951855aa209dd46df239352defd6a82cb023891df5b11406779b44e3a96849704096b2f253c033c2dc73f88f3954520c623853f633cfd14cd116385d6a6ea490a51df0076b2f90dcb40c6e50ed69607a581c7031b540afee42c607bff9a242fff9696cc3919ec89b289d9885424a0c0e113bc6ad2730df16b341bb822a416fabaf49a1118f1188999438b626e7cd9ac438a960bb0fc53fab18000b18cc990136155ff01a4d5bf2cd1fcf22e5b87cde9d8271542a1aa3c878ca300004c82a3701419b87589ff2846e7571ec57d220be3ccfb871584d64db1c07fec4ab2c6367efcb46e91d62e3bd505df391eb0a6fe61bc988632dc714b9c8e14b5efdc226033a6770afb5715cc03609fe7df8cf5da16a7e0bf643d2da4fbf353d7a13828f9abe91f95dd83af0dfc938ce968b332fed42653e79c98861f5d50863118632b6d5c1bec28a67e617cab3c08d962d99ad512475d8f46cc303b73fc0aec517c2d36274faf8a6eed1a9104c7b3626f3aa2c9e2f6820ee973516be7ae9c041f032dbec0ec2d91f7dd038e40dd6f4b7e21721555a606f1a5fb5ea4d94ba8d0afff2954ff3c091d41bb8c109449d97578775bc037ae4f937ee90cfc97e49a335c56cf1371268dafde655827149ae1972d91febbff0ff8539e818ae0b0e13f1491bb0e2e7d5e9d9109ac20bfc46631cc31d212f088661be5e791db047d88b77b00018c8efa1014bc8c514d36109462272ed1bb5f667eff8e72d7231bf40149c54a0c6c2ce1d4039abf6f5a97d213485b49bda7d11aff76ea79bd31c4470694a98c48eb9a4ed8ad8fcc6a02b1021533a2ade1415727db584d7c60bbac26b69d4f157998f6f12ea362c61796f01bb727bb6322808644fb62a84d0388fcf36cd02080411371039172cd3d9dd8ef798753b9b0d3290777db63694beed9f522b5fd7b192d9867c1771993f734861c05decdef2fe6a828a1ef4cc15e4fba26c219d7e405bba4f045158f24ad7755bf6ab954ba2e3eec81ff25e0890efc51955fd3a84c99aeb0f9a0b958a10c6f0339ac006b4953b3e37247393d261b97d6cdd64b88d16916f1e7d1a4c38bd53a35e741bd1bde180a6f1c101b59b74d98ffed9086e803b74e08f172dcf30df23f7200806a55cd0266e9f34958b4b195bb5e1c028b1bda7606fb25ce29b9c2c6c96d811bd0cd115f044a3531267aee78327bcf5136ea37bfd0d3eb5aad7b8e71b8e612b7ef26eb60eb4a4732e1a5ddc4ac0c2cf62575217bf0dfa1eff241b619dfcdb7462489e8e1fd841909354c99021b90abf008e36bcad460f516196920e181c9d36d0988eb9b6f299e1bad405e0be22f9409cbf71dadd63a1941359f91eb54a23b2aae2dad93f0a8730d6633a7f7cd1433a3396270d345d3e0a138bac7a93a116613a5409f4419382de8ec478a0a2d8cef5b7e8e8eda1d57311f433bfd706a0608ed542b773ab85de4225c61abdc8d607291bf32bb72aaad492e5263b391280dfa9b05abcd7ce445f59503a8f849ae008eed3a80de5b7f59def3314398c12cf881e02bf4be16c118fcdeb2be8aff88500cb46a3eb8e948942aacce30590f5d292da4584d7b79ba18e1d387565ab176c70455e039e226bcdf4c0a23e482abcf9a42f1cd5a4633ef4d1f8e2c9ff49ddf89b673c030509883748da0d167758878bd96a9e18408e2e6fab3f383d3a1db827cb55403943173fffc8421866097b92ade7433f23addc0f38b1fac9d82e9a18960fbf988be027d76282fcac866af0e236416c8c6262a86d944e185906e3948dee9404603e2db7284f5b09591126e6ad56977f0565b0731a3f21b83659eb9d2439f93974686197eb5ac174b4dad7394d993b7ac4f97a295517304b459d1842c0dfd8b9d16f6e8166991f94ef668a686e0b3fe1c3b344bd85ff1bc838d45635230b4235dd89f2d47d7d83746c1c74c9d693b2a4c9805814a4fb228640d4e8adb2f8d65b711cc5d1b01ebf34314df978ae0f7e56d6b74a623d1f8f639b5e8a3d67419563e380c55548f4d7c00ed31949c68e267fa5378b37b8b8be8565828bbfbd7bd0fd67e5e4d0d5bef8ad92c18731767c4ebf439520d9a2677013bde21965be9bd3fb3edcd45e0baa250b3f85f1826316a7c573c5e1edafc451876f9617283e44cbb00818e295ee3141a6fedd2b3a29c422f1e220bcac07458656ced6c158ff626182ff44fd35616cd2a42ada82bc98b2ca51e8a48e2f3bee3c408bf21954dc174c1e684b7f0190b7b0547e48d3a010e839d85823dd792b5ad90766942f260ff8c9b03f00dfa98a1984a891c35836c6ea8486af4d4bfa11fd7fc1ca1bb2bb35c30116dd49ed7758620ed9caa96859b67755da6980f645a822a8e9d457da0e5604de3bc85ec699d32e83178ee0445610e2e5fa45632ea9799bb5e0eb184c872ead9535a20d6b54bbb3fae29d0b88f685434c66ad731b991222f410f673156568aacc36bb7e616ce9afb7bf4e10b009dae93389e0b1daf2c9c7ce4ad198f8ba63b3c14e395e755a34e3012c0e7ac0ac290a224a6e6dd4756e4729614fe87a8ea7f6139ab24c74e8c45f36c812365ae3de5ac725f0ac138a4ec5667a3202b7fd5b26815ce9ebe81c607bcb6fc65d94d3c0ba32e869cc628cd160d755123baaa2705509d93129a5b080d5d4c3605044b14532349d696571f2dbd609c9138376d35cd8ff4b5d4d5f64e4a8fc3357c488d567bd8a95cb3c7098f219d9b0843608985d765fed9fc1a471b3cf67164a3e0c9eaa5e4161435b1514ce06615d145118bb8e8d25e69d28f95d58235d587c2f4185b87995a67601d5336df5caeefac0e79be2906d6c4fa42b3406f1354d4ece7899a99c4bd293127022e55b443e44101016f30dbb2ccbde0e649d461c02556457bd52d4a7b2618acde9dbb2348ea52ea92da0e5789220292e08c27ffb05b8ec3d9f7c2759f311a8be068386d3cf3d0884db1c4fbca84e35d2c8a323ebad4681298fab0e1f002ff1bc3dab9d7256881ea984b61d7840809fe542e7bdf6128c4adc57ba87095703a56fbbc3dcd085aa56181ba72dd4bdbc4d083fea820e381b994449a73bcfb1fefec1fd476634aa7fdc1ff34f00eb18c36f7f4bdfcf9b4c3bbe5a2606fdbb5e11e5d4796f16f225a933cbd593314d387787cafa7ea5f1b5c9d0180c23310f6021d1a1cf40f85937960c88e7d30f1a3162e6f2b5ba9c7d11096c6e88acc49cc1c7d581e9815dd110164eb99921d574a006c5c2253e5ae9f9b0453a2bb16105d936277bec5a8d592b4715d7b1ac4bd1c9139ec34b951a86baa8f3883b5396d5e0e33e8f7f176180273f603b6fa86404f1f1c53a6df5578939e2b499e24f3c458a65d3f699f100f29add6bce79fb97e07345723c7f30f965dff4525a82bd4db27b213018617a9525ed8e3f9fc351f9f643a5e3692bc6a006c82f230f3da6fae33d112a09ab530f27626582892ca9a37297432301557e2bd99e73da31c3a21e219414995d7c729c0a5488eb0f42d8f251477708c1405cff5b473ebee8d5ce47b59a4c5d9be7cf223ab1d2d3dfe428ae2e33f7ff74c708049d55c0aedce4917d5fdd59c017ba062a84dd3dfea8a8a459b3e861ec2d5af73360bebe79c22d111444215f1ea9c82f772c36a9295f351f3f00654db37b6c441a23f808bcc882b80c3d0897862c164b439c21125a413874041ddd3401b8a2d6db2624b1c261185fbed1d19ed2b15fafc627992542ea42a09bc84dc168e3d6c85deebb8c5a6d8758f38618b2e0a301fa794e9bebfd986ef4a8df9d489b748ad83ad6cd33d138a67351c58d10880262d18eeb5278cb7d5f12f7fb3d905347d6933acabc3724bcd8e9f4de9f8b80a909d6aeab1484cce81cf738bb5a3b575a606166262c6c66d1b39a2b00f2c859b0ca8aa26137804e8d2c0c175ffab9b33cf76b019d0d3091187dce4abbb6cd0b6df5239aeb7393416587afed55206aef9915901c178a009c6d3b7c4150b3c65ca96856649bf57016283734888fb07ccc56a6a9df4ebb3d569c6e07b1f64f19f74c32f9bf6934f6134b6beaf5a09cf910b6d8a1d61ef9ce799950dae80f7e5731c77d2e1baa10ff849f1b43e407b8ce8c5814cb59a15c30fbcd7e2f8ebc845645ca0c6529952b06e0e863f819e56391516376bd3a62e3364fb3f5b6f92c08e16ff172f39a782fd5e88f16f9130904df060f7d154c017a1e64695e9a81cbe27a30045ddb52982c47ee49a9a965712a309a40296c756f376c126fe97e7af511dbaaa4e5bdf71955dfa878579759d2de4e1f31119435ae399b959624a0c30e68843a85a69f578bbea8bcacf62494ee8b7b5fedbdc24fae6bdf381902c09f34dfb681992119c97d93bc0a391c3ddbb08c4497d32b7981800feb5841940f9c145c92494b1a17a00eabd7de2ad32d6741e340bd55dce8c7c6eca06f7b81bc4df1e9ea88d0c260699f4316adcdc7e6801cb8c12969480d2d6a15db2cca2bcda23078ad50fcd658666cc7573031dc837d59df6836f02583ff70950c495b82c8ac1c7c1e15d9c4c83ac8fd9dcbda77383bb21988ff75f249d96ac550a3127e43ae5b30c91b32d1c9cbf16743201a608f22de3157e53f1ab300deaa8e212907c0497484b65a9d026b43880b15ff1da6a3d021abaf78ab90b751a9835f6fd7634ea1c82ac1df9e8c7267f2c1e506ab1f488a1116eeaacb907b17dcfad8fb58b902d29e1c2ba3ff0392459ff3d49d4896b57515fd3f71a475aac33bb9b96e8ac0634772443137a30c2ca07bcfba0a940a87f399e1a561b64169efab3dc53f64e1c70595a266526a8c52d4b52280186a4b66313f0451947ffd9b8b2665949799bb5f2d3bc609defa5971e2b12ba745780081c73f033063c852801989da0a7a8a206c9a4ae27ead2bceb5f4e771ec859f31cbf521ee983a0a027a140034ad57dd52bac4f732f53818bb0a403f4ed5a1c99494a78e49d620334b85f8ab7943c8cc5bc6a6e856f63792c868afeaa6e96cf8e813cfefbcc2a42688237d9f59caf00b630855575db63128e22df188ddc94a648f76e1d60a75b297225af07dbaff8ec5aa8458803bcf59bc68f61d4eea912d8b99ed3f1fcfb7598a1ce4b518a596571f42a1dcb3b5abdacc3b6ead2c0bf172faccc1ba7ca0405597f0630f7a516462b96257a787353d2bc5f50e9230fecc889eac90cec46378f356153e364f5bf87a32dec24f0157a3ec3d4745fb0cd97a5338f87e5068677a29461cf22b291ffa7a9521eb665a5ad78323a251f0c5550c7b01da0c29cbeeb2474a7839c6834a2800091da24055c7276e18ce55db6ec855c89a348ffb9e1da7f92de17158916c221a491e7406538fa9b5f082765532f438ffaa436ae0acaa3da2bc7dc9e1d76e95e6f088436372d41905af0d4a5c0224943cc0cdd85258a734febb44d7dfb7262dc7da1a153476ace584f45344fa0cc9c9bd34097730a568557fcf87ed1c403638988f70b0ce6da0b3c1d6cdc7a8c11f28fdb885bedd8152f2161465430a95f75f463fc3c463e464e7ba35a70a9384619f674bad7cef0e49012975e1ce4dcee029faca22e0ed76d5ea2662a2e9f7a451a3e3a3385ac55482ab3a57556af3c5a0eafee4045d4d66c5f90d9389f3f571d8dfec0ad4c7d99143b7229bf74e4b04f0b36981aa17e273f91d0b5d51aad4947e93ceb35353828b99712f7e35f1db9cb835d24a4fb6be0839cd7aaefb89580820391b91c00a2f7b613cfb00dd9d43d45032af804c4a71490e8d3f59926f7a6326257fb8c4fa3534a22271cf41fa0ae17769ad849fdd1cb32416e48652f7d62b0e9a0abfde61d311a45f1169c22ad34ece347e9aee14b086f7218925e2e6cc779deff49b289d10fbc06219379edb84d09e6bbc14b8f24852a62262d02ae6b589de245bd86f9e94970c0d3bf8ad56a518ede8249868e0d3d3884c0cb6735c7eb65ffa991e165a55462089a46cc6774acd35b6e66967d9fedd1e646f9a5cc21f83a706c8061cecd88ad4cbd3722539c6f41fa9aad0e1817beaa9dedc1bb71b50684c85650a850b0f10aad25b6a73e3523592ebd2a6482dfb34f1340ebb436474ff491529274de67b009c1ac80d106f83a8f8931609474a557c9fb6f6bf1468a2ebb9057f54121c841961deee14295e1cd676d4fbeb3b992158350f75555bd25d7172d2cb8b33ef6605d5f8bc050e89796c8741efc5685f91ffed847ce886d95d65dfddc3b1694dd33afd18990523fe155a98b7d8fb1872fa1a89aa91062903995903d2aac2650bb62867fa59f749017be18f8b07d58b30091396f26cda2220c09ee7fe189a72aec947e7709f4b37f7c5387df9897da57778b06e0f81bcb9970a523d3d33e02371181af8afe0c7e5f70747cf229ac8ad55709fc758f3cdbe8d6f842c3437f4f1ef99bbfff8c41b516690615501300516928ff1e832f2a30d48d5771d5a895b330238b174558e64a241fdf6fdbc3f754a714adf714a87416a787de436176c411257127036ff5ae3ad6dccc3537791b97b45b8b283fcf4043a779da9a5cceac40702bb554e769c15e9004d49ee08367682efd6150c5002769421317834705b6882d673638d934b4ecad61117868fd0ac15ee7306c243cf052b859454c954b2588d0733afae58c50c2bc5736a5e2759bb12d4b47825fff0dcfc9d95860ce9149105289c588b1b17653b22ae3eaac773da44d9af92d5b4b35d7f6e59b7957f01999cd9986d50b89395c411ff451a106797aeefd88ead53006dddf4a2632444615ff57dad5a1fded7d3da0af5a4c54e92fb9084d8b3451c35763adfbf256cb5400c7f2afec454ff8ebbd9fe3daa8cd22d8dd6fd3a4853ecb6a9a4c93ae949291bc9012b5f816702cdda4db198aacf6575073fb81e5c6f89e1ad1fc4142fc62c2d87f534d209019aae8b0236266a08f6325b85ffd61d5ee224e17ce73fe9d121418bee49ce9cd39c7a7ec6c25859ab5aa9b1d066b17be77285907c706935201084589a179ecd86661d64b4e48b4a99f832e3f8c997fa3ee3c63bcca97b344a2f65cbd9ea9828f70bb8f4e1828651133ce8286bc6a0a69e7135f4f595b4c44355b5642122b4b995820d30a011d299bdfaa0d2af04e091ec752f9aaab8213d8e3571795b5f35ef4efb1b8903aaf8ca466ea221021960fd8624cd1c4ae66bae156a1e8c8b12c38081a06f3dc0dbda709a3356ca7fa58fba0c9a1d88dd067f3c972758988549b158583d1259c027d97891dd84c73d0c944a0654d75e513e0baafc3b921911180b2409b36d2a7254e83374cab456cb30720fa457dab4fa6a6cf12d07d9940534eafc947e4c6f2061966dee5f0a7b80fc594e6a04925f5dde80056ba31e8c1d643f31438a0f1e57d79bb9c6fe72b5316ce5509f6704c100d7c03a393685b9678051760c66899266fe86efabd886cdfca39cb8e220ed1b9543ef8d4193e598c276575cd504563a74026faddd16ffe857eaa546055ebb0e5bdcc51eb14caf894aedc428718728fe2dca0ad82e7c5c55626be26bca22ed507cdb1b4037837eea31286e8239ff3a9bdd9d67da4842cfe785aaff82d477549d25dde2138c7932df880c8636a7e35e631e8ca9c72b2be728fa56f84a71adc56e1f1ccb290a587c033f9a092029fd57577ce40decfb2638bda273481ed9ae92178dfc0e42b87e7fdb34ed3ac3d51b52ecb17bfcd48967cb6cf2e8a497f07984c1376f359a2f98aefd1462c1b6f8e938b77714179bc0a963b964dcc830bd9b0290a190321bfe23404d6a0d72bb64ebd82bd0178865fb443373e00ec902dfaec59c9f0132d2821948ea72408ef586f1bc3ebc158793723053fa5443ef08330879bc4be21188dc2e4b7e0c1cb8d02d0072d3cd627f9466cf871a5a12f49f1ac41cf36e75fc1fd009ee8961a1acd89d3707245f48a1f4e42c60693f5e197c267440c990c7bd3a7c48b3e9579fd0cde62a1bc5d3067bd5d80eae81691c3cdb6da91f8d23da1f3a7f44dbe322c894d25832065d61b46c61a19e4f996738cdeac50bcf5466e8dad409a3291db167076519385d81246e22c2475d730546caad65534c058466fdab90ace4701955dafcb8dfdced042c5c3c58a7433f437fbaf1c944f0721c4fe0e0ac5c4929d7a6de2ac7d2c0f5f40f4c01bfaa8602c8021b0b6d9efdbf806b608078f729237341381ae7a96196464242a4dd4214fd26261ea7e3a2633a87d958ccebb66ff079711c1d6095a8b43fb0b0c31d6287f5f9f24949079ec9477ddd1c9844a0c547916288f130d088c33f9592101668a1bf1a3b421bdb69d3678caaaa2a2bf152cb572e3622cd1cb33b69d10e7923564932638b010185b102333c6a7b673a6773a40736bc80263dde4ba914ce1d565107e538953698643baed3d870bc5e14488b4deb5ec5e3f85833b14903af1b3e7a717884319d39a5939f489701588887d5848427785921281d07a2857aaf1482f093a6f10d1dd40bb9874b4e2e68559f06638c57bc4f8c950711fc87a1288fad27e2559d4d3dbf23c652b2e4b066626e5b7d6844ae50cdc2a38740287288dd3eeb54b405513f9759b41e2b668df580eaaa954c17b6500000031030000000000000000000000000000000000000000000000000000000000dabdd99f4373594543327d2ba09731ad53b82798e148f8e52f45b400da12f0cfe223507022cb49c0e3621672ec1b21c35d5e910908dd019a7244909a212930e37785921281d07a2857aaf1482f093a6f10d1dd40bb9874b4e2e68559f06638c57bc4f8c950711fc87a1288fad27e2559d4d3dbf23c652b2e4b066626e5b7d6844ae50cdc2a38740287288dd3eeb54b405513f9759b41e2b668df580eaaa954c1ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff888e74badc333841ec4e4ebec1260579e7c939384463c7aee3c376ea3ff01318c30a8f379bd5badd7d0c4751aa55a1ec06de03bbed9c42844fa1e6244b45b27f2d23da8026235e78520c47abbf48068ccc93e4ca5efcb0ca2bcb6193630552a858206600000000005720660000000000eb3f08000000000020f83638b4477a208997911e3be041d7f6bc282931f1eed7b71ed66c564c8cbb5df393eba883573170de382718b083760507fd33cdb69043c0423aea3be5c8c03f6a86d412242da901bb16fb96da3155ddc579142ce1c27993087a7d19d0bcb8f40000009d5ea643161b236267bf402c3bec1016fdb94b1ad556dbd49aeb97c727434918336488033fe5f3ef4ccc12af07b9370b92e553e35ecb4a337a1b1c0e4afe1e0edb56114e00fdd4c1f85c892bf35ac9a89289aaecb1ebd0a96cde606a748b5d71d8f65bdc367d30dcee29b756a60fb2421c161c7411c58fd836cc3d2ee80e80f05a84eebf438d8caf71cd08c28dd325bc091cc6bc364b8a0ac5d13a9ec1d0c04d388c818ca8b9251b393131c08a736a67ccb1929782fae74f27a521af81b6ab39d6b8b3788c06f845164b9d6831041aaf2d8de8a0bf7ce65e00c1fa929b1990ad521a00973f2eb859ee50f89dcb2d4c5a33686ff4506146f0451088c8da093ab9ba20c265106b6230cc767403642308044e11849a804103c8e0a143a18d707e8422de21b50a61d1018fca3a0902616022106d29d0d5e883296c486d6f3c23625d364225b889f002b9004498802cb7744c842ac0989b250901125695a184a231a5b8212a45d1891811a88c450192d110dcd23b211a83428b748a90393c0559456641061027e283cce53d040288453410f24c7b00398a314b42c9c162586e1e50ef95b404810de20895533e21c35e2c043216e86122d18f361a09431e45a414ca3646148300043dd2ed1b8d62f0412339172407e8405032bc090f8c2d8012cdd8c04683b8860dfc9062c559806260393c3b28c1fd11b8361e3e27d3d3ec0e4f0f0c5cf59dc89f98b6783fbbc117652d2ff3982fb039e9300b010000000080c3c90100000000ea0aad00000000006bb48f640000000038020000bf20313e03000000000000000000000000000000000000000000000000000000733447b6737747c6510754e5fee8e1cecb5635a53d5f11ff1f821ca71713050c66d73934b7db72d971a4cfc5732c75d1c056374cce18d8bd3b4bc4e840bb93d8307e4dd710e61dcf9df75f3e55794097233f8d91b6d9016fd09341774d4cecd96265617665726275696c642e6f72670020660000000000ac140800000000002c947b446d8550e44e3205eb1ce66493506c5ef2c48468e821015eec7a89ba4dea09d6b09b7e5244d5b205a3db597aa07e6540d8a1dda28653c6dcd29aa4c461cec082ae5243d4a515fc287005dc496c053525e49f34acf7819b9784d1da4ca2f40000002d2aca05696594d2ba9a6a6f45cde8f303fe3530300d2515450f7fffca507c70336488033fe5f3ef4ccc12af07b9370b92e553e35ecb4a337a1b1c0e4afe1e0edb56114e00fdd4c1f85c892bf35ac9a89289aaecb1ebd0a96cde606a748b5d7163759af08ec4f3c98fa482c76aef2b9768a1b07b148bb5d89f37ecb9f7f14f217fb2d818d154b3f5d504b716528172eaec2d3dce07fc499e5f76402722c8b1ae1f9090aae28b8a3dceadf281b0f12828e676c3268682979090c825df91e9f078a7a1e943f121f2b8cd5bdd31efdeae838bb4e4b97ffa52f0a0e4881bbdaec1fa63a9e450b6da4f03971a28a83317ba6eb600384d05e155ccc18446cd0c1ac6aad25054211063740dc6024b1223a15046e74a6915b49804e070d207e002314e4c215b191052e1cba8cf2abc8202642068006ab382405066aded238a086e72c20cbca6b4ae80222901a4c2098060106dd5e023129adae468219f0e44f14141909420210818f41219700c4f5c64bc58c81282dc40014910d14e02680644057205424a2a0c87900188ab790102bc0c3106c24c3b00208a2be1624d80672080262cb4113084622d6488004360c5ab09e7611d1cea2849e19916630b4ccc01e48084022c4e56428851727f01312276491d78ab2461e0c09110ba6f0016089369cd32008144022ca055deb0215a84460ae811f308196e24485a9dcfd30343180e17178562d2c8ff1bf0560a5edc2ca6162dac5618e61dfb92300b010000000080c3c90100000000a613c5000000000057b08f6400000000380200009751942203000000000000000000000000000000000000000000000000000000331b1413a14ec8a05fa165bd21983718fdb7d3fd25d4564e7af7a930c89bb75cdb07825c4126b37f5a0e736d52d0e97772e7d6de35f93147fbfd676f3135e2ba59b6f20eabb865a56777ecde2ab0c623bfda3a5038449a6c94ac934bb93579df7273796e632d6275696c6465722e78797abba4da96406200009070c2a0ef25253ed8bde7cec13cd1c684bb2d3fc5e348e075b9de90db39852dcecae442b1427db9481fc33ba860512495d28a3968d1be873607bffb93561cc6bc181eafe3c317c1c3e6450a447d074992bad87b43b266130e90d2c397b0e973a9ed43993de1a5257d50635eafa95532f0e269831ea9e00050852a803088e27416d2e1b4cd40a53c20660b1abfaae4e991d353d572b39e18f25f48f104ca0e645de84054b2583fb21b961f31fb9ff496bcc41476e4754cdc906b86e9c6d783b68e800606ca467ba90b7b6f7f4e482c6e4bc46f0a5839019cf2c497f8fc10ac24f9637f11a72dc573212505688222978c8750c09c6019df77545f845611334ebd8a463c5212d471f9c7e3a5f46a7addcaa29f8558b5079ac4cae9604e1c798f839128fa8dbf89eb8cdc931cd00146140638bcff81966099614ce257ee02529e3b8c986d9716da0f3b7f000647c7afb829a3f2d78469f420185cd7080e41bd638164a27246a91945a3e964c7e1ee5da26a4c15a841bc63422cf2d24734741bf740a11725f2da781d2e569862f067188a168fcec84cfec11476005c2f21d5aecd0459531bb5b2d60b45db7ae73fbb619305b8c22c7f13d92d54011ce7ad9cd85129b36a09059fa4ce172c3818bcb690cc1cdd785b989c025166da87d38201803442b86ee383b4b2716c7fb80177c5286ac5be08823cb2c100a7c5de79f98895a93da644691e96518b2a1be89a61816df8d8b7d17366927715242650c74d8318cab49cd8e1409c8901a5a69c0f38b3bcfb8bc3355127008011caea61f0e646c109ab89cb55ffd351f887d4b91efeaf45d7550f15951de50e184157d8837ae39e8383be6ec4c808bf53337065b907dc83a952b975b614821b450f20a93324fb792c29144e79b0e030b8eeeae14da1bdc2ce68b5dbd6c87bd4b2164156a23e7020096c90ab3b31eec4a0d3aa498141ce3fae7583c183fa35a8b2919299d148ea56b51d6382e3e96ccd96d280615bb7ebff42d9b3dd0cd6996aa7f908ec2f6ef6a7dd1734871e6d336bced67bbef6179bcff6f4d2c4473466db949571bae0b7521f8562b8fc435ae8c9ed44b786ab1373fb784e56831e155c2c5d957360ba6a4f8a646e5470287d6329847020cdd24730cdf5bfaab0e9a68bfcebe34ba049a28abbff91adeb04545b54f369de8e6b144c728a88142a6f72288d7c955801c7632a3fa706a192dfdf21d972b3406eea28628367ab3257e245d6de1db386f66d0d818f1716b440784b430e75a742ea8239f9580a57851f89043e8ebdeaa9350d4cda926e35974f2169d143500758da678bafffa455386269f01e919e0cea03160c74a28ab194432cffd3ab951716eddf9eab06ba0a3a241dd6a87b4710b98f06d5d9b22e35e4e8c103fb80b507635af839fe042cb6824b24c76a5955a192fa74cf69ba35d5b869e92da2fa5052364fab10d1e446d41b6dc31406fe605cc49bfd8bdb2de076a9462b953e2b54991b4115e402238f73aa3ae2e855632fe15501d520271eb87daf721af0391b6f293684b1944c1ea392a1177f6d3d83d36a4d806d4998b242bc8697b4443a8c79304dcd21ba1e1d4ffcad174a0cd646bb7bb76309f837b9e92c91fe6da6befc837cfa203cb34064cf6391704f2d342ff4e8e3ada3106aed188a9d5716ac9f2bd40c403a14b86dac7e5a82fe9bad81b5877805f44c367bb6b671f14b746794607c0712236800c679fc32bf8bc70a6c5a7bf27faed06ff12a6a668e231334d4a7a6437c04778b04e28507b8d4d7db6e88fa4d2b0233d0387ea742d436d1c6e62f85166b85fe1d0846da7394fe237bc05aa13aa6a6d142feb7561ba350a298e36c9aefcf07abfe85024905e6cef6f68772f2f3f062374b49348e14b6fea4a9a502b2dfa53e9a70ab5bf798b4f48f9b3b9384912dfcb7c754ed6aa19a54c997d8a064ecf44606a0bb495d6d83f1ebef5b83d169799711e481ecadcff9df942edc321c8a146048d77497ee652af270cbf8e35498069aac6751cbb8dbb275a26da51117027eb20f6462d230907c609ab78538ec582742aa0f7df5ce5964c942d134a76615e487a236d9c8ba2b9565b7727f7fda376072ead85b181e5a50b204cf0d687813197ebde4b2db564e5c4378d5c4ed669e9599959a3661b39097d10aa5371b3c332b5c346322cc62b640b13e87e79de4b5fd767c8909274bf13eb7718f4080bdd8a09c22c395da074c80723a98b363e9c3d4744fe0430bfad06e0ae596fcfd1131c8a6fca08b0a2d496d299786fd698acb41245f9f7c27ff9d8afe063431908c7682dd30a2122c71b782638a5f87ad8ae04d3ebbed5ca3716c024d995df8b7321e53b91431e408b13992778909dc6336c7aabcf664ca27f69446c35aec2abaeaa810b7bfea4965932fd691e72baa802fa09d0375264c1480d0b5741db92c33d27915a7cbb5d8eefe9cc2af0ddf11494c9411151b7040699e2a1ec04f0c60e0361bbd83a96ac616214d872998f3602fd7094a5e5e9b221148e4007f3c0214ab5ad507c9a7b38540208c3f593740e5466988d1190197ec0b56a58762094103ee61ca609e189712d821960701ab282698cdefe031352b45eba3fcd2debd025dd64d760dfdc8c4261acfe886fbfd42d06b62f1c6cacf44abde5f12cfaa53d445310785aef0d8d9fd37587bed2fa849485bac9373fb8cc0bbea33178fd8bdf8283e44d1adaf0ecac08ae6130d0e7fdeb21c2d440ca11f10a8895f2781591ec6fbbdde4e4b5b64b5424ec198acc1024c9fc6560250f6a139c85e4632992303c746e63cc530d18b34aad2c561689341f135d1f802820844794a3f21adab79d01bdd265f5e3ca92594dbc2aacf51ca2f1814183b6a3f83a1909cf153a66386f3be4130812bcaf8a44e8dce1c978796657c12c40a0de05f04755f1472d7a9a6868ae82800cc3f44e800ebe76932669d1390932ab93fb218eff814c0248aa51340394ce456e5b9d30ac85d6e7a388b76373c9315876cd589215bfce100ceec5efe2a747509109f09e51c40e41b7ab32a2ba661859e961e5612bfcba706e61420a86e0255fad0082be735a65386e44b7dc73bf7d0eb4bfda09e02e14e8b5892befa7a7fccdd53130b16d0749bafda4f08e3a150d065d48e8b0ee1eac644bba97fecc7c6d2b7b7c261297e97dc0f9c97f43368ec1352d475d67c511d51e26e043f1b88b54584162926f4bda52005008be3d0bff6670b03fa635b4e78780d4b9830b2be14f6094e70ab11618939af5ac4d3bcff2c1d7dbcf6539bfef8fa27a642e3a53ab0faf8f5291110bd8e71417fa5ab675bdb58a0a9597587a036fbedda57ed96f9f749ce5a09f581446a3264d5981ee54eb6f25ed803b814d758145f65b891aeb5d334d1c8d4822e85cd8110f3405892ebf77e0e3b9e8922fb35fd53e84f0e5d252e5561e2ef93738e9dcd6ba3a66a5a6c76c33537f048ddd678f9e1be929ffa810838b5be2c0f7f877f19a4a33e96bbd7a1edc0130383808b06202a039883e738e0c39fc4a3e9635acdf9e10bb754be2f2a4b8f7d724ece94ae6774162a1585257b102ad43b27d980cf650afa8b4e182ceaeea161e0d34e0465a437b62be24d61c5f5359c40ebc6d23628b33298caea2b2d08e3c00c0199ebe0ab3b008b352d8456ee3fd25813522ea01d9885a0ee874242fec008063b242026223ccfe83626a9f4c65f9c3777ee188cfcc71ba72cf8c9ab59cec204ba1f6ca252fa84171bd3a44e30a684aeddfb8b7c688a29009370129a3b05616f2f46bc8e363cd89440f4cfc405f78bdccd2b7d8cb909c7f5c612d03600c385ccff1ba8a4ea2cbda8f2e8dfc8020d9fc3851912bdde347f88f6fb08a1f04a5000e5e66dc9573b407b2d09336fb4381b440f8d879b2cb34554a2fd543b94a511402a3560111f1e01a84190fa001e3101d3fab1c75e1ccdf79b34a08e372ee9ec926fbcfa210da999fe471592c4a64a52894c27901ff1cd3ca60fe8b1097579a2908444927dc5fe9d06c1fbee16f01fa5cce04bf460136de368df82a71130874c9d7fc852dcbd9c4cb639609e56adde7730ae914f6f33bfa97ab9ca2b538259ec9c48ca63d6fcb2f29d2dee844f663813eb190e6b70645b7cafb22eaca7f2afe40cd0423d0dcc4094b1605a0d26e071c420c912eb89a693a0887955491c5938ff7640354cc60ae12ea98bca75c90d548ab712fa49cb0e1a1c91598abb91866d4ed7d5991e169df7f6f03df4666d1013b07e77be4a1f975a8eb1d6152dabca630b6f4c4dd41098afc83082019d7d4e07ceea7e5f280e4d82272e3826184b0033cc098a797af4360910b77b653cdcb095f98c04b4d513b6d2ac92ad8318f02a0cf91866dd82ff3b91dfd46987b8aea4d3d45c4371f294f61e3a8c0372aae5c0674354f6d865d705adfb183216aaf7a6d0f78199f727ecb8b25ad5640a28c7faad36158369fcbcdc855dadc8514facac668cf409fb003090930a65c4e2acff69d63aa3a93f4d912e3fa5bca8d7103b0a43988b7087a27105bb34b30ff536efdd8c48e6af13f9f20fc40834a5d38d567ecabc85c9897e8b16aad44de3ffbeab54b6464bff1b8d92bd2323a5f68dc9c12a9ec3f7317c0f0538b5823679a9fa17e0b5254a351b014e39cbcbd7bc773890047f52e579f27dcb0c3d949328f53045430d3d8c53e953425286d144860f36aaa167d11b4e0719fe28372832345500762b4a626ef7706b119cf23dadf6365fc5c7f61538970831120c35ba412c666e0ba03dda27685ed9533b887ce096f9f58cff750bdfb1f975cc6a9c1781af785e34dc779f723c651d09e3a4647dd945e1245113dc1bcee56231376eff3a54b0d1ce3208c9a0e60050effe9e22a42f757188048caa9522e0505be1b50070dacfb04ebdc546a7da3373eeda5453676681779974afb973295f6b5b5822ed917a10387495eee669bdcc20b5f9fad4add658fec740ba1692b4968e475183bac196ce5e27d3ed9a97bc045ee3c3e2c0b252853d39eb193d8b35f6050f50b20942dc599a06b2ede62c47901ad270c9af2e56ef2a69efa42d4cf88bffa41ed942a9860aefc4ed926482eb9559e8aa3b4645b8eb450e8db70b0a40f27c67f147d195ec9b3c160918b7bb27cc010cbfa9ec94406659b66110495ff2336daec05ad62c64e5b1d7f40299ea1d0ddc348a551f309f1a1df6887bbf29a05a9b5d790d97a4c11b63ceed45090689b616f73a6ba914e6e3a217cc24175e59a401c89bc4c083bd1b2ae52a2a53d7e99d25f2021047b31d02021b92b44530146c8fd061e9860aa014b4a4b2305c8554155d83b6f85aae2cf72fac61745e47e14c3fabdb5f238649490eb5e06948f1849add9d34e1bc1b78e823c5fe210681cd9edd53e704917802359c3449ce92228de5c524a085a387d9b99230708ba7262a81780aee87fa3fec83c8493c5c8140d6acadc711dc714756fc3a24822af190150b9e0c0b7745a581424917b149d70738df5985a0a8077d63cce57f0af5bb17c9713dcd6896dfedb1f90ac4150713e11f267044054ce0802085232095be675796013c70cf4f371b44ef44a3b2934fd2f76281be43ac75b8fa4a72d517567cbe12600f240af488a1854fb060629e8f1e868443ae64d45d00ca0f73ae04d2a403ff7d36a3dc665b7653a4a2aa9596471b9e223eee10ad6cb91fd8bc4b348826794d87d741e99c0a1936fc7d83fb64170d593be6d85309e4abd8220b1d17792c6b1534b89807d828970f73e52e359c264a505b208eaa74cb766b8f57773ccc40bff0ad03cdfa6e6ec7351eecdae4faa7a1e26b22cd1009d1b2290bb00136adc7c97cd298c54468ef3697772f3d1f9682dbeac66ac50e271bd9ab5b2d5f4c94a494fc8a89bc6fc6d8861667afb69a288adb1845461d350a13e1445f272d53009a25752f4d8396cbfc1d2b78ff124817e6ceec773ff3cf87bda8b3622f97290ee4cc0156447987306a22976c2d5a6c5a35ec9bfe9adb591199edee8f7267966a656d944978101379aa95688b03718d3c62869a1870e5702b8cc16e558448f514fb62ba7d0aa15376adb935d0aa01e5e69b6355dd594cea9e6eb412cd4da12d39055005c25a6af05014fb6ea14fe0185db575cec7e97f4e5907ea71c4db3346f26f85d3d8525502f6fc99e9f0d4631e26743e247ca5805cc1c60b5869fb1af4dced30e211384d18880cce04478f29c01ff810e41412237d218083d411d35589fe2c80a51f969fce6bc5bc1ebd08e0bd05e664fc30f47c73523d874c428436f592c2606a352378e23903a2801c3505b82eda4ca9cf641134935352c621dbe5fc11bca843049e47085da7dc75b87ad77d42d9b34c3e29793d30f0a40f9c164cc03d03b0a4d541d16501bd01027aa4dc83c2e2bc737807e047dcde5a43cd9084c76176d2b27454204f3d0db3fd5a725b0a17e2752b28402d89abea8253f5db48cd2fdab37f96ac708fc2fa57322aa6bc94937d9a047a0720f835ab83b182caaded57774584744f255a11171316d7d9c86e32963e388b3d3ae38caf96ccb60ece07297e82a6b551673eaf48b3766fc466a2468675a79024cf39047955392e69e2c8c60e1220fafa8016119426fed5f200e5f2ba2e187a94fc11ad14881634e9ea4efcf54b63bb83c03bd45c0611899824aaec3f5e1a0c1490de1a4e36da831102a2c9d9dbb4445e6cebca2ab9523fa59c9a7f01506320e444c8c9a94778974de21f8cc0c61be005d1f9362d0b2e35a38c45cb93256d190b6c88076c8fd859fd7b17aea57ef66bdb803e31663c5dac132712a066a10d206324e3c805d9d4923ae6c999960d3988c080f0603994a7445eedd22e87eaf72953c9f175be564ec33fbaa2837a24a4e27993269845b1fa9a5b69c3a1f566483b3f552da3fcb7ac8aa08fd70ecab7ce422e11de797e9854dfdbb06c815d4f8a0571ef788161a1db51d0dd207144e7e03e22873594f9b3ab13cb661153b65e024ef6ba9c442046891e9a23ee867458445689648436d3de56257fe2182b1669f2de2105458f98a1b949fd5aeca753735d82e24a549714552ee3a94d743074fbb850f2e615c91c8297d97a960bd87f420e3d3fb91cc74cb6c7d99415dd23a6ec8dda11b6843811272d190125256a48d7af44c8dd8746df4e392835efad5589401371f1bc31cb78ae055d90467ebac55c8ea11d2e314cfbc328c76d84e74c5a7df190295659884c854e1d565cf0f9febffeb114ce595a37b6a912634b76912130a26917807cc626ac64b390027bac3d64dd15359c4346bc38e7d01f04a11e9a0f17b4ae596800a58765e999be8707ff3999c488dbee019d2e59f4572e7bee8465d59119ca1e0621a6c6dcaecd6c1792a5bc926698e17984802ee7366682c704a4a4fd24a5d6237ec32822916f76acfebda2a14bdddfda6e48271d5747c08a1cfaafb133e6986de291bc79963aa5820e4fc7cd20cfaa8b7fbde8d00e557beb05984e7fd02bdddfb65dc986a9e79ce384e1968857cfe1f5e2a996f211b5ae5cbf2ab5f643b8d61df83259a6727df60089e97c2b83c8f3b03f016893b2a901675784fbe4972fe30a8aa79853f3a4f9b7c9a18eb8745fc20d61dcece8c9237394bcc74d68f7204e7aa857da95dbdffbd967ff69fa6b1aaf64ff880e049b0b680a646c66ae97600e67ef0c6e2f4c7a5733b953dad12422a1dd8b31001f7eb43a478fcae66d08b5bf0025b536ff4d4bc9c6315389cf669a850519b878c5634201e5aa1e7643e1944bda7895ce895b2ab3fb96f7836765eab0ca4087405a28f506f3f9017b8e3337bec484ed35eccdb81b9eaf5c5265f24b769649c0b2d4b035d905f3221e83d631d65d97aac26d3fead3f91b516f4beacd7a4c6da1c6e8b62ffcea8e00009b1e79aaae41a932b7c503655c7c7077120abad75b48913a4630255514fed150772bba4c56f39db88f3e2d09f777774142e99828cde70c013df10866bb9816d7c84726c9f339ae4ced85fb16c488895947977d6eb2f7c906cad333191d025519226954e56e505589451867cbbaa85165435771e39bee81a184ef9b6d3fc3d1fca61d48f9a0b80144b137a917ebbbd1e89b8286bb7e5cb316f20c905c8f3acdb4187d764b4a0888f02e29e06dd84305c8f539df0ae5e5889e2f8ad180346141acba7c6538b8aeb9cada9e37d07ab7d5c39161445fe3429366003da05eaf0a429dff2281b8bc76f07d61a2104c1effb27ba0baba7dc1d2ad572473524d5078de603e3822989ba2b9c2a7e01529f9c8374b2f57d4feba5e08ab0d103e78248e77a4d1a1da0323897eb46c0647e4362cbadf41cd2c191087ad1b2ec0728394fb6a847967607c02426940d7635b4771251c19cfd8849ce9b1ef1fc5944a16769bae098a348885091e937b9c4614f321a8a2ce96f82c3b064b5e2cd00c65e2e0f3c18c62aff14881a385ee324c6a643e4a3488eccce42f53de8294ff4bfaa284b52f4abfa5541fa7d322f882b13b487c727df4285a34122e3024e3f12d03ed98a6d78eb357c37b6f8b90d699d1d7c99c2f60b024177c622bcf7e52e80395512c7035c6269095bfbaa167b25b04ec8a58f1e41163610eb852f7879364c53f17fdf079fa4e484878de657f9a436ba98a66088613d62505b5f4e24dd1c637bf716184431ccfc8bac9878bb776c2a26a2b61bd293b7d12037e4e4d0b506058dfb1c641362c9e9d6d7af6beeeeee722af7f086bdb18ca47e687be8c88e2c08afba1b5f30b7b5b5e74328e535c1d9420570856f14865eb19009d833953cf3fa72bb32a18a410aac82923e113af99552c8290e1d062334c97ae6c9b369d590aa2aff9ef862a2869c4fa9bed4ab8e85abaed77c2f139a9a01f6511bd8fa3c6fd336740f3101c9041c811b78b9da4cc2edf0ef97725dac4ab209694b4166cd3f15899c7764fefa3f8f352efea0db7533c4f80f42b5a983d2a87ec4c6b572e403e5e49ef80f6367e875555ac88299185dfa06833c1b986f4b373c98ce24f94aeef9d02dee57e4c857d764f3234407063d77cf3704c91555bd3467947ebfd8392edfdf704c254deaf23ec3ced0638a6b3d5f0ca8e12e742f339f8023fa63f86a181b5e973a30f2b1a1b7b9bc6697a35fe362c5b2a9eeea83c039010020c7fb9263cce9342b096a7cbe009b5275682120a8d5a5bc2349c6cf0dd591cd8ee65de988ede2ff49f8e952892c0222d4f4aad808b6485bf5487490b63f70a1d6860ca56d586fda84853a3730277f2eec2c8b0ab5344467041c3e9b37ff9e5f702f282d4255d42c58ace9e7b363af37949a38f983b2089ada36627c70d0c66714ef49366005bf2933d579824bff5ea1f6d66860cf57352f11a7f3de230b3cdcad2306079fe8e633559f2fe1dc5a7557299a20a3d2e2e2fe417e60488c097896aeda9b5871264add4013ca2b7592091403911af159de208a2852aa2cf002c0cc7f0976f8635284974526b3875d3bc653b936c97808440e4e82e6a74165b5acc6a0611eefd8b2a4be57c42b085954cd89f78e54e4895add8552095e4c47d53f1934e42af810e8f92efb892b50fa466347d822589dd6f0ef7ee4081703aa44a6009aae1433de4a913877d8e85dc683b1bb431958892bbd94cb0e74d80026b99f3d07c181ec3585b64951615729abab499fa71dd9f1815b2ef70c39d97dcdf7c040c73c4907fc6963015388958b40cc72f03f40d50e97f0b75414da96187c95ce87fec291ddfb99c47466c43b5bef01a18f41c858a3351f4b6783e2c75c02d4e3b3e51215ed9aaff8e8a6c6e4214208d89cd14365b9c4fdec4a21ff2efd5fef0b00569f0a9ea2c51457878497423b7b5cfa616fd3a1a8bd19a5b2d4e0f1d946c0cc0fb2ada32ed55b557e1ff93150dbc17ad261ca8951e46ef49403496b1f973b1d582256d12faab3560d5139616e2f37737a105c95af36335603ffe836529ea4a1fed3c80538ea47e72f99e0577b6f1c290fcab7c34d3043902c468d012bc24515b4bf0511ed5075ff85f77e0d084eca7414468a8cd765e3c883286d041335b60a92ae9da567542a476e0a2944ccd2a2e46c0d718c8875818e6c129bf6b1664e7188bcc86113ad6dffd41739027615a3714cf3bd19341415f7d190150299ee69e6f99b5cf132287e7f39136ec0e322e4773e307b888e75f00bde3aae43f036ed393764a67afe08dd735d36c38dd64c5d41a88b564d754d511ca50588a9e48374e0b1667846a8b8ee7a325f8ad9ba690918a9aaf1f8e812a124be95173f0f39a561b1ec6816ad7a1932767755682c582d7774f2b90196cedafdeb22168a0f3349cec582964a256b0e5a10a601670bfcde1efeda2ca9ecff9ea9f73f2a5d646e09da1a89a8c54300b2f4f29a68348d456ff580cebcb67bca6b1b73b7d542b38140ffac24898dee39622158f6a2ddfa16195b2fb548c5fc9ebaca7a0c2d6f82f2a51d2f10cedf1cceb2a0aaf663c7ffa0995d2c4d96abdc2b6b99cd571c80ef3fa936efb9ba9ce7e7a92141f09a636f30bce77f80b4d0fd1829ed5008441a9eae4f3dac86abfee8fc858cbb6ea36ff6975e009e1c293e765e8983262ab577d684daac4796460f75a4910f3fb00bdf13f4355c8140a79a3e9ee26692a3bead794a74fad4f58abd57545d8049ba8f0ca3d8872b8259c284b2a50e514e6b3296284c4cacb9edac1cb78f848b20a6fb9835e8d58f8e7269174206a0f5c2ce40dd59d63583c2999f62aecb43fc4f96ac1b3f8fddbd48800e24c2da80ac1587bb95edb13f0bf8969ab9bc3f71af94371db2942bebc69ec15501f722d7277bc1a21842372c869372ec3fb9c1471fd35f3f1825f48e959487c8b35ad2468f6f9d8c93b5ec36431c4aa6ca6d3adf1901b0481e39652e5e3e87fe6d3f9a2bc3ae951e9b10757b49620238b1f153c2990041c6ed86bb86a6e38f2e4ac932165826a68df82c47941b22a6ac6a220e08cd6d1a0107b4df3c7f9740fb63f70c830b816a387dbdc34c96e0ca7a08528f96e3cfdf5f0362761f03ca484353a72ee0cb2716e3cd981981d4ebce393722b0ffd201ff31b54613114d6d29da944a85547e2d62170e5317df224dc10f56e67f89c804147819356b96876def0b7d7994dd22b89c75918c793cce88166c0f4234bad8d034742a12d1496c4a8167d24eb2f767d794ec9ee4c7d0e08c184b4ce2cdaa57888c04cb4445330bcd29a9bc738dfb99e37544cd6f235a978bc16073251098a7aaac9b780aab9f978ca4990d3ce0daddd294015969ff06f01fab4932cf01f90efc84c3c09646acf7095188970ddbb8f2aa0da4b3ab013a7a6c2e890a9ece69681aeb174ce7193eca298c83573ba0af12bd2f4f1a1efadba688084edbe002b896844da2534e7b956fe5a1b81d0d9b870878c73f99f17fe89ebb9f13b9443beeee2ab9ecf8916967a742f7b3e57a48c13fc7f5b84d2f1e5fc5fc1c69794f0059d1dbfd0c276fa7796a31826516bc3e34bbba73e076b154d6c6abe9e9d5d22bede344a3a84f43153a30b792487a9dcdfae850ab4e12a346b25750cf39908eecfa77a5b8da7b6d9e11a8d794ac0d0eb051de592d04268f47d3bffbcbeb6ba1651b5e647db474bf3cfb0942011089c3263e4e815ce3717f9769367fe6b8a453655d256d16d4cdd3deefbabc5afadf49d0fc17bd796b7c3a71bc14b4f146a03d6aa0e5f5ec04cdd1f851f9f0d4e05add2ad887a94e0f2fa0afacde3f46cabf2faeef6bf9e94952142c655348869339abba5d8e1ee7b4df7867656a3163ab31a0bf92462f3f656a61e60893ab64c8beb2f34bc6750cd209b0fcc5f4c08e8d5103d96b87ed111e6b2e3b71ad4ba3021e66cfedc41e53e5493ed23e6592c638c9b649ea7d1506d054d07b6d4660abfaa732017da05a8b1e9581714cdecf2b41ad19696ad97568d56ae22032a40a96aa074a2af119ace97745171cd820449b016fa4fdf557ca9e652365b747bb1158e3928fe2fb9fb4a633b42aae8b1097f10a78a0ecb7f1007714c543b1d95f4a449a373173396daf87dc3cc7a8e3df03415d882f4684a0b9013b761566252cb515083cce2a0c2f1b08d27a0e36ae2deb4a312493303f4f6b55cd0b778abb1eb801a152c26ef5f9d1c1bd2f83abeef5039408469116b40c7fdac1b78269d8d58b35bf0a7eea00c910114d62a83d108fd51b2fdff2f9099ffa0de99a9ecccee0ec6f984e89c9281cae7ce79a380be5a10bca2f7f638d458b58370763ec9b697af6f5edbad3a1ddebb6b67939f46a1a65aefa391c3bf696bcf9c23aff65e9c51cc694944c7e2ee1cfd1b597ec6e6808f93d649c70e8e1c0687e2e877366bcd580b846f812de34c016c00a9be91285e7f905833822fbd280003758d8973f4587352d0aed2066eaee9438a229e8bef4f7c50722596a8a26979f8aaa7b1b8705415387c65dc3977c229b3e89c9529880de4e2d507943d9d797cc4162dd489232c61f31bcca5171c38c57813cddeb98b9ce83d4de4fbbe9a24583c090fb979f5f9b0f203d3fbef3630f2a61a9e4174ba20645dd1aaa889e42b59aace667eb2f86588fbcef57a6d556ab0fc35b3fb09f5cedbd0a9bd69b7ca82d2a080ccaf04230ec317babfae4295472a786a2ce242dde0ed725a34e05e228bcab568b858fb4a4c1befe3d6004017b186335045e96dfcb2e5849579a4ce46912837deb84007711c9e823281f40ccd8482e3fac5e27336d590f543a052ab3ae36f57bdd9fda841527ff187d0b25af3c021d054513de3ba4b1064543d52be9ef584ce139b3fc2fd03d03310391ce1ff81990636b0153ba88ba670eab88fb84f30cd34c152d9fc12f94df90aded723de009033ae18b2a0ba1db78227857964a322a08f61da22a27b056247845aaaeefb9896d26ee9cbdf47e5aecc0ae9dcc04660bf4b54d9f685d9615fc1d9eeb887c00752cccc2f0811d43481b50442a3c1365e022bd9f8d2b9974576114d2c8b17d4432220226eb014501681708e61bbb1d532fb7729e17ad9624907b6332487e2993111ba3a1447f2af1baf1943ed3e450bc2479af9626519e80f6bbfb344a79c9fabd6a3fc47e1b614e02fa1338ea864a266ac01a57ce20a391e759b5c8942b55bf96f6e6daf4316d5aa8b91f42eb1a0a9961e6d38cf071adad7e4f65561843b114b5a45d0ca2cf45af950276a3219bc84d165ca71ed432cdf394772dd622fd993e770b8c687cf7a194e36fdba24b3aac8558f95163b2539619a7c757558441502766ed191ba468d152f3ef033613c5888ddc278b5b555fe87554426829a8f85decb7da45e7f7c451436c16ebc4aa0ceb7cdc216228a7e3134f335754a7caca814100555289d013290ddd98e804988437aa9023f05cccaf1960e872b2ce8b8378a46938f9c33e5d9fde5cdf1de50158693f28da7844128810ca86b2abca1a6adfbd05596753ef698bf6337ba499f538492a6ca233db30e63a4c9acccd2b30eca7f20c0d5ac94da2789e4bf6f677c898227800c10e9b38573d9e3b728abce818fc93accb33a414992d29492acac3c337fd9c84e6f8d38c0d332ee932ce53c95fa883ebc562424f3618b7f9341110a81159ef599ecdfda6de126c5a1637ba77d68a72ab114c4cbdd74f1b7ca5819748198ed63b3395aed54822c360dbed9cd337b8a5eb160d4c1c76a1bde853b673749fee1fb33cc0f8b7279c5c5b50ddb73ae366e355f3bf089df7ddcda95442b214f159b920cb99f2ffb210c1428fbc5db4a1a59763bb19d4c437be71f3decbf2281c581c0aeb6737c47093aa5418a4d34c6a428ea2d8e3b02dcb921329043744a99fdfb2c14387184942fa952ced6b194a80290882b7a38a832e1fa3da9d0e88ba9417faeef20e10572cbed42f13647e7952fec66d04d5d2592fa2e4b33463bb3b4d65c5dc53e56359efbd4ed6c54abc2275463e4ee9308637c587bfec9dc88f9601f5370a47f76c74e84fdb52fceb393ab01272c73d1bb1fad891233baf975744d3d149a674ed498640a48f9f9a8086c67d89afcebba9251348b2f89fc13d51eb45174b158ec86755e4cf57d29f1aaa0bf6f84982b332bd85cd46ea3ea29dad54249dc8c6f1f5e10607ed2085b2c762087117481bc580726ba56afae4f1ee25fc8cd7e0a796f0c591606f0ff5bb20f0097b4a89dedf0e03128ea898e2a54501684b2a34f9bfcb34325cfa4278e6e308cfab298fb2f19f2a1ec707868bfad2a55b26e4ad7ee2a47edd1aeeb63b0363cbb8387079a30885a48fc2061d59c59607bc83fae2b73a7ba33e45556642d2aab4bbc0cd03d4071a3997479286de59f6856a79862a4fd8459984fe6d0805cc20ca8663b4a172e514fdc996837795f9d1df5cbad1229c390b40f9f726f560db2382890115e4733f5e6ae715707049da19c17c70395e2d03b30b4691862cdeb37428bba5721d0bcb2ff62d775bd2fa60546458aeac3e13edd4f9982ab4eb5e642b2f6ba57ecf18f33eccf5f54be9caba6ce1e945267aae131941744af1f7411d5bc89910612c7480daf856fbf6bdee0c9584934fa22a36340d59b3447609df1db27ccb232f560ac6c1c8752266cea98e1800686f2e78909845c71795b502f9a4f201672aeb9f1c328d7e7d0cb7e79e6bf7d783ac58f0e962a9d19807671a4fafd204d810fc6512cd6621ca402a1d00ce827e3ea90871029ab8cfb17663eb288d3e7480d64f89b78111ccfbe6585bbb5fb38278d3fccafafa172bfecf20d1878fef5ee1d93c0e1c4145a9f13f4ec0b3e63a6859a268cdb5a579c3bcf65e7437bca95a4856dde28b9e6e7fbef8a2acd4b6041b276f1affd0d5d12304821dd708f19f0485df21a37db5856f99d9038b0d822ed4eb24640b4b541c124c75626c5ac8c0e86af038175770689fad744080e3c147bd3859eeca9d95f3e1b48db43b561d9f4db8c5871119068ccb39f1f7ab110b7482a89d39a7607bba3fe262516147c56eac629f367ba1dabf8fca35e77d5ed5423bd94de70c3cc2767978f0dbfd9ab71e8d8c46c4d3715fab015f40eb5c7110f09ce0807474958112ab9599a04c8e6ce7c0f8a1bb0fd73397099e5751eb25b86f274f36ad947dde9ed6f7ba02dfd9641cb950baa6cb837e8fec24201ff8690c5db7184ddc8fee60a0f0d9a29b28f2abe8d811a2b1e3dcedbfd6432629b286f00544ba083da9af7cb338bf127813f2d30eb7d97e4c34160d29cc151c9a753a8d5f11d47d74996c873f0828ac1c0009e83ae347f076648b13586bce705df62a8c7bfb0b4ba443f9315fa915d1cb038eeec4573023636bf01b6e3aedfada57da9ee40647f081345470bb9b9b26aa79a386e35dba439ac3de0b9e6627ce91e02f77091fe9b34f1d9926a5914c2a961c0cbbd2fc83dd392cf90f2f950daf10585b1f3430db0ca296d1f61d1e6a819d1a1cbb5438a1b76ad1e6a0eda93a9cbaf157d66a27a910f96da64801cb7f1fbd4ecce147616a730f81d2ade7250a83da7d294ae886a9b28e62f13ff16397251c85c323b9cc046513222507cf279b7db172ca26b9fcf90566d7d31997062051d9bce3ba4920f70b6f4f9b7bd3314e1d2696dff31c51883c4c750e00eae4b58047ce04e20d805a7a26282a302a325a4c435751a1992c27503d1aaea9d53aae826cdb7935c93a8d685863614ff6d49ad42df321550887c8574e7d48de1aabca32e56f170fd91be34f35683a13c6557faf9e3dc08544c1462a3e088e8aba084e8c35ba60b0ffec99194f68f4f25a102c1f6d23166f86318f734a3c34b3df0b5c29e20cecaf2b4453cd7469596115c8d7d499cfb3c0f97e8b0e92690f3cfad9a02a3aaefc590df69076ed6d8c0d9ccbaa5a1a53ea7e5efc3a567fb40db57b23bda632dcca04f8d43933d859b1a8d9456f0483c9d830051a98853fb29b1fac8d0736b7ad2b008324ca84c4955679d53a436a239cfffe6ad638a4fda27b797abd7621b7d539baab01c2de95dacf77133753e91c17dca8cd074d4e8e115c0c2460f1e81390fb0cdde338b54c894a5b387fad8e2eac96eb8a4737b7d53bbe17a74c790a2f2e4649428c3be227097f87808688b8ae8ead5506e7bb25f71053bf5017848a19ca7625ce8a342763a0d6cf0f7fb139439610905eb544ffb6ce93954d15fc7a675a00e462fc3ab2735f1f538b4a060258a59a994789e34add3308b3029131dc33f7246e78cac44d1c754b14dcfc5ba77d858d12ddb9b8dfeed2111c92dd9e569a430e00796b72496a51c2297b8a2e3a871ab9508f14038e92ea588183305037ccfd8900a78968fb021d7e5cd942d7423150dea1db33ceec2ee40616b11017eeade5c6beaef670e86faeb0e9a9acbb67b71f9ef24d2c18c5ffb1af43638733329128bb36c091a8e9b0e2af5a9fc30810b7ed1c95c006e14d6a3f43b87797a9d821f0c3c55aec78efa1edc274936ad5eec3a834f37cdde66480d9547069837f50c3386cdcbb1cefc778769d68e7f80e8b0962b1023443fb4ece4851e53e7190689a9280c03e04022c0867af26867bc17eec349319c6599f5ff0fd4361bd7b74dc24d5f2a0b4f5c94952b55203d3801cef6dac40fae72604ca60eb5a444266711844478d82809dfb896d4632042d5afd01fa1fc309545b392debba557d174a4d75b63b6e5d3f38a1a420f288f42807ef79cc38ad0b0aa8a631d15b1d7c40df8cc17bb19650ae8c3a05af4c59b80b56c8b570d41d98f607218cb8faaa87ac31b5139b46fa326979e36fee0206b1455846a67b0e6edb19a21a7c9a64e7ff0fbefa7dad0cc8195148749556ec680f3547d7f65a30f7ffe4f807d4261a295cb55a1bf9ad04523059133b06a5578f20a18de17ebfe9e2684781d7815c17326e11c5bd8e9cae49e8c374b836a66204bda110a55dbfbeb9c0f860896f559a7a888c86a5c4f3dd7c662e401387872570e875fa30ddf4b615ece187cf837507f35440e518c084be2049383ae8059d4fea83b4bee6e248ec0eb1505092a6aa5d3c4a9f7b823e2c517e5fef86c66f0fea76b21ea5eac6016a3e47561c78c9f91444c432d045990f2cddbeeadd6b6a42bed0fade305209d4dd37af9e7331ea7b12102b2e20f6597ac6712cdec84a5a5d4a659b5734e3006dba294fbbb836d6eac87b67c0075ea2c4c542ed9b698f29fd92ac47dcb0b22b570a09fd7311b859e0255d4a8bc3dfd1c44fc7f271e0cb3cbf685244637e18e1f6456dfa49e3acab02c202d3730996c115b4099900aeaa1b715bb2b329839e96f5509466a651897735bd6a315376107eafc99343da35381de5c2f13cb1c9e3a8aaecead4e271d96a24e7452c846fc7a416be228ac5b71f5397ed444965b3244b011041024b590f2cc7b061a1b763fb10f5597db90f4ffaa993692618ddcd3050ce859b66d6f462e37a90da7a5098ec891c955ea82a47742ab7d28b11bd467e6ef0d35c2040847a27db51ae1535ce0c59b237fc6418a53a203e07d1073bea271fe13bd872a5e6e467f80552706093f446f978789425292a22974053ec6bb2f98ab3ffec190c0069bf3d424c9ba57ad8c8a714e10c2ca59fb8e602cd29f457d5740cdf63533b229a40737fabf17156161e278951631705cbb7991a8cb52139f651e2cae02c9796a74c87be9ab5f387687c9e0d386269b1d85b9e4f439dca6a6dbdd19c51d5b3d7394503beebfaca28a8aca9bc2f15ea4fb777da304b27429dfd6b39a6d92da4eb987fccbfe81e9f69eeb53993d87847c79f8951c28c533b9a673a5522b5251e94b75dfcd019d0a555b25baeb1bae61d21a9540f3682773658e8bd9eeef4e66849a4b9c0534fa0d2ff03d7be7f6f988678c732d6bf8f6fec11655621c79841a2bde85f1f0e704ad941f9422bb54cae60b751506ef0400f3ba721bf11c69f8f5abd64aea11ad8e6a3b44786a1a840afc623aab826843b8284a73f3a804f4c6ac1f16d7b3370df4b1472c969b6b2e148a603bb0a0cb8c6c4daef80890454585cebb6ca6b07fa85567650d494e11f72b4838e247bb56aa4f915a635644861d8fb1a4612dc6f223b623789433f882c8181e96d4a873424b8d37af757904e43560d565b44a5b1875347ac3543636614ca4824dab9c49f01565c5df02b6ccc482c51918beb301384b281c8deb789671be7145d78628a21182a62fbc2b48b0e53f03600e86a0afbbe4b91d4da2c949b51752212b08a2069c5d8f155d9dd176b19b5b31df38a3639523b9de09ab7ca5abee1c2f8916923e5a5a64ca37980b8fcd4f3df64ddd937a606f19177cb7db06c89bf19429629d6967027cb54fba4a89aa1cdf428ac0b93719ec634610ce13a2827425d5385ba08fb653497e6eba3986f57f6580ef53168e432aabb25d7459b3fea3d0ade1cb6a73eaa7d4d022c2022b73537b99d3c8b306e00a32816d627b4182fdcc95fdd7ae4f36cbb20492b4c89eb09f849c4a6cfd8c6c62a9aa44fa7224eda67fff6504a73064eb9c99bcaa7f09cda77071c884b4c971bf754f4f8e7ec6b2a62d098913096d960f3ab997616a689761c94b41afaf3ff8760a2767b1c62b363038c6e78df1f7c017228b0b81b12a91badbf030a20a99c350d845360cc7a202f5b35dcec0abe7e04c050af469bdb224f2507dbf96430011509ed65f27506fb0bc06eba9a3fb1b1d585d5a6a0be6c160aca1270abb891e4b71b1e2302ac3e9c6b564c9e5e6917fbaf8452055119a9669f880649c1112f1a4fe6e085a0f277ab7289b766ff289090f97fe22414fed8024c20eea069e796ff1a3f28de946d6e03397b6c2dd574d6ca663b62c75728e9cfc5bb70c9599b13d5b2011bcb841904a7f3309066ad64531c1cbcd61ceaa09b753829a8b546e22748b685c3034d0c07b539851c769cfb90680564a2d944e2fd6c186075a6f7280e05e933fff00ae04da2a79ae04454560276ad6e2f15c6d3b77a98e10176e93b7f990d5df9bad35da5d3303e2689323dce6dd40782d0eaf2fa2ebf5927480730d721cd9a742bb5f71da880fb029039eadfb654331688afd929adca6f15549a69e68a3634a97e79bd5f269f54501f904476dc4d6af489415f018c29cf59af4618122e090c21eea39eac6fce9d4d1b1dd5bca876fcfab66298454bd65d10d41d48d222379ac810f745b66db501b4602b38622171e25713c6e845b99d9894680cf9193fd06c5204e9671499b74e417401bf1348fe219068039591559b44aece0f68dbc8c9ad1409fff9ace7311f4a999d2f7e93615a795fd5fa052de945d78e4e8009397d31a22e326300ebf59301c29f4957c0fc676689043eea55c550c8ed7b13977d2346cec22bc75c798a846d7867cb05c8da75ce1037733264aa0bed41a5b8c4d0fdbafc10c683d256130692d6e711ad739fb673dd9decbb7e2e3bee456bce8b11db5e8644c1c6b0c8c71dc628fe9b00910f217ca9b0a67117b4f27e899b5e256a0b40b122f6452f26d5bfa2bebc92e29dcd44172f50665bcd0e4ee86237582fef4a7ed729eb4a6d2bd38ea9a166b2c01c67ec572132b91e1ea8919c8537812e46905563bbb40109fd32d5eb3d74ca2eb289252e04f135c3d1477e008ec65ee3fbe0cb03e9f10838b5e507a72efef1775e4059affa3d3cd78bd94f16518e8b22684f581cb129268295b281103746348c288f0e904989ff638892ddca22952fde2cc8cee6dcc4b3601f22e7c27f1f7835bb5cf3112af224469f2013489ef5668870a0041da68d96e461ca3741505371e6cbe1b27fe4147fb98ec1c35fdf28db24d7189a8c1afa53dc13e5f147c5f6963a7fc7f55a785aa292b3af8570536fdb53dd1d29f77e2094a0350845a81b92685e6f09b4ca5c6aa36cfc54d15fe3086ae023b104f510c3c58202173a4b66052e8b1cc77de3253112998655b1ee6df9d81220c3d0e271529591fc04be55a8846ed23bd86d8dd6f391a629006e82f24947a80e2a8d172bb21f93298a1c12cdf6c87ea08bbc65278249e77e2014d5fe99addb9513b512394ddd49a5afac328348e072666a3c57dd8787587dd805fc5bb6c8d6f0d1e499b1453fe36e6f7716af9c074200f046ade96016dcc8502bcc924b8a98d9cb878e64691d9463a3d64d8564ea488cdf44770f03d261bc9a74b4f0b38e29a93b506d4b24893ad692c5514f9a1f50b77a315e8544847830cd520e1c919a2df5121d354a1463c582ed990b7512603d8870ef3520afc5cc79a93f2e77d089dc5e66c35081121254fe57d4f8eea74a7c1e161123163aaf1277690c77620ee672e493cbe09d6cc2e8e5c6781077085daa3ba4000171e6fe7428a16ee0775448a49c0fa2e412c7512ee99f3f9e74cecec15d4ff522cf9314472fd638f5ad7fcfc0dca463e08fe32107d3413a46d9bc398ffd3a2bc7a041b4f548f3b0777d0a31371d0eacf6e8026d513339db2d2ea4f8fb9dd326343fa5c522ee6842bafc6eba46ec970fb79833342a9b984d3864a8879036914ae5b3e95a3fea50b82ff75441634cce77bc80120706bf1c8e3386fc28e24e01d8fdadd82c89b8a9dd00d3730ee588d92017965a007cd828529e39ad9b4dc4ef7c0190de638c43652f793a254a540a205d3ceff6549ef7514052ef8183d3be44dd915b4e93d043b8eef572273e8057ebe4403f5d0a2c0089d6a4aa87e93f8333d1ac8f53585f6f7709e4717fea801ba8c9a8d74840cc9b500ae4d85318f56885fb5be4ca8e630abcb0a82b3988699e8059f139a48304d7dd4b006d60def002a6b92b6d7edc0fa30b3cb1d2ef68a7be5e294b49172e7fd1f8851825140a29a2f364eddfd776a9e288ffa50d34477efef9f614cf6d2471d52da1c4b538e4b7986752971fbeada2194bfdceb60d68e4fd63a5b44733a4f559009a80dcacbd4c98cf07acf4d16b8c76ccd9ab774af1e4c76782b7ff9c4bb856f1208dcedc0ab16b210bb46f69bb79ba3320485dbf5f878922b797c339a932cfbdc9f717cdb4c9c5d3afa0091e107bc46204887239483e11075c23f4f1872da5208e34ce6035c68d3b28af48550819b602e271ae09e99f794972797d94908deff0a33a925138491f7cd3debc50f38bef2dc0e4ffc14c2e8e0512de35e02e2073c85d08a1cd57d24e748c76ea49610d243502e42abeda75e138709969921618030025c3a0c4aa93434b2dcdcaeb6554e48af63d1e4074c2203061f934b31060c4391dc726e6f8d820164eb7b38939bd233f3b925236d1b95de8839329a8c4b1be02a4f78bf940ad6441d4caba6662ad69790ad3c4d4a8d9a8ab3cfbc1e07cf9f700a7e3a174c1a036f2b88de6db60904174679a9b046754507144826a05b8f9c50b0a55088c9987d6803925d67d447fc3bcfc97f1fb0ce6260792774e8b99d8783b1e47448217fad9f002a0b74ceeef3a5a552f0b2e5a869c5a478000fa3703449325b38d1620a21892a3fd97e216c0467b5519b6f04a543dd2bed34fd1708ad21bd0418e2c3a500ed14997b421f65ad71d419a3836e3cea9f56dc38e6902491e20be12c57e0ad8ed75214a8c4f33e4f0b846774f82b8c4b12394ce71fdbb303ef720cd8070885a788753e6bfb7d10a71f3a4f25676f6eb81bd11a6803ded2bd0261c889b463b2c51da96c581c06fab9c42799f79be5747c18441ea099906d0ebcf7262cde2c9e6716f44463980c563e27363dc97016a3e5d1afa84b188f82baf0ede3c9881e1ff6ec99c91f8cdae90d9ee4d1d8f2d918616f4900feae018df5298eab287a5391724f4556b00171d27fd438aae95fc8400b795417dd2d2ad6f29477095d64bd78d6a2100a1a6f9120f4de9bd70af575957cd6cd1aa2639f7bf1b38174e39eae2d56c1cc08ee59a499cac9b5ffabe406ee007db1778f0bfd56d7ef3df8875561975066898e1eb188f8731dd629234aaee7ba01ea8d8c7ba4212a02088d0bac266b9a6a816de143e222f724da6a78ce38900e6114c786fef26965e1b7ad68249847778aef0e7d9ec28ac0593e85bea7de7557e4abf998a86aad4e1231a20facd6939b9dc8a0573e457850a07c5f7a0cfb20e46297fe0afdd9510789f0752a9e2431313307100ae5694c0d04eca28aa7688b38019c321e33208cf015a57b807665149c3a89c7a02e388d7b98db6dc72071cc5d58910c2eb166fd5929759f948ff895c266b8be469ba81d2268f63a38a21e0fab9c4b4493cb592279c1b99da3a4432414c6d3b0d2cf1104bfca0a0bd1baf8874efadd61544524fef80a2f7808f7acd844ff4141eab0ffc13edf5c3327b20bfb265dea95896a31654fd4b700494384976e1e3b5d109145e40aec9ec5152e6505f6f541f01949b08d71640fc46a7d6b1f0d74b8874d963ce21ee181a3a7426c8b49d1927ce21bda8937830ac81333bc8e00b0e72b8bcc1217f25efc8f6bf5ca420d63a3df341d6579a4149b2d59fede8329ad32efea575980cad10384cb809fa459c0946ebf299c84dd19a69925915a3c242206e638e8c17a2a78587b5b585e97e207ceed42f261867b362f96bf0c74443b394ff4afa93c3ed179b065128b54f3e002bb88d36ab30fae5309c532c3d5b987cc1e85571cf2cf53da6d339d984688394e07c6ed7958792a4fa11bd4927c5ac98f4002572660db6c3c754d22924c84949fa02227e53cc70aa25e23649f777f9dbeed9fe05fec83230d439f0424e187f78d2ce9df73171f4d859b806fe1079851d946e0cb8390c7bb02a5adf94c9ec36b495c1184ceaeb066f03e3fe186b77a5043dbf028699a59fdb385383ff0b9b85f643ea53eec870ade3d3fec3e6d42a2ab7964fc085fe94bb5213eb0647877313298bb784a0992cb0a1e9b8660efb5906c81b7d7cdd80451278d1b56592132ae92d1400ba5679486209b923163a0bc2e7b473b2cfaa3b6d4f61676d365aa1bb959653b49844a0ad6d746660b25251b2bcd46d1fbb4690d247677f2d613f31fd1bf808f79464a432edf1fecc33bd201a3ea4eb0fee2745b3f752fd6337941edc7dace69610d2347d26c28e78400669f2a79745b09e3c4bf54aad93bd186a30b87bf8fe68b6106efc9f5a701b3b66696103f1526f7c58b8213e6da00319f0af0f0295797df420a39b3593d56bdcff31da9d1bc25f411163d3c97e6bf482c455be33b8c293a2ccf8fe004192144f57a705113e61ec62f6828afbd9a11891aea8d94e7904e4a31f5f9a85d236e790de17d2183788854306edf7f9e3703b9464a411c0f19d6d709d301a3af94637d4a549eb5c355e5857badebef057b668413aa6963851586def48bea518d0849284e40e98f2ef058e79ea34799cde554eb8c5a20b0f4b0124f4f60f52ba76093cd4574e023493e924585e48f0c401af1a6c8ea932ad53800c4f30d9d98c76b5523805247903c7950826762d0af5585e775447c08d764f0f0a0f9707d716c5c4e9b6d86dcee92827cbd407697ae201355a988330eae6078be99b9baf99ac7ea863cef4f9720ca497b2d8b12f7d79e23be46791a13c04e66a0afc9281ad7c9827d2fd329b281682932f2e5dc5f6cbe382100a5895c4a1951ebf6537bb1e62f26d4ae439f0f2b6c776e674db6971af3f2aa976d4a1cb09b78c91308d80557f6b07a8258962e7d7908098682d7b0e780d6d26df61b20fcdc8e4e1668b1b2a54cc1660eb1674f96a05cf982b544cc00b44a812efbe519d1a891f2c5b431766aa7b45cb28381b95704c0e068116d03c77285d00c0405638964d0444b9e64cb03d0d43944f5200fba9fc651ee54275a87a423234f41300073433a1cacb9d511ccd3bc910fcebbafa711bf211578a5ef65fb82eb807fd807ce8f7dbed006e04fb77eddbb3dbdce8dc357e4950a1d3dc01c4009aedb6066c88e1558e70405eb1b197466d538449e8afe892f4fda8cf3193768400568bf5f40433403c70b6625b1acdf564b8c0e9839aa2a37af5f3c24482c6bf49be12566a807d2dc512bce1571b9329e13140cfe708dedb24ae770d2a689a4571d62570f8593b4e9d60e57fa1c3f52df4d56fec1729138469a5c9ee5af9c23f7ace81bd314d85b8cb4a20f50fbe4576ca9890c45aeb21791a70ac81eecc01cd55ad35eb894e8ccefa9d9e8f932683891bf2a23859ea45c1f68299ea10fac56976c191d16e599d0542eeceefe17aaff2e1c1857492a5e19361985c5c1e9d46a08f4c6decbca0c18fb429dc38053021bb597395f327eb50b9b05f31dbcca5f8506349ff0363f2b4c2554116857bde1b1a53c799d4b81ac7f7d3c91689209ffa83595ed3d0615b697c652ca53bbb230687800154811b95fa3b70e5eb25a8fb9442385857d56ea77645776284d245d6a8ebda1ae5318998b0c5add75c1a0ed0351afda46dcc5cb16d8fdcbf484eb7613f63a6d0b3ab4969392ad2ed8d4354d0512ec4da911e2b2ac6b787d26695bf95fd0ce8e9653917565ffe3c8ca3b76b93927d5633a46a90ba4e97ff1154fe596905a1c3e7602e3439025cc2f9bfb1ed530b8c28092a0a9ced2c898fc8f504cb52c33d7e634680c3049e31a7e98a53d3bdc38787acf2ca54f8e2cc36d92d1d59e35901839fcf8e59e3e08f022fa3750bad40720ecb2a315dae1c7eb6636ed9924b70796ffc3a5c93a946c31a663a2918073f92ed4aba6b299b36b1661637a075f322b64b9abdd04150ba6a6892a28fbb21ba14b966bf9b6e0b45307ebf5fef20e78c0753b57cceeca4f219f87db888a180bf36b36f00d78ea3d6111390cdf2d2543efec9fb7c352cfad12f38d1674d568b89abd4d58a0384c653dac0d56bdeaf4a9dcfdf6753dbda01e71d8552feedccff603c9004c9adda7b5d7ec956b6e03f4edc24939c526c72c32df5d2c641d07d447c2e7953d11f355411ce455d0051651139ffde18b51e60f81f61571aec2fd14418f3d3a74066ead2f693138ccdb461cc971df184fa113637657dbebfd2918a007cee8f34ef10f7c89cef0ceefd8c7df4cdddcb9cfa459f24958eabdd8547cabfde409ab84ba61638197af0550ef24c68f35c448c16dd336823205cc79595a02b347b502a343110100a31f3bb9ffeb2ad6bc49b30d7ce09fe376976368519e2a71d7c5bd002c0f34a1cbd3b01a35a5320b603838f81a1e6d00e2baabdcfc7d4cccbebffdc090b147bf5171e89d92ca6475f3818e5259419d8e22fc59a498ea6d6631bac2ac8ce28cbc7f0454693359d8a5425bc160160fd1c8928883b37764005269b6b9aab7e9698aa7939a2d3d9f2f88f5b3a61cf603603e7a3c28be36aa7f7312c8d0452e81486fcd24208ae8f6a44701267cf4365942b380d4a59f030a0263d3ada696d6d977a105f8d70fc5803995e12ab16b2505e7bf0fed2f2f8a413eb8405a638d7df3e7a549bef5a7e8f56e3b3892a9f1ae91efefe1a1cd3457f9464fef732708f5084e52dc821696929f29e513cb567c5369a2a9443634a3951f045af614c29771bd2527c82c5c386e46368b4bdd79d367aff78b79ec7c46bd00c749ca2f9835ad8c66b8f4cca8a87189773b61b11cda9bba8158b83a2a655fbd2e67f9efa9a38c516158e3ab2d8c3ba1e3ecf172015a16ae4a839aad9dcfca7a64e2281a222f2666d78b0d274677e34f84c8f8643d6610e16bab3b3ec700ce7c27cbb29cc9c455a69a93b27f1861e82423f79443d7f933546754ecc0cd937d93cba14c515300eef2e209b7dc275a9341296500eb67382c692d9286f9170c8902c946764fa55f1b806d958dd9e1aa007e829dadde457b6676a6bdf1b982faca5853aa5177238824a5b2a0a0417cb9d36dfa112a1610e885a1515199e06a84e26313cad9463d032dcf59f38920161a6cbd2885e87c6a435e3cc893324501f1d9e74bc7988ccb5a16e5796c4534b1fca7c8c1f1a35175372d8397ee3374f843948aa983f60a2d6450a9008a0d4e6aed403326180e893e6756eba22181ba656997bacc91aedf1a75c041ce828aee6de2eab3d7d68f62dbe00fca65b09f02dbfebe5dc2bc1cc931b181b7e444427430a793ce3ce242216216142b4f83c2f94464dbb37084f191d5a392bf9e96ecae5a4e6bca2467ea6ca35a28ffdb03b04c40443bb2a9fdfec1771cac1c105c5846e8de62b425e638f1cca1891d76940b9551fa5f75c0e87cc6cd2f0d204f75aaf4f78bd3e3a2daf0095b7f437491fecce220fbec4eaea3d6fe242a498ac586dfc57a17f1a9f7db18b1a8bd6b53aaf8c607d8638db7f33b28ccbd9bc1cf61a7f9de5ce7ebb5ad13177f72e755fdd981e2d1db0cdbe606f89c27eaeaa265341b068bd454154c0d089a29b2c18e1e4fa2835ab8ab1139e9874cd88fd6e8565ab4271e73d80da8b8767633ac898e1b1c09d57ca97f1d2fd234c09e6904506ebcc1b53f5b4e26f7526db70a9ffbfe0c0d9879b934d4fb4cf348fa23bae4e8f3803ad387d99c349fd2353f8eee6575b9a30d12f0188b236763528594391bdbcdf386f73caf1005976430201bc95c14681c6ca51606d077ed601d0c3e8069d288adda9666eb72ab3cf4fbbe94a42c14eca394c287974cb37f4ddadfb9144e06c02ff3297549bdf6900c5d96d55a34c22fc1a32e33c7750e773bab6fa5ddca28ad96a292ef4bd0713390ac0a02355473ff5cd4e5dd3de491869a3fbde05f246f8ae1e3d43edee4e8dbbf2d18227f3c662ed89454241573f4a164892d1a04e21f0ca5e68def6f77fabb974cf6521efca4aecb1b92e61d584f2487716d155444a42656aa76fa9613b73e01208cb9ea20ee5eaf5e85fd12de1bbf860a9dc5b8dca4aef6cad7a9344e9bf2c2aab352467e9ea08098775a4513bf6ee21afd7e3730bc1f575909c4ba5e22cb37192ce5802828808e915e903fe5322a1a3539423dcc0c73fb91f56732308685f942c534eb94a58003097ed6dfbe1405a784fdf4e548624588c728a22d690b8f8fa488655e291a88f1a026e41b8a2c8bca8564f2be88b7e811e6ec9f0df54020687713946081c5c520666b8b9660a103dd575266181027e3e1b4785f6f86d9337fc35169134f96f2727b0927138ce59c4746890e653d9f3f41b72b565f26bc9be813ab0b063b28aa7a97f0017393366d2c1f66fc4a3500ebdca9811981b1c8754290f8400fd1cb50553cef3aeb96ef7c53fb2c00ab326a0e9c839c5066f3d4045b76636238f532e08d1a03872efde8fd3b6e391ff7c8fe534e79d18995c6736796305c31e64c0631b8b9d351559c4564243d3f182f85f78b104c31ea910ae0751aca24d6507a2c7d1337397e115b847d31e6cab5125817a3f2aaa1dbdd7e0ddec7b26e08bc6d97da8cddb876bd01cbc12b1f75aebe9022d6961a5c8182678107752c3a7a4ed3ec3a3ba0d31b529a125c305795dc861abd55475cc869d60c275da2358edae60d0a3c7b34b725fb5268a5f2bef20a35fa45879aa631998e7930e5df8eea775f5e68385061e01119fab7261cb1f46446870f163585f20266f45328bf750cc50715d615789474d67b4724dac19d665937eb567e6235e1c9130b3a86ec958c6a58ee679258c3bd828b506d026df9c5c02f8c95a73f8b9813a69329c9ef494f1d947528f26a344b072d2eea9d8b6359adbf1c9bdc017685b04d063193a3f53413944026e0bd99a2d8c43c48afc0da026777596fa47c0ff708dc8f1f8d3df291d1b4478038250668cd72f8a2e79c58d17182aa7243e5adcc8947e8a62304d4e25cb3d00e211045bf9d9da786ff9853a9d5235adc9b1daf2539c3365f982d5866ea0cbb309aa2822735767259166f84fae5b7d8c96ff54787f428e1a0793376687f6815ce16824589c1d6437a3c0f86deb2b8e737cdfab8b6a06939eb7928d359a18d7e76ea99467462135183a24a003e4bc9e4dee7cd8384f13575a608d81cd7ac25de0f2722b81e0c984f084c0b377210558f6e3040e3ddc28080055a5bc4d99c0e6f17347f78481e67a58634cc9947e19e6006527aa04cc6f04b38f30b7cf68555b4c7022b6df07bfdcaf2667aa8b8eac8e85d5bc0d8057a7534548941617648cd2390c945933998c1e65be859330268f98d7105227639bef14b67d66308593d8382587e5669efcecdf6d61c879394608e7d3f1721ae3ce5b72359201ff98a026b7e497e1a051132fb965133264db5ff22602899bcb60ea6af77b3ac0e7791d2101f046772a02dab2deee40eec3c15945f7082fed096a6fae1d85897a81644369cd9fc6c072c810fc1d65726a28cc08e8220c68e65a8cde171b7de79fee3f7d6d786d945ae3658139b3222cd0f0600aaf1b18c6d22ed9ea82adb76a54b8a5d3a9b4f04dbf89858fb3b6f68314335e2250244806432acfe715f654b11bee69dc073e99fba011fe0c8f7d9fc23197f57f01c8cd9a557aec3a557d3e4d72350d440d807d7c885e206f1924bca12fcccef6560c33e6b9332ac3e70609436e3fa147b3de2b95979941d55f8a0d8e71545b4fd48d3a40ce01f7f5d6df20c6a94ed7e43ada761c4ec257b8e0d9d4b232917bc0c68627b6daca8ff410b04f743b51c89bed0fdc160a58ae1f760a9247836ab48d45211f7c77471e4442ca0795b882ccb33bbc4bf350ab7cb97e6cb65ce76e7c7bf26d6826f109413957e2fadb10dcdde1d53e9695730822d72be4c9c3c3fb863d60cbcb3f2ce9403f3a8022230ce26a83b00e8f58d061ec0e9b73176c732455faa74fee7aab0cbd068bacd94023d8fe2052e8e662c4c8f9a619350ccbee0947d02e0fc93324adafce4fa7a7885e8a7fd1777719716fbf619670409e854d4e54f8d446f8d0eb682ef6bd5ba3ba68905f50a53a2b55f03bb11b38039aaf1484a0ecedeea63fb14630876493ed99ddbf00901271870a485818066478b3f74eb4c30d051706d01ada2f88d55f5d425c32f2e5c358bc65e944c183df2e196bf48391247c0d68ef8478bce81b92f9146a664eabfafab6f313a79abf13201f1b1857299f3ae6a3fc20db9da9672cf445cdd844378532419b61fab028d354ee6e3090ad0b050a0878bffecc61b2336550cd78a7b3ea7e02ebda811f9e5e7993f268a5c224deed89ce042a88e586b5e4d45bf4c835d32508551007e6277e01d516d152b1c1571d698f8618ef505d5cbe541d51c936e1810a02c64afbab9102851d884734c9fd9669f62f3168d2b197b7a20f9d017d46d7fd57eae7de4314b588ea0f896271619e88e68098cd56589758caa311d3f01316b09ed03afac4e05ed52edd1f820b815c551a259f7102b83b1b3df50a13927385642a42e8fb55cb090b702880ad4a005ae6c4102a418f26013555554ac1e93c53b6b8eb990f7a99ad204bb5f67217bd6db8811f687d2de05e45eb7222f7e72387cc70bcf3332f12076bd42baf91d368398d82d5d728b31df659114a31a34938c4597e4c6b7bb34ddf8bffa1f1ce5ffd84239f28d0d0e81d59d0b63bbced7dcd976d790b1830befd0101998e960a9dbadab27aedab5e1ca38062dc3b5e25e7c9ada1611b65891be20735bd7a9ae7b43629dc8ebcd24492a53b74bdd82e314848cd5fb43b3a5ae89bdbfbd92cf67c072904c227328065555d98ea263a90e798f6e6618dc7bf11b09727f2a76e234181a7722911951a45dc4df4bf52149fcac97fdc0d1d9b55b310b9e6d44e3216f7eac5ae46a998c2f8947a2c63a22c4aacde07754321886857534fdd54b3690ac722321bc52b63f605428759c490f5dcd7642d0ff545b99bf6c5fb6757afd71afac31345bb0a2f7b6449c19c0076643b1fa4d715e84844655b763d32d5e671e2ef9bc3855783b7c1663bbb423e18e61b1edcbd29a9b2e10856c7dfde007ecb064165a1a119eee3223db6ead9587e096a8a3b5388ae64b143f3ca13054985026b0d3c0fcae38d09a8b23c5cdd8d179a7960f278c31dd269cc6a88c331ecf7e8d353d6031bf83098be6020cc85b08914f78b392e5e589edefb0793dfadad19116b813f3fbb12ea78da7d246ee34cdc05e4e49a9a883203711c2cce8911dc1020cd92c65b4bcebcc408c58fe1e404839d1675f89ecfd58e5b2c589af6b4d7e0041d33135e8cafa9e2c27d4263f1b61b01ce417de38907660b6a0c7c98e02e53b23f9884d7887386e6675b41f2527393ac271d333eaebb7d838be7f9d4affa8abbc3e3cc51ed8db7f6fb53bcccb3a956849126776930ec1c7e79334748b11139659a414c72de2048a094dde5f88a7066f72c911f8a23cd8e3c7b536d62840071f145651fecac63ded50b5ea0c730125a2d9e8693d5d5bae2315b72b16ab0ebb09fdc67fd191e01a4d098e5f01f6523df3474733a73fe9e1dca803bc639ef7854ab12db2fb66b8df1e4653f518b1a07f88e387378389d8bfe87e9890441eb286ba2e31f07e57b35a4de9e8f25742480f60b2232084dd5b90780fff6a1b6ffc9f9443d13ed3c1947aff64afcb4ad8cda6ee5ea2fe141dbd1ceced1a53d333eb92fddbbc1f63610d95a306030b844b1fde4bc951e7b52978e48d948a5493453158d1bab1991ed18a9d6af47b45113d2f8287fd3ea4c9be9895cee6dde9643e7eca034c56f91d839392eb04b73c7a70970d1865facadc14930ccc53f395cd6ff41d5c4ae5990df8184f9bd66e6f7160cb5a2eab192702af1bcae28c8075386f6575b1f2c7c1e994318e2103707a5894cbce788fa415d8c28c014ae15343c0cb9dda0f8086f9a96744665a74b4c37831ca96686ecb82c660ed5e884da5e78f38a2101c5c9ba9d6e7f043c776acbc604b0435448dce420fe9cb7c1b05816144c8deec6ca950d5c36574cd863892498f642217be646eb41049713c55c75e2597e6f147d6807542a0405c38a5a2b34912d898650a24df80ad326fe28926a7952ff2a0d19737690b22ea6ba6aa55e2540f85539b65b7614fdb714563760baee04f0bf0a096c5ee315798bd24143832159bddb23f227720284b5300bf90e6917ed4a938a4a877e8aea479dd5dd87a804a8f854a7291bc550c0c9f990fa5edc05d6a3a729663ff312ae78725ece9fb579cee689db616fd6bd6d563e5dca1e78230e9553ad169c4476cdb574f16f480f8b153aef04729c1c9a86cd6211efc28973bbd94be45f6a2260cc5732059f8ed81dcc94fa6aec5efd29d3b92b22933d06c77187a359f8290f31785bf5c3aca3bc962b6d593a04051512847cfd10d2d348e70d9307526b24530d518ce67a0060e86be328f5b966ae48542af9e9b8be190e0613391549372c0238de6552985e239aea182ed5d4ff2fe541d8d8b985054c5e0ed85168a2685f66080f5a37f3eccdceda2f8c4b232741bda97797699d57bdb8bf9e45a7586b5321a96653bf212f427e77622db5c9885349e42445147a4d2595363f5abb39dcd212f1ee0bca504e6b4afd484f4d6d3cf98cce9f20aebccfcfa3cf6d0088b2c7761757af30bdf5d0759f1c9a7c1bcb54cbdfb8eecfba53139b6afcad6114e8dc489cb80cb5edb97a6a4d9004eb5753465a323aaef543f49e8397e99d28d02e773c78dbd5d511a978bc8aad6fb60ce934577ff4d81b3dd68d63495434fd04441dd5ebe02c01d01e2ce2431be2962dc55f87e9007d4f86916c1efb9237cd51ba2914bef840fa2870d46ab29ff31108d010f0fa3683632352b85a32b397a91a15eb063e4998238923d88668474bc3e4a9988fe09c8a8d075dc75951937efd46112446f5ab4bb6b211ddab7e041d4074dc6f058b9c76c9ce735f50ba33ed6545ee9d3c256ee8ed9493e504f30c4f10a6bdb54097724617f67695359cce33a4590058d4df1122f5fa4041bd8b1f3547912d2249b1b2098d27ff8d405ba35dcda31f6085fe8e2da1eb9c4289d3d53e3a7d77968205bb7bdde2dccfaf683e600f86ca6e33f9714688621619b2c8e28ba35108e819676dc561c8e90b257f1682ee93dcec76813f544920ca97ac1b492d4af19896ac9c6188424fefa36c57b8370f064e81e427a90ebfc76d30edb138628e8138005054d620c1a785db05094089220f968985dd9ca01be253069dd69da2c1e5d5e31e5a0f41945a70d6585ab079b872c4f47ed7c9323991f3558f9aa2ce89648472e3efc9dae7fc98a79cd88b55890f9f5a685e222c2efc6289491f552a855d547783a2caf99e621e50c6594e6667462e18f5a04d1a0245cbc37ba67c2f6fba42b89f30298f24c895e15c0981404c43d2e24d3c0c617a071e47be48a9270190cbfac41fa227407e00f225378baa10755fbbeb3346431612b7e64cd4459f9e1c27b79539a94bd42c825813f8406083293b305211f63b03293f3643ad307d9fe2794e84100f021efd1c6594303826c5b17e8166a5ab8374e24836213a7657969dc406e95c99e7220dee71991091a04f74787a627f8a99b8ff001fa473c1aece43dff889e82800e7cbe59e251b7330bb4823d22fee84fc04ab40a61a82b89b33d4c96e1364f8fcab1f4559dbca0fffe13ec78e36a4f0ab70c72ed06d6b724b02b991fc930a6c83b8ae1c5d4202f5643508aa6f3ee13de9b00af807b67d91397ba89839913b53291ba41023aa7b756ad76551dc09f59c9f6474fe36b8e8a69ca93c14e560b16df6454689c096e8a598bfd025c9581e730f7f3a5331cd6a5562cf4a6b0ec289ac3b9e6dccddb32a6cd33ef278345c02d22eaae9b2a065db7503eb08598e59d5b9411a06700b546a47fcd974ef39941ed2c4589989f34c48c9424157fc10dee1eb2b491d756613e2769c689a37d79490e20fa8df63edc92ae005615f73bd0ef1de7101720787819c717c2648d925be719af6daab7a57481ed55dce5f0f0fb128d84b02a254b148cb1faf31cd85ad638bd8337d31a80a234e3e3704298b601e473e74efe90536239a8a732ea5a5c9d6889892ccba5efaa23b24f300c2bd50174113603b2fe5d4495df0e70c66233784187e50716278272c71bdb5d3a0e93fb28b5ab3cd41f4d6d53b5bdc48a7ac53ca75bcd747c468c0618c709e929c7a4dea3e57012ed560edaf4ba7308091ad19d8761f7953e7943d253ae066ed0eaafae0aeb0437ea6e8e1c8763a7252924f6ed4ccf62005b85b571d6f2075abe22c12fb383d53cfc401a7bc589b93222b2604df0a45854cdcc73a43b7f192d6cd86eac70811606850a0a5ffd0968cfa8fea3eaf36f21fd193779f0cea6ccc60e5d4b1f489aaba1195d76688ebcb7b1f202f712e540ade44367fe5eea55bce6ebe2fe0a3567b64f8363035202818e10e5cdf7b5a0e016d7b78a88206fff5a494b57cbd719e60159db2b30a8c807b38a4acb925aed191e35d1e9da77b18de98004549120b147f3c7b445d39946629b470070d98ee8c6e59f8283de79a1f517f4d0df3f65ca9921c0ca5f882ebd8bb8250e104a1fd656096b706e6b634c88d3ef8a55befbacec0f94b21c392afea47b67a861afa0656d48a9c44a2867d2972fb2231ce6aeb585d69e4ae3e5c587a42e22c2b0637eda545e02203b748d1db8b1de0071de9f480d1cf7bc91a56b00a7719de419452a202d141738394c05e721a7a107f543b344a81a422a96605dd800ae458ac2097a170d83cf90121c280da0e20a20a09170824856653eeb3613224bf3a2abf7e595d02b767b112fd407a1ad901632a129215633d9b6413779d08d91646ba7234a3c1a1c8645a538b4ec9d75e3d21b50643d23bbf14beec96f8c06d8f46489478d36fd435cf3d7327ee6db85b7b01f75e5dcdee69173b4db2c7a3b7e0e88f5e01f68300c636f2843cccd7a7bdd93af9df34c2992a818414d4cffcfa5bff1997f7befc6990e4f21a707c96c33f66899143e32c08e71f107fee5a2f199224617ddea2df9eaa7c564ff99ac2786e854081a276d08a841f73edc1b95ac36d2d281747f7d20b1dd1ee3256e6297de8262b0e8bd2fc79b5fa9e1776f7b919465408fb7e283770b8b377c41ec91e55fd0b84a0e42479e1d2f9c48ec1e346325a2d58efe316b19146253acbcb2c6afa6822dfa9b3c8e38f1b09b16eeac00a5a570457aad56817a0f44278568157cad9ac02c74ba4a03000824f53b285ba05daa63412f1553be98ea1ef88cfae2c0ef9ee34c78f8d12f2ffcd048981f6f3dab14345fa24c2a26a49218a5ce7bb4b5dea5d0b1bba704aa4c7d9eae0286a568792d7f7c870eebdb75b15d15903840a248670df3e015cf73cdbef6cac5f0d93db8af9d98a4e27c74cc0f4ae3008124973b871facb2c212076f65d2ef09e22349e4a2629882745f9eae685ba8ac0ac31298a465b2e57b9a852e268b7b3c978979b0766fccfa939bb5743a19c76100d91380aaeab23a1442415c942f900ddc7b3bc28f65489454ad794884e90e8501efbcdaea7176d06132a1066c700de93da6d40d87856fe1c46a9e7b4c885c64ca40327cac73cde8477e925a4d381febc57f46da8b05ba90020ada28489341460a497fe4fdec3fd2e56fef05a779118f5f36a826b196d63b8009198f352bb9707816f58706329d3ccacfdca87268e97e6b71aad8e945cf361614aa3c1dfd78dd79d8fd8aa1fad027eb45074044671f4726a70e802f874fdeb72b3c7d2989d963d7c56070d9d043bf2c491240fdda87ae6b2c2527b92e7beb321d7d8916dfb121cd07577b98b457e1f6a816faf4b135f362f8bc6212071514c8c36d0e4cb8c48f8730b1aea542c47576fbf184973a37f9c31e17732ecc28ee6099793e91642036734fcc3c94380cdbfd78378220c65a4e8019ca428b794800cdba26e3733f56cdeea7f2564ad307a452acccdba838fd285148e2bd0d51c769c4b018719f16d69fc58cfcada04472e4790e87cb8bb13cb3b13fdc56768ad7624b4a7c654a4a479a1874f7c1632c659de99bd153e6795671aa1360f8a5531dffa1a0275ca796fa12f3255cd978a67fb627b035f0750e011174f3b217010b5b9a2aefd2a4645dbb496e79d334bc8b44223dd15e6d29fc8a5c7b05215cfea2fd1bf733faa6c487a8bb96e6c474e2a494235a9c9dfcbd43ef31df2de56626994d2043f589bbbbd452c9125b68fd95cb608a4fb42407f41c6e7af1448686134e5b7c49076e7399627c60bb6c3d96cd0007ef508bf8cb7c53c82fe033532e0d999d74966e0060b540e4157b5d660362eeab7313a0ad7e42c3bc03055629bb5b8665ad43da4e0d78417ae7698651f1856500000132030000000000000000000000000000000000000000000000000000000000fc5bb5e5f90742b376b3547c788b039f47b7f252634179e06c1b164f022327ad9d662b472fa56cc3b28e049b6fbe17e6b2cd74ada103bc6db97b8ea71568908395cb608a4fb42407f41c6e7af1448686134e5b7c49076e7399627c60bb6c3d96cd0007ef508bf8cb7c53c82fe033532e0d999d74966e0060b540e4157b5d660362eeab7313a0ad7e42c3bc03055629bb5b8665ad43da4e0d78417ae7698651f1ffffffffffffffffffffffffffffffffffff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81a2394adee74ac4684f0dff883ba1a3b1b630481c8bd1fcac7bc61d8961e1e052f9f668dcb8f8d3a4dc699e9e21f1a41414e87da01657f041bd6a75555a4c0cf3a9fb1f6e6c74944106c5c8d542ad60adc278871ae0685d23a92d205ee38f89754066000000000074406600000000005c4903000000000043310bcc60d3984e1f7693fc34703107aea381ec7bb96d150ef8dd0ca0b5a82aa9f53bc14c3856e1582b43bd5b5cdf2d3288430947f5a0ebad33164f168e7ee5bc32d027528e36df39bb013f3c7f9e4a5e9e9fde8420a2df711cd12dbd467c3af4000000b56999808951e6516d332f55c208079bd1cfe840228e6d7d216f7b79968b737b336488033fe5f3ef4ccc12af07b9370b92e553e35ecb4a337a1b1c0e4afe1e0edb56114e00fdd4c1f85c892bf35ac9a89289aaecb1ebd0a96cde606a748b5d71d8fd70a4b183a6d05c9a4a0182088c66342258342e068261979099a44a19a3cae6d8fcf00582bac42a5ed88033e9178b85e3610d7d513ffec3790bad7f4b9770b69f8e3f4a4eef5d929de86653ab9768af093a347d0ff52abdf73d76673ce3d63903956f9593c200258d2eab75ac5349a76f18e1c2d9307f2844805183c2933af6ecda4c608c1ce9464e5679b45852b8cf87c3e1a66751b7df87e67a391f6dc1e69efe387c472d948d0dad745381bd3186ce0f99f8a17d26ff6ac90b07eddff845a79d4152fbdd5be8e7fc53e3f50ecf3ffacf987dddd94e19a4c8fbade34e0b1163877ff1546fcc3d79fd1b1c27b76b9ef563ee1aaf7a39637bc949e5999ad6d3dbed5bddf7f8ef6e7c3dc7a6a0c776b91b889e0c8232d2ef811f497bd5b07f0e6ff666688fa7a78d3cea8f557ffadf0ff5fe73dbdc1631fc90ee7306cdebcf75179e30aed77770c9bb6f3a27b27d134bc4abf5c5a57387f9a7fdad9efd4f56cd34f5dd1efcef9832fa01f7b68a201e335da4ca1fbe302dcb356500e1866a8314b0f3f50fbdd2a6f2fafec3f2cd7f63f621beedf45cbbc21409260ed20a9b298ec862934f6711752e3ce9de299d37ac43b7402daa500b010000000080c3c901000000000b8cc90100000000c735916400000000380200003360929c0e0000000000000000000000000000000000000000000000000000005e83da41e7f67cd1ad631527872071a1f13fd3134e73d3c4086dff773b167395f8461e6c52cfdb6ef82aa4b4b5f08d6bd8ce7594f09fcda80ddbc9cceb177c35b74cabbdf4b5c49a69fd6d9cc33e4f105f637acfe2e2590f08f157cacbdc19d3d883010b06846765746888676f312e32302e33856c696e75782040660000000000207e0900000000005d777c17501df48de6828019247ac97d1eb42289546a7e737a1f8895b6b0e17953418250206b2359f5cad25a6cd5e9bb515ea730142e8aaada90b0222d7855b3ed361aac05cef9c8724e522f9d1a9fe6ed8ec95151d6f48ac7673104fc3fb9eff4000000cdb1726b446a53b35f329f567a4f391e97822cff33f421f64b127b8a7a610520336488033fe5f3ef4ccc12af07b9370b92e553e35ecb4a337a1b1c0e4afe1e0edb56114e00fdd4c1f85c892bf35ac9a89289aaecb1ebd0a96cde606a748b5d7120466ef8538d29dd176573daaeac395100a6bc352530ac12affc86b675006b4eb5c2439848bf703a8d23008c1c011c356bd15b82ac588a072906995f3d1732133390fbe2f71b22b59647b2ee4a3b5770448fdb06b48fbe52e1bf2afcf37b8fe46c6f78da082ee0ee68327c8370f7e9b9f787a78c4154f8523a2fe08301561b0ceefb8f9f2c20c41d8cd74b1d566f07cf3f395be285290203441c1060182800008030530541002ce5182229001109314452624d13d30205c4846320658048530088b43505031140e4be42788abb40053311bff48088029c4840400dec6d62414a92c111a945000a0a0c4c38581c808521f2a01982220070a40a6189130d253051da000ac1ac918265660014f59a05801028a80a40168413da82884c5003d595688a628c80243a18a3810213784024004251b1a491ca08f362a08264442a90c1d8bda925194ce4c030c8e4208108e40a2f0a0600261400460346040c060c8094d21975505d6278a4c4442a105c578016eaba0261ea18b82f082511d2c0aca644e54dd65582a181367040f28c5941672906d03ef46401ff7ed6c2d3fe14d2daa1a7ae6d5dbb4a914427e8f0e65d26807d97d799e25f56500b010000000080c3c90100000000a5edb20000000000d731916400000000380200001fb57a5a03000000000000000000000000000000000000000000000000000000c39c02ffa618b1fa4d20349e4f5b454787011b2c5dca077946f8fa541f612b2d849adcd4cdacbe972dd1c66c4554a4c298c620a380bbc55ec7a5fa1b979d9be97f88459f77083e57c44ca4f6469c46c972e8a6fd0c6241a5a2e0ed5d5ef5df8c6265617665726275696c642e6f7267bba4da9640620000814453665c4b46dad568d69d0a3d211c70829ce7c5c17549713ed0996c8743e6b55b3797ea19c0eebac07b0e163fae9aa71bc2561705e492dd206730e8d7e731e621d2d7039ded027d9910bd41b23f642c609986a33f46fb3187faf6a0abc1809811c919b69e9ecbe5c129e3bc6cc6811de879149bf856984cc2a5162aed445600abaccb10a1b48694f150de473b893184c8200c822abc86d3d8d3bab7918b55963553bf9be9d2144a36827db66449e2302a49c72837b3e793666321ffa0a45089cb5f6af2380686485c4a85aa460dafff2c2681ffc4dd2a57ad488e53e904734908fa7759d18edb7e58d54ae6565774b607fd7488f013b6d02cd13beb3ed2a41d983f02f7eeac4b7f4222474252ef4538b5b09c3fe7ba6899412839fb79588387fd75faf7225e9dfd65bb46a795929d1a6a83113cc89c390ef293f9b73f336157e2f4abd6867a7a3aad6cb0472e1f17a73f913822642688fb28944b9df775593ac8a77bac24608066588ffc11a91b0c85d3f078be13ff586f7cdc20a23473f7a8c800c039edaa2ea42e15be9dbd47638ff4389b0a4e7daebe365aaf47ddbc16d3737ef8f4ed64da4ff89064056a794f9232ab744f72c5ae7fc674890d07027dc5541eaaf8dc1edc8d8fb4d5c763053a53697d9e5100ad9afa1e9fc888cf1197ad56d34d0f290b5d73dcb191ca444671fa433332f9d451efa4623ccaa1ca061827b86eafc6f771e184c48f4a3ab88c44829cb86aa86516cddcbe07bb52957e926dbb7bea95e9adb19ab3f99ff83279b5e41dd5cab1b5ee617340c8b46536a4e0b60d7235423760c2a72910dc838457a5a6c2d96bb1fe3c8b1cc292af040bcc5fb030d407a283dab7cf28b5fc8f651afb812b2b138c2dc05c2606320fd82ebe8ca7843ab0058ccdbdac8395bd65df3327fcbe1d8ac52b5e8e8970acf53a46d1ffa4ef16a472e24746a05f13399a7613a2b483855e7d67348cc8b51afec047355d3ba2a1f19d1e2fe3ee7b5137b4d0d257942118700ce0b506ee1b8b0c542ac600ffa734a960b60c13e89d3f60c5de14e3a557159326ae0eaa2328ee3d57ee2406ae9dae30d2bda566d5e22a2bf051a5ca0485b32edb939b949a967d315c0b771ae169433c6b683e0f58e5a4d874e4577d8ec74ee5466491a61cbd96f3d8ae11bb3d5818fda22b5f7914e82ff54d868983315df52ed8ce53b438b6f147343af4508813063e68b6416ddeb0eb0de1c494f0b40211bdf757919a28ef984ca6091f15f5953e0c8250fa5cfe4f1f5e54acd9faa8b5efe29a5daaf0494151b73f6dcc9f8b08558535b1b4887d275cd3feac9424be96efd63191c6fadebe8825917b58a7a286cbdba16cb3df97f1a94c1e41260bc4980ec4ed34032e8c714fe1ff769f8a79217a4a25c1efc38714c68eee4b7f8088e75fc044349471caa4b7fe94793d82e46e81f7bcac3ee933c043bcafb97882ee20d9d45d7c459934926b3079411afea06ae8cba6f092824313ca9998e067051b638b77ea5b90fb69af4ccc66218945554d9b78c3a5ea25d7e4eb9d68bbb40cb99176dd8ced6478af77e10570e5329683d66a2dcddfbcfac27f44ca51e7eb5ebe686e3bfae17a8415a2a13b29149c4392e4226a31225ba4af8df06e20d34c0a0b50376c28e0ff61f55588f8d77e481a3bda3eafb6af54015a2fe2b85c1292d883e4b074123a873f7bace327f77b37239841b1849e87fcd9f1f4c0b5e02ebaac21e3fda7c1f6e5c0bbde58071ff0101cb20fd117b265a8e87063f0b4c0ae6342af61107c2c2d0c9a68b39e8e609dcaea876bb2257d5c5a1e09c0451782ad560b8be7489a4c1e446b1fefe710d1b5d5fb2960d05e931f6fe0b6b85d4a9d4609370308774952614e889827eb7fa6017d5ab5285494620d2a3ead19245e4b6d389d503e7fb3faa7d71eaebd63d106bddee15ccbf80221a12d4cdee182fdabfcb8bd84db3e84cfa6b67d20ba17b7f96f2c9a5206dbdb251094ea01b174f664e3ecd145b876db7b5f900e23ff823e32cd19ee8a2dd30265e196615c6ce66d688fd344d68ffa7a7ad53e1570e5849d06a9d35c26cd41edfeaba7c0fffa5e2e017876d4a10453c906ac9f569ebe129692d49e6d4bfa42a4fe8f0838fcba8107576fa0b970433e1930c575f5827593bacbf77162a8187f7befbfc427bfca2273d24ddc67d7dea6116a1f25a02baf10460040120b6570c01b69a742d260351e64c1911daa80a4c8ca60e2c94b275c864f76a27f8edd99ae770d666f359cd4596978bbc50151ef313955cd867e9b1d4a76d501bc9999c1a5390cdc76333912ed4a3dd34290669a44392917052b1867d68f5ddd332f64e380d4631ded0ebecb92d09bcd7ac2a6f5f39e251f6b1070d614f716e2fb95d9f26aa8b1f8f201e6d473b2ea2624eca1cf297934720ce8e708b2cd1b992a9296232cda34f470a6d79f0ae5f2025f893bd15028988e14dd8074ce97010091de70685584e28bee1963f58a262c85df328377cb0c5cb3f39fe568684439916ec121766afe27abe8fd25ed47c06700b8629f27be989ae3e439aefec3861d3ddc2eab0281868e35001e26f98d7bff81c63c22ecbfb48060d0d8d1235ce28d9080dd2de2ac0408d583b8567309c4dbb0318dadfdeca8b8815fb08dd266955a05101c8a2432530535333ecdfb4f428eed385fb25a101c10a1f06e0d921978f3ea9f999459c488dde6035c1a6eca88998528f8e144b36320d6bb688450c9d394c3089d509cc8a906abb6c43a8b0537707c5bf7b1a9a7e573829fa3c9a415fb0001ffa4b4227e15f1e1f22d65996933cdf20ce49ceff76834f690caf6e012e209e34a4e814ed62d25b66424d5a788a4efc7aae897eb12ae3e51665f478332181fd04a995696afa831ebd6056629bc066cf36ddc88381d3c88fffd68e3cdc1fd9b06105066119994ae81040503f1f0a10c4153a11d1e609adfb9018431c31c1ff2807faab0e7af0239488bc063dec1190981964affee89ab22faaf23e3c24cbcc7d769e7102208d576bd26a640878650ca345aa680befa367dd105b3ebfd99391d53c66afd6154cfe7dd8813fe39059e8dc5027924e25cf94d13a9fa4ba1f16cfb442c8a8d3f898d141d9efae49249fab1d05cb3f9fb900aa0ee6aa232911822e0c17998201c896ee15deff92aab0c34413d132ab731c682c9f3b3d745e6c5e18e673c16a56c4646ec0c2ca04654bab28bb7a5ca579a9170ba9ff3e5363bce737acfdb1eac18377e33978ae4a82dba9bbd4419221e58a10ae80f91067754051ad9c16606b72752f43ecaeeefd9f0af140d0d4461a3d890cb07cbe2a9b001571001fefcc7f0e1b92abaa097e1566d5340853515a15fe4256b83ffe2b723e60e206b75f27ca1b99b1164484197d115a93f85aada209f8ab8a31ce3a66f23c820698febb8e95ba96ac28fca74bca0d504dca4cdba7e85bdaf7fef7b0f17d4b6fafe4c3e9810ee9fc1a83466fc3875eb8e22b2ad6e068b9b18bd9f60f9e66f823cc52a2ea0eea5a1c3e7756d82811c9da030bbc3a51c1150ca8cbf5ba38b106b185e0ac4331e8a0d653a66cad60427efc8b7dbdb817999e346152c197e1b2d61a5a9d7f2ed328aecab1ffee39b76c17dd3577cc399ac7c7e1cc48e4fac0aacc1451793db4f91b593f0ca06236425417238ea6d40e1837a9928af864d8b34fde1cee5bc2bc7e69bb9908c8de49df8c821f0fd6b497657b4ed5cde9502e86ae3e6f7c15189a96b31d30f59faa760de83831397c7f99cfc7e23f2687aaf2ae64deba1902f491299ae927ed9c10ff485f576cef160dd32c11e33003c9eaf468db444bdb715d97acc8df5e08e6aec88d91f747e897fffad73af7e05b0c5cfe23deb931f489763e876088841e9d7358c94619229ef27149b51f0a322200c103e80588e1f6f31a47f40b3b858d0995af11b99d7baa4c7cc145d58e14c240954234e32691001e9cdcde67429cad3962f37fd84a7c61857540799b8ff3d3cda254ba05880e680230712a0618054dd0c89b862e419172a0282277865a2dd45e14a49e31e73db870d70f238a29546e54eb601cc76b8837ceea671faa84f096bfb4b7eded007e12d2efc4f9ff8a421b2000a75c5a01695ab33f027429361fc9f46d0bd883d96a1f9b4b329a9c7256e45f13a298590c0ad15e3c16c73b541bef836e81ba5e18c844c1165fa23932c40287257bedeea72af52893990bd5a6bb57df63a2b6a1565680945f87326e38508918c0020e7f8cc2a26e381e34d8197cc45e0dfe975331d65494aeabece73b741ac9b192e930439dab6b62b91a9dac9f909d78111dd62a5f0561f5f47a9a60c5d55f309ddd4b7b94efc87dfab8effaba010041abafb8757d0f681e1a25939cc5ecf764bd83f2832653feaa0a18d86336aed2c73c84199afdd03171e74fc96b865d0bf7f4f5a54c15c823f27b209b5d34b64cedc5baeb0184b2d9524b012a2e4fd70dd539db32f6964c34d16399a16c5499597423149a97723cdf5b5deb33693d456213793adbe52ec75ea8934e38ecd9299ff8d57ef12e9b4e14806d103954b86321ea42aad93daf0ea876befa5bc2a7659b3608e9efff93a7b5201478798d65d892aeae9ded2fad2ea4007c0cfd35727d44f8ca4c7a52b4e331621e7dab1aa1f7aec02c7e7c3ae36489b421042a9f331cc609990c589f1048c10d1ff1873e9a871477ec91acfbdedcec1cc83e70447a117325ab16b1a69389f4f786acd857064e82ad1da1257e3ed9820be84d6972a5f90ccd96c6409124c845a3feb23a7b862dd28e094e2620ecc39fb590e6cb7444e66f202cf8922ccc47b807776a672aa35e4434e27ba331d0666ee19b472556951fa250b021dce47ac13a33264fcb87597ce6a7d66391d19da9758ef1ee7d19e1f774ce54c5e92a487735cbffd941210fcfc8c42b7af9fcbe376863e4e919916f0d0ccf8fd05d1d7b3b41401864f4c179bcbdfff434dfc4dc4171d35ce0887a0ac8e3d17f150411a09a74e02e47fb8f537f3add4377e0381015a79a5fc12fd86b521dde790030f0ddc7cc34305c0bc5e9e3b22460d405a3cf28761c0e7ada75fc69d11430c04bf856870b689e40491f49f76d18b6c62ee4a4937d2506e5658b2e71adf7fc9aefe03e6fedc0251a99760209fdad863928ff8050c39c8abeced80ecdb13fe10f0f65045f2e2d41958e49bbb4c4fc1c5fc15fddc7644e5366cb4e4416bb1a6afda3a8bcc5f7c51ff01135f7643dabe355f4cc241943521cfd15ea8c2e51bf44e17354353436ea6059f90e393790af9a011bda79f84675f83d3e4ab18a7530369a953490c20ebf4430a5398bf4738abe51a6e43974999d316259501c60c8d3a4efcbe8177833c67658921351d44588c2339704b9d6bcbe30f95b94328cf423be2fd387321e447dd5571a0c1992d091f4397fc47a835e25c6355488cbf4e2a06984410a8df4fb8bf596927531d59bb74f72e147453de54b4b82c99b836fe255878b4156eca6caac99209c9f0054f32c2138c9ecc834a2640d8ea4d6cb521bdc12f12d055774414ab86f995032ef0bf03ad45f1403161b848bd4ef4400e1778f32f5cba7274ffa117a1f3c96fcd6f0e387af6302ce40ed69cdb50b88c76388a3b80c3954c710f6617e44a986cd65909ed542614c1c6f80da78461192553d6e077e9bf8ea20b6016cdc0c995ae07bf473df39af8d0dafa160f252d58d394930d46ef2b2f0a7d1e48d8ef2aaac8a9ec0b7f00145922883de52436598fdf1fba9f1283d31b70ce0ae4daf3db610d970ec2582863e40458de4bc082dfaca451d756ef83a93baa3fa37b3f82ab8cdaa487087eb9175d846a789099e344b2ec58eac67185e6305a81f5f691330fad31715f8fef45e835a9da43a571a016a35bae46b3415ac704c66bc651fe079c797786e047187eb8c3eac665b521beff69db528d5a49568f2eb0030ccd6d5e19ad4adfb271ed46d44024356808f77e16573c4f0aa225694857c34c5f00bcae4ff15c91bc5917502dcb84b78f04e2627794268b54d9a670f0b97d9cb3a5ec637c0eb9f0922a70ba445fcc20710c56b7b05b902262c081958163c0036ddd7aca4daf4814ca4fb003b3f59a76adb7390155e0dd635b8c04ca59be1a0768463d94f49a021efb43645da70770e4b2f4d00bacaa91df4572fdc8903ff47df32da286a5f14a3ed8717e537b640aa123f6b64e5db9ea7e3abe9907fca059493075091e10815eb342b85326d35a5d978515882b8258c71ad6eaf9eebac6ef8284e4d7925d40b48fb1c4ed93ab6b4bc06411cc178e8ecea37cb50a7bea428417ab63dfa931f0885ac82f5330764294d0297003418e70fdc994adf9d0f23486520b8caa560e8c78251fe9c95861a45050797db4586e18d968f6104dc18c6dcb6652ba7f5f8504a76cdbd56c2fd9bb5c3b33384ff6718e9cf70fd97b62a4a2384807a6d5e9151e890ebf9e797c61b0eef785cf25b6e1f930320cf1ed97cc43490f3318d74cb4a5835e742f8ff9abba5562e791eac25fd8450b4f5458fab279ba50b06e2902d04d1f63dd6d08f515a87b1f13822f7fd88e464e384b2ebc91c2ff0a834655c632b5b7e3099132fe6adae081fa6d756e57949bdfaf00a3474b5b4b47442d160c66ad76d9bb755b144f49553feac5e772dfcaa944a31f4ecfe989ff4dc092525d7e95eeb938c87e22de2e18de8891db8fa0aff02dc0c936ee1c5846f454e6dd5a2a8a84111f213242ca48ec4a0ca42de208114b425884bf754f9891a511b6e149009346e2978a89df0394777a636bd6d6cc91cd06cd1395d9c42cd5f278e1ed46ec4799910d6ac90fa9fc346a09a83a27a096602b4269da59eddd4ae1c2f3f30cdb05131399cf3c50c913c683ee1a95ae748b674ccd3ae95b037aef9c98bc4693eeb2c68ec35bad4dfe85ff73b1df1584d3c99ca62f44bde2d01b4a1a20ed9e8309042005d373d3b93bfdc4ac7899a2f4fa9498275caa522098e7ac5d756414e3acbd875643c2525229105cd82a32669590f23573755c92518134dc29ed20ff7391a7d809a4a90d4f3ccd98417306079861565f24088c9f7145f44093f6dc62ed87b0b877110d22048df35d11a9c55f0242a1a4671ec29a9089afd2f394cba94281f8c21f56ae82332b7b04a61d99762498993fef839a27bcc305b47f0746f24394920e5ecb28ec54e49e6a6207c63fdf445b561ae777a5af4717bf84bbcbfd27b47f5a72308e46589dc13056956be4ae308bedd8e7e8f0e796679de5855aca48d26dad61e97f1b66681ab7d3277c7f77e1d69643db6ef966831fec812c326dca60b33f317a1cd6d055aecdc40bd5bd2199ab738595dc59d4fa794d63d7758c06a4aac989686cc8abd3c63122f089cbf5398e933313ccdd960903eb597954b2749b848056b996f5949ed81acead2823d11de1925c547b07fdd7a0764e65d42ba4cfa5277424bd750b6dd6a446752b4b8821949fdd4460c3ef0340de7e9687f468a9b77105354b55bc5eeffba2a27d845f79b7396446353efa313d4422bea82d8bcf95897b3f15aba174e91059115e5e0bd02dd9aa92397f35a424e925c297d70be682f17c470035b58ea2f17703c86333e5790dd1630559e4d4a0313cf7b069bb2467ed1a53f4ec4e2587c49d582a4b21ea988e620b91bd4647297050d64aec86b628bcbafc2106ce8c6e8f52101c0fbce580b18b309d3fafef0c81a3f1c7ffc66585b007270b3868a45bf9168ecbf82489324ca7c1feb0f99b27f9d9a294481c95d5ccfe1dbc888d1e2c4c506d375cbc89925113d25c47ffdf60818744c832a7abc4ab36dfb4a13dff1d2830e9e6fe3fb843a442303b1eb8cb8778ba9b3fbb273a8a91f5e19e09fd2a37738aa63fd26a0b630bb3b36c219b79831562877b484273e72c8b4320ab00d328c3bb1854c99b6aa8e2ee69d767cd5a205c8982ff75ce1a7a46cdde1651e3f8f1bd79ed3eb595e9efe010d59ee3c3fa9470bb03c285389790f8ab442884e4d64b0a479066e1f62f2a1561e0012e44def9309af5566e94d68e4f5ce455ba4f9afb0e662287f87b5b96e0b215a1b9baeb8fb46a52e711afacd1ba7bdfc50e1ff7305ab07264186c83ceb77cacf008b6c10d56fe1f4610cd05844f7e44af4f08e7d7d0e8f55d0f3734956fc9287e2a8294102c2d97ac21f9d741b32c3eb9086bde7712e164865bbf1a84f14d48e0b38f98ef54f06af33c916db45e6abbe3370c9e47c5a5f5cf73b4b784e47bc3f5574155c804c18ee4954f7e89c50ae9ba4d03123093a6500ded8a6118f7dca1fcf62614e68f38d2e598c54a065f228eef188cb7aaf1f41df6f3d4d788a88d204e9e285034a0c6c5b6b894e232b844a4696a3ef7d8f0811e32f6bbfffd557dab2b588eb918d8443d0a9f4a7c82b42c275bca9865e7ac38ca3e49dd150fe2f01fa8df60d6f581f050b3bbe0ef416ff657db803c0c4995b9b871a38a5fab90bb90732766d35452dd0ac64971d75a65d744baf6ca2340c26934f6527c29665ef128f17c20d8c1fcca12fac9d898893a664c600896a922ad526c6283050ae67863d2ec2f47eb01b1a3e19531a2213078edcbb953b57fe701f0445e95b6a78e45d1ba06e3b9077847e1017f6085f75d3bf0223c98fd32000d555b73e6c51ab57246e15d22531693894f793cd27d8fb68355030b0f7a357ab43192956b96afc377de9b07c41d30a6a23f461c47f40d5e2a023795c06fda75737e2a5143d325b86d62aee8500d1a76c1a96269817f465ed46b40140b7d892b68ab40d3430cea6f598b8279625deabc631a7114e99e43a36c83fb7d37a70d742d297b973fa7e0caf2b47ac62f0750e0c22a59ca5952ea74f0b59e16a1e3ce1b391f1a9f28345da7a5f0b37064ab736772f7941bc9b7c758a4c56f1fb5455ee551f5e9e02e8de051e339bf90ffbfa75c45319cad15e2c5aa87b98b604568dd1eb46c9b92d553c5c4268a1a2e44707b3e6538ebdfb5f504e73fd80b0d971a6c280fbf80a35a4723b9e1db4566ae59354322f6a6a2ef45c60ac12ea88edb34c90fbdf7b8bd8708cab7bd1a0b29be454c3479f2629c5018fea8285f03390c355e0accd89f6824d449a38e6d0a2ff8690da806ee42530867b3f363b3d49e738df1563c5600702ecb5bab1726ba55fd0d4ace1581d4f4108368b24fe4d4090b371052098c4974faa7e46e82cf07589822a39aba6b03c2f19746827fc4d2f2ba82df5923d5e2876872d840b657bb2646c9713cd61a83510e5d00a754fd43eaa7fa3a2509a74bc7076096b720b73ea207b4ca9aa638b78f4c0d4a4257fa3d3de17c30507af0a058d99db8706820cd18dad632b954374503edff3191fcbfc5b2b55be2b0b7504de5fe097d97147f788b55f6332331101ad4204cf5b18173d4d0809c7d9eec152c5cacc981b25c8aab74e3adfc472fa13e6f6b3212bf2293f96a2482ada1f4ef9dc524c2499e970eb4496da67b6948958f998dcd398b3aed89d5943d1529ffe74cb7a7c2df90043a24ec03fb8adfd9ed6cbec980b54d199f665e755060c796c9351353a23aa988ceedc8cee0d73be4ed1e3fc765edbf7d8dd5e102cab4181e53ad02a5fdcca3c534f9110e4e7f292f5f4aa5c3fa49ab9877cd3b1c6196f62ccc3f8fd616e08eb364faee03e79b96212a1f1887b85b3502ab1cc20df3480d71aa3db7f60ee2a3167ca7a530698c998ac2352f5043b632650175dd345a3bb805c2fb200eca4612732d72fca8a5501d73777b3bba9cc398f16ef01998e922d41ba8b0bac453b80d453b7ec869bd0d79e9a87cbe0fcbaf47a11849c6695f3b877ec1df5cd248bfb2296192da2af337d4767bc3008ae01b8228d94efd3b1adec17a5f9b2a12ab50175246356edd18bd8d5b363d1bdb7f58943d8bd84d91f1f324a74c654c6307450612e94635ff12c03f08ac4d9602e231bc81eeed25901c51e8c786f66448774e8d79492af9721ddf0e37a9c168287307f2b519864c2f897fea1d8a4b53bcc9b2c5ddc91c84b8c8b090a09da8fee5f148abef2304a840444bc005dd7652b89ba5576f6481891a8a71397348ac7829bf53e3c58e5e095567ebbc9848aca8f2b8d3b6c09af750a10f6a47bcc6a45480820742de945173cf4655d93916154597d1b8de6b5b01f18db2ff6176f0cb89b68f62a1bd48bf7ffb44274c599670ae58084d57d85f244811901762194be0023975a453bb177f136ad9495e9f24b0a781da39ab7832855952722ed031fd1820aab81752d67f23f30a6e3301f3729f6cb068ec65e1ceddeec8b2c163e8624f574a65cf8e7b81570277a08e035407611bc2b136459c96dc986f140dcca94d6c69784c79ee9100ec11d240f95c7920652b63d056b35fba4582471c23a9e5dfbd717a689d9776fe49d1f8ef8fc43b530597b6cc734edec8aaf1c19138f7c65b21766ba935b11ae420d2fd0945cf46e15868805dcbd39a9223c32176cdcc19f49db6ee857aa5b6ec01185255871c4f65edd837e51082cf069fbaf7c841f13eb91cf801ad1de660a0acd43fa5b2a7c49bcc61b744b05d25cc605c81fbfd829032ac6bfb8f328685938eedc8919de180badaf8980ca0745b79e18bfaf31ca778080ea486602c2f9b80db583b32c07353f23b31130770b37863f310ac5c5a9560b57430fbf5fc37359e66735c5867012f7059418714a76fa7c5cabb914f3f9531e4c8a0ff7f8bb5bc7b263660982be7e50e565c0ade5633d94f5de6c71ceb4af1ca4ac2137bb7c02f34d88860e312681e195320727fde90f17f982d04076ab3fdd2357fdc2037db0ed17506f194426e43b065b70ff8460a6234a93d0a5c54024e1c7593815c108cf6d545718b06178fdd7dffdafd222c94f649948e1290cb85f8b166d82b7ae97b3e3dfbf3d0f381318b0a15eee35bb3877e3b966181b5b521aeb4ce1bb11554e7f56d9065e4c849e2046ab6470bb9aa3fc407b0b676e60a60ea7570b3260c7a987a5b2e949ca039f3db17608b6586c169099482869b07f7325720e27f56d07a4656914b5328648296fb66bf95b76578a8fa4fdb83daa7a395008149fd3cdf6fdcf1c80a236b3a1a96e511898cb24b631cc56aa7c7173c36162bf4c2e4f5afac8da6c4385ae6405e88b25c719a464b9a6eb2a3453ed21f62728750af1ebe768c7205e8bbbbad32f61e1ddb6bdd2556b5b21bdaa11dd85717b5eb28d995889ab0b839d8c4a6183d3804cb4403c361b0b1d27bd0cdfb98631ada8be88e17ac77f2a697ba4fb4d98d96c01400454e9d80ef89d29139079ed143e50151bda9ff1f43eeadc6cea6e693d74f4cb1cfe09696d396c25ff629064aa2d8fe449bf9702b19634605d66471b2f74f6daada1d0528fbe4c76c5ac2918e48f0428f0d4388073784e68fc2c0cfa83bd1787849fd849762ad5bafe0ee3ebf8b0599b5a98a520a5be01732d5031bf92ad9ef0c235c582f4f970a502dc4e38ef8bd6e7963731a8e1fb1f2d8bda64d5989d9b8e8971140d5fc36ca356330ae603795e61ef15758b603b9cc62fc0fd03adc9988a7f62b6a18b60eccd1bccc3b27f03dea73d9300f38d7dc40123b365264b04aad43e6857ce22584d3ddd0646e318e204412350dced56e02bb8f30ad1cc553be2c11c989ad8969ebff9c3be0db0ba9cbfca59e7b053463a5fa16ef00c33c308df36f2a8d994e1d1d12297eca66ebf0295772d0e9ba8e6fc8d6fb36d74b86c4459ebc2001110da0b6273d04f8b0c23a16f64e405d72515578b0f2111a7e9c438fec08c60e21b42e396bd9cbc1eeff6e374978fe3e39d75e8fb3eb96a6fd485e4ce9361875470a5c3ff43a2efa1a00a78fc104bed02130fb180409ff8d2a8472285a0016c50a9a41901a4902c19f21e2c120044eacb6c48d3ca1ee79780370d47f296d8cf2b8d473b0e0dcd5feabe4d1d42ae77e7264cba987404969dbe514d2b1ef5b95e06b09d2688f2503ceefb50d21fdc4a897dd6deb6c4ca27eca219c58c1182383a04f500798a3a714802a2fd33cf2cfecc8719d925705e4fd8c491932131413b9f5498acd0463b02d4e6345a4f5ccb2c95a9ec60ca4f6acdd6ae0f2ab1c1f78ba945fd1c8d0d77b374281b49ecf0fae9b27afd520e577c01460bdd07ac1c521f94f3d21c4a87871ea9dd103323ace0bfd122a4993cde5584b69f58f2ecce55e424232db799bf2441aae86c51d22c8c9f4d17b94f786157a07dd8701a1dbb2878c3e6b3911a1d716160e45f83e7565d364d4b3ada1374b7696061d42552dbcb7647c8e4d91ad3e1846cb902c373b5b36e5a09b8ef95628c6c5f846e954d6c02e446210ae89385453948fe1669e52e185f7104efca5b505b14d17c0e6f9719ce4b22f71da941caff7827a8311a0a366afd8d274c76ccaf108626260bcee8f9c0f1d8bd5f979b6b8282103c2af61aded55e0f5a80b2b192f12c42b6929364648d9b4b5680b0ed1a77a21086910bb0c041ab86fc2b25aa395ecfd5d255413eac364998a091181ecc091c64050fdce03e6484815e580f21eb07e6267719a0d88b2291648fc9ae9ab444a5de7e5aedab55d27ce3f400c7dcb57bafcc24a30daac9eae10503b52054ccc8b18220418a850392bc20ec3f768b3a6a236fc237e0a197df2a164a3e49d4133423226783f49c7dd07cb840d128eba5316878e0f85c3ef30bad7ca5ea8a681ac8f6a216abb0d90ace55f37c7179797e8715c5640a0daa39981fa48ff73125f2e1ab1591402515f7ab7b533948d7987b3f237acb2821f2746099d4b714fa228fffa92f42d0c9929e912ca5eae07e07fdd35e62de79ab35f49543eb0a03ac1acc99570289106966173fbc2d594cef0da9da3ce46c046802c1716b380a307c10496b2bc330c2d146f62ca8d5dd254e58fb846bd1a3e50a1faf580735a473f6e40ce67a4696a4612098ef832ef13a82e756bf9b6431a598a12ca8fd80e1c1c52b6e66ca01f6331ff5bcd1821cf35df7e1288e3d72ce727ded3ad0ffee267e28737607c70aa57f72dc4aff85027dd2095866d46b070b26eb4cfaf5b2e5591e9898acd7be659d7780f9de34fd04aad926dc2cf06cbf7992965e7db0ff906029eb798f09924500a6ea5454425783a4f8f6cf623753e36f13f1487d4909bf552f60b64467def6ba257ffc25aa955b46ae2378025acce6a65e90f2ad6474c09ddb1f24ed893baba3facfe0033fe4e5649357d59a4077684a69df61933829bdd84909ab6d684ba7bccc57b5d4b67aec5a1ccfa2c858017c579cbed366c29b6cd1ce009d5879ffba0c650dc18e683b9610e651586954365d8dc567dd0a80f7785b3359e6371e699d57c61c08b9f65be0a23be376f5241a6688b918bf67f32e4576d58a6af7851edcb66b6b8745fbecf1064cc60ee6bc3de69b18cc411733e9a6af08115c2049018342146a9e518299b1e1631d9a2bcda23078ad50fcd658666cc7573031dc837d59df6836f02583ff70950c495b82c8ac1c7c1e15d9c4c83ac8fd9dcbdb44c81120f1f94695aa903ce6db48950003a556b7dc06627069806e71398860c3b619f1060a774e16f4b6dbba5c6c831a8a95f290e17b178dfe3f935fa9e897559e2539e4ba3eea81c61218b26c931c8a1224895f1de6468c97a89d14e5cd400845900af012b4d4d6e29f8a79215b052092c0a9e158e43cdb839c176d75e6e39ee6083494547cf175408d7d2effe17cc862f1246be9434d9e12b490f186be8f6ad7d3c7b5bd068ec6ef7962f49207b05af20eb5aaf7e99f80408556177c7a186b7c7432bdb577d7bfcdf3f485b91a57b60780d4dc41def326e3915a319aabf3e82a6b9708245648314723d2a331974f2a6bf02cd1af9dbbba3ebc42cd8d743724a4cf20eceed48902d52b9ab9f3c3e18f2377970a3fc5c194bd4cdf57c51e2278187b0e9a57f77ccbb39b15d7bcb76a84b0defeae1cd30b59f1c1e41f78f665e6d0a1de233b6d37a8bea9a3bb7fccfc9b102ca6fd636e48a71473c867893ce71f783c3659650266911965ad2ceb2003457a5016281f672f94644c5b58d285f9784e53a64021f3f48c949db5940e9153bf0c34d4ac8ec2628eb792535dbbe5d4547f97606e8d0811a4a342fcd95040371af516303c686793e16b51c8c107b6d1f22b60fc13ec118307aa1bec5041f5d0a9d6c7ac570632a609dae75d58a9b8004873b5f805a0e08482834477a8a9562482c88a9288b48afc8b2624b975f7a0637a5da4851cba6e5a751b891c46f2e2d818f4dbd516b7e6b46c83e8246d0aff2459703d9376138858c08d86ef6d6f3228d44218eb94244698a0bc448c70c340bfe857d4f27e988fa7467820742d641d5fe2679602bb5a146549e0e3e67fb6726d85834950e5c53dede23e0240ee9e3b26ca6cbd9c74562d77cfcf94b4269bd5cf892698a91c3ae42726ee9e07c69e6e38803f6631fd69c2de4a20c4f214a774a8b99eb737b4e8da5727b9dc0d0915c7eee78b1bfb42b9825b1d2c4c9442c952213d17cef7c181c23487149b5b681d7159ea45450e0f25e71aee4b9b50032f86ffc9f36ed9bd7ce63d688b9d8c1f084639bbc7c5262e9e0bb9eed8f7ddba446ecdca3984cde5d0e6bd1195226ddf47c895a64b44f27ba82218c48eafa271502f0705ff2e6f2cd291479c623b3477d67712c94902cca20f4d6dd7e09b1d252effa7c3800e1739f1fc220b91ff440bcd4500176a509889a104944318fd4bb4805d748b8a5a09656e497b46e4ad5ee6bd9477fc41cca86b66014c4dabbdd2825ec7256082774a6fe9ecef481b98ecb3237adeab1f476efe315fedc0d82356f60cc17f8ec26d9f565b16380f4d93f273c26c22f2a2c25c2b03e6ab418cae19711b2cf47a297f51dadab1dd129b0cbf9883553eb7f3f052a18a010f802c2d4d0fb40d891e4256476799d7e11ba0efda9aad41939a1498cc7db0198b09411d1760388527bf4a972a7a06cdc7d211bf85248cd0b783624e5c836c2cf3e1406d8427001ed79a8663fb9174d20d2a6c7adf02b5a0e1d4f7446252e082a0cb1bc524cef2dd07a9d5ffa7bee2f58d8579add29521a9ddc944532622424725bed49f2a6f047a1c770ea9bcbd8b9bf99e3e7ab09e8289b495780a2eb48ec0c45430942e7778dcdccb1de1411d40ba7de1f29cd3270d63ad58951f58275db500eb7c7781843cbef8360837a200b9dae2ef916de0c7c5c5e4c99bce7c2b0f4ac3491bbbe14c01f9e09717e7813beaf694768b53ff3e10dd2bf72ed87d239d8a7c9be4b0e4cb05e08bcb8d93819e197a462ca20b84ddfc071566f4124668c6c0f3f821fb2fc49d1587b58c87f56d3bf1aefee1868abcf44968cb526b7d572e9524bda19d38b57d55a13e529f457e1e2b2f8141396d01461774e350c1155320997151e870cc57dcea9dba96ae9962b0da0e26f21a55e8feafb8ab6383620d01c2b5564bcbdff7f79cd43034846f6a2b20b3da0717f99d394ed1e89349ca3d08a91e5f9595cb8ede82e07bffa174a1c99bd34887850917f10af5ade7e2bb7b1676b86d80e68492b838d6aab7f3f38f7463f2b944c8c2e8f050f93dd47b1ad02e3d7d3b4bcff207f6607eaac83aac5c5aab88cef53f6cc9c25ebcf8e4dbb0027ee977265e85dad4d35a70af240e1714eafe427ed99e7df48dd99c16e9e9a4ec56b0ef79b829d26590cbcf396bf41e06952a3ed7594837b434f5b90c166508aac0b6ebe8141e177e60caf14fd1acdce80c56cdea4182fca2da0b30ab58cff9b80a73302027f19aed6655fd9a86f236bcf134917ed8d7525c3447aec2d2207cb6c4b6761e885b59fb113824188068c32cdf08e973e0fc623e67fbd5bccecbf1ed00a0012df83dc254ebad178b28601d8f8eab90fcf97ff9d0189f9588fbddc7a1a7ba27f1c20427c61a46bdc2873bc8ef8c546503bdced0742951e3dc2a1755f1b0f042c14d5374d68310f10a87fd66287409129ca260d1e9aa34c0976f8cb5bd8d2daaf2761b36a5d3001bcf5fbe1c9b2b3c2b59013d6249a97f1708eead3eef3958ff9086e58e027aa039887b743eb03e02af6d465935df9605072207b6c595f0d9ad56896f010c8f7014cb9eac8f2187ecbe589010cc6563c2d9799ce3e10b66c546e9ee22e814c80d911ea853de53e83190286a87cf262d96441825ddfa696368214fa6dc5658e2c7aefdfa1644376b467bd295c9f1ac597c3a9e8011f03b02adda1cb0f77705a068d6ca6de5eace04fd4240d7972c777453e4f502f0f8d6f7861748250e448baf04f53ed5192ca782d008ed4159215c1031c37876e15a28988071384783d0983bb111940b9881f9c3b4864d2d220d742f9f1dddcaefc58bb9a27d30142b67fb074df8e9324c7bd3452377b6b761e2ff614c6f00e476fefd5396e6305101926fe8d6d48ce6da776b839ed7e1e6e64ac6bfd4dc597c221bb813c741912ec952a1611285b0a001adc61e51b05715129f9682252cbc8d40228401e5b8da773a3b44b23115d908ed8864b6632e95b676914634f4e779b76c4d920b0ac381bc348f2a7b496b90a4306b53a4ae2b8ddcc99b5fe0a10eeb9dc2081649237d24d52095f388f0baf408eaa1075ec09da6eed829ea2031cf95ab4365c9b73fd3b37305aa3a08964c995fd3da9badb11751d98163778a02abc1a08e1d52a4f315224371a8e582bde2ca33c0515d238927e1ed7712f03724b6280ec30f71fa84a30974a54bc0fd48215b6f062216407db840ed952379fc0a8a8c8a24bb1cad4c6f25d00e0f5a84252c3b9d11c2646de4b17cbf2c1cc6d651d3d479014258da22d75789291c510d28f2289b947309a42a0d8ae0f44a173c4c9eaa09893a271d8d7461a774027c234344c4c230ddaa857e1bf4dcd3ad3735f5b4d3448edf90c062e85055588062916434db91a0032c35b6d031425ea9eba1fbe4b3149591c90b5aa94338f5538dccd2654acfabf47daa81da2909f0988ddd16a61b2d4f6565ca852d94a1332f0d0c87c036ac4a9c867ad26030f216e054c9402a49fa5b406eb658e5f0ae9652c0c4575f0872d6065c0264afe7320ac52c3bac84b7285d0c07bac6eab329fdc8131604afd108707080e8df0375dffbc5dd180a798a327d50fd7e2279521b2899888504b9a33dcdb71f89e61093e5f128b5515f00eba90b8f0123f4edb0a485bc1e754e706b7aadc93d89e72e37df01ddcfe622a9ac8e33a4c30bfb7ebcd14296bff62d931007e62c97690636242af6d9875e260faa1d1aa4de4d906c679281d298ac932818fcdbf1ffef2ab9287cdf8662b6a6870f46c497d2364c0cedc1001f3d3ef7b34843f74a1e573a15d91e00ddbf851b3802f171288e0f2fde77937efcc50c2526c5cce34ade8478b148ef19f9454610c2fa62d8cc3983163be291b748dc4ed563b853fdd82b45d0533f5d5585b8d25f6c08f2ab378b803cb0e7802575fbbfd7ebe91c429db8766bd825f3b8ff98c76cee1a76105e2ff7685f4705499108d920dfe2389c2c65222f4ad435c78fa86ad94bcb34a168328161f74c445c8df82f296c5a6fe90d40c0b58d67dd0a07890eba26e2e3ea159ee0265067cc64a364eaaab228a60a9d4a153327cea5267f0aa7d6767ba2109727c244db2ac2d428e1442c200061d33e714976203a663913cc343b973a81b47c0a6832f5e36810c31f2e5fb9726a2a2c8bc7eb2c052125b5c287cefc7362c646c50427b721781d5fb006d018683ec7cc115ed664284748147adec635fb1d8d7e2f355239cfc55a325865523b44b795d389b21e93698eebc368e175b69a5f5faecfb58b96759b7164f193bbd5d2ecf5abfa2602cc23697cfddc6cca661ec574ca2993393ff985fb918fac4435f8177f1c84b8b51b98ec2c0a3e4c36fb09a181b89d93ff4082c9bdaae020a647728ed02ca1fffd408817e63f6d6f0d588873a25a3b8c84b6b6e9d1890ec888aa75eb293463848db0856e34a92be0183e2eb6b06e9ae045d7b9bf9714649fe70a1a4a0d348dab35962e42989d9c2ae38f92224d020ed5f851a3753b581261da8e2ac9511fe1ec0bfa29d3dfebf7a52cafc86ca47c3d25b89d850b20dba9818b375648562e28f93efbba12cf14b7a4203eb946d497b2db4ac73952e72064a48d6e894a35e5f2a82713b81eee2a2c754bc6ee9fa3ebb180c6bb438b9148c53f40c5076098a89a97be4952690c1f5635671f6917c34fa089850b77eb0a4b323ffe8abe46d9f16feb3fcfd7f40f2ded29ff70a9debe2531f343d0e1af3b0764bf5969d8b9fa03429759c29d22701a66bd246c6ddf5939136ad5eae6fa8775dcfcd28cd4e42ff7c8e05a5cdb1d99577a28a4b37aafc0d3f1553e2d2f3a31ffd3a1179e0b0d4dcc248b3b0ad89e3379aa1e404a85a9d33e4d332b970391c22d72c0c128e8c60103cf9a1ebdeee02843e03db59e1e9b8b007dae8a5f12ba87744bde58a11a1c5fa8e137dae0615b7ba3f2b0edc6697141c4b5e4d2e2c00bdb091907501ff54277e541ddf29897d3b90b45de171a78f54f25d7888bff7d0c5b0e3b061a463a093042a9026cf5112142cb504f9906f35cf99ba6726f366315c01dfbfe99d7ef249132b0c3a687dfaf7da86dff39929ab822328798f52de6d546632bb5b866598868a8cb3bb366fd9da63845e2c893d992201349e422e5c912956f2c21ec96db9a7c27c9829f1c7096dc2685ef66294f47023bddc418f91a211e23b25ad2991bf3cd62a81c4511494fbe06f7cca4c5281e14307e52f9da671e7627de5cc5c089697437bb683dfc9e0dac291d47e18586e0578e1d5365961b44451e282f6a54b928b514ec459c54c96e18f98851ab7e15348e34f47b932ae50078019f5d45f42d36f0b76fa4a8f7bb57952374c8e9ce09020053f97e818e2097212edd14bc23e7a165296c4e7b6939fd0720a865e05029bb7590f213541f05cb8edb197e6532b88741eb78ffa6c1103e7be4565111ac12e5c3d34cf595df0700d2ec64d312dbba5018218cf5a2b3e571c79d89f066c538ce63c1049de02982e7e2589da2eb5276a751aef35a676702a8033d4b491e03edf1a70d9fb16c9808a67474dccabc91981d6a6824f26441118059f1f60c72c0ee2225fcf7acb78229101f02b6b8421c9def1306a9f452e304ccfc0f715de13d48ac05a3684a130da6440838a789e946dbe6c7f44c44ffc7fd7c77b9497229052882ecfd0898168232cb4d796781d1054973dddf04e09577481baf23b5468b95a5416c76f28396411e7aad4cea8046591f664dfaa3af8985727ddcd8e8e4b87308ad0328ca4294e8b94fa41b4c2d0b137f93e4d9fa24a301804f5338ee5661eaea06be44df99db421712a1e6bf81713548807beb5aed4a1d78ad06f5c245564d377be61744d0a6db264741d50560469a055a1b8593fbf80ca2f99f819290043d4a68248d47f02432a6cad46b49b945835b230ad0630bf1fa12f698804cb07fafaac84ef483affffda64d7d23edfee1e35955111d1147682c9be955ffdc21298acab5c5b297e7d8e590db6f7a45e4b574cbbf30287fb72eca1a791319a4fd9b9dd8e3dd180d9ad7bbefcc28ab181d65ee89902c71ddcabe414cbfec469e8c6e7b11a2888d858cab007de7df4cd209354468918cd9196663192dd46b732e31235c603c46b00175bae3f536003a21eba94080cf5598533d633b5ba4aceee3d935aff8c6b960ab1f1f21f490c2b7d886377ef1f63d171f4b595e4001ea94a332c292fd6adc7870803e60a0f8a9d50607a2d35acef61f285ebc72479c4d4f7b73487caebddc99c65072eca60ec01543722e6423b02ebb527fbd4392ab3f3a617c89917813fe0f13de5712f80026acec24f31162b61da0a2781bc2676ef17c0eb9571c8b83b5669f22041134dc6574447832ec580337852fbe60a707747e4d4120050805fec5b36aef8d51729da48518bb27750752e7f7636d582edc45bb7cc45c6875fb80da53cdefcc845c4de6d75f593d59d06657dad71e7190551a471130215458df3b789228ab6530a8ab03af0f807228bb454ad9426e0b9dba26abcde8c2ce080b3c708e702057587db6e3078f1053ada7cb26bf2cad2c3cd54df2045b575b0f7a8925689d0344bb4655937c35fb3cfa8204a704cf7c0c8d74bfe5ba6c9e15ec26e38e46d44ef37da3466b28469a79828a99f08a4b2acb5b53b6ac6eaae47ff32d31f25b94d88aeb042b477c63e0f3bd414dd7dec80c23b22fb7f68cfeee7f2cc8e9d7d2638055aabcc033d7b563111f7fc746990f1f9bcba5a2c02dfa6fda46c53e19b150f6d7811d32d464bd76be286a36025679e47ab8cc83d79e08cfe97058872adc80e9bfd4ecad14cc948125ea34778ee0660f22bd7f6b4cdfc18f61eca9987ee73a1dde815cbd79f3e9e8bdc7ae1a03460c72326690e3ab6d68892e80ef0b28e7d7d1051031bdc8aac92f4f17b8abe7485c0dd9c4543e9ad148d7884d4bfe630f7b15d084f375d3c2246ab48992d8b251eb12af12b0fd75e07bfe05bc483b3d3c521b12206f223b24d0513faf45656fd70c4e40a2d85b06c14e633807463d35440c6e6ff9c90782677f1de6f8099f2e97cf700d04add6f380b772ff656a372f8bfe91bc16b8151fdef80d3482f7752adcc9f82c10f582f261ccc647958b3a1b34226972dde904d9ea698c2faf61adab492e3bb492060e2c2af0102e77de5bbfcc2dd0da70c87046be6e089a1be8ecd532b60d9581fcc9a75a9f97361290d2db5d2e4e5d216e8aae0851d8e3c5914b034206b99acd3627c23cc0e726c3da152529c0d0aeb2516b0375096af1da6e3e6ef8baf4bdc5285bc84ae41c351716d0252f073f149fa1e00bf834d44fb62b55f240c4cc22200144cf1b443e55e65d53af7ca9efc873f6040d98c571e5c010d88e20b85b804afdb1d42dbe07853e9934ff798f0c8f26190d28e5b3c1598ebf63781b49f1b5f5b944ef56ffff52b6565c5b96667ac49cc9536d1e7513024328350033b9a8a102aaaa49e9ecd0d0c142dc42c8faaab741240dddf76b02071c58deb5704324a5febe3709b9a87a3bd388d4376ece76ec4fa996f07618fecbb57e1a55c9cc6e5a63143d323003e935243c49552f83975569a59306521a267d826b1abc22f0db3b5db89a367f69c17053e309758a791a147408705182587226df276e11aeb6979114d6e6ea61bb45f68209215ffdc5a8c9d6fb7e775600e3710f3dd532a195a893a86a9324e7e1f5f2bf5bfe9383d6857a3243cbd1b8f726af46ab93ad06fba88b192ad46a15068027dc42131b0f482d146387b0b261a54664c81d41587a196963b55526d56e7317eff6f9859a9f580330bc37ba95be2bc8eabc45a50fe63929bd8b37f7ed3f4cb072272f50f61a66c2b25d676ecfc200a67b015a7255554d8633ec9a0025e249a4c746167c2a1060cc09d6bd69057cde004e8eafbfc6bd4574992ece5a5f6d03b9eaee48a75c72da57395e169e26041d6ed3b65b9c306254b06b09f394fda392e26d911e2f1ced495a2347e9c68138d96e1d84fb26f7e284626fcf756fbc9a4575305555b099f6832a2193c9eb6b5abb95fab25703852be6ff25ec40bbe0c8bfd118aa38f0e9554e00ba3bc7eef0213060d25b23cd6c32e5ff461d82124b519220b115b6f2f18cd3371cd837ced26b69814f0f09027cf1338dc424e9da44d1ffd5c3e0625bb2b8936d36f9430345af3e119f92994899174a0df8c0e4aefb3dd69119b7b957902caf98b1174df0e3b6e7eaf365178511f0ed1b31157730a389c558dfb71105d985c5ddf6e60588431d8adff58f0b5b6fb92ec73b16a6abafe862001f559c85850cffa583c07f0bb766af7d1a11d91bd1c51d4b2e760703b0868df98c4c79093782d7caef607b330a44e31281a812a80dd1ca1df8232a7eb9c7b12decc2ad8c1273051620fee9ba58de4b2879394a701880f75a372f50f25afaa95c4bd2318007851e1c7b04898446c8e792c9f467f169978fe22b4ff6d7f86573631ebf795e5c1ab8fe85b76022ae4b1ed6a5efc02ecfae8b8c96875a101670ec783394b3388b6bb2e49d93f35570fea9f66cb5aa13bf7c211ad307df3f270a4de667759673c4c0c8c70a740abbbf866d3ce9758c92732e8316cab0fd7b44083adda52db9206455dc03020d62863541165a35cc77dec1ff2f610d35d41e16841d87a4f2cb1a8b0e9f048c2c69649052bc798e91b8f7b1650707ebf7fd0b24509ce0e83c5d622bd0d4427262cd09752c22f3156e400fb256402f06603d1ca839ee8754f408603c21b35dffafa3ef07270f1014352be11744d77e1c365110e52cd516ec3d7258cb23037f35f963bf2eeee1ed77caaa2618444fdc739b0624540ceb791d912d077de3386641f2a1463aee3c73f61457b2d51ff1e18d5256da064a7cb04fd1682a48d26f6dc4be147e682957815d1e1c31ab208f79c254681bd008b01d9bbfd6df63fbd59a03dba903d39cb51dec5a38fd27e740310d70cfd2cd4d0839ef24e27725293f2af1d2b728dcda6fc444e3e35145c4cac1affce73b7b99181881ecbad24e47775d475fbb4869e216782ada651ce95af7ea1820f71baf1956f4cc4a487e33e1b284077e4a30509cd068d13b0aa146532ce8e10feb52e71bf2bf0476d99b634d198a1b85c4a7b8001a39d05ed4413ad53c1fc242e58a834d8d2c2c537ad6ba9d6b7e87373568b42cc3b8df4717812092c6f5ea91dbd72b59c827623bafe3999ca7fec5f1c4af8b66b305c9b138d6d79af07d0c780a27dad35ef50a711fc23a1bb70567a6754f3253090147984215275787afd2bb2c12787942e7dc7ec996f90be2173d3984206a6594899c181464fad9b78b718fdbca1ff0db5bf9720c1fceea2ebd62f0b81d943e2986eb204b6d7c64a0502c9f60458c349a1da820c25ff4341a72fea8f66251ee97f8f5721a4e691465f8f24c8454f7aa05a1f339581ca88fee21f5b27874a662eba05b2a28a8d10d17a1d8b5eb8d62386b74d8e87557137272619fbd3520c47ffb0371b04a88e548edf1e85657e912b658ecacdfc63cf007c2e3636575514ce402ea217756bc74d2f1fd8f57824d7718b7b80a27aa5bd9dd9f6375a28e009794cc8ea671e01e3c76a190f86d0647b941e779da687d1a47cefa9c52e85e4d715107e1c4e42ad65a834b403245dee643c2f7b0c355bc2aabc3e5502f6c3395899df540ff194bb0f614441b1104776e549634f217912aaf56fe539cf52436be520e49c6413af7be5f2bc567ce0b0030888491aaadcf5048e4be5534318b63ca18d24ae22ea8b84c534bb16b5e89be9a97df5f26bf9c196cbda125380ace6283f5ca1138096adc4cbfabef87ec0a214e489765302f5ba8d22d175f4c44a60f071c4a4cd70c72df3d3b679b80e8adb29f506a352b95f4a047cade72c49c8cf57f7256fc4bd2a80a76ce25bb2f69c56ef539a6fbfa5771f5b524d7c9668b9bdcf36b42f4972262f9620fd16623dcd7a01163972135544e28c7d7b3ba773eb4fc19a9f356147e87ceef0fae8239cd9af066e786b7e36f207bac0c99ca40c3fa8d174506bde6daada87881bab469fba3f374ce4d28a88b93c40275b4313f58a042bbd3661d67562b97fa0de72ddd9d3489b02508854e4496caffce26df866a25ec7e13e2402bb690d973ba0b0ace987a979de8e3c2b897018962203ffbe2cec697960adac97aa6d5789062eee3d39cba18c42c1aa6af4f22b20f1dddc734f611324debe43d44d2c349e45f16323ef62133aec203d3f3315f98377002665086077e31e210b49ac5a263cc58e55dffe61dcb46fde9b3254309d314e9aa8cdb7a578c46a797521760d51a565ca0d45d6dced98e7d215d1373d135088f434f9732b3a606548b4bbd6356c3cd6aa3d7bd785e3983016a4d81ad153813d24010ba8672d8060f538b759ec30bd1cad9e82fdd7da0a8b381603e9325978c0a466d1aadb59a29d3c71b1bcd1a9b3b0bedb29c3364e0e8ef26b85484fa43f6a37a3215fe6e3c12207cc8bb9c94b96e92b260e33e91cf90f21fb31083632b316424b7b19f2f5213fbca06f53b5091c3173b5fc94c1045e2e73f57ead0fcdb4458a35fdce2c0575225955d2f5939981731d22b33cff03fe767a013da0b22388ccf168a134b3a353513b7c2a6c4b529761a2838fddf68dfbd0a1abe473eace950cac266671f7857955fb84121e0a505a51f024bc94007a21354cdb48e884a4960c1ad204b6b55eaf941fc57fbfed7aa8af71fa142e9fb1746deacdaf0ef81a13e51d98525673b977ad737ad4fba87b7c3af16be2ca81a6b0b73040259380e99939bbf1074c47adf2990204d39101cf9449a7c29f4e21c583b7c40eca3aa0d3cb7e9f5566cb2114a70630df071375d7966eb0b79483698a170b21881c775ba624b80b668f70d714a6d87a0a051f7679852db65fb78ea5df2b5787cec29244eaaf1528b08d65169d6b9699a5598e76d9eb0390863c9ff2b96ea6991c7448c66a651474086a04d9f28b7a72e8bfb35a7eb575c1b9771d21863eaee37c14975c8826ab99b6d4d8a11ea511b60740dddcc6bd8a49b252814ad7512375cd966aed0ba3478a7ae1b3b3ffb0ca843f05160354c7c2afd4ac2ffd164f9b80c60ef761af30a2f379582d4cc9f94bd2df255983378295d436d0eb2bf3739f38eaa1577f9061662825c51cc09bf576b71ba4975b9a4a66ea37205ecb930f83327238518757ab2dfc9d25b63be8abf4d67657d5d98f9bdd7799183f9679443873a1a99160e5f1f66d2257c90baa19505fa70cec3335943bcb3dcca3028f9b34aef83f5e4355fef3790df44b4763aa7ddb5cbba7c04b08edf545e38316663b838302d412cbafb0fa14d633a3dabf53ffbcebf4f08844d5d8c333bff147af758fe9ceab7cfaeccf1fbe95cb6d96465a0bf8d6aa80cb96992fc7545f0b1098c426ddb2fed5ac2975ec6045e44b4025bc9d6c8a4a861758b92f30e5fb57f00dbe89dc7a5c6e0cd4b18ad48df4b359c814d1d7b9aa1b46cec8731ee5b519059934190fa2f7251db9d013dc3318c20aefbb428c6945360d32a598265e95d4512377c38d985bcd1b1ed0dc6a4e82173218eed37e922bfbbf00d9d5eea08abc367903b57fda42539fe2b6abca9670b23e3ce2866d7a0f0bd916551b93a0ab8c96b9a3cbe87a17fe600d691a9bd3e2d587efaedc2820060461a8b2dc3a1a178f0f7056503991b02e3e3ca5d98063d203dcc507faf5d902789acd973464bcf39e57907253c5cf18325d33a1e4b7b52c566aad61b2dd133368b1d892e904d012653fcc3bb7f8217b6cb912271a904764cc049f66a7ca75076ad6e88d7069ed7afd58e74fab8afc8eb34ada73e99d1f6657064e1396d91d7aa190e06502631f738a095baa076ba395dc989f9134b9b2cf562b344e1af1de8990c117e5423a93fbf2c6e18220fd5af039b5c40f87c05b969290d582e602e98abd58ee80e152f74c3094378722c31453e60a9167b2a6c10beba701d623d3f83fa4e77de477ee8dff968977c281f7df560e7d0cabc8ce1df034667d86b8613e8dc26268726ed726618f84e95aa27717d0a15f1c1aa21e7f7a19622df62fe68c8f539ccd858288250c23695bac0d7c97e4f4994cf2aa929edc0b13315f047ad463709dd2679023d79b06ae0deded9888c0a2a56389086c44ced7872fef9d7b6032f79be609d5009f94c89f35a31497d781aceacf77de80108cd70b72cdd70a0a96e03cb48bf429d7b8605e0cbb5e4af9ca117c509bd366ed7c6fe1244571acb410bc6f8d176426abcc73de789285187e0522a17a80aee5a7ec1f0e3ab1f7fde3e66e014b42f28e6590a56fb4d6162aa9e395ec4cf2cf54b4fa779674edc7ea49d6e837a783ea8488ff03f5d603490d1558393bcdfdfca159ea1c207885f2fa5fda4f16587238b18c45e2d83dfaa028ca2d67f0b7acb1c9935fc2301f7f4ba9bcbc06b9af3a326f611e1e9e6d93c93c11758c8092681d371bd85f25f00dcc46c1015d15d0911fa9f4b4db06e604e070bc64fb6169caf17a4844e39d3ca4ccd0efa930f91617d14bc64b2c915ab7d158bfd1a3edf99562af377bb50f371b38c6feac8424e8a034d1471d92a188478a7e41ef947052a0f2c1685a5ec2b1a66c08e5eb9d163d8e7201400a98a0ffd38ba2c917f07bb114ee0250eb2524f09abbcde8d7855bfcf44cf6430236bcb265571f1455e03c29909c9faf61bbc181120b72574627262e70792cc8149c015b475bfb19a6865aa98127ad20ce29306d624b5f1f9bf26ded991f6659a40f2f5d17b46514efb11f90afa868b03bf498392453f2e2bce86727f5eb77124e05ca41704640d5429f1d4aa3ef19661a8ad650e34f177ece60c059080d4d8149c39ab686569ce2aaff7943d992730a830f7584578fdbd3ebc98401a137e6cdeefe363838b3a2a56ea2ca66bdff94a20ef39affb210329181b356beb70545520cd5d9b4b6fcbb2407f97252acea3ed87f4218266291b9238c2a4eeda12f7ae2ef634e104c769d998216ca7392c91a65f7559e0108a636fbdc33a8eab7b545e4ff3da4a6f32fdb804f5c4c431ba0ed780d5214bc68399232a83774582743c696b89cc0ebd110ee1cb72fbf85991e0c2bd055801ae4d9484ec3c94ccf8c3f85190e64826fe955b55e4b04efe3e4cf406c0bea84c992a18af6d3640e88ab34ec92e69f4b51b7a715d2212dd768a019690f655d68d19a0805a7a53939124ee6f5b5e48b7de6bc3f9098fdb5facab6f973b5a1477c397aefe691c2099efb4fbdfbe99509f43c2f3f8452dfe1f63df92e7a0dbeecad2f2ee6012ccf33a627b33c7e2b70aae4bb7bef47dc6935ca79b085fb3094773b2367eb3b0e8d95c5a8c987fbc72d15170a3f966cd6308729a4a6e032033c781680641a0accab1e2682f7e0c19bbc3831d1b97efa0fba00b8bb99ece27370f16a6b4bd3926d4f98017d8b7a23584b34964dcc7602b368d82d2555a346b96677addc77573bed662d7862b576e7334a6223b6f36e141d06bf658bb5e47f405760322b46d37f63955bea7555f6065ac17a580d2eda371309d48759aa462bfd4067aac6730ea6391a9bdb0aaf00d7a5311c5e52a32259dc49466b2e5945f063ba34388c1b15b6900e8c1d8d6c90bb3b4e64e596024919bd4b331eb98fdf08e22b31dd59f9a791ef24c276fe1561a07f89666bee2ebc9916e94475150f9bc3e240db6a803f1ae34ad8efa474b9ffc8178a68e0ab05192f2b7a73389d47088c4a450b85838997a1404afec5cfcf9ad604a49203d1581048d1d8fa1d55a74c0da87171a6e1ed2f0f9f112460a7117a6aa267f4015f3406ff9cc475197d879e0301de7b2abe50b0cbf6cf55d3548f6104705be4b5216784db2effcd539a7956498ba4a2bcde46eaf08cc8baa5316d993b54599bd3b79201880e233c1473b196abc3d15da0b9cf5e51a82052bbf09af7c0e02290ebc360b63e713102ace0446810e80936f234af849dd6d5783cceaffbcc7e493d695c943787b51ff33a7d9ccbd2008ba86035673c8e8670d543ff3b2ba40387de9d7bc0419ebfa88e34058fdf39cf650c8a291446da83f976ee9bfbbe48385601dd0bcb5f2d85834fabe0fc0957338b04576ddd9d1c2fb8e65a36968d7c0e80d797b096603ab4436c3e980553c94808b4dc74e2e66afe93786afa9f2b7e521fae7730084b6ab8777fbfe6b7ba34a0504806f44ce87d02b9abe856a24baac924e6b1e9b0e4f666dfa8aee90d07135503bf628a3a8578b702673f98a8a81cd7833ccff398d692363c82a845516efd2ae4b9a74b72dd0ee69950113c59e61b31203d618882d73a7eba59f932a7b2aadcc971b743a65daed8b0c8d61d146358220844e4eb32302fe5ea871259374c57bb0f62195918a954ea74519530a6e960f38cfc57fe7dc575dc33697fef0ae3173bf23f359dab53fb25741ad295f2ced8924fb1902894e94e195920ea5596e49e05b3783abc3b946faae16c8ba8b3f9b1aa7aeebade70a9fd0b52ead76f176f355d7de239f77e63b038526144e1b49f6299c89fa3e18db1b3b0fbcccc40d0028c043e9783524c4b85fc6338fae6973f5293a55d9c118339777be91bfaa3932eae0f8d7525109a19bab187ca814a484ffce65f413a8ea22ea627f6ecc03a149f9254d45f9d5956e2083493e6f8aa874aeff7c6429d1a18335175c294377694438d3037b96e4aab9454f7dffef76b5813d31a5f377dddcc01e1ec860b88b5b67be6abb889d82da155739dd4860339d33e7ed7d2aa309646bef3390f43f8e1b8ee75468f9c89c8b798febe1acdd493858c3121e9d1e0c4887d9eccc200b7b6492656fd6e22786b6adbf49a0e11456da10afb1d3e896d10ff2c637c0add4e44b9d0156f599b4495ead0c91574cba37c422e5b67d3857e9b035c232ffe1173a387544f1d3735193e00d52bcd0a08402691955c0ec3576209bdb30d4b3dab09d2cf1731e9f36820ffafe6f1e958239fe606a4adde758c5a2fabd59f2a143aa9ff8e5f9b4b8e06eff7750c4d3b2e9f785f332ee74db963c0aad8565fb8f43852a2bba1c04c401f6ab2cbd33beef28da3d399ee4ef17bc8ec2edfb5a6d666e70a6038b6c92c3501c901b1e56510d9059d2f94b7c3e098f9237f62839dcea1dfd1df8daa3919321cdf69efa80b3c2c1b106dbf0bd644323911b0ecfacada1cb3ced99dc03a21781699af040c49cd45dd6292840951e0171922275a557720613e73638a7f0867090293a965081048cb13d17b76f5136ce638c70646157ee7e447a33ca6019d0d778f773ac2d14df176dd1f497cb0e8b7a97e4f71da1874db722b19dec913732aebac806c797798cbe1feec74a86c2f538e8125407db0b2e6edfd2f1b02d05c43e508641338204e633f278a92d1e4baa33db9b892d0c42e509ffba299949cfeb39d47220e65c0b47505d2639c92fa91afaaa31a11bc5d31db74782e1595ceed4b699e259df053642cb27feae1a5a6883c54ca9b5efbe8b802f94a14343ef10a1040649e29b9b886475942b32c57f68e7434d8756641d3d5b101dd36e09483e93bfcb4f25fc7c515779489b8c0a000a9980f21a50dd14c9b2c5d8c396dbde7a69d6d20e95f114996bbab845ac2944f9a81fc5ac476cbccda30e85acfc5c04b84f566b47dac340206744e800a7f4f54c4a7ff3b2f9af933d57ce277b334ad22f686d5603632bb7e2f08a8258ae75eff36b0d97f3d3613ff39f8730936513b8cd07542da0763942b20e66cc32fbf91600cdf92e7fc5255a6adbc1a3bfb6707d19a4c9f61261ce12387ec59d44ea032d10a282f038aa4907eb6fe8f317a89ae74ea6c1489dc3afa1d7d770e1d57d3db0a154ae981469129646f31821e1dd4cdd32d9bbb53044a9a84a52a97cccd41ac38d56075472104c6041a0776fcb067037f3a9117a7ad4c0e08210a35540aab1fe1c3d27535b8d0453ecbc2467a67d9b70b1a8006b7968a776532b04e6f688082651ad296d0b302c7908fdefe09320a67be5775025929120a509dc7dec726c8a0e82aa664a40972ade66cef98ada9cd14c77a11ff055d136c7fe89d3df498973dd5464586c80eb0e53e0e48370eef6faef20dcc95ae3b449920005194bc928290b0bacfc49e12a676f1f23c4cc1bc33dc6cbd86358fa9a30aa89eb2483c3cd6b83cca79891d0160de91d4ce57d5904007ef581d439586c80bbf1ae709f57f55db82553ae0bc18e6d47c2fcae7afd536b90ff52675d0133120dd85612fd7555cbc558343ea08806b1bcf3b7787f2c613080c4e2841489bfb180deb1b60cbc8119699b036dc0f1194c1a4070e8b91d30b7c47ec61e0bb6da86eb29c3ec1ad236aa1232a6c9abd2a1cc47c82b75c9f54b2b8956e9ba3aa11f82c98c1465d2108d0ceb71f527047a1a8160b84aa5fd28eb6f4f477964c3361cc1a20f5f9d0b66b5a8ced1f1fa37f868c513e6da1abe9fff7fe66434276703f6cc0612af0bf5f60f248735019c3140f05281e269d7f002ea6928ec0e8c18eb725b5351134a9ae9f7a6b067b2308a48145576b9019586725c23a80cbc830800c9ad1b9232f6ca0358eaeb361ffff7846fd261068ad6baed747b3dc550b416835fe3ce67ddfc698ef683804c227cb2302f6d82e85c5512f88539404f613a0ff0d438354ef7e52a28a36b98f66a805dd74484d6f3f73f0dc28edf76f3a7430a6130315154cf2550d953ca377bd83fc5df978058357fc6b714a52bf116c630b485916cfecc2b9bbf1b5ab4ccf26da8d1fa2a115ce51e09ae1c07596027f971273d977d42a8bce76daa6649e31da51709cb1cc5bdf9f7a8d25904f8f384531cd881e57b93cfee106e48f53946be9de00526872b46a40ec0abe3a6992b4f52c12643dcf8c0f4d4185eddad2f9d257eed1f49c18340871ff32de637892c5fa825e1227edad6f21dc5f808e08ffb44ac4e275f100925456630effb7e03f091cc7860c9698abd34b56171541edb31bb515a34b84a8d89ea0fbfbe7b2b8c88ddc963f8fa39da45aa99f3aa5693210f20cd848808dcbced3f730f0336b338456233bf5ec5b21df1a2a09f2379a8595ea637fcba01c7f6b765e330554e1966ab7219d004e855df754f5f0f1df247b8e9be7a1aae56a3fea12b3c4f376625b3c1bd50acf0da503314c38bf2c6cef380265fb62879c94d97a552f24fa431ca2a44f6c9c9c4baa2ad1169d3e95c75b29ef3c2922609cd4e08d7f38c3f996f79ce3353a6b79291b3490983a6b54126935b683f1e85e384909f2611f7f127149251b84c741700dc09372ee75bd35cabe2f4d78613d190d84b950159e0136fde672b03a1a3819679202df50d2e72a780e18bd1941bdd9d5284e0f3ad5ed2bfb8fabe287ca2f17267ca7a91cd73f15d2f7b4b9e40a0642c9c03adf2b2d276a2fd0e17991e6f9de0f7258e2a47c69f2544cb02aa8248f320f5967fc5a27cfdd3e1ab7887f2cac10640e1c872d29d01118aa37ceff8b9c7ce4522338891f168bf5c0b5322e003c57d679d9b5f4328f69a05c8fae75e1c7d893a96d759285341473fda21d0e33df6e7e01fd7f8b8fee4b6a3f168bb18e97175f19dbcf56a70bd985612d8e545b6c006c80202e53a1a2742bec72b68c03b36e7a08e9fff36973cb7888cbddc139d3bcff7f9bfb24fabf5de213c293790a9f878e43df13a17dc5828188f51b750bb7373cb932d85da51f8b23b37258e1c2fdb2a823986fcd4149e0d90b8a81b8fd59029b28d27e207e0cf2d4597c1ad425ccc655809a5e6bb1d6345509ed6c8af83685cd76b20de12c3a8dd23f6fb30263553f86d481f91f3c1d43b596ddf7eda69f5897a8ce6b2d080a9380bbb5af7eb3285fcb23d28eafb7648fb2065da3e52c8dbd0fd2bb195e87c2ebeaf72183e521347c2d69ce72ca4bef390868bec18586fd0d77282a92d7ac9f75b3bf58944485a236632f7d22b93984eae51fcff4f452829ea085fcc3fed18399f67240a8028fc578f8fc99b3e896fb845dd593a493e9706a174d89c0136e51df4e04b5a04c4cfca4130a830264fc3f3b7519bb81ccebccccf3a50a666006b264db55c68efd0a03e3c821b4e0aceed5eaea23a70d14956dabb9596674f2caba60f70e50d2733d8c1da23c7c6508eb6e16058377a07abb5056220bc98597969e33ce10d12cbc07cbea15f0195849a22629163755f829fad8227edc54c0a10039680330e490803ad441b8195afdd1ee7f9915f0b6daf48e8d88f46697ea697857a209d8b2c36a8dd89537b9454f23cef2d20258c08cb519dcf557d163a938db68e7058b6c6251380e69da1e751640fa32c12351aa0fd67b7662a65a3ce96f18b417bd6730a57bedc6c020fb2d9f39b2476afca83e7ac3eef594bdbc842b12f2838effa939b2952371af51144b1fd836bb63594501869dccd34f516f26f5251a3b05172eab489da8b4102b69276cc72c4a35502bdf92ad5d857616cf4dc9f919af32c2885aa928b9a8f432316f80101611772def843dd4be19d7bdaf083599b2a9a792bda771f4f4f646d9504fd3c29f8564c616e8820c48bb41898fa309168dde2ca94a0d45c84f950e632cd658c04fde9fb4b8c5ad242713137a21ece27c0fe739c197268e6a6528a158ae88a7eafc34f8ae4fe0f7cd04ec2e33dfe7b042a965e0f05fe2e3ac30f9f33698912aff56edf5756ec081b01b2816cdf34169b6064e69486e87fa0cdc7ecf330a65334fc7d7f7bbf08164466d956b0cc62cfe798fb4d6bd3bc4a429d5eb1d196177aa2ae5f31ae21dd3e7cc524da63a556858c0ccf6b3e0616be091f585b318f4f0c2a8622d0d9684dda67c3d28808495e8efd62b1f0fdae157e961c6c5bee6ee63b90cc61f612088800418609c3b197b7409d7bcd8a53369b4a9bc962548ec50fd3b752c88c6ae41785545617b49da4052fe9ed173899f98271e065ea8cf4d70400128a08c99e153a78efd9a24075b531e71ad876854bb22c3108229a55704627927535b43cdf4a438f046fe1785811347acc2004a91e9c60aa87ed660228f145f29e65e0f774d674a6869262aa14ade1588c4be8f198bf8e7df619b0e4331a5931a2e8b1246bde1938685266c8d6c4913cd5c6d5a278587c789176dde4bcd4390246123c8eaf7230b954f15d7b3ad89df310271a52276afe7a875509432a7658e6b96206d93e5b28056df1f10c9c4a35f40c1131f30290e7798e61d197ca0ea29d9edfa23bd269cc68b022a0236e2bf6d49f288641edd012ba7bb40c130ed612154f0ff101d43a924d06f9199f55b9dbf5a834d251957537db3d7d817be1de33bff93a56d72c9b3fb6f8a9050ec425bcd7666dc4677e954295c61d47743991acee7e796bd682080daa5fa12e314287337674ea0c0394b1e3660d8a3aec378fc8e2e1a159bab309bc2e3dc4a32744c9bb7672d2cc8f193059797683c8614abd3f9f8be9d255fba4cb3fbcd5023a3ab1118590b6b93c65d2440fee25409e92a246622edac62103c7bfaaf22feff70e956d64528b7c4f91e84197524a77807e68bd0a3933a96b488f8f02e5220b6577dc672b9a8b7d6ddf90ff6b585bef46708062b14438a4f3e950239e533a6313fa39afd4952307c996e359629da872755c30fc16b39a6a94cfd862ca86fe13b979b0ac6735ece74be12072ac15941fe6b0337f0ccc2e57c38a764390141847b855015c8b02bfd97fe79ba4a90a58d5ee2a17a734772ce4131d9323b4d5ce1d8df2c339489d7f862320c62357ff37c1b09f627f6f116599b51905402812a45651aad8e420bfc1ca5c31d9046a48bde485f2d326f1c775904afa48790dbc0ad56e1062fdaf4c88dd82645ff648baa453deadbcc18be9f94a8539650df746d13a85db47d45c8268a7c1ccc7c3a4245fa8eebdfdc0b172dc360201002afa077fa07fa5543960a82f81d81417f8d7c3070c3bb5dab0128a47838f2c43ac7ea4bc75b73afbab9fa42ee0deb10b93aaea0059bc38468e3e2b511833e5ebb0062645048c6106044866ed52d331a21fd90e9d2918d1e2b9e60110c6d1dfed8cab1a7e913ac3c4bd681493d398a0fc64108f7971c30184b5b202e69750f1d53140c0809a974341550e5faef1392a266c18333a19e48eafc6252138c7bf610aa440efee6ada47e619a1be9b9e89dbef8df1aab0446daa2e7f3ac9ceeed93886be8b63f56295bd43bde11be741238fb5754ef749df2962088c089adcb47612f1cf5a868e4c0a0c2437ecb5759da41989899951f96261d31343dc131de60243f48384e06faa87baac8da66ac6323a104f3c1b9013f79d9712befaf860c639739de3ab7f6f1376dd99cb7f6c8aa42fb0d0f2dc586b708bf2b8af0e681350663125e913f7c8f2cf03d566acc35f09bf46680fbb699bdbc06d2af725cebcca87caba9553d5fde4248360dde795a78dad54241cce04425902deab8aa6de34fea7ec003a8b9e94a1c82eb83ff19cf2ae9a5ddf59d6f5e0e96ade83eb8a07072fe4b497b26c09843f98a89d10719a4899c886240f395a527055b3b6a8f208bba4cf495dd8b04c5c4f684331929d638400cb8b4927368e7a2365753cdd5f206545a022cb412ae27176214efaaecc0578b9dc9b87610aea8dbe799a94c6ea88bf5ab3945534addd3f63d76856a0360a1eb505abb4be88ef6b571e8a692453f7b3c6e6051d5cc27bf7715af743dd6b6067ec7fb3e13219833198286ea8315faa6f367a606d8148972617d044f9af75f9f62e7db95fcf329273a8d3a328047cf1d25686cf6a696f5127ec71cdc7d5e1ecb212d8fa94f38a7c84d5cb5730f0a4ff8f70b4f41996092cff2ddd991ab30e22ba1ac0144ca776facd476ca07cb50d9289a234e9faf84926e322d271368682f3a0d403c7c80a04c48788742fd29c567806640b7f1bd8d1dd961d92edd846aead2d9f4ad6c6363b35ed5e7f872c32194fa6ff03d3696f2bf78f055e4019146b144ed1ad63be7c3022dec556cd8d2f3a0bbfe725ae304de8affffa097e7f8e2a91bbe59eb6cdeaa4246cff640dcf9824768418535effe74534331242e689734fc393ff38a8f3e88b450112ef26eb58df6d45d4c677aed1e7cfe1e5a681bb5f72aeace6b762cc72408cb004ec049c1cf4a31701068a1c7058cd2f0e98df911627bd791a85817cc503906256240fe4f830ebcc290ce216dfe5b6331d3cc612098e39b821e314b37858a40d1268f31f23bdb75ea64a5bfe3cbbd9284ea4caa57bc27ed3501e2419aa407e5f7b7a5dc7c64566f4abeaffb54d094357eaab85314c953a520eede2f4bbf2784b3cee19c5420e2d5a6a8b86c313605f16731ab67db8c8310290332d36e5dbb4d9a186c89753aea1f88fd6eee5f8f85ad00a237d9dab8e46f3d9755160b4a2b64a325396396af758755659abfe1bd31878a207c3fd141977a92ca93d3b3b7b37e8b1aa2de5c286d8032d1eb578f003e528147bd13c716756ac447eab3a0f57f3039b6f9707d10c282d91bb25bb6699af986ef5ce64df7bd26af607e41f664dbc228c9f0d8cc9cac99400b16842adf4c97fc4393040b5e5a2d7ce2df540cd9776500002b33030000000000000000000000000000000000000000000000000000000000cbaba2b1bed66214c277413dd7a68c0df51163db42b7d8086855b2a1bed799a250306269e9ebb91cecd71fa65b83b169139aa2b1d51147d246507fc10ac3ad25b37e8b1aa2de5c286d8032d1eb578f003e528147bd13c716756ac447eab3a0f57f3039b6f9707d10c282d91bb25bb6699af986ef5ce64df7bd26af607e41f664dbc228c9f0d8cc9cac99400b16842adf4c97fc4393040b5e5a2d7ce2df540cd9fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdffffffffffffffffffffffffffffff8c0b22e8d378c362545ccf089f83e37846b45fc95eb52e71c26d2c222946ed765cf77fc50441c0b4d3b26dbf606fcaf71310128438846a65747a0c9089992a64b86d042d6725135e885024e11cb32719d6fc7b7ba44fbd996ad0ea64ebcb12deab65660000000000aa65660000000000eb71070000000000fcb6c164773147a712fbb0bce05010b8791f55c5ca76eeb0c04aa3ca7dc27c05dfd9e9eac6a715f5d984380a32bbcbd84dbf32b6bb8ee7d497ccaece223091c0a5ff697cd91e966e92a4a306ad61f53fd0f9b771ff1c6848bc6e54764a2b8fdaf40000002c3393704b6e144d3ceee58489a90f69abea2bad6d20498cfdf820bfc425e317336488033fe5f3ef4ccc12af07b9370b92e553e35ecb4a337a1b1c0e4afe1e0edb56114e00fdd4c1f85c892bf35ac9a89289aaecb1ebd0a96cde606a748b5d71ab03d246092331a558c79a7afec160d02cbe7f0e20eedd6b15ec02f832323738b96f116d0383f3e5fc6a0fc68cebbeaf844af59cdcb6ef985621348442d8940c690b9a9e9aa1c9db991c7721a92d351db4fac990faaa1c0f3d26919676230214a9f513e4e65acdba48ed60b2ebaef60716d3b025eb916bb8aed8e9b55caed5a3fc5dff2d308198c26642803f82ae75466dad7c4717314f236da25bce94ad383fa29f2329e126f5ae3d83049a637fa012da9a3d21d576c7c5d2307e7978f4f7426718071b73210ab7ff86bcbcf3707287197fe36b04d3dd08cd16a96beeb3d3fc5a8d48e9cba2b71444ee1c9a4ab39d5dcf304a503a1c0203b781fe0f6861dab609ffbacdfaf1fe7a891c4efcb752a1ff0d3ccc404a6617f7628052bd055c113e42b3a91ff6ce91fdef1ea7bb8f7a6b62e2d22a18e70a11eb0942e51afeff79fe97bf87a44445541fe95e29f384f46776924c417807d68b2ea4f0ed046c920127847e730a65ec948eec6f215c1d975187da20e23ed3baad7b480398b06a4dc3bf0dcfcab487e1d510d3b8a06fc949b9ffaedafc0b7ee56e0f13183e05d8fe176d56da0b98fbf1696d868e334a174cb15a8d20862e7f750b010000000080c3c901000000006e9b4601000000004ff492640000000038020000f87c8668050000000000000000000000000000000000000000000000000000009c4297f072de8d2dad3eaa129e0b68c9bbff1ce399714c4d8c604594f4b02b972e08e5688095baf5b9a28e5068c4228b0380b420a6ff0506f7030406a0c773d74dafac0384726cb1273b49d054eedf30829d1beeb951dc5a79ccf158d3834dde6275696c646572307836395f656600000000006b55060000000000ba22e236ac727bc8f4a7b0b5009eca1c4d5bd9064abd342ad7d0e8671e28084331822134cd1811991be820abdbae380725db94705ad88f06c92bd252aed1362f7ab3ce9a383c3e794755c770e9371a07fee31cbf619cf0572f97f8eeb45950ccf4000000066689db3e612aeab689f216211aac277766d546ef178df9595d19cac566ab64336488033fe5f3ef4ccc12af07b9370b92e553e35ecb4a337a1b1c0e4afe1e0edb56114e00fdd4c1f85c892bf35ac9a89289aaecb1ebd0a96cde606a748b5d71940c9e2fcdf5b2feecc20339bc42a76f200f923f264f67ba033d7ea27924fb58b31977868960ddd34566cb0c99f7c8d226a372aefe4a2cd056640840cafde7e2690b9a9e9aa1c9db991c7721a92d351db4fac990ce8a4c49668ff3fe3a778fd373939b6ca28cd1436c7ac9a59b5ac562f3388f0779d8b41e8c68b8b75ee1463e8ba77879626a6b147eccaef5e12a8698c2a830388d63a3fd458a1948f41a6f83f05314b57874469a884fd3006bad001e7aa0b95bd9b7ff2ae741cb35d4f4b3334a9867b12727c1f5ff8e6956f2720a57f17d27283af4f6cdcf89893e490aea5c925a78bd86111d50dc56b91594507d49c97c89899a24e9f7122edd2de4e9ed36ef86bfcdfa792671e01ce4460253ecfe8a5b57577c10965cb0bc2f7995cf15687b967f24d833f0effb230e9afc2dc6e3c0db1320ceffe64769bd72ab5a10c1c7bd3dae608c6142d0a1b92b8e29e28ef72ae0d2cbed387e1b11411d58161824b8b0ff3a56711fc64f8f29b83cafb779ef8a93e63cddbeec6e9da7830d4e874cb008421e95b596b87661aab2e8ab6f3cb0fcf4fcf92bc75b4f36595710dae61ebe6763595994148bf06d1c641fa69cc4002d18b48136750b010000000080c3c90100000000b7a6b20100000000cbf09264000000003802000049f0f2cf040000000000000000000000000000000000000000000000000000000f5516795996b9f2310c2002b3b20619b9ac4536a4d4bce4641722056d64d0a5c0b9bc2b9c8c4b4c469be2e86d6eb609560dd56021fdeb22c377cf19956a3f08e1a663a4eecaf19ff6b472e8f71bf294308137816f998e4b7f95d4ff19590aa1406275696c64657230783639" } } diff --git a/tests/rpc_server.rs b/tests/rpc_server.rs index 04fdb48cf..8f013f622 100644 --- a/tests/rpc_server.rs +++ b/tests/rpc_server.rs @@ -6,6 +6,7 @@ use std::net::{IpAddr, Ipv4Addr}; use ethers::types::H160; use ethers_core::types::{Bloom, U256}; use ethers_providers::*; +use ethportal_api::ContentValue; use jsonrpsee::async_client::Client; use serde_yaml::Value; use serial_test::serial; @@ -123,7 +124,7 @@ async fn test_eth_get_block_by_hash() { let content_key = HistoryContentKey::BlockHeaderWithProof(block_hash.into()); let content_value = HistoryContentValue::BlockHeaderWithProof(hwp); let result = native_client - .store(content_key, content_value) + .store(content_key, content_value.encode()) .await .unwrap(); assert!(result); @@ -132,7 +133,7 @@ async fn test_eth_get_block_by_hash() { let content_key = HistoryContentKey::BlockBody(block_hash.into()); let content_value = HistoryContentValue::BlockBody(body); let result = native_client - .store(content_key, content_value) + .store(content_key, content_value.encode()) .await .unwrap(); assert!(result); diff --git a/trin-beacon/src/jsonrpc.rs b/trin-beacon/src/jsonrpc.rs index ce17644cf..7ccc34a48 100644 --- a/trin-beacon/src/jsonrpc.rs +++ b/trin-beacon/src/jsonrpc.rs @@ -3,11 +3,10 @@ use std::sync::Arc; use discv5::enr::NodeId; use ethportal_api::{ types::{ - beacon::{ContentInfo, TraceContentInfo}, content_value::ContentValue, distance::Distance, jsonrpc::{endpoints::BeaconEndpoint, request::BeaconJsonRpcRequest}, - portal::{AcceptInfo, FindNodesInfo, PongInfo}, + portal::{AcceptInfo, ContentInfo, FindNodesInfo, PongInfo, TraceContentInfo}, portal_wire::Content, query_trace::QueryTrace, }, @@ -238,7 +237,7 @@ async fn store( content_key: BeaconContentKey, content_value: BeaconContentValue, ) -> Result { - let data = content_value.encode(); + let data = content_value.encode().to_vec(); let response = match network .overlay .store @@ -330,7 +329,7 @@ async fn gossip( content_value: BeaconContentValue, is_trace: bool, ) -> Result { - let data = content_value.encode(); + let data = content_value.encode().to_vec(); match is_trace { true => Ok(json!( network @@ -354,7 +353,7 @@ async fn offer( ) -> Result { match network .overlay - .send_offer(enr, content_key.into(), content_value.encode()) + .send_offer(enr, content_key.into(), content_value.encode().to_vec()) .await { Ok(accept) => Ok(json!(AcceptInfo { @@ -373,7 +372,7 @@ async fn trace_offer( ) -> Result { match network .overlay - .send_offer_trace(enr, content_key.into(), content_value.encode()) + .send_offer_trace(enr, content_key.into(), content_value.encode().to_vec()) .await { Ok(accept) => Ok(json!(accept)), diff --git a/trin-beacon/src/storage.rs b/trin-beacon/src/storage.rs index 331bc7dbb..dfb6a41bd 100644 --- a/trin-beacon/src/storage.rs +++ b/trin-beacon/src/storage.rs @@ -10,6 +10,7 @@ use ethportal_api::{ ForkVersionedLightClientUpdate, LightClientUpdatesByRange, }, distance::Distance, + portal::PaginateLocalContentInfo, portal_wire::ProtocolId, }, BeaconContentKey, OverlayContentKey, @@ -497,7 +498,7 @@ impl BeaconStorage { &self, _offset: &u64, _limit: &u64, - ) -> Result { + ) -> Result, ContentStoreError> { Err(ContentStoreError::Database( "Paginate not implemented for Beacon storage".to_string(), )) diff --git a/trin-history/src/jsonrpc.rs b/trin-history/src/jsonrpc.rs index 50f770054..ff8cf8e2c 100644 --- a/trin-history/src/jsonrpc.rs +++ b/trin-history/src/jsonrpc.rs @@ -4,9 +4,8 @@ use discv5::enr::NodeId; use ethportal_api::{ types::{ distance::Distance, - history::{ContentInfo, TraceContentInfo}, jsonrpc::{endpoints::HistoryEndpoint, request::HistoryJsonRpcRequest}, - portal::{AcceptInfo, FindNodesInfo, PongInfo}, + portal::{AcceptInfo, ContentInfo, FindNodesInfo, PongInfo, TraceContentInfo}, portal_wire::Content, query_trace::QueryTrace, }, @@ -218,7 +217,7 @@ async fn store( content_key: HistoryContentKey, content_value: ethportal_api::HistoryContentValue, ) -> Result { - let data = content_value.encode(); + let data = content_value.encode().to_vec(); let response = match network .overlay .store @@ -309,7 +308,7 @@ async fn gossip( content_key: HistoryContentKey, content_value: ethportal_api::HistoryContentValue, ) -> Result { - let data = content_value.encode(); + let data = content_value.encode().to_vec(); Ok(network .overlay .propagate_gossip(vec![(content_key, data)]) @@ -322,7 +321,7 @@ async fn trace_gossip( content_key: HistoryContentKey, content_value: ethportal_api::HistoryContentValue, ) -> Result { - let data = content_value.encode(); + let data = content_value.encode().to_vec(); Ok(json!( network .overlay @@ -340,7 +339,7 @@ async fn offer( ) -> Result { match network .overlay - .send_offer(enr, content_key.into(), content_value.encode()) + .send_offer(enr, content_key.into(), content_value.encode().to_vec()) .await { Ok(accept) => Ok(json!(AcceptInfo { @@ -359,7 +358,7 @@ async fn trace_offer( ) -> Result { match network .overlay - .send_offer_trace(enr, content_key.into(), content_value.encode()) + .send_offer_trace(enr, content_key.into(), content_value.encode().to_vec()) .await { Ok(accept) => Ok(json!(accept)), diff --git a/trin-history/src/storage.rs b/trin-history/src/storage.rs index 2ac3a06c2..adf64f750 100644 --- a/trin-history/src/storage.rs +++ b/trin-history/src/storage.rs @@ -1,5 +1,5 @@ use ethportal_api::{ - types::{distance::Distance, history::PaginateLocalContentInfo, portal_wire::ProtocolId}, + types::{distance::Distance, portal::PaginateLocalContentInfo, portal_wire::ProtocolId}, HistoryContentKey, OverlayContentKey, }; use trin_storage::{ @@ -68,7 +68,7 @@ impl HistoryStorage { &self, offset: u64, limit: u64, - ) -> Result { + ) -> Result, ContentStoreError> { let paginate_result = self.store.paginate(offset, limit)?; Ok(PaginateLocalContentInfo { content_keys: paginate_result.content_keys, diff --git a/trin-state/src/jsonrpc.rs b/trin-state/src/jsonrpc.rs index 03aea10ff..d6b391822 100644 --- a/trin-state/src/jsonrpc.rs +++ b/trin-state/src/jsonrpc.rs @@ -13,13 +13,12 @@ use ethportal_api::{ types::{ distance::Distance, jsonrpc::{endpoints::StateEndpoint, request::StateJsonRpcRequest}, - portal::{AcceptInfo, FindNodesInfo, PongInfo}, + portal::{AcceptInfo, ContentInfo, FindNodesInfo, PongInfo, TraceContentInfo}, portal_wire::Content, query_trace::QueryTrace, - state::{ContentInfo, TraceContentInfo}, }, utils::bytes::hex_encode, - ContentValue, OverlayContentKey, StateContentKey, StateContentValue, + ContentValue, OverlayContentKey, RawContentValue, StateContentKey, StateContentValue, }; /// Handles State network JSON-RPC requests @@ -270,18 +269,15 @@ async fn recursive_find_content( })?, }; - let content = - StateContentValue::decode(content_bytes.as_ref()).map_err(|err| err.to_string())?; - if is_trace { Ok(json!(TraceContentInfo { - content, + content: RawContentValue::from(content_bytes), utp_transfer, trace: trace.ok_or("Content query trace requested but none provided.".to_string())?, })) } else { Ok(json!(ContentInfo::Content { - content, + content: RawContentValue::from(content_bytes), utp_transfer })) } @@ -313,7 +309,7 @@ async fn offer( "Offer", network .overlay - .send_offer(enr, content_key.into(), content_value.encode()) + .send_offer(enr, content_key.into(), content_value.encode().to_vec()) .await .map(|accept| AcceptInfo { content_keys: accept.content_keys, @@ -331,7 +327,7 @@ async fn trace_offer( "TraceOffer", network .overlay - .send_offer_trace(enr, content_key.into(), content_value.encode()) + .send_offer_trace(enr, content_key.into(), content_value.encode().to_vec()) .await, ) } @@ -346,13 +342,13 @@ async fn gossip( Ok(json!( network .overlay - .propagate_gossip_trace(content_key, content_value.encode()) + .propagate_gossip_trace(content_key, content_value.encode().to_vec()) .await )) } else { Ok(network .overlay - .propagate_gossip(vec![(content_key, content_value.encode())]) + .propagate_gossip(vec![(content_key, content_value.encode().to_vec())]) .into()) } } diff --git a/trin-state/src/storage.rs b/trin-state/src/storage.rs index 5e4a3ab39..9a59782df 100644 --- a/trin-state/src/storage.rs +++ b/trin-state/src/storage.rs @@ -4,8 +4,8 @@ use ethportal_api::{ content_key::state::{AccountTrieNodeKey, ContractBytecodeKey, ContractStorageTrieNodeKey}, content_value::state::{ContractBytecode, TrieNode}, distance::Distance, + portal::PaginateLocalContentInfo, portal_wire::ProtocolId, - state::PaginateLocalContentInfo, }, ContentValue, OverlayContentKey, StateContentKey, StateContentValue, }; @@ -34,7 +34,7 @@ impl ContentStore for StateStorage { value: V, ) -> Result)>, ContentStoreError> { let key = StateContentKey::try_from(key.to_bytes())?; - let value = StateContentValue::decode(value.as_ref())?; + let value = StateContentValue::decode(&key, value.as_ref())?; match &key { StateContentKey::AccountTrieNode(account_trie_node_key) => self @@ -84,7 +84,7 @@ impl StateStorage { &self, offset: u64, limit: u64, - ) -> Result { + ) -> Result, ContentStoreError> { let paginate_result = self.store.paginate(offset, limit)?; Ok(PaginateLocalContentInfo { content_keys: paginate_result.content_keys, @@ -129,8 +129,10 @@ impl StateStorage { let trie_node = TrieNode { node: last_trie_node.clone(), }; - self.store - .insert(content_key, StateContentValue::TrieNode(trie_node).encode()) + self.store.insert( + content_key, + StateContentValue::TrieNode(trie_node).encode().to_vec(), + ) } fn put_contract_storage_trie_node( @@ -165,8 +167,10 @@ impl StateStorage { let trie_node = TrieNode { node: last_trie_node.clone(), }; - self.store - .insert(content_key, StateContentValue::TrieNode(trie_node).encode()) + self.store.insert( + content_key, + StateContentValue::TrieNode(trie_node).encode().to_vec(), + ) } fn put_contract_bytecode( @@ -197,7 +201,9 @@ impl StateStorage { self.store.insert( content_key, - StateContentValue::ContractBytecode(contract_code).encode(), + StateContentValue::ContractBytecode(contract_code) + .encode() + .to_vec(), ) } } diff --git a/trin-state/src/validation/validator.rs b/trin-state/src/validation/validator.rs index 5ae03a0b7..a4efc45ce 100644 --- a/trin-state/src/validation/validator.rs +++ b/trin-state/src/validation/validator.rs @@ -29,7 +29,7 @@ impl Validator for StateValidator { content_key: &StateContentKey, content_value: &[u8], ) -> anyhow::Result> { - let content_value = StateContentValue::decode(content_value) + let content_value = StateContentValue::decode(content_key, content_value) .map_err(|err| anyhow!("Error decoding StateContentValue: {err}"))?; match content_key { @@ -161,8 +161,8 @@ mod tests { use ethportal_api::{ types::{ execution::header_with_proof::{BlockHeaderProof, HeaderWithProof, SszNone}, - history::ContentInfo, jsonrpc::{endpoints::HistoryEndpoint, json_rpc_mock::MockJsonRpcBuilder}, + portal::ContentInfo, }, Header, HistoryContentKey, HistoryContentValue, OverlayContentKey, }; @@ -180,16 +180,17 @@ mod tests { } fn create_validator_with_header(header: Header) -> StateValidator { + let history_content_value = HistoryContentValue::BlockHeaderWithProof(HeaderWithProof { + header: header.clone(), + proof: BlockHeaderProof::None(SszNone::default()), + }); let history_jsonrpc_tx = MockJsonRpcBuilder::new() .with_response( HistoryEndpoint::RecursiveFindContent(HistoryContentKey::BlockHeaderWithProof( header.hash().into(), )), ContentInfo::Content { - content: HistoryContentValue::BlockHeaderWithProof(HeaderWithProof { - header, - proof: BlockHeaderProof::None(SszNone::default()), - }), + content: history_content_value.encode(), utp_transfer: false, }, ) diff --git a/trin-validation/src/oracle.rs b/trin-validation/src/oracle.rs index 46a3b80c3..4364783fa 100644 --- a/trin-validation/src/oracle.rs +++ b/trin-validation/src/oracle.rs @@ -8,13 +8,13 @@ use crate::header_validator::HeaderValidator; use ethportal_api::{ types::{ execution::header_with_proof::HeaderWithProof, - history::ContentInfo, jsonrpc::{ endpoints::{BeaconEndpoint, HistoryEndpoint, StateEndpoint}, request::{BeaconJsonRpcRequest, HistoryJsonRpcRequest, StateJsonRpcRequest}, }, + portal::ContentInfo, }, - BlockHeaderKey, Enr, HistoryContentKey, HistoryContentValue, + BlockHeaderKey, ContentValue, Enr, HistoryContentKey, HistoryContentValue, }; /// Responsible for dispatching cross-overlay-network requests @@ -64,7 +64,7 @@ impl HeaderOracle { let content_key = HistoryContentKey::BlockHeaderWithProof(BlockHeaderKey { block_hash: block_hash.0, }); - let endpoint = HistoryEndpoint::RecursiveFindContent(content_key); + let endpoint = HistoryEndpoint::RecursiveFindContent(content_key.clone()); let (resp, mut resp_rx) = mpsc::unbounded_channel::>(); let request = HistoryJsonRpcRequest { endpoint, resp }; let tx = self.history_jsonrpc_tx()?; @@ -89,6 +89,7 @@ impl HeaderOracle { )) } }; + let content = HistoryContentValue::decode(&content_key, &content)?; match content { HistoryContentValue::BlockHeaderWithProof(content) => Ok(content),