From 9a050a954bcd3f3baedfa148b33e6df356a0c0f0 Mon Sep 17 00:00:00 2001 From: Floris Bruynooghe Date: Mon, 13 May 2024 13:55:57 +0200 Subject: [PATCH 1/3] feat(doctor): Report connection type changes in rolling fashion (#2251) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Description The doctor already shows the current connection type, this changes to show changes in a rolling fashion. It also unambiguously logs each connection type change now. This now prints something like: `Connection with gzjlsppiplwpp7pn changed: direct (after 1.548µs)` on each connection change. ## Breaking Changes ## Notes & open questions Despite using the conn_type_stream this stream events are still lost, especially very early on in the connection lifetime. ## Change checklist - [x] Self-review. - [x] Documentation updates if relevant. - [x] Tests if relevant. - [x] All breaking changes documented. --- iroh-cli/src/commands/doctor.rs | 43 ++++++++++++++----- iroh-net/src/magicsock/node_map/node_state.rs | 24 ++++------- 2 files changed, 42 insertions(+), 25 deletions(-) diff --git a/iroh-cli/src/commands/doctor.rs b/iroh-cli/src/commands/doctor.rs index 492806fcb3..0bb72d8664 100644 --- a/iroh-cli/src/commands/doctor.rs +++ b/iroh-cli/src/commands/doctor.rs @@ -32,11 +32,11 @@ use iroh::{ }, dns::default_resolver, key::{PublicKey, SecretKey}, - magic_endpoint::{self, Connection, RecvStream, SendStream}, + magic_endpoint::{self, Connection, ConnectionTypeStream, RecvStream, SendStream}, netcheck, portmapper, relay::{RelayMap, RelayMode, RelayUrl}, ticket::NodeTicket, - util::AbortingJoinHandle, + util::CancelOnDrop, MagicEndpoint, NodeAddr, NodeId, }, util::{path::IrohPaths, progress::ProgressWriter}, @@ -347,7 +347,7 @@ struct Gui { recv_pb: ProgressBar, echo_pb: ProgressBar, #[allow(dead_code)] - counter_task: Option>, + counter_task: Option, } impl Gui { @@ -373,13 +373,13 @@ impl Gui { .template("{spinner:.green} [{bar:80.cyan/blue}] {msg} {bytes}/{total_bytes} ({bytes_per_sec})").unwrap() .progress_chars("█▉▊▋▌▍▎▏ ")); let counters2 = counters.clone(); - let counter_task = AbortingJoinHandle::from(tokio::spawn(async move { + let counter_task = tokio::spawn(async move { loop { Self::update_counters(&counters2); Self::update_connection_info(&conn_info, &endpoint, &node_id); tokio::time::sleep(Duration::from_millis(100)).await; } - })); + }); Self { mp, pb, @@ -387,7 +387,10 @@ impl Gui { send_pb, recv_pb, echo_pb, - counter_task: Some(counter_task), + counter_task: Some(CancelOnDrop::new( + "counter_task", + counter_task.abort_handle(), + )), } } @@ -587,9 +590,7 @@ async fn recv_test( } /// Passive side that just accepts connections and answers requests (echo, drain or send) -async fn passive_side(endpoint: MagicEndpoint, connection: Connection) -> anyhow::Result<()> { - let remote_peer_id = magic_endpoint::get_remote_node_id(&connection)?; - let gui = Gui::new(endpoint, remote_peer_id); +async fn passive_side(gui: Gui, connection: Connection) -> anyhow::Result<()> { loop { match connection.accept_bi().await { Ok((send, recv)) => { @@ -667,7 +668,13 @@ async fn connect( let conn = endpoint.connect(node_addr, &DR_RELAY_ALPN).await; match conn { Ok(connection) => { - if let Err(cause) = passive_side(endpoint.clone(), connection).await { + let maybe_stream = endpoint.conn_type_stream(&node_id); + let gui = Gui::new(endpoint, node_id); + if let Ok(stream) = maybe_stream { + log_connection_changes(gui.mp.clone(), node_id, stream); + } + + if let Err(cause) = passive_side(gui, connection).await { eprintln!("error handling connection: {cause}"); } } @@ -740,6 +747,9 @@ async fn accept( println!("Accepted connection from {}", remote_peer_id); let t0 = Instant::now(); let gui = Gui::new(endpoint.clone(), remote_peer_id); + if let Ok(stream) = endpoint.conn_type_stream(&remote_peer_id) { + log_connection_changes(gui.mp.clone(), remote_peer_id, stream); + } let res = active_side(connection, &config, Some(&gui)).await; gui.clear(); let dt = t0.elapsed().as_secs_f64(); @@ -764,6 +774,19 @@ async fn accept( Ok(()) } +fn log_connection_changes(pb: MultiProgress, node_id: NodeId, mut stream: ConnectionTypeStream) { + tokio::spawn(async move { + let start = Instant::now(); + while let Some(conn_type) = stream.next().await { + pb.println(format!( + "Connection with {node_id:#} changed: {conn_type} (after {:?})", + start.elapsed() + )) + .ok(); + } + }); +} + async fn port_map(protocol: &str, local_port: NonZeroU16, timeout: Duration) -> anyhow::Result<()> { // create the config that enables exclusively the required protocol let mut enable_upnp = false; diff --git a/iroh-net/src/magicsock/node_map/node_state.rs b/iroh-net/src/magicsock/node_map/node_state.rs index dfdf1ebe07..336d325bfa 100644 --- a/iroh-net/src/magicsock/node_map/node_state.rs +++ b/iroh-net/src/magicsock/node_map/node_state.rs @@ -296,21 +296,15 @@ impl NodeState { (addr, self.relay_url()) } }; - match (best_addr, relay_url.clone()) { - (Some(best_addr), Some(relay_url)) => { - let _ = self - .conn_type - .update(ConnectionType::Mixed(best_addr, relay_url)); - } - (Some(best_addr), None) => { - let _ = self.conn_type.update(ConnectionType::Direct(best_addr)); - } - (None, Some(relay_url)) => { - let _ = self.conn_type.update(ConnectionType::Relay(relay_url)); - } - (None, None) => { - let _ = self.conn_type.update(ConnectionType::None); - } + let typ = match (best_addr, relay_url.clone()) { + (Some(best_addr), Some(relay_url)) => ConnectionType::Mixed(best_addr, relay_url), + (Some(best_addr), None) => ConnectionType::Direct(best_addr), + (None, Some(relay_url)) => ConnectionType::Relay(relay_url), + (None, None) => ConnectionType::None, + }; + if self.conn_type.update(typ).is_ok() { + let typ = self.conn_type.get(); + info!(%typ, "new connection type"); } (best_addr, relay_url) } From 6ed6b34d755aade02ce06e07b4f6c0faae616f09 Mon Sep 17 00:00:00 2001 From: Friedel Ziegelmayer Date: Mon, 13 May 2024 14:27:20 +0200 Subject: [PATCH 2/3] feat(iroh)!: unify node api (#2275) Unifies the way to interact with the node to the rpc layer ## Breaking Changes - moved - `iroh::client::Node::stats` -> `iroh::client::Client::stats` - `iroh::client::Node::connections` -> `iroh::client::Client::connections` - `iroh::client::Node::connection_info` -> `iroh::client::Client::connection_info` - `iroh::client::Node::status` -> `iroh::client::Client::status` - `iroh::client::Node::id` -> `iroh::client::Client::node_id` - `iroh::client::Node::shutdown` -> `iroh::client::Client::shutdown` - added - `iroh::client::Client::my_relay` - `iroh::client::Client::my_addr` - removed - `iroh::node::Node::ticket`, use `iroh::client::blobs::Client::share` instead --------- Co-authored-by: Divma <26765164+divagant-martian@users.noreply.github.com> --- iroh-cli/src/commands/blob.rs | 2 +- iroh-cli/src/commands/doc.rs | 2 +- iroh-cli/src/commands/node.rs | 10 ++++---- iroh/examples/collection-provide.rs | 5 +++- iroh/examples/hello-world-provide.rs | 5 +++- iroh/src/client.rs | 12 +++++---- iroh/src/client/node.rs | 33 ++++++++++++++---------- iroh/src/node.rs | 38 ++++++++-------------------- iroh/src/node/rpc.rs | 23 +++++++++++++---- iroh/src/rpc_protocol.rs | 21 ++++++++++++++- iroh/tests/provide.rs | 11 +++++++- 11 files changed, 101 insertions(+), 61 deletions(-) diff --git a/iroh-cli/src/commands/blob.rs b/iroh-cli/src/commands/blob.rs index 2a0aeeab6a..82ea5bd4e9 100644 --- a/iroh-cli/src/commands/blob.rs +++ b/iroh-cli/src/commands/blob.rs @@ -881,7 +881,7 @@ pub async fn add>( print_add_response(hash, format, entries); if let TicketOption::Print = ticket { - let status = client.node.status().await?; + let status = client.status().await?; let ticket = BlobTicket::new(status.addr, hash, format)?; println!("All-in-one ticket: {ticket}"); } diff --git a/iroh-cli/src/commands/doc.rs b/iroh-cli/src/commands/doc.rs index 9b27fc6aca..7a424735a9 100644 --- a/iroh-cli/src/commands/doc.rs +++ b/iroh-cli/src/commands/doc.rs @@ -1000,7 +1000,7 @@ mod tests { .await?; assert_eq!(2, keys.len()); - iroh.node.shutdown(false).await?; + iroh.shutdown(false).await?; Ok(()) } } diff --git a/iroh-cli/src/commands/node.rs b/iroh-cli/src/commands/node.rs index cd4eac1712..d4136ad369 100644 --- a/iroh-cli/src/commands/node.rs +++ b/iroh-cli/src/commands/node.rs @@ -44,7 +44,7 @@ impl NodeCommands { { match self { Self::Connections => { - let connections = iroh.node.connections().await?; + let connections = iroh.connections().await?; let timestamp = time::OffsetDateTime::now_utc() .format(&time::format_description::well_known::Rfc2822) .unwrap_or_else(|_| String::from("failed to get current time")); @@ -57,17 +57,17 @@ impl NodeCommands { ); } Self::Connection { node_id } => { - let conn_info = iroh.node.connection_info(node_id).await?; + let conn_info = iroh.connection_info(node_id).await?; match conn_info { Some(info) => println!("{}", fmt_connection(info)), None => println!("Not Found"), } } Self::Shutdown { force } => { - iroh.node.shutdown(force).await?; + iroh.shutdown(force).await?; } Self::Stats => { - let stats = iroh.node.stats().await?; + let stats = iroh.stats().await?; for (name, details) in stats.iter() { println!( "{:23} : {:>6} ({})", @@ -76,7 +76,7 @@ impl NodeCommands { } } Self::Status => { - let response = iroh.node.status().await?; + let response = iroh.status().await?; println!("Listening addresses: {:#?}", response.listen_addrs); println!("Node public key: {}", response.addr.node_id); println!("Version: {}", response.version); diff --git a/iroh/examples/collection-provide.rs b/iroh/examples/collection-provide.rs index c6eb7f9fbf..37f05da545 100644 --- a/iroh/examples/collection-provide.rs +++ b/iroh/examples/collection-provide.rs @@ -43,7 +43,10 @@ async fn main() -> anyhow::Result<()> { // create a ticket // tickets wrap all details needed to get a collection - let ticket = node.ticket(hash, BlobFormat::HashSeq).await?; + let ticket = node + .blobs + .share(hash, BlobFormat::HashSeq, Default::default()) + .await?; // print some info about the node println!("serving hash: {}", ticket.hash()); diff --git a/iroh/examples/hello-world-provide.rs b/iroh/examples/hello-world-provide.rs index 0f0be772cd..14be61aef5 100644 --- a/iroh/examples/hello-world-provide.rs +++ b/iroh/examples/hello-world-provide.rs @@ -26,7 +26,10 @@ async fn main() -> anyhow::Result<()> { let res = node.blobs.add_bytes("Hello, world!").await?; // create a ticket - let ticket = node.ticket(res.hash, res.format).await?; + let ticket = node + .blobs + .share(res.hash, res.format, Default::default()) + .await?; // print some info about the node println!("serving hash: {}", ticket.hash()); diff --git a/iroh/src/client.rs b/iroh/src/client.rs index 3e8ad63c5c..7cad7c5517 100644 --- a/iroh/src/client.rs +++ b/iroh/src/client.rs @@ -10,6 +10,7 @@ mod mem; mod quic; pub use self::mem::{Doc as MemDoc, Iroh as MemIroh, RpcClient as MemRpcClient}; +pub use self::node::NodeStatus; pub use self::quic::{Doc as QuicDoc, Iroh as QuicIroh, RpcClient as QuicRpcClient}; pub(crate) use self::quic::{connect_raw as quic_connect_raw, RPC_ALPN}; @@ -17,14 +18,13 @@ pub(crate) use self::quic::{connect_raw as quic_connect_raw, RPC_ALPN}; pub mod authors; pub mod blobs; pub mod docs; -pub mod node; pub mod tags; +mod node; + /// Iroh client. #[derive(Debug, Clone)] pub struct Iroh { - /// Client for node operations. - pub node: node::Client, /// Client for blobs operations. pub blobs: blobs::Client, /// Client for docs operations. @@ -33,6 +33,8 @@ pub struct Iroh { pub authors: authors::Client, /// Client for tags operations. pub tags: tags::Client, + + rpc: RpcClient, } impl Iroh @@ -42,11 +44,11 @@ where /// Create a new high-level client to a Iroh node from the low-level RPC client. pub fn new(rpc: RpcClient) -> Self { Self { - node: node::Client { rpc: rpc.clone() }, blobs: blobs::Client { rpc: rpc.clone() }, docs: docs::Client { rpc: rpc.clone() }, authors: authors::Client { rpc: rpc.clone() }, - tags: tags::Client { rpc }, + tags: tags::Client { rpc: rpc.clone() }, + rpc, } } } diff --git a/iroh/src/client/node.rs b/iroh/src/client/node.rs index eb1de5703a..9bbc2caeb0 100644 --- a/iroh/src/client/node.rs +++ b/iroh/src/client/node.rs @@ -5,24 +5,19 @@ use std::{collections::BTreeMap, net::SocketAddr}; use anyhow::Result; use futures_lite::{Stream, StreamExt}; use iroh_base::key::PublicKey; -use iroh_net::{magic_endpoint::ConnectionInfo, NodeAddr, NodeId}; -use quic_rpc::{RpcClient, ServiceConnection}; +use iroh_net::{magic_endpoint::ConnectionInfo, relay::RelayUrl, NodeAddr, NodeId}; +use quic_rpc::ServiceConnection; use serde::{Deserialize, Serialize}; use crate::rpc_protocol::{ - CounterStats, NodeConnectionInfoRequest, NodeConnectionInfoResponse, NodeConnectionsRequest, - NodeIdRequest, NodeShutdownRequest, NodeStatsRequest, NodeStatusRequest, RpcService, + CounterStats, NodeAddrRequest, NodeConnectionInfoRequest, NodeConnectionInfoResponse, + NodeConnectionsRequest, NodeIdRequest, NodeRelayRequest, NodeShutdownRequest, NodeStatsRequest, + NodeStatusRequest, RpcService, }; -use super::flatten; +use super::{flatten, Iroh}; -/// Iroh node client. -#[derive(Debug, Clone)] -pub struct Client { - pub(super) rpc: RpcClient, -} - -impl Client +impl Iroh where C: ServiceConnection, { @@ -54,11 +49,23 @@ where } /// Get the id of this node. - pub async fn id(&self) -> Result { + pub async fn node_id(&self) -> Result { let id = self.rpc.rpc(NodeIdRequest).await??; Ok(id) } + /// Return the [`NodeAddr`] for this node. + pub async fn my_addr(&self) -> Result { + let addr = self.rpc.rpc(NodeAddrRequest).await??; + Ok(addr) + } + + /// Get the relay server we are connected to. + pub async fn my_relay(&self) -> Result> { + let relay = self.rpc.rpc(NodeRelayRequest).await??; + Ok(relay) + } + /// Shutdown the node. /// /// If `force` is true, the node will be killed instantly without waiting for things to diff --git a/iroh/src/node.rs b/iroh/src/node.rs index 36d9dba3f5..e6928556c5 100644 --- a/iroh/src/node.rs +++ b/iroh/src/node.rs @@ -12,18 +12,11 @@ use std::sync::Arc; use anyhow::{anyhow, Result}; use futures_lite::{future::Boxed as BoxFuture, FutureExt, StreamExt}; -use iroh_base::ticket::BlobTicket; +use iroh_base::key::PublicKey; use iroh_blobs::downloader::Downloader; use iroh_blobs::store::Store as BaoStore; -use iroh_blobs::BlobFormat; -use iroh_blobs::Hash; -use iroh_net::relay::RelayUrl; use iroh_net::util::AbortingJoinHandle; -use iroh_net::{ - key::{PublicKey, SecretKey}, - magic_endpoint::LocalEndpointsStream, - MagicEndpoint, NodeAddr, -}; +use iroh_net::{key::SecretKey, magic_endpoint::LocalEndpointsStream, MagicEndpoint}; use quic_rpc::transport::flume::FlumeConnection; use quic_rpc::RpcClient; use tokio::sync::{mpsc, RwLock}; @@ -211,22 +204,8 @@ impl Node { &self.inner.rt } - /// Return a single token containing everything needed to get a hash. - /// - /// See [`BlobTicket`] for more details of how it can be used. - pub async fn ticket(&self, hash: Hash, format: BlobFormat) -> Result { - // TODO: Verify that the hash exists in the db? - let me = self.my_addr().await?; - BlobTicket::new(me, hash, format) - } - - /// Return the [`NodeAddr`] for this node. - pub async fn my_addr(&self) -> Result { - self.inner.endpoint.my_addr().await - } - /// Get the relay server we are connected to. - pub fn my_relay(&self) -> Option { + pub fn my_relay(&self) -> Option { self.inner.endpoint.my_relay() } @@ -279,8 +258,9 @@ mod tests { use anyhow::{bail, Context}; use bytes::Bytes; - use iroh_blobs::provider::AddProgress; - use iroh_net::{relay::RelayMode, test_utils::DnsPkarrServer}; + use iroh_base::node_addr::AddrInfoOptions; + use iroh_blobs::{provider::AddProgress, BlobFormat}; + use iroh_net::{relay::RelayMode, test_utils::DnsPkarrServer, NodeAddr}; use crate::{ client::blobs::{AddOutcome, WrapOption}, @@ -303,7 +283,11 @@ mod tests { .hash; let _drop_guard = node.cancel_token().drop_guard(); - let ticket = node.ticket(hash, BlobFormat::Raw).await.unwrap(); + let ticket = node + .blobs + .share(hash, BlobFormat::Raw, AddrInfoOptions::RelayAndAddresses) + .await + .unwrap(); println!("addrs: {:?}", ticket.node_addr().info); assert!(!ticket.node_addr().info.direct_addresses.is_empty()); } diff --git a/iroh/src/node/rpc.rs b/iroh/src/node/rpc.rs index 5a8f9d5bab..2ae7409988 100644 --- a/iroh/src/node/rpc.rs +++ b/iroh/src/node/rpc.rs @@ -24,6 +24,7 @@ use iroh_blobs::{ HashAndFormat, }; use iroh_io::AsyncSliceReader; +use iroh_net::relay::RelayUrl; use iroh_net::{MagicEndpoint, NodeAddr, NodeId}; use quic_rpc::{ server::{RpcChannel, RpcServerError}, @@ -35,8 +36,8 @@ use tracing::{debug, info}; use crate::client::blobs::{ BlobInfo, CollectionInfo, DownloadMode, IncompleteBlobInfo, WrapOption, }; -use crate::client::node::NodeStatus; use crate::client::tags::TagInfo; +use crate::client::NodeStatus; use crate::rpc_protocol::{ BlobAddPathRequest, BlobAddPathResponse, BlobAddStreamRequest, BlobAddStreamResponse, BlobAddStreamUpdate, BlobConsistencyCheckRequest, BlobDeleteBlobRequest, BlobDownloadRequest, @@ -45,10 +46,10 @@ use crate::rpc_protocol::{ BlobListRequest, BlobReadAtRequest, BlobReadAtResponse, BlobValidateRequest, CreateCollectionRequest, CreateCollectionResponse, DeleteTagRequest, DocExportFileRequest, DocExportFileResponse, DocImportFileRequest, DocImportFileResponse, DocImportProgress, - DocSetHashRequest, ListTagsRequest, NodeConnectionInfoRequest, NodeConnectionInfoResponse, - NodeConnectionsRequest, NodeConnectionsResponse, NodeIdRequest, NodeShutdownRequest, - NodeStatsRequest, NodeStatsResponse, NodeStatusRequest, NodeWatchRequest, NodeWatchResponse, - Request, RpcService, SetTagOption, + DocSetHashRequest, ListTagsRequest, NodeAddrRequest, NodeConnectionInfoRequest, + NodeConnectionInfoResponse, NodeConnectionsRequest, NodeConnectionsResponse, NodeIdRequest, + NodeRelayRequest, NodeShutdownRequest, NodeStatsRequest, NodeStatsResponse, NodeStatusRequest, + NodeWatchRequest, NodeWatchResponse, Request, RpcService, SetTagOption, }; use super::{Event, NodeInner}; @@ -78,6 +79,8 @@ impl Handler { NodeWatch(msg) => chan.server_streaming(msg, handler, Self::node_watch).await, NodeStatus(msg) => chan.rpc(msg, handler, Self::node_status).await, NodeId(msg) => chan.rpc(msg, handler, Self::node_id).await, + NodeAddr(msg) => chan.rpc(msg, handler, Self::node_addr).await, + NodeRelay(msg) => chan.rpc(msg, handler, Self::node_relay).await, NodeShutdown(msg) => chan.rpc(msg, handler, Self::node_shutdown).await, NodeStats(msg) => chan.rpc(msg, handler, Self::node_stats).await, NodeConnections(msg) => { @@ -797,6 +800,16 @@ impl Handler { Ok(self.inner.secret_key.public()) } + async fn node_addr(self, _: NodeAddrRequest) -> RpcResult { + let addr = self.inner.endpoint.my_addr().await?; + Ok(addr) + } + + #[allow(clippy::unused_async)] + async fn node_relay(self, _: NodeRelayRequest) -> RpcResult> { + Ok(self.inner.endpoint.my_relay()) + } + #[allow(clippy::unused_async)] async fn node_shutdown(self, request: NodeShutdownRequest) { if request.force { diff --git a/iroh/src/rpc_protocol.rs b/iroh/src/rpc_protocol.rs index 3fc34f5edd..c0cd6c9b26 100644 --- a/iroh/src/rpc_protocol.rs +++ b/iroh/src/rpc_protocol.rs @@ -21,6 +21,7 @@ use iroh_blobs::{ use iroh_net::{ key::PublicKey, magic_endpoint::{ConnectionInfo, NodeAddr}, + relay::RelayUrl, NodeId, }; @@ -44,8 +45,8 @@ use crate::{ client::{ blobs::{BlobInfo, CollectionInfo, DownloadMode, IncompleteBlobInfo, WrapOption}, docs::ShareMode, - node::NodeStatus, tags::TagInfo, + NodeStatus, }, docs_engine::LiveEvent, }; @@ -360,6 +361,20 @@ impl RpcMsg for NodeIdRequest { type Response = RpcResult; } +#[derive(Serialize, Deserialize, Debug)] +pub struct NodeAddrRequest; + +impl RpcMsg for NodeAddrRequest { + type Response = RpcResult; +} + +#[derive(Serialize, Deserialize, Debug)] +pub struct NodeRelayRequest; + +impl RpcMsg for NodeRelayRequest { + type Response = RpcResult>; +} + /// A request to watch for the node status #[derive(Serialize, Deserialize, Debug)] pub struct NodeWatchRequest; @@ -1041,6 +1056,8 @@ pub struct RpcService; pub enum Request { NodeStatus(NodeStatusRequest), NodeId(NodeIdRequest), + NodeAddr(NodeAddrRequest), + NodeRelay(NodeRelayRequest), NodeStats(NodeStatsRequest), NodeShutdown(NodeShutdownRequest), NodeConnections(NodeConnectionsRequest), @@ -1100,6 +1117,8 @@ pub enum Request { pub enum Response { NodeStatus(RpcResult), NodeId(RpcResult), + NodeAddr(RpcResult), + NodeRelay(RpcResult>), NodeStats(RpcResult), NodeConnections(RpcResult), NodeConnectionInfo(RpcResult), diff --git a/iroh/tests/provide.rs b/iroh/tests/provide.rs index 9f8370b23f..2c38273201 100644 --- a/iroh/tests/provide.rs +++ b/iroh/tests/provide.rs @@ -9,6 +9,7 @@ use anyhow::{anyhow, Context, Result}; use bytes::Bytes; use futures_lite::FutureExt; use iroh::node::{Builder, Event}; +use iroh_base::node_addr::AddrInfoOptions; use iroh_net::{defaults::default_relay_map, key::SecretKey, NodeAddr, NodeId}; use quic_rpc::transport::misc::DummyServerEndpoint; use rand::RngCore; @@ -493,7 +494,15 @@ async fn test_run_ticket() { let node = test_node(db).spawn().await.unwrap(); let _drop_guard = node.cancel_token().drop_guard(); - let ticket = node.ticket(hash, BlobFormat::HashSeq).await.unwrap(); + let ticket = node + .blobs + .share( + hash, + BlobFormat::HashSeq, + AddrInfoOptions::RelayAndAddresses, + ) + .await + .unwrap(); tokio::time::timeout(Duration::from_secs(10), async move { let request = GetRequest::all(hash); run_collection_get_request(SecretKey::generate(), ticket.node_addr().clone(), request).await From 5343cea0e00741fb5a6c4c014a600c30a9f99fb6 Mon Sep 17 00:00:00 2001 From: Divma <26765164+divagant-martian@users.noreply.github.com> Date: Mon, 13 May 2024 07:27:34 -0500 Subject: [PATCH 3/3] test(iroh-net): fix relay's codec proptesting (#2283) ## Description Closes #2278 proptest take overall less than 2 seconds, which I think is fast enough compared to the time of compiling in release and running all the tests. Regression prop test was not being used (it was in a derp path) and it's obsolete since the client info message changed at some point ## Breaking Changes n/a ## Notes & open questions n/a ## Change checklist - [x] Self-review. - [ ] ~Documentation updates if relevant.~ - [x] Tests if relevant. - [ ] ~All breaking changes documented.~ --- iroh-net/proptest-regressions/derp/codec.txt | 8 ------- iroh-net/src/relay/codec.rs | 22 +++++++++----------- 2 files changed, 10 insertions(+), 20 deletions(-) delete mode 100644 iroh-net/proptest-regressions/derp/codec.txt diff --git a/iroh-net/proptest-regressions/derp/codec.txt b/iroh-net/proptest-regressions/derp/codec.txt deleted file mode 100644 index 3f622205d3..0000000000 --- a/iroh-net/proptest-regressions/derp/codec.txt +++ /dev/null @@ -1,8 +0,0 @@ -# Seeds for failure cases proptest has generated in the past. It is -# automatically read and these particular cases re-run before any -# novel cases are generated. -# -# It is recommended to check this file in to source control so that -# everyone who runs the test benefits from these saved cases. -cc 7ed75c415c2772f22bd2a5eb885a3210201ddcad84b8b0f07df0bf510005018d # shrinks to mut buf = b"\x05\0\0\\\xf0;j'\xbc\xce\xb6\xa4-b\xa3\xa8\xd0*o\rse2\x15w\x1d\xe2C\xa6:\xc0H\xa1\x8bY\xda)\x9d\xcbb\"\xb2\xb1\xfa\x8dt\x94G\xf6\n\xd3\xdd\xec\xb8\xb6\xc4\x82p1RW\x08\x1d\x82\x19\x14wi\xba\x84\xbdl\xa85\x12\xee\xa6\x94g\xb1O\x01\xc6\x15\x81\xdd9\xfd\xcd\xbd\xf8\t\xfa\xf6\xf7Hk~\x1b\x16\xa2\xaa\x13\x7f\x92\xf2H\x04\x82\x9b\xfc\xc7z\xbd\xf8\xc9\xc1\x02bt \xafU\xdcI\x8c\x1d4\x94\xabW\x1b?\x82\xeb\x015\x86UY>\xf8\x01\xd4P\xa0\x1c\xa4\x87S\xfd\xfc\x17\x14\x1b\xef\x86\x99R@\x04Um%\x05(\xa2\x87\xe1\xa9v\xec\xa5,\x90\x93\xd4IO\xb1\xe9I\x0f\x10.\x1d\xa3\xac)V\x1a?\xa0v\xee\xcf\xdb\xc0G9@\x0e\xd0\xd6\x1c\xe9\xf4\xb4\xa30\xee\xee\\A\xdc\x15\x8a\xf0l\xbb\x91nS\x84\x02_2B\x1c\xc2\xe5\xd0\xb1\xdfw\xd2\x7f4\x92LEw1\xad\x0f\xcdZ<\x01\x92`\xadJ\x16\x82M\x14/\xb7_\xfd~\x83\xb6Gzp\xe8\xa9\t\xba\x87\xe6\xf1\xfa(\xa1\x10\xd7J\xd1\xebd\x15)]iI.\xcb\xde\xa0\xfa\xb5\xcb)\xe3\xacq=\t\x95\x08\x97-\xa5\x04\xd9\xc8PB\xc4\\q\x88\x82\xd3y\xd2\x01R\x0bZ~\xe0\x12K\xd7f\x02\xad\xb1\xff\x95\x94\x1d+\x93\xb5\x12 \x059c>\xcc\x1b\xcb\xb6\x104\xa5x\xf7>\x15\"P~\xbd\xb9\x12s\xc8L\xd3|yv\x88;\x14=\x0brnQ\x9e\xcb:\x06\xf6\x192\xf7[?\xf5Or\x0clH\x9e\xb0u.\xcf\x1f\xbf\xc8\xf4\xca\xcb\x9b~\"\x1c\xa2\xcf\x8c\xa3\xdc\x07(\x93\xf6 \xbc\xc1\xc4\xd5\x97\xbd\"\xc4\xf12\x1b\xc7\xfe\xee\xb5z\x9e\x8b\x03\xaeS\xfe\xd7f\xe2Y\rUN\xd0\x96I\xd7\xf1f\x8d\xed\"q\xe6\xce\x84\xe0\xe0h*\x14\x91\xe4\x8bo\xeb\xa2pS\xd9\x8a\xc4+\xd3\xf7d\x84\xfc\x05F\xfa\xae>\x8c\xdd\x87\xfb\xb2\xec\x18\xafi>.'/A:;W\xa60\x06[\x15*\x8ee\xdb\xe1\n\x9f\x05\x01\xa6\x95\x88\xbf\x11r?\x0b\x95\xe8j-n\x02\x0f\x12\xa4\x8d\x83=\xa1a\x9e\xf7\0\xd9|\xd7\x0er\xd6\xb2\xe0\xfb\xe6\x8d\xcb1\xaa\xc1\xa5\x9f\xc1\x05\x9e\xc0\xf2D\x9a\x9f\x14K\x85p\x0cf\x9f\xf7\x08\x0b\x13\xa9($\x94ws\xad\x94p\xbd[\x8d&\xa0akD(\xe5\xc4\xbe\x9e_\xf4\x1d\xe5\xd0\x923t\xe7\x9a\xca\xc7\n$\xef~\xf0p\tf\xfc\xbc\x9a\x8dN`\xfa\xcd\xa96\x1d\x1e\xafW\xcelu\nqs\x02\xd9\xa8\xedg\x809&\xad\xe4ol\xf5\xd4\x88\xf4\x089\xf0\x1a{\x06\xc01\xed\x89\x94\x010\x14\t\x8ab'\xf2L=\x1dz\xe1\x13U\xeba\xb1\xf9\xed\xd6\x8dC\xa3\xe3\x813\xe9S\xda7h\xfa@\xaf;Z\xaa\x0c<_\xe0D\xe1\x9c7H\xe28v\xc6\xc5r\xc8\x93Y\x95l\xb5\xcd\xba\x9b\xf3\xb0\xa8\xf7\xc5\xa73\x83T\x8a\x8f\xf3\xa3A\x10\xdfYc\xfe\xfc\x14\xca\xa3m\xde=\xc5\xc3M\xdci\x9c\x16\xd7\xaf\x9a\xc9\xdc\xea7\"\xf61m\xb7x\n\x93\xa7q\xad'\xe7DM\xa4\twc\xd0)\xcf\xd3&(\xa0L\xb63:\xa6Q\xd9\\\x04\x1e\xb5L)\xce\xc1US7\x88\xa5\xac\x13jDRca3;\x1d\x0c\xb8\xa6\x08\xad\x85k\x14\xd0;zLPD\xc0f*\0}\xb3\x9e\xd1\xbd*\xa2\x1c\xec\x9d\xafE\xf7%\x94\xec\xdbm\xbc\xa5\xb2^\xbb\xe3\xff\x10n\xddMiZ\x1b\xa0\xf1\xe4\x14\x19P:\x0c\xd2:\xd1\xc8Y\xd8b\\\xb37\xf8y\xe0\xf6\xa0\xc8\x1bcJ\x10?m+\xdf\0\x01\xbf\xf5\x87\x8bZ\x13.\x85>\"\x02\xfb\x02\xf4\xfa\x05E\xdd\xe2\x80|5\xf5\xb2\xbfG\xc0\xfd\xf4{\xd2\xf1Kq\x11\r\x7f3\x12\xe4''.1\xd8\xbc\x9a\xa8\x80A\x11(l8\x7f\xde\x9du\xfeC\xcf\xe8L\x84\x84\x06/e\xf7\xb1N\x1fH7\x8c\x1b@A\xe7\xd7\x8f\xca\xa0\x176\x95@j{\r\xe3z\x88\xfd\xc5I\xb0\x93\xe9Z\xabI\xa3%\xd7=s\x07\xc7\x87\x1e\xf1\xc3nV\x188T\xe2y[\xd7\xaa\x91\xac\xd8\\Y\xec\xd9\xc1ot\xee\xbf\x94\xdb{Z\x8f,\x17\xd5O\xfd3\x1d\xd2\x117Z\x06$5\xc2\xa99l\x81\xd6\x01|\x8c\xa6\xa4\x9aU~\xe2\xd9n\xff\xa3\x1b\xf7 {\x16\xc2\xa2riUl\xec\x99\x1d\xc4Ud\x86f\xf8\x87\xbc1\x03kuz\x99\xf4\xa4V\x88I\xbc\x1a\xb8\x05Q\x92\xde>d\x13\xe4\x03\xa5\xf8Q\xb1\x14\x0f\x81s\x1b\xf4O\x9e\xb7E\x95\x8b,\xff\xde\xb1\x88\xc4\x06\xdb\x8b\xd2\x1eO\xeeum;#G\xcf\\f\xc2!\xc30\x88\xbf\x8ds\xa5\x86\xc4FMP\xb7\x06H;\x8c\xc9\xef\x12\x90\x9a\xaa\xcbi=N\xc8\x0f\xdep\"\x9cUg\xb3wn\xec\xb4\x85\xa3a\xbfYI\x8a\x86m0{\0N|\x04\x89y`\x94\xc1$?j\xf1`\x062\x91\xec\xf5\xf1\xe3\xba\x83\xfb_\x813\xb5A\x16\xfeQ\x04\xf7\xd9^\xa0 T#L\x8f\x1f\xc5\xd2%\xef\xf3\x06+\xa5E\xcd\x81\x9a\xf3\x17\xaf\xc4\x8c\xf8\xd34\xae\xdb\xdf+\x93\xf5\xf5\xe4\xa9f\x19\xb7\xd05\xad\x8f\xbbA\xc7\xf2\xae*AC\xe3T\xd4\xb4q\xa0\xe1\xb3\x7f\xda\x9bU?\xc7\xc8\xb1\xc6\x15=\xa6EUN@\x9b\xef\xe4\x10\x97\xfbt\xbb\x10!\x90lp\xf7U\x1f\xdf\xd7\xa27\xd8z\x86\n,#\xecU\x8e\xf8\xab[\x9c\xbb\xb3\xd3s\xde\xf4\x1f\xbcX\\\xd4\xccF*F\xc7wX\x8d\x82S(\x1c\x85\x803\xb0\xc1y\x02\x8e\x13\xf7\xc7\xfb:\x1e\xb4*\x15\x8c\xd7\xa4\xf9\xe6\x0c\x17Vr\xd6\xed|\xa5\xc6\xc8\x1f\x84pV\xcc\xba\xa3\xe1\xdc\xaa\xd5\xe4\xdf\xd6\xa4\xbf\xca{\xc8\x81N\xa5Gl\xeeD\x8d\xc0\x82\x08\xdf\xee\xf7{\xe8\xa1%\xd3G\xe2\x0bS\x1f\x81\x14\xe6\xc7\xe7F\xfb\x08\xdcf=\xbb\x9c\xc2\xf2\x8b\xb6z\xa0$.'=%\xbb1\x05{\xb5\x04>bj@}$lkW\xf6R\xa9\x98F\xa6\xef\x94\xdf\x1a\x03\x8c\xbd\xef\x8e\xe1\xe4\xdd~\xf2\xc3\"\xb3\x84\x13\x1e\"\xf2\xb6#\xfa\xd5\xcdx\xbf\xf4\xddn*>\x7fM\xd6e\xa2\x14\xf0\xd1\x98\xc03\xac4I_3\xd4\x8e\x95j\xf7v\x14@\xe6\x95\xbb\xd8\xf1\x1d\xee\x17\xb8\x8e^Ac~\xaaDj\xa6N\xe1\xa6\xb2v\xe6\xa6\"\xa7\xf3~#\xd8\x87\xef\x9b\x96z\xb17xHp\xf0\x87w>h`\x95X\x99b\x94\x18Pmo\xb3(=\xec\xa7@\x83\xaf\x17\xcb\xca\xe0EIe\x1b\xf4SZ\x98q:\xef\x95\x1d\x91<0\xf5\x0b\xc3\x8abn:MsH\x10\x1a\x0c\xbf\xd5:\xad\x03\xddi$\x9d_hn\x95\x959\xe8|\x9bXi[\xa2\xb9\xf2\x16g\x9a2\x0fQ`\xfa\x93\xcf:\x90\r\xd4\x05\xa6n\xe0\xf2\xbf.\xe1PG,\xc2m\xad\xfc\\\x96d\xd1\x91\x97\xccT\x0e\xaa\x83\xa7\xa1\x8f\xe2\xa2\0\xf8\xf0UZm\xda0v\x12\x93\xc5\xcd\x1cf\xd8\x94\xd2\x9e\xaa\xdf)\xff\xe968\xef\x06\xf6*\x11\xa3\xd6\xc3\xb4\xd6\x90\xa8h\xf5M\xba\x03\xb9t\xcb\x11\x9f\xf3\nv>x\xae\xeb\xde\r\xa0abp_\xe1\xa5\xc6\x7f\x8a%)\x81\xc0[]\xa2\xfc\xfcW1\xe7\xa5\xbbZ\xd8H\x94E%\xe4F\xa2\\\xa7\xc7\xd7;\xfb\xba\xa0\x84Ra\xd3\xabo\xb3\n1J\xeaHR\xa3\xebDl3\xbf\xac`\xe6s\t\x19\xb2\x99\x98>\x96\x1e\xf4\xc4'F\xcf\xb9ap\x80V\x90HG\x02\xb3$\x0fi\xf9\xc0\x93\x8cs\xc9*\xa1CBd\xb1V7\x04\x84;M{\x9d\xb2\x02\xb2\xcc(F;V;\xc4~~\x86\xf9\xdb7?4G-c<.\x95\xf3\x04\xe0\x7f\xd1L\xd9\x1f\xe2\xe7eg\xe7&,\xc0u\xcb[\xf7f\x97\xd1\x91\xa7\xe6\x8e:\xdb\xfe\xf4\x9f\xe1\xf8\xe1\xf5\t\x9d\xad\x7f^R\x14B\x0f\x9d\x07\x89\x0b\x9a_\xa5I\x0c\xa9\xfdS\x03\xbfF|-\x81\x8cut\x80\xb7\xd1\x11\x05\x1d\xb3\xd6*\x1e\x07S\xcaJ\x12o*h^\x1f\xe6\xea\xe7\xc4\xd0\x9c\xe2\xd2\xcd\x8d\xef\x06\x0c\x8113\xb5v\xb9G\xe6\xaf\xc5\x96\x978v\xcfJ\xb9\xad\xc5'8VwRX\xef\xa0\xfb\xa9yO\n\xf9\x02J\xbes\xd2\xbe\xc5g\x1d\xac\x9e\xba\xf9\xcee\xf9\xf5\xeb\xe0rUk*\x17\x89\xd9\x1b\x81/m\xb7'\xae&\x91\xf5\n\xa0U\xd5\xdf*\xba\xb4\xb0\xae|\x8b-sB5vdV\x1c\x0c\xe4hV\xb8\x8b\xf6z*\xed?77r\xb3\xf9\x81\xd0\x9e\x1a\x040\xc05\xc3\xab\xbb\x8e\xfa\xe7\x1c\xb4\x07#\x0f8\xfb\xdaj\xb6Go\x8a\x8fZHn\xbc\x81?\xcd\xf6\x10A+7\xe5\xd6\x84/\xa0\xc4em\xf5\x9d\xb3|\xcd*q,\xcc/\x8d\x95`\x18Mg?\\\xad\xba\x13\x15 \xcd.\xdc\x9a0@\x1c\xf1\xeb\xe6,\x88\x01=ic8\xef\x16\xf9\xc3y\xacZ\xb4\x83\x133\x80\x1a\xdf\xacu\xf5\xd98*\x92m-/7;\x977j:.\x8d.\xffL\\\xb7\xcc\xaf\t\xb0\\\xda?~t*'\xf4:3\x81y\xdf]\xa6M\x94Ox:\x9e\xca\x19\x05[T\xc1\xe0T0\x8dc\xc4\x16\x1e\x14\x9eh\x96 \x8e\xbd\xed\x9e\xf2'+H\x85Z\xf9$\xbaH\x94\n`\xe1\x90.q\xa0W|+:y_E\x83\xb2\xe6\xfc\xbb\x8d\x0e\x88\xc2\xc6\xb2O\xb5l-/Ut~\r\xaf\x1cv~o0\xf6\xc3\xa1\xbc\xd3o\x05\xc1\xf5s\xd3.\x18\xbf\xe9\xe4\x0f\xc0\xbf\x16\x18\x19\xabT\x15\xe9\x7f\xd6*\xfa\xe2\x838\xd5\xf1\xa9\x0fd\x83\xc0y\x96:\xda||\xc0$f\xe6D\xe2\x8c\xf2\xed\x05\xe5\xdbs\xa8d\x96\xe3\x9e#\x1b\xf2uHp\xa0#4\xa7\xe9\xee\x84G\xdb\xe8\x0e\xff&[IF\x9a\xce\xf7\xf2\xcf3D\x9b\xb8\x94D\x06\xe5@\xaf\xafn9T\xb6\xe7\t\xf4|\r\xac\x7f\xd93\x98\xf9\x8a\xed]\x90b\xe8\xad\xf2\x06\x98\xf5d\xa0X\xe7\xf6\xf8\x97\xe8\x03v\xef[\xcb\x94\xbdW\xd27\x83\xc0\x9be\x06\xc9|h\x80\xac\x14c\xa3\x8ev\xd9\x98}\xb3:\xba8\xdaN\x8e\xe7U\x03c\xc1|\xae\x80>R!\x7fb\xa2q\x97g\xc0\xa5(\xac9X\x7f\x9e`\xb2m\xf1\xc6-\xb0P%\xe4\xc2\xa5,{b\xff\xfd\xd4\x18\xbb\x8a\xff\x91\xc6\xca\xb8\xef\xe5QM^@`\xe3X\x84\xc6\xe8'\xe0\xe3\x9c\xa41\xb4\xa5b}\x80\x8c9G\x17:\x7fe=\xfeS\xcc\xd5V\x16R\xbe-\xfd\"\\$G\x8b\xc6\x07\xe5\x8a\x1b\xb9v\xd8\xc4\xfc\xfc\x9f\xfbLf\x0fZ\xba-.|\xeb\xfd/\xbc2\x84?\xbd o\xc2\xabk{\x88\xf8\x99\xce\xd2\xe8J9-A6\xd8\xbe\xcf\xccy\xce\xfc|\xee\xa5b\x80\xb0(\x07!\xce>5Z\xbe<\xdb\xaa\t\x06d\xb6\x87\xf6\xc4\xa7\x92\x1e>\xb0\x13\x83\xc1\x83{\x0f\x91\x80o\xcb\x16\x17w\x9bUQ\xc0\xf95M/\xd8\xfcs]#\xd3\xb9\x0b~\xc7l\x01\xa9E\xb2m\x83rq\xe0~c\xa2\xea\xdf\x9c\x17Yd\xbe\x93\x82\xeez\x0f\xb2\x08\xaeBC\x87\x8d\"\x10\x1f\xfd+\x89E$\xb5\xb5\xae\x04\xe9\x88\xdbd\xac\xc02\xf9L\xff\x1d\x9a\xc8\xd15\xf40\\\x8a+\x8a\x88\x9a\xf2\xab\xed\xd1~@\xd3O\xec\xe9(\x8c\x9d\xefS\xbf\xf0 \xecA\rN\xae\x8d\xae\xca\x93)\xe1\x84B\x9c\xbd\xba]\xa2Y\xf3\xd8R\xa7\x1e\xecV\xcf\xf8\x8c!\t\xfb\x04\xac\x12\x86\x19\xa85q\x0c\x8c-\xde3\x99\xbf\xf5\x1b<$%\xe6\xfa>\x10\xc8\x82{\xccE\xbd\xcc\x16w(\n\xec\x0b\x19\xe6\xa8\xa2'$G\xaa\x1bPj\xc2\x94\x8fT\xbe\xed\xac\xef\xc1\x10\xcc[jN\xbbVA\xd7\xa8VW\xfd\x05D{n\x9c\xae\xd5h\x19\xbf!#*\xfb\xcd\x9e\xeeg\x83%\x95 >#\xa6ll)N\xd1\xc3#)\x1b\t\xce\x16\xef\xba\xd5\x8eyo\xd3\xd8\xb8\x05p1Q\xa2\x8a}\xb9\xba^*\x97\x83p\xcf\xf4\x9a\xe0\x1b\x96\xd5\x92\xb6\x02\xf0E\xcd#f\x86A\xda\x0e\xcd\xb4\xc0\x18\xe3t\x84\xce\xd4O_\xd2\x1bh\xb2\xafG\x1c\xa9N\xc6\xd95\x01\xc48\x8c\xf7n\xf9E\x87\x1a\xc5\xde\xea|\xdb7,\x87\xfa\xbf\x1aa\xae\xa0BA6R\xc4\xdb\x9bf\xdf>\xc3>Z\xf9s\xab\x82\x1f\xf8\xe7>\xb6Ly\x87c\x17'\xf5\x7f\xcb\xf8\xa5!\xafzE\x9c\\\xd6\xad\xd4\xbcB\xe1`F\xd47\xa1fy.\xf7\x86A\x97\x10\xfeha:J\x16u\xa1\x02\xb1\xb8E\xbe\xcd\x94\xb7\x17TX\x01h-\x1f\xfb\xc5\xebk\xaf\xbd7f\xa8\xcf\x0e\xd3\x90\xd8^-=b[p\xe71W\x8diZ\"\xaf\x83#\xefU\x11\xac\xef\x1e\x07\xf7/\x12\x98\xbckMU\xf9\xa1\xdbd7V\x9ek\x1b-\x1e\xff\x9d\xd1?\x8aj\xcaZ\x8f*`\xf3l\x7fG\x13\xae\x1a\xbc\xc2`\xb4\x14a\xe8\r{jR\xe2t\x84\xfa\xbc\xd8s\x979;\x97;F\xbd$\x11\x81Ir\x11\0\xf3G\xcf+/\xf3\xd1\xd8\xd2\xc7\x9f\xfeUM\xa9i\xbe-\xdb\x17#\x84\x84\xb6t\xa3\x85\xcd\x9ck]\x13\xf2/\xf3i1\x19!\x08]v\xe9\x17\x0f\x8e\xeb4\x19\x19\xff\x81\xdcv\xb5w\xdb\x98o\x13\xc6a)\xb7\xe3c\x99\xfc\x88H\xd6Q\xb3\xa8\xe6j\x86pJ\x9ay\x8c\xb4Q|\x87y\x94\xccyv\xa6K\x93\xab[\xdd\x10-\xe7\x1e\xd3>\xbd~'v\xba\xa5\x9b\xc8\x1d\xa5\x1f\x9f\xe3\xeb\x85\xbf\xdcav\x14\xe3\x86\xf8\xbasacT\x06\x0f\xec\x16*{\x0e\x93xTU/B\x8f4|\xad^\xadd\xe5NV\xef\x1e\xa8\x83\x89\x81;\xfc\x9dS\x88$\xf4g%y\xa9U\x8e\xa8^\x97\x96\x0c!\x12.\xe3i`\x94Oq\xf0\xe0\x9e@\xd0\nk\xb8y\xc7\x1a\x9b\xf6$\xc0|/\xeaD\xd1\xd6\x10\xabKT\xee\x9cf\xba\xecQ\xdcpj\xdc\xf7\xaeB\x15\x82e_\xc7_\xa3\xcd^nb\x8a\xa7\x9d\xcc\0 \xb2\x16\xcc\xaf\x06*_\x88\xef\xdd]sI\x04\xf9\x87\xb9{w\xaaF%\xe5r\xcc\xa6\x84\x0cK\x13YL\xea\xa3\xbb[\xddo\x08\xbd,\xc3\xa8^W\xac\xae\x1a\x0cMS\x05\xbd\x8fF\x17\xac?\xbd\xee@g\xfa\x9b%\xd3\xe7>l\xb0\xa3\x9f*\xea\xe4~\x0b\x02 \x02N\xc3\x10\x17\x18\xde+\xd4l\xb32\xad\x9f\xb5z\x02|b\x8f)i\x8d\xc5\xe9\xdd\x06\xc9\x1a\xc7\x06\x99gq\x85\x8c\xf8\xb2j\x90\x99\x01\x96]B\0\x84\x14sb5S\xb4\xe1\xd5\xa9\x0c\x87t\xf8\x8b\"\xe6\xf2\xf3B}\x0b\xa2\x97\x07T\xf1\x9f)|u\xf6i\xb4\xb5\xac\xccY\xebu\t\xbf\xaf\x95\x89\x12vN)\x14JUA\xba\xd7t\xb3\xe4\x9ai\xd7\xbc\xf8\xb8\xf1h+\xc0\xb6r\x0eTi\x1c\xab\r2\x8a\xc4\x17l$\x81\x94~s,\x84\x9aK\x04\xa0\xa6\x90\xf6\xac\x81`n\x19|\xb6\x96\x0cb\xa2\xc3\x88;\x0b\xbf3!\xd07\xd7R|(I\xc6\xa7i\xe6\xc1\xdd\x9dr+\xcb\x0c\x1fO\xc2\t\x12A\xf5\xd2\xb7\xc1j\x19\x8f\x114\x16 .k?\xd2\x0e\xde\0\xa6\xd4`\xc1\xdd\xf1\xea\x96\\+\x01\x0e\xfe\x92EkvR\x92\xb1[\x05<\x82\xe8\x03K\x13\xf2+\xf1d/k\x1d\x9b\x19\xc8\xa3\x03b\x94#R1\n<\n\x1b\xa4\x16$\xa6\xbc\xd4Wm\x8f\x04\xa3\xdc\x18X\r\xee/\x9fq\x1c\xd8\xa4\xba\xa9\xb4\x81h\x83\xfd\xa8\xdbQ\x12\x115+\x19a\x9b1}\xb7\xde\xf9\xe6$\xa0@n\xcc\xee>l\xd9Z\xb5[\x03\x8b\xdc\xa3>\xfcv0>\xe1\xf7\xe3\x1d\xd0c\xae\x91\x98\x84#\xb9\xbc\\x\xb6_{o\x7f\xfb\xdeN<\x95g\x02\xbd\xf6\x18\xd2\xba\x8a\xbbm\x85\xab\xdba\x89\xfe|&\x0e\xcd\xc5cs]\x91\xaa7\xa5\x9ex\x819B\x91\t\xb6\xd0\xabU\xfd\xb5\xadt\t\x0ci\xf0\xb7$\xc6QH\xc1\x95\xa6\x9fd \xe63%\xd5\xa5$J\x99\xc3\xbcKk\xfa\x92\x98li\xc0\xfa \x90\xa8.[\xde\xd1tt\xd9\x10\t\x8c\xc7\0\x99M\xe4'G7\xb9\xe7\xeb\x95F\xab\x179k~\xeeQ \xfa\xf2\x91\x1b\xc2\x1e\x06\xd2\x01\xedb\x85\xee\x9c\x89d\xe4m KtD\\\xc5\x8cg\xe2s]:\xf1\xb4\x96\x01%s\x98X\xe6\x803\xf0\0\xc02$\xc0\x93\x98\xf5\x9a\xea\x91I0\xe7k\x9cG\x87\xaa\xc5\xbd\x8d\tO\xca\xc2Fa\xad\xf4\xe9\xd8\xe9\xeal/\x13\x0eR\x8e.L\xa5\x1dVeJ\xf0tKL\x19\x02\xb2\xdc\x11\xc49\xff\x18Q4\xb1\xaa.\x04Hs`K\x1a\x1cI\xdcMU\xd4\x06\x08\x94&\xdf\x07Q\xaf\x9e\xda\xd2ZG\x91\x93\x1a\x15\xacB~zV\xa9\xee+[\xabY\xe7\xe2y\xf9\xf4\x97\xc1n\xc8-#\xe7n\xeb\x8dZ\x1f\xff7\x0f\xa6\x19\x9c\x91\x92f\xf8\xee\x9b\xc7\xeb\xdc9\x19\xe4rw\x84\xf1%e\x02\x7fmk\xca\xa5\x9eL\x8cC\xa5\xa2\x07\xcf\x89z}=\xbd\x81&\x1f\xba\xe3\x16\x07L\x1b[\x9c\x9d\xf8%\x80;\0+\x87H+\xb1K\xce\xa50?a\x8e}\xf3\xdb\x9b@H\x01yhI\xa0\x83\xb26\xa1\xfeS\xa7p\xa6\xde5\x19\xdb?\xf9\x91\xf2\xd3\xdd+\x93\x04\xa9\xe8\x91\xf5\x0f\x18\xd6\x01F\xe3\xf7M9\xc0K\x15\xb5-z\xdbb\xd1\x1a1\xf9\xd9i\x94\xd4\xbd=\\\xd1\xb5\x1c\xb4@\xf3~\xc5\n}\xddrc\x80/LI\xbbD\xb9\xc3\x9f{\xfc}\xdb\xeb\x03\xf8\x17\xaf\xd8\x1db\x95\xef\xc7\x9b\x8a\x07\xe6\x9b\xab\x0b#`y\r#\x1b)D\xb9M\x97\x9dT\x9d\xfa\xc4\xb40\0\x8c\xab\x1a\xa6\xf4\x0bc\xe37A\x1e\xd9P\x06q\xacD\xd0/\\\xde\x8f\x9f\xa3\x8e\xd3\x86\xc0\xeei\xf1\xfa\"\x1c\xfb\xe6W\xa79\x04]\x9f+\xfb\xf7\x8d\xed\xb9\xc4\x1b\x9d\xe9\xadD\x0e\xdf8c\xaeV3\x0fv=\x88#\xdeU\xa9U|K\xf7\xb1\xa8\x10#S\x19u\xb1H\xed\x8d\xa9\x94\xb98\xe0\x83 \xa22\x91\x0e\x02\xb8k\xce\xe8\x8c\xa3E{Y\x8c\x96\xff\x01\xf2\xb4\x9d\xf7\xd4\xec\x1c\xe5\x9d3K\x93\x9c9wl\xc8%H%Y\xef\xac\0\x9c\xb6\x94\xff\xfdu\xd2\xa4/A1\xd2y\x19\x16\x03\xe7Y\x85_\x0c\x0e\xd8\xa3\xc9(\x1eT\xe3\xdd_\xba\x82\x10\xf7S\x13\x8f\xe0\xba\xf1\xbdn\x08\x16\x14/\xc1\xca\x86\x95\x03\xcf{\x0eB\x08\xe8\xab^w]\x07\x9c\x9f\xd7\x14\xa1\xcbD\x01\x9e\xd4\x139K{\x1cfG\xf1\xfa[0\xfb=\xdc\xe1C\x93\x9e\xf9\xe3\x1b\xf0Zm\x1e\xa2\x9d{\x92\x082\x05\x1b,\x13\xc4\xd1\xc2\x8c\x96\x07\x07\xc3\x12\x1f\xdcZEbFp5M\xea\xeb\xc3uZQo\xbc\x9aM\xa9t\x906\xd0\x9e\x98S\xf9\x02\xde\x02\xcc\xdc\xf6yY\xbd\x15\x8ej\x0bn\xd5\x9c-\xc3`\x91\xe8\xe3D\x0c\xd3\xd1a\xc3\x89\xb0\xf1g`\nP\xf3\xbbM\xed\xb6\x0c\x13\x04\n\xb2\x838q|9ez\xc4F\xdb3oI\xff\x1es\xd6S/Io\xdd\xa8\x9b\x02x\x7f\xe9[T@l\xf2\x8f\x85\xf7\"\xfc\xd0\x83\xb3\xceiv\x9eH\xc2\xbb\xa9\xce\xcb\x88\x94z'2\x1e\x84\x0b(\x1d\xeb\xa1#X\t=\x82\xb0\xdckA`B\xe9\xd9\xcc\xf7\xb4w,\xeb\x98\xadw\xe3\x8e;\x7f^\xec\x1d\\~H\xf0\xa9\xaf\x0f\x1f\xd8d\x0b\xab\x1e\xa3\x18e\x19\xf3\x89\xf1\x80S\xb3\x148b\x95\xd2T\xcc\n\xc8n6(\x84\xac\xf6\xbde\xc3\xec\xf9f\xc4O\xaa\xed\xdd,\xc4\xb7U\x0f\x9cn~\x1f\x17\xf0\xaa\x16Ha\x0f\xe6\x12\xe5\xd0z\xc2\xde:\xac\xff\x92L\xa7zj\xa3c\xb1\xe6?-\x97\xbb\xf0\xd8E\x81\xba~\xd7*k\xe6\x96H\x1b\x1a\x87\x18y\xa2\x08\x8aR\xbc\xe14\xa7I\xfb(L,\xe0'f(6\xb3JW\x9a\x8d\xf5>\xedF\xf3c\xd6\xa8o>D\xb1cJA\xdcS\xa9y\xc4\xc4r\x97\xc5\x10w[\xf7\xd0\xcd\xbf\xc4,\x8d\xce\xb4\xfb\xa1\x93\xcb3\xfefZ\x0cy\xda%\xe6v\xd0l\xbc\xd1\xb1L\xf5\x0e/\x91\xb4A\xbf\xbf\xb5\xd9tN\xb2x\x90\x8c5,U\xcd~c(\xcc\xf9\xd3\xde\xcb\x01\xe1?\x13:\xdd \x95\t\x8d\x8f\xdbY.#\xb8\x12\xdc\x8d\x9biL\x15k\xf1D\xf7\x7f\xc48\x04\xd7\xf7\x1d\xb3\x1e\x02\x02j/\x83\xaezl\xa1R\xbe\"\xe6\xab\xcb\xb4\tN\xcc\xebw\xe1 ]\xb5\xa7\x1c\x9b\xb3\x978f\x03\x99\xd1\x05wj^\x8e\xac\x12;\x1a\xd8\x19c\x19V\xd1|J|\x17\x14/\xd0\x9fP\x98\x81J\xaeuQ\0\x0e\xa42?\xe8\xd1\x95_\x94\x91\xa7\x8b\x1f\xd2\x82\x97\x88Hy\xbdO\xa4f\x8e\xb0\xa7\xca\xbc\x0fD8\xc4\xda\x87\xc9\xa6qW<\x92vYz\xfd\xb1F\xb6~G\x9f{\xde\xfa\xbe\xdc\xae\xd9&8\xbc\xc2\xbb>\x91\x9f\x8f\xaa\\\xd1x\x96D\xca\xad\x17\x12y\xcd\x1a\xab\x19j\x06\x87Pt\xb3\x8f\x92\xfc)\xe2#3H\xb3V\x08\xef\x1b8\xf0\xdcMK\x1d\xb3\x1b\xf8\xd1\x86\xe9\xb2\xf2\xc11O\xc0\x91\xd4\xfeq\xe7\xf6\xa2 \xa2\xcd\tG8qg\xdd\xd3\xf8E\x0e1\x0c\x1cF\xbf\x83\x07\xe2\xcbr\x89\n\xc4\xf1\xbc\xa1_>c\xb0\xa5\x95\xd7\xe5\xee\x1bk\xfas\x11\xe6\xe3\x15\xe4\x857\x19;\x80\r>\xdd\x8c\x8e\x89\xf4t\x05\0\xa7\xc1j\xa7r\x91\xd0\x02V\x88\xc9\xf3\xba\xbd\xf9U\xd4}\xe6\x1en\xad\xaa\xbf\xadR\x9f\xa0&\0\xb6\0Np\x07Tb\xfa!\x16\xeeQ\xd5\xc2shZ\xcd[\xe6\x1d\x8e\xf3\xa2\xcf\xd9\x9b\xe7\xda\xd0\xd25\x14\xa6}\xa3#xl\x11!\xb2\x15M\xf8\x05(\x94\xfb\x9b+\xe6\xc0\xea,\xd7jH\xf5\"n\xc2$\xc8\xdf1J{\x82o\x8d\xb6\xab\xb9g\xc2P\x04Qq\x96\xfezF\x96\x17,L%KG5\xa5\x96V~:\xd0\xf3\x1d\x99\xa5\x1d\xdd\xed\xbe6\xd1\x85\x96c\xaab\x84\x05\x17%\x03!\x92DU-A+7\xae\xcc\xe7\xb3\xc7\xe7\x1af\x18\xfd\xae.\xa3\n5\xcb\xc9\xa4\x874r\xfc\xc4/g\xec\x12qC\x80\xb7\xbc%~\xb5\x05n\xe6b/N\xf6\xf6\xfd\xeaX\x1f,\x92\xcc\x7f\x03\xe2\x92\xdc\x88;/\x85\x91 \xb2_\xfa\xd0\xffv\x11\x05\xfb\r\xd3\xc8\xaa\xf8J\xca\xd3TP\xbb\xbf-VbY\xe8\xdey\xe9\xce\x14#\x98N8o\x04\xd944U\x04,6\xccYc<\xa4E\x0b\xd8'=ggl\0>H\x1cO\xc7\x07?8\x99\xe1\x81\xcec\xb8\\Y\xcc\xc4AP|5\x9e\x132DJ\x9a\x84\x13[\xb0 \xed\x12#*\xadl\xebj\xd5\x06\t\x95d\x97\x1aJ\xa2\xb8\x04\xe09\xd4\xdf\xfeG\xdd|I\xc0H\x08s\xc8\x9f\xc9\xe9\x1e\xde\x93#\xad\xcew7_<|\x9f\xbc\\\xfei\x10\xa4\xd0\xa5\xdf\x14'\x9f\x1b\x8d\x84\xda\xe0\x8di/\x06+\x07`i6\"\x84\xfd-\x1aaF\x9f\xa1& =\x1e%\xd4f\x88@\x99a\xa1\xd7\xc0\x80\xb7\xdc\xafJ\xa2}\x0f\xcb=\x9e\xc7\x91\x12\xe6\xde\xf9-\x0eO\xb4\x0e{5T\xa0\xc5\xc0\xbcl\xce\x83\xe9\x9aJ\x89\x97t\x1fmcs\x1aBz;,\xc4'\xd8\xd0\xf9\x9c\xf3\rz\x856D\x8e/AI\x0bb\xf7[\xbc\x19W\xc8\xbb\xa8\x87\xd9]\xd12\xafq)Y\xb9\x87\xa0\xa6\xa2\t\xaf\x8f{\x84T\xcd\xb8\x8d\xb6MYv\x84\x1a\x90v&(4\x92a\x90\x08\xc7]\xb9x\x864\xb2\xb4\x94I\xd7/(\x01i\x87\x87\xdf\xcf\xa6\xabG\xfdN\xf1\x02^\x11h\x8e\x872c\x9dS\xeda6\xe6|\xc9\x9d\xa3\xc3}\x05R\xf5_\xda\xc5\x14\x8dSUO\x0cD\"\x8c\x98\xfdS\xb18\x0f\x17\x02(\xb1\xc2\x86\x9d\xc6>\xd4\xf7+\x96\x17ckL\xefR5\x7f=#\xc9\xe4,\xf9\xf7\x85`\xa2\\P\t\xed#U'\xf0\xc2\xd0\x1fP\x11K\x1a\xd8\x94\x97\xd9\xdeI\x91k\xe2\xfc\x07\xcc\x8cV\xcajFd}>\x0e\x08\xe1\x1c\xca\x81M\xdd\xfc|\xb19\x99C;\xb9\x06M'EM>\xcd\xbeO\xfe\xb6\xf5d\xf0\xed$\x05A\xcaT\0b\xce\xd6.h\xf4\x156C\xaf\x9a2{\xeb\xeb\n2P!xX\xcf\xb8\x85\xe1 \x8e\x9b\x80dz\x17\xba\x94\x90\x98-\xc4t\t\xde\x9f9\xd9\xf5\xcd\xc4\x9dNx^\xd6R\x11\xb8M\x05\x95\x0eK\xae\x8d\x80w\xde\xfd\xf3\xa8\x90^!\x04\xdb`\xf7\xc3\xd2\xff\x02oF:Z\xa1\xcbu\xce\xbd\xf17\xf5\xf7\x8a\xf1\n\xfb`\x01\x81\x98huz\xca{\xfa\x8a\x85+\xd7AF\xc8\rp\xf8Z\x91\x14y\\\x02j\xafC\xed\x069N\x90\xb0\x8e\x04\x1cK\xf4\x9cw\xe4}\xb9\x94{]q\xeeH;/<&YL\x19\xc7\xd6\xf2\\\xa1S\xf4\x15,\x9cZ`\xa7\x89\x08\x9e\x065\xaaH\x1a&/i\tr\xc1\xa3\xc2\xe0c\x0bY\xb0s\xe8\xb7\xdb_J\xe5T\x98_\x9e<\xb2\xea\xb2\xb06u{'\x8b;\xa9\xf8\x1f\xa9\x02\x97\x80\x99\x9c\xc8\xee\x85\xbd\xb5\xa2\x07\xa9\xa1\xed)'A\xacB\xf5j\x03Pu\xfcV\x8b\x1f\xf6\xd5'\xff\xc4\xb1\x96\x96\xb9\x06J\x82ME\x1e\x06\x1bB\xd7$\x82`\x1aA\x85\xc95|V\x06\xc5\xc4,d\x99\xc3q_\x01\xc2\xfe\xdb\x10\xc5\xf3\x91\xa0\xc4-\xa5\0{.\xe3\xea\xb1P\x9dnP\xbdV:B[\xf7;\xb0,j\x92\x9f)o\xbe\xdb\x06Lu\xb4(\xeb\xd8H\xa7\xff\x03dl\n\xf6\x8eF- *\x1a'{^\xc05\xfeI\xb8\xd0b\xbcsgj\x82\x88m\r\xb1lt\x0e\x11\x1dT\xdbz\x8c\xe7\x82\x13\xa8\x02mQ\x18U\xe0\x93mB\x1f\r\xa8\xf4\xb7\xb7\xc1\xc8\xe7\xabkV\xd2\xb8\xb8\xd9\xb4\xa9?\xc7\xb6x\x0eb\x81\xbf\xaa\x81\xec\x08\xe2\x1f\xca\xa73\xc1P~\xf1\xa6^\x9cP]\x16\x85\x84\xeeC\xdbr\xea\xfd\x06Y\x04\xe9~\xa4\x05\x01\xa2\x83\xbb\x9b\x81x\xbb\x83\xca0,\xd5\xd7\x9d\x94\xe2\x93!(\xd8\x0e\x83[\xf5\\\xef\xe2v\x83\xbf\xe7%q\x83\x8a\xcc\xefBh\xff\x08Y:\xda\xdf\xa9\xc5\x01U;.7\xf0\x88\xa2\x9a?\xdf\x98\xe0x\x7fj\xf6X\x18+8y2\x06h\xdb\x9e\xa4;f9\xe1L\xd6\xf7\xf4(\x7f\x91\xbd\xdc\x8c%\xff\xa7\xe1d2Q\x8a\xae\x94g\x9c\xa3D\x14'\x1d4\x06os\xbcY/\xa4g\xf3\x96\x17\xfa\x1f\x07v\x93\x92\x18}\xb32N\xeca\xda\x16\xe8\xf6B\x91\x8dL6PP\xc3\xf9\xbe\xa1gW)s\xcd<\x0c\xa26K^G\x1e\xcb\x0e\xd7\xd7F\xf3\x1cI=\x8d\xbep\xba\x88\xfc\x0c\x02?\x8d\xb8/:9/\x07\xba\xc3\x1f\x07\x01\xa7)\xa5\xd8\xf1\xf4\xaat\xd3\x11\xe8\xaeU\xba\xbfU\t\xd3\xdd\x01\xb2\x9c\xe3Fe,\x93K\xa0q\xe6SG\xfd \x08\xe7]\x10\x8c\xa7*\xaa\x84\xd5\xc2\xa5Zm3Y\x12>\xc4r\x1c\xc9R\xf7\xb5\xde\xd0\xe7\xb8\x86\xc1\x19\xf5\x17V\x9b\x88\"L\xc0\xcdOr\xb4\xa7\x0fe\xfc\xa0\x1b\x0e\xaa\xe2Z\x80\x1bj\x9a\x8f_\x0c\xc0\x163\\/\xfa\xb0?g\xa1\x04\x05\xe6\xfaq\x1ev1\x85\x16\xc9\xf5\"\x8b\xdc\x14\xadO\xd3]\x0e\x91Jh-\x80I\xed\xc9\x8c\x82\xfa@?\x18*7\xff\x08\xe4\xdc&\xf6\x12}\xfa\xcfRH&\xf0\xceT\xfa\x19S\xd6\x14\x17\x01.!\xcc\x03\xd2\x7f5\xcd\xd8-\xf9vZ*Y\x02\xf0\x1d\\~Vv\x1b\xc8T\x86\xab \x0c\xf5\xb3\xee\xa2\xd6f\tv\xfe\x0bs.\xd0\xc2q\xc4\xf5\xb6^\x80\x05\x86\x84\xf9s\xf5\xf8\x13\xde\t\x9d}\xbdwi\xed\x19V<\xc7\xac\xcc\x1c\x91g\xcb\xc2\xc8<[x\x8d7\xcap\xc4\xf8\xb3\xcd\xb9\x1e\xc0\xa7\\\x08\xe2\xb0%x\xef\xfbd\x06,\x11\xb0\xb1%\xa4\xa3\xfa\xd7}\xda\xf4\x10|\x8e\xc1=I\xaa\xc9Ky\xa2\x8b\xbex\x96\x07\0\x89\xba\x85\x91?\xfb\x05Vq\r1U\x94p\x0c\x8fP:\x19K\xba\xc40F<*\x9a\xd2\xa4$\xed\xb7\xb2~\x07\x86\xe0%(#\x8f\x03\xc1r\x82$u\xf9O!7\xdbj\xbfT>\x1a\xea<\xfc6@\xbd\x9e\xbdF_d\xfc\n\x04g\x07\x85x\xdcT\xa5V\xd7pT\xa3\0q`\xa8\xef\xb5\x91\x02i\x95\x8c\xfd\x19\x9b\n\xdd\x98\x9f\08h\x0bj\xee\xe0\x92l\x07:\x033Y\x1aR7:8\x93\xb0\x7f?\x0eW\xd8\x8aDo\xb6d\x90\0@-\"\x8e{\x19\x10\xea9Z\xdc@\x84\xfe\xf0fXo\x88\xe9\xe1O\xb6\xc3\xe2I\xb0!\xe9\x87\0.\xe1\xc4\x0bJ\x15v\x0e\\\xf9\xdd$\xf5&Nko lg\xf4\x9c~\x99P~\xe4&nN\x07CT\x94@_\x93Q\x02\xac%\xe8\xbc;\xd4\x0f\x18\xd1\xbe@L=>A\x95\x19\xf6\x18\x9ek8\x8a\x89\xae\x84\xe2\x10\xe2;\x9e\x16+P<\x87\xa1\xc1%\xae\x0e\xa4HE\xf6%4I\x14\x98\xc4'\xd4\xac1\x1c\xcf\x19\xbd<\xf1(\xd7\x99\xd5Zw\xad\x93~\x0c\x05\x96\x0br#\xe1\xc2\xf2f\xe9\x1a\x82<\xe9G\xf8\x19\xceC\xe4r\xbfj!&C^\xdd\x0cQn\xa3'\x80\n\x9d\x93\xabA\xa3}\xcc\xb8\xff\xeb\x8b\x12\x12\xf3\xf0g\xb7\x1f\x9bp\xa3\x12\xb8|\x8d\x8e\n7\xfaH:\xc2\x1b\x1a\x0f\xc4\xcd\xc6\xb7Fj=4\xf6+\xbaz@\xc0\xb0\xce\xebA\xe1\xe1\x90\x9e\x84\xa6\xd6\xf8\xe4|X\xd4T\x88\x99\xc5F\xbf\xa34,C\xe92\xa0te\x16\x07\xf2v\xbe\x8a\xec\xf8@\x1a{\x14\xcb\xbf\xdb+$Q\x1e1\x12\x96p\x849\xb3 ZZ\xde\x08\xb4\xcd\xf1\xc7\xcc9\xf7\x9f\x04S\xd0\xff\xc6\xd5#<*D3P\xc5\x80\xdcH\xc9|)u\xbb[\x95BE\x88D\r\xb6r\x1a;\x89\x81IC\x90\xe1J\tw\x89\xed\t\x96\xe6]\x9a^W\x12\xc1\xa5\xf0\xceb\x86\xfa-\xb2\xe47A5V3&\xa6?g\x10P\x18\x85\x1d\x84:\xc8l\t\xc3\x15~\x94\xe5\xee\x85\xa0\xdb\x0c\xb4\xba\xc7\xd7\xa1fb\xf4\x1eC\x1a1\x06\x7f\r8\xc72\xdd\xa0\x83f\xc7\x03\xb5 \x85\xa9\x82\xc5\x07\x0f\x8b(I2 \xdc\xbfJP\x08\xa4\xff\x8f1\xa3\xa5\xee~\xf3NZ\x07\x0c\x96\xb9\x1d\xa91\x12\x04\x1d`R\x116e\x9d\x95\xf2}\x1c,\xad\xab6\xbc\x1c\x84\x87!r@\xcb\xe2_lA\x93\x1beHF\xaeM\x10\xc2>6|\xf5\t\x13\xc6\xf7\xcc\x04\x86\x9a\x06\xa6J\x95\xb4B\x8c&\\ f\xa36\xce\xa1j%\t\x9c\x96i\xa5\xe9=\x1a\xd8|X\xfe\xb3\tb\x90\xdc\x85\x19\x7f\xda\\PM\xccO\x94\xed){\t\x99\xd8\x8a3$\xd4\xaf\x19S\xb8e\xed\xbd\0\xc2i\xe1\xdc5\xc8\xdaivU#\xd7\xe9y\xd4t}\x85\x13\x88\x80\x82.\x8bB\xe5\xa0\xeb\x03ZK\xb3\xa5\x19Fa\xb7\xa8\x16\xaf\x11\xb9\x06\x14\xdc\xa5\x9b\xc1\x08\x9f\xa7\xbb\xf9\xf0\xda\x8aN\xccy\x07\x11X*\x02\xff\xf0\xfe}@\xbcRY!{\x08e\xe4\x82\xb9\x88\x19\xca\x8f `^\xf4\x1c1\xc3\x84\xf5\xa2\rV'Eh\x13\x91\xd4\xe6s\x14\xdd\x07\xd3x\x9f\xe6=t\xcbeq\0\x0b,\xef\xdb\x1a9\x07N\xa3\xa1F\xa0\x85\x93\xbd\x19\x1e\xf3L X\xff\xd1\xc5Z\x8d\r*\x9d\x87\x06\xd6\xbe\xe1\xdem'\x94PWi*1\x1b3\xaay\x9d\xa9~n\xf6\xe0\x9eSS*\xe1f\xa5\xa5\xa2z\xb3\x0bw |\x88\x03LLM,~\rD\xf65\xe5>\x82~\x17U\x01}9d#\xe7\xedOJ\x9c?nTaJ\xc2p\x0e\xab\xc5n(\xef\xaa\xa4qA\x9a:\xad\xa9+*m\xcc\xa3\xb9\xd1\x0b\xaeX\xceaL\xe5\n\xecZ\xdc\xa0\0HpA$\x90\x85\xb0M\x98Lq=\xaeEZ\\\xafD9\x14\xe8K\xda\xa9\xf4.\xd8MgZ+\xf3\n\x82H\xf2\x9ah\x1e%8\xf7\xff3\xfa\x05E\x89Y.Ts\x08k^iH\x8b\x90\x1c/T[\xfb\x9b~\xf2\xb9\x1f\xd7\x8a\x9e\x80\xc2\xd2\x13]\xd5\xd8\x07\xa0\x03\x98\xaeo\x01\x07e\xcb6\xe1B\x11G\xbc\xd0T\x07@\xf0n\xed\x87cK\x91\xc3\x9deZ}\xe5\xb1,\xe8\xeb\xb5\x81\x81\xcfQy\xf5w\x10\x14\xeb\xe4I\x84\x99\xf1\xbb\xa7\xf0[\x10\xae\xc3*\xec\xe0\x0e\x1fr\xe6_\xebb\xcc:\xd1x\x8d-\xa44m\xdfM\xdc\xbco3\xb6E\xb5]\x0f\xc8y\x9a``g9KT}\xfc\xfci*\t\x9b\xe4j\xfc\xe5\x7f\x99\n\xf4\x8b\x8b\xcbjb\x89\xfe\xb4\x0f\xec\xc7\xd4\xc7{x\xfe\x7f\x9bA\x10\xfe\x0c\xde\"\xab\x01n\xd6\x88D\xec\x91\xdam%+\x08\xc9\xa2\xcd\xc7\x80^\xd9\xba\x87\x97\x0c\xee.P-\x1a\x8a\x8e\xb9\xb4]SjA\xcdrU\x16>L}\xa9\xdd\xe2\xceB\xdf\xa1w\x0f\xefD\xcc\xd5\x1fE\xac\x16\xc8L\xfbp\xd703\xbeH\x94\xe9h\xc9Z\x90S\xbf\x08\x84\xe9x\xe1\xa3\x12\x90?\xa8]\x1a\xe1\xd4G.X\xecTRtd\x16L\0\xfd\xf0\xe86:%%\xb8\xb85\xe2]\x81\x18c\xa72\xba\xa9\xcei\x959\xd7\x1dX\xd9\xc8B#-\x88\x80\x9e E\xa1\xbf\x90\x7f\xda\xb94QO\x04\x1be\xcf\xd9\xf5\x95Za\x7fP7_\xbe\xcfE\x86\x90\x8bi\xd5\xfc6{u\x1d\x17=4\xa3\0\xc6=\xdf\xe6\xd1\x90\xd4\x1f\xc3l\x83\xe6\x8b\xb9\x16\x19\x1bz\x97~\x87\x0e\xe7y\xa8\x13\xbb@\xb0B\x8ff?tQ\x95\xb8~,=\xbe\xe4bd\x1dM\xa5.\xfa\xc0\xc3\xe8dm\xe6\xc1u\x12\xb7\xbd\xea4\x0e\xa1\x0f\x11B\xa1\x88\xb4}\"\xd1\xdcs\x17\xa6\x80\x14\xbf\xa9\xcd)\xea\x96O\0hCM8\xdb-(\x8d\xf7\x96x\xa0\xe0b\xc9\xb4\xe8J\xbb\x11\x97\xf6\x82\xf3\xf45\xcaqO\x18`\xa9\xc9\xd4]M\xd6(\xfe\x0eR\x96\xdf\xba#w5,\xec\x82sD\x07U\xbaa\xca<\xb1\xd5\xa00_\x84\xd4DbB}\x81Db\xe4\xd1\x97\x06\x99\xab;\x89\x84\x89\xfd:@\xa9\xfc/\xdd7\x14\x987\xf0^k\x8ev<#\xb9\xbc\x96\x17L3\x87\xd6\x99\xde\xffz\x9b/\xdd\xb5\xb4\xcb?y\xb1a4\xc5\xb3b\x15\x8d\rS\xd2\x93\xda\xe2\x81\xaf9\xef\xd9\xec\xb6\xc79U\xfc\xa3\xe1\x8a>Y\x05 \x8f\xb9\xcf\x91M\x19\xaa\x13~\xe95~+~\xd9N\x1c2\xba\x1b\x1f\xc4v\xeel'\x1e\x9b\xae\x12t0\xb0|g\x97\xa0VoI\xe6\x08\xdb\xc0\x97\x8ef\xcd\x7f)\x8b\xd1'S\xe4\xcb7#\r8e<\x02>\x9dG\xfb\xb4#\x03i\x87\xe0\x0f\xc5\xd8,[\x894\xfdH\xd3\xc0\xad\x90\x96^e\xb6\x9d\xf9\xb7\xe0\x0f\xfeM\xbc\xae\xc2YW\xbb\x02t\x08\xfc1\t\xbb,\x1f\x9a\x11\xe0F\0\x98\r\xd2\xb4z\xec\xd7j\x07\x0f\x03\x91\xb5\x9c\xe5\xfd\x18\x83rp\xc4Q\xcc4R0\x08=\xa4gi\x96\x1bnJ\xaa=\xb8\x042Z\xe1\xd9\x1f\xfa\xc8\xe8\x066!\0\x96)\xe8\x01\x8f\xb0H{x\xb0\xbf\xd7\x1c33\\\x14\t\xf2\xb2sNx\x160\xff\xbe\xd8\xad\x89\x94^\x9e\xcc_\x82\xf0.Q\xcb\x0b\xdb\xd7%\xb6\xb9\x93\xf7jYB\xd5i\x1a\x85{.W+\x0e\x1a(7!\x87Y\x04\xb6lK\x86\x88\xd6\xa2\xe2\xf8\x89\xf9l\x0f\xce\xd3/\x98\xd8&\xdd\xca\xdb`_\xd7\xf7\xa7:C=Jy Q\xcb\xabu\x0ft\x02\x8f\xf9\xda3^\xc3\xfdg\xf7\xdf\x139n\xe6@o1\",&:a\xf7\x08\x94\x10\xaa\x93W\xbc\x85C)\x1f\xe6%\xb8\xe2\x14\xf7\x9bd\xacU\xf2\x06\xc8k@\xbb\xbd\xbf\xa9\xfe\xdd\xb2\\\x1bzZ\x95\x93K\xab\xdc\x0c\xb6\xd2|\xf3\xb0\xfd\xdb\\d\xe0\xa6\xda\x18U\xf6\xcc\x0c\xf4\xd9\xb1q)\x01\xeb\xc2F5&\xdc\x1b\xfa\x15\xee\x88\xd5\xbd&\xac1-\x8c\x96J(NSu\x9b\xb1\xc2\0\xcbAx:}\xd8\x8c\x9e4\x0c\xcc\xee\x06\xb4\x90\xb6w\xb1\x9e\xf91\x9b\x91\xe5\x86\xaed=\xddO\xe4S\xee\xc2\xc2\xdfE\xffh\xbdh(\xbc\xdddl\xf2`\x97K\xae\x1d\x0f\x1cx\x8c\x14e\xed\xff\x93PW\x05a\xe3e\x81F:\xf0\xcc?O\xe3\x8c50>\x95E\xea\xb7\xd8+\xe6P\x8d\xa8=\x01\x19Y\xe6?\x9dLU\xf1\xa3\x99\xe6\xc5F\xd0\xce\xa7V\"X\x03\xd6\x15f\x82\xfb;\xb6\x90$\"\x07\x1a\xe0\xde\x1a\xfd\xf4\xc4\xf1<\x0e\x0c2\x90\x171\x08\x01\x1d+\xef\xad\xf1r\"\x98\xb7{\xf3\xa02\xee\x89\x15\xf4\xbf\x86?\n~\xab\xa2\xccq\xd0\x9a{\xae\xb0\xe7\x07\x8f\x99\x19&J\x9fHS\x9b\x9d\x04\x91ki\x03\x9dz-\x01\x8f\x89\xf0\xa1\xeb\xeeM\xeei\xa8\x0b\x0fG\x06\x94\xcb\xb9\xd7\x03\x12,2\xb6+!\x8b\xa3\x81\x98|id\xf0\x1a5\xaeh\x81\x15'*P4\xce\xff!y\xd8\x02t\x94`\xfa\xb6\x8cc\xaa@=\xe63\xb4\xcdA\xf3B\xad9\x06D\xbd\xd5B\xdb\xf31e\xb2\xb3\xceL\x9d\xaa\x8c\xe5\x1dP\x1b\x12\xfa\xfc\x8e9~\xb9\xf6\xfc\xe3\x8d\xbf\xdf\x90\x9e'\xd8w\x1d\xb3\xad\xcd\x98K\xd51$\xcbDe\xf9\x9fP<\xa4\xf1\xdfP\x0c\xdf0ON\xa7S-\xd7\xa0\x14\xa4\xf9\xc2\xba\x02*.\x9ac\xc4$n\xc7qs\xa6\xe6:&\x0c\t+1\x85\xd6\xc1\xe7\xa6\xad\xee\x12\xd1AZA\x15v)\xfff\x81zP=\xbc=\xf34\x191\xde\x85\x86'\x13\x8b\xf3\xc6\xdcX\x1b\x11n\x05\xe8\x8f5C\xf2\x94WS\xfa\xabV\x19\x8aj\xc7,\x9c\x94e\xf9\xe9\xdeG[\x03m\x04\xbd\xc6\x94\x87\x07\xb2[L\x98$!C\xf9\x1c\xb9\xf7\x10\x0e\x92&\xb5a\xeb\xb6\xf5\xacm\xdcy\xb2\xbe\x0b\xe1\xf4f\x14;\x0f\x94\x8bO\xc6\xe7\x064\x1b\xafo\xd4\xbbIa.\x8a\x95JZ\0\xec\xc0\xe0;\xfb\x8b\xad\xde>\x7f\x02\xf5\x9e\x80\"h\xca\x0e\xab4\x1f\x07\xc5\xdf\xa2\xb4)\x185E\xe7\x8e\xff\xf6\xab|\xf9y\xefA\xea\xb1C\xc5J\xc8\xd0R`\x14g\xd6<\xfa\x7f,\xe1\xd0\x82\x02\xfe\x08F?6\x10\xf7P3#\xfe8\xb9\xfeP\xe9\xfb\xda\x0c\x91\xaa3\xf2K^J\xd4\x81\xac7\x0c:\xcb\x84\x96(\xd2\x7f\xe0Lz\x88\x8c)\xa2&\xc3z\xe1Y\xd87;c\xe1\xd7\xbd\xc3dO_\xbdp\xb1X\xac\xcd\x86\x8d\xbb\xedD\xf8kwb:\x11y\xec\xe3a\xa5\x95\xcd2\xd3\xc1\xcb\xbcCr9\xe0\xe4\xd9~B\x88\xac\xc3\x97A\x07\xd7\x88\xb4\x81\x8b\xd6V\xca\xab\x10\x9c\xcet\xe4\xa8\x87\x04\x17\x04/*\x9b\x89\xe1\xa1\x80\x13u\xab\xbfE\xa5\xf0\x86\xae\x88\x87OU#\x06?\xe8 \xef\x9c<\xa2\xcf\xd7\xc2A{w\x05}\x87v\xcc.\xe0X\xb3\xdf\xac0\x16\xdfYlqx\xc1\xed\xa8\xe0\xec\\4N'4\x1a\x89Dw\xa4\xeb\x16\xf3\x169\xf8\xa1)\xe6\xb1\xf1y\xd4y~\x7f\x81Q\xd2BI\xdd\x7fB\x85\xb9\x05\x85/\x87%xY!\x83a\xc6\xbc\xfc\x88\xd0\x99\x95\xc2\x06l^h\xe4\x0f\x87\xd31\xa7\\\x1b}f\xe4B6\xa007%c\xe3\x07\xb4>t\xbdG\x86\xe3f;\x01\xb8\xee%Pq*\xd3\xd1~\xd9\xd7\xb9-\xe2t8\xef\x10\x06\xaf\x99U\xc2\x12\xd6Et\xf4X\xee\xbbt\x88\xab>\xcc\xcf\xaa\x9b\xf4\xe2\x97 #\xb7\xff\x0e\x99\xf652!UM\xf4\t\x0b\xb3\xaa\x06\x0455\xde\x8eX?\xee\xa2\xff\xe2N\xb7)\xe1bGB\xe0F\x8a\xdb\x84\xc2e\xa6b\xbd\x91\xcfB\xd6\xa7\xf1\x94\xfa\xf3\xfbaV6\x9ax,\x03+\xca\x8bHW\xf0\xe9LpG\x11cU\x0cs\xb14\x8aYT@\xcai\xaf*\xf6}\xd2\xb9a\xcbDx*\x8c\x13I1\xc6\x19=%O(@\xdd0\x82\x1e\x81\xcb.3tk\x0bb\xb2\x98\xaa\xd7v'\"e\xbb\xab\x94!\xec\xb4E!\xc5\xfd\xd3\x1a\xc1n\x9e!\x94\xa5\x19\xf4,\x045\xab\xd4`4\xe6\x10\xac@\xee\x88x\x9fPc\xb7\xe6W\xf1$\x13e\xb3\x86+\x0c\x9e\x8b\xc8\xb4N\x7fG\xb9,o]\x9e\"\x0bD\xd0\xdaZD\xc9\xc0\xae\xe5q \x8eJk\xf3o\x17B\x16c\x9c\xd5M\x16\xc2\xd7\0\x84Mz\xa1\xf2l\xfc\xe7\x8c\xa6}\x8d\x8b\x19\xe9\x98\x94\xec.\xba\xb31\xdb\xf2\xf0\xf0\xff\xe6\xb1$\x95Uz\x9bUn\x1e\xec\xdf\x9dmF.\x7f\x80\xbfA\xcd\xbe\xb3\xc9!vbW\xdf\xaf\xa5\x8eh\xf7[]T\xcd\xc8d\x15Sse\xf9Iq#q\xe1S\xdb\xe2\x9ac\xb3\xa0\xe7\xe3b\xdf\x0et\xa5y\xc076\xc8\x8beR\x0e\x05\xcf'\xd3\x05\x19\x89\x8d@\x12\x18\xccyf\xe9=1Pf!\xdf\x7f\xc8V\xe2\n\x18ZF<\xdd\xcf~f\xf4\xa9O!\x98qCZK\xb3*\x98S\0\xa4\xa8k\xa1\x13\xabM\xcb;\xc8\xdeh\x8e\x139\xa1g\xf7x.D\x8c\x8a\x87$1\xdd\x90B7\xael\xa8'g\xc5\xbf\x01\xa4\xe8\xfc\xf9,\xd7\xe2\xdf0\xad\xa19\xae:H\x82h\x1e|Y\x14(\x9f9\x97,\x84\x9f\x19\xd5\xf1\xeae\x01\xf1s\xaf%a$\x1b\x8e\x7f?+X\xceA\xa4\t\xfdR\xd5\x91\xa9\xfd\x9eF\xa7\x99F\x1dL\x06\xd5O\x84\xf9\x07>\x81\xb6]\xf9b/\01W\xbd=\x97G\x85\t\xdbO\\<\xb3\x9e(\xf8\xfe\xe4rsd\xb3n\x8d\xe8jyY[e\x84\xbcpsxso\x9a\x95\xf0\x11\x0f\xd5 l\xd8\x8a\x11\xa3\xd2\xb8\xe5\x15\x18y\x89\xaf\x04\xea\xc1hta\xb0{\x01/\xb6\xd3\xcbW\xd6\xac\xda\xf1.0\xf8[Q\x91\xc5)\xf976\x0c<\x0f\x01\x80\x11\xcf\x89L\xc3\xc7\x04\xf6\x89\xeb\r\xfdmq\xec\x1a\xe9\xc2\x18\xae\xb7d)\xdd\xe3\x1c\xd8K.\xa0\x9b\x18\xdd\x10\0\xcbU\x88\xc3\xe9A\xa55\xaf\xfaE\x95\\45[\xc6(n\x01\xb2H\xedH\x7f\x0b\x84\x17w\xf3P\n2\xc5\xe3\xacFS\xd6\xb9\x18,\xac\x7f\x1e\x93\xe5U@\xbf\x1a\x9c;6\xf4D9\xf2^\x14\x92\xaf\xfc+\0\xe4\xae\x91*\xd7!\x88\x95\xa0\xf9\"?\x89&\x10i\xd3-)oI\x97\xaeO\x18.\xcf\xae71Q\xaa\xbau{\xfbX\0K\x92nv\x1e\xa21\x05\xed\xcf9\x9f\xc8\x06\xcb\xe0\x1cd\x19<\x1c-\x0b\xa1\xfe\x7f\x1c\xba\x07YDg8\x8b`\xcf\xde\x88/\x8b\xb6n\xa0\xd7V\x8a\xc0\x8d\xde\xab2\xcfT\x90q\x8cl\xad2e\xe3+\x9f\xee\x03x\xd0\x1b\xbcd\x98S\x12\x87\xe4\xa64\xc6\xd2#tP\xfc~\x9a\xb5=U\n\xe5vrh\xc6=[\xf3\xec\xc7og\xab\x8d\xf3\xbcURf\xae\x8c\xc7d&\xb0\x9a\x8e\xd0\x08\x0eU\x08n\xa9~\x8dy\xb0\xb6\t-z\xedW-\xca;\x92\xcc\xe3\xd8\x91\xd3\xa2nz\xd9\xcf\xbf\x9c9\x7f\x92\x0f\tg\xfc\x06\xb2\xa7\x90\xf4j\xc3\x15\x06<\x88&H\xe12\x99\xf8\x81\r\xd4<#\x8c\0q\xca\x10\xdfd`\x99>\x01w\xbfw\xac\xd2/<\xe8z\xcf\x84\x0f\xbb\x15\xef\xb8\xfd\x96\xb3n\xf0^\xea\x90\xcd\x03*y\x9c\xbc_\xa8\x0c\x9d\xb3B<\xbc0\x80\xac\xc1.C\xa2\xb7\x84\xda\x17\xbf\x7fG\x9d\xf4{K\x9d\x94e\xde\xb1\xe6\x04G\x86!\xc4\xfb\xc66\xc9\x16\x7f\xb4\xcb\xf0\xd6z|\xaa\x18R\xfc\xdd\xaar\x1d\xf9\xec\xac:\x9a\xd5+hx6\xbb\xd7\x1d\xf9\x1bF[ckmz\n\x81\xd5\xb7t\x9eA\xde\x9d\xbf\x95\xc6\xcc\xdf\xba\x18\x85\x96\xea\xe7,\00\xea\xedR~5\xaa\xd3\xb7\xed\x16oWG\xac\x0cn\x7f\xb3s\xbb\x8a\xc7\xae\x17\x92Y\xbe\xf3\x8c\x0c\xc5\xb3\0\xcaP\xc6}\xf0\x1c\xab\"\x9as_{\xb4\xbew\x9d\x83\x9d\xa5\x11u\x8c\xc6qL\x18\x0bR\xd1\x86\xc5\xa7g\x97\xe9\r\xe9T\x91\xe8d\x83\x8d\\\x9f\x88\xb2\x16#\xa9 Be\x06\x1aq\xb9\xbc\x1a_\xd9\x89`\xd5\xd5=z\xbf\xfdo,\xcb\xb4\xdbP\xf5\x8c\xf4\xd2\\Iz?%?\xb5-\x90\xe3J\xaa\xc6\xaf0\xcd\x05\xaf\x1e\xf3\x9d\x9e\xfc\xa92\xdd\xf6h\x93\x0e\xb3\x11\xfe\xecJ#\xe27\xbc\x80\xe8|\x9d\x9c\xab\xbb\x06y\xb7\n\x90n;\xa6\xef\x9d\xb9\xe7\x9bB\xcf4\xed\xf1\xa2\xb38\x85\xd8\x1d+\x7fu\x7f\xd6\x9b\xedx\x1c\xbe:5\x9aNZ\x92\xf1\xb4\xa3Vl;\xa2\x9bP\\\xe6\rX\xf86O\xb8\x9brxj\xae\xc7\xd5a\xc7\xf9\x17\x87\xfco\r\xcb/\x0cK\xeb`Q\xdc\xa4\x1c\x1a\rx!\xc8\x85\x95\x82:\x175p'\x1b\x91\x8d\x16#\xee\xfd9\xc3\xad\xa1\xcf\x9dw\xf6v\x03e\xfe&\xc9!&hA3%!@\xfd\x1at\xc15\xd5\xf8+\xba*\x02\x87\x9eR\xf2\xceim\0\xce\x96\xe5V\x92\x08#\xc6\xacy\xa0\xd5c(\x9e*F\xfac\xb5\x92\xc6\xd5\xa8\x92Oa@O\x1e\x115\x8d\xd6\xcf\xd5\xd7\x98\xb0\x894P\xdd\xa4\x90RI\xbc\"h\xad\xbd\xce\x8c\x88\xc7\xfc\"\xb7\xba\xf1\x12\xa3\x08\x11@\xecv<\xb6\xf3`I\x01\xa0E\xd9\xbb\xe0\xf95W?\xcb\xdbml\xa8\xe1\xa9\xc2o\0\xf6\xab\xb8\xdc\0$\x1a\xf5\xf6\xd5\x88\x86bS\xb2\xa0\x1b\xed\x9c\x9b\xd4\xf6\x01\xcb\xdf>\x10!\xde~\xc4y\x1frr\xabe\x7fO\xfd\x8e\x97A_\xde\x1e\xab\xe2\x1e\x0e\x7f\x9a\xa0\01j\xdd\xdc\t8\x9b\xc6\xea\x07\xa0\xc1{\x94\x1b1z\xa5;=m\xc4\xc3\xc99l\xa5PY\xda\x04B\xfb\xb0\x80\x16v\rh\xbb\xce\xbc{i\xca;\x19\x0b\xbe\xeb\x91\x93\xf9\x16\xf5\t\x93\xda~\xa7L5\x10\x8e\xb8\xb0\x7fU\xd2\xc7\xb1!\x88;L\xc0\x05\xf4\xfa\xb3\xab\x03\x84wOP\x06\xf6,\xf7qt\xf6\xea\xb7\0N \xc4\"\x99\x03`u\xac2&\xfe`x\xe3\xb6\xd5\xa0\xc6\xa5\x8b\x93\xc9\xb6{\x8b\xd8\0\xbe\x0cn\xc2\xd9T,7\xe5U\xec\x14\xdd\xe2\t\xa4C\x10\x7f\xbb\x87]\xf53\xc6_\x99Q\x9cZ\xfa3^T\x13o\xe1\xb2\x8fU\xef\x808\xdf\xd0\x0e\x16\xfe\xacPU\x8d#\xbb\xb2\xaa\x13@\x0f\x99V\xbcb?\"?c*\x05\xc0\x16\x96\x04rQ]\x88y\xf9\x97\x86\xacG\x18\xac\xd3$\xb3}\x1d\x99\x9fD\xcb\xef1\x13W\x068}\xfc^\tA:%\xc5\xff\xb0\xf0\x8e\xd7o9\x83\x03\x0f\xc8\xaa6?\x1e\xb0\xe3\x169\xd6\x89\xf4\xed\xfd\x17\x81\xa0\xfaR\x86:~2\xba\xa4\x8b\x0ea3*\x08G\x13K\xe4\xb3WB\0|\x14}\xa5\x87M\xdd\x14\x86kj\xba\xc7\xa0\xe3@\x96*\x1alG\x9a8B\xaf9\xd8\x87\xda8\x0c\xa4\xcd}\x83\xaf|\x1e\x9a\xa1\x98\xf5\xb7\xd0m\x80Gb\x19\x9e\x0fv\xd3^\xe4\xbd!\x1b\xb2\xd3%\xc9\x07\xb5f+\xf6`\xfen/>EgL\xbb\xe4\xa0E7V\x10?\xb8\xbf\xaf\x93\xdbbu\xc5\xff\x06\xa1\xab\xf0K#y\x14\xbb\x07\xa3bN\xd8^\xcbBOV\xb0\x8f\xa8c\xb1+\xfd\xc6ye\x90\xe5(\xf5\xef\xc9T\xdf'${\xa3\xb8N\xec\xb1($[9G\x10\x06QkQA\xf9et\x04\xc4)9\x14\xbbh\xf7\x1d\xe9+\xddh\xe8VT\x8a\xeb\x9c)?\xc1h\xa3.sf\xe0\xbcQ/+\xb4\xdfa\x11\x1f\xd1\xfe)P\x8fr\xccO\x960\xa6\xf73+T0\xd1k\xe6\xf3\x15\xca\xdc\xc9\xe6S\xd5\xb13\xc8C\x86\xf6\x0e\x8d\x18\xd2\x87\xaf\x14y\xa7\x15b+\x06\xc0@\x12b?G|&\xdeb\x03us\xd9\xbd\xf0=\xde \xa7\xb1\xac<>\xff\xab\xba~\xb6a\xf5\xc4E\x1e\xe3\x98\x8a6\tUB\xd3A\xd7\xcc\xf4\x1a\x9c\xdd]\xb2\x0e$7\xcc\x17\x7f2\xf2z65\xe7\x85)\x0c\"&\xe9:\x1bU\xf3![#T\xa5m\x1c\xd8\xca\x07&\xd4\xbcd\xb7^\xa2\x0b\x02\xf9de=k\x85yiI\xdaA\xd6\xbd<\xff\r\x7f0\x96D\x0f\xa5\xf1\xa5\xf0h\x8a\x10b\xb9Z2\xf6\xc0\x05\x9d\x8e\xaa\x1d\x16\0\xcf\xa1A\x19w\xd0\xceOX\x16\x9ax\x99\xc1\xffs3b\xfa&6\x9f\x95\xccUfb&\xe2$*u\x8f\x8c\xc3\xf1\x06\xf7\x88\x9c\x89\x96\"\xdf\x0c\x06\x07C%\xc9{*\xd1\xea.\xf7y}\xb2F\xc4\x03\x06\xc3j\xe1\x98\x97\xa4\xfd\x11f\xf4\x1f\xfa\x1eD\x17\xb96Ck&$\xabs\xdf;\xe4\xe6\x1a\x07$F\x80!?l\x01\xa3(7\x8bF\xa0\xf8\xbeg\x02\xdbwM\xddp8\xd9\xa1\x93\xd4\xe0W\xa00\xb3Z@\xabB\r)8go]$\x16\x15 '\xdf\xe8\xa6\xbcw\xb1\xf7\xffY\x18\xda\x84\xc7wW%\x9e[\xa8\xe8\xcd\x91\\\n\x93\xcf\x16\xb0/a\xaa\x9c\x01\x92\xc5\x01\xcc\x10\xb2N\xb98\x02uAe\xfc\xbd\xa9\xdf8q\xd8\x8fuLi\xc4\x07\x1aN\x06\xa2\xb1\x81a\\\x14\xacx\x97m\xad.\x11!\xc0\xf0w\xb0S\"\x19\xc0\xb3chb\x0c\x11\xdb\xf1\x0c\xdf\xd3k\xadQ\xce\xd3Hp#\"\x8e\xd4\xae\x80_\xacY\xd9\xeb\xe0\xfb\x9c\xbal\xbb\xf9\x826\x94\x0e)\xdfY\xae\xd0\x17\x11\x10\xe6\xa8\xf4\x12\xa3\xcd\x19\xb5\x1d\xcfe\x82?\x8e\xc5\xc5cw\xa2\xdb\x8d\xfa\xfe\xb8oB\xc5\xa3D=\x9bLE_\x92\x17i\x83\x0b\xdf\xbck\xfbm\x9e\x1cN\xf3d:f\x8b\xd0\x89<@J\x96\x15\xd5&%W\x80\xb3IX\xber\x05Sc\xd3n\xaa\x8e\x10\xde\xdb\xfc\x08)\xc7\rW=\x1b\x99\x02\xb69^W\xee\xa3\xcc*W\xac\xe5bL\x983\x01\xbc\x19MO\xb9\xe2$;\xc2qMU\xc2m\xd4ji\x9b\xb7\x8a\x0f\x07\x01$o\x1e\0\xc0\xcd\x10\rk\xceJ\x8e\x87xk|\x91\xb4\xcbP\x9d\x1d\xb6\x98}w\xd7\xb6\xdcg<\xfb\xb1F\x89\xabV\x92ik\xc1%g\xf5\xbf\x91\xe1(\xcf,\xf9\xe4\n\x81\xc1\x93dW\xfd\xea\xe7%\xab$\xa2\xda\x89?B\xfc\xf7\x9d\xcb\xa9\xaf\x9e=\xb4\xad\x87\xe5!\x8eA\x06>Y\xda\x94\x1f\xe2\x13\x97\x80v\x8aBi\xf5\xfbh3{\n\xf2\xfd\x89-L\xa1\x81'\xa3\xd3\xd0}\xb3(\x8d\x87\xdb_\x19\xb9q\x92|}\xb4\xd0Gd@\x9dX\x0e`\xec\x8b~\xc3\x03\x93\xdf\x90`\x10e\x11\xe5\xf5\xba;v\xc8\x9dn\x93\x0e\xb5\\\0c\xe2\xdc\tt8r\x9f\xb3\x87\x7f7\xad\xb1q\x11e\xc2\x8e:\x98\x8f\xdc\xc3T\xe2S\xa1\xe2xG\xbb|J+\xa3\xb4\x8e\xfb\xc3$V\xc1\x92\xba\xd5\xad\xec\xb8\xaa\x03\xde\xc9739\xe2!=\xc6n\xee\xe3\x03\xa2~\xe8\xd3\xf5\xcb\xe1\xcc\xef\xe8\x8d\xb8\x8af\x04\xce&\xef\xea\xc6^\x85\x1a\xf0O\x8cwF~\xa3\x9c\xfd\x08\x08\xfdH\x92\x0b\xb4\x0c\x19\xa3\xbcm\xd6\xd9\xd4\x93r$S\xd6Qn\x08}w:4O\\l\xd0\x0b\xf1\xa3'G?\xc0Z\x1d\xed\x8ep\x85\xf6G\x7f\xc4{\xc4\x97\xf0\xf7\x83D; k3\0\xdd\x97\xc9\xe1\xb17npns<\xbfR\xc6P9W\xd7Z\x96\x9d\xf1\xcd\xa1\x03~\x93\xd3\xbe\xebb\xb0\x8a*\xef\xb4I?\xbfT<\xf5\x03\x05\xeb\xa8\x91&\x91\x99Ez\x83\xac\x04\x02@\x05P\xa1U\xcd\xdb!\xa8\0g$\xf97RHo\xab\xd8+\xa3p\x12\xc2B\xfd\xf1i\x03\xc3\x12\x15\x8b\xc6\xae@\xbcl\xd3\xa7+\xf3\x8b\xbe\xc2\"\xf6\x9c\\\x9a\xc2\xe4\xc2T/\xe4\x92\xda\x852\x92\xba\xce\x98MC&\x99\r\x9d\x07\xd7\x15jgl\xbb\xb4o,\x04\xc0\xd9\xd9\xfa\xa6\x7fU\x17\x1c\xbb\x95Nrw\x7f\xf4r#7\xf0m&\x81I\x19\x8e\x13]U\xa6\xc1\xbd\xb14\xc48\xd5d\x92+\x12\xc9E\xaa\xf8v~\xd2R\xb7\x03\x9b\x0b\xc4+\x0b!R\xc8\x06\x1bf\x93\x1c\xd4\x87\xb6\x8dC\xb0\xf2}\xe3\xd6\xdc\xb8iN\xdah\xb5\x86\xe9\0e\x86\xb4W\xae9O\x1f\xf6\x88'\x11\x0f\x1f\"\xf3M\x12\xd0\n\x86\xca\x8f\x12\x12\tE%-\xf1\xc5\xaf\xd0\xe03\xe3m\x1ep\x99\xb7\xf0cz\xe2\x83\xf4\x02O+\xb4\xfc\xb0p\xd7\xce\xcc\x8b\xadf\x05\x9b\xeb5\xd2\x0c\xdd\xed\x81\xd7\x85\xe1\xb2+\x8cE\x80}\xf2\xeb\xe7\x14J\x9e\xc5\r\xce\xf3\x08$-3\xb7\xd9\x1d\x1c\x84\xa6\x81$\x82\xd2\x86\x19\xb8/xq\xee\x830\xb0\xf8E\x9b\x89\x1f\xfa)\x9b$\x1d\xd55\xe2\xd4\n\xb6\xc1\xe8\xce\xf3\xc8\xbd\xc0\x80\xc5\xcb\x9b\xca\xb2C\xc8(\x16m\xe2\xcf\xfc\xec\x87\xa3\x81U/jU[<\x13\x14\x83\x99R\xfc\xe5\xce\xb1\xd6[\xb7\x92\xb6e\x95\xe2\xc0\x06}\x9b\x9f?\x95\x830%!\xb1\xe0\xc5(\xd1'\xf0\x10\xf2l\xaa~H\x95\rE\xe4\x195g\x1c\xdc\xd9E\xe4\xff8z\x8e\xca\xe7p\xdd``\x9d\x9d\xe3\xf2\x9dc\xa1\x89PW\x1f\xeeU\x935\xf8:=\x80:0\x08\xcd\x8d#\x7f\xc0\xfey\xaaGMY@\x8b\x0c\x80\xae\xed\x19*\xcd.B\x86\x1d\x95\xdeN\xbev$\xf5fF\xc0\xdb\xd7\xf2\x83\xd1P\xdd-#\x88\xa5\xc2\xb9\xce9\xc3b\xf92[\x8a\xc0\xa3\x86\xda%\x04\xd3\xfb\xf8\x0f]zW\x89'BnnI;\xd0\xb5IUW\xfa\x19A\x10\x97\xb0(:\xb7$\x92\x11;\r{s\xd9\x80\x9b-\xe5l;\x85\xc3\x0fm^\xd7\x86SE\x10\x17y6\x87\xecE.\xd6\x81\x8f/\xb7o\xecNQ\xb7q\xad/\xd4\x04\xc9#\x05\xfbK\xce\x0b\x7f\x95b\x8e\xf1\xd6I\x1b/\xf9\x80<;P\xa8\"\x16J\xda\xe9\x91HL\xe0\r+H\xb8\x9a\xbdp\xf0\xb4\xd5\xf1\x95\x95I\xdd\x7f\xc9uQ87\x07\xca~\x90qC\xaao1Pt\x05\x9f\x15\xdf\xfad\xc4\x9e2\xcb\x15N\xbek{\x89\xccT\xff\xf2\xdc$\xdc\xd4\x88\xbd\x10\xd2;\x97W\x9ceo/\x95\xcfK\x1a\x8a)f\xcf0\x87n\x81\xf3)\xd1%+\x15\x93EWi~5/\xac\x98\x9a\xb29Q\x97(M\x9f32N\x14\xeej\xca\xce\xec(\xcb\x1e_\xd9f\x9dm,\xfe\x86\xb42\x9b\xaf\xa1\xbdC|s\x02g\xde\xebr\xc8\xf0\xea[\xca\t7\x8e\x01v\xf2\xd1%\xbfv\xb3\xeb1\xb8\xf3\x89bq\x83\xde\xe5\x02\xd2&\xa3B=\xfc\xea\xd1\xdbnLb\x1c\xe2F\x12\x04\x97{\x06\x9d\xc0E\xff\x95\xd2S+\xa9\xd9\x13\xc3,\xaf\xb0\xe4\xc1\x87\x16\x90_\x1a\xab\xc9,\xe8Z\x04`\xc5G(\xfa\x1f\x0e6y\xe0\x91%h\xd6\xb7\xf5\x1b#T\x13\xd0=\x08\xd4\xec\xdb\x812K%\xfc\xd0\x1e/11O\r\x8a\x8ax\x88n\x91\xd5\xb92\xd4]\x8a\xba?\"]\x95\x11\xddI_\x12.\xb5\x03\x01\xcb\xea-E\xa1\xc1\x97\x10\xa4!\xde\xeecS\x97X\xc5\x80\x05)\x90\xee\xcf\xbf+\x90U\x8c)\x86\xb5\x81\x06Z\xe1a\x0e\xb5\xc45\xb5\x9c\x94\xc2(\xeaU\x87\xf1s\xb7\xd7`\x95\x92\xe4\xc7\x88-\x01\xf7\x93\xc6\xfc2\xa9\x8a^\x90W\x90\xf0on\xc8U\xc2\x0fYQ\xb8``\"\x0c\x1d\x94\xa4\\\x14Z\xdc\xe9\xa7\xf5I>\x95f>\xd3c\x01\x98iB\xf5\x9b\xef\x1d\xf61\xd8\xe7`\x9b\xbf\xf1\x88\x18\x9bk\xe9\x14hZ\x04\xdd\x17J*um\xdf\xf4\xb9;\x9a\x13\x108\xeb\t$\x80M \xff(I\x81\xa2\xc6\x9b4\xcf\xed\x84\xe8\x12}\x01G\xf3\xa7-\xf9\x9aK\xf1\xd0\x03\x17\x1a\xea-='\x8b\x01\xb8\x10p1\x86\x87\x1c\x1d\x13\x14<\x8fk\x8a\xcc7J\xf12\xc0\x9a \x82\x81!#\xe42j\x7f^1e\xf6\x1a([/\x8a\x04\x88\xaa\xd3(s\x97Z\xa8\x0eb\n\x0c\x9b\xc62\xdd\x8e\xb8Z*\x86\xdbq\xa0(q\xa9\xc9\xf1D\xc7\xab=\x9e \x03\x08\xed\xd8O\xbf\x84W\x80,\xda\x85\xf5\xffB\t\xc7>(\xd3\xdc&\x02\xad&\x8e6oV\xfb\xa81\xf3\xc2\xc8\xbd\xfc\xa1\xc1\xa3f\xf0\xb5\x8f\x97N@\x8e#I\xf0\x87\x1cM\xd39\x15Wa\x15H;To\xf9\xee\xda\xdf}A\x92\x9e\xde\x91\xbd\x8d\xcd\xbb/V\\1#\xc6\xc5\x01.\xd1\xef%\xe3r\x11\x994\x86\x9d[\x1b\xfd\xc2I\x8a\xe3\x06\x06\x1a\xf0\x17f\xe9\xe3jY\xca\x06 \x9c\x05;Pvi:8\x0c\x15\xea\xc6\x92\x16\xd7\xea\xf9\xc9!+D%\xef\xf7\xc6e0Z\xde\x10\xe9\x9c@80\x17\xf4\xec\x1c\xe7Z_\x90F\x1fk\xb7\xa1\xd8cdgC\xbc\x01\xd9H\xf97/\xf2BrQ}\x85\x0b\x85N\xf9g^\xf92\x11U\x9fO\x1f!\xc1\xe6\x0c>\xd8u\xdbg\xbe\xf2\xd7\xeb\xbc%\xd8\xd4\x81\x7fj\xa8\x89J\xcd\x98\xc3\x9d;\x84\xb0i\\\xecz\x81\xb4\xbf\\\xc3?}~\xc4\n\xefa64>\xee\xb1\xe5p\x0b\xa2{\x97\xde\xcf`~\xed\xc3\xc9M4\xbb\xdb*\x8b\x170\x1b\xee\xb3p\x8e\xec\x15\xa0\r\xe8Y\xf08\xf0\xcev~4\xdf^:_\xf8\xee\n\xd5\xe4%\xf4\x83\xebXf\xc0\xd9&\x84\xa1qH\xe0\x97\xdd\x9e\x938\x80\x12\xebCD\xc7\xcbb\x12{\xf0r\x08-\x1d\x920\xa4\xb4\xf7\x1f|\x10n\xe7\xb0\x1e\x87\xb8\xa7\x0e\xe2225\x84}D\x99\x0f\n\x8fS'2\xad\x0cg{b9\xddP\xd6~\xce\xd5\xe6U\r\xcb\xda\xf8\xc2-\x1c\xfa\\\xef\x0fH\xc9*\xee\xa2.IA\xd0\xd0j\xb1\xd5\xdcC\xea\xc1\x18\\\x05\x07\xb1\xd9\xe9\xb1\x9f\xfd\xb7\x97>\xea\xae\x02\xc66\xa5r\xf6\xfaTg<\xcbh\xe6\xae\xa4D\x96W8 \x19\xd1\xa9 \x1bf\x03\x08\x88\x08s\x0b\xd3\xda\xad\xa9W\x9e\xee=*\x1f)\\G\x17BD)\xf1\xcc\x87\x17\x0b\x03D\xd9\x02\x14.\x82M\x80f\x15\x13y\"\xdc*\x07D[\x08\xd6@\xe6\xa0rz~FT\xfdt\xa5\xc5\xc2bG\xd6\x91\xce\x8c#O\\\x06\x0b\x92\x02\x11\0\x92\xf7\xad~O\xeb\x9ex\xf6'\xf1\"\xe1|g\xa9\xe4d\x94\xc6\x8fE\xc3+6y\rm\x89\x9d\xddj\xe9Bd\xf6\xc5u\xa51\xf5x(\xdd_\xe8cy.@N?[\x0e\x8a\x97\x16\x88e\xa3Z\xe0\x1d\xcc7\xee\x93\xef\x8f\x10\x01\x0cir:2x\x9eQ\x7fl\xa1\xd4\xbc\xe2O\x90\xb7q\xc8\xc7\x94~\x06rUa\xd5\xee\xe2\xda\x0b\xa2Z _M\xf4yf\x1a)/\xd5MvP\xcf\xb7\xad\x89\x04\xee\xed\xbd\xfd\xacz\x1aE\x86\xe4\xb6n\xe2\xfbj\xde\x82\xa0(\x13g.\xd4\xd2\xd6\x8a\x19u\x85\xc1\x94EX~V\x9c\x15\x10\xa2_\x04\0\x8b\xbb\xf5\t\x98\xbf\x1eAG\xcb\xb3\xea\xf05\xec8\xa7p\x89\x85l\x88\xeb\x11\tD\xa1\xab\x0e\x0f\x1a\x9bae\\8\x98O\xb9\xb4\xe4\xc9\x01\xad\x01>'^3L\x87\"\x1bM\xa4W\x1fV\xe3\xfc=E\xbdR\x9a\xa5\x88s\xa5\x10\xe4\xf4\xee-\tY\x05\xd4\xcd\xba\x95f\xf7\x9b\\\n\xbf\xb3\xad\x11KGY\xf9\xe1\xf7\x87c\xe8\x0e\xb13\xa9{{/\x92k3C\x7ft\x84\x01i{\xcb_\x83\x11\xd1<\xe3(\x90\xfb,\x057\x17\x1b\x1bx\xb1\xda|\x0b\xa8{\xbe\x16\x1f\n\t\x0f\x0f\xd3\xd2\xc0\xdab\xb0\n\x9bs7\xda%\xe0F\xa7\xcc\x92\xd6\x03\xecA\xf9\xe5\xd3\x181u\xf1\xfcC\xdc\xb7t\xc5\xc1[`\xc5H\xca\xb4\xf3]\xed\"\x153\xa4\xd3\xd6+\xe7\x85\xd8\x7f\0\xb7/4\xdf\xe8\xf7\x7f\x03v\xfb\xf2\xae\x84\xcc\xf8A\xc0\xd6\xc7\xbe\xa1\x0b\x88\x95\xa8\xfb=\r\xe0\xbd\x94F\xd5d>\x19\x92vM\x1d\xaaGy\x93\xa8&i\xbb5M^\xdd\x02S\xb1c(\x0e\xe7\xd3]\x96v\xed\x9bp`\xb5\x9e\x1f\x1e\xdc\x0f8\xdc\x97\xa7\x88\xfb\xa7\xa2\xd0\xa6\x99\x12\xc4\x90~xA\xe8\xf6\x03`\xa6\xd8\x11l\xb5\xa9p9=+\xa3\x85Y\x1c\xc8\xec\xb2\x0c\xc8\xb7\xad\t\xdf\x9e1b\x07*vZ\xf6j\xads\x97{,\xe1\xc5\xc7\x9e\xed\r\x15\xf1\xf2;t\xe9q\xfa\xc4@1\x1e*\xa4\xec\xc6\xf5&\x94\xdf\x8e\x06\x84Yj\x12\xdb\xfaK|\x8cP\xe0-\xc3\xbb_\xd8\x8d\xd7\x86+\x07/\x8eK\xdc\xce\xfe-\xb9\xbf\xdeq\xe7eVl#\xd4\n\xf4\xc1\x80Uh$-\xcf\xdfo\x9b\xe5x2v\xe6\xe8\xdc\xd7i\x93g\xfc}&\xa0\xeb\x99\xa4\xb9\xcf\x7f\xfb\xf5*\xe2\xdc\xc9\x89\xf2>\xe9W\xdc\x0b \x07\x82:u\xb4\xa1\xf2Z2\xf8\x9f\xdf\x05OzF\xe7\xe3\xb5>\xff\xd8\xd4\x03'\xe9\x1a\xe8\xa5\x94B\xd3\xf3\xeb\xc4}\xce_\x1c@R\x82\x8d\xd1\xa7+\xa7>'\xd3\xcb\xad_\xebg\xf5\x1d0M\xfe\xb9\xa3@\x13\x1br\xa7[-\xcfH\xd1\xccM\x98\x8abwE\x84N\x0b]\xbf\x98\xfa\xaa\x05\x89\x0b\xb5\x7f\"\xfa\xe0\xcd\xff\xb8\x14\xfbOY\x1a\xde\xbdJY\xf8+\xa7\x12\xd3\x9eX\x14\xb6\x91\x91\x7fc\xb0\xb1\xca\xb6\\n\xebOv\xdc\x1b*P\xc7\xbd\xc0\xb1\x9d\xb1R\xfc\xfe\xe3\x94r\x89\xac\xa0Z\xee\x82u\x1c\0\x8b\xc99\xc7\xf21\"C\xb0l\xba\xd7\xb8r\xb3P\x19\x1e\xb3*PN\xa9\"x8]@3\xb1\x01\xd6\xaf\xc1\0\x18$soy\\\x18\xdb\xb8\xe4`A\xe2'\x88\x8a,\xe8\xc6\x8d\xb1\xfd!\xe8\x10*\xc8I\xfb\xd0k\xd1\xf6\x87\xac\x87*\xbb\"Am\x83\x9a\xdc\xe7)\x9a\xa8\x03\xdb\xa3\xf2\tr\x84\xbd\x06\xbaQE\xe6\xf3\x8b\xa7#\n\x7f\x83\xe9R\xf2\xe3\xc7\xc9\"\x9b8\x86\xc3\xa8\xeft|\xa8\xf7r\xd5\xd7\x04h\x10~'-Ft\xeek\xc0H\xaf\x1c\xf4\xbf!|>\xa9\x1aeA\xbe\r+\xab\x13\x03\x02\xe21\xe6\xa3g\xdf;\xf0\xdav\xd2d\x1e\x14'\x04\xb9b\x8b\xbb\xb9\xd1\x889f\xbb\x91p\xd6\x9d\xa9w\x04\xa5\x0f\x90\xe9j`\xa6\x15 \xe5t\xbd\xcb\x95?a\x0eJ\x82{A\xf56\xfa\xd5\xa8\xbbJr\xe0\x9a\xc1\xa6\xcd\xcf\x81CychbV\xe0\xa0\t\x83\xeeUz\xc7t\x94Fj>\xb1\x15\xd4)v\xd9\xcb\x9b\xc8\x07\x0c{\xd4\xb18\x12\x89\xa1\xec\xa0d'~\x07\xa4\xe9U\x16\0\xfet\x08x7v\xdfq\xa0=#\xa3\x1d\xe8\xcb\x1dJ\xea\xfb\xb2Z\xec\xc4\x97\xd6\xfds\xd9\\y\xdf\xecN\xe3\xee\x9f\xfe4h\xd2\xc3\xe1\x05\xf5*9*\x9c\xa4\xc7r\xac\xd8\xfe\xc2u\x8f\xf7P\xef\xb1\x93,\xf5\x06D\x89\x94\xa0\x83<\xf8\xe7\x9f\xc5g\x87t\xbe\xa8\xcc\x9a\xd2Y\x95\x8bv\x96\xb9\xfd\xb6\x8e.$\xcanYt/\xe0\xd3C\xb3\xea%:W\x1f\x08&1_\x0c\xdd\xeaOC\x16B\xael\x9c:\x99\xbeL\xa3\xe2\x0c\xf1\x99\x9a\xbe/\xc9\xe0s\xd7\x85\"\xa7\xe8\x8f/\x12YP\x8f\xf4\xf1\xd8b\x97\xbc\x16(c\xb5`<\xaa#\x85\x9c\xbe8\x80\x89\xcd\x87\x7fc\xcb\xac\xf4I\xc0\xea\xa7r\x1a\xec\x0e\xb2E]@\x92\x17\n\xebP\x8f \xec\xa8\x9dXa\x88>\x93?\xb1b#P6F\xe4?\xe4\xb2\xf0bm\xa1x]\n\x94\x16\xb3\x13^\x88\x88\xde/\xe1\x84\x82r\x0c\x1fm\xef5L\x0bF\xc5hc\xf9\x9d\x1a]\xf3L\xfa\xad\xb5\x88\x9fRN\xe3\x14+\xfe\xe6_M\xf2\xe5;\xb47\xf9\xdf\xb6\xf6\x9b-)\xcaB\x1e\xb4Ura\xb8e\x9f\x96\x8c\x1b\x12\xe6Y/\x9a{\xd6\x1b\x11r\x9b\x8e\xfdT\xd8\xf0\xb9\x1a\x1f\x83\x02\xb3\xaa)\xacM\xb0t[\xefH\xa3\xb2\xaa\x1f=\xa1\xa0o\xf9z5Kp\x13g\xfd\xc8\xd3@G\xca\x92\xe4Z\xcd-\xde\"\x18*P\x08\x05\xf8B=(r\xa0x\x92\xd39d\x04\xf8\xde\x10\x8f\x11\x82\xf49\xf8P\xb6PyA\x15\x12\xc9\xad\xc8\x7f\t>\x02a\xfb\x15\xedt\xe4R*5D\r\x9a\xcf\x1f#,F\xecF\x8f\xb5\xe8^9\x7f\x0e\xce\xbf\xfb\xdf$n\xc8M|_\x0fd\x11\xc2fs\xa4ZjI\xed\x91\x81\x94\xa5\x0b\x86\xfag\xcd\xbe\x90\xf1p\x86T\x0b\xc5+\x07O\xf4\xb5\xc5\xb5\xc2}\xf6`|\x14\x02\x8d$H@Oqc\x88\xf5~\x90\x07lt\xd9k-\xb4v\xfa\xd5\x9c\xe2^\xfc\xb4L\x0cY\x16\xc6\xaeA(u1j\xca\xaf\xaaV\x14\xe9k\xc6m\xc7\xe2\x80\xec\x98k\xe1!\xee\x11{'PH\xb3\\\xcb\xe1O\x11u\xf1\x824\xe4\x15\xb7P\x01\x81\x17\xe3\x1a\x91&\xde\xcdcE\xa5>\xdf\x14\xc5\x01\xadHV\xb9Qq\x03@\xac\x0fD>!\x05\xb9\x19\xc6\xdei\x19K/\xab\xa0\xf0~\x15\xc5\x0f\ti0\xcbq\x99\xdf .\xbc\xd7\xba/\xac\xc19\xbd\x1b\xcf\xc2P\x95.d\x04\xefd\xbe\xfaq\xf6 \xde\xe6\xdb\xcd\x95\xcb2!\xca\xd5ct\x1f\xe5{\x8d\xa68}\xdf e,\x13q}*\xc6];\x03P\xf9F\xca[\x8b\xe9\n\x0f0\xa7\xdc\xeb\xd6\xba\x11\xd4|.w=6\x86\x94{y\xc8*\xb8p\x8f\x11\xe9\xe4;\xe1+me\xcfw\x9096$\xa6\xfe\xd1o*\x035\xf0\x19\\\xe7\x1f\x82!S\x17\x14\x03\xba\xdb\xed9bn\xb0\x92\xc6jc\x81\xf9<7\xdb\xe6\x03\xaa:z'0\x8e)\t9\x86\xbe\xc5%b\x9f\xf8mG\xef4D|?\xa0!Fi\xab-\x9f\xd3\xb4\x05\xc72\x12 \xb7\x99\xf4\x8e\xa2l\xef\xd4\xa7\xfd/\x82 \xa6\xf1\xa3\xa0av\xaaw\xec\xfc\xdb\x8b7+#\x83E\xe8 1m\x17[\xf7\xff\x066\xddB\x11\x82E\x03\xa2\xf7\xcccH\x06\xcd\0o\xd3\xce\x91\xc1\x16\x88T\x0f\x91\xc3E\xfb\xa4\x87\x12\x0f\xfen\x87q\x81f~\xb8\xa6D;R(\0\0\xd0\xd6\x0eA\xbb\x97%\xf39\x86E\xed6\"\x1c\nA\xf9\x03\xd2\x7fZ\x1b\n\xbb\0\x87\xb4\xb6{_\xb4O\n\xb8\x12\xe4h\xbcB\xc1\tV\xd9\x17\x8b,0\x86Q\xea\xce\x9e*\x8b!Q\x04\x08*n\xa2\x18CK\x19\xe9R*\x0ePDi\xaa\x95\x95\0\xbc6\xfen\x9f\xfa\xc5s=2\x01j\x17\xa1t\xe7\x9a\xd9\x0b+\n\x855\x95\xa9gDT\xdb\xc2\xf7\x93\tt\xdcU\xf5#\0\x10W\x05\xc3yl\x80\xc5\x10_\xdc\x90\xdc]\xe2R\x86\t\x15Tf\x07\x0e\n\xf2\x101\xf9U\x83Nv\xf1=\xbd\x99Y\xd8EQ\x91mF\x97\xa8\x9cNUF\xa0G#\xae\xaet\xac\x9f\x99\x85\x17\xf1\x88\x8c(\xde\x91|y\x94\xbd\x8d7\x0f*\xee\0\xc4\x91\xd0\xdc\x7f\x99\xb8\x15\xc1V\\\xfc\xd0/\xf0M\xa7\t\xf4g[\xf0\xf8\xdc\x83\x16\"\x13\xbe6\xf0\xe2\x12\x7fbm(s\x8a\x86=M\xed\x15\xadu\xf5\xd5\xba1\0\xd3\xdc}\xce\xe0\0\x12\x81\xa1\xa9PK3%y\xd1`\xf2\x86\x1e;\xa4\xdfu\x9c\xe5E\x05i\xec\xb0\xdb9\xc0\x92\xf4\xf9\xdaIin\xbb\xa3B.\xb4#\xc4\xda\xdd\x92A\xad\x9f{\x95\xacP\x7f\xd1}\x1f7\xb1\xaa\xa7\xe8T\x83\x13\x16j\xfcx\x88\x0c\xd9\x7f\x83\xd9\xaal\xe5K\xb8w\x13\xab\x11p\x8d\x83\xc1b\xa4\xba\"-\x1d\x1a\xc9\xfb\xdc/\xe6\xc1\x92\xd7h\xd3L\xfd\xdd`\x80\x9e\x19\xfdC\x81\x8a\xacO\xd2\x14?W\xd6qZ\x84[Q\xf1R\xfd\x0e\x0f`O<9\xbc\xcct\x8ct\xc3\xf0=\xe6],\xba\t\x9an\"F\xa7h\xe0\xdd\x9a@\xde}\x98H\xea\x11\xd6\x01-'BL\x8d+\xab\xa5\xa6\x0e\x1d\x11\x18\x0f\x16\x9f\xfe9@\x9ec\xdd5\x81\x13\x15<[B\xc4N\xf1\x07\xb4\xcd\xd6\xa1r&]\xf9\xf7\x84\xaf\xf7\xd1^\x80\xdf\xc9\xd8&8P\x89\xd3{\xfb6\x97\xd1\xaf\xe1\xbbo\t`\x9b\xf9\x06\xe1+j\xe2m\x86Au\x9e{qN\xeb$\xbcd=\x98\x16\xd7\xdb\xe1;c\x19Q:\xe0\xfd\x9dPV\x92\xec\xfb\xab\x9bL\x81\x8d\xbd\xdaLnJL\x89M\x01Z\xedI\xab\x83]?^\x01qP\x96T\xbf\x1d\x9a\x06\x1d:-2\x8a\xc8\xaa\xa8\xc8 \x0b\xa5sX\x93:\xe4g\xf4~\xa9X\xb5\x05w\x14\x8f\x82ER\xe0o\xda^\xd8}P\x9d#g\x90\x07\xc5F\xf2\x11\x1e*\x02+\xee7E\x80\xf1>\xfb\x83B@?5\xb4?\xb6\xa8;\xe1v\xa3\x81\xcc\xceq\x89\xd3\xb4\xe5\xc0!7}\xc9ml\xcaZ\xb5\x18\xf4pD\xb3\xe6\xbcS\x87\xfco\x90\x12\xcdO\x17\x19\xc7\xbb\x106J\xc1\x150\xd0\xd9o\x98L[\xa2Qv\xdfCN\xa9\xa5\x8c\xdb\x94\xcfG\xa0X\xf3f\xa9\xe7[\x177\xd9\xd0\x11\xdeEZf\xb8\xe3-\xbe\x03|\xf8\xb1\xf4dcc4\xf2W\xd4\xfd\xec\xb8\xaf\x82\xd3\xa9\xce\xd0\xa2s\x7fm$\xdd\xed\xe6<\xa2\xd9V\x9dD J;\x01\xd2\x03\\\xf1O\x94\x0fu\xf1z\"3\x18Vzy\x16I\xe3\xd4]V6E\x18Z\xabGK\x95\xd5g\xfb\xdf\xaeQv|\x90\xd0\xbc\xccx\xe0X\xaf\x1fM\x0f\x8d\x0b[*\xec0\x0fs+\xec$gp\xf3\x91\xc0\xf9\xf7zg\xb3\x07\xa4\xc4I\xb5\x04%\xf8\xf4,\xae\xe4\xd5\x8f\xaf\x8d4\xc4\xb5\xd3\xc0\xe7\xaf\xf7&\x18\xe6\xcc\xe2\xc8?\xf8\xad>\xc0\x16\xc5~!#\xdbKlg%\xcb\xe7F\xa1+\xb1\xcd\xa9\x04$\x12 \x1cm\xe0\xb5\xe8\xc8p\x85\x0bD\xe1a\xdd\xce\xc2F\x1d\x8b\x82\x9c\xd5\xe9H\x1a\xbcz\xdb\x1c\x892\xe5u\xfe\x1c\xcd\xf2Srz\x8a\xfa\xb6e\x1e\xc4P\x0e\xcd[\x15\xcd\xeb\xa1e7`Z\x1c\x1d\xc11\xd7=\xbf\xf2i\x9b\t*\\\x93+\xae\r\xd9\x04\xdc\xc8@y\xe85\x89\xf4\xbb\xc4\x8f.-k\x81\xa4h\xa4\x18\xc8\xb5\xd7\xd6%p\xee\xda7\xc8[F\xc7\xee\xa9\x9d\x16]\xef\x88\0\nw\xec\x17\x98\x98\xc6\xdfKL\x81\xcf\xc5\xde\x91\x1fp7\x80&\x9d\x12.\xe7\x0f\xc4\x86\xf3\x94\x80b\xae\xaa\xf2\x9a\xde\xa4\x9dx\xcfi418\xcb.\x9e\xd6\x1e\x18^\xa4\xd9\xc7>\xe2$Y-\xfc\xf0\xf4=\x91\x13\x16#x\x7fv\x95\xd8?^\xda\xffE\xc9D\x14\xa1\xcb\x90\xc6\x8e|C&\xf9\t\xf6\x8c\xc8\xa6\x17qU\xf0\xc7\x19l\x05J\xfe\x99=\xfef\xa3%\xe9a`\"%%\xb5\xab\xb3)\x89\xa5D\x9a@\xc0c.[{\xd5-\xee\rq\xbc\xb4\xd6\xc1{\xbd;\x80(\x01Ez\xf1l\xb7P\xcd\xe3\x13\xb6R\xae@\xb5\xe8\xf7\xf7\xba|\x97y\xa9b\xf2\xbd\xf7\xb0Hg\xc8)I\xaf\xb8\xab/\xe2\xfe\xed\x15@\xf6\xf8qV\xba\xb1\xd2\xe0\x0f\xf2%\xad\xfe i\xe0\xee\x17\xe7\xb6\xabOH\xd9\xf7\xc8\xa3\x8fp\x18\x01\xd20\x8b/_\xc5\x92\xba\x0cy(\xbbP\x9b\xd6\x7f\xc5\x1a.5/\x13c\xf5Ft\xcd\xda4X\xe1\x12\xa3\x80\x9b7\xaa\x9ar!cV\x89\xc0\x8fH\x170\x13\xec\xae\xe7\tf\xf7\x1c\x16yF\xf0\xa9\x1a8\xe8$[\x1d\xedd\x17[\x9e\xc8\x0f\xfe\xa0\x96P'P\xeb!@x\x04\x99\xe4\xa2\xb4\xc6}\x97\x92\xde|\xc6\x8d|\xc8\xb01\xd6\x83P^R\xd7-\xf5\0\xabG\x88\xff\xfa\x9a\x8e\xeb\xf1\xaa\x07\x9b\xf0\xc9JD\xc9\x96j\xdc\x85\xc0\xba\x0c\xc7*d#\x8c\xbd\xcd(]\x12\xa8\x11\t\xc0\xa2\xcd\tu\xbc\x08\x92Yi\x01\x98\x98%\xdeN\xb5\xa4\x97)g\xb7\x95\xf1`E\xea\xa3\xb2$\xa1\xfd\x96\xe1#\xbb\xfb\xd3\x1cF\xf3;\xf7\x10\xf2\0\n\xc0\xb6!<\xb2d\xc5\x06y\x7f\xee\xdd\x14\xe5\xca\xf7\xe1\x9dA\xda\x17B\xdb\xfdA\xf9\xa1\xd16'\xe1\x11\x81\xfa\x02K\x08\x021\xfe\xd9\xa9\xba\x964\x05\xe0\x19\xc9]\xaa\x10\x7f\x95\xd3_\xfe,\xc5\r\x12\xf8\xab&6\x1a\xb0\xa9\xdcK\xf9y\xf56H\x16\x7f\xc6\xf6\0\x1c\xebX$\xa7\xb2\xcd6:\x19^\x0f^\xc4.\x1e\xcc>\xd4`\xa5X\x89\xfd\x9c\x03*H\x96\xbf\x93\x84|\x923\x82\xef\x139j\x9c\xfd3\x10@\x86q\xc9\xfe\xd5\xec\x90\x98\xb7y\xe6{\xb6\x94\xeaOO\xf4q\n\x8a\xe6\x8cx\xbbd\xf0\xaf!\xea\xdc\xf9\xc6\x02\x82z:\x06c\x1cA\xe9v1\xca\x18\x1f\xe3\xb2Sj\xe0\x16\x06\xec\x1f\xe1\xd8\0\x80\x94\xc3X\xfaJ\xb7\xc1.\xe5\x97f\x9dt\x8aL'@WBz\xdb\x06k\x03\xdf\x04\xd8\x993\xcdV\xf6\xa6 $\x83\xf0\xd8\xbf\xe2\xd1\xab\xbb\x81\xda\x10\xc8\xec\xec\xe4\x14d\xf9q\xc0\xa5\x17\xa5\xc8\x0cS\x9c+Lc?\xda\xa9\x8d\x9ckU\xea\xa2c-\x94R\x82\xc4\xf8FH\xce\t?)\xcb\x16e\xa3\x06\xfe\x10I\xcay \x0b\x89\x17\x8fp\xb6\xb0\xb4\xe8\xc2\x1e8V)\xba\xd7\xdc\xa0O\xef\xd3\x14\xed\x8f\xfb\xcauc\xd6O\xe3P\x95\xae\xaf\x11+w\x8b\x1a\xdf\xb6\x02\x10'\xd3\x15C\x95\x91G`I40\x16\xd2\x91\xc0\x1c\xe9\x83Q\tW\xc8\x80q\x9d\x1er\xf17\xdc|m)\xca\x08\x05a-0y$/\xaf\xe8\xba\x12\xb0\xe0\xf0\xd7Jj\x91\xd2\x96\xe8)\xa3!\xa1\x88M\xb0\xb7&5\xee\x9d\x0b\xf7IFl \x81\x97e\xd6l\x14\xe6qR\x9b'\x9e(\xc09j\xd1^\\\xfe\xdd\x02\x87\x85U\xe2\x01\xb6\x82\x1c\xb6\xae\x1b\x04\xdd\x94\x7f=X2\xbf\xcd\x85\x8aE_&s\xeb\x05w\xd8Y\xb2T\xa9>\x18\xf0\xaf\xa3\x98\xf9\x9b\xe6|\xd1\xf5\xd5(\x9b\x1e\x1b\t\x11\xbb\"\x07\xa4\xeed+\x07\xa1\xaa\xad\xd2zj\xc8\xa3\xa0\xef\x0ea\x1bu\xa4n\xe1Q\x03\x87G'\x07\x9b\xa6;\xfd\xe3f,\x85b\x87\xc2I\x97\x17\x87\x1b\n\x12\xdd\xe8NsQ\t\xa2\xec\xe4\x12w\x95\n\xc4\x0e\x97\0\xf8\xa7\\^\xa7\x9a7\x1av:\xef\xe7\xe3'\xc3s\xdd\xccjn\xd29\xbf\xb6\xde'\x7f\x19\x9a\\\x93\n\\x\xba:\xef\xc5I:e\x80XC\xe4\xf7m\xdc\xea\x92\x80\x84w\x1cQ\x92)\xbc\x92\xfe*X\t\xbe|\x8bD/\xf3\xc7\xdf\x9d\\\x15\"\x1c\xe0uY\xe6\x91J\x93T\xd6\xd5\x1a\x9e\xa8\xc1O\x8f7r\xe3\x8b\xbf\xd2:b\xe4.\xf1)\x18=_R\xc7\xffux\x96\xfd\xc8\r\xe3\x95/\xb6\x9fo\xfb\n=*x\x85\x86\xb2[\x1bg\x7f\xff\x8d\x08\xd6\xee\xc7\xdc\xca\xf3\xfa\x03,\xcd\xf2 \xd2 \xa8\x03\xa0\xd1*\xfaI&\xf6\x95\xcc\x0b\x05\xc6\x10\xc6~\xe6\xe5{\xcf\x9b\xf5\x94\x90'\x85\x0f\xc5\x80Aa\xee%\x9eh\xbf\xb55\xf0C\xb2\xabY\x0e^\xf7[\xc2\xef`\xdc\xe0\xce1\xcdQLb\xa5\xde\xc4Q\xb3/\xd9ckG\xea\x18&\xc1Q~\xbe\xafU\x05T'\xd1\t\xb1i\x1d0\xd9\x84\xebDIo\x04\tIC\x96\xa7\xa2h\xed}\x9f)[\x10\x87\xb1\ti8W\xda+\xa9)\x7fh\xc0K\x0e\x0e]\x7f\xf7\x94\xd4)\xea&+\0\xeb\x87y\xf6)w\xc0f9\xcc'\x8aa1`4P\xb6\xc0\x03$+\xda\x98ec\x7f\xf0\x05\xc9\xe8\nv\xf2b\x1d\xdd\x8f\x93\xb3(\x8e\xd7\xd8\xec\xa1J\xbd\x9f\r\xee\x97\x19F\xdc\xbc\xe5\xfdu\0DZ\xd1i\xb0\xaa\x01\xcf\xe1\xe1(YsX\xdeWt\xb0dp\xc5\xf1\xd3\x9d}\xad>\x8a\xb2\xce\xce\x13\x10D\xc9\xe2zp\xed\xae6\xa84\xd4\xed\x97^\xc9`\xa9\x95\xb1\xf4\x9axOYsW\xe6W\xff\xd9\xa1\xdd\xa0\xb2\xa2\xba\xea1\xf7\x96\xd4\xe1\xfa7\x13\x16\xc4\xd1{\xca\x08\xcd\x13\xef|\x9a\xa3\x19\x8a\x15B\xa3\n\xbbV\xe5k\xc91qd\xbf\x16`?\xb5iEi\x80Jwc\xfc\xcd+\x055R$\xec\xf0\x0e\x84`\xce\x9f\x1ci\xe9Znaf\x8e\xf8\x93\xedB\xed\x9c\x875\xd2H\xaa_\xb7d\x16\x80\xb5\x86J\x07R\x04U?\x1a~\x83\xc3\x88<\x86V\x83\xd6\xf6y\xba\xd3|\xda\xe6s\x91\xaa\xfbq\x01\rr\x9b\x99\x8f|\x05g\xa95\x87\xd5vR\xaa\xd6dE\xb1?e\x82\xe2\x0e\xc9\xae\x8f\x8c\x9fm\x7f\xa5@\x0b\xb9^\xbb\x05\x01\x11\xe3\x83\x1bWXj\xa3\xed`\x8d\x1a\xea\x05\xe1\x1f\x1a\x81&'\xa5\xad\xca\x1bS\x9b\x98\x9aF\x8bo\x075\r\xd9\xb0[!'\xae\xae\x0cl\r%\x952\xd6\xee\xec\x08\x90]\x83(ZU\0\xa9}\xaeO\x95!\xe3\xf5C \xc9\xc8\xd8[7\xc2\xb7f\xb8e\xe8\xde\x1b\x1a\xc5\xe9\xc8\x9d\xcb\xc8\xd8\xb5\x80K:\xb3\x17\xcc\xe7\xdfs`+a|\xb0\x0e\xcc\xab)\xcc\x0e\xd2\x15\xca\xf3P\xcdMx\xb4\xbb\x033\x07\xf0\xf6HP \x82jE\xab\x82\xa3\x9a\xfc6\xae\n\xdaF\xb0\xd7\xb2uN7Jcr#SODO\xd4b\xd9\x0c${\xd3\xda\xec\x18\xf1<\x03\xb4\xf1\xd3\t\xc7\xfa\xa5\xebwd\xf2\x99\x93\x99S\xfe\xb3\xb8\xd5;\x86F\"q\x12Y\x06\x94\x1f\x15\xd3\xf3\x8fV\xb7UQKv\xb5\xf1\x0cD\x0c\xbbT\xd5\xfei\x9e\xd1W\"9\xf5\xea\x86\x03\x8c\xeb\x10.;\x1a\x93o\x97S\xc6\xaf\x88\x92:\xc1R\xb4'\xe8\xe4\x7f\xff\x88\xc6oH\xd5a\xf2}kZ\x1d\xae\xa1\x1c\xb5_]&\xd0 \xc4\x01V4\xfe-\xec\xd3'gJ\xfb\x81GBb\xe5\x9fbzf\x86\x94\x1b8\x0b\xa9&\xf3n\x12\x1f\x15\xb3\xb3\xeb~.\xb9rn\xbf\xc2!=\xcaw@/\xb9F'\xfb\xddW.\xaf\xe7\xffB=W!7I\xdb\x8f3/\xfe.\xb4\xe4+\x8a_\x8d\xdeP\xfa\xf5(\x8d\xc7DS\x9b\xbcbZ\x1e&\xe9M\xaa\x97\x8a\xc4\x05Vf)\xef\xd5\x0f{\x1f5\xa4PH\x8b\xc9ZQj\x7f\xb8\x08v\xf6lI\xfcP\xaa\xc6\xcf1\xbby\xa6\x01\xf6)\xd6\xbc\xc8\xa7\x9d#/\xe8G\x98`W\xa9:R\x87\xe7\xe6\xe5\xf4*\xfb\\\xa8f\xb2\x08\xf7\x844\x1c\xed\x19\x91^L\x8a\xdf\x03\xf3)\x1d\x9a_4L\xe4v\xb4\x93\x07`\xc8\xe9\xe1\xa3f\xa7\xd4\xcf8\x9eh\xed\x90f\x9e\x9238\xfb\x99M\x0fU\xa0q4<\x03U\xb3\x9e\xfe\xeal[\x88\xce\x8a\xfa\xe61_A r\x8e./\x1d\xe3<\xaa\xa2\x95\xde{\x1e4Z.\xa9\xcd\xec\x95\xe93y9\xb1\xc7\xb6\xb75\x1fz\x03EQi\x1aJ\xa2\xa9G\x18F\x07\xe1\xcc\x97\xfb\x9a/\xe9\xeaD\xbd<\x15\xd1C\x93\x98.6\xad\xf3h\xec\x9a'\xe3Tyx/wd\xa7\x9fH\xd8\xc0\xaa\xe8\x1dPq\x12FX\x8b\x04\xb1r\x92\xe9\xca\xe0w.\x1f\x91\x1d\x19,\xde\n\x8a\x83\xcdL\x9a\xc5w&\xee\xf6\xdc\x8d\xb0%\xd6\x8b\xd4\x08\xa1\xf6M\xfe\xc2\x8e\n\t\x9c\xd4\xba\x81\x19\xd5H/\xb9\x99\x8b\x15\x1e\x17\x9b\xe5\xb1\t\xbd\xac\xa0\0z\x9d\x07\xdf\xd6\xe3Ow\x8b\xe2\xdcg\x888\xa2m\xb9^\x9b8\xb7z\x94\xa2\xa6u_i\xa0\x013\xdfD\x93\x95\xdc!\x80)\x1e\xd5\x96\x0fN9\xf3\x17\x0f\x8cN/\xc4E\xbe$\xa1Q\xb2\xbf\xd8\x1d\x0f\xfd\xc3\xb7\n2e\xed\x90\x06\xaa\xb1\x9f\xdf\x94\xf9w\xddgI\xc6G\x7f\xcf\xa5\x84\xe7\xea\xa3Ia\xbf\x8b\xa0\0~\x02\xa6`\xd9\xa9i\xe5\xfe$\xa1\x9b\xbdu\x8e\x1b\xf5`\xac\x1f\xdd`\xc2a^\xdb\x05\xe9,_\xed4\x88\xf4\xc7\xdf\x10C^\xafF&\x85\x8cM\xc4\xd1d\x8b\xd3>\xe8a\xbbM\xe4x]\"\x1fhh\x9c\xe2\x95<`!\x87\xb2\xc4Vx\x1e |\xc7\xf3B\x93$\x08,\xbe\r\xffj\x13\xfa\xb9\xa0Z\x0bS\xc0(\xb2,\x94l\xacN+\x84\x7f\xca\xb3\"~H0" -cc a4d0f81aaf2ce60a94ed443644f9997053f4d2cf84af0347ce853c213fe4a9e1 # shrinks to frame = ClientInfo { client_public_key: PublicKey(hnvcppgow2sc2yvdvdicu3ynonsteflxdxrehjr2ybekdc2z3iuq), encrypted_message: b"" } diff --git a/iroh-net/src/relay/codec.rs b/iroh-net/src/relay/codec.rs index 8b4e02f493..5eef327e45 100644 --- a/iroh-net/src/relay/codec.rs +++ b/iroh-net/src/relay/codec.rs @@ -101,8 +101,6 @@ pub(crate) enum FrameType { /// /// Handled on the `[relay::Client]`, but currently never sent on the `[relay::Server]` Restarting = 15, - /// 32B src pub key + 32B dst pub key + packet bytes - ForwardPacket = 16, #[num_enum(default)] Unknown = 255, } @@ -565,9 +563,7 @@ mod tests { } } -/// these test are slow in debug mode, so only run them in release mode #[cfg(test)] -#[cfg(not(debug_assertions))] mod proptests { use super::*; use proptest::prelude::*; @@ -588,11 +584,16 @@ mod proptests { /// Generates a random valid frame fn frame() -> impl Strategy { - let server_key = key().prop_map(|key| Frame::ServerKey { key }); - let client_info = (key(), data(32)).prop_map(|(client_public_key, encrypted_message)| { + let client_info = (secret_key()).prop_map(|secret_key| { + let info = ClientInfo { + version: PROTOCOL_VERSION, + }; + let msg = postcard::to_stdvec(&info).expect("using default ClientInfo"); + let signature = secret_key.sign(&msg); Frame::ClientInfo { - client_public_key, - encrypted_message, + client_public_key: secret_key.public(), + message: msg.into(), + signature, } }); let send_packet = @@ -611,9 +612,7 @@ mod proptests { try_for, }); prop_oneof![ - server_key, client_info, - server_info, send_packet, recv_packet, keep_alive, @@ -629,8 +628,7 @@ mod proptests { fn inject_error(buf: &mut BytesMut) { fn is_fixed_size(tpe: FrameType) -> bool { match tpe { - FrameType::ServerKey - | FrameType::KeepAlive + FrameType::KeepAlive | FrameType::NotePreferred | FrameType::Ping | FrameType::Pong