diff --git a/pr/338/docs/help.html b/pr/338/docs/help.html index 99d8cb979..2565ad385 100644 --- a/pr/338/docs/help.html +++ b/pr/338/docs/help.html @@ -1 +1 @@ -Help

All

Rustdoc help

Back
\ No newline at end of file +Help

All

Rustdoc help

Back
\ No newline at end of file diff --git a/pr/338/docs/iroh_quinn/enum.ConnectionError.html b/pr/338/docs/iroh_quinn/enum.ConnectionError.html index 9f306c121..aa546de4a 100644 --- a/pr/338/docs/iroh_quinn/enum.ConnectionError.html +++ b/pr/338/docs/iroh_quinn/enum.ConnectionError.html @@ -1,4 +1,4 @@ -ConnectionError in iroh_quinn - Rust

ConnectionError

Enum ConnectionError 

Source
pub enum ConnectionError {
+ConnectionError in iroh_quinn - Rust

ConnectionError

Enum ConnectionError 

Source
pub enum ConnectionError {
     VersionMismatch,
     TransportError(Error),
     ConnectionClosed(ConnectionClose),
@@ -20,8 +20,8 @@ and §

LocallyClosed

The local application closed the connection

§

CidsExhausted

The connection could not be created because not enough of the CID space is available

Try using longer connection IDs.

-

Trait Implementations§

Source§

impl Clone for ConnectionError

Source§

fn clone(&self) -> ConnectionError

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for ConnectionError

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error>

Formats the value using the given formatter. Read more
Source§

impl Display for ConnectionError

Source§

fn fmt(&self, __formatter: &mut Formatter<'_>) -> Result<(), Error>

Formats the value using the given formatter. Read more
Source§

impl Error for ConnectionError

Source§

fn source(&self) -> Option<&(dyn Error + 'static)>

Returns the lower-level source of this error, if any. Read more
1.0.0 · Source§

fn description(&self) -> &str

👎Deprecated since 1.42.0: use the Display impl or to_string()
1.0.0 · Source§

fn cause(&self) -> Option<&dyn Error>

👎Deprecated since 1.33.0: replaced by Error::source, which can support downcasting
Source§

fn provide<'a>(&'a self, request: &mut Request<'a>)

🔬This is a nightly-only experimental API. (error_generic_member_access)
Provides type-based access to context intended for error reports. Read more
Source§

impl From<Close> for ConnectionError

Source§

fn from(x: Close) -> ConnectionError

Converts to this type from the input type.
Source§

impl From<CloseReason> for ConnectionError

Source§

fn from(value: CloseReason) -> ConnectionError

Converts to this type from the input type.
Source§

impl From<ConnectionError> for ReadError

Source§

fn from(source: ConnectionError) -> Self

Converts to this type from the input type.
Source§

impl From<ConnectionError> for ResetError

Source§

fn from(source: ConnectionError) -> Self

Converts to this type from the input type.
Source§

impl From<ConnectionError> for SendDatagramError

Source§

fn from(source: ConnectionError) -> Self

Converts to this type from the input type.
Source§

impl From<ConnectionError> for StoppedError

Source§

fn from(source: ConnectionError) -> Self

Converts to this type from the input type.
Source§

impl From<ConnectionError> for WriteError

Source§

fn from(source: ConnectionError) -> Self

Converts to this type from the input type.
Source§

impl From<Error> for ConnectionError

Source§

fn from(source: Error) -> ConnectionError

Converts to this type from the input type.
Source§

impl PartialEq for ConnectionError

Source§

fn eq(&self, other: &ConnectionError) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, -and should not be overridden without very good reason.
Source§

impl Eq for ConnectionError

Source§

impl StructuralPartialEq for ConnectionError

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where +

Trait Implementations§

Source§

impl Clone for ConnectionError

Source§

fn clone(&self) -> ConnectionError

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for ConnectionError

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error>

Formats the value using the given formatter. Read more
Source§

impl Display for ConnectionError

Source§

fn fmt(&self, __formatter: &mut Formatter<'_>) -> Result<(), Error>

Formats the value using the given formatter. Read more
Source§

impl Error for ConnectionError

Source§

fn source(&self) -> Option<&(dyn Error + 'static)>

Returns the lower-level source of this error, if any. Read more
1.0.0 · Source§

fn description(&self) -> &str

👎Deprecated since 1.42.0: use the Display impl or to_string()
1.0.0 · Source§

fn cause(&self) -> Option<&dyn Error>

👎Deprecated since 1.33.0: replaced by Error::source, which can support downcasting
Source§

fn provide<'a>(&'a self, request: &mut Request<'a>)

🔬This is a nightly-only experimental API. (error_generic_member_access)
Provides type-based access to context intended for error reports. Read more
Source§

impl From<Close> for ConnectionError

Source§

fn from(x: Close) -> ConnectionError

Converts to this type from the input type.
Source§

impl From<CloseReason> for ConnectionError

Source§

fn from(value: CloseReason) -> ConnectionError

Converts to this type from the input type.
Source§

impl From<ConnectionError> for ReadError

Source§

fn from(source: ConnectionError) -> Self

Converts to this type from the input type.
Source§

impl From<ConnectionError> for ResetError

Source§

fn from(source: ConnectionError) -> Self

Converts to this type from the input type.
Source§

impl From<ConnectionError> for SendDatagramError

Source§

fn from(source: ConnectionError) -> Self

Converts to this type from the input type.
Source§

impl From<ConnectionError> for StoppedError

Source§

fn from(source: ConnectionError) -> Self

Converts to this type from the input type.
Source§

impl From<ConnectionError> for WriteError

Source§

fn from(source: ConnectionError) -> Self

Converts to this type from the input type.
Source§

impl From<Error> for ConnectionError

Source§

fn from(source: Error) -> ConnectionError

Converts to this type from the input type.
Source§

impl PartialEq for ConnectionError

Source§

fn eq(&self, other: &ConnectionError) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, +and should not be overridden without very good reason.
Source§

impl Eq for ConnectionError

Source§

impl StructuralPartialEq for ConnectionError

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where diff --git a/pr/338/docs/iroh_quinn_proto/enum.ClosePathError.html b/pr/338/docs/iroh_quinn_proto/enum.ClosePathError.html index b7a804288..58c09315c 100644 --- a/pr/338/docs/iroh_quinn_proto/enum.ClosePathError.html +++ b/pr/338/docs/iroh_quinn_proto/enum.ClosePathError.html @@ -1,11 +1,11 @@ -ClosePathError in iroh_quinn_proto - Rust

ClosePathError

Enum ClosePathError 

Source
pub enum ClosePathError {
+ClosePathError in iroh_quinn_proto - Rust

ClosePathError

Enum ClosePathError 

Source
pub enum ClosePathError {
     ClosedPath,
     LastOpenPath,
 }
Expand description

Errors triggered when abandoning a path

Variants§

§

ClosedPath

The path is already closed or was never opened

§

LastOpenPath

This is the last path, which can not be abandoned

-

Trait Implementations§

Source§

impl Clone for ClosePathError

Source§

fn clone(&self) -> ClosePathError

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for ClosePathError

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Display for ClosePathError

Source§

fn fmt(&self, __formatter: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Error for ClosePathError

1.30.0 · Source§

fn source(&self) -> Option<&(dyn Error + 'static)>

Returns the lower-level source of this error, if any. Read more
1.0.0 · Source§

fn description(&self) -> &str

👎Deprecated since 1.42.0: use the Display impl or to_string()
1.0.0 · Source§

fn cause(&self) -> Option<&dyn Error>

👎Deprecated since 1.33.0: replaced by Error::source, which can support downcasting
Source§

fn provide<'a>(&'a self, request: &mut Request<'a>)

🔬This is a nightly-only experimental API. (error_generic_member_access)
Provides type-based access to context intended for error reports. Read more
Source§

impl PartialEq for ClosePathError

Source§

fn eq(&self, other: &ClosePathError) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, -and should not be overridden without very good reason.
Source§

impl Eq for ClosePathError

Source§

impl StructuralPartialEq for ClosePathError

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where +

Trait Implementations§

Source§

impl Clone for ClosePathError

Source§

fn clone(&self) -> ClosePathError

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for ClosePathError

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Display for ClosePathError

Source§

fn fmt(&self, __formatter: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Error for ClosePathError

1.30.0 · Source§

fn source(&self) -> Option<&(dyn Error + 'static)>

Returns the lower-level source of this error, if any. Read more
1.0.0 · Source§

fn description(&self) -> &str

👎Deprecated since 1.42.0: use the Display impl or to_string()
1.0.0 · Source§

fn cause(&self) -> Option<&dyn Error>

👎Deprecated since 1.33.0: replaced by Error::source, which can support downcasting
Source§

fn provide<'a>(&'a self, request: &mut Request<'a>)

🔬This is a nightly-only experimental API. (error_generic_member_access)
Provides type-based access to context intended for error reports. Read more
Source§

impl PartialEq for ClosePathError

Source§

fn eq(&self, other: &ClosePathError) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, +and should not be overridden without very good reason.
Source§

impl Eq for ClosePathError

Source§

impl StructuralPartialEq for ClosePathError

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where diff --git a/pr/338/docs/iroh_quinn_proto/enum.ConnectionError.html b/pr/338/docs/iroh_quinn_proto/enum.ConnectionError.html index 5810ff1bf..fb01e0ff9 100644 --- a/pr/338/docs/iroh_quinn_proto/enum.ConnectionError.html +++ b/pr/338/docs/iroh_quinn_proto/enum.ConnectionError.html @@ -1,4 +1,4 @@ -ConnectionError in iroh_quinn_proto - Rust

ConnectionError

Enum ConnectionError 

Source
pub enum ConnectionError {
+ConnectionError in iroh_quinn_proto - Rust

ConnectionError

Enum ConnectionError 

Source
pub enum ConnectionError {
     VersionMismatch,
     TransportError(TransportError),
     ConnectionClosed(ConnectionClose),
@@ -20,8 +20,8 @@ and §

LocallyClosed

The local application closed the connection

§

CidsExhausted

The connection could not be created because not enough of the CID space is available

Try using longer connection IDs.

-

Trait Implementations§

Source§

impl Clone for ConnectionError

Source§

fn clone(&self) -> ConnectionError

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for ConnectionError

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Display for ConnectionError

Source§

fn fmt(&self, __formatter: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Error for ConnectionError

Source§

fn source(&self) -> Option<&(dyn Error + 'static)>

Returns the lower-level source of this error, if any. Read more
1.0.0 · Source§

fn description(&self) -> &str

👎Deprecated since 1.42.0: use the Display impl or to_string()
1.0.0 · Source§

fn cause(&self) -> Option<&dyn Error>

👎Deprecated since 1.33.0: replaced by Error::source, which can support downcasting
Source§

fn provide<'a>(&'a self, request: &mut Request<'a>)

🔬This is a nightly-only experimental API. (error_generic_member_access)
Provides type-based access to context intended for error reports. Read more
Source§

impl From<ConnectionError> for Error

Source§

fn from(x: ConnectionError) -> Self

Converts to this type from the input type.
Source§

impl From<Error> for ConnectionError

Source§

fn from(source: TransportError) -> Self

Converts to this type from the input type.
Source§

impl PartialEq for ConnectionError

Source§

fn eq(&self, other: &ConnectionError) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, -and should not be overridden without very good reason.
Source§

impl Eq for ConnectionError

Source§

impl StructuralPartialEq for ConnectionError

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where +

Trait Implementations§

Source§

impl Clone for ConnectionError

Source§

fn clone(&self) -> ConnectionError

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for ConnectionError

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Display for ConnectionError

Source§

fn fmt(&self, __formatter: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Error for ConnectionError

Source§

fn source(&self) -> Option<&(dyn Error + 'static)>

Returns the lower-level source of this error, if any. Read more
1.0.0 · Source§

fn description(&self) -> &str

👎Deprecated since 1.42.0: use the Display impl or to_string()
1.0.0 · Source§

fn cause(&self) -> Option<&dyn Error>

👎Deprecated since 1.33.0: replaced by Error::source, which can support downcasting
Source§

fn provide<'a>(&'a self, request: &mut Request<'a>)

🔬This is a nightly-only experimental API. (error_generic_member_access)
Provides type-based access to context intended for error reports. Read more
Source§

impl From<ConnectionError> for Error

Source§

fn from(x: ConnectionError) -> Self

Converts to this type from the input type.
Source§

impl From<Error> for ConnectionError

Source§

fn from(source: TransportError) -> Self

Converts to this type from the input type.
Source§

impl PartialEq for ConnectionError

Source§

fn eq(&self, other: &ConnectionError) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, +and should not be overridden without very good reason.
Source§

impl Eq for ConnectionError

Source§

impl StructuralPartialEq for ConnectionError

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where diff --git a/pr/338/docs/iroh_quinn_proto/enum.Event.html b/pr/338/docs/iroh_quinn_proto/enum.Event.html index 21c947f09..702948cf6 100644 --- a/pr/338/docs/iroh_quinn_proto/enum.Event.html +++ b/pr/338/docs/iroh_quinn_proto/enum.Event.html @@ -1,4 +1,4 @@ -Event in iroh_quinn_proto - Rust

Event

Enum Event 

Source
pub enum Event {
+Event in iroh_quinn_proto - Rust

Event

Enum Event 

Source
pub enum Event {
     HandshakeDataReady,
     Connected,
     HandshakeConfirmed,
@@ -22,7 +22,7 @@
 
§

DatagramsUnblocked

One or more application datagrams have been sent after blocking

§

Path(PathEvent)

(Multi)Path events

§

NatTraversal(Event)

Iroh’s nat traversal events

-

Trait Implementations§

Source§

impl Debug for Event

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl From<PathEvent> for Event

Source§

fn from(source: PathEvent) -> Self

Converts to this type from the input type.

Auto Trait Implementations§

§

impl !Freeze for Event

§

impl !RefUnwindSafe for Event

§

impl Send for Event

§

impl Sync for Event

§

impl Unpin for Event

§

impl !UnwindSafe for Event

Blanket Implementations§

Source§

impl<T> Any for T
where +

Trait Implementations§

Source§

impl Debug for Event

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl From<PathEvent> for Event

Source§

fn from(source: PathEvent) -> Self

Converts to this type from the input type.

Auto Trait Implementations§

§

impl !Freeze for Event

§

impl !RefUnwindSafe for Event

§

impl Send for Event

§

impl Sync for Event

§

impl Unpin for Event

§

impl !UnwindSafe for Event

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

diff --git a/pr/338/docs/iroh_quinn_proto/enum.PathError.html b/pr/338/docs/iroh_quinn_proto/enum.PathError.html index 6144c48b3..03edb5997 100644 --- a/pr/338/docs/iroh_quinn_proto/enum.PathError.html +++ b/pr/338/docs/iroh_quinn_proto/enum.PathError.html @@ -1,4 +1,4 @@ -PathError in iroh_quinn_proto - Rust

PathError

Enum PathError 

Source
pub enum PathError {
+PathError in iroh_quinn_proto - Rust

PathError

Enum PathError 

Source
pub enum PathError {
     MultipathNotNegotiated,
     ServerSideNotAllowed,
     MaxPathIdReached,
@@ -12,8 +12,8 @@
 
§

RemoteCidsExhausted

No remote CIDs available to open a new path

§

ValidationFailed

Path could not be validated and will be abandoned

§

InvalidRemoteAddress(SocketAddr)

The remote address for the path is not supported by the endpoint

-

Trait Implementations§

Source§

impl Clone for PathError

Source§

fn clone(&self) -> PathError

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for PathError

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Display for PathError

Source§

fn fmt(&self, __formatter: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Error for PathError

1.30.0 · Source§

fn source(&self) -> Option<&(dyn Error + 'static)>

Returns the lower-level source of this error, if any. Read more
1.0.0 · Source§

fn description(&self) -> &str

👎Deprecated since 1.42.0: use the Display impl or to_string()
1.0.0 · Source§

fn cause(&self) -> Option<&dyn Error>

👎Deprecated since 1.33.0: replaced by Error::source, which can support downcasting
Source§

fn provide<'a>(&'a self, request: &mut Request<'a>)

🔬This is a nightly-only experimental API. (error_generic_member_access)
Provides type-based access to context intended for error reports. Read more
Source§

impl PartialEq for PathError

Source§

fn eq(&self, other: &PathError) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, -and should not be overridden without very good reason.
Source§

impl Copy for PathError

Source§

impl Eq for PathError

Source§

impl StructuralPartialEq for PathError

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where +

Trait Implementations§

Source§

impl Clone for PathError

Source§

fn clone(&self) -> PathError

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for PathError

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Display for PathError

Source§

fn fmt(&self, __formatter: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Error for PathError

1.30.0 · Source§

fn source(&self) -> Option<&(dyn Error + 'static)>

Returns the lower-level source of this error, if any. Read more
1.0.0 · Source§

fn description(&self) -> &str

👎Deprecated since 1.42.0: use the Display impl or to_string()
1.0.0 · Source§

fn cause(&self) -> Option<&dyn Error>

👎Deprecated since 1.33.0: replaced by Error::source, which can support downcasting
Source§

fn provide<'a>(&'a self, request: &mut Request<'a>)

🔬This is a nightly-only experimental API. (error_generic_member_access)
Provides type-based access to context intended for error reports. Read more
Source§

impl PartialEq for PathError

Source§

fn eq(&self, other: &PathError) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, +and should not be overridden without very good reason.
Source§

impl Copy for PathError

Source§

impl Eq for PathError

Source§

impl StructuralPartialEq for PathError

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where diff --git a/pr/338/docs/iroh_quinn_proto/enum.PathEvent.html b/pr/338/docs/iroh_quinn_proto/enum.PathEvent.html index 0275d4421..683f2c81c 100644 --- a/pr/338/docs/iroh_quinn_proto/enum.PathEvent.html +++ b/pr/338/docs/iroh_quinn_proto/enum.PathEvent.html @@ -47,7 +47,7 @@ changes the status.

Fields

§id: PathId

Path over which the observed address was reported, PathId::ZERO when multipath is not negotiated

§addr: SocketAddr

The address observed by the remote over this path

-

Trait Implementations§

Source§

impl Clone for PathEvent

Source§

fn clone(&self) -> PathEvent

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for PathEvent

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl From<PathEvent> for Event

Source§

fn from(source: PathEvent) -> Self

Converts to this type from the input type.
Source§

impl PartialEq for PathEvent

Source§

fn eq(&self, other: &PathEvent) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, +

Trait Implementations§

Source§

impl Clone for PathEvent

Source§

fn clone(&self) -> PathEvent

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for PathEvent

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl From<PathEvent> for Event

Source§

fn from(source: PathEvent) -> Self

Converts to this type from the input type.
Source§

impl PartialEq for PathEvent

Source§

fn eq(&self, other: &PathEvent) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
Source§

impl Eq for PathEvent

Source§

impl StructuralPartialEq for PathEvent

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where diff --git a/pr/338/docs/iroh_quinn_proto/struct.Connection.html b/pr/338/docs/iroh_quinn_proto/struct.Connection.html index bdfadbec8..6f12fea18 100644 --- a/pr/338/docs/iroh_quinn_proto/struct.Connection.html +++ b/pr/338/docs/iroh_quinn_proto/struct.Connection.html @@ -33,7 +33,7 @@ increasing time. Specifically, calling Instant may be interleaved in any order with a call to handle_event at that same instant; however events or timeouts with different instants must not be interleaved.

-

Implementations§

Source§

impl Connection

Source

pub fn poll_timeout(&mut self) -> Option<Instant>

Returns the next time at which handle_timeout should be called

+

Implementations§

Source§

impl Connection

Source

pub fn poll_timeout(&mut self) -> Option<Instant>

Returns the next time at which handle_timeout should be called

The value returned may change after:

  • the application performed some I/O on the connection
  • @@ -41,17 +41,17 @@ events or timeouts with different instants must not be interleaved.

  • a call to poll_transmit returned Some
  • a call was made to handle_timeout
-
Source

pub fn poll(&mut self) -> Option<Event>

Returns application-facing events

+
Source

pub fn poll(&mut self) -> Option<Event>

Returns application-facing events

Connections should be polled for events after:

  • a call was made to handle_event
  • a call was made to handle_timeout
-
Source

pub fn poll_endpoint_events(&mut self) -> Option<EndpointEvent>

Return endpoint-facing events

-
Source

pub fn streams(&mut self) -> Streams<'_>

Provide control over streams

-
Source

pub fn recv_stream(&mut self, id: StreamId) -> RecvStream<'_>

Provide control over streams

-
Source

pub fn send_stream(&mut self, id: StreamId) -> SendStream<'_>

Provide control over streams

-
Source

pub fn open_path_ensure( +

Source

pub fn poll_endpoint_events(&mut self) -> Option<EndpointEvent>

Return endpoint-facing events

+
Source

pub fn streams(&mut self) -> Streams<'_>

Provide control over streams

+
Source

pub fn recv_stream(&mut self, id: StreamId) -> RecvStream<'_>

Provide control over streams

+
Source

pub fn send_stream(&mut self, id: StreamId) -> SendStream<'_>

Provide control over streams

+
Source

pub fn open_path_ensure( &mut self, network_path: FourTuple, initial_status: PathStatus, @@ -65,7 +65,7 @@ remote addresses.

remote, should it not be known yet. We assume that if we already have a path to the remote, the OS is likely to use the same interface to talk to said remote.

See also open_path. Returns (path_id, true) if the path already existed. (path_id, false) if was opened.

-

Source

pub fn open_path( +

Source

pub fn open_path( &mut self, network_path: FourTuple, initial_status: PathStatus, @@ -73,7 +73,7 @@ the OS is likely to use the same interface to talk to said remote.

) -> Result<PathId, PathError>

Opens a new path

Further errors might occur and they will be emitted in PathEvent::LocallyClosed events. When the path is opened it will be reported as an PathEvent::Opened.

-
Source

pub fn close_path( +

Source

pub fn close_path( &mut self, now: Instant, path_id: PathId, @@ -82,32 +82,32 @@ When the path is opened it will be reported as an
Source

pub fn paths(&self) -> Vec<PathId>

Returns all known paths.

+

Source

pub fn paths(&self) -> Vec<PathId>

Returns all known paths.

There is no guarantee any of these paths are open or usable.

-
Source

pub fn path_status(&self, path_id: PathId) -> Result<PathStatus, ClosedPath>

Gets the local PathStatus for a known PathId

-
Source

pub fn network_path(&self, path_id: PathId) -> Result<FourTuple, ClosedPath>

Returns the path’s network path represented as a 4-tuple.

-
Source

pub fn set_path_status( +

Source

pub fn path_status(&self, path_id: PathId) -> Result<PathStatus, ClosedPath>

Gets the local PathStatus for a known PathId

+
Source

pub fn network_path(&self, path_id: PathId) -> Result<FourTuple, ClosedPath>

Returns the path’s network path represented as a 4-tuple.

+
Source

pub fn set_path_status( &mut self, path_id: PathId, status: PathStatus, ) -> Result<PathStatus, SetPathStatusError>

Sets the PathStatus for a known PathId

Returns the previous path status on success.

-
Source

pub fn remote_path_status(&self, path_id: PathId) -> Option<PathStatus>

Returns the remote path status

-
Source

pub fn set_path_max_idle_timeout( +

Source

pub fn remote_path_status(&self, path_id: PathId) -> Option<PathStatus>

Returns the remote path status

+
Source

pub fn set_path_max_idle_timeout( &mut self, path_id: PathId, timeout: Option<Duration>, ) -> Result<Option<Duration>, ClosedPath>

Sets the max_idle_timeout for a specific path

See TransportConfig::default_path_max_idle_timeout for details.

Returns the previous value of the setting.

-
Source

pub fn set_path_keep_alive_interval( +

Source

pub fn set_path_keep_alive_interval( &mut self, path_id: PathId, interval: Option<Duration>, ) -> Result<Option<Duration>, ClosedPath>

Sets the keep_alive_interval for a specific path

See TransportConfig::default_path_keep_alive_interval for details.

Returns the previous value of the setting.

-
Source

pub fn poll_transmit( +

Source

pub fn poll_transmit( &mut self, now: Instant, max_datagrams: NonZeroUsize, @@ -121,60 +121,60 @@ for a path that was never opened locally.

max_datagrams specifies how many datagrams can be returned inside a single Transmit using GSO. This must be at least 1.

-

Source

pub fn handle_event(&mut self, event: ConnectionEvent)

Process ConnectionEvents generated by the associated Endpoint

+
Source

pub fn handle_event(&mut self, event: ConnectionEvent)

Process ConnectionEvents generated by the associated Endpoint

Will execute protocol logic upon receipt of a connection event, in turn preparing signals (including application Events, EndpointEvents and outgoing datagrams) that should be extracted through the relevant methods.

-
Source

pub fn handle_timeout(&mut self, now: Instant)

Process timer expirations

+
Source

pub fn handle_timeout(&mut self, now: Instant)

Process timer expirations

Executes protocol logic, potentially preparing signals (including application Events, EndpointEvents and outgoing datagrams) that should be extracted through the relevant methods.

It is most efficient to call this immediately after the system clock reaches the latest Instant that was output by poll_timeout; however spurious extra calls will simply no-op and therefore are safe.

-
Source

pub fn close(&mut self, now: Instant, error_code: VarInt, reason: Bytes)

Close a connection immediately

+
Source

pub fn close(&mut self, now: Instant, error_code: VarInt, reason: Bytes)

Close a connection immediately

This does not ensure delivery of outstanding data. It is the application’s responsibility to call this only when all important communications have been completed, e.g. by calling SendStream::finish on outstanding streams and waiting for the corresponding StreamEvent::Finished event.

If Streams::send_streams returns 0, all outstanding stream data has been delivered. There may still be data from the peer that has not been received.

-
Source

pub fn datagrams(&mut self) -> Datagrams<'_>

Control datagrams

-
Source

pub fn stats(&mut self) -> ConnectionStats

Returns connection statistics

-
Source

pub fn path_stats(&mut self, path_id: PathId) -> Option<PathStats>

Returns path statistics

-
Source

pub fn ping(&mut self)

Ping the remote endpoint

+
Source

pub fn datagrams(&mut self) -> Datagrams<'_>

Control datagrams

+
Source

pub fn stats(&mut self) -> ConnectionStats

Returns connection statistics

+
Source

pub fn path_stats(&mut self, path_id: PathId) -> Option<PathStats>

Returns path statistics

+
Source

pub fn ping(&mut self)

Ping the remote endpoint

Causes an ACK-eliciting packet to be transmitted on the connection.

-
Source

pub fn ping_path(&mut self, path: PathId) -> Result<(), ClosedPath>

Ping the remote endpoint over a specific path

+
Source

pub fn ping_path(&mut self, path: PathId) -> Result<(), ClosedPath>

Ping the remote endpoint over a specific path

Causes an ACK-eliciting packet to be transmitted on the path.

-
Source

pub fn force_key_update(&mut self)

Update traffic keys spontaneously

+
Source

pub fn force_key_update(&mut self)

Update traffic keys spontaneously

This can be useful for testing key updates, as they otherwise only happen infrequently.

-
Source

pub fn crypto_session(&self) -> &dyn Session

Get a session reference

-
Source

pub fn is_handshaking(&self) -> bool

Whether the connection is in the process of being established

+
Source

pub fn crypto_session(&self) -> &dyn Session

Get a session reference

+
Source

pub fn is_handshaking(&self) -> bool

Whether the connection is in the process of being established

If this returns false, the connection may be either established or closed, signaled by the emission of a Connected or ConnectionLost message respectively.

-
Source

pub fn is_closed(&self) -> bool

Whether the connection is closed

+
Source

pub fn is_closed(&self) -> bool

Whether the connection is closed

Closed connections cannot transport any further data. A connection becomes closed when either peer application intentionally closes it, or when either transport layer detects an error such as a time-out or certificate validation failure.

A ConnectionLost event is emitted with details when the connection becomes closed.

-
Source

pub fn is_drained(&self) -> bool

Whether there is no longer any need to keep the connection around

+
Source

pub fn is_drained(&self) -> bool

Whether there is no longer any need to keep the connection around

Closed connections become drained after a brief timeout to absorb any remaining in-flight packets from the peer. All drained connections have been closed.

-
Source

pub fn accepted_0rtt(&self) -> bool

For clients, if the peer accepted the 0-RTT data packets

+
Source

pub fn accepted_0rtt(&self) -> bool

For clients, if the peer accepted the 0-RTT data packets

The value is meaningless until after the handshake completes.

-
Source

pub fn has_0rtt(&self) -> bool

Whether 0-RTT is/was possible during the handshake

-
Source

pub fn has_pending_retransmits(&self) -> bool

Whether there are any pending retransmits

-
Source

pub fn side(&self) -> Side

Look up whether we’re the client or server of this Connection

-
Source

pub fn path_observed_address( +

Source

pub fn has_0rtt(&self) -> bool

Whether 0-RTT is/was possible during the handshake

+
Source

pub fn has_pending_retransmits(&self) -> bool

Whether there are any pending retransmits

+
Source

pub fn side(&self) -> Side

Look up whether we’re the client or server of this Connection

+
Source

pub fn path_observed_address( &self, path_id: PathId, ) -> Result<Option<SocketAddr>, ClosedPath>

Get the address observed by the remote over the given path

-
Source

pub fn rtt(&self, path_id: PathId) -> Option<Duration>

Current best estimate of this connection’s latency (round-trip-time)

-
Source

pub fn congestion_state(&self, path_id: PathId) -> Option<&dyn Controller>

Current state of this connection’s congestion controller, for debugging purposes

-
Source

pub fn set_max_concurrent_streams(&mut self, dir: Dir, count: VarInt)

Modify the number of remotely initiated streams that may be concurrently open

+
Source

pub fn rtt(&self, path_id: PathId) -> Option<Duration>

Current best estimate of this connection’s latency (round-trip-time)

+
Source

pub fn congestion_state(&self, path_id: PathId) -> Option<&dyn Controller>

Current state of this connection’s congestion controller, for debugging purposes

+
Source

pub fn set_max_concurrent_streams(&mut self, dir: Dir, count: VarInt)

Modify the number of remotely initiated streams that may be concurrently open

No streams may be opened by the peer unless fewer than count are already open. Large counts increase both minimum and worst-case memory consumption.

-
Source

pub fn set_max_concurrent_paths( +

Source

pub fn set_max_concurrent_paths( &mut self, now: Instant, count: NonZeroU32, @@ -185,36 +185,36 @@ actively reduce paths they must be closed using TransportConfig) this can not enable multipath and will fail.

-

Source

pub fn max_concurrent_streams(&self, dir: Dir) -> u64

Current number of remotely initiated streams that may be concurrently open

+
Source

pub fn max_concurrent_streams(&self, dir: Dir) -> u64

Current number of remotely initiated streams that may be concurrently open

If the target for this limit is reduced using set_max_concurrent_streams, it will not change immediately, even if fewer streams are open. Instead, it will decrement by one for each time a remotely initiated stream of matching directionality is closed.

-
Source

pub fn set_send_window(&mut self, send_window: u64)

Source

pub fn set_receive_window(&mut self, receive_window: VarInt)

Source

pub fn is_multipath_negotiated(&self) -> bool

Whether the Multipath for QUIC extension is enabled.

+
Source

pub fn set_send_window(&mut self, send_window: u64)

Source

pub fn set_receive_window(&mut self, receive_window: VarInt)

Source

pub fn is_multipath_negotiated(&self) -> bool

Whether the Multipath for QUIC extension is enabled.

Multipath is only enabled after the handshake is completed and if it was enabled by both peers.

-
Source

pub fn local_address_changed(&mut self)

Handle a change in the local address, i.e. an active migration

-
Source

pub fn current_mtu(&self) -> u16

Storage size required for the largest packet that can be transmitted on all currently +

Source

pub fn local_address_changed(&mut self)

Handle a change in the local address, i.e. an active migration

+
Source

pub fn current_mtu(&self) -> u16

Storage size required for the largest packet that can be transmitted on all currently available paths

Buffers passed to Connection::poll_transmit should be at least this large.

When multipath is enabled, this value is the minimum MTU across all available paths.

-
Source

pub fn add_nat_traversal_address( +

Source

pub fn add_nat_traversal_address( &mut self, address: SocketAddr, ) -> Result<(), Error>

Add addresses the local endpoint considers are reachable for nat traversal

-
Source

pub fn remove_nat_traversal_address( +

Source

pub fn remove_nat_traversal_address( &mut self, address: SocketAddr, ) -> Result<(), Error>

Removes an address the endpoing no longer considers reachable for nat traversal

Addresses not present in the set will be silently ignored.

-
Source

pub fn get_local_nat_traversal_addresses( +

Source

pub fn get_local_nat_traversal_addresses( &self, ) -> Result<Vec<SocketAddr>, Error>

Get the current local nat traversal addresses

-
Source

pub fn get_remote_nat_traversal_addresses( +

Source

pub fn get_remote_nat_traversal_addresses( &self, ) -> Result<Vec<SocketAddr>, Error>

Get the currently advertised nat traversal addresses by the server

-
Source

pub fn initiate_nat_traversal_round( +

Source

pub fn initiate_nat_traversal_round( &mut self, now: Instant, ) -> Result<Vec<SocketAddr>, Error>

Initiates a new nat traversal round

@@ -224,7 +224,7 @@ initiated, the previous one is cancelled, and paths that have not been opened ar

Returns the server addresses that are now being probed. If addresses fail due to spurious errors, these might succeed later and not be returned in this set.

-

Trait Implementations§

Source§

impl Debug for Connection

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

§

impl !Freeze for Connection

§

impl !RefUnwindSafe for Connection

§

impl Send for Connection

§

impl Sync for Connection

§

impl Unpin for Connection

§

impl !UnwindSafe for Connection

Blanket Implementations§

Source§

impl<T> Any for T
where +

Trait Implementations§

Source§

impl Debug for Connection

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

§

impl !Freeze for Connection

§

impl !RefUnwindSafe for Connection

§

impl Send for Connection

§

impl Sync for Connection

§

impl Unpin for Connection

§

impl !UnwindSafe for Connection

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

diff --git a/pr/338/docs/iroh_quinn_proto/struct.MultipathNotNegotiated.html b/pr/338/docs/iroh_quinn_proto/struct.MultipathNotNegotiated.html index de9c372b2..c46edf038 100644 --- a/pr/338/docs/iroh_quinn_proto/struct.MultipathNotNegotiated.html +++ b/pr/338/docs/iroh_quinn_proto/struct.MultipathNotNegotiated.html @@ -1,5 +1,5 @@ -MultipathNotNegotiated in iroh_quinn_proto - Rust

MultipathNotNegotiated

Struct MultipathNotNegotiated 

Source
pub struct MultipathNotNegotiated { /* private fields */ }
Expand description

Error when the multipath extension was not negotiated, but attempted to be used.

-

Trait Implementations§

Source§

impl Clone for MultipathNotNegotiated

Source§

fn clone(&self) -> MultipathNotNegotiated

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for MultipathNotNegotiated

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Display for MultipathNotNegotiated

Source§

fn fmt(&self, __formatter: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Error for MultipathNotNegotiated

1.30.0 · Source§

fn source(&self) -> Option<&(dyn Error + 'static)>

Returns the lower-level source of this error, if any. Read more
1.0.0 · Source§

fn description(&self) -> &str

👎Deprecated since 1.42.0: use the Display impl or to_string()
1.0.0 · Source§

fn cause(&self) -> Option<&dyn Error>

👎Deprecated since 1.33.0: replaced by Error::source, which can support downcasting
Source§

fn provide<'a>(&'a self, request: &mut Request<'a>)

🔬This is a nightly-only experimental API. (error_generic_member_access)
Provides type-based access to context intended for error reports. Read more
Source§

impl Copy for MultipathNotNegotiated

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where +MultipathNotNegotiated in iroh_quinn_proto - Rust

MultipathNotNegotiated

Struct MultipathNotNegotiated 

Source
pub struct MultipathNotNegotiated { /* private fields */ }
Expand description

Error when the multipath extension was not negotiated, but attempted to be used.

+

Trait Implementations§

Source§

impl Clone for MultipathNotNegotiated

Source§

fn clone(&self) -> MultipathNotNegotiated

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for MultipathNotNegotiated

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Display for MultipathNotNegotiated

Source§

fn fmt(&self, __formatter: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Error for MultipathNotNegotiated

1.30.0 · Source§

fn source(&self) -> Option<&(dyn Error + 'static)>

Returns the lower-level source of this error, if any. Read more
1.0.0 · Source§

fn description(&self) -> &str

👎Deprecated since 1.42.0: use the Display impl or to_string()
1.0.0 · Source§

fn cause(&self) -> Option<&dyn Error>

👎Deprecated since 1.33.0: replaced by Error::source, which can support downcasting
Source§

fn provide<'a>(&'a self, request: &mut Request<'a>)

🔬This is a nightly-only experimental API. (error_generic_member_access)
Provides type-based access to context intended for error reports. Read more
Source§

impl Copy for MultipathNotNegotiated

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where diff --git a/pr/338/docs/iroh_quinn_proto/struct.TransportError.html b/pr/338/docs/iroh_quinn_proto/struct.TransportError.html index a3c8acce4..7cb495959 100644 --- a/pr/338/docs/iroh_quinn_proto/struct.TransportError.html +++ b/pr/338/docs/iroh_quinn_proto/struct.TransportError.html @@ -11,7 +11,7 @@
§reason: String

Human-readable explanation of the reason

§crypto: Option<Arc<dyn Error + Send + Sync>>

An underlying crypto (e.g. TLS) layer error

Implementations§

Source§

impl Error

Source

pub fn new(code: Code, reason: String) -> Self

Construct an error with a code and a reason

-

Trait Implementations§

Source§

impl Clone for Error

Source§

fn clone(&self) -> Error

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for Error

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Display for Error

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Error for Error

1.30.0 · Source§

fn source(&self) -> Option<&(dyn Error + 'static)>

Returns the lower-level source of this error, if any. Read more
1.0.0 · Source§

fn description(&self) -> &str

👎Deprecated since 1.42.0: use the Display impl or to_string()
1.0.0 · Source§

fn cause(&self) -> Option<&dyn Error>

👎Deprecated since 1.33.0: replaced by Error::source, which can support downcasting
Source§

fn provide<'a>(&'a self, request: &mut Request<'a>)

🔬This is a nightly-only experimental API. (error_generic_member_access)
Provides type-based access to context intended for error reports. Read more
Source§

impl From<Error> for ConnectionClose

Source§

fn from(x: TransportError) -> Self

Converts to this type from the input type.
Source§

impl From<Error> for ConnectionError

Source§

fn from(source: TransportError) -> Self

Converts to this type from the input type.
Source§

impl From<Error> for TransportError

Source§

fn from(e: Error) -> Self

Converts to this type from the input type.
Source§

impl PartialEq for Error

Source§

fn eq(&self, other: &Self) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, +

Trait Implementations§

Source§

impl Clone for Error

Source§

fn clone(&self) -> Error

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for Error

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Display for Error

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Error for Error

1.30.0 · Source§

fn source(&self) -> Option<&(dyn Error + 'static)>

Returns the lower-level source of this error, if any. Read more
1.0.0 · Source§

fn description(&self) -> &str

👎Deprecated since 1.42.0: use the Display impl or to_string()
1.0.0 · Source§

fn cause(&self) -> Option<&dyn Error>

👎Deprecated since 1.33.0: replaced by Error::source, which can support downcasting
Source§

fn provide<'a>(&'a self, request: &mut Request<'a>)

🔬This is a nightly-only experimental API. (error_generic_member_access)
Provides type-based access to context intended for error reports. Read more
Source§

impl From<Error> for ConnectionClose

Source§

fn from(x: TransportError) -> Self

Converts to this type from the input type.
Source§

impl From<Error> for ConnectionError

Source§

fn from(source: TransportError) -> Self

Converts to this type from the input type.
Source§

impl From<Error> for TransportError

Source§

fn from(e: Error) -> Self

Converts to this type from the input type.
Source§

impl PartialEq for Error

Source§

fn eq(&self, other: &Self) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
Source§

impl Eq for Error

Auto Trait Implementations§

§

impl Freeze for Error

§

impl !RefUnwindSafe for Error

§

impl Send for Error

§

impl Sync for Error

§

impl Unpin for Error

§

impl !UnwindSafe for Error

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where diff --git a/pr/338/docs/search.index/entry/97f94d3449ba.js b/pr/338/docs/search.index/entry/03289d5b1053.js similarity index 94% rename from pr/338/docs/search.index/entry/97f94d3449ba.js rename to pr/338/docs/search.index/entry/03289d5b1053.js index f008a916f..3d7151f04 100644 --- a/pr/338/docs/search.index/entry/97f94d3449ba.js +++ b/pr/338/docs/search.index/entry/03289d5b1053.js @@ -1 +1 @@ -rd_("Ah[3954,15,3955,0,119,0,0]Ak[4739,15,4740,4740,120,0,0]Ai[3954,15,3955,0,4140,0,0]Al[4739,15,4740,1934,4141,0,0]Al[4445,15,4446,4446,4142,0,0]Al[4739,15,1840,1840,1593,0,0]Ao[1365,13,1366,1366,3986,3140,0]Ao[3954,13,3955,3712,4781,3140,0]Ao[3954,13,3955,4090,4405,3140,0]Ao[3954,13,3955,4090,3148,3140,0]Ao[3954,13,3955,4090,3337,3140,0]Ao[3954,13,3955,4090,4404,3140,0]Ao[3954,13,3955,4095,3355,3140,0]Ao[3954,13,3955,4095,4174,3140,0]Al[3954,13,3955,0,1603,3140,0]Al[3954,13,3955,0,4940,3140,0]Al[3954,13,3955,0,1324,3140,0]Al[3954,13,3955,0,1586,3140,0]Al[3954,13,3955,0,2434,3140,0]Al[3954,13,3955,0,3145,3140,0]Al[3954,13,3955,0,2018,3140,0]Al[3954,13,3955,0,4126,3140,0]Al[3954,13,3955,0,4499,3140,0]Al[3954,13,3955,0,3999,3140,0]Al[3954,13,3955,0,3989,3140,0]Al[3954,13,3955,0,3128,3140,0]Al[3954,13,3955,0,4496,3140,0]Al[3954,13,3955,0,4684,3140,0]Al[3954,13,3955,0,4132,3140,0]Al[3954,13,3955,0,4135,3140,0]Al[3954,13,3955,0,4140,3140,0]Al[3954,13,3955,0,4839,3140,0]Ak[3954,13,3955,0,485,3140,0]Ak[3954,13,3955,0,119,3140,0]Al[3954,13,3955,0,2422,3140,0]Al[3954,13,1844,0,5086,3140,0]Al[3954,13,1923,0,1341,3140,0]Ao[4739,13,4740,1960,1604,3140,0]Ao[4739,13,4740,1960,4941,3140,0]Ao[4739,13,4740,3164,1325,3140,0]Ao[4739,13,4740,3173,4782,3140,0]Ao[4739,13,4740,1526,1587,3140,0]Ao[4739,13,4740,1526,3331,3140,0]Ao[4739,13,4740,1526,3144,3140,0]Ao[4739,13,4740,1526,4836,3140,0]Ao[4739,13,4740,1526,3306,3140,0]Ao[4739,13,4740,1541,2435,3140,0]Ao[4739,13,4740,1541,3146,3140,0]Ao[4739,13,4740,1075,3149,3140,0]Ao[4739,13,4740,1075,4294,3140,0]Ao[4739,13,4740,1080,2019,3140,0]Ao[4739,13,4740,1080,3356,3140,0]Ao[4739,13,4740,1080,3998,3140,0]Ao[4739,13,4740,2152,4016,3140,0]Ao[4739,13,4740,2152,4406,3140,0]Ao[4739,13,4740,2152,4130,3140,0]Ao[4739,13,4740,3713,4500,3140,0]Ao[4739,13,4740,3713,3141,3140,0]Ao[4739,13,4740,3713,4372,3140,0]Ao[4739,13,4740,3293,4000,3140,0]Ao[4739,13,4740,1842,3990,3140,0]Ao[4739,13,4740,1516,3129,3140,0]Ao[4739,13,4740,1516,4387,3140,0]Ao[4739,13,4740,1516,3323,3140,0]Ao[4739,13,4740,1516,3345,3140,0]Ao[4739,13,4740,1516,4137,3140,0]Ao[4739,13,4740,1516,4498,3140,0]Ao[4739,13,4740,1516,4686,3140,0]Ao[4739,13,4740,2445,4690,3140,0]Ao[4739,13,4740,2445,4133,3140,0]Ao[4739,13,4740,1907,2406,3140,0]Ao[4739,13,4740,1907,4780,3140,0]Ao[4739,13,4740,1934,4136,3140,0]Ao[4739,13,4740,1934,4141,3140,0]Al[4739,13,4740,0,4410,3140,0]Al[4739,13,4740,0,4840,3140,0]An[4739,13,4740,4740,486,3140,0]An[4739,13,4740,4740,120,3140,0]Ao[4739,13,4740,4740,2423,3140,0]Ao[4739,13,4740,4740,3127,3140,0]Ao[4739,13,1840,1840,4300,3140,0]Ao[4739,13,4982,4982,4881,3140,0]Ao[4739,13,4982,4982,1343,3140,0]Ao[4739,13,1845,1845,5087,3140,0]Al[4739,13,1924,0,1342,3140,0]Ao[4445,13,4446,4446,4142,3140,0]Ak[3954,13,3955,1049,478,0,0]Al[3954,13,3955,4090,3335,0,0]Al[3954,13,3955,4090,4882,0,0]Al[3954,13,3955,4095,3341,0,0]Ai[4739,14,3142,0,1580,0,0]Ai[4739,14,3142,0,1570,0,0]Ai[4739,14,3142,0,3107,0,0]Ai[4739,14,3142,0,4277,0,0]Ai[4739,14,3142,0,4161,0,0]Ai[4739,14,3142,0,4154,0,0]Ai[4739,14,4015,0,2416,0,0]Ai[4739,14,4015,0,2437,0,0]Ai[4739,14,4015,0,2401,0,0]Ai[4739,14,4015,0,2007,0,0]Ae[1365,7,1366,0,0,0,0]Ah[4739,14,4511,0,474,0,0]Ai[3954,15,3955,0,3128,0,0]Al[4739,15,4740,1516,3129,0,0]Ag[3954,5,3707,135,0,0,0]Ag[4739,5,3708,135,0,0,0]Al[1050,15,1051,1051,4874,0,0]Ae[3974,5,3975,0,0,0,0]Ah[3954,6,3955,4740,0,0,0]Ae[4739,6,4740,0,0,0,0]Al[4739,15,1840,1840,1593,0,0]Ai[3954,19,3955,0,1603,0,0]Ai[3954,19,3955,0,1586,0,0]Al[4739,19,4740,1960,1604,0,0]Al[4739,19,4740,1526,1587,0,0]Ae[1365,5,1366,0,0,0,0]Ae[1050,5,1834,0,0,0,0]Ae[1050,5,1929,0,0,0,0]Ah[3954,15,3955,0,119,0,0]Ak[4739,15,4740,4740,120,0,0]Ak[3954,13,3955,0,1603,130,0]Ak[3954,13,3955,0,1586,130,0]Ak[3954,13,3955,0,3999,130,0]Ak[3954,13,3955,0,4135,130,0]Aj[3954,13,3955,0,485,130,0]Aj[3954,13,3955,0,119,130,0]Ak[3954,13,3955,0,2422,130,0]An[4739,13,4740,1960,1604,130,0]An[4739,13,4740,3173,4782,130,0]An[4739,13,4740,1526,1587,130,0]An[4739,13,4740,1075,3149,130,0]An[4739,13,4740,1075,4294,130,0]An[4739,13,4740,1080,3356,130,0]An[4739,13,4740,3293,4000,130,0]An[4739,13,4740,2445,4690,130,0]An[4739,13,4740,1907,4780,130,0]An[4739,13,4740,1934,4136,130,0]Am[4739,13,4740,4740,486,130,0]Am[4739,13,4740,4740,120,130,0]An[4739,13,4740,4740,2423,130,0]Ai[3954,13,3955,0,2422,0,0]Al[4739,13,4740,4740,2423,0,0]Ai[4739,14,4015,0,1581,0,0]Ai[4739,14,4015,0,3113,0,0]Ai[3954,14,3955,0,2431,0,0]Al[4739,14,4740,4740,2432,0,0]Al[4445,14,4446,4446,2420,0,0]Al[4445,14,4446,4446,2433,0,0]An[1365,13,1366,1366,127,1331,0]Ao[1365,13,1366,1366,3986,1331,0]Ao[1365,13,1540,1540,4407,1331,0]Ao[4023,13,4024,4024,5028,1331,0]Ao[3954,13,3955,3712,3308,1331,0]Ao[3954,13,3955,3712,3310,1331,0]Ao[3954,13,3955,3712,4943,1331,0]Dd[3954,13,3955,3712,4781,1979,0,\"impl-Display-for-SendDatagramError\"]Db[3954,13,3955,3712,4781,1331,0,\"impl-Debug-for-SendDatagramError\"]Ao[3954,13,3955,2444,2399,1331,0]Ao[3954,13,3955,2444,4267,1331,0]Ao[3954,13,3955,2471,2403,1331,0]Cm[3954,13,3955,2471,3338,1979,0,\"impl-Display-for-RetryError\"]Ck[3954,13,3955,2471,3338,1331,0,\"impl-Debug-for-RetryError\"]Ao[3954,13,3955,2471,4386,1331,0]An[3954,13,3955,1049,478,1331,0]Ao[3954,13,3955,4090,3335,1331,0]Ao[3954,13,3955,4090,4882,1331,0]Da[3954,13,3955,4090,4405,1979,0,\"impl-Display-for-ReadToEndError\"]Co[3954,13,3955,4090,4405,1331,0,\"impl-Debug-for-ReadToEndError\"]Cj[3954,13,3955,4090,3148,1331,0,\"impl-Debug-for-ReadError\"]Cl[3954,13,3955,4090,3148,1979,0,\"impl-Display-for-ReadError\"]Cm[3954,13,3955,4090,3337,1979,0,\"impl-Display-for-ResetError\"]Ck[3954,13,3955,4090,3337,1331,0,\"impl-Debug-for-ResetError\"]Co[3954,13,3955,4090,4404,1331,0,\"impl-Debug-for-ReadExactError\"]Da[3954,13,3955,4090,4404,1979,0,\"impl-Display-for-ReadExactError\"]Ao[3954,13,3955,1552,4175,1331,0]Ao[3954,13,3955,1092,4012,1331,0]Ao[3954,13,3955,4095,3341,1331,0]Cm[3954,13,3955,4095,3355,1979,0,\"impl-Display-for-WriteError\"]Ck[3954,13,3955,4095,3355,1331,0,\"impl-Debug-for-WriteError\"]Co[3954,13,3955,4095,4174,1979,0,\"impl-Display-for-StoppedError\"]Cm[3954,13,3955,4095,4174,1331,0,\"impl-Debug-for-StoppedError\"]Cf[3954,13,3955,0,1603,1979,0,\"impl-Display-for-VarInt\"]Cd[3954,13,3955,0,1603,1331,0,\"impl-Debug-for-VarInt\"]Db[3954,13,3955,0,4940,1331,0,\"impl-Debug-for-VarIntBoundsExceeded\"]Dd[3954,13,3955,0,4940,1979,0,\"impl-Display-for-VarIntBoundsExceeded\"]Al[3954,13,3955,0,1324,1331,0]Cf[3954,13,3955,0,1586,1979,0,\"impl-Display-for-PathId\"]Cd[3954,13,3955,0,1586,1331,0,\"impl-Debug-for-PathId\"]Al[3954,13,3955,0,2434,1331,0]Al[3954,13,3955,0,3316,1331,0]Al[3954,13,3955,0,3145,1331,0]Al[3954,13,3955,0,4503,1331,0]Al[3954,13,3955,0,2018,1331,0]Cj[3954,13,3955,0,4126,1331,0,\"impl-Debug-for-ClosedStream\"]Cl[3954,13,3955,0,4126,1979,0,\"impl-Display-for-ClosedStream\"]Cm[3954,13,3955,0,4499,1331,0,\"impl-Debug-for-ConnectionError\"]Co[3954,13,3955,0,4499,1979,0,\"impl-Display-for-ConnectionError\"]Al[3954,13,3955,0,4513,1331,0]Al[3954,13,3955,0,4520,1331,0]Al[3954,13,3955,0,4805,1331,0]Al[3954,13,3955,0,4820,1331,0]Al[3954,13,3955,0,3999,1331,0]Al[3954,13,3955,0,4381,1331,0]Al[3954,13,3955,0,4168,1331,0]Al[3954,13,3955,0,4997,1331,0]Al[3954,13,3955,0,4120,1331,0]Ck[3954,13,3955,0,3989,1979,0,\"impl-Display-for-ConfigError\"]Ci[3954,13,3955,0,3989,1331,0,\"impl-Debug-for-ConfigError\"]Cg[3954,13,3955,0,3128,1331,0,\"impl-Debug-for-FrameType\"]Ci[3954,13,3955,0,3128,1979,0,\"impl-Display-for-FrameType\"]Co[3954,13,3955,0,4496,1979,0,\"impl-Display-for-ConnectionClose\"]Cm[3954,13,3955,0,4496,1331,0,\"impl-Debug-for-ConnectionClose\"]Cn[3954,13,3955,0,4684,1331,0,\"impl-Debug-for-ApplicationClose\"]D`[3954,13,3955,0,4684,1979,0,\"impl-Display-for-ApplicationClose\"]Cj[3954,13,3955,0,4132,1331,0,\"impl-Debug-for-ConnectError\"]Cl[3954,13,3955,0,4132,1979,0,\"impl-Display-for-ConnectError\"]Cl[3954,13,3955,0,4135,1979,0,\"impl-Display-for-ConnectionId\"]Cj[3954,13,3955,0,4135,1331,0,\"impl-Debug-for-ConnectionId\"]Al[3954,13,3955,0,4140,1331,0]D`[3954,13,3955,0,4839,1331,0,\"impl-Debug-for-TransportErrorCode\"]Db[3954,13,3955,0,4839,1979,0,\"impl-Display-for-TransportErrorCode\"]Al[3954,13,3955,0,3319,1331,0]Al[3954,13,3955,0,4715,1331,0]Ak[3954,13,3955,0,485,1331,0]Cb[3954,13,3955,0,119,1979,0,\"impl-Display-for-Dir\"]C`[3954,13,3955,0,119,1331,0,\"impl-Debug-for-Dir\"]Cf[3954,13,3955,0,2422,1331,0,\"impl-Debug-for-StreamId\"]Ch[3954,13,3955,0,2422,1979,0,\"impl-Display-for-StreamId\"]Al[3954,13,3955,0,2431,1331,0]Ak[3954,13,3707,0,113,1331,0]Al[3954,13,3707,0,3116,1331,0]Al[3954,13,3707,0,1328,1331,0]Al[3954,13,3707,0,3994,1331,0]Al[3954,13,3707,0,1992,1331,0]Al[3954,13,3707,0,4286,1331,0]Al[3954,13,3707,0,4773,1331,0]Al[3954,13,1844,0,5086,1331,0]Al[3954,13,1844,0,3992,1331,0]Al[3954,13,1844,0,4843,1331,0]Dd[3954,13,1923,0,4936,1979,0,\"impl-Display-for-NoInitialCipherSuite\"]Db[3954,13,1923,0,4936,1331,0,\"impl-Debug-for-NoInitialCipherSuite\"]Cc[3954,13,1923,0,1341,1331,0,\"impl-Debug-for-Error\"]Ce[3954,13,1923,0,1341,1979,0,\"impl-Display-for-Error\"]Ao[4739,13,4740,3713,3311,1331,0]Ao[4739,13,4740,2445,2400,1331,0]Ci[4739,13,4740,1960,1604,1979,0,\"impl-Display-for-VarInt\"]Cg[4739,13,4740,1960,1604,1331,0,\"impl-Debug-for-VarInt\"]Dg[4739,13,4740,1960,4941,1979,0,\"impl-Display-for-VarIntBoundsExceeded\"]De[4739,13,4740,1960,4941,1331,0,\"impl-Debug-for-VarIntBoundsExceeded\"]Ao[4739,13,4740,3164,1325,1331,0]Db[4739,13,4740,3173,4782,1331,0,\"impl-Debug-for-SendDatagramError\"]Dd[4739,13,4740,3173,4782,1979,0,\"impl-Display-for-SendDatagramError\"]Ci[4739,13,4740,1526,1587,1979,0,\"impl-Display-for-PathId\"]Cg[4739,13,4740,1526,1587,1331,0,\"impl-Debug-for-PathId\"]Ao[4739,13,4740,1526,4164,1331,0]Ao[4739,13,4740,1526,3331,1331,0]Ao[4739,13,4740,1526,3144,1331,0]Dc[4739,13,4740,1526,4836,1331,0,\"impl-Debug-for-SetPathStatusError\"]De[4739,13,4740,1526,4836,1979,0,\"impl-Display-for-SetPathStatusError\"]Cm[4739,13,4740,1526,3306,1979,0,\"impl-Display-for-ClosedPath\"]Ck[4739,13,4740,1526,3306,1331,0,\"impl-Debug-for-ClosedPath\"]Ao[4739,13,4740,1541,2435,1331,0]Ao[4739,13,4740,1541,3317,1331,0]Ao[4739,13,4740,1541,3146,1331,0]Ao[4739,13,4740,1541,4504,1331,0]Cl[4739,13,4740,1075,3149,1979,0,\"impl-Display-for-ReadError\"]Cj[4739,13,4740,1075,3149,1331,0,\"impl-Debug-for-ReadError\"]D`[4739,13,4740,1075,4294,1979,0,\"impl-Display-for-ReadableError\"]Cn[4739,13,4740,1075,4294,1331,0,\"impl-Debug-for-ReadableError\"]Ao[4739,13,4740,1080,2019,1331,0]Cm[4739,13,4740,1080,3356,1979,0,\"impl-Display-for-WriteError\"]Ck[4739,13,4740,1080,3356,1331,0,\"impl-Debug-for-WriteError\"]Cl[4739,13,4740,1080,3998,1331,0,\"impl-Debug-for-FinishError\"]Cn[4739,13,4740,1080,3998,1979,0,\"impl-Display-for-FinishError\"]Ao[4739,13,4740,2152,4016,1331,0]Ao[4739,13,4740,2152,4406,1331,0]Co[4739,13,4740,2152,4130,1979,0,\"impl-Display-for-ClosedStream\"]Cm[4739,13,4740,2152,4130,1331,0,\"impl-Debug-for-ClosedStream\"]D`[4739,13,4740,3713,4500,1331,0,\"impl-Debug-for-ConnectionError\"]Db[4739,13,4740,3713,4500,1979,0,\"impl-Display-for-ConnectionError\"]Cj[4739,13,4740,3713,3141,1331,0,\"impl-Debug-for-PathError\"]Cl[4739,13,4740,3713,3141,1979,0,\"impl-Display-for-PathError\"]Co[4739,13,4740,3713,4372,1331,0,\"impl-Debug-for-ClosePathError\"]Da[4739,13,4740,3713,4372,1979,0,\"impl-Display-for-ClosePathError\"]Di[4739,13,4740,3713,5024,1979,0,\"impl-Display-for-MultipathNotNegotiated\"]Dg[4739,13,4740,3713,5024,1331,0,\"impl-Debug-for-MultipathNotNegotiated\"]Ao[4739,13,4740,3713,1346,1331,0]Ao[4739,13,4740,1071,4514,1331,0]Ao[4739,13,4740,3293,4521,1331,0]Ao[4739,13,4740,3293,4806,1331,0]Ao[4739,13,4740,3293,4821,1331,0]Ao[4739,13,4740,3293,4000,1331,0]Ao[4739,13,4740,1842,4382,1331,0]Ao[4739,13,4740,1842,4170,1331,0]Ao[4739,13,4740,1842,4998,1331,0]Ao[4739,13,4740,1842,4122,1331,0]Cn[4739,13,4740,1842,3990,1979,0,\"impl-Display-for-ConfigError\"]Cl[4739,13,4740,1842,3990,1331,0,\"impl-Debug-for-ConfigError\"]Cj[4739,13,4740,1516,3129,1331,0,\"impl-Debug-for-FrameType\"]Cl[4739,13,4740,1516,3129,1979,0,\"impl-Display-for-FrameType\"]Co[4739,13,4740,1516,4387,1331,0,\"impl-Debug-for-InvalidFrameId\"]Da[4739,13,4740,1516,4387,1979,0,\"impl-Display-for-InvalidFrameId\"]Cm[4739,13,4740,1516,3323,1979,0,\"impl-Display-for-MaybeFrame\"]Ck[4739,13,4740,1516,3323,1331,0,\"impl-Debug-for-MaybeFrame\"]Cm[4739,13,4740,1516,3345,1979,0,\"impl-Display-for-StreamInfo\"]Ck[4739,13,4740,1516,3345,1331,0,\"impl-Debug-for-StreamInfo\"]Co[4739,13,4740,1516,4137,1979,0,\"impl-Display-for-DatagramInfo\"]Cm[4739,13,4740,1516,4137,1331,0,\"impl-Debug-for-DatagramInfo\"]Db[4739,13,4740,1516,4498,1979,0,\"impl-Display-for-ConnectionClose\"]D`[4739,13,4740,1516,4498,1331,0,\"impl-Debug-for-ConnectionClose\"]Da[4739,13,4740,1516,4686,1331,0,\"impl-Debug-for-ApplicationClose\"]Dc[4739,13,4740,1516,4686,1979,0,\"impl-Display-for-ApplicationClose\"]Ck[4739,13,4740,1516,2393,1979,0,\"impl-Display-for-Datagram\"]Ci[4739,13,4740,1516,2393,1331,0,\"impl-Debug-for-Datagram\"]Ao[4739,13,4740,2445,4690,1331,0]Ao[4739,13,4740,2445,2404,1331,0]Cm[4739,13,4740,2445,4133,1331,0,\"impl-Debug-for-ConnectError\"]Co[4739,13,4740,2445,4133,1979,0,\"impl-Display-for-ConnectError\"]Ao[4739,13,4740,2445,3984,1331,0]Ck[4739,13,4740,2445,3339,1331,0,\"impl-Debug-for-RetryError\"]Cm[4739,13,4740,2445,3339,1979,0,\"impl-Display-for-RetryError\"]Ao[4739,13,4740,1907,4289,1331,0]Ao[4739,13,4740,1907,4512,1331,0]Ao[4739,13,4740,1907,5027,1331,0]Ao[4739,13,4740,1907,2406,1331,0]Db[4739,13,4740,1907,4780,1331,0,\"impl-Debug-for-PacketDecodeError\"]Dd[4739,13,4740,1907,4780,1979,0,\"impl-Display-for-PacketDecodeError\"]Ao[4739,13,4740,1934,4502,1331,0]Ao[4739,13,4740,1934,4266,1331,0]Co[4739,13,4740,1934,4136,1979,0,\"impl-Display-for-ConnectionId\"]Cm[4739,13,4740,1934,4136,1331,0,\"impl-Debug-for-ConnectionId\"]Ao[4739,13,4740,1934,4141,1331,0]Ce[4739,13,4740,0,4410,1979,0,\"impl-Display-for-Error\"]Cc[4739,13,4740,0,4410,1331,0,\"impl-Debug-for-Error\"]Cb[4739,13,4740,0,4840,1331,0,\"impl-Debug-for-Code\"]Cd[4739,13,4740,0,4840,1979,0,\"impl-Display-for-Code\"]Ao[4739,13,4740,4307,3320,1331,0]Ao[4739,13,4740,4307,5120,1331,0]Ao[4739,13,4740,4870,4716,1331,0]An[4739,13,4740,4740,486,1331,0]Ce[4739,13,4740,4740,120,1979,0,\"impl-Display-for-Dir\"]Cc[4739,13,4740,4740,120,1331,0,\"impl-Debug-for-Dir\"]Ck[4739,13,4740,4740,2423,1979,0,\"impl-Display-for-StreamId\"]Ci[4739,13,4740,4740,2423,1331,0,\"impl-Debug-for-StreamId\"]Ao[4739,13,4740,4740,2432,1331,0]Cj[4739,13,4740,4740,3127,1331,0,\"impl-Debug-for-FourTuple\"]Cl[4739,13,4740,4740,3127,1979,0,\"impl-Display-for-FourTuple\"]D`[4739,13,1840,1840,4300,1979,0,\"impl-Display-for-UnexpectedEnd\"]Cn[4739,13,1840,1840,4300,1331,0,\"impl-Debug-for-UnexpectedEnd\"]Ao[4739,13,4982,4982,4881,1331,0]Cf[4739,13,4982,4982,1343,1331,0,\"impl-Debug-for-Error\"]Ch[4739,13,4982,4982,1343,1979,0,\"impl-Display-for-Error\"]Ao[4739,13,1845,1845,5087,1331,0]Ao[4739,13,1845,1845,3993,1331,0]Ao[4739,13,1845,1845,4846,1331,0]Dg[4739,13,1924,1924,4937,1979,0,\"impl-Display-for-NoInitialCipherSuite\"]De[4739,13,1924,1924,4937,1331,0,\"impl-Debug-for-NoInitialCipherSuite\"]Ce[4739,13,1924,0,1342,1979,0,\"impl-Display-for-Error\"]Cc[4739,13,1924,0,1342,1331,0,\"impl-Debug-for-Error\"]Am[4739,13,3708,135,114,1331,0]An[4739,13,3708,135,3117,1331,0]Ao[4739,13,3708,1511,1329,1331,0]Ao[4739,13,3708,1511,3995,1331,0]Ao[4739,13,3708,2493,1993,1331,0]Ao[4739,13,3708,2493,4287,1331,0]Ao[4739,13,3708,3708,4774,1331,0]Ch[4739,13,2123,2123,1344,1979,0,\"impl-Display-for-Error\"]Cf[4739,13,2123,2123,1344,1331,0,\"impl-Debug-for-Error\"]Ao[4739,13,2123,2123,1347,1331,0]An[4445,13,4446,393,4411,1331,0]Ao[4445,13,4446,4446,2420,1331,0]Ao[4445,13,4446,4446,2433,1331,0]Ao[4445,13,4446,4446,4142,1331,0]Al[4739,13,4740,1526,4164,0,0]Ai[3954,14,3955,0,2434,0,0]Al[4739,14,4740,1541,2435,0,0]Al[4739,13,4740,1907,4289,0,0]Al[4739,14,4740,1907,5027,0,0]Ah[4739,14,4511,0,474,0,0]Al[4445,14,4446,4446,2420,0,0]Ai[3954,13,3955,0,4997,0,0]Al[4739,13,4740,1842,4998,0,0]8Al[1365,13,1540,1540,4407,0,0]Al[4023,13,4024,4024,5028,0,0]Ai[3954,13,3955,0,4258,0,0]Al[3954,13,3955,2444,2399,0,0]Ai[3954,13,3955,0,3332,0,0]Ai[3954,13,3955,0,4513,0,0]Ai[3954,13,3955,0,4381,0,0]Ai[3954,13,3955,0,4168,0,0]Ai[3954,13,3955,0,4120,0,0]Ai[3954,13,3955,0,4135,0,0]Ai[3954,13,3955,0,4715,0,0]Ai[3954,13,3955,0,2422,0,0]Ah[3954,13,3707,0,113,0,0]Ai[3954,13,3707,0,1328,0,0]Ai[3954,13,3707,0,1992,0,0]Al[4739,13,4740,4530,4259,0,0]Al[4739,13,4740,1071,3333,0,0]Al[4739,13,4740,2445,2400,0,0]Al[4739,13,4740,1907,5145,0,0]Al[4739,13,4740,4307,5115,0,0]Al[4739,13,4740,1071,4514,0,0]Al[4739,13,4740,1842,4382,0,0]Al[4739,13,4740,1842,4170,0,0]Al[4739,13,4740,1842,4122,0,0]Al[4739,13,4740,1907,4289,0,0]Al[4739,13,4740,1934,4136,0,0]Ai[4739,13,4740,0,4410,0,0]Al[4739,13,4740,4307,5120,0,0]Al[4739,13,4740,4870,4716,0,0]Al[4739,13,4740,4740,2423,0,0]Aj[4739,13,3708,135,114,0,0]Al[4739,13,3708,1511,1329,0,0]Al[4739,13,3708,2493,1993,0,0]Ak[4445,13,4446,393,4411,0,0]Al[1050,13,4227,4227,5072,0,0]Al[1050,13,4227,4227,5073,0,0]Aj[3954,13,3955,0,485,126,0]Am[4739,13,4740,4740,486,126,0]Ai[3954,12,3955,0,3348,0,0]Al[3954,13,3955,2144,2004,0,0]0Ao[3954,13,3955,1552,4175,2004,0]Al[3954,13,3955,0,4298,3348,0]Al[4739,12,4740,1842,3349,0,0]Ao[4739,13,4740,1842,4299,3349,0]Al[3954,13,3955,3712,3310,0,0]Ai[3954,14,3955,0,3145,0,0]Al[4739,13,4740,3713,3311,0,0]Al[4739,14,4740,1541,3146,0,0]Ae[1050,7,1834,0,0,0,0]Ae[1050,7,1929,0,0,0,0]Ae[3954,4,3955,0,0,0,0]Ai[3954,15,3955,0,4140,0,0]Al[4739,15,4740,1934,4141,0,0]Al[4445,15,4446,4446,4142,0,0]210Ah[3954,5,1844,1845,0,0,0]Ae[4739,5,1845,0,0,0,0]Al[4739,15,4740,1907,4512,0,0]Al[4739,15,4740,1516,3323,0,0]Ah[3954,5,3955,1049,0,0,0]Al[4739,15,4740,3713,1346,0,0]Ai[3954,15,3955,0,3128,0,0]Al[4739,15,4740,1516,3129,0,0]Al[3954,15,3955,4090,4405,0,0]Ah[3954,6,3955,4740,0,0,0]Ae[4739,6,4740,0,0,0,0]Ai[3954,19,3955,0,1586,0,0]Al[4739,19,4740,1526,1587,0,0]Ai[3954,14,3955,0,3316,0,0]Al[4739,14,4740,1541,3317,0,0]Ai[4739,14,3142,0,4154,0,0]Al[4445,14,4446,4446,2420,0,0]Aa[495,3,0,0,0,0,0]Ai[4739,14,4740,0,4410,0,0]Ai[3954,14,3955,0,3145,0,0]Al[4739,14,4740,1541,3146,0,0]Al[4739,14,4740,1516,2393,0,0]An[3954,13,3955,3712,2413,462,0]An[3954,13,3955,2471,2403,462,0]An[3954,13,3955,4090,3335,462,0]An[3954,13,3955,4095,3341,462,0]An[4739,13,4740,1075,1566,462,0]Am[1365,13,1366,1366,127,469,0]An[1365,13,1366,1366,3986,469,0]An[1365,13,1540,1540,4017,469,0]An[1365,13,1540,1540,1361,469,0]An[1365,13,1540,1540,4407,469,0]Ak[495,13,496,496,3987,469,0]An[4023,13,4024,4024,5028,469,0]An[3954,13,3955,3712,4525,469,0]An[3954,13,3955,3712,2413,469,0]Ak[3954,13,3955,0,4258,469,0]An[3954,13,3955,1049,2414,469,0]An[3954,13,3955,1049,3119,469,0]An[3954,13,3955,1049,4682,469,0]An[3954,13,3955,3712,3308,469,0]An[3954,13,3955,3712,3310,469,0]An[3954,13,3955,3712,1995,469,0]An[3954,13,3955,3712,1579,469,0]An[3954,13,3955,3712,3109,469,0]An[3954,13,3955,3712,2387,469,0]An[3954,13,3955,3712,4160,469,0]An[3954,13,3955,3712,4165,469,0]An[3954,13,3955,3712,4943,469,0]An[3954,13,3955,3712,4781,469,0]0An[3954,13,3955,2444,2399,469,0]An[3954,13,3955,2444,4267,469,0]An[3954,13,3955,2444,1558,469,0]An[3954,13,3955,2471,2403,469,0]An[3954,13,3955,2471,3338,469,0]An[3954,13,3955,2471,4386,469,0]Am[3954,13,3955,1049,478,469,0]An[3954,13,3955,4090,3335,469,0]An[3954,13,3955,4090,4882,469,0]An[3954,13,3955,4090,4405,469,0]0Dm[3954,13,3955,4090,3148,469,0,\"impl-From%3CConnectionError%3E-for-ReadError\"]An[3954,13,3955,4090,3148,469,0]Dh[3954,13,3955,4090,3148,469,0,\"impl-From%3CResetError%3E-for-ReadError\"]An[3954,13,3955,4090,3337,469,0]0An[3954,13,3955,4090,4404,469,0]0An[3954,13,3955,1552,4175,469,0]An[3954,13,3955,1092,4012,469,0]An[3954,13,3955,4095,3341,469,0]Dn[3954,13,3955,4095,3355,469,0,\"impl-From%3CConnectionError%3E-for-WriteError\"]An[3954,13,3955,4095,3355,469,0]Dk[3954,13,3955,4095,3355,469,0,\"impl-From%3CClosedStream%3E-for-WriteError\"]Dk[3954,13,3955,4095,3355,469,0,\"impl-From%3CStoppedError%3E-for-WriteError\"]An[3954,13,3955,4095,4174,469,0]0Ak[3954,13,3955,0,3332,469,0]Ak[3954,13,3955,0,4298,469,0]Ak[3954,13,3955,0,4517,469,0]Ak[3954,13,3955,0,4152,469,0]Ak[3954,13,3955,0,4395,469,0]Ck[3954,13,3955,0,1603,469,0,\"impl-From%3Cu32%3E-for-VarInt\"]Cj[3954,13,3955,0,1603,469,0,\"impl-From%3Cu8%3E-for-VarInt\"]Ck[3954,13,3955,0,1603,469,0,\"impl-From%3Cu16%3E-for-VarInt\"]D`[3954,13,3955,0,1603,469,0,\"impl-From%3CStreamId%3E-for-VarInt\"]Ak[3954,13,3955,0,1603,469,0]Dj[3954,13,3955,0,1603,469,0,\"impl-From%3CTransportErrorCode%3E-for-VarInt\"]Ak[3954,13,3955,0,4940,469,0]Ak[3954,13,3955,0,1324,469,0]Ak[3954,13,3955,0,1586,469,0]0Ak[3954,13,3955,0,2434,469,0]Ak[3954,13,3955,0,3316,469,0]Ak[3954,13,3955,0,3145,469,0]Ak[3954,13,3955,0,4503,469,0]Ak[3954,13,3955,0,2018,469,0]Ak[3954,13,3955,0,4126,469,0]Ak[3954,13,3955,0,4499,469,0]Dl[3954,13,3955,0,4499,469,0,\"impl-From%3CCloseReason%3E-for-ConnectionError\"]Do[3954,13,3955,0,4499,469,0,\"impl-From%3CTransportError%3E-for-ConnectionError\"]Df[3954,13,3955,0,4499,469,0,\"impl-From%3CClose%3E-for-ConnectionError\"]Ak[3954,13,3955,0,4513,469,0]Ak[3954,13,3955,0,4520,469,0]Ak[3954,13,3955,0,4805,469,0]Ak[3954,13,3955,0,4820,469,0]Ak[3954,13,3955,0,3999,469,0]0Ak[3954,13,3955,0,4381,469,0]Ak[3954,13,3955,0,4168,469,0]Ak[3954,13,3955,0,4997,469,0]Ak[3954,13,3955,0,4120,469,0]Ea[3954,13,3955,0,3989,469,0,\"impl-From%3CVarIntBoundsExceeded%3E-for-ConfigError\"]Dl[3954,13,3955,0,3989,469,0,\"impl-From%3CTryFromIntError%3E-for-ConfigError\"]Ak[3954,13,3955,0,3989,469,0]Ak[3954,13,3955,0,3128,469,0]Ak[3954,13,3955,0,4496,469,0]0Ak[3954,13,3955,0,4684,469,0]Ak[3954,13,3955,0,4132,469,0]0Ak[3954,13,3955,0,4135,469,0]Ak[3954,13,3955,0,4140,469,0]Ak[3954,13,3955,0,4839,469,0]0Ak[3954,13,3955,0,3319,469,0]Ak[3954,13,3955,0,4715,469,0]Aj[3954,13,3955,0,485,469,0]Aj[3954,13,3955,0,119,469,0]Ak[3954,13,3955,0,2422,469,0]0Ak[3954,13,3955,0,2431,469,0]Aj[3954,13,3707,0,113,469,0]Ak[3954,13,3707,0,3116,469,0]Ak[3954,13,3707,0,1328,469,0]Ak[3954,13,3707,0,3994,469,0]Ak[3954,13,3707,0,1992,469,0]Ak[3954,13,3707,0,4286,469,0]Ak[3954,13,3707,0,4773,469,0]Ak[3954,13,1844,0,1987,469,0]Aj[3954,13,1844,0,472,469,0]Ak[3954,13,1844,0,5086,469,0]Ak[3954,13,1844,0,3992,469,0]0Ak[3954,13,1844,0,4843,469,0]Ak[3954,13,1923,0,3350,469,0]Ak[3954,13,1923,0,4269,469,0]Ak[3954,13,1923,0,4711,469,0]Ak[3954,13,1923,0,4713,469,0]Ak[3954,13,1923,0,4936,469,0]Dg[3954,13,1923,0,1341,469,0,\"impl-From%3CInconsistentKeys%3E-for-Error\"]E`[3954,13,1923,0,1341,469,0,\"impl-From%3CUnsupportedOperationError%3E-for-Error\"]Da[3954,13,1923,0,1341,469,0,\"impl-From%3COtherError%3E-for-Error\"]Df[3954,13,1923,0,1341,469,0,\"impl-From%3CGetRandomFailed%3E-for-Error\"]Ak[3954,13,1923,0,1341,469,0]Df[3954,13,1923,0,1341,469,0,\"impl-From%3CSystemTimeError%3E-for-Error\"]E`[3954,13,1923,0,1341,469,0,\"impl-From%3CEncryptedClientHelloError%3E-for-Error\"]Dn[3954,13,1923,0,1341,469,0,\"impl-From%3CCertRevocationListError%3E-for-Error\"]Dg[3954,13,1923,0,1341,469,0,\"impl-From%3CCertificateError%3E-for-Error\"]Dg[3954,13,1923,0,1341,469,0,\"impl-From%3CPeerIncompatible%3E-for-Error\"]De[3954,13,1923,0,1341,469,0,\"impl-From%3CInvalidMessage%3E-for-Error\"]De[3954,13,1923,0,1341,469,0,\"impl-From%3CPeerMisbehaved%3E-for-Error\"]An[4739,13,4740,4530,4259,469,0]An[4739,13,4740,3173,3123,469,0]An[4739,13,4740,1075,1566,469,0]An[4739,13,4740,2152,2012,469,0]An[4739,13,4740,2152,3336,469,0]An[4739,13,4740,2152,3342,469,0]An[4739,13,4740,3713,3311,469,0]An[4739,13,4740,1071,3333,469,0]An[4739,13,4740,1842,4299,469,0]An[4739,13,4740,2445,2400,469,0]An[4739,13,4740,2445,4265,469,0]An[4739,13,4740,1907,5145,469,0]An[4739,13,4740,4307,5115,469,0]An[4739,13,4740,1551,4518,469,0]An[4739,13,4740,1551,4153,469,0]An[4739,13,4740,1551,4396,469,0]Cm[4739,13,4740,1960,1604,469,0,\"impl-From%3Cu8%3E-for-VarInt\"]Cn[4739,13,4740,1960,1604,469,0,\"impl-From%3Cu16%3E-for-VarInt\"]Cn[4739,13,4740,1960,1604,469,0,\"impl-From%3Cu32%3E-for-VarInt\"]Dc[4739,13,4740,1960,1604,469,0,\"impl-From%3CStreamId%3E-for-VarInt\"]Co[4739,13,4740,1960,1604,469,0,\"impl-From%3CCode%3E-for-VarInt\"]An[4739,13,4740,1960,1604,469,0]An[4739,13,4740,1960,4941,469,0]An[4739,13,4740,3164,1325,469,0]An[4739,13,4740,3173,4782,469,0]An[4739,13,4740,1526,1587,469,0]0An[4739,13,4740,1526,4164,469,0]An[4739,13,4740,1526,3331,469,0]An[4739,13,4740,1526,3144,469,0]An[4739,13,4740,1526,4836,469,0]An[4739,13,4740,1526,3306,469,0]An[4739,13,4740,1541,2435,469,0]An[4739,13,4740,1541,3317,469,0]An[4739,13,4740,1541,3146,469,0]An[4739,13,4740,1541,4504,469,0]An[4739,13,4740,1075,3149,469,0]An[4739,13,4740,1075,4294,469,0]An[4739,13,4740,1080,2019,469,0]An[4739,13,4740,1080,3356,469,0]An[4739,13,4740,1080,3998,469,0]An[4739,13,4740,2152,4016,469,0]An[4739,13,4740,2152,4406,469,0]An[4739,13,4740,2152,4130,469,0]An[4739,13,4740,3713,4500,469,0]0An[4739,13,4740,3713,3141,469,0]An[4739,13,4740,3713,4372,469,0]An[4739,13,4740,3713,5024,469,0]An[4739,13,4740,3713,1346,469,0]0An[4739,13,4740,1071,4514,469,0]An[4739,13,4740,3293,4521,469,0]An[4739,13,4740,3293,4806,469,0]An[4739,13,4740,3293,4821,469,0]An[4739,13,4740,3293,4000,469,0]0An[4739,13,4740,1842,4382,469,0]An[4739,13,4740,1842,4170,469,0]An[4739,13,4740,1842,4998,469,0]An[4739,13,4740,1842,4122,469,0]Ed[4739,13,4740,1842,3990,469,0,\"impl-From%3CVarIntBoundsExceeded%3E-for-ConfigError\"]An[4739,13,4740,1842,3990,469,0]Do[4739,13,4740,1842,3990,469,0,\"impl-From%3CTryFromIntError%3E-for-ConfigError\"]An[4739,13,4740,1516,3129,469,0]An[4739,13,4740,1516,4387,469,0]An[4739,13,4740,1516,3323,469,0]An[4739,13,4740,1516,3345,469,0]An[4739,13,4740,1516,4137,469,0]An[4739,13,4740,1516,4498,469,0]0An[4739,13,4740,1516,4686,469,0]An[4739,13,4740,1516,2393,469,0]An[4739,13,4740,2445,4690,469,0]An[4739,13,4740,2445,2404,469,0]An[4739,13,4740,2445,4133,469,0]0An[4739,13,4740,2445,3984,469,0]An[4739,13,4740,2445,3339,469,0]An[4739,13,4740,1907,4289,469,0]An[4739,13,4740,1907,4512,469,0]An[4739,13,4740,1907,5027,469,0]An[4739,13,4740,1907,2406,469,0]An[4739,13,4740,1907,4780,469,0]0An[4739,13,4740,1934,4502,469,0]An[4739,13,4740,1934,4266,469,0]An[4739,13,4740,1934,4136,469,0]An[4739,13,4740,1934,4141,469,0]Ak[4739,13,4740,0,4410,469,0]0Ak[4739,13,4740,0,4840,469,0]0An[4739,13,4740,4307,3320,469,0]An[4739,13,4740,4307,5120,469,0]An[4739,13,4740,4870,4716,469,0]Am[4739,13,4740,4740,486,469,0]Am[4739,13,4740,4740,120,469,0]An[4739,13,4740,4740,2423,469,0]0An[4739,13,4740,4740,2432,469,0]An[4739,13,4740,4740,3127,469,0]An[4739,13,1840,1840,4300,469,0]An[4739,13,4982,4982,4881,469,0]An[4739,13,4982,4982,1343,469,0]0An[4739,13,1845,1845,1988,469,0]Am[4739,13,1845,1845,473,469,0]An[4739,13,1845,1845,5087,469,0]An[4739,13,1845,1845,3993,469,0]0An[4739,13,1845,1845,4846,469,0]An[4739,13,1924,1924,3351,469,0]An[4739,13,1924,1924,4270,469,0]An[4739,13,1924,1924,4712,469,0]An[4739,13,1924,1924,4714,469,0]An[4739,13,1924,1924,4937,469,0]Ak[4739,13,1924,0,1342,469,0]De[4739,13,1924,0,1342,469,0,\"impl-From%3CPeerMisbehaved%3E-for-Error\"]Df[4739,13,1924,0,1342,469,0,\"impl-From%3CSystemTimeError%3E-for-Error\"]Dn[4739,13,1924,0,1342,469,0,\"impl-From%3CCertRevocationListError%3E-for-Error\"]Df[4739,13,1924,0,1342,469,0,\"impl-From%3CGetRandomFailed%3E-for-Error\"]Dg[4739,13,1924,0,1342,469,0,\"impl-From%3CCertificateError%3E-for-Error\"]Da[4739,13,1924,0,1342,469,0,\"impl-From%3COtherError%3E-for-Error\"]E`[4739,13,1924,0,1342,469,0,\"impl-From%3CUnsupportedOperationError%3E-for-Error\"]Dg[4739,13,1924,0,1342,469,0,\"impl-From%3CInconsistentKeys%3E-for-Error\"]Dg[4739,13,1924,0,1342,469,0,\"impl-From%3CPeerIncompatible%3E-for-Error\"]De[4739,13,1924,0,1342,469,0,\"impl-From%3CInvalidMessage%3E-for-Error\"]E`[4739,13,1924,0,1342,469,0,\"impl-From%3CEncryptedClientHelloError%3E-for-Error\"]Al[4739,13,3708,135,114,469,0]Am[4739,13,3708,135,3117,469,0]An[4739,13,3708,1511,1329,469,0]An[4739,13,3708,1511,3995,469,0]An[4739,13,3708,2493,1993,469,0]An[4739,13,3708,2493,4287,469,0]An[4739,13,3708,3708,4774,469,0]An[4739,13,2123,2123,1344,469,0]An[4739,13,2123,2123,1347,469,0]An[4445,13,4446,4446,3354,469,0]0Am[4445,13,4446,393,4411,469,0]An[4445,13,4446,4446,2420,469,0]An[4445,13,4446,4446,2433,469,0]An[4445,13,4446,4446,4142,469,0]An[1050,13,1051,1051,3120,469,0]An[1050,13,1051,1051,4874,469,0]Am[1050,13,1834,1834,128,469,0]An[1050,13,1542,1542,1362,469,0]An[1050,13,1542,1542,4018,469,0]An[1050,13,1542,1542,4508,469,0]An[1050,13,4227,4227,5072,469,0]An[1050,13,4227,4227,5073,469,0]Am[1050,13,1929,1929,129,469,0]Am[3974,13,3975,3975,118,469,0]An[3974,13,3975,3975,2390,469,0]Ak[3954,13,3955,0,1603,470,0]Ak[3954,13,3955,0,1586,470,0]Ak[3954,13,3955,0,3999,470,0]Ak[3954,13,3955,0,4135,470,0]Aj[3954,13,3955,0,485,470,0]Aj[3954,13,3955,0,119,470,0]Ak[3954,13,3955,0,2422,470,0]An[4739,13,4740,1960,1604,470,0]An[4739,13,4740,3173,4782,470,0]An[4739,13,4740,1526,1587,470,0]An[4739,13,4740,1075,3149,470,0]An[4739,13,4740,1075,4294,470,0]An[4739,13,4740,1080,3356,470,0]An[4739,13,4740,3293,4000,470,0]An[4739,13,4740,2445,4690,470,0]An[4739,13,4740,1907,4780,470,0]An[4739,13,4740,1934,4136,470,0]Am[4739,13,4740,4740,486,470,0]Am[4739,13,4740,4740,120,470,0]An[4739,13,4740,4740,2423,470,0]An[4739,13,4740,4740,3127,470,0]Am[1365,13,1366,1366,127,471,0]An[1365,13,1366,1366,3986,471,0]An[1365,13,1540,1540,4017,471,0]An[1365,13,1540,1540,1361,471,0]An[1365,13,1540,1540,4407,471,0]Ak[495,13,496,496,3987,471,0]An[4023,13,4024,4024,5028,471,0]An[3954,13,3955,3712,4525,471,0]An[3954,13,3955,3712,2413,471,0]Ak[3954,13,3955,0,4258,471,0]An[3954,13,3955,1049,2414,471,0]An[3954,13,3955,1049,3119,471,0]An[3954,13,3955,1049,4682,471,0]An[3954,13,3955,3712,3308,471,0]An[3954,13,3955,3712,3310,471,0]An[3954,13,3955,3712,1995,471,0]An[3954,13,3955,3712,1579,471,0]An[3954,13,3955,3712,3109,471,0]An[3954,13,3955,3712,2387,471,0]An[3954,13,3955,3712,4160,471,0]An[3954,13,3955,3712,4165,471,0]An[3954,13,3955,3712,4943,471,0]An[3954,13,3955,3712,4781,471,0]An[3954,13,3955,2444,2399,471,0]An[3954,13,3955,2444,4267,471,0]An[3954,13,3955,2444,1558,471,0]An[3954,13,3955,2471,2403,471,0]An[3954,13,3955,2471,3338,471,0]An[3954,13,3955,2471,4386,471,0]Am[3954,13,3955,1049,478,471,0]An[3954,13,3955,4090,3335,471,0]An[3954,13,3955,4090,4882,471,0]An[3954,13,3955,4090,4405,471,0]An[3954,13,3955,4090,3148,471,0]An[3954,13,3955,4090,3337,471,0]An[3954,13,3955,4090,4404,471,0]An[3954,13,3955,1552,4175,471,0]An[3954,13,3955,1092,4012,471,0]An[3954,13,3955,4095,3341,471,0]An[3954,13,3955,4095,3355,471,0]An[3954,13,3955,4095,4174,471,0]Ak[3954,13,3955,0,3332,471,0]Ak[3954,13,3955,0,4298,471,0]Ak[3954,13,3955,0,4517,471,0]Ak[3954,13,3955,0,4152,471,0]Ak[3954,13,3955,0,4395,471,0]Ak[3954,13,3955,0,1603,471,0]Ak[3954,13,3955,0,4940,471,0]Ak[3954,13,3955,0,1324,471,0]Ak[3954,13,3955,0,1586,471,0]Ak[3954,13,3955,0,2434,471,0]Ak[3954,13,3955,0,3316,471,0]Ak[3954,13,3955,0,3145,471,0]Ak[3954,13,3955,0,4503,471,0]Ak[3954,13,3955,0,2018,471,0]Ak[3954,13,3955,0,4126,471,0]Ak[3954,13,3955,0,4499,471,0]Ak[3954,13,3955,0,4513,471,0]Ak[3954,13,3955,0,4520,471,0]Ak[3954,13,3955,0,4805,471,0]Ak[3954,13,3955,0,4820,471,0]Ak[3954,13,3955,0,3999,471,0]Ak[3954,13,3955,0,4381,471,0]Ak[3954,13,3955,0,4168,471,0]Ak[3954,13,3955,0,4997,471,0]Ak[3954,13,3955,0,4120,471,0]Ak[3954,13,3955,0,3989,471,0]Ak[3954,13,3955,0,3128,471,0]Ak[3954,13,3955,0,4496,471,0]Ak[3954,13,3955,0,4684,471,0]Ak[3954,13,3955,0,4132,471,0]Ak[3954,13,3955,0,4135,471,0]Ak[3954,13,3955,0,4140,471,0]Ak[3954,13,3955,0,4839,471,0]Ak[3954,13,3955,0,3319,471,0]Ak[3954,13,3955,0,4715,471,0]Aj[3954,13,3955,0,485,471,0]Aj[3954,13,3955,0,119,471,0]Ak[3954,13,3955,0,2422,471,0]Ak[3954,13,3955,0,2431,471,0]Aj[3954,13,3707,0,113,471,0]Ak[3954,13,3707,0,3116,471,0]Ak[3954,13,3707,0,1328,471,0]Ak[3954,13,3707,0,3994,471,0]Ak[3954,13,3707,0,1992,471,0]Ak[3954,13,3707,0,4286,471,0]Ak[3954,13,3707,0,4773,471,0]Ak[3954,13,1844,0,1987,471,0]Aj[3954,13,1844,0,472,471,0]Ak[3954,13,1844,0,5086,471,0]Ak[3954,13,1844,0,3992,471,0]Ak[3954,13,1844,0,4843,471,0]Ak[3954,13,1923,0,3350,471,0]Ak[3954,13,1923,0,4269,471,0]Ak[3954,13,1923,0,4711,471,0]Ak[3954,13,1923,0,4713,471,0]Ak[3954,13,1923,0,4936,471,0]Ak[3954,13,1923,0,1341,471,0]An[4739,13,4740,4530,4259,471,0]An[4739,13,4740,3173,3123,471,0]An[4739,13,4740,1075,1566,471,0]An[4739,13,4740,2152,2012,471,0]An[4739,13,4740,2152,3336,471,0]An[4739,13,4740,2152,3342,471,0]An[4739,13,4740,3713,3311,471,0]An[4739,13,4740,1071,3333,471,0]An[4739,13,4740,1842,4299,471,0]An[4739,13,4740,2445,2400,471,0]An[4739,13,4740,2445,4265,471,0]An[4739,13,4740,1907,5145,471,0]An[4739,13,4740,4307,5115,471,0]An[4739,13,4740,1551,4518,471,0]An[4739,13,4740,1551,4153,471,0]An[4739,13,4740,1551,4396,471,0]An[4739,13,4740,1960,1604,471,0]An[4739,13,4740,1960,4941,471,0]An[4739,13,4740,3164,1325,471,0]An[4739,13,4740,3173,4782,471,0]An[4739,13,4740,1526,1587,471,0]An[4739,13,4740,1526,4164,471,0]An[4739,13,4740,1526,3331,471,0]An[4739,13,4740,1526,3144,471,0]An[4739,13,4740,1526,4836,471,0]An[4739,13,4740,1526,3306,471,0]An[4739,13,4740,1541,2435,471,0]An[4739,13,4740,1541,3317,471,0]An[4739,13,4740,1541,3146,471,0]An[4739,13,4740,1541,4504,471,0]An[4739,13,4740,1075,3149,471,0]An[4739,13,4740,1075,4294,471,0]An[4739,13,4740,1080,2019,471,0]An[4739,13,4740,1080,3356,471,0]An[4739,13,4740,1080,3998,471,0]An[4739,13,4740,2152,4016,471,0]An[4739,13,4740,2152,4406,471,0]An[4739,13,4740,2152,4130,471,0]An[4739,13,4740,3713,4500,471,0]An[4739,13,4740,3713,3141,471,0]An[4739,13,4740,3713,4372,471,0]An[4739,13,4740,3713,5024,471,0]An[4739,13,4740,3713,1346,471,0]An[4739,13,4740,1071,4514,471,0]An[4739,13,4740,3293,4521,471,0]An[4739,13,4740,3293,4806,471,0]An[4739,13,4740,3293,4821,471,0]An[4739,13,4740,3293,4000,471,0]An[4739,13,4740,1842,4382,471,0]An[4739,13,4740,1842,4170,471,0]An[4739,13,4740,1842,4998,471,0]An[4739,13,4740,1842,4122,471,0]An[4739,13,4740,1842,3990,471,0]An[4739,13,4740,1516,3129,471,0]An[4739,13,4740,1516,4387,471,0]An[4739,13,4740,1516,3323,471,0]An[4739,13,4740,1516,3345,471,0]An[4739,13,4740,1516,4137,471,0]An[4739,13,4740,1516,4498,471,0]An[4739,13,4740,1516,4686,471,0]An[4739,13,4740,1516,2393,471,0]An[4739,13,4740,2445,4690,471,0]An[4739,13,4740,2445,2404,471,0]An[4739,13,4740,2445,4133,471,0]An[4739,13,4740,2445,3984,471,0]An[4739,13,4740,2445,3339,471,0]An[4739,13,4740,1907,4289,471,0]An[4739,13,4740,1907,4512,471,0]An[4739,13,4740,1907,5027,471,0]An[4739,13,4740,1907,2406,471,0]An[4739,13,4740,1907,4780,471,0]An[4739,13,4740,1934,4502,471,0]An[4739,13,4740,1934,4266,471,0]An[4739,13,4740,1934,4136,471,0]An[4739,13,4740,1934,4141,471,0]Ak[4739,13,4740,0,4410,471,0]Ak[4739,13,4740,0,4840,471,0]An[4739,13,4740,4307,3320,471,0]An[4739,13,4740,4307,5120,471,0]An[4739,13,4740,4870,4716,471,0]Am[4739,13,4740,4740,486,471,0]Am[4739,13,4740,4740,120,471,0]An[4739,13,4740,4740,2423,471,0]An[4739,13,4740,4740,2432,471,0]An[4739,13,4740,4740,3127,471,0]An[4739,13,1840,1840,4300,471,0]An[4739,13,4982,4982,4881,471,0]An[4739,13,4982,4982,1343,471,0]An[4739,13,1845,1845,1988,471,0]Am[4739,13,1845,1845,473,471,0]An[4739,13,1845,1845,5087,471,0]An[4739,13,1845,1845,3993,471,0]An[4739,13,1845,1845,4846,471,0]An[4739,13,1924,1924,3351,471,0]An[4739,13,1924,1924,4270,471,0]An[4739,13,1924,1924,4712,471,0]An[4739,13,1924,1924,4714,471,0]An[4739,13,1924,1924,4937,471,0]Ak[4739,13,1924,0,1342,471,0]Al[4739,13,3708,135,114,471,0]Am[4739,13,3708,135,3117,471,0]An[4739,13,3708,1511,1329,471,0]An[4739,13,3708,1511,3995,471,0]An[4739,13,3708,2493,1993,471,0]An[4739,13,3708,2493,4287,471,0]An[4739,13,3708,3708,4774,471,0]An[4739,13,2123,2123,1344,471,0]An[4739,13,2123,2123,1347,471,0]An[4445,13,4446,4446,3354,471,0]Am[4445,13,4446,393,4411,471,0]An[4445,13,4446,4446,2420,471,0]An[4445,13,4446,4446,2433,471,0]An[4445,13,4446,4446,4142,471,0]An[1050,13,1051,1051,3120,471,0]An[1050,13,1051,1051,4874,471,0]Am[1050,13,1834,1834,128,471,0]An[1050,13,1542,1542,1362,471,0]An[1050,13,1542,1542,4018,471,0]An[1050,13,1542,1542,4508,471,0]An[1050,13,4227,4227,5072,471,0]An[1050,13,4227,4227,5073,471,0]Am[1050,13,1929,1929,129,471,0]Am[3974,13,3975,3975,118,471,0]An[3974,13,3975,3975,2390,471,0]Ac[495,7,496,0,0,0,0]Ae[4023,7,4024,0,0,0,0]Ae[4310,7,4311,0,0,0,0]Ae[3974,7,3975,0,0,0,0]Ae[4800,7,4801,0,0,0,0]Al[4739,13,4740,1075,1566,0,0]Ai[3954,12,1844,0,1971,0,0]Al[4739,13,4740,2152,2012,0,0]Al[4739,12,1845,1845,1972,0,0]Al[3954,13,3955,3712,3310,0,0]Ab[1050,3,0,0,0,0,0]Ak[3954,13,3955,1049,478,0,0]Ai[3954,14,3955,0,3316,0,0]Al[4739,13,4740,3713,3311,0,0]Al[4739,14,4740,1541,3317,0,0]Al[3954,12,3955,2144,3299,0,0]Ao[3954,13,3955,3712,4525,1576,0]Ao[3954,13,3955,3712,2413,1576,0]Ao[3954,13,3955,1049,2414,1576,0]Ao[3954,13,3955,1049,3119,1576,0]Ao[3954,13,3955,3712,3308,1576,0]Ao[3954,13,3955,3712,1995,1576,0]Ao[3954,13,3955,3712,1579,1576,0]Ao[3954,13,3955,3712,3109,1576,0]Ao[3954,13,3955,3712,2387,1576,0]Ao[3954,13,3955,3712,4160,1576,0]Ao[3954,13,3955,3712,4165,1576,0]Ao[3954,13,3955,2444,1558,1576,0]Ao[3954,13,3955,2471,4386,1576,0]?Al[3954,13,3955,4090,3335,0,0]Al[4739,13,4740,2152,3336,0,0]Al[4739,13,4982,4982,4881,0,0]Al[4739,13,4740,3173,3123,0,0]Ak[4445,13,4446,393,4411,0,0]Ai[3954,12,1844,0,1971,0,0]Al[4739,12,1845,1845,1972,0,0]32Ai[3954,13,3955,0,4997,0,0]Al[4739,13,4740,1842,4998,0,0]Al[3954,13,3955,3712,3310,0,0]Al[4739,13,4740,3713,3311,0,0]Ai[3954,12,1844,0,1983,0,0]Al[4739,12,1845,1845,1984,0,0]Al[1365,14,1540,1540,4407,0,0]Ai[3954,14,3955,0,2431,0,0]Al[4739,14,4740,4740,2432,0,0]Ai[4739,14,4511,0,1358,0,0]Al[3954,13,3955,4090,3335,0,0]Al[3954,13,3955,4090,4882,0,0]Al[4739,13,4740,2152,3336,0,0]Ai[3954,12,3955,0,3352,0,0]Al[3954,13,3955,0,4395,3352,0]Al[3954,13,3955,0,4715,3352,0]Al[4739,12,4740,1551,3353,0,0]Ao[4739,13,4740,1551,4396,3353,0]Ao[4739,13,4740,4870,4716,3353,0]Am[1365,13,1366,1366,127,488,0]An[1365,13,1366,1366,3986,488,0]An[1365,13,1540,1540,4017,488,0]An[1365,13,1540,1540,1361,488,0]An[1365,13,1540,1540,4407,488,0]Ak[495,13,496,496,3987,488,0]An[4023,13,4024,4024,5028,488,0]An[3954,13,3955,3712,4525,488,0]An[3954,13,3955,3712,2413,488,0]Ak[3954,13,3955,0,4258,488,0]An[3954,13,3955,1049,2414,488,0]An[3954,13,3955,1049,3119,488,0]An[3954,13,3955,1049,4682,488,0]An[3954,13,3955,3712,3308,488,0]An[3954,13,3955,3712,3310,488,0]An[3954,13,3955,3712,1995,488,0]An[3954,13,3955,3712,1579,488,0]An[3954,13,3955,3712,3109,488,0]An[3954,13,3955,3712,2387,488,0]An[3954,13,3955,3712,4160,488,0]An[3954,13,3955,3712,4165,488,0]An[3954,13,3955,3712,4943,488,0]An[3954,13,3955,3712,4781,488,0]An[3954,13,3955,2444,2399,488,0]An[3954,13,3955,2444,4267,488,0]An[3954,13,3955,2444,1558,488,0]An[3954,13,3955,2471,2403,488,0]An[3954,13,3955,2471,3338,488,0]An[3954,13,3955,2471,4386,488,0]Am[3954,13,3955,1049,478,488,0]An[3954,13,3955,4090,3335,488,0]An[3954,13,3955,4090,4882,488,0]An[3954,13,3955,4090,4405,488,0]An[3954,13,3955,4090,3148,488,0]An[3954,13,3955,4090,3337,488,0]An[3954,13,3955,4090,4404,488,0]An[3954,13,3955,1552,4175,488,0]An[3954,13,3955,1092,4012,488,0]An[3954,13,3955,4095,3341,488,0]An[3954,13,3955,4095,3355,488,0]An[3954,13,3955,4095,4174,488,0]Ak[3954,13,3955,0,3332,488,0]Ak[3954,13,3955,0,4298,488,0]Ak[3954,13,3955,0,4517,488,0]Ak[3954,13,3955,0,4152,488,0]Ak[3954,13,3955,0,4395,488,0]Ak[3954,13,3955,0,1603,488,0]Ak[3954,13,3955,0,4940,488,0]Ak[3954,13,3955,0,1324,488,0]Ak[3954,13,3955,0,1586,488,0]Ak[3954,13,3955,0,2434,488,0]Ak[3954,13,3955,0,3316,488,0]Ak[3954,13,3955,0,3145,488,0]Ak[3954,13,3955,0,4503,488,0]Ak[3954,13,3955,0,2018,488,0]Ak[3954,13,3955,0,4126,488,0]Ak[3954,13,3955,0,4499,488,0]Ak[3954,13,3955,0,4513,488,0]Ak[3954,13,3955,0,4520,488,0]Ak[3954,13,3955,0,4805,488,0]Ak[3954,13,3955,0,4820,488,0]Ak[3954,13,3955,0,3999,488,0]Ak[3954,13,3955,0,4381,488,0]Ak[3954,13,3955,0,4168,488,0]Ak[3954,13,3955,0,4997,488,0]Ak[3954,13,3955,0,4120,488,0]Ak[3954,13,3955,0,3989,488,0]Ak[3954,13,3955,0,3128,488,0]Ak[3954,13,3955,0,4496,488,0]Ak[3954,13,3955,0,4684,488,0]Ak[3954,13,3955,0,4132,488,0]Ak[3954,13,3955,0,4135,488,0]Ak[3954,13,3955,0,4140,488,0]Ak[3954,13,3955,0,4839,488,0]Ak[3954,13,3955,0,3319,488,0]Ak[3954,13,3955,0,4715,488,0]Aj[3954,13,3955,0,485,488,0]Aj[3954,13,3955,0,119,488,0]Ak[3954,13,3955,0,2422,488,0]Ak[3954,13,3955,0,2431,488,0]Aj[3954,13,3707,0,113,488,0]Ak[3954,13,3707,0,3116,488,0]Ak[3954,13,3707,0,1328,488,0]Ak[3954,13,3707,0,3994,488,0]Ak[3954,13,3707,0,1992,488,0]Ak[3954,13,3707,0,4286,488,0]Ak[3954,13,3707,0,4773,488,0]Ak[3954,13,1844,0,1987,488,0]Aj[3954,13,1844,0,472,488,0]Ak[3954,13,1844,0,5086,488,0]Ak[3954,13,1844,0,3992,488,0]Ak[3954,13,1844,0,4843,488,0]Ak[3954,13,1923,0,3350,488,0]Ak[3954,13,1923,0,4269,488,0]Ak[3954,13,1923,0,4711,488,0]Ak[3954,13,1923,0,4713,488,0]Ak[3954,13,1923,0,4936,488,0]Ak[3954,13,1923,0,1341,488,0]An[4739,13,4740,4530,4259,488,0]An[4739,13,4740,3173,3123,488,0]An[4739,13,4740,1075,1566,488,0]An[4739,13,4740,2152,2012,488,0]An[4739,13,4740,2152,3336,488,0]An[4739,13,4740,2152,3342,488,0]An[4739,13,4740,3713,3311,488,0]An[4739,13,4740,1071,3333,488,0]An[4739,13,4740,1842,4299,488,0]An[4739,13,4740,2445,2400,488,0]An[4739,13,4740,2445,4265,488,0]An[4739,13,4740,1907,5145,488,0]An[4739,13,4740,4307,5115,488,0]An[4739,13,4740,1551,4518,488,0]An[4739,13,4740,1551,4153,488,0]An[4739,13,4740,1551,4396,488,0]An[4739,13,4740,1960,1604,488,0]An[4739,13,4740,1960,4941,488,0]An[4739,13,4740,3164,1325,488,0]An[4739,13,4740,3173,4782,488,0]An[4739,13,4740,1526,1587,488,0]An[4739,13,4740,1526,4164,488,0]An[4739,13,4740,1526,3331,488,0]An[4739,13,4740,1526,3144,488,0]An[4739,13,4740,1526,4836,488,0]An[4739,13,4740,1526,3306,488,0]An[4739,13,4740,1541,2435,488,0]An[4739,13,4740,1541,3317,488,0]An[4739,13,4740,1541,3146,488,0]An[4739,13,4740,1541,4504,488,0]An[4739,13,4740,1075,3149,488,0]An[4739,13,4740,1075,4294,488,0]An[4739,13,4740,1080,2019,488,0]An[4739,13,4740,1080,3356,488,0]An[4739,13,4740,1080,3998,488,0]An[4739,13,4740,2152,4016,488,0]An[4739,13,4740,2152,4406,488,0]An[4739,13,4740,2152,4130,488,0]An[4739,13,4740,3713,4500,488,0]An[4739,13,4740,3713,3141,488,0]An[4739,13,4740,3713,4372,488,0]An[4739,13,4740,3713,5024,488,0]An[4739,13,4740,3713,1346,488,0]An[4739,13,4740,1071,4514,488,0]An[4739,13,4740,3293,4521,488,0]An[4739,13,4740,3293,4806,488,0]An[4739,13,4740,3293,4821,488,0]An[4739,13,4740,3293,4000,488,0]An[4739,13,4740,1842,4382,488,0]An[4739,13,4740,1842,4170,488,0]An[4739,13,4740,1842,4998,488,0]An[4739,13,4740,1842,4122,488,0]An[4739,13,4740,1842,3990,488,0]An[4739,13,4740,1516,3129,488,0]An[4739,13,4740,1516,4387,488,0]An[4739,13,4740,1516,3323,488,0]An[4739,13,4740,1516,3345,488,0]An[4739,13,4740,1516,4137,488,0]An[4739,13,4740,1516,4498,488,0]An[4739,13,4740,1516,4686,488,0]An[4739,13,4740,1516,2393,488,0]An[4739,13,4740,2445,4690,488,0]An[4739,13,4740,2445,2404,488,0]An[4739,13,4740,2445,4133,488,0]An[4739,13,4740,2445,3984,488,0]An[4739,13,4740,2445,3339,488,0]An[4739,13,4740,1907,4289,488,0]An[4739,13,4740,1907,4512,488,0]An[4739,13,4740,1907,5027,488,0]An[4739,13,4740,1907,2406,488,0]An[4739,13,4740,1907,4780,488,0]An[4739,13,4740,1934,4502,488,0]An[4739,13,4740,1934,4266,488,0]An[4739,13,4740,1934,4136,488,0]An[4739,13,4740,1934,4141,488,0]Ak[4739,13,4740,0,4410,488,0]Ak[4739,13,4740,0,4840,488,0]An[4739,13,4740,4307,3320,488,0]An[4739,13,4740,4307,5120,488,0]An[4739,13,4740,4870,4716,488,0]Am[4739,13,4740,4740,486,488,0]Am[4739,13,4740,4740,120,488,0]An[4739,13,4740,4740,2423,488,0]An[4739,13,4740,4740,2432,488,0]An[4739,13,4740,4740,3127,488,0]An[4739,13,1840,1840,4300,488,0]An[4739,13,4982,4982,4881,488,0]An[4739,13,4982,4982,1343,488,0]An[4739,13,1845,1845,1988,488,0]Am[4739,13,1845,1845,473,488,0]An[4739,13,1845,1845,5087,488,0]An[4739,13,1845,1845,3993,488,0]An[4739,13,1845,1845,4846,488,0]An[4739,13,1924,1924,3351,488,0]An[4739,13,1924,1924,4270,488,0]An[4739,13,1924,1924,4712,488,0]An[4739,13,1924,1924,4714,488,0]An[4739,13,1924,1924,4937,488,0]Ak[4739,13,1924,0,1342,488,0]Al[4739,13,3708,135,114,488,0]Am[4739,13,3708,135,3117,488,0]An[4739,13,3708,1511,1329,488,0]An[4739,13,3708,1511,3995,488,0]An[4739,13,3708,2493,1993,488,0]An[4739,13,3708,2493,4287,488,0]An[4739,13,3708,3708,4774,488,0]An[4739,13,2123,2123,1344,488,0]An[4739,13,2123,2123,1347,488,0]An[1050,13,1051,1051,3120,488,0]An[1050,13,1051,1051,4874,488,0]Am[1050,13,1834,1834,128,488,0]An[1050,13,1542,1542,1362,488,0]An[1050,13,1542,1542,4018,488,0]An[1050,13,1542,1542,4508,488,0]An[1050,13,4227,4227,5072,488,0]An[1050,13,4227,4227,5073,488,0]Am[1050,13,1929,1929,129,488,0]Am[3974,13,3975,3975,118,488,0]An[3974,13,3975,3975,2390,488,0]Ah[3954,5,3955,3164,0,0,0]Ah[4739,5,4740,3164,0,0,0]Ah[3954,5,3707,1511,0,0,0]Ah[4739,5,3708,1511,0,0,0]Al[1050,15,1051,1051,4874,0,0]Ah[3954,6,1923,1514,0,0,0]Ah[4739,6,1924,1514,0,0,0]Ae[4739,6,4982,0,0,0,0]Ae[4739,6,2123,0,0,0,0]Ah[4739,6,4740,3713,0,0,0]1Al[4739,15,4740,1516,3323,0,0]Ai[3954,15,1923,0,1341,0,0]Ai[4739,15,1924,0,1342,0,0]Al[3954,15,3955,4090,3148,0,0]Ai[3954,15,3955,0,4499,0,0]Al[4739,15,4740,1075,3149,0,0]Al[4739,15,4740,3713,4500,0,0]Al[4739,15,4740,1907,4512,0,0]0Ae[1365,5,1540,0,0,0,0]Ae[1050,5,1542,0,0,0,0]Ab[1365,3,0,0,0,0,0]Ai[3954,12,3707,0,4771,0,0]Al[3954,13,3707,0,3116,4771,0]Al[3954,13,3707,0,3994,4771,0]Al[3954,13,3707,0,4286,4771,0]Al[4739,12,3708,3708,4772,0,0]An[4739,13,3708,135,3117,4772,0]Ao[4739,13,3708,1511,3995,4772,0]Ao[4739,13,3708,2493,4287,4772,0]Al[1050,13,1051,1051,4874,0,0]Ai[3954,14,3955,0,1324,0,0]Ai[3954,14,3955,0,2434,0,0]Ai[3954,14,3955,0,2018,0,0]Al[4739,14,4740,3164,1325,0,0]Al[4739,14,4740,1541,2435,0,0]Al[4739,14,4740,1080,2019,0,0]Al[4739,14,4740,2445,3984,0,0]An[1365,13,1366,1366,127,1326,0]Ao[1365,13,1366,1366,3986,1326,0]Ao[3954,13,3955,3712,3310,1326,0]Ao[3954,13,3955,3712,4943,1326,0]Ao[3954,13,3955,3712,4781,1326,0]Ao[3954,13,3955,2444,2399,1326,0]Ao[3954,13,3955,2444,4267,1326,0]Ao[3954,13,3955,4090,4405,1326,0]Ao[3954,13,3955,4090,3148,1326,0]Ao[3954,13,3955,4090,3337,1326,0]Ao[3954,13,3955,4090,4404,1326,0]Ao[3954,13,3955,4095,3355,1326,0]Ao[3954,13,3955,4095,4174,1326,0]Al[3954,13,3955,0,1603,1326,0]Al[3954,13,3955,0,4940,1326,0]Al[3954,13,3955,0,1586,1326,0]Al[3954,13,3955,0,2434,1326,0]Al[3954,13,3955,0,3316,1326,0]Al[3954,13,3955,0,3145,1326,0]Al[3954,13,3955,0,4503,1326,0]Al[3954,13,3955,0,2018,1326,0]Al[3954,13,3955,0,4126,1326,0]Al[3954,13,3955,0,4499,1326,0]Al[3954,13,3955,0,4520,1326,0]Al[3954,13,3955,0,4805,1326,0]Al[3954,13,3955,0,4820,1326,0]Al[3954,13,3955,0,3999,1326,0]Al[3954,13,3955,0,4381,1326,0]Al[3954,13,3955,0,4168,1326,0]Al[3954,13,3955,0,4997,1326,0]Al[3954,13,3955,0,4120,1326,0]Al[3954,13,3955,0,3989,1326,0]Al[3954,13,3955,0,3128,1326,0]Al[3954,13,3955,0,4496,1326,0]Al[3954,13,3955,0,4684,1326,0]Al[3954,13,3955,0,4132,1326,0]Al[3954,13,3955,0,4135,1326,0]Al[3954,13,3955,0,4140,1326,0]Al[3954,13,3955,0,4839,1326,0]Al[3954,13,3955,0,3319,1326,0]Ak[3954,13,3955,0,485,1326,0]Ak[3954,13,3955,0,119,1326,0]Al[3954,13,3955,0,2422,1326,0]Ak[3954,13,3707,0,113,1326,0]Al[3954,13,3707,0,3116,1326,0]Al[3954,13,3707,0,1328,1326,0]Al[3954,13,3707,0,3994,1326,0]Al[3954,13,3707,0,1992,1326,0]Al[3954,13,3707,0,4286,1326,0]Al[3954,13,1923,0,4936,1326,0]Al[3954,13,1923,0,1341,1326,0]Ao[4739,13,4740,1960,1604,1326,0]Ao[4739,13,4740,1960,4941,1326,0]Ao[4739,13,4740,3173,4782,1326,0]Ao[4739,13,4740,1526,1587,1326,0]Ao[4739,13,4740,1526,4164,1326,0]Ao[4739,13,4740,1526,3331,1326,0]Ao[4739,13,4740,1526,3144,1326,0]Ao[4739,13,4740,1526,4836,1326,0]Ao[4739,13,4740,1526,3306,1326,0]Ao[4739,13,4740,1541,2435,1326,0]Ao[4739,13,4740,1541,3317,1326,0]Ao[4739,13,4740,1541,3146,1326,0]Ao[4739,13,4740,1541,4504,1326,0]Ao[4739,13,4740,1075,3149,1326,0]Ao[4739,13,4740,1075,4294,1326,0]Ao[4739,13,4740,1080,2019,1326,0]Ao[4739,13,4740,1080,3356,1326,0]Ao[4739,13,4740,1080,3998,1326,0]Ao[4739,13,4740,2152,4406,1326,0]Ao[4739,13,4740,2152,4130,1326,0]Ao[4739,13,4740,3713,4500,1326,0]Ao[4739,13,4740,3713,3141,1326,0]Ao[4739,13,4740,3713,4372,1326,0]Ao[4739,13,4740,3713,5024,1326,0]Ao[4739,13,4740,3293,4521,1326,0]Ao[4739,13,4740,3293,4806,1326,0]Ao[4739,13,4740,3293,4821,1326,0]Ao[4739,13,4740,3293,4000,1326,0]Ao[4739,13,4740,1842,4382,1326,0]Ao[4739,13,4740,1842,4170,1326,0]Ao[4739,13,4740,1842,4998,1326,0]Ao[4739,13,4740,1842,4122,1326,0]Ao[4739,13,4740,1842,3990,1326,0]Ao[4739,13,4740,1516,3129,1326,0]Ao[4739,13,4740,1516,3323,1326,0]Ao[4739,13,4740,1516,3345,1326,0]Ao[4739,13,4740,1516,4137,1326,0]Ao[4739,13,4740,1516,4498,1326,0]Ao[4739,13,4740,1516,4686,1326,0]Ao[4739,13,4740,1516,2393,1326,0]Ao[4739,13,4740,2445,4690,1326,0]Ao[4739,13,4740,2445,4133,1326,0]Ao[4739,13,4740,1907,4512,1326,0]Ao[4739,13,4740,1907,5027,1326,0]Ao[4739,13,4740,1907,2406,1326,0]Ao[4739,13,4740,1907,4780,1326,0]Ao[4739,13,4740,1934,4136,1326,0]Ao[4739,13,4740,1934,4141,1326,0]Al[4739,13,4740,0,4410,1326,0]Al[4739,13,4740,0,4840,1326,0]Ao[4739,13,4740,4307,3320,1326,0]Ao[4739,13,4740,4307,5120,1326,0]An[4739,13,4740,4740,486,1326,0]An[4739,13,4740,4740,120,1326,0]Ao[4739,13,4740,4740,2423,1326,0]Ao[4739,13,4740,4740,3127,1326,0]Ao[4739,13,1840,1840,4300,1326,0]Ao[4739,13,4982,4982,4881,1326,0]Ao[4739,13,4982,4982,1343,1326,0]Ao[4739,13,1924,1924,4937,1326,0]Al[4739,13,1924,0,1342,1326,0]Am[4739,13,3708,135,114,1326,0]An[4739,13,3708,135,3117,1326,0]Ao[4739,13,3708,1511,1329,1326,0]Ao[4739,13,3708,1511,3995,1326,0]Ao[4739,13,3708,2493,1993,1326,0]Ao[4739,13,3708,2493,4287,1326,0]Ao[4739,13,2123,2123,1347,1326,0]Ao[4445,13,4446,4446,2420,1326,0]Ao[4445,13,4446,4446,2433,1326,0]Ao[4445,13,4446,4446,4142,1326,0]Ao[1050,13,1051,1051,4874,1326,0]Ao[1050,13,1542,1542,4508,1326,0]Al[3954,13,3955,3712,3310,0,0]Al[3954,13,3955,2444,2399,0,0]Ak[3954,13,3955,1049,478,0,0]Al[4739,13,4740,3713,3311,0,0]Al[3954,13,3955,0,4135,1332,0]Ao[4739,13,4740,1934,4136,1332,0]Ai[4739,14,3142,0,4277,0,0]Ai[4739,14,4740,0,4410,0,0]Ai[3954,13,3955,0,2422,0,0]Al[4739,13,4740,4740,2423,0,0]Ai[3954,13,3955,0,4140,0,0]Al[4739,13,4740,1934,4141,0,0]Ai[3954,14,1844,0,1987,0,0]Al[4739,14,1845,1845,1988,0,0]Al[4739,12,4740,1907,4811,0,0]Ao[4739,13,4740,1907,5145,4811,0]=Al[4739,13,4982,4982,4881,0,0]Ah[3954,5,3955,2444,0,0,0]Ai[3954,15,3955,0,3128,0,0]Al[4739,15,4740,1516,3129,0,0]Al[1365,15,1366,1366,3986,0,0]0Al[4739,15,4740,1526,3331,0,0]Ah[4739,5,4740,1075,0,0,0]Ah[3954,15,3955,0,485,0,0]Ak[4739,15,4740,4740,486,0,0]Al[3974,15,3975,3975,2390,0,0]Al[4739,15,4740,1526,3144,0,0]Al[4739,15,2123,2123,1344,0,0]98Ah[3954,5,3955,3712,0,0,0]2Al[4739,15,4740,2152,4016,0,0]Ah[3954,5,3955,1526,0,0,0]Ah[4739,5,4740,1526,0,0,0]Ae[4739,8,1840,0,0,0,0]987>Al[4739,15,4740,3713,1346,0,0]>Ah[3954,5,3955,1960,0,0,0]Ah[4739,5,4740,1960,0,0,0]Al[3954,13,3955,2444,2399,0,0]Al[3954,13,3955,2471,2403,0,0]Al[4739,13,4740,2152,2012,0,0]Al[4739,13,4740,2445,2400,0,0]An[1365,13,1366,1366,127,1564,0]Ao[1365,13,1366,1366,3986,1564,0]Ao[1365,13,1540,1540,4017,1564,0]Ao[1365,13,1540,1540,1361,1564,0]Ao[1365,13,1540,1540,4407,1564,0]Al[495,13,496,496,3987,1564,0]Ao[4023,13,4024,4024,5028,1564,0]Ao[3954,13,3955,3712,4525,1564,0]Ao[3954,13,3955,3712,2413,1564,0]Al[3954,13,3955,0,4258,1564,0]Ao[3954,13,3955,1049,2414,1564,0]Ao[3954,13,3955,1049,3119,1564,0]Ao[3954,13,3955,1049,4682,1564,0]Ao[3954,13,3955,3712,3308,1564,0]Ao[3954,13,3955,3712,3310,1564,0]Ao[3954,13,3955,3712,1995,1564,0]Ao[3954,13,3955,3712,1579,1564,0]Ao[3954,13,3955,3712,3109,1564,0]Ao[3954,13,3955,3712,2387,1564,0]Ao[3954,13,3955,3712,4160,1564,0]Ao[3954,13,3955,3712,4165,1564,0]Ao[3954,13,3955,3712,4943,1564,0]Ao[3954,13,3955,3712,4781,1564,0]Ao[3954,13,3955,2444,2399,1564,0]Ao[3954,13,3955,2444,4267,1564,0]Ao[3954,13,3955,2444,1558,1564,0]Ao[3954,13,3955,2471,2403,1564,0]Ao[3954,13,3955,2471,3338,1564,0]Ao[3954,13,3955,2471,4386,1564,0]An[3954,13,3955,1049,478,1564,0]Ao[3954,13,3955,4090,3335,1564,0]Ao[3954,13,3955,4090,4882,1564,0]Ao[3954,13,3955,4090,4405,1564,0]Ao[3954,13,3955,4090,3148,1564,0]Ao[3954,13,3955,4090,3337,1564,0]Ao[3954,13,3955,4090,4404,1564,0]Ao[3954,13,3955,1552,4175,1564,0]Ao[3954,13,3955,1092,4012,1564,0]Ao[3954,13,3955,4095,3341,1564,0]Ao[3954,13,3955,4095,3355,1564,0]Ao[3954,13,3955,4095,4174,1564,0]Al[3954,13,3955,0,3332,1564,0]Al[3954,13,3955,0,4298,1564,0]Al[3954,13,3955,0,4517,1564,0]Al[3954,13,3955,0,4152,1564,0]Al[3954,13,3955,0,4395,1564,0]Al[3954,13,3955,0,1603,1564,0]Al[3954,13,3955,0,4940,1564,0]Al[3954,13,3955,0,1324,1564,0]Al[3954,13,3955,0,1586,1564,0]Al[3954,13,3955,0,2434,1564,0]Al[3954,13,3955,0,3316,1564,0]Al[3954,13,3955,0,3145,1564,0]Al[3954,13,3955,0,4503,1564,0]Al[3954,13,3955,0,2018,1564,0]Al[3954,13,3955,0,4126,1564,0]Al[3954,13,3955,0,4499,1564,0]Al[3954,13,3955,0,4513,1564,0]Al[3954,13,3955,0,4520,1564,0]Al[3954,13,3955,0,4805,1564,0]Al[3954,13,3955,0,4820,1564,0]Al[3954,13,3955,0,3999,1564,0]Al[3954,13,3955,0,4381,1564,0]Al[3954,13,3955,0,4168,1564,0]Al[3954,13,3955,0,4997,1564,0]Al[3954,13,3955,0,4120,1564,0]Al[3954,13,3955,0,3989,1564,0]Al[3954,13,3955,0,3128,1564,0]Al[3954,13,3955,0,4496,1564,0]Al[3954,13,3955,0,4684,1564,0]Al[3954,13,3955,0,4132,1564,0]Al[3954,13,3955,0,4135,1564,0]Al[3954,13,3955,0,4140,1564,0]Al[3954,13,3955,0,4839,1564,0]Al[3954,13,3955,0,3319,1564,0]Al[3954,13,3955,0,4715,1564,0]Ak[3954,13,3955,0,485,1564,0]Ak[3954,13,3955,0,119,1564,0]Al[3954,13,3955,0,2422,1564,0]Al[3954,13,3955,0,2431,1564,0]Ak[3954,13,3707,0,113,1564,0]Al[3954,13,3707,0,3116,1564,0]Al[3954,13,3707,0,1328,1564,0]Al[3954,13,3707,0,3994,1564,0]Al[3954,13,3707,0,1992,1564,0]Al[3954,13,3707,0,4286,1564,0]Al[3954,13,3707,0,4773,1564,0]Al[3954,13,1844,0,1987,1564,0]Ak[3954,13,1844,0,472,1564,0]Al[3954,13,1844,0,5086,1564,0]Al[3954,13,1844,0,3992,1564,0]Al[3954,13,1844,0,4843,1564,0]Al[3954,13,1923,0,3350,1564,0]Al[3954,13,1923,0,4269,1564,0]Al[3954,13,1923,0,4711,1564,0]Al[3954,13,1923,0,4713,1564,0]Al[3954,13,1923,0,4936,1564,0]Al[3954,13,1923,0,1341,1564,0]Ao[4739,13,4740,4530,4259,1564,0]Ao[4739,13,4740,3173,3123,1564,0]Ao[4739,13,4740,1075,1566,1564,0]Ao[4739,13,4740,2152,2012,1564,0]Ao[4739,13,4740,2152,3336,1564,0]Ao[4739,13,4740,2152,3342,1564,0]Ao[4739,13,4740,3713,3311,1564,0]Ao[4739,13,4740,1071,3333,1564,0]Ao[4739,13,4740,1842,4299,1564,0]Ao[4739,13,4740,2445,2400,1564,0]Ao[4739,13,4740,2445,4265,1564,0]Ao[4739,13,4740,1907,5145,1564,0]Ao[4739,13,4740,4307,5115,1564,0]Ao[4739,13,4740,1551,4518,1564,0]Ao[4739,13,4740,1551,4153,1564,0]Ao[4739,13,4740,1551,4396,1564,0]Ao[4739,13,4740,1960,1604,1564,0]Ao[4739,13,4740,1960,4941,1564,0]Ao[4739,13,4740,3164,1325,1564,0]Ao[4739,13,4740,3173,4782,1564,0]Ao[4739,13,4740,1526,1587,1564,0]Ao[4739,13,4740,1526,4164,1564,0]Ao[4739,13,4740,1526,3331,1564,0]Ao[4739,13,4740,1526,3144,1564,0]Ao[4739,13,4740,1526,4836,1564,0]Ao[4739,13,4740,1526,3306,1564,0]Ao[4739,13,4740,1541,2435,1564,0]Ao[4739,13,4740,1541,3317,1564,0]Ao[4739,13,4740,1541,3146,1564,0]Ao[4739,13,4740,1541,4504,1564,0]Ao[4739,13,4740,1075,3149,1564,0]Ao[4739,13,4740,1075,4294,1564,0]Ao[4739,13,4740,1080,2019,1564,0]Ao[4739,13,4740,1080,3356,1564,0]Ao[4739,13,4740,1080,3998,1564,0]Ao[4739,13,4740,2152,4016,1564,0]Ao[4739,13,4740,2152,4406,1564,0]Ao[4739,13,4740,2152,4130,1564,0]Ao[4739,13,4740,3713,4500,1564,0]Ao[4739,13,4740,3713,3141,1564,0]Ao[4739,13,4740,3713,4372,1564,0]Ao[4739,13,4740,3713,5024,1564,0]Ao[4739,13,4740,3713,1346,1564,0]Ao[4739,13,4740,1071,4514,1564,0]Ao[4739,13,4740,3293,4521,1564,0]Ao[4739,13,4740,3293,4806,1564,0]Ao[4739,13,4740,3293,4821,1564,0]Ao[4739,13,4740,3293,4000,1564,0]Ao[4739,13,4740,1842,4382,1564,0]Ao[4739,13,4740,1842,4170,1564,0]Ao[4739,13,4740,1842,4998,1564,0]Ao[4739,13,4740,1842,4122,1564,0]Ao[4739,13,4740,1842,3990,1564,0]Ao[4739,13,4740,1516,3129,1564,0]Ao[4739,13,4740,1516,4387,1564,0]Ao[4739,13,4740,1516,3323,1564,0]Ao[4739,13,4740,1516,3345,1564,0]Ao[4739,13,4740,1516,4137,1564,0]Ao[4739,13,4740,1516,4498,1564,0]Ao[4739,13,4740,1516,4686,1564,0]Ao[4739,13,4740,1516,2393,1564,0]Ao[4739,13,4740,2445,4690,1564,0]Ao[4739,13,4740,2445,2404,1564,0]Ao[4739,13,4740,2445,4133,1564,0]Ao[4739,13,4740,2445,3984,1564,0]Ao[4739,13,4740,2445,3339,1564,0]Ao[4739,13,4740,1907,4289,1564,0]Ao[4739,13,4740,1907,4512,1564,0]Ao[4739,13,4740,1907,5027,1564,0]Ao[4739,13,4740,1907,2406,1564,0]Ao[4739,13,4740,1907,4780,1564,0]Ao[4739,13,4740,1934,4502,1564,0]Ao[4739,13,4740,1934,4266,1564,0]Ao[4739,13,4740,1934,4136,1564,0]Ao[4739,13,4740,1934,4141,1564,0]Al[4739,13,4740,0,4410,1564,0]Al[4739,13,4740,0,4840,1564,0]Ao[4739,13,4740,4307,3320,1564,0]Ao[4739,13,4740,4307,5120,1564,0]Ao[4739,13,4740,4870,4716,1564,0]An[4739,13,4740,4740,486,1564,0]An[4739,13,4740,4740,120,1564,0]Ao[4739,13,4740,4740,2423,1564,0]Ao[4739,13,4740,4740,2432,1564,0]Ao[4739,13,4740,4740,3127,1564,0]Ao[4739,13,1840,1840,4300,1564,0]Ao[4739,13,4982,4982,4881,1564,0]Ao[4739,13,4982,4982,1343,1564,0]Ao[4739,13,1845,1845,1988,1564,0]An[4739,13,1845,1845,473,1564,0]Ao[4739,13,1845,1845,5087,1564,0]Ao[4739,13,1845,1845,3993,1564,0]Ao[4739,13,1845,1845,4846,1564,0]Ao[4739,13,1924,1924,3351,1564,0]Ao[4739,13,1924,1924,4270,1564,0]Ao[4739,13,1924,1924,4712,1564,0]Ao[4739,13,1924,1924,4714,1564,0]Ao[4739,13,1924,1924,4937,1564,0]Al[4739,13,1924,0,1342,1564,0]Am[4739,13,3708,135,114,1564,0]An[4739,13,3708,135,3117,1564,0]Ao[4739,13,3708,1511,1329,1564,0]Ao[4739,13,3708,1511,3995,1564,0]Ao[4739,13,3708,2493,1993,1564,0]Ao[4739,13,3708,2493,4287,1564,0]Ao[4739,13,3708,3708,4774,1564,0]Ao[4739,13,2123,2123,1344,1564,0]Ao[4739,13,2123,2123,1347,1564,0]Ao[4445,13,4446,4446,3354,1564,0]An[4445,13,4446,393,4411,1564,0]Ao[4445,13,4446,4446,2420,1564,0]Ao[4445,13,4446,4446,2433,1564,0]Ao[4445,13,4446,4446,4142,1564,0]Ao[1050,13,1051,1051,3120,1564,0]Ao[1050,13,1051,1051,4874,1564,0]An[1050,13,1834,1834,128,1564,0]Ao[1050,13,1542,1542,1362,1564,0]Ao[1050,13,1542,1542,4018,1564,0]Ao[1050,13,1542,1542,4508,1564,0]Ao[1050,13,4227,4227,5072,1564,0]Ao[1050,13,4227,4227,5073,1564,0]An[1050,13,1929,1929,129,1564,0]An[3974,13,3975,3975,118,1564,0]Ao[3974,13,3975,3975,2390,1564,0]Ai[3954,14,3955,0,2018,0,0]Al[4739,14,4740,1080,2019,0,0]Ak[1365,14,1366,1366,127,0,0]Ac[495,7,496,0,0,0,0]Al[3954,13,3955,2444,2399,0,0]Ae[1050,2,1051,0,0,0,0]Ae[4800,7,4801,0,0,0,0]Al[3954,13,3955,3712,3310,0,0]Ae[4739,2,4740,0,0,0,0]Al[4739,13,4740,2445,2400,0,0]Ah[3954,2,3955,4740,0,0,0]Ai[3954,13,3955,0,4839,0,0]Ai[3954,14,3955,0,3316,0,0]Ai[3954,14,3955,0,4168,0,0]5Ai[4739,13,4740,0,4840,0,0]Al[4739,14,4740,1541,3317,0,0]Al[4739,14,4740,1842,4170,0,0]Ai[4739,14,4740,0,4410,0,0]Al[3954,13,3955,0,1603,3124,0]Al[3954,13,3955,0,1586,3124,0]Al[3954,13,3955,0,3128,3124,0]Al[3954,13,3955,0,4839,3124,0]Al[3954,13,3955,0,2422,3124,0]Ao[4739,13,4740,1960,1604,3124,0]Ao[4739,13,4740,1526,1587,3124,0]Ao[4739,13,4740,1516,3129,3124,0]Ao[4739,13,4740,1516,3323,3124,0]Al[4739,13,4740,1907,4512,0,0]Al[4739,13,4740,0,4840,3124,0]Ao[4739,13,4740,4740,2423,3124,0]Al[4739,12,1840,1840,3124,0,0]Al[4445,14,4446,4446,2420,0,0]Al[3954,13,3955,0,1603,3125,0]Al[3954,13,3955,0,1586,3125,0]Al[3954,13,3955,0,3128,3125,0]Al[3954,13,3955,0,4839,3125,0]Al[3954,13,3955,0,2422,3125,0]Ao[4739,13,4740,1960,1604,3125,0]Ao[4739,13,4740,1526,1587,3125,0]Ao[4739,13,4740,1516,3129,3125,0]Ao[4739,13,4740,1516,3323,3125,0]Ao[4739,13,4740,1516,2393,3125,0]Al[4739,13,4740,0,4840,3125,0]Ao[4739,13,4740,4740,2423,3125,0]Al[4739,12,1840,1840,3125,0,0]Al[3954,13,3955,4095,3341,0,0]Al[4739,13,4740,2152,3342,0,0]Al[1050,13,1542,1542,4018,0,0]Al[4739,13,4740,2445,2400,0,0]Ah[3954,14,1844,0,472,0,0]Ak[4739,14,1845,1845,473,0,0]Al[3954,13,3955,2471,2403,0,0]3Ai[3954,12,3955,0,3352,0,0]Al[3954,13,3955,0,4395,3352,0]Al[3954,13,3955,0,4715,3352,0]Al[4739,12,4740,1551,3353,0,0]Ao[4739,13,4740,1551,4396,3353,0]Ao[4739,13,4740,4870,4716,3353,0]Al[1050,14,1051,1051,3120,0,0]Ai[3954,14,3955,0,1324,0,0]Al[4739,14,4740,3164,1325,0,0]Ai[3954,13,3707,0,3312,0,0]Ak[3954,13,3707,0,113,3312,0]Al[3954,13,3707,0,1328,3312,0]Al[3954,13,3707,0,1992,3312,0]Al[4739,13,3708,3708,3313,0,0]Am[4739,13,3708,135,114,3313,0]Ao[4739,13,3708,1511,1329,3313,0]Ao[4739,13,3708,2493,1993,3313,0]Ah[3954,14,1844,0,472,0,0]Ak[4739,14,1845,1845,473,0,0]Ai[4739,14,4511,0,4719,0,0]Ai[3954,14,3955,0,4496,0,0]Ai[3954,14,3955,0,4684,0,0]Al[4739,14,4740,1516,4498,0,0]Al[4739,14,4740,1516,4686,0,0]Ai[4739,14,4740,0,4410,0,0]Ai[4739,14,1345,0,4374,0,0]Al[3954,13,3955,2444,2399,0,0]Al[3954,13,3955,2471,2403,0,0]Al[4739,13,4740,2445,2400,0,0]Ai[3954,14,1844,0,1987,0,0]Al[4739,14,4740,4740,3127,0,0]Al[4739,14,1845,1845,1988,0,0]Ae[3954,4,3955,0,0,0,0]Ah[3954,2,1844,1845,0,0,0]Ae[4739,4,4740,0,0,0,0]Ae[4739,2,1845,0,0,0,0]Ac[495,7,496,0,0,0,0]:Ae[1050,2,1051,0,0,0,0]Ae[4800,7,4801,0,0,0,0]Ao[3954,13,3955,3712,4781,1334,0]Ao[3954,13,3955,4090,4405,1334,0]Ao[3954,13,3955,4090,3148,1334,0]Ao[3954,13,3955,4090,3337,1334,0]Ao[3954,13,3955,4090,4404,1334,0]Ao[3954,13,3955,4095,3355,1334,0]Ao[3954,13,3955,4095,4174,1334,0]Al[3954,13,3955,0,4499,1334,0]Ao[4739,13,4740,3713,4500,1334,0]Ai[3954,14,3955,0,2431,0,0]Al[4739,14,4740,4740,2432,0,0]Al[4445,14,4446,4446,2433,0,0]Ak[3954,13,3955,1049,478,0,0]Ai[4739,14,3142,0,4161,0,0]Ai[3954,14,3955,0,3316,0,0]Al[4739,14,4740,1541,3317,0,0]Al[4445,14,4446,4446,2420,0,0]Ai[3954,14,3955,0,3145,0,0]Ai[3954,14,3955,0,4503,0,0]Al[4739,14,4740,1541,3146,0,0]Al[4739,14,4740,1541,4504,0,0]3210Ai[3954,12,1844,0,1983,0,0]Al[4739,12,1845,1845,1984,0,0]Ai[3954,12,3707,0,3312,0,0]Ak[3954,13,3707,0,113,3312,0]Al[3954,13,3707,0,1328,3312,0]Al[3954,13,3707,0,1992,3312,0]Al[4739,12,3708,3708,3313,0,0]Am[4739,13,3708,135,114,3313,0]Ao[4739,13,3708,1511,1329,3313,0]Ao[4739,13,3708,2493,1993,3313,0]Ai[3954,10,1844,1845,0,0,0]Af[4739,10,1845,0,0,0,0]Al[4739,15,4740,3173,4782,0,0]Al[4739,15,4740,1075,3149,0,0]Al[4739,15,4740,1080,3356,0,0]Ai[3954,15,1923,0,1341,0,0]Ai[4739,15,1924,0,1342,0,0]65Al[4739,15,4740,1907,4512,0,0]Ah[3954,5,1844,1845,0,0,0]Ae[4739,5,1845,0,0,0,0]Ai[3954,15,3955,0,3128,0,0]Al[4739,15,4740,1516,3129,0,0]Ah[3954,5,3707,2493,0,0,0]Ah[4739,5,3708,2493,0,0,0]Al[1050,15,1051,1051,4874,0,0]Ah[3954,5,3955,3712,0,0,0]5454Ai[3954,10,3955,2144,0,0,0]Ai[3954,10,1844,1845,0,0,0]Af[4739,10,1845,0,0,0,0]Al[3954,15,3955,4095,3355,0,0]?Al[4739,15,4740,1080,3998,0,0]Al[4739,15,4740,2152,4016,0,0]Ah[4739,5,4740,2152,0,0,0]Al[3954,15,3955,4090,4405,0,0]Al[4739,15,4740,1516,3323,0,0]Ah[3954,5,3955,1080,0,0,0]Ah[4739,5,4740,1080,0,0,0]Al[4739,15,4740,1907,2406,0,0]Ai[3954,12,3955,0,4988,0,0]Al[4739,12,4740,4307,4989,0,0]Ao[4739,13,4740,4307,5115,4989,0]Ao[4739,13,4740,4307,5120,4989,0]Ak[1365,14,1366,1366,127,0,0]An[1365,13,1366,1366,127,4373,0]Ao[1050,13,1051,1051,3120,4373,0]An[1050,13,1834,1834,128,4373,0]An[1050,13,1929,1929,129,4373,0]An[3974,13,3975,3975,118,4373,0]Ak[3974,14,3975,3975,118,0,0]Al[3954,13,3955,0,1603,3307,0]Al[3954,13,3955,0,1586,3307,0]Al[3954,13,3955,0,3999,3307,0]Al[3954,13,3955,0,4135,3307,0]Ak[3954,13,3955,0,485,3307,0]Ak[3954,13,3955,0,119,3307,0]Al[3954,13,3955,0,2422,3307,0]Ao[4739,13,4740,1960,1604,3307,0]Ao[4739,13,4740,3173,4782,3307,0]Ao[4739,13,4740,1526,1587,3307,0]Ao[4739,13,4740,1075,3149,3307,0]Ao[4739,13,4740,1075,4294,3307,0]Ao[4739,13,4740,1080,3356,3307,0]Ao[4739,13,4740,3293,4000,3307,0]Ao[4739,13,4740,2445,4690,3307,0]Ao[4739,13,4740,1907,4780,3307,0]Ao[4739,13,4740,1934,4136,3307,0]An[4739,13,4740,4740,486,3307,0]An[4739,13,4740,4740,120,3307,0]Ao[4739,13,4740,4740,2423,3307,0]Al[3954,13,3955,2444,2399,0,0]Al[4739,13,4740,2445,2400,0,0]Ai[3954,12,1844,0,3138,0,0]Ai[3954,12,1844,0,3131,0,0]Al[4739,12,1845,1845,3139,0,0]Al[4739,12,1845,1845,3132,0,0]Ao[1365,13,1540,1540,4017,1978,0]Ao[1365,13,1540,1540,1361,1978,0]Al[495,13,496,496,3987,1978,0]Al[3954,13,3955,0,4258,1978,0]Ao[3954,13,3955,2444,4267,1978,0]Al[3954,13,3955,0,1603,1978,0]Al[3954,13,3955,0,1586,1978,0]Al[3954,13,3955,0,2434,1978,0]Al[3954,13,3955,0,3316,1978,0]Al[3954,13,3955,0,3145,1978,0]Al[3954,13,3955,0,4503,1978,0]Al[3954,13,3955,0,2018,1978,0]Al[3954,13,3955,0,4126,1978,0]Al[3954,13,3955,0,4520,1978,0]Al[3954,13,3955,0,4805,1978,0]Al[3954,13,3955,0,4820,1978,0]Al[3954,13,3955,0,3999,1978,0]Al[3954,13,3955,0,4381,1978,0]Al[3954,13,3955,0,4997,1978,0]Al[3954,13,3955,0,4715,1978,0]Al[3954,13,3707,0,3116,1978,0]Al[3954,13,3707,0,3994,1978,0]Al[3954,13,3707,0,4286,1978,0]Al[3954,13,3707,0,4773,1978,0]Ao[4739,13,4740,4530,4259,1978,0]Ao[4739,13,4740,4307,5115,1978,0]Ao[4739,13,4740,1960,1604,1978,0]Ao[4739,13,4740,1526,1587,1978,0]Ao[4739,13,4740,1526,3331,1978,0]Ao[4739,13,4740,1526,3306,1978,0]Ao[4739,13,4740,1541,2435,1978,0]Ao[4739,13,4740,1541,3317,1978,0]Ao[4739,13,4740,1541,3146,1978,0]Ao[4739,13,4740,1541,4504,1978,0]Ao[4739,13,4740,1080,2019,1978,0]Ao[4739,13,4740,2152,4406,1978,0]Ao[4739,13,4740,2152,4130,1978,0]Ao[4739,13,4740,3293,4521,1978,0]Ao[4739,13,4740,3293,4806,1978,0]Ao[4739,13,4740,3293,4821,1978,0]Ao[4739,13,4740,3293,4000,1978,0]Ao[4739,13,4740,1842,4382,1978,0]Ao[4739,13,4740,1842,4998,1978,0]Ao[4739,13,4740,4307,5120,1978,0]Ao[4739,13,4740,4870,4716,1978,0]An[4739,13,3708,135,3117,1978,0]Ao[4739,13,3708,1511,3995,1978,0]Ao[4739,13,3708,2493,4287,1978,0]Ao[4739,13,3708,3708,4774,1978,0]Ao[4445,13,4446,4446,2420,1978,0]Ao[1050,13,1542,1542,1362,1978,0]Ao[1050,13,1542,1542,4508,1978,0]Al[4739,13,4740,1934,4266,0,0]Al[4739,13,4740,1907,4289,0,0]Al[4739,13,4740,1907,4512,0,0]Al[4739,14,4740,1907,5027,0,0]Ai[4739,14,4779,0,4841,0,0]Ah[4739,14,4511,0,474,0,0]Ai[4739,14,4511,0,1356,0,0]Ai[4739,14,4511,0,1358,0,0]Ai[4739,14,4511,0,4719,0,0]Ai[3954,12,1844,0,3138,0,0]Ai[3954,12,1844,0,3131,0,0]Al[4739,12,1845,1845,3139,0,0]Al[4739,12,1845,1845,3132,0,0]Ae[4739,2,4740,0,0,0,0]Al[3954,13,3955,4090,3335,0,0]Al[3954,13,3955,4090,4882,0,0]Ai[3954,13,3707,0,3312,0,0]Ak[3954,13,3707,0,113,3312,0]Al[3954,13,3707,0,1328,3312,0]Al[3954,13,3707,0,1992,3312,0]Al[4739,13,3708,3708,3313,0,0]Am[4739,13,3708,135,114,3313,0]Ao[4739,13,3708,1511,1329,3313,0]Ao[4739,13,3708,2493,1993,3313,0]Ai[3954,13,3955,0,4520,0,0]Al[4739,13,4740,3293,4521,0,0]9854Al[3954,13,3955,3712,3310,0,0]Al[3954,13,3955,1049,2414,0,0]Al[4739,14,4740,1907,5027,0,0]Ai[4739,14,4779,0,4841,0,0]Ah[4739,14,4511,0,474,0,0]Ai[4739,14,4511,0,1356,0,0]Ai[4739,14,4511,0,4719,0,0]Al[3954,13,3955,4095,3341,0,0]Al[4739,13,4740,2152,3342,0,0]Ak[1365,14,1366,1366,127,0,0]Al[1365,14,1540,1540,1361,0,0]Al[4739,13,4740,3713,3311,0,0]Ai[3954,12,1844,0,3138,0,0]Al[4739,12,1845,1845,3139,0,0]Am[1365,13,1366,1366,127,111,0]An[1365,13,1366,1366,3986,111,0]An[1365,13,1540,1540,4017,111,0]An[1365,13,1540,1540,1361,111,0]An[1365,13,1540,1540,4407,111,0]Ak[495,13,496,496,3987,111,0]An[4023,13,4024,4024,5028,111,0]An[3954,13,3955,3712,4525,111,0]An[3954,13,3955,3712,2413,111,0]Ak[3954,13,3955,0,4258,111,0]An[3954,13,3955,1049,2414,111,0]An[3954,13,3955,1049,3119,111,0]An[3954,13,3955,1049,4682,111,0]An[3954,13,3955,3712,3308,111,0]An[3954,13,3955,3712,3310,111,0]An[3954,13,3955,3712,1995,111,0]An[3954,13,3955,3712,1579,111,0]An[3954,13,3955,3712,3109,111,0]An[3954,13,3955,3712,2387,111,0]An[3954,13,3955,3712,4160,111,0]An[3954,13,3955,3712,4165,111,0]An[3954,13,3955,3712,4943,111,0]An[3954,13,3955,3712,4781,111,0]An[3954,13,3955,2444,2399,111,0]An[3954,13,3955,2444,4267,111,0]An[3954,13,3955,2444,1558,111,0]An[3954,13,3955,2471,2403,111,0]An[3954,13,3955,2471,3338,111,0]An[3954,13,3955,2471,4386,111,0]Am[3954,13,3955,1049,478,111,0]An[3954,13,3955,4090,3335,111,0]An[3954,13,3955,4090,4882,111,0]An[3954,13,3955,4090,4405,111,0]An[3954,13,3955,4090,3148,111,0]An[3954,13,3955,4090,3337,111,0]An[3954,13,3955,4090,4404,111,0]An[3954,13,3955,1552,4175,111,0]An[3954,13,3955,1092,4012,111,0]An[3954,13,3955,4095,3341,111,0]An[3954,13,3955,4095,3355,111,0]An[3954,13,3955,4095,4174,111,0]Ak[3954,13,3955,0,3332,111,0]Ak[3954,13,3955,0,4298,111,0]Ak[3954,13,3955,0,4517,111,0]Ak[3954,13,3955,0,4152,111,0]Ak[3954,13,3955,0,4395,111,0]Ak[3954,13,3955,0,1603,111,0]Ak[3954,13,3955,0,4940,111,0]Ak[3954,13,3955,0,1324,111,0]Ak[3954,13,3955,0,1586,111,0]Ak[3954,13,3955,0,2434,111,0]Ak[3954,13,3955,0,3316,111,0]Ak[3954,13,3955,0,3145,111,0]Ak[3954,13,3955,0,4503,111,0]Ak[3954,13,3955,0,2018,111,0]Ak[3954,13,3955,0,4126,111,0]Ak[3954,13,3955,0,4499,111,0]Ak[3954,13,3955,0,4513,111,0]Ak[3954,13,3955,0,4520,111,0]Ak[3954,13,3955,0,4805,111,0]Ak[3954,13,3955,0,4820,111,0]Ak[3954,13,3955,0,3999,111,0]Ak[3954,13,3955,0,4381,111,0]Ak[3954,13,3955,0,4168,111,0]Ak[3954,13,3955,0,4997,111,0]Ak[3954,13,3955,0,4120,111,0]Ak[3954,13,3955,0,3989,111,0]Ak[3954,13,3955,0,3128,111,0]Ak[3954,13,3955,0,4496,111,0]Ak[3954,13,3955,0,4684,111,0]Ak[3954,13,3955,0,4132,111,0]Ak[3954,13,3955,0,4135,111,0]Ak[3954,13,3955,0,4140,111,0]Ak[3954,13,3955,0,4839,111,0]Ak[3954,13,3955,0,3319,111,0]Ak[3954,13,3955,0,4715,111,0]Aj[3954,13,3955,0,485,111,0]Aj[3954,13,3955,0,119,111,0]Ak[3954,13,3955,0,2422,111,0]Ak[3954,13,3955,0,2431,111,0]Aj[3954,13,3707,0,113,111,0]Ak[3954,13,3707,0,3116,111,0]Ak[3954,13,3707,0,1328,111,0]Ak[3954,13,3707,0,3994,111,0]Ak[3954,13,3707,0,1992,111,0]Ak[3954,13,3707,0,4286,111,0]Ak[3954,13,3707,0,4773,111,0]Ak[3954,13,1844,0,1987,111,0]Aj[3954,13,1844,0,472,111,0]Ak[3954,13,1844,0,5086,111,0]Ak[3954,13,1844,0,3992,111,0]Ak[3954,13,1844,0,4843,111,0]Ak[3954,13,1923,0,3350,111,0]Ak[3954,13,1923,0,4269,111,0]Ak[3954,13,1923,0,4711,111,0]Ak[3954,13,1923,0,4713,111,0]Ak[3954,13,1923,0,4936,111,0]Ak[3954,13,1923,0,1341,111,0]An[4739,13,4740,4530,4259,111,0]An[4739,13,4740,3173,3123,111,0]An[4739,13,4740,1075,1566,111,0]An[4739,13,4740,2152,2012,111,0]An[4739,13,4740,2152,3336,111,0]An[4739,13,4740,2152,3342,111,0]An[4739,13,4740,3713,3311,111,0]An[4739,13,4740,1071,3333,111,0]An[4739,13,4740,1842,4299,111,0]An[4739,13,4740,2445,2400,111,0]An[4739,13,4740,2445,4265,111,0]An[4739,13,4740,1907,5145,111,0]An[4739,13,4740,4307,5115,111,0]An[4739,13,4740,1551,4518,111,0]An[4739,13,4740,1551,4153,111,0]An[4739,13,4740,1551,4396,111,0]An[4739,13,4740,1960,1604,111,0]An[4739,13,4740,1960,4941,111,0]An[4739,13,4740,3164,1325,111,0]An[4739,13,4740,3173,4782,111,0]An[4739,13,4740,1526,1587,111,0]An[4739,13,4740,1526,4164,111,0]An[4739,13,4740,1526,3331,111,0]An[4739,13,4740,1526,3144,111,0]An[4739,13,4740,1526,4836,111,0]An[4739,13,4740,1526,3306,111,0]An[4739,13,4740,1541,2435,111,0]An[4739,13,4740,1541,3317,111,0]An[4739,13,4740,1541,3146,111,0]An[4739,13,4740,1541,4504,111,0]An[4739,13,4740,1075,3149,111,0]An[4739,13,4740,1075,4294,111,0]An[4739,13,4740,1080,2019,111,0]An[4739,13,4740,1080,3356,111,0]An[4739,13,4740,1080,3998,111,0]An[4739,13,4740,2152,4016,111,0]An[4739,13,4740,2152,4406,111,0]An[4739,13,4740,2152,4130,111,0]An[4739,13,4740,3713,4500,111,0]An[4739,13,4740,3713,3141,111,0]An[4739,13,4740,3713,4372,111,0]An[4739,13,4740,3713,5024,111,0]An[4739,13,4740,3713,1346,111,0]An[4739,13,4740,1071,4514,111,0]An[4739,13,4740,3293,4521,111,0]An[4739,13,4740,3293,4806,111,0]An[4739,13,4740,3293,4821,111,0]An[4739,13,4740,3293,4000,111,0]An[4739,13,4740,1842,4382,111,0]An[4739,13,4740,1842,4170,111,0]An[4739,13,4740,1842,4998,111,0]An[4739,13,4740,1842,4122,111,0]An[4739,13,4740,1842,3990,111,0]An[4739,13,4740,1516,3129,111,0]An[4739,13,4740,1516,4387,111,0]An[4739,13,4740,1516,3323,111,0]An[4739,13,4740,1516,3345,111,0]An[4739,13,4740,1516,4137,111,0]An[4739,13,4740,1516,4498,111,0]An[4739,13,4740,1516,4686,111,0]An[4739,13,4740,1516,2393,111,0]An[4739,13,4740,2445,4690,111,0]An[4739,13,4740,2445,2404,111,0]An[4739,13,4740,2445,4133,111,0]An[4739,13,4740,2445,3984,111,0]An[4739,13,4740,2445,3339,111,0]An[4739,13,4740,1907,4289,111,0]An[4739,13,4740,1907,4512,111,0]An[4739,13,4740,1907,5027,111,0]An[4739,13,4740,1907,2406,111,0]An[4739,13,4740,1907,4780,111,0]An[4739,13,4740,1934,4502,111,0]An[4739,13,4740,1934,4266,111,0]An[4739,13,4740,1934,4136,111,0]An[4739,13,4740,1934,4141,111,0]Ak[4739,13,4740,0,4410,111,0]Ak[4739,13,4740,0,4840,111,0]An[4739,13,4740,4307,3320,111,0]An[4739,13,4740,4307,5120,111,0]An[4739,13,4740,4870,4716,111,0]Am[4739,13,4740,4740,486,111,0]Am[4739,13,4740,4740,120,111,0]An[4739,13,4740,4740,2423,111,0]An[4739,13,4740,4740,2432,111,0]An[4739,13,4740,4740,3127,111,0]An[4739,13,1840,1840,4300,111,0]An[4739,13,4982,4982,4881,111,0]An[4739,13,4982,4982,1343,111,0]An[4739,13,1845,1845,1988,111,0]Am[4739,13,1845,1845,473,111,0]An[4739,13,1845,1845,5087,111,0]An[4739,13,1845,1845,3993,111,0]An[4739,13,1845,1845,4846,111,0]An[4739,13,1924,1924,3351,111,0]An[4739,13,1924,1924,4270,111,0]An[4739,13,1924,1924,4712,111,0]An[4739,13,1924,1924,4714,111,0]An[4739,13,1924,1924,4937,111,0]Ak[4739,13,1924,0,1342,111,0]Al[4739,13,3708,135,114,111,0]Am[4739,13,3708,135,3117,111,0]An[4739,13,3708,1511,1329,111,0]An[4739,13,3708,1511,3995,111,0]An[4739,13,3708,2493,1993,111,0]An[4739,13,3708,2493,4287,111,0]An[4739,13,3708,3708,4774,111,0]An[4739,13,2123,2123,1344,111,0]An[4739,13,2123,2123,1347,111,0]An[4445,13,4446,4446,3354,111,0]Am[4445,13,4446,393,4411,111,0]An[4445,13,4446,4446,2420,111,0]An[4445,13,4446,4446,2433,111,0]An[4445,13,4446,4446,4142,111,0]An[1050,13,1051,1051,3120,111,0]An[1050,13,1051,1051,4874,111,0]Am[1050,13,1834,1834,128,111,0]An[1050,13,1542,1542,1362,111,0]An[1050,13,1542,1542,4018,111,0]An[1050,13,1542,1542,4508,111,0]An[1050,13,4227,4227,5072,111,0]An[1050,13,4227,4227,5073,111,0]Am[1050,13,1929,1929,129,111,0]Am[3974,13,3975,3975,118,111,0]An[3974,13,3975,3975,2390,111,0]Al[3954,13,3955,3712,4943,0,0]Ai[3954,13,3955,0,4120,0,0]Al[4739,13,4740,1842,4122,0,0]Al[4739,14,4740,1907,5027,0,0]Ai[4739,14,4779,0,4841,0,0]Ah[4739,14,4511,0,474,0,0]Ai[4739,14,4511,0,1356,0,0]Ah[3954,5,3955,3712,0,0,0]Al[1365,15,1366,1366,3986,0,0]Ae[3974,6,3975,0,0,0,0]Ai[3954,15,3955,0,3128,0,0]Al[4739,15,4740,1516,3129,0,0]Ah[4739,5,4740,1516,0,0,0]Al[3954,15,3955,3712,4781,0,0]Al[4739,15,4740,3173,4782,0,0]Ah[3954,5,3955,2444,0,0,0]Ah[4739,5,4740,2445,0,0,0]Al[4739,15,4740,2152,4016,0,0]Ah[3954,5,3955,2471,0,0,0]2Ah[4739,6,4740,1907,0,0,0]Ai[3954,19,3955,0,1603,0,0]Al[4739,19,4740,1960,1604,0,0]Ai[3954,19,3955,0,4839,0,0]Ai[4739,19,4740,0,4840,0,0]=Ai[3954,12,1844,0,4169,0,0]>Al[3954,13,1923,0,4713,4169,0]>Al[4739,12,1845,1845,4171,0,0]>Ao[4739,13,1924,1924,4714,4171,0]Ao[1050,13,4227,4227,5073,4171,0]An[3974,13,3975,3975,118,4001,0]Ao[3974,13,3975,3975,2390,4001,0]Ai[3954,14,3955,0,3145,0,0]Al[4739,14,4740,1541,3146,0,0]Ai[3954,13,3955,0,4168,0,0]Al[4739,13,4740,1842,4170,0,0]Al[3954,13,3955,2144,4369,0,0]0>=Al[1050,13,1542,1542,4508,0,0]Ae[1050,2,1051,0,0,0,0]Al[3954,13,3955,2471,2403,0,0]Al[4739,13,4740,2445,2404,0,0]Ai[3954,14,3955,0,3316,0,0]Al[4739,14,4740,1541,3317,0,0]Al[4739,13,4740,3713,3311,0,0]Ai[3954,13,3955,0,4520,0,0]Al[4739,13,4740,3293,4521,0,0]43Ai[3954,14,3955,0,2431,0,0]Al[4739,14,4740,4740,2432,0,0]Al[4445,14,4446,4446,2433,0,0]Al[4739,13,4740,2152,2012,0,0]Al[4739,13,4740,4307,5115,0,0]Al[4739,13,4740,4307,5120,0,0]Al[3954,13,3955,4095,3341,0,0]Al[4739,13,4740,2152,3342,0,0]<;Al[1365,14,1540,1540,1361,0,0]Ai[495,14,496,496,3987,0,0]Ai[3954,13,1923,0,4711,0,0]Ai[3954,13,1923,0,4713,0,0]Al[4739,13,1924,1924,4712,0,0]Al[4739,13,1924,1924,4714,0,0]76Ai[3954,15,1923,0,1341,0,0]Ai[4739,15,1924,0,1342,0,0]Ah[3954,5,3955,4530,0,0,0]Ah[4739,5,4740,4530,0,0,0]Ai[3954,15,3955,0,4499,0,0]Ai[3954,15,3955,0,4132,0,0]Al[4739,15,4740,3713,4500,0,0]Al[4739,15,4740,2445,4133,0,0]Ah[4739,6,4740,2445,0,0,0]Ah[4739,5,4740,1934,0,0,0]Ah[3954,5,3955,2444,0,0,0]Al[3954,15,3955,4090,4404,0,0]Ah[3954,5,1923,1924,0,0,0]Ae[4739,5,1924,0,0,0,0]Ai[3954,15,3955,0,3128,0,0]Al[4739,15,4740,1516,3129,0,0]Ai[3954,19,3955,0,4839,0,0]Ai[4739,19,4740,0,4840,0,0]Al[4739,15,4740,1907,4780,0,0]>Al[4739,15,4740,1526,3144,0,0]=5454Al[4739,15,4740,2445,4265,0,0]Ah[3954,5,3707,2493,0,0,0]Ah[4739,5,3708,2493,0,0,0]Ah[4739,5,4740,1907,0,0,0]98Ah[4739,6,4740,1075,0,0,0]:9Ah[3954,5,3955,1842,0,0,0]Ah[4739,5,4740,1842,0,0,0]Ae[4739,5,1840,0,0,0,0]Al[4739,13,4740,3713,3311,0,0]Ai[3954,14,3955,0,3316,0,0]Al[4739,14,4740,1541,3317,0,0]Al[1050,14,1051,1051,3120,0,0]Ae[4739,2,4740,0,0,0,0]Ai[3954,13,3955,0,4381,0,0]Al[4739,13,4740,1842,4382,0,0]Al[3954,12,3955,2144,4369,0,0]Ab[4310,3,0,0,0,0,0]Ak[1365,14,1366,1366,127,0,0]Al[1365,14,1540,1540,4017,0,0]98Al[3954,13,3955,2471,3338,0,0]Al[4739,13,4740,2445,3339,0,0]Ai[3954,13,3955,0,4805,0,0]Al[4739,13,4740,3293,4806,0,0];=Al[3954,13,3955,4090,4882,0,0]Al[4739,13,4740,2152,3336,0,0]Al[3954,13,3955,3712,3308,0,0]Al[3954,13,3955,3712,3310,0,0]Al[3954,13,3955,2471,2403,0,0]Ak[3954,13,3955,1049,478,0,0]Al[4739,13,4740,2445,2404,0,0]<;Ai[3954,13,3955,0,1603,0,0]Ai[3954,13,3955,0,1586,0,0]Al[4739,13,4740,1960,1604,0,0]Al[4739,13,4740,1526,1587,0,0]20Ae[1365,7,1540,0,0,0,0]?>Al[1365,14,1540,1540,1361,0,0]Ao[1050,13,1051,1051,4874,3153,0]Ai[3954,15,3955,0,3128,0,0]Ah[3954,5,3955,1516,0,0,0]Al[4739,15,4740,1516,3129,0,0]Ah[4739,5,4740,1516,0,0,0]Ah[3954,6,3955,3713,0,0,0]Ah[4739,6,4740,3713,0,0,0]Al[4739,15,4740,2445,4265,0,0]Ah[4739,5,4740,1934,0,0,0]Ah[3954,5,3955,1541,0,0,0]Ah[4739,5,4740,1541,0,0,0]97Ae[1050,5,1542,0,0,0,0]:8Ah[4739,6,4740,1907,0,0,0]Ah[3954,5,3955,1071,0,0,0]Ah[4739,5,4740,1071,0,0,0]Ah[3954,5,3955,1551,0,0,0]Ah[4739,5,4740,1551,0,0,0]Ah[3954,5,3955,3293,0,0,0]Ah[4739,5,4740,3293,0,0,0]Ai[3954,15,3955,0,4499,0,0]Al[4739,15,4740,3713,4500,0,0]Ah[3954,5,3955,3712,0,0,0]Al[3954,15,3955,4090,3148,0,0]Al[3954,15,3955,4090,3337,0,0]Al[3954,15,3955,4095,3355,0,0]Al[3954,15,3955,4095,4174,0,0]An[1365,13,1366,1366,127,4264,0]Ao[1365,13,1366,1366,3986,4264,0]Ao[3954,13,3955,3712,3310,4264,0]Ao[3954,13,3955,3712,4943,4264,0]Ao[3954,13,3955,3712,4781,4264,0]Ao[3954,13,3955,2444,2399,4264,0]Ao[3954,13,3955,2444,4267,4264,0]Ao[3954,13,3955,4090,4405,4264,0]Ao[3954,13,3955,4090,3148,4264,0]Ao[3954,13,3955,4090,3337,4264,0]Ao[3954,13,3955,4090,4404,4264,0]Ao[3954,13,3955,4095,3355,4264,0]Ao[3954,13,3955,4095,4174,4264,0]Al[3954,13,3955,0,1603,4264,0]Al[3954,13,3955,0,4940,4264,0]Al[3954,13,3955,0,1586,4264,0]Al[3954,13,3955,0,2434,4264,0]Al[3954,13,3955,0,3316,4264,0]Al[3954,13,3955,0,3145,4264,0]Al[3954,13,3955,0,4503,4264,0]Al[3954,13,3955,0,2018,4264,0]Al[3954,13,3955,0,4126,4264,0]Al[3954,13,3955,0,4499,4264,0]Al[3954,13,3955,0,4520,4264,0]Al[3954,13,3955,0,4805,4264,0]Al[3954,13,3955,0,4820,4264,0]Al[3954,13,3955,0,3999,4264,0]Al[3954,13,3955,0,4381,4264,0]Al[3954,13,3955,0,4168,4264,0]Al[3954,13,3955,0,4997,4264,0]Al[3954,13,3955,0,4120,4264,0]Al[3954,13,3955,0,3989,4264,0]Al[3954,13,3955,0,3128,4264,0]Al[3954,13,3955,0,4496,4264,0]Al[3954,13,3955,0,4684,4264,0]Al[3954,13,3955,0,4132,4264,0]Al[3954,13,3955,0,4135,4264,0]Al[3954,13,3955,0,4140,4264,0]Al[3954,13,3955,0,4839,4264,0]Al[3954,13,3955,0,3319,4264,0]Ak[3954,13,3955,0,485,4264,0]Ak[3954,13,3955,0,119,4264,0]Al[3954,13,3955,0,2422,4264,0]Ak[3954,13,3707,0,113,4264,0]Al[3954,13,3707,0,3116,4264,0]Al[3954,13,3707,0,1328,4264,0]Al[3954,13,3707,0,3994,4264,0]Al[3954,13,3707,0,1992,4264,0]Al[3954,13,3707,0,4286,4264,0]Al[3954,13,1923,0,4936,4264,0]Al[3954,13,1923,0,1341,4264,0]Ao[4739,13,4740,1960,1604,4264,0]Ao[4739,13,4740,1960,4941,4264,0]Ao[4739,13,4740,3173,4782,4264,0]Ao[4739,13,4740,1526,1587,4264,0]Ao[4739,13,4740,1526,4164,4264,0]Ao[4739,13,4740,1526,3331,4264,0]Ao[4739,13,4740,1526,3144,4264,0]Ao[4739,13,4740,1526,4836,4264,0]Ao[4739,13,4740,1526,3306,4264,0]Ao[4739,13,4740,1541,2435,4264,0]Ao[4739,13,4740,1541,3317,4264,0]Ao[4739,13,4740,1541,3146,4264,0]Ao[4739,13,4740,1541,4504,4264,0]Ao[4739,13,4740,1075,3149,4264,0]Ao[4739,13,4740,1075,4294,4264,0]Ao[4739,13,4740,1080,2019,4264,0]Ao[4739,13,4740,1080,3356,4264,0]Ao[4739,13,4740,1080,3998,4264,0]Ao[4739,13,4740,2152,4406,4264,0]Ao[4739,13,4740,2152,4130,4264,0]Ao[4739,13,4740,3713,4500,4264,0]Ao[4739,13,4740,3713,3141,4264,0]Ao[4739,13,4740,3713,4372,4264,0]Ao[4739,13,4740,3713,5024,4264,0]Ao[4739,13,4740,3293,4521,4264,0]Ao[4739,13,4740,3293,4806,4264,0]Ao[4739,13,4740,3293,4821,4264,0]Ao[4739,13,4740,3293,4000,4264,0]Ao[4739,13,4740,1842,4382,4264,0]Ao[4739,13,4740,1842,4170,4264,0]Ao[4739,13,4740,1842,4998,4264,0]Ao[4739,13,4740,1842,4122,4264,0]Ao[4739,13,4740,1842,3990,4264,0]Ao[4739,13,4740,1516,3129,4264,0]Ao[4739,13,4740,1516,3323,4264,0]Ao[4739,13,4740,1516,3345,4264,0]Ao[4739,13,4740,1516,4137,4264,0]Ao[4739,13,4740,1516,4498,4264,0]Ao[4739,13,4740,1516,4686,4264,0]Ao[4739,13,4740,1516,2393,4264,0]Ao[4739,13,4740,2445,4690,4264,0]Ao[4739,13,4740,2445,4133,4264,0]Ao[4739,13,4740,1907,4512,4264,0]Ao[4739,13,4740,1907,5027,4264,0]Ao[4739,13,4740,1907,2406,4264,0]Ao[4739,13,4740,1907,4780,4264,0]Ao[4739,13,4740,1934,4136,4264,0]Ao[4739,13,4740,1934,4141,4264,0]Al[4739,13,4740,0,4410,4264,0]Al[4739,13,4740,0,4840,4264,0]Ao[4739,13,4740,4307,3320,4264,0]Ao[4739,13,4740,4307,5120,4264,0]An[4739,13,4740,4740,486,4264,0]An[4739,13,4740,4740,120,4264,0]Ao[4739,13,4740,4740,2423,4264,0]Ao[4739,13,4740,4740,3127,4264,0]Ao[4739,13,1840,1840,4300,4264,0]Ao[4739,13,4982,4982,4881,4264,0]Ao[4739,13,4982,4982,1343,4264,0]Ao[4739,13,1924,1924,4937,4264,0]Al[4739,13,1924,0,1342,4264,0]Am[4739,13,3708,135,114,4264,0]An[4739,13,3708,135,3117,4264,0]Ao[4739,13,3708,1511,1329,4264,0]Ao[4739,13,3708,1511,3995,4264,0]Ao[4739,13,3708,2493,1993,4264,0]Ao[4739,13,3708,2493,4287,4264,0]Ao[4739,13,2123,2123,1347,4264,0]Ao[4445,13,4446,4446,2420,4264,0]Ao[4445,13,4446,4446,2433,4264,0]Ao[4445,13,4446,4446,4142,4264,0]Ao[1050,13,1051,1051,4874,4264,0]Ao[1050,13,1542,1542,4508,4264,0]Ah[3954,7,3955,2144,0,0,0]Ai[3954,13,3955,0,4381,0,0]Al[4739,13,4740,1842,4382,0,0]Ai[3954,12,1844,0,3138,0,0]Al[4739,12,1845,1845,3139,0,0]Al[4445,14,4446,4446,2420,0,0]Ai[3954,14,3955,0,3316,0,0]Al[4739,14,4740,1541,3317,0,0]10Ae[1050,7,1051,0,0,0,0]Al[3954,13,3955,2444,2399,0,0]Ae[4310,7,4311,0,0,0,0]Ae[1365,7,1366,0,0,0,0]Al[4739,13,4740,3713,3311,0,0]Al[3954,13,3955,3712,3310,0,0]1Al[4739,13,4740,2152,4406,0,0]Al[1365,13,1540,1540,1361,0,0]Al[1365,14,1540,1540,4017,0,0]Al[3954,12,3955,2144,2004,0,0]Ao[3954,13,3955,1552,4175,2004,0]Ao[3954,13,3955,1092,4012,2004,0]Ai[3954,12,1844,0,2005,0,0]Al[3954,13,1923,0,3350,2005,0]Al[4739,12,1845,1845,2006,0,0]Ao[4739,13,1924,1924,3351,2006,0]Ah[3954,5,3955,1049,0,0,0]Ai[3954,15,3955,0,3128,0,0]Ah[3954,5,3955,1516,0,0,0]Al[4739,15,4740,1516,3129,0,0]Ah[4739,5,4740,1516,0,0,0]Ai[3954,15,3955,0,4499,0,0]Al[4739,15,4740,3713,4500,0,0]Ah[4739,5,4740,2445,0,0,0]Al[4739,15,4740,3713,1346,0,0]Ai[3954,15,3955,0,4132,0,0]Al[4739,15,4740,2445,4133,0,0]Ai[3954,19,3955,0,4839,0,0]Ai[4739,19,4740,0,4840,0,0]Ai[3954,15,1923,0,1341,0,0]Ai[4739,15,1924,0,1342,0,0]32Al[4739,15,4740,3713,3141,0,0]><><><21Ah[3954,5,1923,1924,0,0,0]Ae[4739,5,1924,0,0,0,0]10Ah[3954,5,3955,4870,0,0,0]Ah[4739,5,4740,4870,0,0,0]Al[4739,15,2123,2123,1344,0,0]5Al[4739,15,4740,1907,4512,0,0]Ai[3954,12,3955,0,2427,0,0]Al[3954,13,3955,0,4258,2427,0]Al[3954,13,3955,0,4152,2427,0]Al[4739,12,4740,1551,2428,0,0]Ao[4739,13,4740,4530,4259,2428,0]Ao[4739,13,4740,1551,4153,2428,0]Ae[4023,7,4024,0,0,0,0]Al[3954,13,3955,3712,3310,0,0]Al[4739,13,4740,3713,3311,0,0]Ai[3954,14,3955,0,3316,0,0]Al[4739,14,4740,1541,3317,0,0]32An[1365,13,1366,1366,127,4383,0]Ao[1050,13,1051,1051,3120,4383,0]An[1050,13,1834,1834,128,4383,0]An[1050,13,1929,1929,129,4383,0]An[3974,13,3975,3975,118,4383,0]Ao[3974,13,3975,3975,2390,4383,0]Ab[4739,3,0,0,0,0,0]Ak[4445,13,4446,393,4411,0,0]Ai[3954,13,3955,0,4520,0,0]Al[4739,13,4740,3293,4521,0,0];:Al[3954,13,3955,2444,2399,0,0]Al[4739,13,4740,2445,2400,0,0]?>32Ae[4310,7,4311,0,0,0,0]5Al[1050,14,1051,1051,3120,0,0]60Ae[1365,7,1366,0,0,0,0]Ai[3954,13,3955,0,4168,0,0]Ai[3954,13,3955,0,4120,0,0]Al[4739,13,4740,1842,4170,0,0]Al[4739,13,4740,1842,4122,0,0]Ai[3954,14,3955,0,4168,0,0]Al[4739,14,4740,1842,4170,0,0]53Al[3954,13,3955,4095,3341,0,0]Ai[3954,19,3955,0,4839,0,0]Ai[4739,19,4740,0,4840,0,0]Ai[3954,15,3955,0,4499,0,0]Al[4739,15,4740,3713,4500,0,0]Ai[3954,10,3707,3708,0,0,0]Af[4739,10,3708,0,0,0,0]Ah[3954,5,3707,3708,0,0,0]Ae[4739,5,3708,0,0,0,0]Ai[3954,10,1844,1845,0,0,0]Af[4739,10,1845,0,0,0,0]Ai[3954,15,3955,0,4132,0,0]Al[4739,15,4740,2445,4133,0,0]Ah[4739,6,4740,1907,0,0,0]Ah[3954,6,3955,3712,0,0,0]Ah[4739,6,4740,3173,0,0,0]Ai[3954,15,3955,0,3128,0,0]Al[4739,15,4740,1516,3129,0,0]10Al[3954,15,3955,3712,4781,0,0]Al[4739,15,4740,3173,4782,0,0]Ai[3954,14,3955,0,3145,0,0]Al[4739,14,4740,1541,3146,0,0]Ai[3954,14,3707,0,4773,0,0]Al[4739,14,3708,3708,4774,0,0]Al[3954,13,3955,3712,3310,0,0]Ai[3954,14,3955,0,3316,0,0]Al[4739,14,4740,1541,3317,0,0]10Al[4739,13,4740,3173,3123,0,0]Al[3954,13,3955,2444,2399,0,0]Al[4739,13,4740,2445,2400,0,0]Ab[4800,3,0,0,0,0,0]Ao[1050,13,1051,1051,4874,3153,0]Ai[3954,19,3955,0,4839,0,0]Ai[4739,19,4740,0,4840,0,0]Ah[3954,5,3955,3293,0,0,0]Ah[4739,5,4740,3293,0,0,0]Ai[3954,15,1923,0,1341,0,0]Ai[4739,15,1924,0,1342,0,0]54Ai[4739,10,4740,1907,0,0,0]Al[4739,15,4740,3713,1346,0,0]7600Al[4739,15,4740,1075,4294,0,0]4365Al[4739,15,2123,2123,1344,0,0]Ae[1050,9,1051,0,0,0,0]:9Ai[3954,15,3955,0,3128,0,0]Al[4739,15,4740,1516,3129,0,0]<;<;Ah[4739,6,4740,1526,0,0,0]21Ae[3954,5,3955,0,0,0,0]Ae[4739,5,4740,0,0,0,0]Ai[3954,15,3955,0,4132,0,0]Ah[3954,5,1844,1845,0,0,0]Al[4739,15,4740,2445,4133,0,0]Al[4739,15,4740,1907,4780,0,0]Ae[4739,5,1845,0,0,0,0]An[1365,13,1366,1366,127,4373,0]Ao[1050,13,1051,1051,3120,4373,0]An[1050,13,1834,1834,128,4373,0]An[1050,13,1929,1929,129,4373,0]An[3974,13,3975,3975,118,4373,0]Ai[3954,13,3955,0,4520,0,0]Al[4739,13,4740,3293,4521,0,0]Ai[3954,13,3955,0,1603,0,0]Al[4739,13,4740,1960,1604,0,0]Al[3954,14,3955,2444,4267,0,0]Ai[3954,13,3955,0,4381,0,0]Al[4739,13,4740,1842,4382,0,0]Ai[3954,13,3955,0,4258,0,0]Al[4739,13,4740,4530,4259,0,0]Ai[3954,14,3955,0,3316,0,0]Al[4739,14,4740,1541,3317,0,0]6Al[4739,13,4740,3713,3311,0,0]Al[3954,13,3955,3712,3310,0,0]0176Ao[4023,13,4024,4024,5028,4834,0]Ai[3954,13,3955,0,4513,0,0]Al[4739,13,4740,1071,4514,0,0]Ae[1050,6,1051,0,0,0,0]Ai[3954,15,3955,0,3128,0,0]Al[4739,15,4740,1516,3129,0,0]10Al[4739,15,4740,3713,3141,0,0]Ae[4739,5,4982,0,0,0,0]Ah[3954,5,3955,4090,0,0,0]Ai[3954,15,1923,0,1341,0,0]Ai[4739,15,1924,0,1342,0,0]Al[4739,15,2123,2123,1344,0,0]Al[3954,14,3955,2444,4267,0,0]Ak[3954,13,3955,0,485,3110,0]Ak[3954,13,3955,0,119,3110,0]Al[3954,13,3955,0,2422,3110,0]An[4739,13,4740,4740,486,3110,0]An[4739,13,4740,4740,120,3110,0]Ao[4739,13,4740,4740,2423,3110,0]Ao[3974,13,3975,3975,2390,3346,0]Ai[3954,13,3955,0,4820,0,0]Al[4739,13,4740,3293,4821,0,0]Ai[3954,12,1844,0,2005,0,0]Al[3954,13,1923,0,3350,2005,0]Al[4739,12,1845,1845,2006,0,0]Ao[4739,13,1924,1924,3351,2006,0]Al[3954,13,3955,3712,3310,0,0]Ai[3954,13,3955,0,4520,0,0]Al[4739,13,4740,3293,4521,0,0]Ai[3954,14,3955,0,3145,0,0]Al[4739,14,4740,1541,3146,0,0]Ai[3954,12,3707,0,3312,0,0]Ak[3954,13,3707,0,113,3312,0]Al[3954,13,3707,0,1328,3312,0]Al[3954,13,3707,0,1992,3312,0]Al[4739,12,3708,3708,3313,0,0]Am[4739,13,3708,135,114,3313,0]Ao[4739,13,3708,1511,1329,3313,0]Ao[4739,13,3708,2493,1993,3313,0]Al[3954,14,3955,2444,4267,0,0]Al[4739,13,4740,2152,2012,0,0]Ah[4739,2,4305,4094,0,0,0]Ae[1365,7,1366,0,0,0,0]==Ak[3954,13,3955,1049,478,0,0]Ak[4445,13,4446,393,4411,0,0]032Ai[3954,12,1844,0,2005,0,0]Al[3954,13,1923,0,3350,2005,0]Ae[4739,2,4740,0,0,0,0]Al[4739,12,1845,1845,2006,0,0]Ao[4739,13,1924,1924,3351,2006,0]Ai[3954,10,3955,4307,0,0,0]Ai[4739,10,4740,4307,0,0,0]Ai[3954,15,1923,0,1341,0,0]Ai[4739,15,1924,0,1342,0,0]Ai[3954,15,3955,0,4132,0,0]Al[4739,15,4740,2445,4133,0,0]Ai[3954,19,3955,0,4839,0,0]Ai[4739,19,4740,0,4840,0,0]Ah[3954,5,3955,1842,0,0,0]Ah[4739,5,4740,1842,0,0,0]Ai[3954,12,1844,0,3138,0,0]Al[4739,12,1845,1845,3139,0,0]Al[4739,13,4740,2445,2400,0,0]Al[4739,13,4740,4740,3127,0,0]Al[4739,13,4740,3713,3311,0,0]Ai[3954,13,3707,0,4286,0,0]Al[4739,13,3708,2493,4287,0,0]Al[3954,13,3955,2144,3151,0,0]0Al[3954,13,3955,3712,3310,0,0]4Ai[3954,14,3955,0,3316,0,0]Al[4739,14,4740,1541,3317,0,0]Ai[3954,13,3955,0,4520,0,0]Al[4739,13,4740,3293,4521,0,0]Al[1050,14,1051,1051,3120,0,0]Ai[3954,19,3955,0,4839,0,0]Ai[4739,19,4740,0,4840,0,0]Al[4739,15,2123,2123,1344,0,0]Ai[3954,15,1923,0,1341,0,0]Ai[4739,15,1924,0,1342,0,0]10Al[4739,15,4740,1526,4836,0,0]Al[4739,15,4740,3713,3141,0,0]Ah[4739,5,4740,3713,0,0,0]Ai[3954,15,3955,0,3128,0,0]Al[4739,15,4740,1516,3129,0,0]Ah[4739,5,4740,1907,0,0,0]Ae[4023,5,4024,0,0,0,0]Al[1050,13,1051,1051,3120,0,0]Al[3954,13,3955,3712,3310,0,0]Ai[3954,12,1844,0,2005,0,0]Al[3954,13,1923,0,3350,2005,0]Al[4739,12,1845,1845,2006,0,0]Ao[4739,13,1924,1924,3351,2006,0]Ah[4739,7,4916,4915,0,0,0]0Al[4739,13,4740,3713,3311,0,0]6Ak[3954,13,3955,1049,478,0,0]Ai[3954,14,3955,0,3316,0,0]Al[4739,14,4740,1541,3317,0,0]Ao[4023,13,4024,4024,5028,4834,0]0Ai[3954,13,3955,0,4120,0,0]Al[4739,13,4740,1842,4122,0,0]Ai[3954,15,1923,0,1341,0,0]Ai[4739,15,1924,0,1342,0,0]10Ai[3954,13,3955,0,4805,0,0]Al[4739,13,4740,3293,4806,0,0]Am[1365,13,1366,1366,127,460,0]An[1050,13,1051,1051,3120,460,0]Am[1050,13,1834,1834,128,460,0]Am[1050,13,1929,1929,129,460,0]Am[3974,13,3975,3975,118,460,0]??>An[1365,13,1366,1366,127,4383,0]Ao[1050,13,1051,1051,3120,4383,0]An[1050,13,1834,1834,128,4383,0]An[1050,13,1929,1929,129,4383,0]An[3974,13,3975,3975,118,4383,0]Ao[3974,13,3975,3975,2390,4383,0]Ai[3954,13,3955,0,4168,0,0]Al[4739,13,4740,1842,4170,0,0]Ai[3954,19,3955,0,4839,0,0]Ai[4739,19,4740,0,4840,0,0]Ae[1050,5,4227,0,0,0,0]0Ai[3954,13,3955,0,4381,0,0]Al[4739,13,4740,1842,4382,0,0]Ai[3954,13,3955,0,4120,0,0]Al[4739,13,4740,1842,4122,0,0]Al[3954,13,3955,2444,2399,0,0]Al[3954,13,3955,2471,2403,0,0]Al[4739,13,4740,2445,2404,0,0]Al[4739,13,4740,3713,3311,0,0]Ao[4023,13,4024,4024,5028,4834,0];:Ah[3954,5,1844,1845,0,0,0]Ae[4739,5,1845,0,0,0,0]Ai[3954,15,1923,0,1341,0,0]Ai[4739,15,1924,0,1342,0,0]?>?>Al[3954,13,3955,3712,3310,0,0]6Ai[3954,13,3955,0,4520,0,0]Al[4739,13,4740,3293,4521,0,0]Ae[4023,7,4024,0,0,0,0]Ae[4310,7,4311,0,0,0,0]Ai[3954,14,3955,0,3316,0,0]Al[4739,14,4740,1541,3317,0,0]?=Ai[3954,19,3955,0,4839,0,0]Ai[4739,19,4740,0,4840,0,0]2=<==<>=>=>=<;<;Al[4739,14,4982,4982,4881,0,0]?>Ai[4739,18,4740,3293,0,0,0]") \ No newline at end of file +rd_("Ah[3954,15,3955,0,119,0,0]Ak[4739,15,4740,4740,120,0,0]Ai[3954,15,3955,0,4140,0,0]Al[4739,15,4740,1934,4141,0,0]Al[4445,15,4446,4446,4142,0,0]Al[4739,15,1840,1840,1593,0,0]Ao[1365,13,1366,1366,3986,3140,0]Ao[3954,13,3955,3712,4781,3140,0]Ao[3954,13,3955,4090,4405,3140,0]Ao[3954,13,3955,4090,3148,3140,0]Ao[3954,13,3955,4090,3337,3140,0]Ao[3954,13,3955,4090,4404,3140,0]Ao[3954,13,3955,4095,3355,3140,0]Ao[3954,13,3955,4095,4174,3140,0]Al[3954,13,3955,0,1603,3140,0]Al[3954,13,3955,0,4940,3140,0]Al[3954,13,3955,0,1324,3140,0]Al[3954,13,3955,0,1586,3140,0]Al[3954,13,3955,0,2434,3140,0]Al[3954,13,3955,0,3145,3140,0]Al[3954,13,3955,0,2018,3140,0]Al[3954,13,3955,0,4126,3140,0]Al[3954,13,3955,0,4499,3140,0]Al[3954,13,3955,0,3999,3140,0]Al[3954,13,3955,0,3989,3140,0]Al[3954,13,3955,0,3128,3140,0]Al[3954,13,3955,0,4496,3140,0]Al[3954,13,3955,0,4684,3140,0]Al[3954,13,3955,0,4132,3140,0]Al[3954,13,3955,0,4135,3140,0]Al[3954,13,3955,0,4140,3140,0]Al[3954,13,3955,0,4839,3140,0]Ak[3954,13,3955,0,485,3140,0]Ak[3954,13,3955,0,119,3140,0]Al[3954,13,3955,0,2422,3140,0]Al[3954,13,1844,0,5086,3140,0]Al[3954,13,1923,0,1341,3140,0]Ao[4739,13,4740,1960,1604,3140,0]Ao[4739,13,4740,1960,4941,3140,0]Ao[4739,13,4740,3164,1325,3140,0]Ao[4739,13,4740,3173,4782,3140,0]Ao[4739,13,4740,1526,1587,3140,0]Ao[4739,13,4740,1526,3331,3140,0]Ao[4739,13,4740,1526,3144,3140,0]Ao[4739,13,4740,1526,4836,3140,0]Ao[4739,13,4740,1526,3306,3140,0]Ao[4739,13,4740,1542,2435,3140,0]Ao[4739,13,4740,1542,3146,3140,0]Ao[4739,13,4740,1075,3149,3140,0]Ao[4739,13,4740,1075,4294,3140,0]Ao[4739,13,4740,1080,2019,3140,0]Ao[4739,13,4740,1080,3356,3140,0]Ao[4739,13,4740,1080,3998,3140,0]Ao[4739,13,4740,2152,4016,3140,0]Ao[4739,13,4740,2152,4406,3140,0]Ao[4739,13,4740,2152,4130,3140,0]Ao[4739,13,4740,3713,4500,3140,0]Ao[4739,13,4740,3713,3141,3140,0]Ao[4739,13,4740,3713,4372,3140,0]Ao[4739,13,4740,3293,4000,3140,0]Ao[4739,13,4740,1842,3990,3140,0]Ao[4739,13,4740,1516,3129,3140,0]Ao[4739,13,4740,1516,4387,3140,0]Ao[4739,13,4740,1516,3323,3140,0]Ao[4739,13,4740,1516,3345,3140,0]Ao[4739,13,4740,1516,4137,3140,0]Ao[4739,13,4740,1516,4498,3140,0]Ao[4739,13,4740,1516,4686,3140,0]Ao[4739,13,4740,2445,4690,3140,0]Ao[4739,13,4740,2445,4133,3140,0]Ao[4739,13,4740,1907,2406,3140,0]Ao[4739,13,4740,1907,4780,3140,0]Ao[4739,13,4740,1934,4136,3140,0]Ao[4739,13,4740,1934,4141,3140,0]Al[4739,13,4740,0,4410,3140,0]Al[4739,13,4740,0,4840,3140,0]An[4739,13,4740,4740,486,3140,0]An[4739,13,4740,4740,120,3140,0]Ao[4739,13,4740,4740,2423,3140,0]Ao[4739,13,4740,4740,3127,3140,0]Ao[4739,13,1840,1840,4300,3140,0]Ao[4739,13,4982,4982,4881,3140,0]Ao[4739,13,4982,4982,1343,3140,0]Ao[4739,13,1845,1845,5087,3140,0]Al[4739,13,1924,0,1342,3140,0]Ao[4445,13,4446,4446,4142,3140,0]Ak[3954,13,3955,1049,478,0,0]Al[3954,13,3955,4090,3335,0,0]Al[3954,13,3955,4090,4882,0,0]Al[3954,13,3955,4095,3341,0,0]Ai[4739,14,3142,0,1580,0,0]Ai[4739,14,3142,0,1570,0,0]Ai[4739,14,3142,0,3107,0,0]Ai[4739,14,3142,0,4277,0,0]Ai[4739,14,3142,0,4161,0,0]Ai[4739,14,3142,0,4154,0,0]Ai[4739,14,4015,0,2416,0,0]Ai[4739,14,4015,0,2437,0,0]Ai[4739,14,4015,0,2401,0,0]Ai[4739,14,4015,0,2007,0,0]Ae[1365,7,1366,0,0,0,0]Ah[4739,14,4511,0,474,0,0]Ai[3954,15,3955,0,3128,0,0]Al[4739,15,4740,1516,3129,0,0]Ag[3954,5,3707,135,0,0,0]Ag[4739,5,3708,135,0,0,0]Al[1050,15,1051,1051,4874,0,0]Ae[3974,5,3975,0,0,0,0]Ah[3954,6,3955,4740,0,0,0]Ae[4739,6,4740,0,0,0,0]Al[4739,15,1840,1840,1593,0,0]Ai[3954,19,3955,0,1603,0,0]Ai[3954,19,3955,0,1586,0,0]Al[4739,19,4740,1960,1604,0,0]Al[4739,19,4740,1526,1587,0,0]Ae[1365,5,1366,0,0,0,0]Ae[1050,5,1834,0,0,0,0]Ae[1050,5,1929,0,0,0,0]Ah[3954,15,3955,0,119,0,0]Ak[4739,15,4740,4740,120,0,0]Ak[3954,13,3955,0,1603,130,0]Ak[3954,13,3955,0,1586,130,0]Ak[3954,13,3955,0,3999,130,0]Ak[3954,13,3955,0,4135,130,0]Aj[3954,13,3955,0,485,130,0]Aj[3954,13,3955,0,119,130,0]Ak[3954,13,3955,0,2422,130,0]An[4739,13,4740,1960,1604,130,0]An[4739,13,4740,3173,4782,130,0]An[4739,13,4740,1526,1587,130,0]An[4739,13,4740,1075,3149,130,0]An[4739,13,4740,1075,4294,130,0]An[4739,13,4740,1080,3356,130,0]An[4739,13,4740,3293,4000,130,0]An[4739,13,4740,2445,4690,130,0]An[4739,13,4740,1907,4780,130,0]An[4739,13,4740,1934,4136,130,0]Am[4739,13,4740,4740,486,130,0]Am[4739,13,4740,4740,120,130,0]An[4739,13,4740,4740,2423,130,0]Ai[3954,13,3955,0,2422,0,0]Al[4739,13,4740,4740,2423,0,0]Ai[4739,14,4015,0,1581,0,0]Ai[4739,14,4015,0,3113,0,0]Ai[3954,14,3955,0,2431,0,0]Al[4739,14,4740,4740,2432,0,0]Al[4445,14,4446,4446,2420,0,0]Al[4445,14,4446,4446,2433,0,0]An[1365,13,1366,1366,127,1331,0]Ao[1365,13,1366,1366,3986,1331,0]Ao[1365,13,1540,1540,4407,1331,0]Ao[4023,13,4024,4024,5028,1331,0]Ao[3954,13,3955,3712,3308,1331,0]Ao[3954,13,3955,3712,3310,1331,0]Ao[3954,13,3955,3712,4943,1331,0]Dd[3954,13,3955,3712,4781,1979,0,\"impl-Display-for-SendDatagramError\"]Db[3954,13,3955,3712,4781,1331,0,\"impl-Debug-for-SendDatagramError\"]Ao[3954,13,3955,2444,2399,1331,0]Ao[3954,13,3955,2444,4267,1331,0]Ao[3954,13,3955,2471,2403,1331,0]Cm[3954,13,3955,2471,3338,1979,0,\"impl-Display-for-RetryError\"]Ck[3954,13,3955,2471,3338,1331,0,\"impl-Debug-for-RetryError\"]Ao[3954,13,3955,2471,4386,1331,0]An[3954,13,3955,1049,478,1331,0]Ao[3954,13,3955,4090,3335,1331,0]Ao[3954,13,3955,4090,4882,1331,0]Da[3954,13,3955,4090,4405,1979,0,\"impl-Display-for-ReadToEndError\"]Co[3954,13,3955,4090,4405,1331,0,\"impl-Debug-for-ReadToEndError\"]Cj[3954,13,3955,4090,3148,1331,0,\"impl-Debug-for-ReadError\"]Cl[3954,13,3955,4090,3148,1979,0,\"impl-Display-for-ReadError\"]Cm[3954,13,3955,4090,3337,1979,0,\"impl-Display-for-ResetError\"]Ck[3954,13,3955,4090,3337,1331,0,\"impl-Debug-for-ResetError\"]Co[3954,13,3955,4090,4404,1331,0,\"impl-Debug-for-ReadExactError\"]Da[3954,13,3955,4090,4404,1979,0,\"impl-Display-for-ReadExactError\"]Ao[3954,13,3955,1552,4175,1331,0]Ao[3954,13,3955,1092,4012,1331,0]Ao[3954,13,3955,4095,3341,1331,0]Cm[3954,13,3955,4095,3355,1979,0,\"impl-Display-for-WriteError\"]Ck[3954,13,3955,4095,3355,1331,0,\"impl-Debug-for-WriteError\"]Co[3954,13,3955,4095,4174,1979,0,\"impl-Display-for-StoppedError\"]Cm[3954,13,3955,4095,4174,1331,0,\"impl-Debug-for-StoppedError\"]Cf[3954,13,3955,0,1603,1979,0,\"impl-Display-for-VarInt\"]Cd[3954,13,3955,0,1603,1331,0,\"impl-Debug-for-VarInt\"]Db[3954,13,3955,0,4940,1331,0,\"impl-Debug-for-VarIntBoundsExceeded\"]Dd[3954,13,3955,0,4940,1979,0,\"impl-Display-for-VarIntBoundsExceeded\"]Al[3954,13,3955,0,1324,1331,0]Cf[3954,13,3955,0,1586,1979,0,\"impl-Display-for-PathId\"]Cd[3954,13,3955,0,1586,1331,0,\"impl-Debug-for-PathId\"]Al[3954,13,3955,0,2434,1331,0]Al[3954,13,3955,0,3316,1331,0]Al[3954,13,3955,0,3145,1331,0]Al[3954,13,3955,0,4503,1331,0]Al[3954,13,3955,0,2018,1331,0]Cj[3954,13,3955,0,4126,1331,0,\"impl-Debug-for-ClosedStream\"]Cl[3954,13,3955,0,4126,1979,0,\"impl-Display-for-ClosedStream\"]Cm[3954,13,3955,0,4499,1331,0,\"impl-Debug-for-ConnectionError\"]Co[3954,13,3955,0,4499,1979,0,\"impl-Display-for-ConnectionError\"]Al[3954,13,3955,0,4513,1331,0]Al[3954,13,3955,0,4520,1331,0]Al[3954,13,3955,0,4805,1331,0]Al[3954,13,3955,0,4820,1331,0]Al[3954,13,3955,0,3999,1331,0]Al[3954,13,3955,0,4381,1331,0]Al[3954,13,3955,0,4168,1331,0]Al[3954,13,3955,0,4997,1331,0]Al[3954,13,3955,0,4120,1331,0]Ck[3954,13,3955,0,3989,1979,0,\"impl-Display-for-ConfigError\"]Ci[3954,13,3955,0,3989,1331,0,\"impl-Debug-for-ConfigError\"]Cg[3954,13,3955,0,3128,1331,0,\"impl-Debug-for-FrameType\"]Ci[3954,13,3955,0,3128,1979,0,\"impl-Display-for-FrameType\"]Co[3954,13,3955,0,4496,1979,0,\"impl-Display-for-ConnectionClose\"]Cm[3954,13,3955,0,4496,1331,0,\"impl-Debug-for-ConnectionClose\"]Cn[3954,13,3955,0,4684,1331,0,\"impl-Debug-for-ApplicationClose\"]D`[3954,13,3955,0,4684,1979,0,\"impl-Display-for-ApplicationClose\"]Cj[3954,13,3955,0,4132,1331,0,\"impl-Debug-for-ConnectError\"]Cl[3954,13,3955,0,4132,1979,0,\"impl-Display-for-ConnectError\"]Cl[3954,13,3955,0,4135,1979,0,\"impl-Display-for-ConnectionId\"]Cj[3954,13,3955,0,4135,1331,0,\"impl-Debug-for-ConnectionId\"]Al[3954,13,3955,0,4140,1331,0]D`[3954,13,3955,0,4839,1331,0,\"impl-Debug-for-TransportErrorCode\"]Db[3954,13,3955,0,4839,1979,0,\"impl-Display-for-TransportErrorCode\"]Al[3954,13,3955,0,3319,1331,0]Al[3954,13,3955,0,4715,1331,0]Ak[3954,13,3955,0,485,1331,0]Cb[3954,13,3955,0,119,1979,0,\"impl-Display-for-Dir\"]C`[3954,13,3955,0,119,1331,0,\"impl-Debug-for-Dir\"]Cf[3954,13,3955,0,2422,1331,0,\"impl-Debug-for-StreamId\"]Ch[3954,13,3955,0,2422,1979,0,\"impl-Display-for-StreamId\"]Al[3954,13,3955,0,2431,1331,0]Ak[3954,13,3707,0,113,1331,0]Al[3954,13,3707,0,3116,1331,0]Al[3954,13,3707,0,1328,1331,0]Al[3954,13,3707,0,3994,1331,0]Al[3954,13,3707,0,1992,1331,0]Al[3954,13,3707,0,4286,1331,0]Al[3954,13,3707,0,4773,1331,0]Al[3954,13,1844,0,5086,1331,0]Al[3954,13,1844,0,3992,1331,0]Al[3954,13,1844,0,4843,1331,0]Dd[3954,13,1923,0,4936,1979,0,\"impl-Display-for-NoInitialCipherSuite\"]Db[3954,13,1923,0,4936,1331,0,\"impl-Debug-for-NoInitialCipherSuite\"]Cc[3954,13,1923,0,1341,1331,0,\"impl-Debug-for-Error\"]Ce[3954,13,1923,0,1341,1979,0,\"impl-Display-for-Error\"]Ao[4739,13,4740,3713,3311,1331,0]Ao[4739,13,4740,2445,2400,1331,0]Ci[4739,13,4740,1960,1604,1979,0,\"impl-Display-for-VarInt\"]Cg[4739,13,4740,1960,1604,1331,0,\"impl-Debug-for-VarInt\"]Dg[4739,13,4740,1960,4941,1979,0,\"impl-Display-for-VarIntBoundsExceeded\"]De[4739,13,4740,1960,4941,1331,0,\"impl-Debug-for-VarIntBoundsExceeded\"]Ao[4739,13,4740,3164,1325,1331,0]Db[4739,13,4740,3173,4782,1331,0,\"impl-Debug-for-SendDatagramError\"]Dd[4739,13,4740,3173,4782,1979,0,\"impl-Display-for-SendDatagramError\"]Ci[4739,13,4740,1526,1587,1979,0,\"impl-Display-for-PathId\"]Cg[4739,13,4740,1526,1587,1331,0,\"impl-Debug-for-PathId\"]Ao[4739,13,4740,1526,4164,1331,0]Ao[4739,13,4740,1526,3331,1331,0]Ao[4739,13,4740,1526,3144,1331,0]Dc[4739,13,4740,1526,4836,1331,0,\"impl-Debug-for-SetPathStatusError\"]De[4739,13,4740,1526,4836,1979,0,\"impl-Display-for-SetPathStatusError\"]Cm[4739,13,4740,1526,3306,1979,0,\"impl-Display-for-ClosedPath\"]Ck[4739,13,4740,1526,3306,1331,0,\"impl-Debug-for-ClosedPath\"]Ao[4739,13,4740,1542,2435,1331,0]Ao[4739,13,4740,1542,3317,1331,0]Ao[4739,13,4740,1542,3146,1331,0]Ao[4739,13,4740,1542,4504,1331,0]Cl[4739,13,4740,1075,3149,1979,0,\"impl-Display-for-ReadError\"]Cj[4739,13,4740,1075,3149,1331,0,\"impl-Debug-for-ReadError\"]D`[4739,13,4740,1075,4294,1979,0,\"impl-Display-for-ReadableError\"]Cn[4739,13,4740,1075,4294,1331,0,\"impl-Debug-for-ReadableError\"]Ao[4739,13,4740,1080,2019,1331,0]Cm[4739,13,4740,1080,3356,1979,0,\"impl-Display-for-WriteError\"]Ck[4739,13,4740,1080,3356,1331,0,\"impl-Debug-for-WriteError\"]Cl[4739,13,4740,1080,3998,1331,0,\"impl-Debug-for-FinishError\"]Cn[4739,13,4740,1080,3998,1979,0,\"impl-Display-for-FinishError\"]Ao[4739,13,4740,2152,4016,1331,0]Ao[4739,13,4740,2152,4406,1331,0]Co[4739,13,4740,2152,4130,1979,0,\"impl-Display-for-ClosedStream\"]Cm[4739,13,4740,2152,4130,1331,0,\"impl-Debug-for-ClosedStream\"]D`[4739,13,4740,3713,4500,1331,0,\"impl-Debug-for-ConnectionError\"]Db[4739,13,4740,3713,4500,1979,0,\"impl-Display-for-ConnectionError\"]Cj[4739,13,4740,3713,3141,1331,0,\"impl-Debug-for-PathError\"]Cl[4739,13,4740,3713,3141,1979,0,\"impl-Display-for-PathError\"]Co[4739,13,4740,3713,4372,1331,0,\"impl-Debug-for-ClosePathError\"]Da[4739,13,4740,3713,4372,1979,0,\"impl-Display-for-ClosePathError\"]Di[4739,13,4740,3713,5024,1979,0,\"impl-Display-for-MultipathNotNegotiated\"]Dg[4739,13,4740,3713,5024,1331,0,\"impl-Debug-for-MultipathNotNegotiated\"]Ao[4739,13,4740,3713,1346,1331,0]Ao[4739,13,4740,1071,4514,1331,0]Ao[4739,13,4740,3293,4521,1331,0]Ao[4739,13,4740,3293,4806,1331,0]Ao[4739,13,4740,3293,4821,1331,0]Ao[4739,13,4740,3293,4000,1331,0]Ao[4739,13,4740,1842,4382,1331,0]Ao[4739,13,4740,1842,4170,1331,0]Ao[4739,13,4740,1842,4998,1331,0]Ao[4739,13,4740,1842,4122,1331,0]Cn[4739,13,4740,1842,3990,1979,0,\"impl-Display-for-ConfigError\"]Cl[4739,13,4740,1842,3990,1331,0,\"impl-Debug-for-ConfigError\"]Cj[4739,13,4740,1516,3129,1331,0,\"impl-Debug-for-FrameType\"]Cl[4739,13,4740,1516,3129,1979,0,\"impl-Display-for-FrameType\"]Co[4739,13,4740,1516,4387,1331,0,\"impl-Debug-for-InvalidFrameId\"]Da[4739,13,4740,1516,4387,1979,0,\"impl-Display-for-InvalidFrameId\"]Cm[4739,13,4740,1516,3323,1979,0,\"impl-Display-for-MaybeFrame\"]Ck[4739,13,4740,1516,3323,1331,0,\"impl-Debug-for-MaybeFrame\"]Cm[4739,13,4740,1516,3345,1979,0,\"impl-Display-for-StreamInfo\"]Ck[4739,13,4740,1516,3345,1331,0,\"impl-Debug-for-StreamInfo\"]Co[4739,13,4740,1516,4137,1979,0,\"impl-Display-for-DatagramInfo\"]Cm[4739,13,4740,1516,4137,1331,0,\"impl-Debug-for-DatagramInfo\"]Db[4739,13,4740,1516,4498,1979,0,\"impl-Display-for-ConnectionClose\"]D`[4739,13,4740,1516,4498,1331,0,\"impl-Debug-for-ConnectionClose\"]Da[4739,13,4740,1516,4686,1331,0,\"impl-Debug-for-ApplicationClose\"]Dc[4739,13,4740,1516,4686,1979,0,\"impl-Display-for-ApplicationClose\"]Ck[4739,13,4740,1516,2393,1979,0,\"impl-Display-for-Datagram\"]Ci[4739,13,4740,1516,2393,1331,0,\"impl-Debug-for-Datagram\"]Ao[4739,13,4740,2445,4690,1331,0]Ao[4739,13,4740,2445,2404,1331,0]Cm[4739,13,4740,2445,4133,1331,0,\"impl-Debug-for-ConnectError\"]Co[4739,13,4740,2445,4133,1979,0,\"impl-Display-for-ConnectError\"]Ao[4739,13,4740,2445,3984,1331,0]Ck[4739,13,4740,2445,3339,1331,0,\"impl-Debug-for-RetryError\"]Cm[4739,13,4740,2445,3339,1979,0,\"impl-Display-for-RetryError\"]Ao[4739,13,4740,1907,4289,1331,0]Ao[4739,13,4740,1907,4512,1331,0]Ao[4739,13,4740,1907,5027,1331,0]Ao[4739,13,4740,1907,2406,1331,0]Db[4739,13,4740,1907,4780,1331,0,\"impl-Debug-for-PacketDecodeError\"]Dd[4739,13,4740,1907,4780,1979,0,\"impl-Display-for-PacketDecodeError\"]Ao[4739,13,4740,1934,4502,1331,0]Ao[4739,13,4740,1934,4266,1331,0]Co[4739,13,4740,1934,4136,1979,0,\"impl-Display-for-ConnectionId\"]Cm[4739,13,4740,1934,4136,1331,0,\"impl-Debug-for-ConnectionId\"]Ao[4739,13,4740,1934,4141,1331,0]Ce[4739,13,4740,0,4410,1979,0,\"impl-Display-for-Error\"]Cc[4739,13,4740,0,4410,1331,0,\"impl-Debug-for-Error\"]Cb[4739,13,4740,0,4840,1331,0,\"impl-Debug-for-Code\"]Cd[4739,13,4740,0,4840,1979,0,\"impl-Display-for-Code\"]Ao[4739,13,4740,4307,3320,1331,0]Ao[4739,13,4740,4307,5120,1331,0]Ao[4739,13,4740,4870,4716,1331,0]An[4739,13,4740,4740,486,1331,0]Ce[4739,13,4740,4740,120,1979,0,\"impl-Display-for-Dir\"]Cc[4739,13,4740,4740,120,1331,0,\"impl-Debug-for-Dir\"]Ck[4739,13,4740,4740,2423,1979,0,\"impl-Display-for-StreamId\"]Ci[4739,13,4740,4740,2423,1331,0,\"impl-Debug-for-StreamId\"]Ao[4739,13,4740,4740,2432,1331,0]Cj[4739,13,4740,4740,3127,1331,0,\"impl-Debug-for-FourTuple\"]Cl[4739,13,4740,4740,3127,1979,0,\"impl-Display-for-FourTuple\"]D`[4739,13,1840,1840,4300,1979,0,\"impl-Display-for-UnexpectedEnd\"]Cn[4739,13,1840,1840,4300,1331,0,\"impl-Debug-for-UnexpectedEnd\"]Ao[4739,13,4982,4982,4881,1331,0]Cf[4739,13,4982,4982,1343,1331,0,\"impl-Debug-for-Error\"]Ch[4739,13,4982,4982,1343,1979,0,\"impl-Display-for-Error\"]Ao[4739,13,1845,1845,5087,1331,0]Ao[4739,13,1845,1845,3993,1331,0]Ao[4739,13,1845,1845,4846,1331,0]Dg[4739,13,1924,1924,4937,1979,0,\"impl-Display-for-NoInitialCipherSuite\"]De[4739,13,1924,1924,4937,1331,0,\"impl-Debug-for-NoInitialCipherSuite\"]Ce[4739,13,1924,0,1342,1979,0,\"impl-Display-for-Error\"]Cc[4739,13,1924,0,1342,1331,0,\"impl-Debug-for-Error\"]Am[4739,13,3708,135,114,1331,0]An[4739,13,3708,135,3117,1331,0]Ao[4739,13,3708,1511,1329,1331,0]Ao[4739,13,3708,1511,3995,1331,0]Ao[4739,13,3708,2493,1993,1331,0]Ao[4739,13,3708,2493,4287,1331,0]Ao[4739,13,3708,3708,4774,1331,0]Ch[4739,13,2123,2123,1344,1979,0,\"impl-Display-for-Error\"]Cf[4739,13,2123,2123,1344,1331,0,\"impl-Debug-for-Error\"]Ao[4739,13,2123,2123,1347,1331,0]An[4445,13,4446,393,4411,1331,0]Ao[4445,13,4446,4446,2420,1331,0]Ao[4445,13,4446,4446,2433,1331,0]Ao[4445,13,4446,4446,4142,1331,0]Al[4739,13,4740,1526,4164,0,0]Ai[3954,14,3955,0,2434,0,0]Al[4739,14,4740,1542,2435,0,0]Al[4739,13,4740,1907,4289,0,0]Al[4739,14,4740,1907,5027,0,0]Ah[4739,14,4511,0,474,0,0]Al[4445,14,4446,4446,2420,0,0]Ai[3954,13,3955,0,4997,0,0]Al[4739,13,4740,1842,4998,0,0]8Al[1365,13,1540,1540,4407,0,0]Al[4023,13,4024,4024,5028,0,0]Ai[3954,13,3955,0,4258,0,0]Al[3954,13,3955,2444,2399,0,0]Ai[3954,13,3955,0,3332,0,0]Ai[3954,13,3955,0,4513,0,0]Ai[3954,13,3955,0,4381,0,0]Ai[3954,13,3955,0,4168,0,0]Ai[3954,13,3955,0,4120,0,0]Ai[3954,13,3955,0,4135,0,0]Ai[3954,13,3955,0,4715,0,0]Ai[3954,13,3955,0,2422,0,0]Ah[3954,13,3707,0,113,0,0]Ai[3954,13,3707,0,1328,0,0]Ai[3954,13,3707,0,1992,0,0]Al[4739,13,4740,4530,4259,0,0]Al[4739,13,4740,1071,3333,0,0]Al[4739,13,4740,2445,2400,0,0]Al[4739,13,4740,1907,5145,0,0]Al[4739,13,4740,4307,5115,0,0]Al[4739,13,4740,1071,4514,0,0]Al[4739,13,4740,1842,4382,0,0]Al[4739,13,4740,1842,4170,0,0]Al[4739,13,4740,1842,4122,0,0]Al[4739,13,4740,1907,4289,0,0]Al[4739,13,4740,1934,4136,0,0]Ai[4739,13,4740,0,4410,0,0]Al[4739,13,4740,4307,5120,0,0]Al[4739,13,4740,4870,4716,0,0]Al[4739,13,4740,4740,2423,0,0]Aj[4739,13,3708,135,114,0,0]Al[4739,13,3708,1511,1329,0,0]Al[4739,13,3708,2493,1993,0,0]Ak[4445,13,4446,393,4411,0,0]Al[1050,13,4227,4227,5072,0,0]Al[1050,13,4227,4227,5073,0,0]Aj[3954,13,3955,0,485,126,0]Am[4739,13,4740,4740,486,126,0]Ai[3954,12,3955,0,3348,0,0]Al[3954,13,3955,2144,2004,0,0]0Ao[3954,13,3955,1552,4175,2004,0]Al[3954,13,3955,0,4298,3348,0]Al[4739,12,4740,1842,3349,0,0]Ao[4739,13,4740,1842,4299,3349,0]Al[3954,13,3955,3712,3310,0,0]Ai[3954,14,3955,0,3145,0,0]Al[4739,13,4740,3713,3311,0,0]Al[4739,14,4740,1542,3146,0,0]Ae[1050,7,1834,0,0,0,0]Ae[1050,7,1929,0,0,0,0]Ae[3954,4,3955,0,0,0,0]Ai[3954,15,3955,0,4140,0,0]Al[4739,15,4740,1934,4141,0,0]Al[4445,15,4446,4446,4142,0,0]210Ah[3954,5,1844,1845,0,0,0]Ae[4739,5,1845,0,0,0,0]Al[4739,15,4740,1907,4512,0,0]Al[4739,15,4740,1516,3323,0,0]Ah[3954,5,3955,1049,0,0,0]Al[4739,15,4740,3713,1346,0,0]Ai[3954,15,3955,0,3128,0,0]Al[4739,15,4740,1516,3129,0,0]Al[3954,15,3955,4090,4405,0,0]Ah[3954,6,3955,4740,0,0,0]Ae[4739,6,4740,0,0,0,0]Ai[3954,19,3955,0,1586,0,0]Al[4739,19,4740,1526,1587,0,0]Ai[3954,14,3955,0,3316,0,0]Al[4739,14,4740,1542,3317,0,0]Ai[4739,14,3142,0,4154,0,0]Al[4445,14,4446,4446,2420,0,0]Aa[495,3,0,0,0,0,0]Ai[4739,14,4740,0,4410,0,0]Ai[3954,14,3955,0,3145,0,0]Al[4739,14,4740,1542,3146,0,0]Al[4739,14,4740,1516,2393,0,0]An[3954,13,3955,3712,2413,462,0]An[3954,13,3955,2471,2403,462,0]An[3954,13,3955,4090,3335,462,0]An[3954,13,3955,4095,3341,462,0]An[4739,13,4740,1075,1566,462,0]Am[1365,13,1366,1366,127,469,0]An[1365,13,1366,1366,3986,469,0]An[1365,13,1540,1540,4017,469,0]An[1365,13,1540,1540,1361,469,0]An[1365,13,1540,1540,4407,469,0]Ak[495,13,496,496,3987,469,0]An[4023,13,4024,4024,5028,469,0]An[3954,13,3955,3712,4525,469,0]An[3954,13,3955,3712,2413,469,0]Ak[3954,13,3955,0,4258,469,0]An[3954,13,3955,1049,2414,469,0]An[3954,13,3955,1049,3119,469,0]An[3954,13,3955,1049,4682,469,0]An[3954,13,3955,3712,3308,469,0]An[3954,13,3955,3712,3310,469,0]An[3954,13,3955,3712,1995,469,0]An[3954,13,3955,3712,1579,469,0]An[3954,13,3955,3712,3109,469,0]An[3954,13,3955,3712,2387,469,0]An[3954,13,3955,3712,4160,469,0]An[3954,13,3955,3712,4165,469,0]An[3954,13,3955,3712,4943,469,0]An[3954,13,3955,3712,4781,469,0]0An[3954,13,3955,2444,2399,469,0]An[3954,13,3955,2444,4267,469,0]An[3954,13,3955,2444,1558,469,0]An[3954,13,3955,2471,2403,469,0]An[3954,13,3955,2471,3338,469,0]An[3954,13,3955,2471,4386,469,0]Am[3954,13,3955,1049,478,469,0]An[3954,13,3955,4090,3335,469,0]An[3954,13,3955,4090,4882,469,0]An[3954,13,3955,4090,4405,469,0]0Dm[3954,13,3955,4090,3148,469,0,\"impl-From%3CConnectionError%3E-for-ReadError\"]An[3954,13,3955,4090,3148,469,0]Dh[3954,13,3955,4090,3148,469,0,\"impl-From%3CResetError%3E-for-ReadError\"]An[3954,13,3955,4090,3337,469,0]0An[3954,13,3955,4090,4404,469,0]0An[3954,13,3955,1552,4175,469,0]An[3954,13,3955,1092,4012,469,0]An[3954,13,3955,4095,3341,469,0]Dn[3954,13,3955,4095,3355,469,0,\"impl-From%3CConnectionError%3E-for-WriteError\"]An[3954,13,3955,4095,3355,469,0]Dk[3954,13,3955,4095,3355,469,0,\"impl-From%3CClosedStream%3E-for-WriteError\"]Dk[3954,13,3955,4095,3355,469,0,\"impl-From%3CStoppedError%3E-for-WriteError\"]An[3954,13,3955,4095,4174,469,0]0Ak[3954,13,3955,0,3332,469,0]Ak[3954,13,3955,0,4298,469,0]Ak[3954,13,3955,0,4517,469,0]Ak[3954,13,3955,0,4152,469,0]Ak[3954,13,3955,0,4395,469,0]Ck[3954,13,3955,0,1603,469,0,\"impl-From%3Cu32%3E-for-VarInt\"]Cj[3954,13,3955,0,1603,469,0,\"impl-From%3Cu8%3E-for-VarInt\"]Ck[3954,13,3955,0,1603,469,0,\"impl-From%3Cu16%3E-for-VarInt\"]D`[3954,13,3955,0,1603,469,0,\"impl-From%3CStreamId%3E-for-VarInt\"]Ak[3954,13,3955,0,1603,469,0]Dj[3954,13,3955,0,1603,469,0,\"impl-From%3CTransportErrorCode%3E-for-VarInt\"]Ak[3954,13,3955,0,4940,469,0]Ak[3954,13,3955,0,1324,469,0]Ak[3954,13,3955,0,1586,469,0]0Ak[3954,13,3955,0,2434,469,0]Ak[3954,13,3955,0,3316,469,0]Ak[3954,13,3955,0,3145,469,0]Ak[3954,13,3955,0,4503,469,0]Ak[3954,13,3955,0,2018,469,0]Ak[3954,13,3955,0,4126,469,0]Ak[3954,13,3955,0,4499,469,0]Dl[3954,13,3955,0,4499,469,0,\"impl-From%3CCloseReason%3E-for-ConnectionError\"]Do[3954,13,3955,0,4499,469,0,\"impl-From%3CTransportError%3E-for-ConnectionError\"]Df[3954,13,3955,0,4499,469,0,\"impl-From%3CClose%3E-for-ConnectionError\"]Ak[3954,13,3955,0,4513,469,0]Ak[3954,13,3955,0,4520,469,0]Ak[3954,13,3955,0,4805,469,0]Ak[3954,13,3955,0,4820,469,0]Ak[3954,13,3955,0,3999,469,0]0Ak[3954,13,3955,0,4381,469,0]Ak[3954,13,3955,0,4168,469,0]Ak[3954,13,3955,0,4997,469,0]Ak[3954,13,3955,0,4120,469,0]Ea[3954,13,3955,0,3989,469,0,\"impl-From%3CVarIntBoundsExceeded%3E-for-ConfigError\"]Dl[3954,13,3955,0,3989,469,0,\"impl-From%3CTryFromIntError%3E-for-ConfigError\"]Ak[3954,13,3955,0,3989,469,0]Ak[3954,13,3955,0,3128,469,0]Ak[3954,13,3955,0,4496,469,0]0Ak[3954,13,3955,0,4684,469,0]Ak[3954,13,3955,0,4132,469,0]0Ak[3954,13,3955,0,4135,469,0]Ak[3954,13,3955,0,4140,469,0]Ak[3954,13,3955,0,4839,469,0]0Ak[3954,13,3955,0,3319,469,0]Ak[3954,13,3955,0,4715,469,0]Aj[3954,13,3955,0,485,469,0]Aj[3954,13,3955,0,119,469,0]Ak[3954,13,3955,0,2422,469,0]0Ak[3954,13,3955,0,2431,469,0]Aj[3954,13,3707,0,113,469,0]Ak[3954,13,3707,0,3116,469,0]Ak[3954,13,3707,0,1328,469,0]Ak[3954,13,3707,0,3994,469,0]Ak[3954,13,3707,0,1992,469,0]Ak[3954,13,3707,0,4286,469,0]Ak[3954,13,3707,0,4773,469,0]Ak[3954,13,1844,0,1987,469,0]Aj[3954,13,1844,0,472,469,0]Ak[3954,13,1844,0,5086,469,0]Ak[3954,13,1844,0,3992,469,0]0Ak[3954,13,1844,0,4843,469,0]Ak[3954,13,1923,0,3350,469,0]Ak[3954,13,1923,0,4269,469,0]Ak[3954,13,1923,0,4711,469,0]Ak[3954,13,1923,0,4713,469,0]Ak[3954,13,1923,0,4936,469,0]Dg[3954,13,1923,0,1341,469,0,\"impl-From%3CInconsistentKeys%3E-for-Error\"]E`[3954,13,1923,0,1341,469,0,\"impl-From%3CUnsupportedOperationError%3E-for-Error\"]Da[3954,13,1923,0,1341,469,0,\"impl-From%3COtherError%3E-for-Error\"]Df[3954,13,1923,0,1341,469,0,\"impl-From%3CGetRandomFailed%3E-for-Error\"]Ak[3954,13,1923,0,1341,469,0]Df[3954,13,1923,0,1341,469,0,\"impl-From%3CSystemTimeError%3E-for-Error\"]E`[3954,13,1923,0,1341,469,0,\"impl-From%3CEncryptedClientHelloError%3E-for-Error\"]Dn[3954,13,1923,0,1341,469,0,\"impl-From%3CCertRevocationListError%3E-for-Error\"]Dg[3954,13,1923,0,1341,469,0,\"impl-From%3CCertificateError%3E-for-Error\"]Dg[3954,13,1923,0,1341,469,0,\"impl-From%3CPeerIncompatible%3E-for-Error\"]De[3954,13,1923,0,1341,469,0,\"impl-From%3CInvalidMessage%3E-for-Error\"]De[3954,13,1923,0,1341,469,0,\"impl-From%3CPeerMisbehaved%3E-for-Error\"]An[4739,13,4740,4530,4259,469,0]An[4739,13,4740,3173,3123,469,0]An[4739,13,4740,1075,1566,469,0]An[4739,13,4740,2152,2012,469,0]An[4739,13,4740,2152,3336,469,0]An[4739,13,4740,2152,3342,469,0]An[4739,13,4740,3713,3311,469,0]An[4739,13,4740,1071,3333,469,0]An[4739,13,4740,1842,4299,469,0]An[4739,13,4740,2445,2400,469,0]An[4739,13,4740,2445,4265,469,0]An[4739,13,4740,1907,5145,469,0]An[4739,13,4740,4307,5115,469,0]An[4739,13,4740,1551,4518,469,0]An[4739,13,4740,1551,4153,469,0]An[4739,13,4740,1551,4396,469,0]Cm[4739,13,4740,1960,1604,469,0,\"impl-From%3Cu8%3E-for-VarInt\"]Cn[4739,13,4740,1960,1604,469,0,\"impl-From%3Cu16%3E-for-VarInt\"]Cn[4739,13,4740,1960,1604,469,0,\"impl-From%3Cu32%3E-for-VarInt\"]Dc[4739,13,4740,1960,1604,469,0,\"impl-From%3CStreamId%3E-for-VarInt\"]Co[4739,13,4740,1960,1604,469,0,\"impl-From%3CCode%3E-for-VarInt\"]An[4739,13,4740,1960,1604,469,0]An[4739,13,4740,1960,4941,469,0]An[4739,13,4740,3164,1325,469,0]An[4739,13,4740,3173,4782,469,0]An[4739,13,4740,1526,1587,469,0]0An[4739,13,4740,1526,4164,469,0]An[4739,13,4740,1526,3331,469,0]An[4739,13,4740,1526,3144,469,0]An[4739,13,4740,1526,4836,469,0]An[4739,13,4740,1526,3306,469,0]An[4739,13,4740,1542,2435,469,0]An[4739,13,4740,1542,3317,469,0]An[4739,13,4740,1542,3146,469,0]An[4739,13,4740,1542,4504,469,0]An[4739,13,4740,1075,3149,469,0]An[4739,13,4740,1075,4294,469,0]An[4739,13,4740,1080,2019,469,0]An[4739,13,4740,1080,3356,469,0]An[4739,13,4740,1080,3998,469,0]An[4739,13,4740,2152,4016,469,0]An[4739,13,4740,2152,4406,469,0]An[4739,13,4740,2152,4130,469,0]An[4739,13,4740,3713,4500,469,0]0An[4739,13,4740,3713,3141,469,0]An[4739,13,4740,3713,4372,469,0]An[4739,13,4740,3713,5024,469,0]An[4739,13,4740,3713,1346,469,0]0An[4739,13,4740,1071,4514,469,0]An[4739,13,4740,3293,4521,469,0]An[4739,13,4740,3293,4806,469,0]An[4739,13,4740,3293,4821,469,0]An[4739,13,4740,3293,4000,469,0]0An[4739,13,4740,1842,4382,469,0]An[4739,13,4740,1842,4170,469,0]An[4739,13,4740,1842,4998,469,0]An[4739,13,4740,1842,4122,469,0]Ed[4739,13,4740,1842,3990,469,0,\"impl-From%3CVarIntBoundsExceeded%3E-for-ConfigError\"]An[4739,13,4740,1842,3990,469,0]Do[4739,13,4740,1842,3990,469,0,\"impl-From%3CTryFromIntError%3E-for-ConfigError\"]An[4739,13,4740,1516,3129,469,0]An[4739,13,4740,1516,4387,469,0]An[4739,13,4740,1516,3323,469,0]An[4739,13,4740,1516,3345,469,0]An[4739,13,4740,1516,4137,469,0]An[4739,13,4740,1516,4498,469,0]0An[4739,13,4740,1516,4686,469,0]An[4739,13,4740,1516,2393,469,0]An[4739,13,4740,2445,4690,469,0]An[4739,13,4740,2445,2404,469,0]An[4739,13,4740,2445,4133,469,0]0An[4739,13,4740,2445,3984,469,0]An[4739,13,4740,2445,3339,469,0]An[4739,13,4740,1907,4289,469,0]An[4739,13,4740,1907,4512,469,0]An[4739,13,4740,1907,5027,469,0]An[4739,13,4740,1907,2406,469,0]An[4739,13,4740,1907,4780,469,0]0An[4739,13,4740,1934,4502,469,0]An[4739,13,4740,1934,4266,469,0]An[4739,13,4740,1934,4136,469,0]An[4739,13,4740,1934,4141,469,0]Ak[4739,13,4740,0,4410,469,0]0Ak[4739,13,4740,0,4840,469,0]0An[4739,13,4740,4307,3320,469,0]An[4739,13,4740,4307,5120,469,0]An[4739,13,4740,4870,4716,469,0]Am[4739,13,4740,4740,486,469,0]Am[4739,13,4740,4740,120,469,0]An[4739,13,4740,4740,2423,469,0]0An[4739,13,4740,4740,2432,469,0]An[4739,13,4740,4740,3127,469,0]An[4739,13,1840,1840,4300,469,0]An[4739,13,4982,4982,4881,469,0]An[4739,13,4982,4982,1343,469,0]0An[4739,13,1845,1845,1988,469,0]Am[4739,13,1845,1845,473,469,0]An[4739,13,1845,1845,5087,469,0]An[4739,13,1845,1845,3993,469,0]0An[4739,13,1845,1845,4846,469,0]An[4739,13,1924,1924,3351,469,0]An[4739,13,1924,1924,4270,469,0]An[4739,13,1924,1924,4712,469,0]An[4739,13,1924,1924,4714,469,0]An[4739,13,1924,1924,4937,469,0]Ak[4739,13,1924,0,1342,469,0]De[4739,13,1924,0,1342,469,0,\"impl-From%3CPeerMisbehaved%3E-for-Error\"]Df[4739,13,1924,0,1342,469,0,\"impl-From%3CSystemTimeError%3E-for-Error\"]Dn[4739,13,1924,0,1342,469,0,\"impl-From%3CCertRevocationListError%3E-for-Error\"]Df[4739,13,1924,0,1342,469,0,\"impl-From%3CGetRandomFailed%3E-for-Error\"]Dg[4739,13,1924,0,1342,469,0,\"impl-From%3CCertificateError%3E-for-Error\"]Da[4739,13,1924,0,1342,469,0,\"impl-From%3COtherError%3E-for-Error\"]E`[4739,13,1924,0,1342,469,0,\"impl-From%3CUnsupportedOperationError%3E-for-Error\"]Dg[4739,13,1924,0,1342,469,0,\"impl-From%3CInconsistentKeys%3E-for-Error\"]Dg[4739,13,1924,0,1342,469,0,\"impl-From%3CPeerIncompatible%3E-for-Error\"]De[4739,13,1924,0,1342,469,0,\"impl-From%3CInvalidMessage%3E-for-Error\"]E`[4739,13,1924,0,1342,469,0,\"impl-From%3CEncryptedClientHelloError%3E-for-Error\"]Al[4739,13,3708,135,114,469,0]Am[4739,13,3708,135,3117,469,0]An[4739,13,3708,1511,1329,469,0]An[4739,13,3708,1511,3995,469,0]An[4739,13,3708,2493,1993,469,0]An[4739,13,3708,2493,4287,469,0]An[4739,13,3708,3708,4774,469,0]An[4739,13,2123,2123,1344,469,0]An[4739,13,2123,2123,1347,469,0]An[4445,13,4446,4446,3354,469,0]0Am[4445,13,4446,393,4411,469,0]An[4445,13,4446,4446,2420,469,0]An[4445,13,4446,4446,2433,469,0]An[4445,13,4446,4446,4142,469,0]An[1050,13,1051,1051,3120,469,0]An[1050,13,1051,1051,4874,469,0]Am[1050,13,1834,1834,128,469,0]An[1050,13,1541,1541,1362,469,0]An[1050,13,1541,1541,4018,469,0]An[1050,13,1541,1541,4508,469,0]An[1050,13,4227,4227,5072,469,0]An[1050,13,4227,4227,5073,469,0]Am[1050,13,1929,1929,129,469,0]Am[3974,13,3975,3975,118,469,0]An[3974,13,3975,3975,2390,469,0]Ak[3954,13,3955,0,1603,470,0]Ak[3954,13,3955,0,1586,470,0]Ak[3954,13,3955,0,3999,470,0]Ak[3954,13,3955,0,4135,470,0]Aj[3954,13,3955,0,485,470,0]Aj[3954,13,3955,0,119,470,0]Ak[3954,13,3955,0,2422,470,0]An[4739,13,4740,1960,1604,470,0]An[4739,13,4740,3173,4782,470,0]An[4739,13,4740,1526,1587,470,0]An[4739,13,4740,1075,3149,470,0]An[4739,13,4740,1075,4294,470,0]An[4739,13,4740,1080,3356,470,0]An[4739,13,4740,3293,4000,470,0]An[4739,13,4740,2445,4690,470,0]An[4739,13,4740,1907,4780,470,0]An[4739,13,4740,1934,4136,470,0]Am[4739,13,4740,4740,486,470,0]Am[4739,13,4740,4740,120,470,0]An[4739,13,4740,4740,2423,470,0]An[4739,13,4740,4740,3127,470,0]Am[1365,13,1366,1366,127,471,0]An[1365,13,1366,1366,3986,471,0]An[1365,13,1540,1540,4017,471,0]An[1365,13,1540,1540,1361,471,0]An[1365,13,1540,1540,4407,471,0]Ak[495,13,496,496,3987,471,0]An[4023,13,4024,4024,5028,471,0]An[3954,13,3955,3712,4525,471,0]An[3954,13,3955,3712,2413,471,0]Ak[3954,13,3955,0,4258,471,0]An[3954,13,3955,1049,2414,471,0]An[3954,13,3955,1049,3119,471,0]An[3954,13,3955,1049,4682,471,0]An[3954,13,3955,3712,3308,471,0]An[3954,13,3955,3712,3310,471,0]An[3954,13,3955,3712,1995,471,0]An[3954,13,3955,3712,1579,471,0]An[3954,13,3955,3712,3109,471,0]An[3954,13,3955,3712,2387,471,0]An[3954,13,3955,3712,4160,471,0]An[3954,13,3955,3712,4165,471,0]An[3954,13,3955,3712,4943,471,0]An[3954,13,3955,3712,4781,471,0]An[3954,13,3955,2444,2399,471,0]An[3954,13,3955,2444,4267,471,0]An[3954,13,3955,2444,1558,471,0]An[3954,13,3955,2471,2403,471,0]An[3954,13,3955,2471,3338,471,0]An[3954,13,3955,2471,4386,471,0]Am[3954,13,3955,1049,478,471,0]An[3954,13,3955,4090,3335,471,0]An[3954,13,3955,4090,4882,471,0]An[3954,13,3955,4090,4405,471,0]An[3954,13,3955,4090,3148,471,0]An[3954,13,3955,4090,3337,471,0]An[3954,13,3955,4090,4404,471,0]An[3954,13,3955,1552,4175,471,0]An[3954,13,3955,1092,4012,471,0]An[3954,13,3955,4095,3341,471,0]An[3954,13,3955,4095,3355,471,0]An[3954,13,3955,4095,4174,471,0]Ak[3954,13,3955,0,3332,471,0]Ak[3954,13,3955,0,4298,471,0]Ak[3954,13,3955,0,4517,471,0]Ak[3954,13,3955,0,4152,471,0]Ak[3954,13,3955,0,4395,471,0]Ak[3954,13,3955,0,1603,471,0]Ak[3954,13,3955,0,4940,471,0]Ak[3954,13,3955,0,1324,471,0]Ak[3954,13,3955,0,1586,471,0]Ak[3954,13,3955,0,2434,471,0]Ak[3954,13,3955,0,3316,471,0]Ak[3954,13,3955,0,3145,471,0]Ak[3954,13,3955,0,4503,471,0]Ak[3954,13,3955,0,2018,471,0]Ak[3954,13,3955,0,4126,471,0]Ak[3954,13,3955,0,4499,471,0]Ak[3954,13,3955,0,4513,471,0]Ak[3954,13,3955,0,4520,471,0]Ak[3954,13,3955,0,4805,471,0]Ak[3954,13,3955,0,4820,471,0]Ak[3954,13,3955,0,3999,471,0]Ak[3954,13,3955,0,4381,471,0]Ak[3954,13,3955,0,4168,471,0]Ak[3954,13,3955,0,4997,471,0]Ak[3954,13,3955,0,4120,471,0]Ak[3954,13,3955,0,3989,471,0]Ak[3954,13,3955,0,3128,471,0]Ak[3954,13,3955,0,4496,471,0]Ak[3954,13,3955,0,4684,471,0]Ak[3954,13,3955,0,4132,471,0]Ak[3954,13,3955,0,4135,471,0]Ak[3954,13,3955,0,4140,471,0]Ak[3954,13,3955,0,4839,471,0]Ak[3954,13,3955,0,3319,471,0]Ak[3954,13,3955,0,4715,471,0]Aj[3954,13,3955,0,485,471,0]Aj[3954,13,3955,0,119,471,0]Ak[3954,13,3955,0,2422,471,0]Ak[3954,13,3955,0,2431,471,0]Aj[3954,13,3707,0,113,471,0]Ak[3954,13,3707,0,3116,471,0]Ak[3954,13,3707,0,1328,471,0]Ak[3954,13,3707,0,3994,471,0]Ak[3954,13,3707,0,1992,471,0]Ak[3954,13,3707,0,4286,471,0]Ak[3954,13,3707,0,4773,471,0]Ak[3954,13,1844,0,1987,471,0]Aj[3954,13,1844,0,472,471,0]Ak[3954,13,1844,0,5086,471,0]Ak[3954,13,1844,0,3992,471,0]Ak[3954,13,1844,0,4843,471,0]Ak[3954,13,1923,0,3350,471,0]Ak[3954,13,1923,0,4269,471,0]Ak[3954,13,1923,0,4711,471,0]Ak[3954,13,1923,0,4713,471,0]Ak[3954,13,1923,0,4936,471,0]Ak[3954,13,1923,0,1341,471,0]An[4739,13,4740,4530,4259,471,0]An[4739,13,4740,3173,3123,471,0]An[4739,13,4740,1075,1566,471,0]An[4739,13,4740,2152,2012,471,0]An[4739,13,4740,2152,3336,471,0]An[4739,13,4740,2152,3342,471,0]An[4739,13,4740,3713,3311,471,0]An[4739,13,4740,1071,3333,471,0]An[4739,13,4740,1842,4299,471,0]An[4739,13,4740,2445,2400,471,0]An[4739,13,4740,2445,4265,471,0]An[4739,13,4740,1907,5145,471,0]An[4739,13,4740,4307,5115,471,0]An[4739,13,4740,1551,4518,471,0]An[4739,13,4740,1551,4153,471,0]An[4739,13,4740,1551,4396,471,0]An[4739,13,4740,1960,1604,471,0]An[4739,13,4740,1960,4941,471,0]An[4739,13,4740,3164,1325,471,0]An[4739,13,4740,3173,4782,471,0]An[4739,13,4740,1526,1587,471,0]An[4739,13,4740,1526,4164,471,0]An[4739,13,4740,1526,3331,471,0]An[4739,13,4740,1526,3144,471,0]An[4739,13,4740,1526,4836,471,0]An[4739,13,4740,1526,3306,471,0]An[4739,13,4740,1542,2435,471,0]An[4739,13,4740,1542,3317,471,0]An[4739,13,4740,1542,3146,471,0]An[4739,13,4740,1542,4504,471,0]An[4739,13,4740,1075,3149,471,0]An[4739,13,4740,1075,4294,471,0]An[4739,13,4740,1080,2019,471,0]An[4739,13,4740,1080,3356,471,0]An[4739,13,4740,1080,3998,471,0]An[4739,13,4740,2152,4016,471,0]An[4739,13,4740,2152,4406,471,0]An[4739,13,4740,2152,4130,471,0]An[4739,13,4740,3713,4500,471,0]An[4739,13,4740,3713,3141,471,0]An[4739,13,4740,3713,4372,471,0]An[4739,13,4740,3713,5024,471,0]An[4739,13,4740,3713,1346,471,0]An[4739,13,4740,1071,4514,471,0]An[4739,13,4740,3293,4521,471,0]An[4739,13,4740,3293,4806,471,0]An[4739,13,4740,3293,4821,471,0]An[4739,13,4740,3293,4000,471,0]An[4739,13,4740,1842,4382,471,0]An[4739,13,4740,1842,4170,471,0]An[4739,13,4740,1842,4998,471,0]An[4739,13,4740,1842,4122,471,0]An[4739,13,4740,1842,3990,471,0]An[4739,13,4740,1516,3129,471,0]An[4739,13,4740,1516,4387,471,0]An[4739,13,4740,1516,3323,471,0]An[4739,13,4740,1516,3345,471,0]An[4739,13,4740,1516,4137,471,0]An[4739,13,4740,1516,4498,471,0]An[4739,13,4740,1516,4686,471,0]An[4739,13,4740,1516,2393,471,0]An[4739,13,4740,2445,4690,471,0]An[4739,13,4740,2445,2404,471,0]An[4739,13,4740,2445,4133,471,0]An[4739,13,4740,2445,3984,471,0]An[4739,13,4740,2445,3339,471,0]An[4739,13,4740,1907,4289,471,0]An[4739,13,4740,1907,4512,471,0]An[4739,13,4740,1907,5027,471,0]An[4739,13,4740,1907,2406,471,0]An[4739,13,4740,1907,4780,471,0]An[4739,13,4740,1934,4502,471,0]An[4739,13,4740,1934,4266,471,0]An[4739,13,4740,1934,4136,471,0]An[4739,13,4740,1934,4141,471,0]Ak[4739,13,4740,0,4410,471,0]Ak[4739,13,4740,0,4840,471,0]An[4739,13,4740,4307,3320,471,0]An[4739,13,4740,4307,5120,471,0]An[4739,13,4740,4870,4716,471,0]Am[4739,13,4740,4740,486,471,0]Am[4739,13,4740,4740,120,471,0]An[4739,13,4740,4740,2423,471,0]An[4739,13,4740,4740,2432,471,0]An[4739,13,4740,4740,3127,471,0]An[4739,13,1840,1840,4300,471,0]An[4739,13,4982,4982,4881,471,0]An[4739,13,4982,4982,1343,471,0]An[4739,13,1845,1845,1988,471,0]Am[4739,13,1845,1845,473,471,0]An[4739,13,1845,1845,5087,471,0]An[4739,13,1845,1845,3993,471,0]An[4739,13,1845,1845,4846,471,0]An[4739,13,1924,1924,3351,471,0]An[4739,13,1924,1924,4270,471,0]An[4739,13,1924,1924,4712,471,0]An[4739,13,1924,1924,4714,471,0]An[4739,13,1924,1924,4937,471,0]Ak[4739,13,1924,0,1342,471,0]Al[4739,13,3708,135,114,471,0]Am[4739,13,3708,135,3117,471,0]An[4739,13,3708,1511,1329,471,0]An[4739,13,3708,1511,3995,471,0]An[4739,13,3708,2493,1993,471,0]An[4739,13,3708,2493,4287,471,0]An[4739,13,3708,3708,4774,471,0]An[4739,13,2123,2123,1344,471,0]An[4739,13,2123,2123,1347,471,0]An[4445,13,4446,4446,3354,471,0]Am[4445,13,4446,393,4411,471,0]An[4445,13,4446,4446,2420,471,0]An[4445,13,4446,4446,2433,471,0]An[4445,13,4446,4446,4142,471,0]An[1050,13,1051,1051,3120,471,0]An[1050,13,1051,1051,4874,471,0]Am[1050,13,1834,1834,128,471,0]An[1050,13,1541,1541,1362,471,0]An[1050,13,1541,1541,4018,471,0]An[1050,13,1541,1541,4508,471,0]An[1050,13,4227,4227,5072,471,0]An[1050,13,4227,4227,5073,471,0]Am[1050,13,1929,1929,129,471,0]Am[3974,13,3975,3975,118,471,0]An[3974,13,3975,3975,2390,471,0]Ac[495,7,496,0,0,0,0]Ae[4023,7,4024,0,0,0,0]Ae[4310,7,4311,0,0,0,0]Ae[3974,7,3975,0,0,0,0]Ae[4800,7,4801,0,0,0,0]Al[4739,13,4740,1075,1566,0,0]Ai[3954,12,1844,0,1971,0,0]Al[4739,13,4740,2152,2012,0,0]Al[4739,12,1845,1845,1972,0,0]Al[3954,13,3955,3712,3310,0,0]Ab[1050,3,0,0,0,0,0]Ak[3954,13,3955,1049,478,0,0]Ai[3954,14,3955,0,3316,0,0]Al[4739,13,4740,3713,3311,0,0]Al[4739,14,4740,1542,3317,0,0]Al[3954,12,3955,2144,3299,0,0]Ao[3954,13,3955,3712,4525,1576,0]Ao[3954,13,3955,3712,2413,1576,0]Ao[3954,13,3955,1049,2414,1576,0]Ao[3954,13,3955,1049,3119,1576,0]Ao[3954,13,3955,3712,3308,1576,0]Ao[3954,13,3955,3712,1995,1576,0]Ao[3954,13,3955,3712,1579,1576,0]Ao[3954,13,3955,3712,3109,1576,0]Ao[3954,13,3955,3712,2387,1576,0]Ao[3954,13,3955,3712,4160,1576,0]Ao[3954,13,3955,3712,4165,1576,0]Ao[3954,13,3955,2444,1558,1576,0]Ao[3954,13,3955,2471,4386,1576,0]?Al[3954,13,3955,4090,3335,0,0]Al[4739,13,4740,2152,3336,0,0]Al[4739,13,4982,4982,4881,0,0]Al[4739,13,4740,3173,3123,0,0]Ak[4445,13,4446,393,4411,0,0]Ai[3954,12,1844,0,1971,0,0]Al[4739,12,1845,1845,1972,0,0]32Ai[3954,13,3955,0,4997,0,0]Al[4739,13,4740,1842,4998,0,0]Al[3954,13,3955,3712,3310,0,0]Al[4739,13,4740,3713,3311,0,0]Ai[3954,12,1844,0,1983,0,0]Al[4739,12,1845,1845,1984,0,0]Al[1365,14,1540,1540,4407,0,0]Ai[3954,14,3955,0,2431,0,0]Al[4739,14,4740,4740,2432,0,0]Ai[4739,14,4511,0,1358,0,0]Al[3954,13,3955,4090,3335,0,0]Al[3954,13,3955,4090,4882,0,0]Al[4739,13,4740,2152,3336,0,0]Ai[3954,12,3955,0,3352,0,0]Al[3954,13,3955,0,4395,3352,0]Al[3954,13,3955,0,4715,3352,0]Al[4739,12,4740,1551,3353,0,0]Ao[4739,13,4740,1551,4396,3353,0]Ao[4739,13,4740,4870,4716,3353,0]Am[1365,13,1366,1366,127,488,0]An[1365,13,1366,1366,3986,488,0]An[1365,13,1540,1540,4017,488,0]An[1365,13,1540,1540,1361,488,0]An[1365,13,1540,1540,4407,488,0]Ak[495,13,496,496,3987,488,0]An[4023,13,4024,4024,5028,488,0]An[3954,13,3955,3712,4525,488,0]An[3954,13,3955,3712,2413,488,0]Ak[3954,13,3955,0,4258,488,0]An[3954,13,3955,1049,2414,488,0]An[3954,13,3955,1049,3119,488,0]An[3954,13,3955,1049,4682,488,0]An[3954,13,3955,3712,3308,488,0]An[3954,13,3955,3712,3310,488,0]An[3954,13,3955,3712,1995,488,0]An[3954,13,3955,3712,1579,488,0]An[3954,13,3955,3712,3109,488,0]An[3954,13,3955,3712,2387,488,0]An[3954,13,3955,3712,4160,488,0]An[3954,13,3955,3712,4165,488,0]An[3954,13,3955,3712,4943,488,0]An[3954,13,3955,3712,4781,488,0]An[3954,13,3955,2444,2399,488,0]An[3954,13,3955,2444,4267,488,0]An[3954,13,3955,2444,1558,488,0]An[3954,13,3955,2471,2403,488,0]An[3954,13,3955,2471,3338,488,0]An[3954,13,3955,2471,4386,488,0]Am[3954,13,3955,1049,478,488,0]An[3954,13,3955,4090,3335,488,0]An[3954,13,3955,4090,4882,488,0]An[3954,13,3955,4090,4405,488,0]An[3954,13,3955,4090,3148,488,0]An[3954,13,3955,4090,3337,488,0]An[3954,13,3955,4090,4404,488,0]An[3954,13,3955,1552,4175,488,0]An[3954,13,3955,1092,4012,488,0]An[3954,13,3955,4095,3341,488,0]An[3954,13,3955,4095,3355,488,0]An[3954,13,3955,4095,4174,488,0]Ak[3954,13,3955,0,3332,488,0]Ak[3954,13,3955,0,4298,488,0]Ak[3954,13,3955,0,4517,488,0]Ak[3954,13,3955,0,4152,488,0]Ak[3954,13,3955,0,4395,488,0]Ak[3954,13,3955,0,1603,488,0]Ak[3954,13,3955,0,4940,488,0]Ak[3954,13,3955,0,1324,488,0]Ak[3954,13,3955,0,1586,488,0]Ak[3954,13,3955,0,2434,488,0]Ak[3954,13,3955,0,3316,488,0]Ak[3954,13,3955,0,3145,488,0]Ak[3954,13,3955,0,4503,488,0]Ak[3954,13,3955,0,2018,488,0]Ak[3954,13,3955,0,4126,488,0]Ak[3954,13,3955,0,4499,488,0]Ak[3954,13,3955,0,4513,488,0]Ak[3954,13,3955,0,4520,488,0]Ak[3954,13,3955,0,4805,488,0]Ak[3954,13,3955,0,4820,488,0]Ak[3954,13,3955,0,3999,488,0]Ak[3954,13,3955,0,4381,488,0]Ak[3954,13,3955,0,4168,488,0]Ak[3954,13,3955,0,4997,488,0]Ak[3954,13,3955,0,4120,488,0]Ak[3954,13,3955,0,3989,488,0]Ak[3954,13,3955,0,3128,488,0]Ak[3954,13,3955,0,4496,488,0]Ak[3954,13,3955,0,4684,488,0]Ak[3954,13,3955,0,4132,488,0]Ak[3954,13,3955,0,4135,488,0]Ak[3954,13,3955,0,4140,488,0]Ak[3954,13,3955,0,4839,488,0]Ak[3954,13,3955,0,3319,488,0]Ak[3954,13,3955,0,4715,488,0]Aj[3954,13,3955,0,485,488,0]Aj[3954,13,3955,0,119,488,0]Ak[3954,13,3955,0,2422,488,0]Ak[3954,13,3955,0,2431,488,0]Aj[3954,13,3707,0,113,488,0]Ak[3954,13,3707,0,3116,488,0]Ak[3954,13,3707,0,1328,488,0]Ak[3954,13,3707,0,3994,488,0]Ak[3954,13,3707,0,1992,488,0]Ak[3954,13,3707,0,4286,488,0]Ak[3954,13,3707,0,4773,488,0]Ak[3954,13,1844,0,1987,488,0]Aj[3954,13,1844,0,472,488,0]Ak[3954,13,1844,0,5086,488,0]Ak[3954,13,1844,0,3992,488,0]Ak[3954,13,1844,0,4843,488,0]Ak[3954,13,1923,0,3350,488,0]Ak[3954,13,1923,0,4269,488,0]Ak[3954,13,1923,0,4711,488,0]Ak[3954,13,1923,0,4713,488,0]Ak[3954,13,1923,0,4936,488,0]Ak[3954,13,1923,0,1341,488,0]An[4739,13,4740,4530,4259,488,0]An[4739,13,4740,3173,3123,488,0]An[4739,13,4740,1075,1566,488,0]An[4739,13,4740,2152,2012,488,0]An[4739,13,4740,2152,3336,488,0]An[4739,13,4740,2152,3342,488,0]An[4739,13,4740,3713,3311,488,0]An[4739,13,4740,1071,3333,488,0]An[4739,13,4740,1842,4299,488,0]An[4739,13,4740,2445,2400,488,0]An[4739,13,4740,2445,4265,488,0]An[4739,13,4740,1907,5145,488,0]An[4739,13,4740,4307,5115,488,0]An[4739,13,4740,1551,4518,488,0]An[4739,13,4740,1551,4153,488,0]An[4739,13,4740,1551,4396,488,0]An[4739,13,4740,1960,1604,488,0]An[4739,13,4740,1960,4941,488,0]An[4739,13,4740,3164,1325,488,0]An[4739,13,4740,3173,4782,488,0]An[4739,13,4740,1526,1587,488,0]An[4739,13,4740,1526,4164,488,0]An[4739,13,4740,1526,3331,488,0]An[4739,13,4740,1526,3144,488,0]An[4739,13,4740,1526,4836,488,0]An[4739,13,4740,1526,3306,488,0]An[4739,13,4740,1542,2435,488,0]An[4739,13,4740,1542,3317,488,0]An[4739,13,4740,1542,3146,488,0]An[4739,13,4740,1542,4504,488,0]An[4739,13,4740,1075,3149,488,0]An[4739,13,4740,1075,4294,488,0]An[4739,13,4740,1080,2019,488,0]An[4739,13,4740,1080,3356,488,0]An[4739,13,4740,1080,3998,488,0]An[4739,13,4740,2152,4016,488,0]An[4739,13,4740,2152,4406,488,0]An[4739,13,4740,2152,4130,488,0]An[4739,13,4740,3713,4500,488,0]An[4739,13,4740,3713,3141,488,0]An[4739,13,4740,3713,4372,488,0]An[4739,13,4740,3713,5024,488,0]An[4739,13,4740,3713,1346,488,0]An[4739,13,4740,1071,4514,488,0]An[4739,13,4740,3293,4521,488,0]An[4739,13,4740,3293,4806,488,0]An[4739,13,4740,3293,4821,488,0]An[4739,13,4740,3293,4000,488,0]An[4739,13,4740,1842,4382,488,0]An[4739,13,4740,1842,4170,488,0]An[4739,13,4740,1842,4998,488,0]An[4739,13,4740,1842,4122,488,0]An[4739,13,4740,1842,3990,488,0]An[4739,13,4740,1516,3129,488,0]An[4739,13,4740,1516,4387,488,0]An[4739,13,4740,1516,3323,488,0]An[4739,13,4740,1516,3345,488,0]An[4739,13,4740,1516,4137,488,0]An[4739,13,4740,1516,4498,488,0]An[4739,13,4740,1516,4686,488,0]An[4739,13,4740,1516,2393,488,0]An[4739,13,4740,2445,4690,488,0]An[4739,13,4740,2445,2404,488,0]An[4739,13,4740,2445,4133,488,0]An[4739,13,4740,2445,3984,488,0]An[4739,13,4740,2445,3339,488,0]An[4739,13,4740,1907,4289,488,0]An[4739,13,4740,1907,4512,488,0]An[4739,13,4740,1907,5027,488,0]An[4739,13,4740,1907,2406,488,0]An[4739,13,4740,1907,4780,488,0]An[4739,13,4740,1934,4502,488,0]An[4739,13,4740,1934,4266,488,0]An[4739,13,4740,1934,4136,488,0]An[4739,13,4740,1934,4141,488,0]Ak[4739,13,4740,0,4410,488,0]Ak[4739,13,4740,0,4840,488,0]An[4739,13,4740,4307,3320,488,0]An[4739,13,4740,4307,5120,488,0]An[4739,13,4740,4870,4716,488,0]Am[4739,13,4740,4740,486,488,0]Am[4739,13,4740,4740,120,488,0]An[4739,13,4740,4740,2423,488,0]An[4739,13,4740,4740,2432,488,0]An[4739,13,4740,4740,3127,488,0]An[4739,13,1840,1840,4300,488,0]An[4739,13,4982,4982,4881,488,0]An[4739,13,4982,4982,1343,488,0]An[4739,13,1845,1845,1988,488,0]Am[4739,13,1845,1845,473,488,0]An[4739,13,1845,1845,5087,488,0]An[4739,13,1845,1845,3993,488,0]An[4739,13,1845,1845,4846,488,0]An[4739,13,1924,1924,3351,488,0]An[4739,13,1924,1924,4270,488,0]An[4739,13,1924,1924,4712,488,0]An[4739,13,1924,1924,4714,488,0]An[4739,13,1924,1924,4937,488,0]Ak[4739,13,1924,0,1342,488,0]Al[4739,13,3708,135,114,488,0]Am[4739,13,3708,135,3117,488,0]An[4739,13,3708,1511,1329,488,0]An[4739,13,3708,1511,3995,488,0]An[4739,13,3708,2493,1993,488,0]An[4739,13,3708,2493,4287,488,0]An[4739,13,3708,3708,4774,488,0]An[4739,13,2123,2123,1344,488,0]An[4739,13,2123,2123,1347,488,0]An[1050,13,1051,1051,3120,488,0]An[1050,13,1051,1051,4874,488,0]Am[1050,13,1834,1834,128,488,0]An[1050,13,1541,1541,1362,488,0]An[1050,13,1541,1541,4018,488,0]An[1050,13,1541,1541,4508,488,0]An[1050,13,4227,4227,5072,488,0]An[1050,13,4227,4227,5073,488,0]Am[1050,13,1929,1929,129,488,0]Am[3974,13,3975,3975,118,488,0]An[3974,13,3975,3975,2390,488,0]Ah[3954,5,3955,3164,0,0,0]Ah[4739,5,4740,3164,0,0,0]Ah[3954,5,3707,1511,0,0,0]Ah[4739,5,3708,1511,0,0,0]Al[1050,15,1051,1051,4874,0,0]Ah[3954,6,1923,1514,0,0,0]Ah[4739,6,1924,1514,0,0,0]Ae[4739,6,4982,0,0,0,0]Ae[4739,6,2123,0,0,0,0]Ah[4739,6,4740,3713,0,0,0]1Al[4739,15,4740,1516,3323,0,0]Ai[3954,15,1923,0,1341,0,0]Ai[4739,15,1924,0,1342,0,0]Al[3954,15,3955,4090,3148,0,0]Ai[3954,15,3955,0,4499,0,0]Al[4739,15,4740,1075,3149,0,0]Al[4739,15,4740,3713,4500,0,0]Al[4739,15,4740,1907,4512,0,0]0Ae[1365,5,1540,0,0,0,0]Ae[1050,5,1541,0,0,0,0]Ab[1365,3,0,0,0,0,0]Ai[3954,12,3707,0,4771,0,0]Al[3954,13,3707,0,3116,4771,0]Al[3954,13,3707,0,3994,4771,0]Al[3954,13,3707,0,4286,4771,0]Al[4739,12,3708,3708,4772,0,0]An[4739,13,3708,135,3117,4772,0]Ao[4739,13,3708,1511,3995,4772,0]Ao[4739,13,3708,2493,4287,4772,0]Al[1050,13,1051,1051,4874,0,0]Ai[3954,14,3955,0,1324,0,0]Ai[3954,14,3955,0,2434,0,0]Ai[3954,14,3955,0,2018,0,0]Al[4739,14,4740,3164,1325,0,0]Al[4739,14,4740,1542,2435,0,0]Al[4739,14,4740,1080,2019,0,0]Al[4739,14,4740,2445,3984,0,0]An[1365,13,1366,1366,127,1326,0]Ao[1365,13,1366,1366,3986,1326,0]Ao[3954,13,3955,3712,3310,1326,0]Ao[3954,13,3955,3712,4943,1326,0]Ao[3954,13,3955,3712,4781,1326,0]Ao[3954,13,3955,2444,2399,1326,0]Ao[3954,13,3955,2444,4267,1326,0]Ao[3954,13,3955,4090,4405,1326,0]Ao[3954,13,3955,4090,3148,1326,0]Ao[3954,13,3955,4090,3337,1326,0]Ao[3954,13,3955,4090,4404,1326,0]Ao[3954,13,3955,4095,3355,1326,0]Ao[3954,13,3955,4095,4174,1326,0]Al[3954,13,3955,0,1603,1326,0]Al[3954,13,3955,0,4940,1326,0]Al[3954,13,3955,0,1586,1326,0]Al[3954,13,3955,0,2434,1326,0]Al[3954,13,3955,0,3316,1326,0]Al[3954,13,3955,0,3145,1326,0]Al[3954,13,3955,0,4503,1326,0]Al[3954,13,3955,0,2018,1326,0]Al[3954,13,3955,0,4126,1326,0]Al[3954,13,3955,0,4499,1326,0]Al[3954,13,3955,0,4520,1326,0]Al[3954,13,3955,0,4805,1326,0]Al[3954,13,3955,0,4820,1326,0]Al[3954,13,3955,0,3999,1326,0]Al[3954,13,3955,0,4381,1326,0]Al[3954,13,3955,0,4168,1326,0]Al[3954,13,3955,0,4997,1326,0]Al[3954,13,3955,0,4120,1326,0]Al[3954,13,3955,0,3989,1326,0]Al[3954,13,3955,0,3128,1326,0]Al[3954,13,3955,0,4496,1326,0]Al[3954,13,3955,0,4684,1326,0]Al[3954,13,3955,0,4132,1326,0]Al[3954,13,3955,0,4135,1326,0]Al[3954,13,3955,0,4140,1326,0]Al[3954,13,3955,0,4839,1326,0]Al[3954,13,3955,0,3319,1326,0]Ak[3954,13,3955,0,485,1326,0]Ak[3954,13,3955,0,119,1326,0]Al[3954,13,3955,0,2422,1326,0]Ak[3954,13,3707,0,113,1326,0]Al[3954,13,3707,0,3116,1326,0]Al[3954,13,3707,0,1328,1326,0]Al[3954,13,3707,0,3994,1326,0]Al[3954,13,3707,0,1992,1326,0]Al[3954,13,3707,0,4286,1326,0]Al[3954,13,1923,0,4936,1326,0]Al[3954,13,1923,0,1341,1326,0]Ao[4739,13,4740,1960,1604,1326,0]Ao[4739,13,4740,1960,4941,1326,0]Ao[4739,13,4740,3173,4782,1326,0]Ao[4739,13,4740,1526,1587,1326,0]Ao[4739,13,4740,1526,4164,1326,0]Ao[4739,13,4740,1526,3331,1326,0]Ao[4739,13,4740,1526,3144,1326,0]Ao[4739,13,4740,1526,4836,1326,0]Ao[4739,13,4740,1526,3306,1326,0]Ao[4739,13,4740,1542,2435,1326,0]Ao[4739,13,4740,1542,3317,1326,0]Ao[4739,13,4740,1542,3146,1326,0]Ao[4739,13,4740,1542,4504,1326,0]Ao[4739,13,4740,1075,3149,1326,0]Ao[4739,13,4740,1075,4294,1326,0]Ao[4739,13,4740,1080,2019,1326,0]Ao[4739,13,4740,1080,3356,1326,0]Ao[4739,13,4740,1080,3998,1326,0]Ao[4739,13,4740,2152,4406,1326,0]Ao[4739,13,4740,2152,4130,1326,0]Ao[4739,13,4740,3713,4500,1326,0]Ao[4739,13,4740,3713,3141,1326,0]Ao[4739,13,4740,3713,4372,1326,0]Ao[4739,13,4740,3713,5024,1326,0]Ao[4739,13,4740,3293,4521,1326,0]Ao[4739,13,4740,3293,4806,1326,0]Ao[4739,13,4740,3293,4821,1326,0]Ao[4739,13,4740,3293,4000,1326,0]Ao[4739,13,4740,1842,4382,1326,0]Ao[4739,13,4740,1842,4170,1326,0]Ao[4739,13,4740,1842,4998,1326,0]Ao[4739,13,4740,1842,4122,1326,0]Ao[4739,13,4740,1842,3990,1326,0]Ao[4739,13,4740,1516,3129,1326,0]Ao[4739,13,4740,1516,3323,1326,0]Ao[4739,13,4740,1516,3345,1326,0]Ao[4739,13,4740,1516,4137,1326,0]Ao[4739,13,4740,1516,4498,1326,0]Ao[4739,13,4740,1516,4686,1326,0]Ao[4739,13,4740,1516,2393,1326,0]Ao[4739,13,4740,2445,4690,1326,0]Ao[4739,13,4740,2445,4133,1326,0]Ao[4739,13,4740,1907,4512,1326,0]Ao[4739,13,4740,1907,5027,1326,0]Ao[4739,13,4740,1907,2406,1326,0]Ao[4739,13,4740,1907,4780,1326,0]Ao[4739,13,4740,1934,4136,1326,0]Ao[4739,13,4740,1934,4141,1326,0]Al[4739,13,4740,0,4410,1326,0]Al[4739,13,4740,0,4840,1326,0]Ao[4739,13,4740,4307,3320,1326,0]Ao[4739,13,4740,4307,5120,1326,0]An[4739,13,4740,4740,486,1326,0]An[4739,13,4740,4740,120,1326,0]Ao[4739,13,4740,4740,2423,1326,0]Ao[4739,13,4740,4740,3127,1326,0]Ao[4739,13,1840,1840,4300,1326,0]Ao[4739,13,4982,4982,4881,1326,0]Ao[4739,13,4982,4982,1343,1326,0]Ao[4739,13,1924,1924,4937,1326,0]Al[4739,13,1924,0,1342,1326,0]Am[4739,13,3708,135,114,1326,0]An[4739,13,3708,135,3117,1326,0]Ao[4739,13,3708,1511,1329,1326,0]Ao[4739,13,3708,1511,3995,1326,0]Ao[4739,13,3708,2493,1993,1326,0]Ao[4739,13,3708,2493,4287,1326,0]Ao[4739,13,2123,2123,1347,1326,0]Ao[4445,13,4446,4446,2420,1326,0]Ao[4445,13,4446,4446,2433,1326,0]Ao[4445,13,4446,4446,4142,1326,0]Ao[1050,13,1051,1051,4874,1326,0]Ao[1050,13,1541,1541,4508,1326,0]Al[3954,13,3955,3712,3310,0,0]Al[3954,13,3955,2444,2399,0,0]Ak[3954,13,3955,1049,478,0,0]Al[4739,13,4740,3713,3311,0,0]Al[3954,13,3955,0,4135,1332,0]Ao[4739,13,4740,1934,4136,1332,0]Ai[4739,14,3142,0,4277,0,0]Ai[4739,14,4740,0,4410,0,0]Ai[3954,13,3955,0,2422,0,0]Al[4739,13,4740,4740,2423,0,0]Ai[3954,13,3955,0,4140,0,0]Al[4739,13,4740,1934,4141,0,0]Ai[3954,14,1844,0,1987,0,0]Al[4739,14,1845,1845,1988,0,0]Al[4739,12,4740,1907,4811,0,0]Ao[4739,13,4740,1907,5145,4811,0]=Al[4739,13,4982,4982,4881,0,0]Ah[3954,5,3955,2444,0,0,0]Ai[3954,15,3955,0,3128,0,0]Al[4739,15,4740,1516,3129,0,0]Al[1365,15,1366,1366,3986,0,0]0Al[4739,15,4740,1526,3331,0,0]Ah[4739,5,4740,1075,0,0,0]Ah[3954,15,3955,0,485,0,0]Ak[4739,15,4740,4740,486,0,0]Al[3974,15,3975,3975,2390,0,0]Al[4739,15,4740,1526,3144,0,0]Al[4739,15,2123,2123,1344,0,0]98Ah[3954,5,3955,3712,0,0,0]2Al[4739,15,4740,2152,4016,0,0]Ah[3954,5,3955,1526,0,0,0]Ah[4739,5,4740,1526,0,0,0]Ae[4739,8,1840,0,0,0,0]987>Al[4739,15,4740,3713,1346,0,0]>Ah[3954,5,3955,1960,0,0,0]Ah[4739,5,4740,1960,0,0,0]Al[3954,13,3955,2444,2399,0,0]Al[3954,13,3955,2471,2403,0,0]Al[4739,13,4740,2152,2012,0,0]Al[4739,13,4740,2445,2400,0,0]An[1365,13,1366,1366,127,1564,0]Ao[1365,13,1366,1366,3986,1564,0]Ao[1365,13,1540,1540,4017,1564,0]Ao[1365,13,1540,1540,1361,1564,0]Ao[1365,13,1540,1540,4407,1564,0]Al[495,13,496,496,3987,1564,0]Ao[4023,13,4024,4024,5028,1564,0]Ao[3954,13,3955,3712,4525,1564,0]Ao[3954,13,3955,3712,2413,1564,0]Al[3954,13,3955,0,4258,1564,0]Ao[3954,13,3955,1049,2414,1564,0]Ao[3954,13,3955,1049,3119,1564,0]Ao[3954,13,3955,1049,4682,1564,0]Ao[3954,13,3955,3712,3308,1564,0]Ao[3954,13,3955,3712,3310,1564,0]Ao[3954,13,3955,3712,1995,1564,0]Ao[3954,13,3955,3712,1579,1564,0]Ao[3954,13,3955,3712,3109,1564,0]Ao[3954,13,3955,3712,2387,1564,0]Ao[3954,13,3955,3712,4160,1564,0]Ao[3954,13,3955,3712,4165,1564,0]Ao[3954,13,3955,3712,4943,1564,0]Ao[3954,13,3955,3712,4781,1564,0]Ao[3954,13,3955,2444,2399,1564,0]Ao[3954,13,3955,2444,4267,1564,0]Ao[3954,13,3955,2444,1558,1564,0]Ao[3954,13,3955,2471,2403,1564,0]Ao[3954,13,3955,2471,3338,1564,0]Ao[3954,13,3955,2471,4386,1564,0]An[3954,13,3955,1049,478,1564,0]Ao[3954,13,3955,4090,3335,1564,0]Ao[3954,13,3955,4090,4882,1564,0]Ao[3954,13,3955,4090,4405,1564,0]Ao[3954,13,3955,4090,3148,1564,0]Ao[3954,13,3955,4090,3337,1564,0]Ao[3954,13,3955,4090,4404,1564,0]Ao[3954,13,3955,1552,4175,1564,0]Ao[3954,13,3955,1092,4012,1564,0]Ao[3954,13,3955,4095,3341,1564,0]Ao[3954,13,3955,4095,3355,1564,0]Ao[3954,13,3955,4095,4174,1564,0]Al[3954,13,3955,0,3332,1564,0]Al[3954,13,3955,0,4298,1564,0]Al[3954,13,3955,0,4517,1564,0]Al[3954,13,3955,0,4152,1564,0]Al[3954,13,3955,0,4395,1564,0]Al[3954,13,3955,0,1603,1564,0]Al[3954,13,3955,0,4940,1564,0]Al[3954,13,3955,0,1324,1564,0]Al[3954,13,3955,0,1586,1564,0]Al[3954,13,3955,0,2434,1564,0]Al[3954,13,3955,0,3316,1564,0]Al[3954,13,3955,0,3145,1564,0]Al[3954,13,3955,0,4503,1564,0]Al[3954,13,3955,0,2018,1564,0]Al[3954,13,3955,0,4126,1564,0]Al[3954,13,3955,0,4499,1564,0]Al[3954,13,3955,0,4513,1564,0]Al[3954,13,3955,0,4520,1564,0]Al[3954,13,3955,0,4805,1564,0]Al[3954,13,3955,0,4820,1564,0]Al[3954,13,3955,0,3999,1564,0]Al[3954,13,3955,0,4381,1564,0]Al[3954,13,3955,0,4168,1564,0]Al[3954,13,3955,0,4997,1564,0]Al[3954,13,3955,0,4120,1564,0]Al[3954,13,3955,0,3989,1564,0]Al[3954,13,3955,0,3128,1564,0]Al[3954,13,3955,0,4496,1564,0]Al[3954,13,3955,0,4684,1564,0]Al[3954,13,3955,0,4132,1564,0]Al[3954,13,3955,0,4135,1564,0]Al[3954,13,3955,0,4140,1564,0]Al[3954,13,3955,0,4839,1564,0]Al[3954,13,3955,0,3319,1564,0]Al[3954,13,3955,0,4715,1564,0]Ak[3954,13,3955,0,485,1564,0]Ak[3954,13,3955,0,119,1564,0]Al[3954,13,3955,0,2422,1564,0]Al[3954,13,3955,0,2431,1564,0]Ak[3954,13,3707,0,113,1564,0]Al[3954,13,3707,0,3116,1564,0]Al[3954,13,3707,0,1328,1564,0]Al[3954,13,3707,0,3994,1564,0]Al[3954,13,3707,0,1992,1564,0]Al[3954,13,3707,0,4286,1564,0]Al[3954,13,3707,0,4773,1564,0]Al[3954,13,1844,0,1987,1564,0]Ak[3954,13,1844,0,472,1564,0]Al[3954,13,1844,0,5086,1564,0]Al[3954,13,1844,0,3992,1564,0]Al[3954,13,1844,0,4843,1564,0]Al[3954,13,1923,0,3350,1564,0]Al[3954,13,1923,0,4269,1564,0]Al[3954,13,1923,0,4711,1564,0]Al[3954,13,1923,0,4713,1564,0]Al[3954,13,1923,0,4936,1564,0]Al[3954,13,1923,0,1341,1564,0]Ao[4739,13,4740,4530,4259,1564,0]Ao[4739,13,4740,3173,3123,1564,0]Ao[4739,13,4740,1075,1566,1564,0]Ao[4739,13,4740,2152,2012,1564,0]Ao[4739,13,4740,2152,3336,1564,0]Ao[4739,13,4740,2152,3342,1564,0]Ao[4739,13,4740,3713,3311,1564,0]Ao[4739,13,4740,1071,3333,1564,0]Ao[4739,13,4740,1842,4299,1564,0]Ao[4739,13,4740,2445,2400,1564,0]Ao[4739,13,4740,2445,4265,1564,0]Ao[4739,13,4740,1907,5145,1564,0]Ao[4739,13,4740,4307,5115,1564,0]Ao[4739,13,4740,1551,4518,1564,0]Ao[4739,13,4740,1551,4153,1564,0]Ao[4739,13,4740,1551,4396,1564,0]Ao[4739,13,4740,1960,1604,1564,0]Ao[4739,13,4740,1960,4941,1564,0]Ao[4739,13,4740,3164,1325,1564,0]Ao[4739,13,4740,3173,4782,1564,0]Ao[4739,13,4740,1526,1587,1564,0]Ao[4739,13,4740,1526,4164,1564,0]Ao[4739,13,4740,1526,3331,1564,0]Ao[4739,13,4740,1526,3144,1564,0]Ao[4739,13,4740,1526,4836,1564,0]Ao[4739,13,4740,1526,3306,1564,0]Ao[4739,13,4740,1542,2435,1564,0]Ao[4739,13,4740,1542,3317,1564,0]Ao[4739,13,4740,1542,3146,1564,0]Ao[4739,13,4740,1542,4504,1564,0]Ao[4739,13,4740,1075,3149,1564,0]Ao[4739,13,4740,1075,4294,1564,0]Ao[4739,13,4740,1080,2019,1564,0]Ao[4739,13,4740,1080,3356,1564,0]Ao[4739,13,4740,1080,3998,1564,0]Ao[4739,13,4740,2152,4016,1564,0]Ao[4739,13,4740,2152,4406,1564,0]Ao[4739,13,4740,2152,4130,1564,0]Ao[4739,13,4740,3713,4500,1564,0]Ao[4739,13,4740,3713,3141,1564,0]Ao[4739,13,4740,3713,4372,1564,0]Ao[4739,13,4740,3713,5024,1564,0]Ao[4739,13,4740,3713,1346,1564,0]Ao[4739,13,4740,1071,4514,1564,0]Ao[4739,13,4740,3293,4521,1564,0]Ao[4739,13,4740,3293,4806,1564,0]Ao[4739,13,4740,3293,4821,1564,0]Ao[4739,13,4740,3293,4000,1564,0]Ao[4739,13,4740,1842,4382,1564,0]Ao[4739,13,4740,1842,4170,1564,0]Ao[4739,13,4740,1842,4998,1564,0]Ao[4739,13,4740,1842,4122,1564,0]Ao[4739,13,4740,1842,3990,1564,0]Ao[4739,13,4740,1516,3129,1564,0]Ao[4739,13,4740,1516,4387,1564,0]Ao[4739,13,4740,1516,3323,1564,0]Ao[4739,13,4740,1516,3345,1564,0]Ao[4739,13,4740,1516,4137,1564,0]Ao[4739,13,4740,1516,4498,1564,0]Ao[4739,13,4740,1516,4686,1564,0]Ao[4739,13,4740,1516,2393,1564,0]Ao[4739,13,4740,2445,4690,1564,0]Ao[4739,13,4740,2445,2404,1564,0]Ao[4739,13,4740,2445,4133,1564,0]Ao[4739,13,4740,2445,3984,1564,0]Ao[4739,13,4740,2445,3339,1564,0]Ao[4739,13,4740,1907,4289,1564,0]Ao[4739,13,4740,1907,4512,1564,0]Ao[4739,13,4740,1907,5027,1564,0]Ao[4739,13,4740,1907,2406,1564,0]Ao[4739,13,4740,1907,4780,1564,0]Ao[4739,13,4740,1934,4502,1564,0]Ao[4739,13,4740,1934,4266,1564,0]Ao[4739,13,4740,1934,4136,1564,0]Ao[4739,13,4740,1934,4141,1564,0]Al[4739,13,4740,0,4410,1564,0]Al[4739,13,4740,0,4840,1564,0]Ao[4739,13,4740,4307,3320,1564,0]Ao[4739,13,4740,4307,5120,1564,0]Ao[4739,13,4740,4870,4716,1564,0]An[4739,13,4740,4740,486,1564,0]An[4739,13,4740,4740,120,1564,0]Ao[4739,13,4740,4740,2423,1564,0]Ao[4739,13,4740,4740,2432,1564,0]Ao[4739,13,4740,4740,3127,1564,0]Ao[4739,13,1840,1840,4300,1564,0]Ao[4739,13,4982,4982,4881,1564,0]Ao[4739,13,4982,4982,1343,1564,0]Ao[4739,13,1845,1845,1988,1564,0]An[4739,13,1845,1845,473,1564,0]Ao[4739,13,1845,1845,5087,1564,0]Ao[4739,13,1845,1845,3993,1564,0]Ao[4739,13,1845,1845,4846,1564,0]Ao[4739,13,1924,1924,3351,1564,0]Ao[4739,13,1924,1924,4270,1564,0]Ao[4739,13,1924,1924,4712,1564,0]Ao[4739,13,1924,1924,4714,1564,0]Ao[4739,13,1924,1924,4937,1564,0]Al[4739,13,1924,0,1342,1564,0]Am[4739,13,3708,135,114,1564,0]An[4739,13,3708,135,3117,1564,0]Ao[4739,13,3708,1511,1329,1564,0]Ao[4739,13,3708,1511,3995,1564,0]Ao[4739,13,3708,2493,1993,1564,0]Ao[4739,13,3708,2493,4287,1564,0]Ao[4739,13,3708,3708,4774,1564,0]Ao[4739,13,2123,2123,1344,1564,0]Ao[4739,13,2123,2123,1347,1564,0]Ao[4445,13,4446,4446,3354,1564,0]An[4445,13,4446,393,4411,1564,0]Ao[4445,13,4446,4446,2420,1564,0]Ao[4445,13,4446,4446,2433,1564,0]Ao[4445,13,4446,4446,4142,1564,0]Ao[1050,13,1051,1051,3120,1564,0]Ao[1050,13,1051,1051,4874,1564,0]An[1050,13,1834,1834,128,1564,0]Ao[1050,13,1541,1541,1362,1564,0]Ao[1050,13,1541,1541,4018,1564,0]Ao[1050,13,1541,1541,4508,1564,0]Ao[1050,13,4227,4227,5072,1564,0]Ao[1050,13,4227,4227,5073,1564,0]An[1050,13,1929,1929,129,1564,0]An[3974,13,3975,3975,118,1564,0]Ao[3974,13,3975,3975,2390,1564,0]Ai[3954,14,3955,0,2018,0,0]Al[4739,14,4740,1080,2019,0,0]Ak[1365,14,1366,1366,127,0,0]Ac[495,7,496,0,0,0,0]Al[3954,13,3955,2444,2399,0,0]Ae[1050,2,1051,0,0,0,0]Ae[4800,7,4801,0,0,0,0]Al[3954,13,3955,3712,3310,0,0]Ae[4739,2,4740,0,0,0,0]Al[4739,13,4740,2445,2400,0,0]Ah[3954,2,3955,4740,0,0,0]Ai[3954,13,3955,0,4839,0,0]Ai[3954,14,3955,0,3316,0,0]Ai[3954,14,3955,0,4168,0,0]5Ai[4739,13,4740,0,4840,0,0]Al[4739,14,4740,1542,3317,0,0]Al[4739,14,4740,1842,4170,0,0]Ai[4739,14,4740,0,4410,0,0]Al[3954,13,3955,0,1603,3124,0]Al[3954,13,3955,0,1586,3124,0]Al[3954,13,3955,0,3128,3124,0]Al[3954,13,3955,0,4839,3124,0]Al[3954,13,3955,0,2422,3124,0]Ao[4739,13,4740,1960,1604,3124,0]Ao[4739,13,4740,1526,1587,3124,0]Ao[4739,13,4740,1516,3129,3124,0]Ao[4739,13,4740,1516,3323,3124,0]Al[4739,13,4740,1907,4512,0,0]Al[4739,13,4740,0,4840,3124,0]Ao[4739,13,4740,4740,2423,3124,0]Al[4739,12,1840,1840,3124,0,0]Al[4445,14,4446,4446,2420,0,0]Al[3954,13,3955,0,1603,3125,0]Al[3954,13,3955,0,1586,3125,0]Al[3954,13,3955,0,3128,3125,0]Al[3954,13,3955,0,4839,3125,0]Al[3954,13,3955,0,2422,3125,0]Ao[4739,13,4740,1960,1604,3125,0]Ao[4739,13,4740,1526,1587,3125,0]Ao[4739,13,4740,1516,3129,3125,0]Ao[4739,13,4740,1516,3323,3125,0]Ao[4739,13,4740,1516,2393,3125,0]Al[4739,13,4740,0,4840,3125,0]Ao[4739,13,4740,4740,2423,3125,0]Al[4739,12,1840,1840,3125,0,0]Al[3954,13,3955,4095,3341,0,0]Al[4739,13,4740,2152,3342,0,0]Al[1050,13,1541,1541,4018,0,0]Al[4739,13,4740,2445,2400,0,0]Ah[3954,14,1844,0,472,0,0]Ak[4739,14,1845,1845,473,0,0]Al[3954,13,3955,2471,2403,0,0]3Ai[3954,12,3955,0,3352,0,0]Al[3954,13,3955,0,4395,3352,0]Al[3954,13,3955,0,4715,3352,0]Al[4739,12,4740,1551,3353,0,0]Ao[4739,13,4740,1551,4396,3353,0]Ao[4739,13,4740,4870,4716,3353,0]Al[1050,14,1051,1051,3120,0,0]Ai[3954,14,3955,0,1324,0,0]Al[4739,14,4740,3164,1325,0,0]Ai[3954,13,3707,0,3312,0,0]Ak[3954,13,3707,0,113,3312,0]Al[3954,13,3707,0,1328,3312,0]Al[3954,13,3707,0,1992,3312,0]Al[4739,13,3708,3708,3313,0,0]Am[4739,13,3708,135,114,3313,0]Ao[4739,13,3708,1511,1329,3313,0]Ao[4739,13,3708,2493,1993,3313,0]Ah[3954,14,1844,0,472,0,0]Ak[4739,14,1845,1845,473,0,0]Ai[4739,14,4511,0,4719,0,0]Ai[3954,14,3955,0,4496,0,0]Ai[3954,14,3955,0,4684,0,0]Al[4739,14,4740,1516,4498,0,0]Al[4739,14,4740,1516,4686,0,0]Ai[4739,14,4740,0,4410,0,0]Ai[4739,14,1345,0,4374,0,0]Al[3954,13,3955,2444,2399,0,0]Al[3954,13,3955,2471,2403,0,0]Al[4739,13,4740,2445,2400,0,0]Ai[3954,14,1844,0,1987,0,0]Al[4739,14,4740,4740,3127,0,0]Al[4739,14,1845,1845,1988,0,0]Ae[3954,4,3955,0,0,0,0]Ah[3954,2,1844,1845,0,0,0]Ae[4739,4,4740,0,0,0,0]Ae[4739,2,1845,0,0,0,0]Ac[495,7,496,0,0,0,0]:Ae[1050,2,1051,0,0,0,0]Ae[4800,7,4801,0,0,0,0]Ao[3954,13,3955,3712,4781,1334,0]Ao[3954,13,3955,4090,4405,1334,0]Ao[3954,13,3955,4090,3148,1334,0]Ao[3954,13,3955,4090,3337,1334,0]Ao[3954,13,3955,4090,4404,1334,0]Ao[3954,13,3955,4095,3355,1334,0]Ao[3954,13,3955,4095,4174,1334,0]Al[3954,13,3955,0,4499,1334,0]Ao[4739,13,4740,3713,4500,1334,0]Ai[3954,14,3955,0,2431,0,0]Al[4739,14,4740,4740,2432,0,0]Al[4445,14,4446,4446,2433,0,0]Ak[3954,13,3955,1049,478,0,0]Ai[4739,14,3142,0,4161,0,0]Ai[3954,14,3955,0,3316,0,0]Al[4739,14,4740,1542,3317,0,0]Al[4445,14,4446,4446,2420,0,0]Ai[3954,14,3955,0,3145,0,0]Ai[3954,14,3955,0,4503,0,0]Al[4739,14,4740,1542,3146,0,0]Al[4739,14,4740,1542,4504,0,0]3210Ai[3954,12,1844,0,1983,0,0]Al[4739,12,1845,1845,1984,0,0]Ai[3954,12,3707,0,3312,0,0]Ak[3954,13,3707,0,113,3312,0]Al[3954,13,3707,0,1328,3312,0]Al[3954,13,3707,0,1992,3312,0]Al[4739,12,3708,3708,3313,0,0]Am[4739,13,3708,135,114,3313,0]Ao[4739,13,3708,1511,1329,3313,0]Ao[4739,13,3708,2493,1993,3313,0]Ai[3954,10,1844,1845,0,0,0]Af[4739,10,1845,0,0,0,0]Al[4739,15,4740,3173,4782,0,0]Al[4739,15,4740,1075,3149,0,0]Al[4739,15,4740,1080,3356,0,0]Ai[3954,15,1923,0,1341,0,0]Ai[4739,15,1924,0,1342,0,0]65Al[4739,15,4740,1907,4512,0,0]Ah[3954,5,1844,1845,0,0,0]Ae[4739,5,1845,0,0,0,0]Ai[3954,15,3955,0,3128,0,0]Al[4739,15,4740,1516,3129,0,0]Ah[3954,5,3707,2493,0,0,0]Ah[4739,5,3708,2493,0,0,0]Al[1050,15,1051,1051,4874,0,0]Ah[3954,5,3955,3712,0,0,0]5454Ai[3954,10,3955,2144,0,0,0]Ai[3954,10,1844,1845,0,0,0]Af[4739,10,1845,0,0,0,0]Al[3954,15,3955,4095,3355,0,0]?Al[4739,15,4740,1080,3998,0,0]Al[4739,15,4740,2152,4016,0,0]Ah[4739,5,4740,2152,0,0,0]Al[3954,15,3955,4090,4405,0,0]Al[4739,15,4740,1516,3323,0,0]Ah[3954,5,3955,1080,0,0,0]Ah[4739,5,4740,1080,0,0,0]Al[4739,15,4740,1907,2406,0,0]Ai[3954,12,3955,0,4988,0,0]Al[4739,12,4740,4307,4989,0,0]Ao[4739,13,4740,4307,5115,4989,0]Ao[4739,13,4740,4307,5120,4989,0]Ak[1365,14,1366,1366,127,0,0]An[1365,13,1366,1366,127,4373,0]Ao[1050,13,1051,1051,3120,4373,0]An[1050,13,1834,1834,128,4373,0]An[1050,13,1929,1929,129,4373,0]An[3974,13,3975,3975,118,4373,0]Ak[3974,14,3975,3975,118,0,0]Al[3954,13,3955,0,1603,3307,0]Al[3954,13,3955,0,1586,3307,0]Al[3954,13,3955,0,3999,3307,0]Al[3954,13,3955,0,4135,3307,0]Ak[3954,13,3955,0,485,3307,0]Ak[3954,13,3955,0,119,3307,0]Al[3954,13,3955,0,2422,3307,0]Ao[4739,13,4740,1960,1604,3307,0]Ao[4739,13,4740,3173,4782,3307,0]Ao[4739,13,4740,1526,1587,3307,0]Ao[4739,13,4740,1075,3149,3307,0]Ao[4739,13,4740,1075,4294,3307,0]Ao[4739,13,4740,1080,3356,3307,0]Ao[4739,13,4740,3293,4000,3307,0]Ao[4739,13,4740,2445,4690,3307,0]Ao[4739,13,4740,1907,4780,3307,0]Ao[4739,13,4740,1934,4136,3307,0]An[4739,13,4740,4740,486,3307,0]An[4739,13,4740,4740,120,3307,0]Ao[4739,13,4740,4740,2423,3307,0]Al[3954,13,3955,2444,2399,0,0]Al[4739,13,4740,2445,2400,0,0]Ai[3954,12,1844,0,3138,0,0]Ai[3954,12,1844,0,3131,0,0]Al[4739,12,1845,1845,3139,0,0]Al[4739,12,1845,1845,3132,0,0]Ao[1365,13,1540,1540,4017,1978,0]Ao[1365,13,1540,1540,1361,1978,0]Al[495,13,496,496,3987,1978,0]Al[3954,13,3955,0,4258,1978,0]Ao[3954,13,3955,2444,4267,1978,0]Al[3954,13,3955,0,1603,1978,0]Al[3954,13,3955,0,1586,1978,0]Al[3954,13,3955,0,2434,1978,0]Al[3954,13,3955,0,3316,1978,0]Al[3954,13,3955,0,3145,1978,0]Al[3954,13,3955,0,4503,1978,0]Al[3954,13,3955,0,2018,1978,0]Al[3954,13,3955,0,4126,1978,0]Al[3954,13,3955,0,4520,1978,0]Al[3954,13,3955,0,4805,1978,0]Al[3954,13,3955,0,4820,1978,0]Al[3954,13,3955,0,3999,1978,0]Al[3954,13,3955,0,4381,1978,0]Al[3954,13,3955,0,4997,1978,0]Al[3954,13,3955,0,4715,1978,0]Al[3954,13,3707,0,3116,1978,0]Al[3954,13,3707,0,3994,1978,0]Al[3954,13,3707,0,4286,1978,0]Al[3954,13,3707,0,4773,1978,0]Ao[4739,13,4740,4530,4259,1978,0]Ao[4739,13,4740,4307,5115,1978,0]Ao[4739,13,4740,1960,1604,1978,0]Ao[4739,13,4740,1526,1587,1978,0]Ao[4739,13,4740,1526,3331,1978,0]Ao[4739,13,4740,1526,3306,1978,0]Ao[4739,13,4740,1542,2435,1978,0]Ao[4739,13,4740,1542,3317,1978,0]Ao[4739,13,4740,1542,3146,1978,0]Ao[4739,13,4740,1542,4504,1978,0]Ao[4739,13,4740,1080,2019,1978,0]Ao[4739,13,4740,2152,4406,1978,0]Ao[4739,13,4740,2152,4130,1978,0]Ao[4739,13,4740,3293,4521,1978,0]Ao[4739,13,4740,3293,4806,1978,0]Ao[4739,13,4740,3293,4821,1978,0]Ao[4739,13,4740,3293,4000,1978,0]Ao[4739,13,4740,1842,4382,1978,0]Ao[4739,13,4740,1842,4998,1978,0]Ao[4739,13,4740,4307,5120,1978,0]Ao[4739,13,4740,4870,4716,1978,0]An[4739,13,3708,135,3117,1978,0]Ao[4739,13,3708,1511,3995,1978,0]Ao[4739,13,3708,2493,4287,1978,0]Ao[4739,13,3708,3708,4774,1978,0]Ao[4445,13,4446,4446,2420,1978,0]Ao[1050,13,1541,1541,1362,1978,0]Ao[1050,13,1541,1541,4508,1978,0]Al[4739,13,4740,1934,4266,0,0]Al[4739,13,4740,1907,4289,0,0]Al[4739,13,4740,1907,4512,0,0]Al[4739,14,4740,1907,5027,0,0]Ai[4739,14,4779,0,4841,0,0]Ah[4739,14,4511,0,474,0,0]Ai[4739,14,4511,0,1356,0,0]Ai[4739,14,4511,0,1358,0,0]Ai[4739,14,4511,0,4719,0,0]Ai[3954,12,1844,0,3138,0,0]Ai[3954,12,1844,0,3131,0,0]Al[4739,12,1845,1845,3139,0,0]Al[4739,12,1845,1845,3132,0,0]Ae[4739,2,4740,0,0,0,0]Al[3954,13,3955,4090,3335,0,0]Al[3954,13,3955,4090,4882,0,0]Ai[3954,13,3707,0,3312,0,0]Ak[3954,13,3707,0,113,3312,0]Al[3954,13,3707,0,1328,3312,0]Al[3954,13,3707,0,1992,3312,0]Al[4739,13,3708,3708,3313,0,0]Am[4739,13,3708,135,114,3313,0]Ao[4739,13,3708,1511,1329,3313,0]Ao[4739,13,3708,2493,1993,3313,0]Ai[3954,13,3955,0,4520,0,0]Al[4739,13,4740,3293,4521,0,0]9854Al[3954,13,3955,3712,3310,0,0]Al[3954,13,3955,1049,2414,0,0]Al[4739,14,4740,1907,5027,0,0]Ai[4739,14,4779,0,4841,0,0]Ah[4739,14,4511,0,474,0,0]Ai[4739,14,4511,0,1356,0,0]Ai[4739,14,4511,0,4719,0,0]Al[3954,13,3955,4095,3341,0,0]Al[4739,13,4740,2152,3342,0,0]Ak[1365,14,1366,1366,127,0,0]Al[1365,14,1540,1540,1361,0,0]Al[4739,13,4740,3713,3311,0,0]Ai[3954,12,1844,0,3138,0,0]Al[4739,12,1845,1845,3139,0,0]Am[1365,13,1366,1366,127,111,0]An[1365,13,1366,1366,3986,111,0]An[1365,13,1540,1540,4017,111,0]An[1365,13,1540,1540,1361,111,0]An[1365,13,1540,1540,4407,111,0]Ak[495,13,496,496,3987,111,0]An[4023,13,4024,4024,5028,111,0]An[3954,13,3955,3712,4525,111,0]An[3954,13,3955,3712,2413,111,0]Ak[3954,13,3955,0,4258,111,0]An[3954,13,3955,1049,2414,111,0]An[3954,13,3955,1049,3119,111,0]An[3954,13,3955,1049,4682,111,0]An[3954,13,3955,3712,3308,111,0]An[3954,13,3955,3712,3310,111,0]An[3954,13,3955,3712,1995,111,0]An[3954,13,3955,3712,1579,111,0]An[3954,13,3955,3712,3109,111,0]An[3954,13,3955,3712,2387,111,0]An[3954,13,3955,3712,4160,111,0]An[3954,13,3955,3712,4165,111,0]An[3954,13,3955,3712,4943,111,0]An[3954,13,3955,3712,4781,111,0]An[3954,13,3955,2444,2399,111,0]An[3954,13,3955,2444,4267,111,0]An[3954,13,3955,2444,1558,111,0]An[3954,13,3955,2471,2403,111,0]An[3954,13,3955,2471,3338,111,0]An[3954,13,3955,2471,4386,111,0]Am[3954,13,3955,1049,478,111,0]An[3954,13,3955,4090,3335,111,0]An[3954,13,3955,4090,4882,111,0]An[3954,13,3955,4090,4405,111,0]An[3954,13,3955,4090,3148,111,0]An[3954,13,3955,4090,3337,111,0]An[3954,13,3955,4090,4404,111,0]An[3954,13,3955,1552,4175,111,0]An[3954,13,3955,1092,4012,111,0]An[3954,13,3955,4095,3341,111,0]An[3954,13,3955,4095,3355,111,0]An[3954,13,3955,4095,4174,111,0]Ak[3954,13,3955,0,3332,111,0]Ak[3954,13,3955,0,4298,111,0]Ak[3954,13,3955,0,4517,111,0]Ak[3954,13,3955,0,4152,111,0]Ak[3954,13,3955,0,4395,111,0]Ak[3954,13,3955,0,1603,111,0]Ak[3954,13,3955,0,4940,111,0]Ak[3954,13,3955,0,1324,111,0]Ak[3954,13,3955,0,1586,111,0]Ak[3954,13,3955,0,2434,111,0]Ak[3954,13,3955,0,3316,111,0]Ak[3954,13,3955,0,3145,111,0]Ak[3954,13,3955,0,4503,111,0]Ak[3954,13,3955,0,2018,111,0]Ak[3954,13,3955,0,4126,111,0]Ak[3954,13,3955,0,4499,111,0]Ak[3954,13,3955,0,4513,111,0]Ak[3954,13,3955,0,4520,111,0]Ak[3954,13,3955,0,4805,111,0]Ak[3954,13,3955,0,4820,111,0]Ak[3954,13,3955,0,3999,111,0]Ak[3954,13,3955,0,4381,111,0]Ak[3954,13,3955,0,4168,111,0]Ak[3954,13,3955,0,4997,111,0]Ak[3954,13,3955,0,4120,111,0]Ak[3954,13,3955,0,3989,111,0]Ak[3954,13,3955,0,3128,111,0]Ak[3954,13,3955,0,4496,111,0]Ak[3954,13,3955,0,4684,111,0]Ak[3954,13,3955,0,4132,111,0]Ak[3954,13,3955,0,4135,111,0]Ak[3954,13,3955,0,4140,111,0]Ak[3954,13,3955,0,4839,111,0]Ak[3954,13,3955,0,3319,111,0]Ak[3954,13,3955,0,4715,111,0]Aj[3954,13,3955,0,485,111,0]Aj[3954,13,3955,0,119,111,0]Ak[3954,13,3955,0,2422,111,0]Ak[3954,13,3955,0,2431,111,0]Aj[3954,13,3707,0,113,111,0]Ak[3954,13,3707,0,3116,111,0]Ak[3954,13,3707,0,1328,111,0]Ak[3954,13,3707,0,3994,111,0]Ak[3954,13,3707,0,1992,111,0]Ak[3954,13,3707,0,4286,111,0]Ak[3954,13,3707,0,4773,111,0]Ak[3954,13,1844,0,1987,111,0]Aj[3954,13,1844,0,472,111,0]Ak[3954,13,1844,0,5086,111,0]Ak[3954,13,1844,0,3992,111,0]Ak[3954,13,1844,0,4843,111,0]Ak[3954,13,1923,0,3350,111,0]Ak[3954,13,1923,0,4269,111,0]Ak[3954,13,1923,0,4711,111,0]Ak[3954,13,1923,0,4713,111,0]Ak[3954,13,1923,0,4936,111,0]Ak[3954,13,1923,0,1341,111,0]An[4739,13,4740,4530,4259,111,0]An[4739,13,4740,3173,3123,111,0]An[4739,13,4740,1075,1566,111,0]An[4739,13,4740,2152,2012,111,0]An[4739,13,4740,2152,3336,111,0]An[4739,13,4740,2152,3342,111,0]An[4739,13,4740,3713,3311,111,0]An[4739,13,4740,1071,3333,111,0]An[4739,13,4740,1842,4299,111,0]An[4739,13,4740,2445,2400,111,0]An[4739,13,4740,2445,4265,111,0]An[4739,13,4740,1907,5145,111,0]An[4739,13,4740,4307,5115,111,0]An[4739,13,4740,1551,4518,111,0]An[4739,13,4740,1551,4153,111,0]An[4739,13,4740,1551,4396,111,0]An[4739,13,4740,1960,1604,111,0]An[4739,13,4740,1960,4941,111,0]An[4739,13,4740,3164,1325,111,0]An[4739,13,4740,3173,4782,111,0]An[4739,13,4740,1526,1587,111,0]An[4739,13,4740,1526,4164,111,0]An[4739,13,4740,1526,3331,111,0]An[4739,13,4740,1526,3144,111,0]An[4739,13,4740,1526,4836,111,0]An[4739,13,4740,1526,3306,111,0]An[4739,13,4740,1542,2435,111,0]An[4739,13,4740,1542,3317,111,0]An[4739,13,4740,1542,3146,111,0]An[4739,13,4740,1542,4504,111,0]An[4739,13,4740,1075,3149,111,0]An[4739,13,4740,1075,4294,111,0]An[4739,13,4740,1080,2019,111,0]An[4739,13,4740,1080,3356,111,0]An[4739,13,4740,1080,3998,111,0]An[4739,13,4740,2152,4016,111,0]An[4739,13,4740,2152,4406,111,0]An[4739,13,4740,2152,4130,111,0]An[4739,13,4740,3713,4500,111,0]An[4739,13,4740,3713,3141,111,0]An[4739,13,4740,3713,4372,111,0]An[4739,13,4740,3713,5024,111,0]An[4739,13,4740,3713,1346,111,0]An[4739,13,4740,1071,4514,111,0]An[4739,13,4740,3293,4521,111,0]An[4739,13,4740,3293,4806,111,0]An[4739,13,4740,3293,4821,111,0]An[4739,13,4740,3293,4000,111,0]An[4739,13,4740,1842,4382,111,0]An[4739,13,4740,1842,4170,111,0]An[4739,13,4740,1842,4998,111,0]An[4739,13,4740,1842,4122,111,0]An[4739,13,4740,1842,3990,111,0]An[4739,13,4740,1516,3129,111,0]An[4739,13,4740,1516,4387,111,0]An[4739,13,4740,1516,3323,111,0]An[4739,13,4740,1516,3345,111,0]An[4739,13,4740,1516,4137,111,0]An[4739,13,4740,1516,4498,111,0]An[4739,13,4740,1516,4686,111,0]An[4739,13,4740,1516,2393,111,0]An[4739,13,4740,2445,4690,111,0]An[4739,13,4740,2445,2404,111,0]An[4739,13,4740,2445,4133,111,0]An[4739,13,4740,2445,3984,111,0]An[4739,13,4740,2445,3339,111,0]An[4739,13,4740,1907,4289,111,0]An[4739,13,4740,1907,4512,111,0]An[4739,13,4740,1907,5027,111,0]An[4739,13,4740,1907,2406,111,0]An[4739,13,4740,1907,4780,111,0]An[4739,13,4740,1934,4502,111,0]An[4739,13,4740,1934,4266,111,0]An[4739,13,4740,1934,4136,111,0]An[4739,13,4740,1934,4141,111,0]Ak[4739,13,4740,0,4410,111,0]Ak[4739,13,4740,0,4840,111,0]An[4739,13,4740,4307,3320,111,0]An[4739,13,4740,4307,5120,111,0]An[4739,13,4740,4870,4716,111,0]Am[4739,13,4740,4740,486,111,0]Am[4739,13,4740,4740,120,111,0]An[4739,13,4740,4740,2423,111,0]An[4739,13,4740,4740,2432,111,0]An[4739,13,4740,4740,3127,111,0]An[4739,13,1840,1840,4300,111,0]An[4739,13,4982,4982,4881,111,0]An[4739,13,4982,4982,1343,111,0]An[4739,13,1845,1845,1988,111,0]Am[4739,13,1845,1845,473,111,0]An[4739,13,1845,1845,5087,111,0]An[4739,13,1845,1845,3993,111,0]An[4739,13,1845,1845,4846,111,0]An[4739,13,1924,1924,3351,111,0]An[4739,13,1924,1924,4270,111,0]An[4739,13,1924,1924,4712,111,0]An[4739,13,1924,1924,4714,111,0]An[4739,13,1924,1924,4937,111,0]Ak[4739,13,1924,0,1342,111,0]Al[4739,13,3708,135,114,111,0]Am[4739,13,3708,135,3117,111,0]An[4739,13,3708,1511,1329,111,0]An[4739,13,3708,1511,3995,111,0]An[4739,13,3708,2493,1993,111,0]An[4739,13,3708,2493,4287,111,0]An[4739,13,3708,3708,4774,111,0]An[4739,13,2123,2123,1344,111,0]An[4739,13,2123,2123,1347,111,0]An[4445,13,4446,4446,3354,111,0]Am[4445,13,4446,393,4411,111,0]An[4445,13,4446,4446,2420,111,0]An[4445,13,4446,4446,2433,111,0]An[4445,13,4446,4446,4142,111,0]An[1050,13,1051,1051,3120,111,0]An[1050,13,1051,1051,4874,111,0]Am[1050,13,1834,1834,128,111,0]An[1050,13,1541,1541,1362,111,0]An[1050,13,1541,1541,4018,111,0]An[1050,13,1541,1541,4508,111,0]An[1050,13,4227,4227,5072,111,0]An[1050,13,4227,4227,5073,111,0]Am[1050,13,1929,1929,129,111,0]Am[3974,13,3975,3975,118,111,0]An[3974,13,3975,3975,2390,111,0]Al[3954,13,3955,3712,4943,0,0]Ai[3954,13,3955,0,4120,0,0]Al[4739,13,4740,1842,4122,0,0]Al[4739,14,4740,1907,5027,0,0]Ai[4739,14,4779,0,4841,0,0]Ah[4739,14,4511,0,474,0,0]Ai[4739,14,4511,0,1356,0,0]Ah[3954,5,3955,3712,0,0,0]Al[1365,15,1366,1366,3986,0,0]Ae[3974,6,3975,0,0,0,0]Ai[3954,15,3955,0,3128,0,0]Al[4739,15,4740,1516,3129,0,0]Ah[4739,5,4740,1516,0,0,0]Al[3954,15,3955,3712,4781,0,0]Al[4739,15,4740,3173,4782,0,0]Ah[3954,5,3955,2444,0,0,0]Ah[4739,5,4740,2445,0,0,0]Al[4739,15,4740,2152,4016,0,0]Ah[3954,5,3955,2471,0,0,0]2Ah[4739,6,4740,1907,0,0,0]Ai[3954,19,3955,0,1603,0,0]Al[4739,19,4740,1960,1604,0,0]Ai[3954,19,3955,0,4839,0,0]Ai[4739,19,4740,0,4840,0,0]=Ai[3954,12,1844,0,4169,0,0]>Al[3954,13,1923,0,4713,4169,0]>Al[4739,12,1845,1845,4171,0,0]>Ao[4739,13,1924,1924,4714,4171,0]Ao[1050,13,4227,4227,5073,4171,0]An[3974,13,3975,3975,118,4001,0]Ao[3974,13,3975,3975,2390,4001,0]Ai[3954,14,3955,0,3145,0,0]Al[4739,14,4740,1542,3146,0,0]Ai[3954,13,3955,0,4168,0,0]Al[4739,13,4740,1842,4170,0,0]Al[3954,13,3955,2144,4369,0,0]0>=Al[1050,13,1541,1541,4508,0,0]Ae[1050,2,1051,0,0,0,0]Al[3954,13,3955,2471,2403,0,0]Al[4739,13,4740,2445,2404,0,0]Ai[3954,14,3955,0,3316,0,0]Al[4739,14,4740,1542,3317,0,0]Al[4739,13,4740,3713,3311,0,0]Ai[3954,13,3955,0,4520,0,0]Al[4739,13,4740,3293,4521,0,0]43Ai[3954,14,3955,0,2431,0,0]Al[4739,14,4740,4740,2432,0,0]Al[4445,14,4446,4446,2433,0,0]Al[4739,13,4740,2152,2012,0,0]Al[4739,13,4740,4307,5115,0,0]Al[4739,13,4740,4307,5120,0,0]Al[3954,13,3955,4095,3341,0,0]Al[4739,13,4740,2152,3342,0,0]<;Al[1365,14,1540,1540,1361,0,0]Ai[495,14,496,496,3987,0,0]Ai[3954,13,1923,0,4711,0,0]Ai[3954,13,1923,0,4713,0,0]Al[4739,13,1924,1924,4712,0,0]Al[4739,13,1924,1924,4714,0,0]76Ai[3954,15,1923,0,1341,0,0]Ai[4739,15,1924,0,1342,0,0]Ah[3954,5,3955,4530,0,0,0]Ah[4739,5,4740,4530,0,0,0]Ai[3954,15,3955,0,4499,0,0]Ai[3954,15,3955,0,4132,0,0]Al[4739,15,4740,3713,4500,0,0]Al[4739,15,4740,2445,4133,0,0]Ah[4739,6,4740,2445,0,0,0]Ah[4739,5,4740,1934,0,0,0]Ah[3954,5,3955,2444,0,0,0]Al[3954,15,3955,4090,4404,0,0]Ah[3954,5,1923,1924,0,0,0]Ae[4739,5,1924,0,0,0,0]Ai[3954,15,3955,0,3128,0,0]Al[4739,15,4740,1516,3129,0,0]Ai[3954,19,3955,0,4839,0,0]Ai[4739,19,4740,0,4840,0,0]Al[4739,15,4740,1907,4780,0,0]>Al[4739,15,4740,1526,3144,0,0]=5454Al[4739,15,4740,2445,4265,0,0]Ah[3954,5,3707,2493,0,0,0]Ah[4739,5,3708,2493,0,0,0]Ah[4739,5,4740,1907,0,0,0]98Ah[4739,6,4740,1075,0,0,0]:9Ah[3954,5,3955,1842,0,0,0]Ah[4739,5,4740,1842,0,0,0]Ae[4739,5,1840,0,0,0,0]Al[4739,13,4740,3713,3311,0,0]Ai[3954,14,3955,0,3316,0,0]Al[4739,14,4740,1542,3317,0,0]Al[1050,14,1051,1051,3120,0,0]Ae[4739,2,4740,0,0,0,0]Ai[3954,13,3955,0,4381,0,0]Al[4739,13,4740,1842,4382,0,0]Al[3954,12,3955,2144,4369,0,0]Ab[4310,3,0,0,0,0,0]Ak[1365,14,1366,1366,127,0,0]Al[1365,14,1540,1540,4017,0,0]98Al[3954,13,3955,2471,3338,0,0]Al[4739,13,4740,2445,3339,0,0]Ai[3954,13,3955,0,4805,0,0]Al[4739,13,4740,3293,4806,0,0];=Al[3954,13,3955,4090,4882,0,0]Al[4739,13,4740,2152,3336,0,0]Al[3954,13,3955,3712,3308,0,0]Al[3954,13,3955,3712,3310,0,0]Al[3954,13,3955,2471,2403,0,0]Ak[3954,13,3955,1049,478,0,0]Al[4739,13,4740,2445,2404,0,0]<;Ai[3954,13,3955,0,1603,0,0]Ai[3954,13,3955,0,1586,0,0]Al[4739,13,4740,1960,1604,0,0]Al[4739,13,4740,1526,1587,0,0]20Ae[1365,7,1540,0,0,0,0]?>Al[1365,14,1540,1540,1361,0,0]Ao[1050,13,1051,1051,4874,3153,0]Ai[3954,15,3955,0,3128,0,0]Ah[3954,5,3955,1516,0,0,0]Al[4739,15,4740,1516,3129,0,0]Ah[4739,5,4740,1516,0,0,0]Ah[3954,6,3955,3713,0,0,0]Ah[4739,6,4740,3713,0,0,0]Al[4739,15,4740,2445,4265,0,0]Ah[4739,5,4740,1934,0,0,0]Ah[3954,5,3955,1542,0,0,0]Ah[4739,5,4740,1542,0,0,0]97Ae[1050,5,1541,0,0,0,0]:8Ah[4739,6,4740,1907,0,0,0]Ah[3954,5,3955,1071,0,0,0]Ah[4739,5,4740,1071,0,0,0]Ah[3954,5,3955,1551,0,0,0]Ah[4739,5,4740,1551,0,0,0]Ah[3954,5,3955,3293,0,0,0]Ah[4739,5,4740,3293,0,0,0]Ai[3954,15,3955,0,4499,0,0]Al[4739,15,4740,3713,4500,0,0]Ah[3954,5,3955,3712,0,0,0]Al[3954,15,3955,4090,3148,0,0]Al[3954,15,3955,4090,3337,0,0]Al[3954,15,3955,4095,3355,0,0]Al[3954,15,3955,4095,4174,0,0]An[1365,13,1366,1366,127,4264,0]Ao[1365,13,1366,1366,3986,4264,0]Ao[3954,13,3955,3712,3310,4264,0]Ao[3954,13,3955,3712,4943,4264,0]Ao[3954,13,3955,3712,4781,4264,0]Ao[3954,13,3955,2444,2399,4264,0]Ao[3954,13,3955,2444,4267,4264,0]Ao[3954,13,3955,4090,4405,4264,0]Ao[3954,13,3955,4090,3148,4264,0]Ao[3954,13,3955,4090,3337,4264,0]Ao[3954,13,3955,4090,4404,4264,0]Ao[3954,13,3955,4095,3355,4264,0]Ao[3954,13,3955,4095,4174,4264,0]Al[3954,13,3955,0,1603,4264,0]Al[3954,13,3955,0,4940,4264,0]Al[3954,13,3955,0,1586,4264,0]Al[3954,13,3955,0,2434,4264,0]Al[3954,13,3955,0,3316,4264,0]Al[3954,13,3955,0,3145,4264,0]Al[3954,13,3955,0,4503,4264,0]Al[3954,13,3955,0,2018,4264,0]Al[3954,13,3955,0,4126,4264,0]Al[3954,13,3955,0,4499,4264,0]Al[3954,13,3955,0,4520,4264,0]Al[3954,13,3955,0,4805,4264,0]Al[3954,13,3955,0,4820,4264,0]Al[3954,13,3955,0,3999,4264,0]Al[3954,13,3955,0,4381,4264,0]Al[3954,13,3955,0,4168,4264,0]Al[3954,13,3955,0,4997,4264,0]Al[3954,13,3955,0,4120,4264,0]Al[3954,13,3955,0,3989,4264,0]Al[3954,13,3955,0,3128,4264,0]Al[3954,13,3955,0,4496,4264,0]Al[3954,13,3955,0,4684,4264,0]Al[3954,13,3955,0,4132,4264,0]Al[3954,13,3955,0,4135,4264,0]Al[3954,13,3955,0,4140,4264,0]Al[3954,13,3955,0,4839,4264,0]Al[3954,13,3955,0,3319,4264,0]Ak[3954,13,3955,0,485,4264,0]Ak[3954,13,3955,0,119,4264,0]Al[3954,13,3955,0,2422,4264,0]Ak[3954,13,3707,0,113,4264,0]Al[3954,13,3707,0,3116,4264,0]Al[3954,13,3707,0,1328,4264,0]Al[3954,13,3707,0,3994,4264,0]Al[3954,13,3707,0,1992,4264,0]Al[3954,13,3707,0,4286,4264,0]Al[3954,13,1923,0,4936,4264,0]Al[3954,13,1923,0,1341,4264,0]Ao[4739,13,4740,1960,1604,4264,0]Ao[4739,13,4740,1960,4941,4264,0]Ao[4739,13,4740,3173,4782,4264,0]Ao[4739,13,4740,1526,1587,4264,0]Ao[4739,13,4740,1526,4164,4264,0]Ao[4739,13,4740,1526,3331,4264,0]Ao[4739,13,4740,1526,3144,4264,0]Ao[4739,13,4740,1526,4836,4264,0]Ao[4739,13,4740,1526,3306,4264,0]Ao[4739,13,4740,1542,2435,4264,0]Ao[4739,13,4740,1542,3317,4264,0]Ao[4739,13,4740,1542,3146,4264,0]Ao[4739,13,4740,1542,4504,4264,0]Ao[4739,13,4740,1075,3149,4264,0]Ao[4739,13,4740,1075,4294,4264,0]Ao[4739,13,4740,1080,2019,4264,0]Ao[4739,13,4740,1080,3356,4264,0]Ao[4739,13,4740,1080,3998,4264,0]Ao[4739,13,4740,2152,4406,4264,0]Ao[4739,13,4740,2152,4130,4264,0]Ao[4739,13,4740,3713,4500,4264,0]Ao[4739,13,4740,3713,3141,4264,0]Ao[4739,13,4740,3713,4372,4264,0]Ao[4739,13,4740,3713,5024,4264,0]Ao[4739,13,4740,3293,4521,4264,0]Ao[4739,13,4740,3293,4806,4264,0]Ao[4739,13,4740,3293,4821,4264,0]Ao[4739,13,4740,3293,4000,4264,0]Ao[4739,13,4740,1842,4382,4264,0]Ao[4739,13,4740,1842,4170,4264,0]Ao[4739,13,4740,1842,4998,4264,0]Ao[4739,13,4740,1842,4122,4264,0]Ao[4739,13,4740,1842,3990,4264,0]Ao[4739,13,4740,1516,3129,4264,0]Ao[4739,13,4740,1516,3323,4264,0]Ao[4739,13,4740,1516,3345,4264,0]Ao[4739,13,4740,1516,4137,4264,0]Ao[4739,13,4740,1516,4498,4264,0]Ao[4739,13,4740,1516,4686,4264,0]Ao[4739,13,4740,1516,2393,4264,0]Ao[4739,13,4740,2445,4690,4264,0]Ao[4739,13,4740,2445,4133,4264,0]Ao[4739,13,4740,1907,4512,4264,0]Ao[4739,13,4740,1907,5027,4264,0]Ao[4739,13,4740,1907,2406,4264,0]Ao[4739,13,4740,1907,4780,4264,0]Ao[4739,13,4740,1934,4136,4264,0]Ao[4739,13,4740,1934,4141,4264,0]Al[4739,13,4740,0,4410,4264,0]Al[4739,13,4740,0,4840,4264,0]Ao[4739,13,4740,4307,3320,4264,0]Ao[4739,13,4740,4307,5120,4264,0]An[4739,13,4740,4740,486,4264,0]An[4739,13,4740,4740,120,4264,0]Ao[4739,13,4740,4740,2423,4264,0]Ao[4739,13,4740,4740,3127,4264,0]Ao[4739,13,1840,1840,4300,4264,0]Ao[4739,13,4982,4982,4881,4264,0]Ao[4739,13,4982,4982,1343,4264,0]Ao[4739,13,1924,1924,4937,4264,0]Al[4739,13,1924,0,1342,4264,0]Am[4739,13,3708,135,114,4264,0]An[4739,13,3708,135,3117,4264,0]Ao[4739,13,3708,1511,1329,4264,0]Ao[4739,13,3708,1511,3995,4264,0]Ao[4739,13,3708,2493,1993,4264,0]Ao[4739,13,3708,2493,4287,4264,0]Ao[4739,13,2123,2123,1347,4264,0]Ao[4445,13,4446,4446,2420,4264,0]Ao[4445,13,4446,4446,2433,4264,0]Ao[4445,13,4446,4446,4142,4264,0]Ao[1050,13,1051,1051,4874,4264,0]Ao[1050,13,1541,1541,4508,4264,0]Ah[3954,7,3955,2144,0,0,0]Ai[3954,13,3955,0,4381,0,0]Al[4739,13,4740,1842,4382,0,0]Ai[3954,12,1844,0,3138,0,0]Al[4739,12,1845,1845,3139,0,0]Al[4445,14,4446,4446,2420,0,0]Ai[3954,14,3955,0,3316,0,0]Al[4739,14,4740,1542,3317,0,0]10Ae[1050,7,1051,0,0,0,0]Al[3954,13,3955,2444,2399,0,0]Ae[4310,7,4311,0,0,0,0]Ae[1365,7,1366,0,0,0,0]Al[4739,13,4740,3713,3311,0,0]Al[3954,13,3955,3712,3310,0,0]1Al[4739,13,4740,2152,4406,0,0]Al[1365,13,1540,1540,1361,0,0]Al[1365,14,1540,1540,4017,0,0]Al[3954,12,3955,2144,2004,0,0]Ao[3954,13,3955,1552,4175,2004,0]Ao[3954,13,3955,1092,4012,2004,0]Ai[3954,12,1844,0,2005,0,0]Al[3954,13,1923,0,3350,2005,0]Al[4739,12,1845,1845,2006,0,0]Ao[4739,13,1924,1924,3351,2006,0]Ah[3954,5,3955,1049,0,0,0]Ai[3954,15,3955,0,3128,0,0]Ah[3954,5,3955,1516,0,0,0]Al[4739,15,4740,1516,3129,0,0]Ah[4739,5,4740,1516,0,0,0]Ai[3954,15,3955,0,4499,0,0]Al[4739,15,4740,3713,4500,0,0]Ah[4739,5,4740,2445,0,0,0]Al[4739,15,4740,3713,1346,0,0]Ai[3954,15,3955,0,4132,0,0]Al[4739,15,4740,2445,4133,0,0]Ai[3954,19,3955,0,4839,0,0]Ai[4739,19,4740,0,4840,0,0]Ai[3954,15,1923,0,1341,0,0]Ai[4739,15,1924,0,1342,0,0]32Al[4739,15,4740,3713,3141,0,0]><><><21Ah[3954,5,1923,1924,0,0,0]Ae[4739,5,1924,0,0,0,0]10Ah[3954,5,3955,4870,0,0,0]Ah[4739,5,4740,4870,0,0,0]Al[4739,15,2123,2123,1344,0,0]5Al[4739,15,4740,1907,4512,0,0]Ai[3954,12,3955,0,2427,0,0]Al[3954,13,3955,0,4258,2427,0]Al[3954,13,3955,0,4152,2427,0]Al[4739,12,4740,1551,2428,0,0]Ao[4739,13,4740,4530,4259,2428,0]Ao[4739,13,4740,1551,4153,2428,0]Ae[4023,7,4024,0,0,0,0]Al[3954,13,3955,3712,3310,0,0]Al[4739,13,4740,3713,3311,0,0]Ai[3954,14,3955,0,3316,0,0]Al[4739,14,4740,1542,3317,0,0]32An[1365,13,1366,1366,127,4383,0]Ao[1050,13,1051,1051,3120,4383,0]An[1050,13,1834,1834,128,4383,0]An[1050,13,1929,1929,129,4383,0]An[3974,13,3975,3975,118,4383,0]Ao[3974,13,3975,3975,2390,4383,0]Ab[4739,3,0,0,0,0,0]Ak[4445,13,4446,393,4411,0,0]Ai[3954,13,3955,0,4520,0,0]Al[4739,13,4740,3293,4521,0,0];:Al[3954,13,3955,2444,2399,0,0]Al[4739,13,4740,2445,2400,0,0]?>32Ae[4310,7,4311,0,0,0,0]5Al[1050,14,1051,1051,3120,0,0]60Ae[1365,7,1366,0,0,0,0]Ai[3954,13,3955,0,4168,0,0]Ai[3954,13,3955,0,4120,0,0]Al[4739,13,4740,1842,4170,0,0]Al[4739,13,4740,1842,4122,0,0]Ai[3954,14,3955,0,4168,0,0]Al[4739,14,4740,1842,4170,0,0]53Al[3954,13,3955,4095,3341,0,0]Ai[3954,19,3955,0,4839,0,0]Ai[4739,19,4740,0,4840,0,0]Ai[3954,15,3955,0,4499,0,0]Al[4739,15,4740,3713,4500,0,0]Ai[3954,10,3707,3708,0,0,0]Af[4739,10,3708,0,0,0,0]Ah[3954,5,3707,3708,0,0,0]Ae[4739,5,3708,0,0,0,0]Ai[3954,10,1844,1845,0,0,0]Af[4739,10,1845,0,0,0,0]Ai[3954,15,3955,0,4132,0,0]Al[4739,15,4740,2445,4133,0,0]Ah[4739,6,4740,1907,0,0,0]Ah[3954,6,3955,3712,0,0,0]Ah[4739,6,4740,3173,0,0,0]Ai[3954,15,3955,0,3128,0,0]Al[4739,15,4740,1516,3129,0,0]10Al[3954,15,3955,3712,4781,0,0]Al[4739,15,4740,3173,4782,0,0]Ai[3954,14,3955,0,3145,0,0]Al[4739,14,4740,1542,3146,0,0]Ai[3954,14,3707,0,4773,0,0]Al[4739,14,3708,3708,4774,0,0]Al[3954,13,3955,3712,3310,0,0]Ai[3954,14,3955,0,3316,0,0]Al[4739,14,4740,1542,3317,0,0]10Al[4739,13,4740,3173,3123,0,0]Al[3954,13,3955,2444,2399,0,0]Al[4739,13,4740,2445,2400,0,0]Ab[4800,3,0,0,0,0,0]Ao[1050,13,1051,1051,4874,3153,0]Ai[3954,19,3955,0,4839,0,0]Ai[4739,19,4740,0,4840,0,0]Ah[3954,5,3955,3293,0,0,0]Ah[4739,5,4740,3293,0,0,0]Ai[3954,15,1923,0,1341,0,0]Ai[4739,15,1924,0,1342,0,0]54Ai[4739,10,4740,1907,0,0,0]Al[4739,15,4740,3713,1346,0,0]7600Al[4739,15,4740,1075,4294,0,0]4365Al[4739,15,2123,2123,1344,0,0]Ae[1050,9,1051,0,0,0,0]:9Ai[3954,15,3955,0,3128,0,0]Al[4739,15,4740,1516,3129,0,0]<;<;Ah[4739,6,4740,1526,0,0,0]21Ae[3954,5,3955,0,0,0,0]Ae[4739,5,4740,0,0,0,0]Ai[3954,15,3955,0,4132,0,0]Ah[3954,5,1844,1845,0,0,0]Al[4739,15,4740,2445,4133,0,0]Al[4739,15,4740,1907,4780,0,0]Ae[4739,5,1845,0,0,0,0]An[1365,13,1366,1366,127,4373,0]Ao[1050,13,1051,1051,3120,4373,0]An[1050,13,1834,1834,128,4373,0]An[1050,13,1929,1929,129,4373,0]An[3974,13,3975,3975,118,4373,0]Ai[3954,13,3955,0,4520,0,0]Al[4739,13,4740,3293,4521,0,0]Ai[3954,13,3955,0,1603,0,0]Al[4739,13,4740,1960,1604,0,0]Al[3954,14,3955,2444,4267,0,0]Ai[3954,13,3955,0,4381,0,0]Al[4739,13,4740,1842,4382,0,0]Ai[3954,13,3955,0,4258,0,0]Al[4739,13,4740,4530,4259,0,0]Ai[3954,14,3955,0,3316,0,0]Al[4739,14,4740,1542,3317,0,0]6Al[4739,13,4740,3713,3311,0,0]Al[3954,13,3955,3712,3310,0,0]0176Ao[4023,13,4024,4024,5028,4834,0]Ai[3954,13,3955,0,4513,0,0]Al[4739,13,4740,1071,4514,0,0]Ae[1050,6,1051,0,0,0,0]Ai[3954,15,3955,0,3128,0,0]Al[4739,15,4740,1516,3129,0,0]10Al[4739,15,4740,3713,3141,0,0]Ae[4739,5,4982,0,0,0,0]Ah[3954,5,3955,4090,0,0,0]Ai[3954,15,1923,0,1341,0,0]Ai[4739,15,1924,0,1342,0,0]Al[4739,15,2123,2123,1344,0,0]Al[3954,14,3955,2444,4267,0,0]Ak[3954,13,3955,0,485,3110,0]Ak[3954,13,3955,0,119,3110,0]Al[3954,13,3955,0,2422,3110,0]An[4739,13,4740,4740,486,3110,0]An[4739,13,4740,4740,120,3110,0]Ao[4739,13,4740,4740,2423,3110,0]Ao[3974,13,3975,3975,2390,3346,0]Ai[3954,13,3955,0,4820,0,0]Al[4739,13,4740,3293,4821,0,0]Ai[3954,12,1844,0,2005,0,0]Al[3954,13,1923,0,3350,2005,0]Al[4739,12,1845,1845,2006,0,0]Ao[4739,13,1924,1924,3351,2006,0]Al[3954,13,3955,3712,3310,0,0]Ai[3954,13,3955,0,4520,0,0]Al[4739,13,4740,3293,4521,0,0]Ai[3954,14,3955,0,3145,0,0]Al[4739,14,4740,1542,3146,0,0]Ai[3954,12,3707,0,3312,0,0]Ak[3954,13,3707,0,113,3312,0]Al[3954,13,3707,0,1328,3312,0]Al[3954,13,3707,0,1992,3312,0]Al[4739,12,3708,3708,3313,0,0]Am[4739,13,3708,135,114,3313,0]Ao[4739,13,3708,1511,1329,3313,0]Ao[4739,13,3708,2493,1993,3313,0]Al[3954,14,3955,2444,4267,0,0]Al[4739,13,4740,2152,2012,0,0]Ah[4739,2,4305,4094,0,0,0]Ae[1365,7,1366,0,0,0,0]==Ak[3954,13,3955,1049,478,0,0]Ak[4445,13,4446,393,4411,0,0]032Ai[3954,12,1844,0,2005,0,0]Al[3954,13,1923,0,3350,2005,0]Ae[4739,2,4740,0,0,0,0]Al[4739,12,1845,1845,2006,0,0]Ao[4739,13,1924,1924,3351,2006,0]Ai[3954,10,3955,4307,0,0,0]Ai[4739,10,4740,4307,0,0,0]Ai[3954,15,1923,0,1341,0,0]Ai[4739,15,1924,0,1342,0,0]Ai[3954,15,3955,0,4132,0,0]Al[4739,15,4740,2445,4133,0,0]Ai[3954,19,3955,0,4839,0,0]Ai[4739,19,4740,0,4840,0,0]Ah[3954,5,3955,1842,0,0,0]Ah[4739,5,4740,1842,0,0,0]Ai[3954,12,1844,0,3138,0,0]Al[4739,12,1845,1845,3139,0,0]Al[4739,13,4740,2445,2400,0,0]Al[4739,13,4740,4740,3127,0,0]Al[4739,13,4740,3713,3311,0,0]Ai[3954,13,3707,0,4286,0,0]Al[4739,13,3708,2493,4287,0,0]Al[3954,13,3955,2144,3151,0,0]0Al[3954,13,3955,3712,3310,0,0]4Ai[3954,14,3955,0,3316,0,0]Al[4739,14,4740,1542,3317,0,0]Ai[3954,13,3955,0,4520,0,0]Al[4739,13,4740,3293,4521,0,0]Al[1050,14,1051,1051,3120,0,0]Ai[3954,19,3955,0,4839,0,0]Ai[4739,19,4740,0,4840,0,0]Al[4739,15,2123,2123,1344,0,0]Ai[3954,15,1923,0,1341,0,0]Ai[4739,15,1924,0,1342,0,0]10Al[4739,15,4740,1526,4836,0,0]Al[4739,15,4740,3713,3141,0,0]Ah[4739,5,4740,3713,0,0,0]Ai[3954,15,3955,0,3128,0,0]Al[4739,15,4740,1516,3129,0,0]Ah[4739,5,4740,1907,0,0,0]Ae[4023,5,4024,0,0,0,0]Al[1050,13,1051,1051,3120,0,0]Al[3954,13,3955,3712,3310,0,0]Ai[3954,12,1844,0,2005,0,0]Al[3954,13,1923,0,3350,2005,0]Al[4739,12,1845,1845,2006,0,0]Ao[4739,13,1924,1924,3351,2006,0]Ah[4739,7,4916,4915,0,0,0]0Al[4739,13,4740,3713,3311,0,0]6Ak[3954,13,3955,1049,478,0,0]Ai[3954,14,3955,0,3316,0,0]Al[4739,14,4740,1542,3317,0,0]Ao[4023,13,4024,4024,5028,4834,0]0Ai[3954,13,3955,0,4120,0,0]Al[4739,13,4740,1842,4122,0,0]Ai[3954,15,1923,0,1341,0,0]Ai[4739,15,1924,0,1342,0,0]10Ai[3954,13,3955,0,4805,0,0]Al[4739,13,4740,3293,4806,0,0]Am[1365,13,1366,1366,127,460,0]An[1050,13,1051,1051,3120,460,0]Am[1050,13,1834,1834,128,460,0]Am[1050,13,1929,1929,129,460,0]Am[3974,13,3975,3975,118,460,0]??>An[1365,13,1366,1366,127,4383,0]Ao[1050,13,1051,1051,3120,4383,0]An[1050,13,1834,1834,128,4383,0]An[1050,13,1929,1929,129,4383,0]An[3974,13,3975,3975,118,4383,0]Ao[3974,13,3975,3975,2390,4383,0]Ai[3954,13,3955,0,4168,0,0]Al[4739,13,4740,1842,4170,0,0]Ai[3954,19,3955,0,4839,0,0]Ai[4739,19,4740,0,4840,0,0]Ae[1050,5,4227,0,0,0,0]0Ai[3954,13,3955,0,4381,0,0]Al[4739,13,4740,1842,4382,0,0]Ai[3954,13,3955,0,4120,0,0]Al[4739,13,4740,1842,4122,0,0]Al[3954,13,3955,2444,2399,0,0]Al[3954,13,3955,2471,2403,0,0]Al[4739,13,4740,2445,2404,0,0]Al[4739,13,4740,3713,3311,0,0]Ao[4023,13,4024,4024,5028,4834,0];:Ah[3954,5,1844,1845,0,0,0]Ae[4739,5,1845,0,0,0,0]Ai[3954,15,1923,0,1341,0,0]Ai[4739,15,1924,0,1342,0,0]?>?>Al[3954,13,3955,3712,3310,0,0]6Ai[3954,13,3955,0,4520,0,0]Al[4739,13,4740,3293,4521,0,0]Ae[4023,7,4024,0,0,0,0]Ae[4310,7,4311,0,0,0,0]Ai[3954,14,3955,0,3316,0,0]Al[4739,14,4740,1542,3317,0,0]?=Ai[3954,19,3955,0,4839,0,0]Ai[4739,19,4740,0,4840,0,0]2=<==<>=>=>=<;<;Al[4739,14,4982,4982,4881,0,0]?>Ai[4739,18,4740,3293,0,0,0]") \ No newline at end of file diff --git a/pr/338/docs/search.index/function/7b4c2933f234.js b/pr/338/docs/search.index/function/1b0ac63e8098.js similarity index 96% rename from pr/338/docs/search.index/function/7b4c2933f234.js rename to pr/338/docs/search.index/function/1b0ac63e8098.js index f531a43c4..b9c6f5f08 100644 --- a/pr/338/docs/search.index/function/7b4c2933f234.js +++ b/pr/338/docs/search.index/function/1b0ac63e8098.js @@ -1 +1 @@ -rd_("Bf[\"{{{AIAj{AOBd}}{AIAj{AOBd}}}CMn}\",[]]Bf[\"{{{AIAj{BEEj}}{AIAj{BEEj}}}CMn}\",[]]Bf[\"{{{AIAj{BBFj}}{AIAj{BBFj}}}CMn}\",[]]Bf[\"{{{AIAj{AHIh}}{AIAj{AHIh}}}CMn}\",[]]Bf[\"{{{AIAj{AJAb}}{AIAj{AJAb}}}CMn}\",[]]Bf[\"{{{AIAj{BBFh}}{AIAj{BBFh}}}CMn}\",[]]Bf[\"{{{AIAj{AJCf}}{AIAj{AJCf}}}CMn}\",[]]Bf[\"{{{AIAj{B@Il}}{AIAj{B@Il}}}CMn}\",[]]Bd[\"{{{AIAj{LHf}}{AIAj{LHf}}}CMn}\",[]]Bf[\"{{{AIAj{BFIh}}{AIAj{BFIh}}}CMn}\",[]]Bd[\"{{{AIAj{JEh}}{AIAj{JEh}}}CMn}\",[]]Bd[\"{{{AIAj{LFd}}{AIAj{LFd}}}CMn}\",[]]Bf[\"{{{AIAj{AC@d}}{AIAj{AC@d}}}CMn}\",[]]Bf[\"{{{AIAj{AHIb}}{AIAj{AHIb}}}CMn}\",[]]Bd[\"{{{AIAj{OLd}}{AIAj{OLd}}}CMn}\",[]]Bf[\"{{{AIAj{B@Cl}}{AIAj{B@Cl}}}CMn}\",[]]Bf[\"{{{AIAj{BCBf}}{AIAj{BCBf}}}CMn}\",[]]Bf[\"{{{AIAj{AOCn}}{AIAj{AOCn}}}CMn}\",[]]Bf[\"{{{AIAj{AOBj}}{AIAj{AOBj}}}CMn}\",[]]Bf[\"{{{AIAj{AHG`}}{AIAj{AHG`}}}CMn}\",[]]Bf[\"{{{AIAj{BCB`}}{AIAj{BCB`}}}CMn}\",[]]Bf[\"{{{AIAj{BDIh}}{AIAj{BDIh}}}CMn}\",[]]Bf[\"{{{AIAj{B@Dh}}{AIAj{B@Dh}}}CMn}\",[]]Bf[\"{{{AIAj{B@Dn}}{AIAj{B@Dn}}}CMn}\",[]]Bf[\"{{{AIAj{B@Eh}}{AIAj{B@Eh}}}CMn}\",[]]Bf[\"{{{AIAj{BELn}}{AIAj{BELn}}}CMn}\",[]]Bd[\"{{{AIAj{CLj}}{AIAj{CLj}}}CMn}\",[]]Bb[\"{{{AIAj{Nn}}{AIAj{Nn}}}CMn}\",[]]Bf[\"{{{AIAj{ABNl}}{AIAj{ABNl}}}CMn}\",[]]Bf[\"{{{AIAj{BGKl}}{AIAj{BGKl}}}CMn}\",[]]Bd[\"{{{AIAj{JGj}}{AIAj{JGj}}}CMn}\",[]]Bd[\"{{{AIAj{LHh}}{AIAj{LHh}}}CMn}\",[]]Bf[\"{{{AIAj{BFIj}}{AIAj{BFIj}}}CMn}\",[]]Bd[\"{{{AIAj{JEj}}{AIAj{JEj}}}CMn}\",[]]Bf[\"{{{AIAj{BEEl}}{AIAj{BEEl}}}CMn}\",[]]Bd[\"{{{AIAj{LFf}}{AIAj{LFf}}}CMn}\",[]]Bf[\"{{{AIAj{AJ@f}}{AIAj{AJ@f}}}CMn}\",[]]Bf[\"{{{AIAj{AHI`}}{AIAj{AHI`}}}CMn}\",[]]Bf[\"{{{AIAj{BELh}}{AIAj{BELh}}}CMn}\",[]]Bf[\"{{{AIAj{AIMd}}{AIAj{AIMd}}}CMn}\",[]]Bf[\"{{{AIAj{AC@f}}{AIAj{AC@f}}}CMn}\",[]]Bf[\"{{{AIAj{AHId}}{AIAj{AHId}}}CMn}\",[]]Bf[\"{{{AIAj{AHIj}}{AIAj{AHIj}}}CMn}\",[]]Bf[\"{{{AIAj{BAHl}}{AIAj{BAHl}}}CMn}\",[]]Bd[\"{{{AIAj{OLf}}{AIAj{OLf}}}CMn}\",[]]Bf[\"{{{AIAj{AJCh}}{AIAj{AJCh}}}CMn}\",[]]Bf[\"{{{AIAj{AOCl}}{AIAj{AOCl}}}CMn}\",[]]Bf[\"{{{AIAj{AOF`}}{AIAj{AOF`}}}CMn}\",[]]Bf[\"{{{AIAj{BBFl}}{AIAj{BBFl}}}CMn}\",[]]Bf[\"{{{AIAj{B@Dd}}{AIAj{B@Dd}}}CMn}\",[]]Bf[\"{{{AIAj{BCBh}}{AIAj{BCBh}}}CMn}\",[]]Bf[\"{{{AIAj{AHHj}}{AIAj{AHHj}}}CMn}\",[]]Bf[\"{{{AIAj{BBBh}}{AIAj{BBBh}}}CMn}\",[]]Bf[\"{{{AIAj{AOD`}}{AIAj{AOD`}}}CMn}\",[]]Bf[\"{{{AIAj{AOBl}}{AIAj{AOBl}}}CMn}\",[]]Bf[\"{{{AIAj{AHGb}}{AIAj{AHGb}}}CMn}\",[]]Bf[\"{{{AIAj{BBDf}}{AIAj{BBDf}}}CMn}\",[]]Bf[\"{{{AIAj{AIOf}}{AIAj{AIOf}}}CMn}\",[]]Bf[\"{{{AIAj{AJBb}}{AIAj{AJBb}}}CMn}\",[]]Bf[\"{{{AIAj{B@Eb}}{AIAj{B@Eb}}}CMn}\",[]]Bf[\"{{{AIAj{BCBd}}{AIAj{BCBd}}}CMn}\",[]]Bf[\"{{{AIAj{BDIl}}{AIAj{BDIl}}}CMn}\",[]]Bf[\"{{{AIAj{BDJd}}{AIAj{BDJd}}}CMn}\",[]]Bf[\"{{{AIAj{B@Dj}}{AIAj{B@Dj}}}CMn}\",[]]Bf[\"{{{AIAj{ABLl}}{AIAj{ABLl}}}CMn}\",[]]Bf[\"{{{AIAj{BEEh}}{AIAj{BEEh}}}CMn}\",[]]Bf[\"{{{AIAj{B@E`}}{AIAj{B@E`}}}CMn}\",[]]Bf[\"{{{AIAj{B@Ej}}{AIAj{B@Ej}}}CMn}\",[]]Bf[\"{{{AIAj{BBGd}}{AIAj{BBGd}}}CMn}\",[]]Bf[\"{{{AIAj{BEM`}}{AIAj{BEM`}}}CMn}\",[]]Bd[\"{{{AIAj{CLl}}{AIAj{CLl}}}CMn}\",[]]Bb[\"{{{AIAj{O`}}{AIAj{O`}}}CMn}\",[]]Bf[\"{{{AIAj{ABNn}}{AIAj{ABNn}}}CMn}\",[]]Bf[\"{{{AIAj{AHFn}}{AIAj{AHFn}}}CMn}\",[]]Bf[\"{{{AIAj{BAIh}}{AIAj{BAIh}}}CMn}\",[]]Bf[\"{{{AIAj{BFBb}}{AIAj{BFBb}}}CMn}\",[]]Bd[\"{{{AIAj{JGn}}{AIAj{JGn}}}CMn}\",[]]Bf[\"{{{AIAj{BGKn}}{AIAj{BGKn}}}CMn}\",[]]Bd[\"{{{AIAj{JGl}}{AIAj{JGl}}}CMn}\",[]]Bf[\"{{{AIAj{B@El}}{AIAj{B@El}}}CMn}\",[]]Ai[\"{{{AIAj{CKl}}}LFd}\",[]]Ak[\"{{{AIAj{AJ@n}}}ABNl}\",[]]Ak[\"{{{AIAj{BFBd}}}ABNl}\",[]]Ak[\"{{{AIAj{AJAj}}}ABNl}\",[]]o[\"{LEhLFf}\",[]]o[\"{LDdLFf}\",[]]A`[\"{AHDfLFf}\",[]]A`[\"{BAFjLFf}\",[]]A`[\"{B@HbLFf}\",[]]A`[\"{B@GdLFf}\",[]]Aa[\"{ABN`ABNn}\",[]]Aa[\"{AC@jABNn}\",[]]Aa[\"{ABLbABNn}\",[]]A`[\"{OJnABNn}\",[]]n[\"{{}OJf}\",[]]A`[\"{CKdABLl}\",[]]Be[\"{{{AIAj{LHf}}{AIAj{LHf}}}ABMn}\",[]]Be[\"{{{AIAj{LFd}}{AIAj{LFd}}}ABMn}\",[]]Bg[\"{{{AIAj{AOCn}}{AIAj{AOCn}}}ABMn}\",[]]Bg[\"{{{AIAj{B@Dn}}{AIAj{B@Dn}}}ABMn}\",[]]Be[\"{{{AIAj{CLj}}{AIAj{CLj}}}ABMn}\",[]]Bc[\"{{{AIAj{Nn}}{AIAj{Nn}}}ABMn}\",[]]Bg[\"{{{AIAj{ABNl}}{AIAj{ABNl}}}ABMn}\",[]]Be[\"{{{AIAj{LHh}}{AIAj{LHh}}}ABMn}\",[]]Bg[\"{{{AIAj{BEEl}}{AIAj{BEEl}}}ABMn}\",[]]Be[\"{{{AIAj{LFf}}{AIAj{LFf}}}ABMn}\",[]]Bg[\"{{{AIAj{AHIj}}{AIAj{AHIj}}}ABMn}\",[]]Bg[\"{{{AIAj{BAHl}}{AIAj{BAHl}}}ABMn}\",[]]Bg[\"{{{AIAj{AJCh}}{AIAj{AJCh}}}ABMn}\",[]]Bg[\"{{{AIAj{AOD`}}{AIAj{AOD`}}}ABMn}\",[]]Bg[\"{{{AIAj{BDJd}}{AIAj{BDJd}}}ABMn}\",[]]Bg[\"{{{AIAj{BEEh}}{AIAj{BEEh}}}ABMn}\",[]]Bg[\"{{{AIAj{B@E`}}{AIAj{B@E`}}}ABMn}\",[]]Be[\"{{{AIAj{CLl}}{AIAj{CLl}}}ABMn}\",[]]Bc[\"{{{AIAj{O`}}{AIAj{O`}}}ABMn}\",[]]Bg[\"{{{AIAj{ABNn}}{AIAj{ABNn}}}ABMn}\",[]]o[\"{ABNlNn}\",[]]o[\"{ABNnO`}\",[]]n[\"{LEjO`}\",[]]o[\"{AHEbO`}\",[]]A`[\"{ABOnLF`}\",[]]A`[\"{AC@`LF`}\",[]]A`[\"{ABNhLF`}\",[]]A`[\"{AC@bLF`}\",[]]Bg[\"{{{AIAj{On}}{AIAj{CBfAHFl}}}LFh}\",[]]Bi[\"{{{AIAj{AOBd}}{AIAj{CBfAHFl}}}LFh}\",[]]Bi[\"{{{AIAj{BBFn}}{AIAj{CBfAHFl}}}LFh}\",[]]Bi[\"{{{AIAj{BGDh}}{AIAj{CBfAHFl}}}LFh}\",[]]Bi[\"{{{AIAj{AIMh}}{AIAj{CBfAHFl}}}LFh}\",[]]Bi[\"{{{AIAj{AIMl}}{AIAj{CBfAHFl}}}LFh}\",[]]Bi[\"{{{AIAj{BFIn}}{AIAj{CBfAHFl}}}LFh}\",[]]Bi[\"{{{AIAj{BEEj}}{AIAj{CBfAHFl}}}LFh}\",[]]0Bi[\"{{{AIAj{ABKn}}{AIAj{CBfAHFl}}}LFh}\",[]]Bi[\"{{{AIAj{BAEf}}{AIAj{CBfAHFl}}}LFh}\",[]]Bi[\"{{{AIAj{ABLf}}{AIAj{CBfAHFl}}}LFh}\",[]]Bi[\"{{{AIAj{AJAd}}{AIAj{CBfAHFl}}}LFh}\",[]]0Bi[\"{{{AIAj{BBDd}}{AIAj{CBfAHFl}}}LFh}\",[]]Bh[\"{{{AIAj{CKl}}{AIAj{CBfAHFl}}}LFh}\",[]]Bi[\"{{{AIAj{AJ@n}}{AIAj{CBfAHFl}}}LFh}\",[]]Bi[\"{{{AIAj{BFBd}}{AIAj{CBfAHFl}}}LFh}\",[]]Bi[\"{{{AIAj{BBFj}}{AIAj{CBfAHFl}}}LFh}\",[]]0Bi[\"{{{AIAj{AHIh}}{AIAj{CBfAHFl}}}LFh}\",[]]0Bi[\"{{{AIAj{AJAb}}{AIAj{CBfAHFl}}}LFh}\",[]]0Bi[\"{{{AIAj{BBFh}}{AIAj{CBfAHFl}}}LFh}\",[]]0Bi[\"{{{AIAj{B@In}}{AIAj{CBfAHFl}}}LFh}\",[]]Bi[\"{{{AIAj{AOEh}}{AIAj{CBfAHFl}}}LFh}\",[]]Bi[\"{{{AIAj{AJAj}}{AIAj{CBfAHFl}}}LFh}\",[]]Bi[\"{{{AIAj{AJCf}}{AIAj{CBfAHFl}}}LFh}\",[]]0Bi[\"{{{AIAj{B@Il}}{AIAj{CBfAHFl}}}LFh}\",[]]0Cd[\"{{{AIAj{LHf}}{AIAj{CBfAHFl}}}{{LFj{HJ`JFj}}}}\",[]]0Ce[\"{{{AIAj{BFIh}}{AIAj{CBfAHFl}}}{{LFj{HJ`JFj}}}}\",[]]0Cd[\"{{{AIAj{JEh}}{AIAj{CBfAHFl}}}{{LFj{HJ`JFj}}}}\",[]]Cd[\"{{{AIAj{LFd}}{AIAj{CBfAHFl}}}{{LFj{HJ`JFj}}}}\",[]]0Ce[\"{{{AIAj{AC@d}}{AIAj{CBfAHFl}}}{{LFj{HJ`JFj}}}}\",[]]Ce[\"{{{AIAj{AINh}}{AIAj{CBfAHFl}}}{{LFj{HJ`JFj}}}}\",[]]Ce[\"{{{AIAj{AHIb}}{AIAj{CBfAHFl}}}{{LFj{HJ`JFj}}}}\",[]]Ce[\"{{{AIAj{BCBn}}{AIAj{CBfAHFl}}}{{LFj{HJ`JFj}}}}\",[]]Cd[\"{{{AIAj{OLd}}{AIAj{CBfAHFl}}}{{LFj{HJ`JFj}}}}\",[]]Ce[\"{{{AIAj{B@Cl}}{AIAj{CBfAHFl}}}{{LFj{HJ`JFj}}}}\",[]]0Ce[\"{{{AIAj{BCBf}}{AIAj{CBfAHFl}}}{{LFj{HJ`JFj}}}}\",[]]0Ce[\"{{{AIAj{BCDb}}{AIAj{CBfAHFl}}}{{LFj{HJ`JFj}}}}\",[]]Ce[\"{{{AIAj{BCE`}}{AIAj{CBfAHFl}}}{{LFj{HJ`JFj}}}}\",[]]Ce[\"{{{AIAj{BEHj}}{AIAj{CBfAHFl}}}{{LFj{HJ`JFj}}}}\",[]]Ce[\"{{{AIAj{BEJh}}{AIAj{CBfAHFl}}}{{LFj{HJ`JFj}}}}\",[]]Ce[\"{{{AIAj{AOCn}}{AIAj{CBfAHFl}}}{{LFj{HJ`JFj}}}}\",[]]Ce[\"{{{AIAj{BBCj}}{AIAj{CBfAHFl}}}{{LFj{HJ`JFj}}}}\",[]]Ce[\"{{{AIAj{B@I`}}{AIAj{CBfAHFl}}}{{LFj{HJ`JFj}}}}\",[]]Ce[\"{{{AIAj{BG@j}}{AIAj{CBfAHFl}}}{{LFj{HJ`JFj}}}}\",[]]Ce[\"{{{AIAj{B@C`}}{AIAj{CBfAHFl}}}{{LFj{HJ`JFj}}}}\",[]]Ce[\"{{{AIAj{AOBj}}{AIAj{CBfAHFl}}}{{LFj{HJ`JFj}}}}\",[]]0Ce[\"{{{AIAj{AHG`}}{AIAj{CBfAHFl}}}{{LFj{HJ`JFj}}}}\",[]]0Ce[\"{{{AIAj{BCB`}}{AIAj{CBfAHFl}}}{{LFj{HJ`JFj}}}}\",[]]0Ce[\"{{{AIAj{BDIh}}{AIAj{CBfAHFl}}}{{LFj{HJ`JFj}}}}\",[]]0Ce[\"{{{AIAj{B@Dh}}{AIAj{CBfAHFl}}}{{LFj{HJ`JFj}}}}\",[]]0Ce[\"{{{AIAj{B@Dn}}{AIAj{CBfAHFl}}}{{LFj{HJ`JFj}}}}\",[]]0Ce[\"{{{AIAj{B@Eh}}{AIAj{CBfAHFl}}}{{LFj{HJ`JFj}}}}\",[]]Ce[\"{{{AIAj{BELn}}{AIAj{CBfAHFl}}}{{LFj{HJ`JFj}}}}\",[]]0Ce[\"{{{AIAj{AINn}}{AIAj{CBfAHFl}}}{{LFj{HJ`JFj}}}}\",[]]Ce[\"{{{AIAj{BDMf}}{AIAj{CBfAHFl}}}{{LFj{HJ`JFj}}}}\",[]]Cd[\"{{{AIAj{CLj}}{AIAj{CBfAHFl}}}{{LFj{HJ`JFj}}}}\",[]]Cc[\"{{{AIAj{Nn}}{AIAj{CBfAHFl}}}{{LFj{HJ`JFj}}}}\",[]]0Ce[\"{{{AIAj{ABNl}}{AIAj{CBfAHFl}}}{{LFj{HJ`JFj}}}}\",[]]0Ce[\"{{{AIAj{ABOn}}{AIAj{CBfAHFl}}}{{LFj{HJ`JFj}}}}\",[]]Cc[\"{{{AIAj{Nb}}{AIAj{CBfAHFl}}}{{LFj{HJ`JFj}}}}\",[]]Ce[\"{{{AIAj{AHEh}}{AIAj{CBfAHFl}}}{{LFj{HJ`JFj}}}}\",[]]Cd[\"{{{AIAj{JF`}}{AIAj{CBfAHFl}}}{{LFj{HJ`JFj}}}}\",[]]Ce[\"{{{AIAj{AOCd}}{AIAj{CBfAHFl}}}{{LFj{HJ`JFj}}}}\",[]]Cd[\"{{{AIAj{OI`}}{AIAj{CBfAHFl}}}{{LFj{HJ`JFj}}}}\",[]]Ce[\"{{{AIAj{BAGl}}{AIAj{CBfAHFl}}}{{LFj{HJ`JFj}}}}\",[]]Ce[\"{{{AIAj{BEDj}}{AIAj{CBfAHFl}}}{{LFj{HJ`JFj}}}}\",[]]Ce[\"{{{AIAj{BGKl}}{AIAj{CBfAHFl}}}{{LFj{HJ`JFj}}}}\",[]]Ce[\"{{{AIAj{AOC`}}{AIAj{CBfAHFl}}}{{LFj{HJ`JFj}}}}\",[]]Ce[\"{{{AIAj{BEMf}}{AIAj{CBfAHFl}}}{{LFj{HJ`JFj}}}}\",[]]Ce[\"{{{AIAj{BFI`}}{AIAj{CBfAHFl}}}{{LFj{HJ`JFj}}}}\",[]]0Cd[\"{{{AIAj{JGj}}{AIAj{CBfAHFl}}}{{LFj{HJ`JFj}}}}\",[]]0Bi[\"{{{AIAj{AIMn}}{AIAj{CBfAHFl}}}LFh}\",[]]Bi[\"{{{AIAj{ABL`}}{AIAj{CBfAHFl}}}LFh}\",[]]Bh[\"{{{AIAj{LHh}}{AIAj{CBfAHFl}}}LFh}\",[]]0Bi[\"{{{AIAj{BFIj}}{AIAj{CBfAHFl}}}LFh}\",[]]0Bh[\"{{{AIAj{JEj}}{AIAj{CBfAHFl}}}LFh}\",[]]Bi[\"{{{AIAj{BEEl}}{AIAj{CBfAHFl}}}LFh}\",[]]0Bh[\"{{{AIAj{LFf}}{AIAj{CBfAHFl}}}LFh}\",[]]0Bi[\"{{{AIAj{B@Hh}}{AIAj{CBfAHFl}}}LFh}\",[]]Bi[\"{{{AIAj{AJ@f}}{AIAj{CBfAHFl}}}LFh}\",[]]Bi[\"{{{AIAj{AHI`}}{AIAj{CBfAHFl}}}LFh}\",[]]Bi[\"{{{AIAj{BELh}}{AIAj{CBfAHFl}}}LFh}\",[]]0Bi[\"{{{AIAj{AIMd}}{AIAj{CBfAHFl}}}LFh}\",[]]0Bi[\"{{{AIAj{AC@f}}{AIAj{CBfAHFl}}}LFh}\",[]]Bi[\"{{{AIAj{AINj}}{AIAj{CBfAHFl}}}LFh}\",[]]Bi[\"{{{AIAj{AHId}}{AIAj{CBfAHFl}}}LFh}\",[]]Bi[\"{{{AIAj{BCC`}}{AIAj{CBfAHFl}}}LFh}\",[]]Bi[\"{{{AIAj{AHIj}}{AIAj{CBfAHFl}}}LFh}\",[]]0Bi[\"{{{AIAj{BAHl}}{AIAj{CBfAHFl}}}LFh}\",[]]0Bh[\"{{{AIAj{OLf}}{AIAj{CBfAHFl}}}LFh}\",[]]Bi[\"{{{AIAj{AJCh}}{AIAj{CBfAHFl}}}LFh}\",[]]0Bi[\"{{{AIAj{AOCl}}{AIAj{CBfAHFl}}}LFh}\",[]]0Bi[\"{{{AIAj{AOF`}}{AIAj{CBfAHFl}}}LFh}\",[]]Bi[\"{{{AIAj{BBFl}}{AIAj{CBfAHFl}}}LFh}\",[]]Bi[\"{{{AIAj{B@Dd}}{AIAj{CBfAHFl}}}LFh}\",[]]0Bi[\"{{{AIAj{BCBh}}{AIAj{CBfAHFl}}}LFh}\",[]]0Bi[\"{{{AIAj{AHHj}}{AIAj{CBfAHFl}}}LFh}\",[]]0Bi[\"{{{AIAj{BBBh}}{AIAj{CBfAHFl}}}LFh}\",[]]0Bi[\"{{{AIAj{BGD`}}{AIAj{CBfAHFl}}}LFh}\",[]]0Bh[\"{{{AIAj{JHd}}{AIAj{CBfAHFl}}}LFh}\",[]]Bi[\"{{{AIAj{BCDd}}{AIAj{CBfAHFl}}}LFh}\",[]]Bi[\"{{{AIAj{BCEb}}{AIAj{CBfAHFl}}}LFh}\",[]]Bi[\"{{{AIAj{BEHl}}{AIAj{CBfAHFl}}}LFh}\",[]]Bi[\"{{{AIAj{BEJj}}{AIAj{CBfAHFl}}}LFh}\",[]]Bi[\"{{{AIAj{AOD`}}{AIAj{CBfAHFl}}}LFh}\",[]]Bi[\"{{{AIAj{BBCl}}{AIAj{CBfAHFl}}}LFh}\",[]]Bi[\"{{{AIAj{B@Id}}{AIAj{CBfAHFl}}}LFh}\",[]]Bi[\"{{{AIAj{BG@l}}{AIAj{CBfAHFl}}}LFh}\",[]]Bi[\"{{{AIAj{B@Cd}}{AIAj{CBfAHFl}}}LFh}\",[]]Bi[\"{{{AIAj{AOBl}}{AIAj{CBfAHFl}}}LFh}\",[]]0Bi[\"{{{AIAj{AHGb}}{AIAj{CBfAHFl}}}LFh}\",[]]0Bi[\"{{{AIAj{BBDf}}{AIAj{CBfAHFl}}}LFh}\",[]]0Bi[\"{{{AIAj{AIOf}}{AIAj{CBfAHFl}}}LFh}\",[]]0Bi[\"{{{AIAj{AJBb}}{AIAj{CBfAHFl}}}LFh}\",[]]0Bi[\"{{{AIAj{B@Eb}}{AIAj{CBfAHFl}}}LFh}\",[]]0Bi[\"{{{AIAj{BCBd}}{AIAj{CBfAHFl}}}LFh}\",[]]0Bi[\"{{{AIAj{BDIl}}{AIAj{CBfAHFl}}}LFh}\",[]]0Bi[\"{{{AIAj{ABKb}}{AIAj{CBfAHFl}}}LFh}\",[]]0Bi[\"{{{AIAj{BDJd}}{AIAj{CBfAHFl}}}LFh}\",[]]Bi[\"{{{AIAj{ABLh}}{AIAj{CBfAHFl}}}LFh}\",[]]Bi[\"{{{AIAj{B@Dj}}{AIAj{CBfAHFl}}}LFh}\",[]]0Bi[\"{{{AIAj{AOB`}}{AIAj{CBfAHFl}}}LFh}\",[]]Bi[\"{{{AIAj{AJAf}}{AIAj{CBfAHFl}}}LFh}\",[]]0Bi[\"{{{AIAj{BAHb}}{AIAj{CBfAHFl}}}LFh}\",[]]Bi[\"{{{AIAj{BCD`}}{AIAj{CBfAHFl}}}LFh}\",[]]Bi[\"{{{AIAj{BGDf}}{AIAj{CBfAHFl}}}LFh}\",[]]Bi[\"{{{AIAj{ABLl}}{AIAj{CBfAHFl}}}LFh}\",[]]Bi[\"{{{AIAj{BEEh}}{AIAj{CBfAHFl}}}LFh}\",[]]0Bi[\"{{{AIAj{BCBl}}{AIAj{CBfAHFl}}}LFh}\",[]]Bi[\"{{{AIAj{BAEd}}{AIAj{CBfAHFl}}}LFh}\",[]]Bi[\"{{{AIAj{B@E`}}{AIAj{CBfAHFl}}}LFh}\",[]]0Bi[\"{{{AIAj{B@Ej}}{AIAj{CBfAHFl}}}LFh}\",[]]Bi[\"{{{AIAj{BBGd}}{AIAj{CBfAHFl}}}LFh}\",[]]0Bi[\"{{{AIAj{BEM`}}{AIAj{CBfAHFl}}}LFh}\",[]]0Bi[\"{{{AIAj{AIO`}}{AIAj{CBfAHFl}}}LFh}\",[]]Bi[\"{{{AIAj{BH@`}}{AIAj{CBfAHFl}}}LFh}\",[]]Bi[\"{{{AIAj{BDMh}}{AIAj{CBfAHFl}}}LFh}\",[]]Bh[\"{{{AIAj{CLl}}{AIAj{CBfAHFl}}}LFh}\",[]]Bg[\"{{{AIAj{O`}}{AIAj{CBfAHFl}}}LFh}\",[]]0Bi[\"{{{AIAj{ABNn}}{AIAj{CBfAHFl}}}LFh}\",[]]0Bi[\"{{{AIAj{AC@`}}{AIAj{CBfAHFl}}}LFh}\",[]]Bi[\"{{{AIAj{AHFn}}{AIAj{CBfAHFl}}}LFh}\",[]]0Bi[\"{{{AIAj{BAIh}}{AIAj{CBfAHFl}}}LFh}\",[]]0Bi[\"{{{AIAj{BFBb}}{AIAj{CBfAHFl}}}LFh}\",[]]Bh[\"{{{AIAj{JGn}}{AIAj{CBfAHFl}}}LFh}\",[]]0Bi[\"{{{AIAj{BGKn}}{AIAj{CBfAHFl}}}LFh}\",[]]Bi[\"{{{AIAj{AOCb}}{AIAj{CBfAHFl}}}LFh}\",[]]Bi[\"{{{AIAj{BEMl}}{AIAj{CBfAHFl}}}LFh}\",[]]Bi[\"{{{AIAj{BFIb}}{AIAj{CBfAHFl}}}LFh}\",[]]0Cd[\"{{{AIAj{JGl}}{AIAj{CBfAHFl}}}{{LFj{HJ`JFj}}}}\",[]]0Bg[\"{{{AIAj{Nd}}{AIAj{CBfAHFl}}}LFh}\",[]]Bi[\"{{{AIAj{AHEj}}{AIAj{CBfAHFl}}}LFh}\",[]]Bh[\"{{{AIAj{JFb}}{AIAj{CBfAHFl}}}LFh}\",[]]Bi[\"{{{AIAj{AOCf}}{AIAj{CBfAHFl}}}LFh}\",[]]Bh[\"{{{AIAj{OIb}}{AIAj{CBfAHFl}}}LFh}\",[]]Bi[\"{{{AIAj{BAGn}}{AIAj{CBfAHFl}}}LFh}\",[]]Bi[\"{{{AIAj{BEDl}}{AIAj{CBfAHFl}}}LFh}\",[]]Bh[\"{{{AIAj{JH`}}{AIAj{CBfAHFl}}}LFh}\",[]]0Bh[\"{{{AIAj{JHf}}{AIAj{CBfAHFl}}}LFh}\",[]]Bi[\"{{{AIAj{BBGf}}{AIAj{CBfAHFl}}}LFh}\",[]]Bi[\"{{{AIAj{ABNh}}{AIAj{CBfAHFl}}}LFh}\",[]]Bi[\"{{{AIAj{AC@b}}{AIAj{CBfAHFl}}}LFh}\",[]]Bi[\"{{{AIAj{B@El}}{AIAj{CBfAHFl}}}LFh}\",[]]Ak[\"{{{AIAj{B@Hh}}}ABKj}\",[]]A`[\"{AC@dCId}\",[]]A`[\"{AC@fCId}\",[]]Aj[\"{{{AIAj{BAHb}}}LBd}\",[]]A`[\"{BGDfCId}\",[]]o[\"{CKdCId}\",[]]A`[\"{ABNhLBd}\",[]]Ce[\"{{{AIAj{CBfBG@j}}{N`{ABOf}}}{{AIAj{CBfBG@j}}}}\",[]]Ce[\"{{{AIAj{CBfBG@l}}{N`{ABOh}}}{{AIAj{CBfBG@l}}}}\",[]]8Af[\"{{ABKjCId}BBFn}\",[]]Ag[\"{{}{{N`{BGDh}}}}\",[]]Ae[\"{{LBdCIb}BADd}\",[]]Cd[\"{{BBCj{LF`{B@I`}}AHJ`{N`{OJh}}}{{LFl{ABKn}}}}\",[]]Ah[\"{{{Nh{JJh}}}AJ@h}\",[]]A`[\"{OJ`BCDb}\",[]]Ah[\"{{{N`{OGn}}}BBCj}\",[]]Bc[\"{{{N`{B@Ib}}{N`{BEDn}}}B@I`}\",[]]Ai[\"{{{N`{B@Cb}}}B@C`}\",[]]B`[\"{{{AIAj{{L@`{Mh}}}}}B@Dn}\",[]]Ae[\"{{CIbLBd}BDMf}\",[]]Ag[\"{{CLjNnCId}ABNl}\",[]]Aj[\"{{{N`{AHEh}}CI`}Nb}\",[]]An[\"{{{N`{AOCd}}OHdCI`}JF`}\",[]]An[\"{{{N`{BAGl}}OHdCI`}OI`}\",[]]Ae[\"{{LBdCIb}BADf}\",[]]Ah[\"{{{Nh{JJh}}}AJ@j}\",[]]Bm[\"{{{N`{BBCl}}{LF`{{N`{B@Id}}}}CMn}ABL`}\",[]]A`[\"{LBdBHCb}\",[]]o[\"{{}BGOf}\",[]]A`[\"{OJ`BCDd}\",[]]Ah[\"{{{N`{OH`}}}BBCl}\",[]]Bc[\"{{{N`{B@If}}{N`{BEE`}}}B@Id}\",[]]Ai[\"{{{N`{B@Cf}}}B@Cd}\",[]]Ek[\"{{ABJh{AIAj{c}}{AIAj{{L@`{CIb}}}}CMn}{{LFj{{LBb{BAHb{LF`{ABJh}}}}BEEh}}}{BEIfJJ`}}\",[\"\"]]B`[\"{{{AIAj{{L@`{Mh}}}}}B@E`}\",[]]Af[\"{{BEM`LHb}BBGd}\",[]]A`[\"{LBdBH@`}\",[]]Ae[\"{{CIbLBd}BDMh}\",[]]Ag[\"{{CLlO`CId}ABNn}\",[]]Aj[\"{{{N`{AHEj}}CI`}Nd}\",[]]An[\"{{{N`{AOCf}}OHdCI`}JFb}\",[]]An[\"{{{N`{BAGn}}OHdCI`}OIb}\",[]]Aj[\"{AJCd{{LFl{BBGf}}}}\",[]]Ai[\"{{{N`{BDM`}}}BGJ`}\",[]]Ai[\"{{{N`{BDMd}}}BGJb}\",[]]o[\"{CLjCLj}\",[]]o[\"{CLlCLl}\",[]]Ak[\"{{{AIAj{AJBh}}}AJBf}\",[]]Ai[\"{{{AIAj{OJh}}}OHd}\",[]]0Aj[\"{{{AIAj{B@In}}}OHd}\",[]]Ak[\"{{{AIAj{BAId}}}AJBf}\",[]]Ak[\"{{{AIAj{AJBj}}}AJBf}\",[]]Ak[\"{{{AIAj{BAIf}}}AJBf}\",[]]Bg[\"{{{AIAj{AIMl}}LFd}{{LF`{ABKj}}}}\",[]]Aa[\"{AHIbABKj}\",[]]Bg[\"{{{AIAj{AIMn}}LFf}{{LF`{ABKj}}}}\",[]]Aa[\"{AHIdABKj}\",[]]Ah[\"{A@`{{LFn{HJ`}}}}\",[]]Ah[\"{A@b{{LFn{HJ`}}}}\",[]]A`[\"{AINhCId}\",[]]A`[\"{AINjCId}\",[]]Aa[\"{B@GdAJB`}\",[]]Aa[\"{ABNhAJB`}\",[]]Aa[\"{BBGdBEM`}\",[]]A`[\"{AHIbCId}\",[]]A`[\"{AHIdCId}\",[]]A`[\"{ABKbJEf}\",[]]Am[\"{{{AIAj{CBfABMj}}}HJ`}\",[]]Am[\"{{{AIAj{CBfABLf}}}HJ`}\",[]]Am[\"{{{AIAj{CBfAJ@n}}}HJ`}\",[]]Am[\"{{{AIAj{CBfAJAj}}}HJ`}\",[]]Al[\"{{{AIAj{CBfLCl}}}HJ`}\",[]]A`[\"{cc{}}\",[\"T\"]]000000000000000000000Aa[\"{BCBfBEEj}\",[]]1111111111Aa[\"{AHIhBBFj}\",[]]2Aa[\"{BCBfAHIh}\",[]]3Aa[\"{AJAbAHIh}\",[]]Aa[\"{BCBfAJAb}\",[]]5Aa[\"{AHIhBBFh}\",[]]6666Aa[\"{BCBfAJCf}\",[]]7Aa[\"{B@ClAJCf}\",[]]Aa[\"{B@IlAJCf}\",[]]9Aa[\"{BCBfB@Il}\",[]]:::::o[\"{CIbLHf}\",[]]n[\"{MhLHf}\",[]]o[\"{CI`LHf}\",[]]A`[\"{ABNlLHf}\",[]]>A`[\"{BELnLHf}\",[]]??Al[\"{cLFd{{CJn{CIb}}}}\",[\"T\"]]A`[\"{cc{}}\",[\"T\"]]0000000Aa[\"{AOBhBCBf}\",[]]A`[\"{JGdBCBf}\",[]]A`[\"{JEnBCBf}\",[]]3333A`[\"{LHfAOCn}\",[]]44444Aa[\"{BFIhAOBj}\",[]]Aa[\"{BCEdAOBj}\",[]]66A`[\"{JGdBCB`}\",[]]77Aa[\"{BEMfB@Dh}\",[]]888A`[\"{LHfBELn}\",[]]999999A`[\"{LHfABNl}\",[]]:::::::::::Aa[\"{AOFfAOC`}\",[]];;;;;;;A`[\"{BDK`JGj}\",[]]A`[\"{BGLlJGj}\",[]]A`[\"{AIOlJGj}\",[]]A`[\"{BCCbJGj}\",[]]?A`[\"{BCDhJGj}\",[]]A`[\"{BGKjJGj}\",[]]A`[\"{BGFlJGj}\",[]]A`[\"{BDInJGj}\",[]]A`[\"{BDLhJGj}\",[]]A`[\"{BBDhJGj}\",[]]A`[\"{BBEjJGj}\",[]]A`[\"{cc{}}\",[\"T\"]]000000000000000n[\"{MhLHh}\",[]]o[\"{CI`LHh}\",[]]o[\"{CIbLHh}\",[]]A`[\"{ABNnLHh}\",[]]A`[\"{BEM`LHh}\",[]]5555Al[\"{cLFf{{CJn{CIb}}}}\",[\"T\"]]666666666666666666Aa[\"{BBGdBCBh}\",[]]77777A`[\"{AHI`JHd}\",[]]8888A`[\"{LHhAOD`}\",[]]99999Aa[\"{BFIjAOBl}\",[]]:Aa[\"{BCEdAOBl}\",[]];;;;;Aa[\"{BBGdBCBd}\",[]]<<<<<>>>>A`[\"{JGnBBGd}\",[]]?A`[\"{LHhBEM`}\",[]]A`[\"{cc{}}\",[\"T\"]]0000A`[\"{LHhABNn}\",[]]11111A`[\"{BAIhJGn}\",[]]22222Aa[\"{AOFfAOCb}\",[]]3333333A`[\"{BBEjJGl}\",[]]A`[\"{BCDhJGl}\",[]]A`[\"{BGFlJGl}\",[]]A`[\"{BCCbJGl}\",[]]A`[\"{BDInJGl}\",[]]A`[\"{AIOlJGl}\",[]]A`[\"{BGLlJGl}\",[]]A`[\"{BDK`JGl}\",[]]A`[\"{BDLhJGl}\",[]]A`[\"{BBDhJGl}\",[]]A`[\"{BGKjJGl}\",[]]>>>>>>>>>An[\"{{{AIAj{c}}}AJCdCIj}\",[\"S\"]]????????????????Bm[\"{{{AIAj{LHf}}{AIAj{CBfc}}}HJ`LEb}\",[\"__H\"]]Bk[\"{{{AIAj{LFd}}{AIAj{CBfc}}}HJ`LEb}\",[\"H\"]]Bn[\"{{{AIAj{AOCn}}{AIAj{CBfc}}}HJ`LEb}\",[\"__H\"]]Bn[\"{{{AIAj{B@Dn}}{AIAj{CBfc}}}HJ`LEb}\",[\"__H\"]]Bm[\"{{{AIAj{CLj}}{AIAj{CBfc}}}HJ`LEb}\",[\"__H\"]]Bl[\"{{{AIAj{Nn}}{AIAj{CBfc}}}HJ`LEb}\",[\"__H\"]]Bn[\"{{{AIAj{ABNl}}{AIAj{CBfc}}}HJ`LEb}\",[\"__H\"]]Bm[\"{{{AIAj{LHh}}{AIAj{CBfc}}}HJ`LEb}\",[\"__H\"]]Bn[\"{{{AIAj{BEEl}}{AIAj{CBfc}}}HJ`LEb}\",[\"__H\"]]Bk[\"{{{AIAj{LFf}}{AIAj{CBfc}}}HJ`LEb}\",[\"H\"]]Bn[\"{{{AIAj{AHIj}}{AIAj{CBfc}}}HJ`LEb}\",[\"__H\"]]Bn[\"{{{AIAj{BAHl}}{AIAj{CBfc}}}HJ`LEb}\",[\"__H\"]]Bn[\"{{{AIAj{AJCh}}{AIAj{CBfc}}}HJ`LEb}\",[\"__H\"]]Bn[\"{{{AIAj{AOD`}}{AIAj{CBfc}}}HJ`LEb}\",[\"__H\"]]Bn[\"{{{AIAj{BDJd}}{AIAj{CBfc}}}HJ`LEb}\",[\"__H\"]]Bn[\"{{{AIAj{BEEh}}{AIAj{CBfc}}}HJ`LEb}\",[\"__H\"]]Bn[\"{{{AIAj{B@E`}}{AIAj{CBfc}}}HJ`LEb}\",[\"__H\"]]Bm[\"{{{AIAj{CLl}}{AIAj{CBfc}}}HJ`LEb}\",[\"__H\"]]Bl[\"{{{AIAj{O`}}{AIAj{CBfc}}}HJ`LEb}\",[\"__H\"]]Bn[\"{{{AIAj{ABNn}}{AIAj{CBfc}}}HJ`LEb}\",[\"__H\"]]Bn[\"{{{AIAj{AHFn}}{AIAj{CBfc}}}HJ`LEb}\",[\"__H\"]]Aa[\"{{}c{}}\",[\"U\"]]00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000n[\"{{}HJ`}\",[]]0000Cc[\"{{{AIAj{CBfLCl}}LBd}{{LFj{{LF`{JEj}}AHIj}}}}\",[]]El[\"{{{AIAj{OFf}}{AIAj{CBf{L@`{Mh}}}}{AIAj{{L@`{Mh}}}}}{{LFj{{AIAj{CBf{L@`{Mh}}}}AOC`}}}}\",[]]Bh[\"{{{AIAj{CBfOKh}}O`}{{LF`{ABNn}}}}\",[]]El[\"{{{AIAj{OFh}}{AIAj{CBf{L@`{Mh}}}}{AIAj{{L@`{Mh}}}}}{{LFj{{AIAj{CBf{L@`{Mh}}}}AOCb}}}}\",[]]Bf[\"{{{AIAj{AIMl}}LFd}{{LF`{CKl}}}}\",[]]Bf[\"{{{AIAj{CKl}}}{{LFj{HJ`AILn}}}}\",[]]A`[\"{AINhCId}\",[]]Am[\"{{{AIAj{CBfAIMn}}}HJ`}\",[]]A`[\"{AINjCId}\",[]]Ck[\"{{{A@f{{AIAj{CBfAILf}}}}{AIAj{CBfOGb}}}{{CLd{HJ`}}}}\",[]]Dk[\"{{{A@f{{AIAj{CBfBCEj}}}}{AIAj{CBfOGb}}}{{CLd{c}}}{}}\",[\"Future::Output\"]]Dk[\"{{{A@f{{AIAj{CBfABMj}}}}{AIAj{CBfOGb}}}{{CLd{c}}}{}}\",[\"Future::Output\"]]Dk[\"{{{A@f{{AIAj{CBfABMl}}}}{AIAj{CBfOGb}}}{{CLd{c}}}{}}\",[\"Future::Output\"]]Dk[\"{{{A@f{{AIAj{CBfAHEn}}}}{AIAj{CBfOGb}}}{{CLd{c}}}{}}\",[\"Future::Output\"]]Dk[\"{{{A@f{{AIAj{CBfAIMh}}}}{AIAj{CBfOGb}}}{{CLd{c}}}{}}\",[\"Future::Output\"]]Dj[\"{{{A@f{{AIAj{CBfOIf}}}}{AIAj{CBfOGb}}}{{CLd{c}}}{}}\",[\"Future::Output\"]]Dj[\"{{{A@f{{AIAj{CBfLEf}}}}{AIAj{CBfOGb}}}{{CLd{c}}}{}}\",[\"Future::Output\"]]Dk[\"{{{A@f{{AIAj{CBfAHDj}}}}{AIAj{CBfOGb}}}{{CLd{c}}}{}}\",[\"Future::Output\"]]Dk[\"{{{A@f{{AIAj{CBfABJf}}}}{AIAj{CBfOGb}}}{{CLd{c}}}{}}\",[\"Future::Output\"]]Dk[\"{{{A@f{{AIAj{CBfB@H`}}}}{AIAj{CBfOGb}}}{{CLd{c}}}{}}\",[\"Future::Output\"]]Dk[\"{{{A@f{{AIAj{CBfB@Hj}}}}{AIAj{CBfOGb}}}{{CLd{c}}}{}}\",[\"Future::Output\"]]Dj[\"{{{A@f{{AIAj{CBfLBl}}}}{AIAj{CBfOGb}}}{{CLd{c}}}{}}\",[\"Future::Output\"]]Dk[\"{{{A@f{{AIAj{CBfBBDd}}}}{AIAj{CBfOGb}}}{{CLd{c}}}{}}\",[\"Future::Output\"]]Bf[\"{{{AIAj{CBfAIMn}}}{{LF`{JHd}}}}\",[]]De[\"{{{AIAj{CBfAJ@n}}{AIAj{CBf{L@`{Mh}}}}}{{LFj{{LF`{LBd}}AHIh}}}}\",[]]Bm[\"{{{AIAj{CBfAJA`}}CMn}{{LFj{LClBAHl}}}}\",[]]Bo[\"{{CLl{AIAj{CBfc}}}{{LFj{BFBbJGn}}}Nj}\",[\"R\"]]Bf[\"{{{AIAj{CBfAHFf}}}{{LF`{JEf}}}}\",[]]Ec[\"{{{AIAj{BBGf}}AJCd{AIAj{CBf{L@`{AIOb}}}}{AIAj{CBf{L@`{ABNh}}}}}{{LFl{LBd}}}}\",[]]Dk[\"{{{AIAj{OFf}}{AIAj{CBf{A@l{Mh}}}}{AIAj{{L@`{Mh}}}}}{{LFj{HJ`AOC`}}}}\",[]]Dk[\"{{{AIAj{OFh}}{AIAj{CBf{A@l{Mh}}}}{AIAj{{L@`{Mh}}}}}{{LFj{HJ`AOCb}}}}\",[]]C`[\"{{{AIAj{CBfAHFf}}JEfCMn}{{LFj{HJ`BEEl}}}}\",[]]Cc[\"{{{AIAj{BBGf}}AJCd{AIAj{AC@b}}}{{LFl{HJ`}}}}\",[]]Bn[\"{{{AIAj{CBfBG@j}}CIb}{{AIAj{CBfBG@j}}}}\",[]]Bn[\"{{{AIAj{CBfBG@l}}CIb}{{AIAj{CBfBG@l}}}}\",[]]Aj[\"{{{AIAj{AIMl}}}CLj}\",[]]Aj[\"{{{AIAj{AIMn}}}CLl}\",[]]Cn[\"{{{AIAj{OGn}}{AIAj{{L@`{Mh}}}}{AIAj{CBf{L@`{Mh}}}}}HJ`}\",[]]Cn[\"{{{AIAj{OH`}}{AIAj{{L@`{Mh}}}}{AIAj{CBf{L@`{Mh}}}}}HJ`}\",[]]A`[\"{BBFnCId}\",[]]A`[\"{ABOnLBd}\",[]]A`[\"{AC@`LBd}\",[]]o[\"{JIlCMn}\",[]]Bm[\"{{{AIAj{CBfAJ@n}}LHf}{{LFj{HJ`B@Cl}}}}\",[]]Bm[\"{{{AIAj{CBfBFBd}}LHf}{{LFj{HJ`B@Cl}}}}\",[]]Bm[\"{{{AIAj{CBfAJA`}}LHh}{{LFj{HJ`B@Dd}}}}\",[]]Bn[\"{{{AIAj{AJC`}}{AIAj{CHn}}}{{LF`{JEf}}}}\",[]]Bn[\"{{{AIAj{BBEf}}{AIAj{CHn}}}{{LF`{JEf}}}}\",[]]Bn[\"{{{AIAj{BDMf}}{AIAj{CHn}}}{{LF`{JEf}}}}\",[]]Bn[\"{{{AIAj{AJCb}}{AIAj{CHn}}}{{LF`{JEf}}}}\",[]]Bn[\"{{{AIAj{BBEh}}{AIAj{CHn}}}{{LF`{JEf}}}}\",[]]Bn[\"{{{AIAj{BDMh}}{AIAj{CHn}}}{{LF`{JEf}}}}\",[]]Aa[\"{{}c{}}\",[\"V\"]]000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000Bg[\"{{{N`{BEDf}}OHdCI`}{{Nh{AIN`}}}}\",[]]Bg[\"{{{N`{AHEh}}OHdCI`}{{Nh{AIN`}}}}\",[]]Bg[\"{{{N`{AOCd}}OHdCI`}{{Nh{AIN`}}}}\",[]]Bg[\"{{{N`{BAGl}}OHdCI`}{{Nh{AIN`}}}}\",[]]Bg[\"{{{N`{BEDh}}OHdCI`}{{Nh{AINb}}}}\",[]]Bg[\"{{{N`{AHEj}}OHdCI`}{{Nh{AINb}}}}\",[]]Bg[\"{{{N`{AOCf}}OHdCI`}{{Nh{AINb}}}}\",[]]Bg[\"{{{N`{BAGn}}OHdCI`}{{Nh{AINb}}}}\",[]]Ai[\"{BFAd{{N`{BEDh}}}}\",[]]o[\"{JEhJEf}\",[]]A`[\"{AC@dCId}\",[]]o[\"{OLdLBd}\",[]]o[\"{JEjJEf}\",[]]A`[\"{AC@fCId}\",[]]o[\"{OLfLBd}\",[]]Aa[\"{AOB`BCBh}\",[]]Ag[\"{{{AIAj{On}}}On}\",[]]Ak[\"{{{AIAj{AOBd}}}AOBd}\",[]]Ak[\"{{{AIAj{AIMl}}}AIMl}\",[]]Ak[\"{{{AIAj{BFIn}}}BFIn}\",[]]Ak[\"{{{AIAj{BEEj}}}BEEj}\",[]]Ak[\"{{{AIAj{ABKn}}}ABKn}\",[]]Ak[\"{{{AIAj{BAEf}}}BAEf}\",[]]Ak[\"{{{AIAj{BBFj}}}BBFj}\",[]]Ak[\"{{{AIAj{AHIh}}}AHIh}\",[]]Ak[\"{{{AIAj{AJAb}}}AJAb}\",[]]Ak[\"{{{AIAj{BBFh}}}BBFh}\",[]]Ak[\"{{{AIAj{AJCf}}}AJCf}\",[]]Ak[\"{{{AIAj{B@Il}}}B@Il}\",[]]Ai[\"{{{AIAj{LHf}}}LHf}\",[]]Ak[\"{{{AIAj{BFIh}}}BFIh}\",[]]Ai[\"{{{AIAj{LFd}}}LFd}\",[]]Ak[\"{{{AIAj{AC@d}}}AC@d}\",[]]Ak[\"{{{AIAj{AINh}}}AINh}\",[]]Ak[\"{{{AIAj{AHIb}}}AHIb}\",[]]Ak[\"{{{AIAj{BCBn}}}BCBn}\",[]]Ai[\"{{{AIAj{OLd}}}OLd}\",[]]Ak[\"{{{AIAj{B@Cl}}}B@Cl}\",[]]Ak[\"{{{AIAj{BCBf}}}BCBf}\",[]]Ak[\"{{{AIAj{BCE`}}}BCE`}\",[]]Ak[\"{{{AIAj{BEHj}}}BEHj}\",[]]Ak[\"{{{AIAj{BEJh}}}BEJh}\",[]]Ak[\"{{{AIAj{AOCn}}}AOCn}\",[]]Ak[\"{{{AIAj{BBCj}}}BBCj}\",[]]Ak[\"{{{AIAj{B@I`}}}B@I`}\",[]]Ak[\"{{{AIAj{BG@j}}}BG@j}\",[]]Ak[\"{{{AIAj{B@C`}}}B@C`}\",[]]Ak[\"{{{AIAj{AOBj}}}AOBj}\",[]]Ak[\"{{{AIAj{AHG`}}}AHG`}\",[]]Ak[\"{{{AIAj{BCB`}}}BCB`}\",[]]Ak[\"{{{AIAj{BDIh}}}BDIh}\",[]]Ak[\"{{{AIAj{B@Dh}}}B@Dh}\",[]]Ak[\"{{{AIAj{B@Dn}}}B@Dn}\",[]]Ak[\"{{{AIAj{B@Eh}}}B@Eh}\",[]]Ak[\"{{{AIAj{BELn}}}BELn}\",[]]Ak[\"{{{AIAj{AINn}}}AINn}\",[]]Ai[\"{{{AIAj{CLj}}}CLj}\",[]]Ag[\"{{{AIAj{Nn}}}Nn}\",[]]Ak[\"{{{AIAj{ABNl}}}ABNl}\",[]]Ag[\"{{{AIAj{Nb}}}Nb}\",[]]Ak[\"{{{AIAj{AHEh}}}AHEh}\",[]]Ai[\"{{{AIAj{JF`}}}JF`}\",[]]Ak[\"{{{AIAj{AOCd}}}AOCd}\",[]]Ai[\"{{{AIAj{OI`}}}OI`}\",[]]Ak[\"{{{AIAj{BAGl}}}BAGl}\",[]]Ak[\"{{{AIAj{BFI`}}}BFI`}\",[]]Ai[\"{{{AIAj{JGj}}}JGj}\",[]]Ai[\"{{{AIAj{LHh}}}LHh}\",[]]Ak[\"{{{AIAj{BFIj}}}BFIj}\",[]]Ak[\"{{{AIAj{BEEl}}}BEEl}\",[]]Ai[\"{{{AIAj{LFf}}}LFf}\",[]]Ak[\"{{{AIAj{B@Hh}}}B@Hh}\",[]]Ak[\"{{{AIAj{AJ@f}}}AJ@f}\",[]]Ak[\"{{{AIAj{AHI`}}}AHI`}\",[]]Ak[\"{{{AIAj{BELh}}}BELh}\",[]]Ak[\"{{{AIAj{AIMd}}}AIMd}\",[]]Ak[\"{{{AIAj{AC@f}}}AC@f}\",[]]Ak[\"{{{AIAj{AINj}}}AINj}\",[]]Ak[\"{{{AIAj{AHId}}}AHId}\",[]]Ak[\"{{{AIAj{BCC`}}}BCC`}\",[]]Ak[\"{{{AIAj{AHIj}}}AHIj}\",[]]Ak[\"{{{AIAj{BAHl}}}BAHl}\",[]]Ai[\"{{{AIAj{OLf}}}OLf}\",[]]Ak[\"{{{AIAj{AJCh}}}AJCh}\",[]]Ak[\"{{{AIAj{AOCl}}}AOCl}\",[]]Ak[\"{{{AIAj{BBFl}}}BBFl}\",[]]Ak[\"{{{AIAj{B@Dd}}}B@Dd}\",[]]Ak[\"{{{AIAj{BCBh}}}BCBh}\",[]]Ak[\"{{{AIAj{AHHj}}}AHHj}\",[]]Ak[\"{{{AIAj{BBBh}}}BBBh}\",[]]Ak[\"{{{AIAj{BGD`}}}BGD`}\",[]]Ak[\"{{{AIAj{BCEb}}}BCEb}\",[]]Ak[\"{{{AIAj{BEHl}}}BEHl}\",[]]Ak[\"{{{AIAj{BEJj}}}BEJj}\",[]]Ak[\"{{{AIAj{AOD`}}}AOD`}\",[]]Ak[\"{{{AIAj{BBCl}}}BBCl}\",[]]Ak[\"{{{AIAj{B@Id}}}B@Id}\",[]]Ak[\"{{{AIAj{BG@l}}}BG@l}\",[]]Ak[\"{{{AIAj{B@Cd}}}B@Cd}\",[]]Ak[\"{{{AIAj{AOBl}}}AOBl}\",[]]Ak[\"{{{AIAj{AHGb}}}AHGb}\",[]]Ak[\"{{{AIAj{AIOf}}}AIOf}\",[]]Ak[\"{{{AIAj{AJBb}}}AJBb}\",[]]Ak[\"{{{AIAj{B@Eb}}}B@Eb}\",[]]Ak[\"{{{AIAj{BCBd}}}BCBd}\",[]]Ak[\"{{{AIAj{BDIl}}}BDIl}\",[]]Ak[\"{{{AIAj{ABKb}}}ABKb}\",[]]Ak[\"{{{AIAj{BDJd}}}BDJd}\",[]]Ak[\"{{{AIAj{B@Dj}}}B@Dj}\",[]]Ak[\"{{{AIAj{BCD`}}}BCD`}\",[]]Ak[\"{{{AIAj{BGDf}}}BGDf}\",[]]Ak[\"{{{AIAj{ABLl}}}ABLl}\",[]]Ak[\"{{{AIAj{BEEh}}}BEEh}\",[]]Ak[\"{{{AIAj{B@E`}}}B@E`}\",[]]Ak[\"{{{AIAj{B@Ej}}}B@Ej}\",[]]Ak[\"{{{AIAj{BBGd}}}BBGd}\",[]]Ak[\"{{{AIAj{BEM`}}}BEM`}\",[]]Ak[\"{{{AIAj{AIO`}}}AIO`}\",[]]Ak[\"{{{AIAj{BH@`}}}BH@`}\",[]]Ai[\"{{{AIAj{CLl}}}CLl}\",[]]Ag[\"{{{AIAj{O`}}}O`}\",[]]Ak[\"{{{AIAj{ABNn}}}ABNn}\",[]]Ak[\"{{{AIAj{AHFn}}}AHFn}\",[]]Ak[\"{{{AIAj{BAIh}}}BAIh}\",[]]Ak[\"{{{AIAj{BFBb}}}BFBb}\",[]]Ai[\"{{{AIAj{JGn}}}JGn}\",[]]Ak[\"{{{AIAj{BFIb}}}BFIb}\",[]]Ai[\"{{{AIAj{JGl}}}JGl}\",[]]Ag[\"{{{AIAj{Nd}}}Nd}\",[]]Ak[\"{{{AIAj{AHEj}}}AHEj}\",[]]Ai[\"{{{AIAj{JFb}}}JFb}\",[]]Ak[\"{{{AIAj{AOCf}}}AOCf}\",[]]Ai[\"{{{AIAj{OIb}}}OIb}\",[]]Ak[\"{{{AIAj{BAGn}}}BAGn}\",[]]Ai[\"{{{AIAj{JHf}}}JHf}\",[]]Ak[\"{{{AIAj{ABNh}}}ABNh}\",[]]Ak[\"{{{AIAj{AC@b}}}AC@b}\",[]]Ak[\"{{{AIAj{B@El}}}B@El}\",[]]Ak[\"{{{AIAj{BFAd}}}BFAd}\",[]]Ak[\"{{{AIAj{BCCh}}}BCCh}\",[]]Bn[\"{{{AIAj{AIMl}}LHf{AIAj{{L@`{Mh}}}}}HJ`}\",[]]Bn[\"{{{AIAj{ABKn}}LHf{AIAj{{L@`{Mh}}}}}HJ`}\",[]]Bg[\"{{{AIAj{CKl}}}{{LFj{AHEnBBBf}}}}\",[]]Bf[\"{{{AIAj{CBfAIMn}}OHdLHhJEf}HJ`}\",[]]Bj[\"{{{AIAj{B@Dn}}}{{AIAj{{L@`{Mh}}}}}}\",[]]Bj[\"{{{AIAj{B@E`}}}{{AIAj{{L@`{Mh}}}}}}\",[]]Aa[\"{BAFjAHHj}\",[]]Aa[\"{BBGdAIOf}\",[]]A`[\"{ABNlCId}\",[]]A`[\"{ABNnCId}\",[]]A`[\"{B@EhCMn}\",[]]A`[\"{B@EjCMn}\",[]]l[\"{OHf}\",[]]l[\"{OHh}\",[]]Ce[\"{{{AIAj{BEIf}}{AIAj{CBfNj}}}{{LFj{B@E`BEEh}}}}\",[]]Ce[\"{{{AIAj{BHCb}}{AIAj{CBfNj}}}{{LFj{B@E`BEEh}}}}\",[]]Bc[\"{{{AIAj{AIMn}}}{{A@l{LFf}}}}\",[]]Bd[\"{{{AIAj{JJb}}{AIAj{CHn}}}HJ`}\",[]]Am[\"{{{AIAj{AOBf}}LBd}HJ`}\",[]]Ai[\"{{{AIAj{JJd}}}HJ`}\",[]]Bg[\"{{{A@f{{AIAj{CBfAILf}}}}OHd}HJ`}\",[]]Bm[\"{{{AIAj{CBfAJAj}}LHf}{{LFj{HJ`B@Cl}}}}\",[]]Bm[\"{{{AIAj{CBfAJAl}}LHh}{{LFj{HJ`B@Dd}}}}\",[]]Am[\"{ABLf{{LFj{HJ`AJAd}}}}\",[]]Dc[\"{{{AIAj{CBfABL`}}ABLh{AIAj{CBf{A@l{Mh}}}}}{{LFj{AC@`AJAf}}}}\",[]]Bi[\"{{{AIAj{OJh}}{A@f{{Nh{LE`}}}}}HJ`}\",[]]Bj[\"{{{AIAj{B@In}}{A@f{{Nh{LE`}}}}}HJ`}\",[]]Bj[\"{{{AIAj{AOEh}}{A@f{{Nh{LE`}}}}}HJ`}\",[]]n[\"{OnCMn}\",[]]Ak[\"{{{AIAj{AIMl}}}BCBn}\",[]]Ak[\"{{{AIAj{ABKn}}}BAEf}\",[]]An[\"{{{AIAj{CBfAIMn}}}BCC`}\",[]]Ce[\"{{{AIAj{CBfAJ@h}}{LF`{LHb}}}{{AIAj{CBfAJ@h}}}}\",[]]Ce[\"{{{AIAj{CBfAJ@j}}{LF`{LHb}}}{{AIAj{CBfAJ@j}}}}\",[]]Ck[\"{{{AIAj{CBfAJAj}}{AIAj{{L@`{Mh}}}}}{{LFj{LBdAJCf}}}}\",[]]Ck[\"{{{AIAj{CBfAJAl}}{AIAj{{L@`{Mh}}}}}{{LFj{LBdAJCh}}}}\",[]]Bl[\"{{{AIAj{BFBb}}{AIAj{CBfc}}}HJ`LCj}\",[\"W\"]]Aj[\"{{{AIAj{ABKn}}}LBl}\",[]]An[\"{ABLf{{LFj{AIMhBCBf}}}}\",[]]Bh[\"{{{AIAj{CBfOKh}}O`}{{LF`{ABNn}}}}\",[]]Fh[\"{{{AIAj{CBfABL`}}ABLhOHd{AIAj{CBf{A@l{Mh}}}}{LF`{{N`{B@Id}}}}}{{LFj{{LBb{BDJdAIMn}}{Nh{AOB`}}}}}}\",[]]Am[\"{AIAj{{AIAj{c}}}{}}\",[\"T\"]]00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000o[\"{OLdLBd}\",[]]o[\"{OLfLBd}\",[]]o[\"{OnAOBd}\",[]]Bb[\"{{AJB`BBBdOn}{{LFn{AOBf}}}}\",[]]Aj[\"{AJB`{{LFl{ABKn}}}}\",[]]B`[\"{{}{{LFj{HJ`{Nh{JFl}}}}}}\",[]]Ak[\"{{{AIAj{AIMl}}}BCBf}\",[]]Be[\"{{{AIAj{ABL`}}}{{AIAj{BBCl}}}}\",[]]o[\"{MhBELn}\",[]]A`[\"{AINhCId}\",[]]o[\"{B@I`N`}\",[]]o[\"{MhBEM`}\",[]]A`[\"{AINjCId}\",[]]o[\"{B@IdN`}\",[]]A`[\"{BBGdLF`}\",[]]Bl[\"{{{AIAj{CBfc}}}{{LFj{LHfBAIh}}}Nj}\",[\"B\"]]Bl[\"{{{AIAj{CBfc}}}{{LFj{LFdBAIh}}}Nj}\",[\"B\"]]Bm[\"{{{AIAj{CBfc}}}{{LFj{AHG`BAIh}}}Nj}\",[\"B\"]]Bm[\"{{{AIAj{CBfc}}}{{LFj{BELnBAIh}}}Nj}\",[\"B\"]]Bm[\"{{{AIAj{CBfc}}}{{LFj{ABNlBAIh}}}Nj}\",[\"B\"]]Bh[\"{{{AIAj{CBfc}}}{{LGb{LHh}}}Nj}\",[\"B\"]]Bh[\"{{{AIAj{CBfc}}}{{LGb{LFf}}}Nj}\",[\"B\"]]Bi[\"{{{AIAj{CBfc}}}{{LGb{AHGb}}}Nj}\",[\"B\"]]Bi[\"{{{AIAj{CBfc}}}{{LGb{AIOf}}}Nj}\",[\"B\"]]Ek[\"{{{AIAj{CBf{LDn{ABJh}}}}{AIAj{c}}{AIAj{{L@`{CIb}}}}CMn}{{LFj{BCD`BEEh}}}{BEIfJJ`}}\",[\"\"]]Bi[\"{{{AIAj{CBfc}}}{{LGb{BEM`}}}Nj}\",[\"B\"]]Bi[\"{{{AIAj{CBfc}}}{{LGb{ABNn}}}Nj}\",[\"B\"]]Bi[\"{{{AIAj{CBfc}}}{{LGb{AHFh}}}Nj}\",[\"B\"]]A`[\"{ABNhLF`}\",[]]Bk[\"{{{AIAj{LHf}}{AIAj{CBfc}}}HJ`LCj}\",[\"B\"]]Bk[\"{{{AIAj{LFd}}{AIAj{CBfc}}}HJ`LCj}\",[\"B\"]]Bl[\"{{{AIAj{AHG`}}{AIAj{CBfc}}}HJ`LCj}\",[\"B\"]]Bl[\"{{{AIAj{BELn}}{AIAj{CBfc}}}HJ`LCj}\",[\"B\"]]Bl[\"{{{AIAj{ABNl}}{AIAj{CBfc}}}HJ`LCj}\",[\"B\"]]Bk[\"{{{AIAj{LHh}}{AIAj{CBfc}}}HJ`LCj}\",[\"B\"]]Bk[\"{{{AIAj{LFf}}{AIAj{CBfc}}}HJ`LCj}\",[\"B\"]]Bl[\"{{{AIAj{AHGb}}{AIAj{CBfc}}}HJ`LCj}\",[\"B\"]]Bl[\"{{{AIAj{AIOf}}{AIAj{CBfc}}}HJ`LCj}\",[\"B\"]]Bl[\"{{{AIAj{ABKb}}{AIAj{CBfc}}}HJ`LCj}\",[\"B\"]]Bl[\"{{{AIAj{BEM`}}{AIAj{CBfc}}}HJ`LCj}\",[\"B\"]]Bl[\"{{{AIAj{ABNn}}{AIAj{CBfc}}}HJ`LCj}\",[\"B\"]]Bl[\"{{{AIAj{AHFj}}{AIAj{CBfc}}}HJ`LCj}\",[\"B\"]]Bj[\"{{{AIAj{CBfAJAj}}}{{LFj{HJ`B@Cl}}}}\",[]]Bj[\"{{{AIAj{CBfAJAl}}}{{LFj{HJ`AOCl}}}}\",[]]An[\"{{{AIAj{AOFd}}ABKj}HJ`}\",[]]Ea[\"{{{AIAj{CBfABL`}}OHdAHFn{LF`{B@Ej}}ABJh{AIAj{CBf{A@l{Mh}}}}}{{LF`{BAEb}}}}\",[]]o[\"{CK`OHf}\",[]]o[\"{CKbOHh}\",[]]A`[\"{ABLfHJ`}\",[]]Ba[\"{{{AIAj{CBfABL`}}ABLh}HJ`}\",[]]Bh[\"{{{AIAj{AJC`}}{AIAj{CHn}}JEf}HJ`}\",[]]Bh[\"{{{AIAj{BBEf}}{AIAj{CHn}}JEf}HJ`}\",[]]Bh[\"{{{AIAj{BDMf}}{AIAj{CHn}}JEf}HJ`}\",[]]Bh[\"{{{AIAj{AJCb}}{AIAj{CHn}}JEf}HJ`}\",[]]Bh[\"{{{AIAj{BBEh}}{AIAj{CHn}}JEf}HJ`}\",[]]Bh[\"{{{AIAj{BDMh}}{AIAj{CHn}}JEf}HJ`}\",[]]A`[\"{AHF`CMn}\",[]]o[\"{JEhCId}\",[]]o[\"{JEjCId}\",[]]Ce[\"{{{AIAj{CBfAIN`}}OHdOHdCIdCMn{AIAj{B@Hf}}}HJ`}\",[]]Cc[\"{{{AIAj{CBfNb}}OHdOHdCIdCMn{AIAj{B@Hf}}}HJ`}\",[]]Cd[\"{{{AIAj{CBfJF`}}OHdOHdCIdCMn{AIAj{B@Hf}}}HJ`}\",[]]Cd[\"{{{AIAj{CBfOI`}}OHdOHdCIdCMn{AIAj{B@Hf}}}HJ`}\",[]]Ce[\"{{{AIAj{CBfAINb}}OHdOHdCIdCMn{AIAj{B@Hh}}}HJ`}\",[]]Cc[\"{{{AIAj{CBfNd}}OHdOHdCIdCMn{AIAj{B@Hh}}}HJ`}\",[]]Cd[\"{{{AIAj{CBfJFb}}OHdOHdCIdCMn{AIAj{B@Hh}}}HJ`}\",[]]Cd[\"{{{AIAj{CBfOIb}}OHdOHdCIdCMn{AIAj{B@Hh}}}HJ`}\",[]]o[\"{CK`OHf}\",[]]o[\"{CKbOHh}\",[]]o[\"{BDMnMh}\",[]]A`[\"{BCB`JEf}\",[]]A`[\"{BDIhJEf}\",[]]A`[\"{BCBdJEf}\",[]]A`[\"{BDIlJEf}\",[]]A`[\"{BBGdLHb}\",[]]Aa[\"{BBBlBCBh}\",[]]Bg[\"{{{AIAj{ABKn}}AHJ`}{{LFl{HJ`}}}}\",[]]A`[\"{ABLfHJ`}\",[]]Cf[\"{{{AIAj{CBfABL`}}ABLh{AIAj{CBf{A@l{Mh}}}}}AC@`}\",[]]l[\"{OHf}\",[]]Aa[\"{AHFnAJB`}\",[]]l[\"{OHh}\",[]]Am[\"{{ABKlOn}{{LFn{HJ`}}}}\",[]]B`[\"{{B@I`AJB`}{{LFl{ABKn}}}}\",[]]Bb[\"{B@Hn{{LFj{HJ`{Nh{JFl}}}}}}\",[]]Bk[\"{{{AIAj{BEEj}}}{{LF`{{AIAj{JFl}}}}}}\",[]]Bk[\"{{{AIAj{BBFj}}}{{LF`{{AIAj{JFl}}}}}}\",[]]Bk[\"{{{AIAj{AHIh}}}{{LF`{{AIAj{JFl}}}}}}\",[]]Bk[\"{{{AIAj{AJAb}}}{{LF`{{AIAj{JFl}}}}}}\",[]]Bk[\"{{{AIAj{BBFh}}}{{LF`{{AIAj{JFl}}}}}}\",[]]Bk[\"{{{AIAj{AJCf}}}{{LF`{{AIAj{JFl}}}}}}\",[]]Bk[\"{{{AIAj{B@Il}}}{{LF`{{AIAj{JFl}}}}}}\",[]]Bk[\"{{{AIAj{BCBf}}}{{LF`{{AIAj{JFl}}}}}}\",[]]Bk[\"{{{AIAj{BCBh}}}{{LF`{{AIAj{JFl}}}}}}\",[]]A`[\"{ABOnLF`}\",[]]A`[\"{AC@`LF`}\",[]]A`[\"{AC@bLF`}\",[]]Bg[\"{{{AIAj{CKl}}}{{LFj{AJ@dAILn}}}}\",[]]Aa[\"{B@HbAJ@f}\",[]]A`[\"{AINhCId}\",[]]A`[\"{AINjCId}\",[]]A`[\"{ABNhLBd}\",[]]Aa[\"{AHIbAC@d}\",[]]Aa[\"{BCBnAC@d}\",[]]Aa[\"{AHIdAC@f}\",[]]Aa[\"{BCC`AC@f}\",[]]3210Dh[\"{{{AIAj{OGn}}{AIAj{{L@`{Mh}}}}{AIAj{{L@`{Mh}}}}}{{LFj{HJ`AOC`}}}}\",[]]Dh[\"{{{AIAj{OH`}}{AIAj{{L@`{Mh}}}}{AIAj{{L@`{Mh}}}}}{{LFj{HJ`AOCb}}}}\",[]]Aj[\"{{{AIAj{AIN`}}}CId}\",[]]Ah[\"{{{AIAj{Nb}}}CId}\",[]]Ai[\"{{{AIAj{JF`}}}CId}\",[]]Ai[\"{{{AIAj{OI`}}}CId}\",[]]Aj[\"{{{AIAj{AINb}}}CId}\",[]]Ah[\"{{{AIAj{Nd}}}CId}\",[]]Ai[\"{{{AIAj{JFb}}}CId}\",[]]Ai[\"{{{AIAj{OIb}}}CId}\",[]]Aj[\"{{{AIAj{BFOh}}}LBd}\",[]]Aj[\"{{{AIAj{BFOj}}}LBd}\",[]]Aj[\"{{{AIAj{BGOf}}}LBd}\",[]]Aj[\"{{{AIAj{BH@`}}}LBd}\",[]]n[\"{OnLBd}\",[]]n[\"{{}OG`}\",[]]0000o[\"{NlABJl}\",[]]Ba[\"{{AIAj{AIAj{c}}}ABMn{}}\",[\"K\"]]0000000000000000000Cg[\"{{{AIAj{ABKn}}AJB`{AIAj{CHn}}}{{LFj{AIMhB@Dh}}}}\",[]]Dl[\"{{{AIAj{CBfABL`}}OHdB@CdAJB`{AIAj{CHn}}}{{LFj{{LBb{BDJdAIMn}}B@Dj}}}}\",[]]Dm[\"{{{AIAj{AHHd}}LFdCId{AIAj{{L@`{Mh}}}}{AIAj{CBfABJh}}}{{LFj{HJ`AOC`}}}}\",[]]Ca[\"{{{AIAj{AHGf}}LBd{AIAj{CBf{L@`{Mh}}}}}HJ`}\",[]]Dm[\"{{{AIAj{AHHf}}LFfCId{AIAj{{L@`{Mh}}}}{AIAj{CBfABJh}}}{{LFj{HJ`AOCb}}}}\",[]]Ca[\"{{{AIAj{AHGh}}LBd{AIAj{CBf{L@`{Mh}}}}}HJ`}\",[]]o[\"{{}AOFb}\",[]]n[\"{{}JJb}\",[]]o[\"{{}AOBf}\",[]]o[\"{{}BADd}\",[]]o[\"{{}BAEf}\",[]]n[\"{{}LHf}\",[]]n[\"{{}LFd}\",[]]o[\"{{}AC@d}\",[]]o[\"{{}AINh}\",[]]o[\"{{}AHIb}\",[]]o[\"{{}BCBn}\",[]]n[\"{{}OLd}\",[]]o[\"{{}B@Cl}\",[]]o[\"{{}BCE`}\",[]]o[\"{{}BEHj}\",[]]o[\"{{}BEJh}\",[]]o[\"{{}AOCn}\",[]]o[\"{{}BBCj}\",[]]o[\"{{}BG@j}\",[]]o[\"{{}BDMf}\",[]]o[\"{{}AHEh}\",[]]o[\"{{}AOCd}\",[]]o[\"{{}BAGl}\",[]]o[\"{{}BEDj}\",[]]o[\"{{}BADf}\",[]]o[\"{{}BGOf}\",[]]n[\"{{}LHh}\",[]]n[\"{{}LFf}\",[]]o[\"{{}AJ@f}\",[]]o[\"{{}AIMd}\",[]]o[\"{{}AC@f}\",[]]o[\"{{}AINj}\",[]]o[\"{{}AHId}\",[]]o[\"{{}BCC`}\",[]]n[\"{{}OLf}\",[]]o[\"{{}BBFl}\",[]]o[\"{{}B@Dd}\",[]]o[\"{{}BCEb}\",[]]o[\"{{}BEHl}\",[]]o[\"{{}BEJj}\",[]]o[\"{{}AOD`}\",[]]o[\"{{}BBCl}\",[]]o[\"{{}BG@l}\",[]]o[\"{{}BH@`}\",[]]o[\"{{}BDMh}\",[]]o[\"{{}AHEj}\",[]]o[\"{{}AOCf}\",[]]o[\"{{}BAGn}\",[]]o[\"{{}BEDl}\",[]]o[\"{{}ABNh}\",[]]n[\"{{}JJd}\",[]]o[\"{{}BCCh}\",[]]o[\"{{}BAEd}\",[]]Ak[\"{{{AIAj{BAHb}}}B@E`}\",[]]Ak[\"{{{AIAj{BCD`}}}B@E`}\",[]]Aa[\"{BGDfB@E`}\",[]]Aa[\"{BEMbB@E`}\",[]]A`[\"{CKdB@E`}\",[]]A`[\"{JIhB@E`}\",[]]A`[\"{JIlB@E`}\",[]]Aa[\"{BDMnB@E`}\",[]]Cg[\"{{{AIAj{AHHd}}LFdCId{AIAj{CBf{L@`{Mh}}}}LBd}HJ`}\",[]]Ca[\"{{{AIAj{AHGf}}LBd{AIAj{CBf{L@`{Mh}}}}}HJ`}\",[]]Cg[\"{{{AIAj{AHHf}}LFfCId{AIAj{CBf{L@`{Mh}}}}LBd}HJ`}\",[]]Ca[\"{{{AIAj{AHGh}}LBd{AIAj{CBf{L@`{Mh}}}}}HJ`}\",[]]Aj[\"{{{AIAj{AJ@n}}}CMn}\",[]]Aj[\"{{{AIAj{BFBd}}}CMn}\",[]]Ak[\"{{{AIAj{AIN`}}}BEDj}\",[]]Ai[\"{{{AIAj{Nb}}}BEDj}\",[]]Aj[\"{{{AIAj{JF`}}}BEDj}\",[]]Aj[\"{{{AIAj{OI`}}}BEDj}\",[]]Ak[\"{{{AIAj{AINb}}}BEDl}\",[]]Ai[\"{{{AIAj{Nd}}}BEDl}\",[]]Aj[\"{{{AIAj{JFb}}}BEDl}\",[]]Aj[\"{{{AIAj{OIb}}}BEDl}\",[]]Bn[\"{{{AIAj{CBfBCE`}}CI`}{{AIAj{CBfBCE`}}}}\",[]]Bn[\"{{{AIAj{CBfBCEb}}CI`}{{AIAj{CBfBCEb}}}}\",[]]Bf[\"{{{AIAj{CBfAIN`}}OHdCIdCId}HJ`}\",[]]Bd[\"{{{AIAj{CBfNb}}OHdCIdCId}HJ`}\",[]]Bf[\"{{{AIAj{CBfAINb}}OHdCIdCId}HJ`}\",[]]Bd[\"{{{AIAj{CBfNd}}OHdCIdCId}HJ`}\",[]]Aj[\"{{{AIAj{AIMl}}}LEf}\",[]]Bc[\"{{{AIAj{ABMl}}}{{LF`{LFd}}}}\",[]]Aa[\"{BGDfB@E`}\",[]]Aa[\"{BEMbB@E`}\",[]]A`[\"{CKdB@E`}\",[]]A`[\"{JIhB@E`}\",[]]Aa[\"{BDMnB@E`}\",[]]Di[\"{{{AIAj{AJAj}}}{{`{{LE`{}{{LFb{{LFj{{LF`{LHf}}B@Il}}}}}}CLhCLn}}}}\",[]]Bn[\"{{{AIAj{AJAl}}}{{LFj{{LF`{LHh}}B@Dd}}}}\",[]]n[\"{OnLBd}\",[]]o[\"{JJbLBd}\",[]]Am[\"{{{AIAj{CBfAIMn}}}OKh}\",[]]Aj[\"{{{AIAj{AHHd}}}LBd}\",[]]Aj[\"{{{AIAj{AHHf}}}LBd}\",[]]A`[\"{AIAjLHd}\",[]]00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000Bd[\"{{{AIAj{BFIn}}}{{LF`{AIMl}}}}\",[]]Bn[\"{{{AIAj{CBfB@C`}}CIb}{{AIAj{CBfB@C`}}}}\",[]]Bn[\"{{{AIAj{CBfB@Cd}}CIb}{{AIAj{CBfB@Cd}}}}\",[]]A`[\"{BGDfCIb}\",[]]A`[\"{BEMbCIb}\",[]]o[\"{CKdCIb}\",[]]o[\"{JIhCIb}\",[]]A`[\"{AHF`LF`}\",[]]Aa[\"{AC@bAIAj}\",[]]A`[\"{AINhCId}\",[]]A`[\"{AINjCId}\",[]]Aa[\"{BBFnABKj}\",[]]A`[\"{LClBBFl}\",[]]Aa[\"{BCBnAINh}\",[]]Aa[\"{BCC`AINj}\",[]]10Bg[\"{{{AIAj{CBfc}}LBd}B@Dn{NjJJ`}}\",[\"\"]]Bg[\"{{{AIAj{CBfc}}LBd}B@E`{NjJJ`}}\",[\"\"]]o[\"{{}BCDb}\",[]]o[\"{{}BCDd}\",[]]A`[\"{CIdBGOf}\",[]]Cd[\"{{{AIAj{CHn}}}{{LFn{AOBdc}}}{}}\",[\"FromStr::Err\"]]o[\"{CIbLHf}\",[]]o[\"{CIbLHh}\",[]]Al[\"{CId{{LFj{LHfBFIh}}}}\",[]]Al[\"{CId{{LFj{LHhBFIj}}}}\",[]]Aa[\"{BFHbAOBn}\",[]]Aa[\"{BHCdBAFb}\",[]]Aa[\"{BFHdAOBn}\",[]]Aa[\"{BHCfBAFb}\",[]]Af[\"{{}{{LF`{Ab}}}}\",[]]0000Aj[\"{{{AIAj{AIMn}}}CMn}\",[]]Bo[\"{{{AIAj{CBfBEJh}}ABKj}{{AIAj{CBfBEJh}}}}\",[]]Bo[\"{{{AIAj{CBfBEJj}}ABKj}{{AIAj{CBfBEJj}}}}\",[]]Ao[\"{{{Nh{AIN`}}}{{Nh{Mn}}}}\",[]]Am[\"{{{Nh{Nb}}}{{Nh{Mn}}}}\",[]]An[\"{{{Nh{JF`}}}{{Nh{Mn}}}}\",[]]An[\"{{{Nh{OI`}}}{{Nh{Mn}}}}\",[]]Ao[\"{{{Nh{AINb}}}{{Nh{Mn}}}}\",[]]Am[\"{{{Nh{Nd}}}{{Nh{Mn}}}}\",[]]An[\"{{{Nh{JFb}}}{{Nh{Mn}}}}\",[]]An[\"{{{Nh{OIb}}}{{Nh{Mn}}}}\",[]]Aj[\"{{{AIAj{BFIn}}}CMn}\",[]]Bo[\"{{{AIAj{CBfBG@j}}ABKj}{{AIAj{CBfBG@j}}}}\",[]]Bo[\"{{{AIAj{CBfBG@l}}ABKj}{{AIAj{CBfBG@l}}}}\",[]]Bc[\"{{{AIAj{AIMh}}}{{LF`{LEd}}}}\",[]]Bc[\"{{{AIAj{AIMl}}}{{LF`{LEd}}}}\",[]]Bc[\"{{{AIAj{ABLf}}}{{LF`{LEd}}}}\",[]]Bc[\"{{{AIAj{ABLh}}}{{LF`{LEd}}}}\",[]]A`[\"{AHFnLF`}\",[]]A`[\"{AINhCId}\",[]]A`[\"{AINjCId}\",[]]Bc[\"{{{AIAj{AHFf}}}{{LF`{LBd}}}}\",[]]Am[\"{{{AIAj{AOFd}}LBd}HJ`}\",[]]Aj[\"{{{AIAj{AIMl}}}OIf}\",[]]Bg[\"{{{AIAj{AJAj}}}{{LFj{CA`B@Cl}}}}\",[]]Bg[\"{{{AIAj{AJAl}}}{{LFj{CA`B@Dd}}}}\",[]]A`[\"{BAEjLF`}\",[]]A`[\"{BAElLF`}\",[]]A`[\"{AHF`LF`}\",[]]A`[\"{AOB`LF`}\",[]]Ck[\"{{{AIAj{CBfBBCj}}{LF`{{JJj{Mh}}}}}{{AIAj{CBfBBCj}}}}\",[]]Ck[\"{{{AIAj{CBfBBCl}}{LF`{{JJj{Mh}}}}}{{AIAj{CBfBBCl}}}}\",[]]A`[\"{BEDjLF`}\",[]]A`[\"{BEDlLF`}\",[]]Ac[\"{AIAjc{}}\",[\"T\"]]000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000Ao[\"{c{{LFj{e}}}{}{}}\",[\"U\",\"T\"]]000000000000000000000000000000000000000000000Al[\"{LBd{{LFj{LHfBFIh}}}}\",[]]Al[\"{HIn{{LFj{LHfBFIh}}}}\",[]]Al[\"{CId{{LFj{LHfBFIh}}}}\",[]]333333333333333Aj[\"{ABKj{{LFj{AOCn}}}}\",[]]444444Ai[\"{CId{{LFj{AHG`}}}}\",[]]555555555555555555555555555Bb[\"{{{N`{B@Bl}}}{{LFj{BDLn}}}}\",[]]6Aj[\"{B@Bl{{LFj{BDLn}}}}\",[]]Bb[\"{{{N`{B@Hl}}}{{LFj{BDMb}}}}\",[]]Aj[\"{B@Hl{{LFj{BDMb}}}}\",[]]99999999999999999999Al[\"{CId{{LFj{LHhBFIj}}}}\",[]]Al[\"{HIn{{LFj{LHhBFIj}}}}\",[]]Al[\"{LBd{{LFj{LHhBFIj}}}}\",[]]<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>Bm[\"{B@Bl{{LFj{BDM`c}}}{}}\",[\"TryFrom::Error\"]]Ce[\"{{{N`{B@Bl}}}{{LFj{BDM`c}}}{}}\",[\"TryFrom::Error\"]]Ao[\"{c{{LFj{e}}}{}{}}\",[\"U\",\"T\"]]Ce[\"{{{N`{B@Hl}}}{{LFj{BDMdc}}}{}}\",[\"TryFrom::Error\"]]Bm[\"{B@Hl{{LFj{BDMdc}}}{}}\",[\"TryFrom::Error\"]]2222222222222222222222222222Aj[\"{{}{{LFj{c}}}{}}\",[\"U\"]]00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000Cd[\"{{{A@f{{AIAj{CBfc}}}}{AIAj{CBfOGb}}}CLd{}}\",[\"F\"]]000000000Cc[\"{{{AIAj{BBGf}}AJCd{AIAj{AC@b}}}{{LFl{HJ`}}}}\",[]]Bk[\"{{{AIAj{BFOh}}B@Dn}{{LFj{HJ`AINn}}}}\",[]]Bk[\"{{{AIAj{BFOj}}B@E`}{{LFj{HJ`AIO`}}}}\",[]]0Bk[\"{{{AIAj{BGOf}}B@E`}{{LFj{HJ`AIO`}}}}\",[]]Ak[\"{{{AIAj{AIMl}}}ABJf}\",[]]Bi[\"{{{AIAj{CBfB@J`}}}{{LFj{LHfJGf}}}}\",[]]Bi[\"{{{AIAj{CBfB@J`}}}{{LFj{CLjJGf}}}}\",[]]Bh[\"{{{AIAj{CBfB@J`}}}{{LFj{NnJGf}}}}\",[]]Bj[\"{{{AIAj{CBfB@J`}}}{{LFj{ABNlJGf}}}}\",[]]Bf[\"{{{AIAj{CBfB@J`}}}{{LG`{LHh}}}}\",[]]Bf[\"{{{AIAj{CBfB@J`}}}{{LG`{CLl}}}}\",[]]Be[\"{{{AIAj{CBfB@J`}}}{{LG`{O`}}}}\",[]]Bg[\"{{{AIAj{CBfB@J`}}}{{LG`{ABNn}}}}\",[]]Aa[\"{AOBdBFIf}\",[]]Bc[\"{{{AIAj{AIN`}}}{{Nh{AIN`}}}}\",[]]Ba[\"{{{AIAj{Nb}}}{{Nh{AIN`}}}}\",[]]Bb[\"{{{AIAj{JF`}}}{{Nh{AIN`}}}}\",[]]Bb[\"{{{AIAj{OI`}}}{{Nh{AIN`}}}}\",[]]Bc[\"{{{AIAj{AINb}}}{{Nh{AINb}}}}\",[]]Ba[\"{{{AIAj{Nd}}}{{Nh{AINb}}}}\",[]]Bb[\"{{{AIAj{JFb}}}{{Nh{AINb}}}}\",[]]Bb[\"{{{AIAj{OIb}}}{{Nh{AINb}}}}\",[]]A`[\"{AC@dCId}\",[]]An[\"{{{AIAj{CBfAIMn}}}AHFf}\",[]]A`[\"{AC@fCId}\",[]]C`[\"{{{AIAj{CBfB@Dn}}}{{AIAj{CBf{L@`{Mh}}}}}}\",[]]C`[\"{{{AIAj{CBfB@E`}}}{{AIAj{CBf{L@`{Mh}}}}}}\",[]]Ah[\"{Mh{{LF`{B@Eh}}}}\",[]]Ah[\"{Mh{{LF`{B@Ej}}}}\",[]]Ah[\"{Mh{{LF`{B@El}}}}\",[]]A`[\"{ABNlCLj}\",[]]A`[\"{ABNnCLl}\",[]]Bi[\"{AIMh{{LFj{{LBb{AIMlBCEj}}AIMh}}}}\",[]]o[\"{CLjCMn}\",[]]o[\"{CLlCMn}\",[]]Aj[\"{{{AIAj{AIMn}}}CMn}\",[]]21Aj[\"{{{AIAj{ABLf}}}CMn}\",[]]Aj[\"{{{AIAj{ABLh}}}CMn}\",[]]Bn[\"{{{AIAj{CBfB@I`}}CMn}{{AIAj{CBfB@I`}}}}\",[]]Bn[\"{{{AIAj{CBfB@Id}}CMn}{{AIAj{CBfB@Id}}}}\",[]]Bl[\"{{{AIAj{OJh}}OHd}{{A@f{{Nh{AILf}}}}}}\",[]]Bm[\"{{{AIAj{B@In}}OHd}{{A@f{{Nh{AILf}}}}}}\",[]]Bm[\"{{{AIAj{AOEh}}OHd}{{A@f{{Nh{AILf}}}}}}\",[]]A`[\"{AINhCId}\",[]]A`[\"{AINjCId}\",[]]Ak[\"{{{AIAj{AIMl}}}ABMj}\",[]]Bc[\"{{{AIAj{AIMl}}AJB`AJ@d}ABMl}\",[]]Ce[\"{{{AIAj{CBfAIMn}}AHFnAJ@fOHd}{{LFj{LFfAHHj}}}}\",[]]43Bm[\"{{{AIAj{CBfAIMn}}LFf}{{LFj{HJ`AIMd}}}}\",[]]E`[\"{{{A@f{{AIAj{CBfBDId}}}}{AIAj{CBfOGb}}}{{CLd{{LF`{c}}}}}{}}\",[\"Stream::Item\"]]Ef[\"{{{A@f{{AIAj{CBfAJ@n}}}}{AIAj{CBfOGb}}{AIAj{CBf{L@`{Mh}}}}}{{CLd{{LFl{LBd}}}}}}\",[]]Ec[\"{{{AIAj{CBfAJ@n}}{AIAj{CBfOGb}}{AIAj{CBf{L@`{Mh}}}}}{{CLd{{LFj{LBdAHIh}}}}}}\",[]]E`[\"{{{A@f{{AIAj{CBfAJ@n}}}}{AIAj{CBfOGb}}{AIAj{CBfOJb}}}{{CLd{{LFl{HJ`}}}}}}\",[]]Fg[\"{{{AIAj{CBfBBBb}}{AIAj{CBfOGb}}{AIAj{CBf{L@`{AIOb}}}}{AIAj{CBf{L@`{ABNh}}}}}{{CLd{{LFl{LBd}}}}}}\",[]]Dn[\"{{{A@f{{AIAj{CBfAHIn}}}}{AIAj{AC@b}}{AIAj{CBfOGb}}}{{CLd{{LFl{HJ`}}}}}}\",[]];:Cd[\"{{{AIAj{CBfBBCj}}{N`{OGn}}}{{AIAj{CBfBBCj}}}}\",[]]Cd[\"{{{AIAj{CBfBBCl}}{N`{OH`}}}{{AIAj{CBfBBCl}}}}\",[]]Cj[\"{{{AIAj{B@Ib}}CIbB@Dn{AIAj{{L@`{Mh}}}}}{{JJj{Mh}}}}\",[]]Cj[\"{{{AIAj{BDMb}}CIbB@Dn{AIAj{{L@`{Mh}}}}}{{JJj{Mh}}}}\",[]]Cj[\"{{{AIAj{B@If}}CIbB@E`{AIAj{{L@`{Mh}}}}}{{JJj{Mh}}}}\",[]]Cj[\"{{{AIAj{BDMd}}CIbB@E`{AIAj{{L@`{Mh}}}}}{{JJj{Mh}}}}\",[]]Cj[\"{{{AIAj{BGJb}}CIbB@Dl{AIAj{{L@`{Mh}}}}}{{JJj{Mh}}}}\",[]]Bb[\"{LBd{{LBb{LBd{LF`{LBd}}}}}}\",[]]00000Aj[\"{{{AIAj{AIMl}}}LBd}\",[]]A`[\"{AIAjLHb}\",[]]0000000000000000000000000000000000000000000000000000000000000Ce[\"{{{AIAj{CBfB@I`}}{N`{BEDn}}}{{AIAj{CBfB@I`}}}}\",[]]Ce[\"{{{AIAj{CBfB@Id}}{N`{BEE`}}}{{AIAj{CBfB@Id}}}}\",[]]A`[\"{BGDfJHn}\",[]]o[\"{B@I`N`}\",[]]o[\"{B@IdN`}\",[]]Aj[\"{{{AIAj{ABKn}}}HJ`}\",[]]Ck[\"{{{AIAj{CBfAJAj}}{AIAj{{L@`{Mh}}}}}{{LFj{HJ`AJCf}}}}\",[]]n[\"{{}LBd}\",[]]Ak[\"{{{AIAj{AIMl}}}AHDj}\",[]]Bn[\"{{{AIAj{CBfBCE`}}CMn}{{AIAj{CBfBCE`}}}}\",[]]Bn[\"{{{AIAj{CBfBCEb}}CMn}{{AIAj{CBfBCEb}}}}\",[]]Bi[\"{{{AIAj{CBf}}}{{AIAj{CBfc}}}{}}\",[\"T\"]]00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000Bc[\"{{AIAj{AIAj{CBfc}}}HJ`{}}\",[\"T\"]]000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000Cc[\"{{{AIAj{CBfAIMn}}OHdLFfLHh}{{LFj{HJ`BBBh}}}}\",[]]A`[\"{AHF`CMn}\",[]]B`[\"{{AIAj{AIAj{c}}}CMn{}}\",[\"K\"]]00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000Aa[\"{BCB`BELn}\",[]]A`[\"{BDIhLHf}\",[]]Aa[\"{BCBdBEM`}\",[]]A`[\"{BDIlLHh}\",[]]o[\"{LDdLHh}\",[]]o[\"{OJnLHh}\",[]]Aa[\"{BCB`AIOd}\",[]]Aa[\"{BCBdAIOf}\",[]]o[\"{LHfCId}\",[]]o[\"{LHhCId}\",[]]Aj[\"{{{AIAj{AIMn}}}CMn}\",[]]Aj[\"{{{AIAj{BAEd}}}CMn}\",[]]Bd[\"{{{AIAj{BBBb}}}{{LFl{AJB`}}}}\",[]]Bd[\"{{{AIAj{ABKn}}}{{LFl{AJB`}}}}\",[]]A`[\"{AHIbCId}\",[]]A`[\"{AHIdCId}\",[]]Cb[\"{{{AIAj{BCCh}}{AIAj{AJAh}}CId}{{N`{AOFd}}}}\",[]]Bn[\"{{{AIAj{CBfBCE`}}CMn}{{AIAj{CBfBCE`}}}}\",[]]Bn[\"{{{AIAj{CBfBCEb}}CMn}{{AIAj{CBfBCEb}}}}\",[]]Bg[\"{{{AIAj{AIMl}}LFd}{{LF`{AHIb}}}}\",[]]Bj[\"{{{AIAj{CBfAIMn}}LFf}{{LF`{AHId}}}}\",[]]Aa[\"{AHDfAHId}\",[]]Db[\"{{{A@f{{AIAj{CBfAJAj}}}}{AIAj{CBfOGb}}}{{CLd{{LFl{HJ`}}}}}}\",[]]00Ec[\"{{{A@f{{AIAj{CBfAJAj}}}}{AIAj{CBfOGb}}{AIAj{{L@`{Mh}}}}}{{CLd{{LFl{LBd}}}}}}\",[]]0Eg[\"{{{A@f{{AIAj{CBfAJAj}}}}{AIAj{CBfOGb}}{AIAj{{L@`{Mh}}}}}{{CLd{{LFj{LBdAJCf}}}}}}\",[]]Bm[\"{{{AIAj{JJd}}{AIAj{CKj}}}{{LFl{HJ`}}}}\",[]]Cd[\"{{{AIAj{CBfAJ@n}}LBd}{{LFj{{LF`{JEh}}AHIh}}}}\",[]]Cd[\"{{{AIAj{CBfBFBd}}LBd}{{LFj{{LF`{JEh}}AHIh}}}}\",[]]Cn[\"{{{AIAj{CBfAJ@n}}{AIAj{CBf{L@`{Mh}}}}}{{LFj{HJ`BBFh}}}}\",[]]Bj[\"{{{AIAj{CKl}}AJ@d}{{LFj{HJ`BELf}}}}\",[]]Bn[\"{{{AIAj{CBfAJ@h}}OHd}{{AIAj{CBfAJ@h}}}}\",[]]Bn[\"{{{AIAj{CBfAJ@j}}OHd}{{AIAj{CBfAJ@j}}}}\",[]]A`[\"{BBFnADj}\",[]]o[\"{JJbCId}\",[]]o[\"{{}AJB`}\",[]]0o[\"{{}AIAj}\",[]]Bj[\"{{ABLf{N`{B@I`}}}{{LFj{AIMhBCBf}}}}\",[]]A`[\"{AINhCId}\",[]]A`[\"{AINjCId}\",[]]Bh[\"{{{AIAj{AHF`}}AJB`}{{LFn{AHJ`}}}}\",[]]A`[\"{AHIbCI`}\",[]]Aj[\"{{{AIAj{AIMn}}}CI`}\",[]]A`[\"{AHIdCI`}\",[]]Ce[\"{{{AIAj{CBfAJ@h}}{LF`{LHb}}}{{AIAj{CBfAJ@h}}}}\",[]]Ce[\"{{{AIAj{CBfAJ@j}}{LF`{LHb}}}{{AIAj{CBfAJ@j}}}}\",[]]Aa[\"{ABOnAJB`}\",[]]Aa[\"{AC@`AJB`}\",[]]Aa[\"{AC@bAJB`}\",[]]n[\"{OnCI`}\",[]]Bn[\"{{{AIAj{CBfBCE`}}CI`}{{AIAj{CBfBCE`}}}}\",[]]Bn[\"{{{AIAj{CBfBCEb}}CI`}{{AIAj{CBfBCEb}}}}\",[]]A`[\"{AHF`CI`}\",[]]Bo[\"{{{AIAj{CBfBCE`}}ABKj}{{AIAj{CBfBCE`}}}}\",[]]Bo[\"{{{AIAj{CBfBCEb}}ABKj}{{AIAj{CBfBCEb}}}}\",[]]A`[\"{AHF`LF`}\",[]]k[\"{{}}\",[]]00000000000Bh[\"{ABLfc{}}\",[\"IntoFuture::IntoFuture\"]]1A`[\"{AINhCId}\",[]]A`[\"{AINjCId}\",[]]n[\"{OnLBd}\",[]]Ao[\"{{AIAjc}{{OHj{c}}}{}}\",[\"S\"]]0C`[\"{{{AIAj{CBfAIN`}}OHdCIdCMn{LF`{CId}}}HJ`}\",[]]Bn[\"{{{AIAj{CBfNb}}OHdCIdCMn{LF`{CId}}}HJ`}\",[]]C`[\"{{{AIAj{CBfAINb}}OHdCIdCMn{LF`{CId}}}HJ`}\",[]]Bn[\"{{{AIAj{CBfNd}}OHdCIdCMn{LF`{CId}}}HJ`}\",[]]Bk[\"{{{AIAj{CBfJJd}}OHd{AIAj{BCCh}}}HJ`}\",[]]A`[\"{BEDjLF`}\",[]]A`[\"{BEDlLF`}\",[]]Bn[\"{{{AIAj{LHf}}{AIAj{LHf}}}{{LF`{ABMn}}}}\",[]]Bn[\"{{{AIAj{LFd}}{AIAj{LFd}}}{{LF`{ABMn}}}}\",[]]C`[\"{{{AIAj{AOCn}}{AIAj{AOCn}}}{{LF`{ABMn}}}}\",[]]C`[\"{{{AIAj{B@Dn}}{AIAj{B@Dn}}}{{LF`{ABMn}}}}\",[]]Bn[\"{{{AIAj{CLj}}{AIAj{CLj}}}{{LF`{ABMn}}}}\",[]]Bl[\"{{{AIAj{Nn}}{AIAj{Nn}}}{{LF`{ABMn}}}}\",[]]C`[\"{{{AIAj{ABNl}}{AIAj{ABNl}}}{{LF`{ABMn}}}}\",[]]Bn[\"{{{AIAj{LHh}}{AIAj{LHh}}}{{LF`{ABMn}}}}\",[]]C`[\"{{{AIAj{BEEl}}{AIAj{BEEl}}}{{LF`{ABMn}}}}\",[]]Bn[\"{{{AIAj{LFf}}{AIAj{LFf}}}{{LF`{ABMn}}}}\",[]]C`[\"{{{AIAj{AHIj}}{AIAj{AHIj}}}{{LF`{ABMn}}}}\",[]]C`[\"{{{AIAj{BAHl}}{AIAj{BAHl}}}{{LF`{ABMn}}}}\",[]]C`[\"{{{AIAj{AJCh}}{AIAj{AJCh}}}{{LF`{ABMn}}}}\",[]]C`[\"{{{AIAj{AOD`}}{AIAj{AOD`}}}{{LF`{ABMn}}}}\",[]]C`[\"{{{AIAj{BDJd}}{AIAj{BDJd}}}{{LF`{ABMn}}}}\",[]]C`[\"{{{AIAj{BEEh}}{AIAj{BEEh}}}{{LF`{ABMn}}}}\",[]]C`[\"{{{AIAj{B@E`}}{AIAj{B@E`}}}{{LF`{ABMn}}}}\",[]]Bn[\"{{{AIAj{CLl}}{AIAj{CLl}}}{{LF`{ABMn}}}}\",[]]Bl[\"{{{AIAj{O`}}{AIAj{O`}}}{{LF`{ABMn}}}}\",[]]C`[\"{{{AIAj{ABNn}}{AIAj{ABNn}}}{{LF`{ABMn}}}}\",[]]Be[\"{{{AIAj{AIMl}}}{{ABNd{AHHn}}}}\",[]]Bk[\"{{{AIAj{AIMn}}LFf}{{LFj{AJ@fAIMd}}}}\",[]]Df[\"{{{AIAj{CBfAJ@n}}{AIAj{CBf{L@`{JEf}}}}}{{LFj{{LF`{LBd}}AHIh}}}}\",[]]Cc[\"{{{AIAj{CBfAJ@n}}LBd}{{LFj{{A@l{Mh}}BBFj}}}}\",[]]Bb[\"{{{AIAj{CBfAIMn}}ABNn}AJA`}\",[]]Aj[\"{{{AIAj{AHGf}}}LBd}\",[]]Aj[\"{{{AIAj{AHGh}}}LBd}\",[]]Bb[\"{{{AIAj{CBfAIMn}}ABNn}AJAl}\",[]]Bn[\"{{{AIAj{CBfBCE`}}CId}{{AIAj{CBfBCE`}}}}\",[]]Bn[\"{{{AIAj{CBfBCEb}}CId}{{AIAj{CBfBCEb}}}}\",[]]A`[\"{AHF`LF`}\",[]]A`[\"{BAEjLF`}\",[]]A`[\"{BAElLF`}\",[]]Ce[\"{{{AIAj{CBfB@I`}}{N`{AJBh}}}{{AIAj{CBfB@I`}}}}\",[]]Ce[\"{{{AIAj{CBfB@Id}}{N`{AJBj}}}{{AIAj{CBfB@Id}}}}\",[]]Ce[\"{{{AIAj{CBfB@C`}}{N`{AJC`}}}{{AIAj{CBfB@C`}}}}\",[]]Ce[\"{{{AIAj{CBfB@Cd}}{N`{AJCb}}}{{AIAj{CBfB@Cd}}}}\",[]]n[\"{OnCId}\",[]]Bn[\"{{{AIAj{CBfBEJh}}CI`}{{AIAj{CBfBEJh}}}}\",[]]Bn[\"{{{AIAj{CBfBEJj}}CI`}{{AIAj{CBfBEJj}}}}\",[]]Ak[\"{{{AIAj{AIMl}}}BFIn}\",[]]Ai[\"{{{N`{B@Ib}}}B@I`}\",[]]Ai[\"{{{N`{B@If}}}B@Id}\",[]]Aj[\"{{BCDbc}BCDbABOd}\",[\"\"]]Aj[\"{{BCDdc}BCDdABOd}\",[\"\"]]Bm[\"{{{AIAj{CBfAJAj}}JEf}{{LFj{HJ`AJCf}}}}\",[]]n[\"{{}LEd}\",[]]o[\"{OG`OG`}\",[]]0000Bd[\"{{{AIAj{BFOh}}}{{LF`{ABKj}}}}\",[]]Bd[\"{{{AIAj{BFOj}}}{{LF`{ABKj}}}}\",[]]Bd[\"{{{AIAj{BGOf}}}{{LF`{ABKj}}}}\",[]]Bd[\"{{{AIAj{BH@`}}}{{LF`{ABKj}}}}\",[]]Bd[\"{{{AIAj{AIMl}}}{{LF`{BCBf}}}}\",[]]Ck[\"{{{AIAj{ABKn}}B@C`AJB`{AIAj{CHn}}}{{LFj{AIMhB@Dh}}}}\",[]]Ak[\"{{{AIAj{B@Hh}}}ABKj}\",[]]A`[\"{AINhCId}\",[]]A`[\"{AINjCId}\",[]]An[\"{{AJ@lCMn}{{LFn{LBd}}}}\",[]]Cj[\"{{{AIAj{OJj}}}{{LF`{{LBb{{Nh{AHGf}}{Nh{AHHd}}}}}}}}\",[]]Ck[\"{{{AIAj{AJBl}}}{{LF`{{LBb{{Nh{AHGf}}{Nh{AHHd}}}}}}}}\",[]]Cj[\"{{{AIAj{OJl}}}{{LF`{{LBb{{Nh{AHGh}}{Nh{AHHf}}}}}}}}\",[]]Ck[\"{{{AIAj{AJBn}}}{{LF`{{LBb{{Nh{AHGh}}{Nh{AHHf}}}}}}}}\",[]]A`[\"{BFHbA@l}\",[]]A`[\"{BHCdA@l}\",[]]A`[\"{BFHdA@l}\",[]]A`[\"{BHCfA@l}\",[]]An[\"{{{AIAj{CBfBFOh}}}B@Dn}\",[]]An[\"{{{AIAj{CBfBFOj}}}B@E`}\",[]]An[\"{{{AIAj{CBfBGOf}}}B@E`}\",[]]An[\"{{{AIAj{CBfBH@`}}}B@E`}\",[]]Ak[\"{{{AIAj{BBGf}}}B@Fn}\",[]]Ba[\"{{{AIAj{CBfAIMn}}BCBl}HJ`}\",[]]Bo[\"{{{AIAj{CBfABL`}}BDJdBAEd}{{LF`{BCBl}}}}\",[]]B`[\"{{{AIAj{OJj}}B@DnCLj}CK`}\",[]]Bn[\"{{{AIAj{B@Ib}}CIbB@Dn}{{LFj{CK`BEMf}}}}\",[]]Ba[\"{{{AIAj{AJBl}}B@DnCLj}CK`}\",[]]Bn[\"{{{AIAj{BDMb}}CIbB@Dn}{{LFj{CK`BEMf}}}}\",[]]B`[\"{{{AIAj{OJl}}B@E`CLl}CKb}\",[]]Bn[\"{{{AIAj{B@If}}CIbB@E`}{{LFj{CKbBEMl}}}}\",[]]Ba[\"{{{AIAj{AJBn}}B@E`CLl}CKb}\",[]]Bn[\"{{{AIAj{BDMd}}CIbB@E`}{{LFj{CKbBEMl}}}}\",[]]Bn[\"{{{AIAj{BGJb}}CIbB@Dl}{{LFj{CKbBEMl}}}}\",[]]Aj[\"{{}{{OJd{c}}}{}}\",[\"T\"]]0A`[\"{AHIbCId}\",[]]A`[\"{AHIdCId}\",[]]Bn[\"{{{AIAj{CBfB@I`}}LBd}{{AIAj{CBfB@I`}}}}\",[]]Bn[\"{{{AIAj{CBfB@Id}}LBd}{{AIAj{CBfB@Id}}}}\",[]]Aj[\"{{{AIAj{BBBb}}}CMn}\",[]]0Aj[\"{{{AIAj{BBGf}}}CMn}\",[]]Bk[\"{{{AIAj{AIMn}}LFf}{{LFj{AHFnAIMd}}}}\",[]]Cb[\"{{{AIAj{BCCh}}{AIAj{AJ@l}}CId}{{N`{AOFd}}}}\",[]]Ak[\"{{{AIAj{ABLf}}}B@Dn}\",[]]Ak[\"{{{AIAj{ABLh}}}B@E`}\",[]]A`[\"{AINhCId}\",[]]A`[\"{AINjCId}\",[]]Bf[\"{{{AIAj{CBfAIMn}}}{{LF`{OHd}}}}\",[]]Ce[\"{{{AIAj{CBfBCE`}}{N`{AODl}}}{{AIAj{CBfBCE`}}}}\",[]]Ce[\"{{{AIAj{CBfBCEb}}{N`{AODn}}}{{AIAj{CBfBCEb}}}}\",[]]43A`[\"{ABOnLF`}\",[]]A`[\"{AC@`LF`}\",[]]A`[\"{AC@bLF`}\",[]]Ai[\"{{{AIAj{OKh}}}LBd}\",[]]Bo[\"{{{AIAj{CBfBGOf}}ABKj}{{AIAj{CBfBGOf}}}}\",[]]Bo[\"{{{AIAj{CBfBH@`}}ABKj}{{AIAj{CBfBH@`}}}}\",[]]Bj[\"{{{AIAj{AJAj}}CA`}{{LFj{HJ`B@Cl}}}}\",[]]Bm[\"{{{AIAj{CBfAJAl}}CA`}{{LFj{HJ`B@Dd}}}}\",[]]<;A`[\"{JJbAOFb}\",[]]A`[\"{AOBfJJb}\",[]]Bi[\"{{{N`{B@Bl}}JJf}{{LFj{BDLnBFI`}}}}\",[]]Bi[\"{{{N`{B@Hl}}JJf}{{LFj{BDMbBFI`}}}}\",[]]Bi[\"{{{N`{B@Bl}}JJf}{{LFj{BDM`BFIb}}}}\",[]]Bi[\"{{{N`{B@Hl}}JJf}{{LFj{BDMdBFIb}}}}\",[]]Co[\"{{{AIAj{CBfAJAj}}{AIAj{CBf{L@`{JEf}}}}}{{LFj{OLdAJCf}}}}\",[]]Co[\"{{{AIAj{CBfAJAl}}{AIAj{CBf{L@`{JEf}}}}}{{LFj{OLfAJCh}}}}\",[]]Aj[\"{{{AIAj{AIMn}}}CMn}\",[]]A`[\"{AINhCId}\",[]]A`[\"{AINjCId}\",[]]A`[\"{AHF`CMn}\",[]]E`[\"{{{AIAj{CBfBBCj}}c}{{AIAj{CBfBBCj}}}{{A`{}{{LFb{{Nh{BFOh}}}}}}CLhCLn}}\",[\"F\"]]E`[\"{{{AIAj{CBfBBCl}}c}{{AIAj{CBfBBCl}}}{{A`{}{{LFb{{Nh{BFOj}}}}}}CLhCLn}}\",[\"F\"]]Bj[\"{{{AIAj{BBBb}}}{{A@f{{Nh{AHIn}}}}}}\",[]]n[\"{OnCId}\",[]]Aa[\"{AOFbAHGj}\",[]]76Aa[\"{AJAdABLf}\",[]]Aa[\"{AJAfABLh}\",[]]Cf[\"{{{AIAj{CBfBEHj}}{LF`{ABKj}}}{{AIAj{CBfBEHj}}}}\",[]]Cf[\"{{{AIAj{CBfBEHl}}{LF`{ABKj}}}{{AIAj{CBfBEHl}}}}\",[]]9;:An[\"{{{AIAj{AOFd}}ABKj}HJ`}\",[]]B`[\"{{{AIAj{CBfAIN`}}CI`}HJ`}\",[]]An[\"{{{AIAj{CBfNb}}CI`}HJ`}\",[]]Ao[\"{{{AIAj{CBfJF`}}CI`}HJ`}\",[]]Ao[\"{{{AIAj{CBfOI`}}CI`}HJ`}\",[]]B`[\"{{{AIAj{CBfAINb}}CI`}HJ`}\",[]]An[\"{{{AIAj{CBfNd}}CI`}HJ`}\",[]]Ao[\"{{{AIAj{CBfJFb}}CI`}HJ`}\",[]]Ao[\"{{{AIAj{CBfOIb}}CI`}HJ`}\",[]]A`[\"{AINhCId}\",[]]A`[\"{AINjCId}\",[]]10Bh[\"{{{AIAj{AIMl}}}{{LF`{{Nh{Mn}}}}}}\",[]]Bg[\"{{{AIAj{OJj}}}{{LF`{{Nh{Mn}}}}}}\",[]]Bh[\"{{{AIAj{AJBl}}}{{LF`{{Nh{Mn}}}}}}\",[]]Bg[\"{{{AIAj{OJl}}}{{LF`{{Nh{Mn}}}}}}\",[]]Bh[\"{{{AIAj{AJBn}}}{{LF`{{Nh{Mn}}}}}}\",[]]Dm[\"{{{AIAj{CBfAJ@n}}{AIAj{CBfOGb}}{AIAj{CBfOJb}}}{{CLd{{LFj{HJ`AHIh}}}}}}\",[]]Db[\"{{{A@f{{AIAj{CBfAJAj}}}}{AIAj{CBfOGb}}}{{CLd{{LFl{HJ`}}}}}}\",[]]Db[\"{{{AIAj{CBfAIMn}}OHdB@Fn{AIAj{CBf{A@l{Mh}}}}}{{LF`{AC@`}}}}\",[]]Cf[\"{{{AIAj{CBfBCE`}}{AIAj{CHn}}}{{AIAj{CBfBCE`}}}}\",[]]Cf[\"{{{AIAj{CBfBCEb}}{AIAj{CHn}}}{{AIAj{CBfBCEb}}}}\",[]]Ak[\"{{{AIAj{AIMl}}}B@H`}\",[]]Bj[\"{{{AIAj{AIMl}}JEf}{{LFj{HJ`BEEj}}}}\",[]]Bn[\"{{{AIAj{CBfBCE`}}CMn}{{AIAj{CBfBCE`}}}}\",[]]Bn[\"{{{AIAj{CBfBCEb}}CMn}{{AIAj{CBfBCEb}}}}\",[]]Ai[\"{{{AIAj{OGn}}}LBd}\",[]]Ai[\"{{{AIAj{OH`}}}LBd}\",[]]De[\"{{{N`{B@Cb}}CIb{AIAj{CHn}}{AIAj{BFBb}}}{{LFj{{Nh{OJj}}B@Dh}}}}\",[]]Bo[\"{{{N`{B@Ib}}CIb{AIAj{BFBb}}}{{Nh{OJj}}}}\",[]]De[\"{{{N`{BDLn}}CIb{AIAj{CHn}}{AIAj{BFBb}}}{{LFj{{Nh{OJj}}B@Dh}}}}\",[]]Bo[\"{{{N`{BDMb}}CIb{AIAj{BFBb}}}{{Nh{OJj}}}}\",[]]De[\"{{{N`{B@Cf}}CIb{AIAj{CHn}}{AIAj{BFBb}}}{{LFj{{Nh{OJl}}B@Dj}}}}\",[]]Bo[\"{{{N`{B@If}}CIb{AIAj{BFBb}}}{{Nh{OJl}}}}\",[]]De[\"{{{N`{BDM`}}CIb{AIAj{CHn}}{AIAj{BFBb}}}{{LFj{{Nh{OJl}}B@Dj}}}}\",[]]Bo[\"{{{N`{BDMd}}CIb{AIAj{BFBb}}}{{Nh{OJl}}}}\",[]]De[\"{{{N`{BGJ`}}CIb{AIAj{CHn}}{AIAj{BFBb}}}{{LFj{{Nh{OJl}}B@Df}}}}\",[]]Bo[\"{{{N`{BGJb}}CIb{AIAj{BFBb}}}{{Nh{OJl}}}}\",[]]Bm[\"{LBd{{LFj{{LBb{LBd{LF`{LBd}}}}BFAf}}}}\",[]]0Cc[\"{{{AIAj{BEDn}}{AIAj{{L@`{Mh}}}}}{{Nh{OFf}}}}\",[]]Cc[\"{{{AIAj{BEE`}}{AIAj{{L@`{Mh}}}}}{{Nh{OFh}}}}\",[]]Bm[\"{{AJB`BBBdOn}{{LFn{{LBb{ABKlAIMj}}}}}}\",[]]Bd[\"{{{AIAj{AIMn}}}{{AIAj{OJl}}}}\",[]]A`[\"{AOBfJJb}\",[]]Cb[\"{{{AIAj{AODl}}CLjAJB`B@DnOHd}{{LF`{AJ@h}}}}\",[]]Cb[\"{{{AIAj{BCDb}}CLjAJB`B@DnOHd}{{LF`{AJ@h}}}}\",[]]Cb[\"{{{AIAj{AODn}}CLlAJB`B@E`OHd}{{LF`{AJ@j}}}}\",[]]Cb[\"{{{AIAj{BCDd}}CLlAJB`B@E`OHd}{{LF`{AJ@j}}}}\",[]]B`[\"{{{AIAj{CBfAIMn}}OHd}HJ`}\",[]]Bo[\"{{{AIAj{CBfAIMh}}}{{LFj{{Nh{Mn}}BCBf}}}}\",[]]Bh[\"{{{AIAj{AIMl}}}{{LF`{{Nh{Mn}}}}}}\",[]]Bg[\"{{{AIAj{OJj}}}{{LF`{{Nh{Mn}}}}}}\",[]]Bh[\"{{{AIAj{AJBl}}}{{LF`{{Nh{Mn}}}}}}\",[]]Bg[\"{{{AIAj{OJl}}}{{LF`{{Nh{Mn}}}}}}\",[]]Bh[\"{{{AIAj{AJBn}}}{{LF`{{Nh{Mn}}}}}}\",[]]o[\"{AINhMh}\",[]]o[\"{AINjMh}\",[]]Ai[\"{{{AIAj{CHn}}}CMn}\",[]]Aj[\"{{{AIAj{AIN`}}}CId}\",[]]Ah[\"{{{AIAj{Nb}}}CId}\",[]]Bn[\"{{{AIAj{CBfAHEh}}CId}{{AIAj{CBfAHEh}}}}\",[]]Ai[\"{{{AIAj{JF`}}}CId}\",[]]Bn[\"{{{AIAj{CBfAOCd}}CId}{{AIAj{CBfAOCd}}}}\",[]]Ai[\"{{{AIAj{OI`}}}CId}\",[]]Bn[\"{{{AIAj{CBfBAGl}}CId}{{AIAj{CBfBAGl}}}}\",[]]Aj[\"{{{AIAj{AINb}}}CId}\",[]]Ah[\"{{{AIAj{Nd}}}CId}\",[]]Bn[\"{{{AIAj{CBfAHEj}}CId}{{AIAj{CBfAHEj}}}}\",[]]Ai[\"{{{AIAj{JFb}}}CId}\",[]]Bn[\"{{{AIAj{CBfAOCf}}CId}{{AIAj{CBfAOCf}}}}\",[]]Ai[\"{{{AIAj{OIb}}}CId}\",[]]Bn[\"{{{AIAj{CBfBAGn}}CId}{{AIAj{CBfBAGn}}}}\",[]]Aa[\"{AJ@nBFBd}\",[]]Ai[\"{{{AIAj{OJj}}}CMn}\",[]]Aj[\"{{{AIAj{AJBl}}}CMn}\",[]]Aj[\"{{{AIAj{AIMn}}}CMn}\",[]]Ai[\"{{{AIAj{OJl}}}CMn}\",[]]Aj[\"{{{AIAj{AJBn}}}CMn}\",[]]Co[\"{{{AIAj{OJj}}B@Dn{AIAj{{L@`{Mh}}}}{AIAj{{L@`{Mh}}}}}CMn}\",[]]D`[\"{{{AIAj{AJBl}}B@Dn{AIAj{{L@`{Mh}}}}{AIAj{{L@`{Mh}}}}}CMn}\",[]]Co[\"{{{AIAj{OJl}}B@E`{AIAj{{L@`{Mh}}}}{AIAj{{L@`{Mh}}}}}CMn}\",[]]D`[\"{{{AIAj{AJBn}}B@E`{AIAj{{L@`{Mh}}}}{AIAj{{L@`{Mh}}}}}CMn}\",[]]Bn[\"{{{AIAj{CBfBEJh}}CI`}{{AIAj{CBfBEJh}}}}\",[]]Bn[\"{{{AIAj{CBfBEJj}}CI`}{{AIAj{CBfBEJj}}}}\",[]]Cc[\"{{{AIAj{CBfOJj}}}{{LF`{{OHf{{Nh{AHHd}}}}}}}}\",[]]Cd[\"{{{AIAj{CBfAJBl}}}{{LF`{{OHf{{Nh{AHHd}}}}}}}}\",[]]Cc[\"{{{AIAj{CBfOJl}}}{{LF`{{OHh{{Nh{AHHf}}}}}}}}\",[]]Cd[\"{{{AIAj{CBfAJBn}}}{{LF`{{OHh{{Nh{AHHf}}}}}}}}\",[]]A`[\"{AINhCId}\",[]]A`[\"{AINjCId}\",[]]De[\"{{{AIAj{CBfBCE`}}c{AIAj{CHn}}}{{AIAj{CBfBCE`}}}{{JEd{CKj}}}}\",[\"\"]]De[\"{{{AIAj{CBfBCEb}}c{AIAj{CHn}}}{{AIAj{CBfBCEb}}}{{JEd{CKj}}}}\",[\"\"]]Ci[\"{{{AIAj{CBfOJj}}{AIAj{{L@`{Mh}}}}}{{LFj{CMnJGd}}}}\",[]]Cj[\"{{{AIAj{CBfAJBl}}{AIAj{{L@`{Mh}}}}}{{LFj{CMnJGd}}}}\",[]]Cj[\"{{{AIAj{CBfOJl}}{AIAj{{L@`{Mh}}}}}{{LFj{CMnBBGd}}}}\",[]]Ck[\"{{{AIAj{CBfAJBn}}{AIAj{{L@`{Mh}}}}}{{LFj{CMnBBGd}}}}\",[]]n[\"{OnCMn}\",[]]Bn[\"{{{AIAj{CBfBCE`}}LHf}{{AIAj{CBfBCE`}}}}\",[]]Bn[\"{{{AIAj{CBfBCEb}}LHh}{{AIAj{CBfBCEb}}}}\",[]]A`[\"{AHF`LF`}\",[]]Ca[\"{{{AIAj{CBfAJ@n}}}{{LFj{{LF`{LHf}}AJAb}}}}\",[]]Ca[\"{{{AIAj{CBfBFBd}}}{{LFj{{LF`{LHf}}AJAb}}}}\",[]]Ca[\"{{{AIAj{CBfAJA`}}}{{LFj{{LF`{LHh}}B@Dd}}}}\",[]]Ak[\"{{{AIAj{AIMh}}}AJB`}\",[]]Ak[\"{{{AIAj{AIMl}}}AJB`}\",[]]Ak[\"{{{AIAj{ABLf}}}AJB`}\",[]]Bg[\"{{{AIAj{CKl}}}{{LFj{AJB`AILn}}}}\",[]]Ak[\"{{{AIAj{ABLh}}}AJB`}\",[]]A`[\"{AINhCId}\",[]]A`[\"{AINjCId}\",[]]B`[\"{{LHfc}LHf{{CJn{LHf}}}}\",[\"\"]]B`[\"{{LFdc}LFd{{CJn{LFd}}}}\",[\"\"]]B`[\"{{LHhc}LHh{{CJn{LHh}}}}\",[\"\"]]B`[\"{{LFfc}LFf{{CJn{LFf}}}}\",[\"\"]]20Ae[\"{{ABKjCId}ADj}\",[]]Bn[\"{{{AIAj{CBfBCE`}}ADh}{{AIAj{CBfBCE`}}}}\",[]]Bn[\"{{{AIAj{CBfBCEb}}ADh}{{AIAj{CBfBCEb}}}}\",[]]A`[\"{JJbABKj}\",[]]B`[\"{{}{{AIAj{{L@`{BFAd}}}}}}\",[]]Ao[\"{{AIAj{A@Kn{CBfMh}}}HJ`}\",[]]000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000Am[\"{{}{{LF`{{N`{OJh}}}}}}\",[]]Bn[\"{{{AIAj{CBfBBCj}}CMn}{{AIAj{CBfBBCj}}}}\",[]]Bn[\"{{{AIAj{CBfBBCl}}CMn}{{AIAj{CBfBBCl}}}}\",[]]Aj[\"{{{AIAj{AHHd}}}CId}\",[]]Aj[\"{{{AIAj{AHHf}}}CId}\",[]]A`[\"{ABNhLF`}\",[]]A`[\"{AINhCId}\",[]]A`[\"{AINjCId}\",[]]10Bf[\"{{{AIAj{CHn}}}{{LFn{CIdBAH`}}}}\",[]]Bm[\"{{{AIAj{ABKn}}{Nh{BBBb}}}{{LFl{HJ`}}}}\",[]]Ai[\"{AIMj{{LFn{HJ`}}}}\",[]]Ci[\"{{{AIAj{OJf}}BBBdBAHj{AIAj{On}}}{{LBb{AJB`ABKl}}}}\",[]]Cb[\"{{{AIAj{CBfAIMn}}LFfAJ@f}{{LFj{AJ@fBELh}}}}\",[]]Am[\"{{{AIAj{AIMl}}CId}HJ`}\",[]]B`[\"{{{AIAj{CBfAIMn}}CId}HJ`}\",[]]A`[\"{BBFlCMn}\",[]]B`[\"{{{AIAj{CBfJJb}}BBFn}HJ`}\",[]]Aa[\"{AOFbAHGj}\",[]]Bm[\"{{{AIAj{OJh}}AHJ`}{{LFl{{Nh{BBBb}}}}}}\",[]]Bn[\"{{{AIAj{B@In}}AHJ`}{{LFl{{Nh{BBBb}}}}}}\",[]]Bn[\"{{{AIAj{AOEh}}AHJ`}{{LFl{{Nh{BBBb}}}}}}\",[]]Ci[\"{{{AIAj{CBfOJj}}{AIAj{CBf{A@l{Mh}}}}}{{LF`{CK`}}}}\",[]]Cj[\"{{{AIAj{CBfAJBl}}{AIAj{CBf{A@l{Mh}}}}}{{LF`{CK`}}}}\",[]]Ci[\"{{{AIAj{CBfOJl}}{AIAj{CBf{A@l{Mh}}}}}{{LF`{CKb}}}}\",[]]Cj[\"{{{AIAj{CBfAJBn}}{AIAj{CBf{A@l{Mh}}}}}{{LF`{CKb}}}}\",[]]Cb[\"{{{AIAj{ABOf}}HInAJBfABKj}{{LFj{HJ`BCDj}}}}\",[]]Cb[\"{{{AIAj{BADd}}HInAJBfABKj}{{LFj{HJ`BCDj}}}}\",[]]Cb[\"{{{AIAj{B@G`}}HInAJBfABKj}{{LFj{HJ`BCDj}}}}\",[]]Cb[\"{{{AIAj{ABOh}}HInAJBfABKj}{{LFj{HJ`BCDl}}}}\",[]]Cb[\"{{{AIAj{BADf}}HInAJBfABKj}{{LFj{HJ`BCDl}}}}\",[]]Cb[\"{{{AIAj{B@Gb}}HInAJBfABKj}{{LFj{HJ`BCDl}}}}\",[]]Al[\"{{}{{LFj{B@BnBFIb}}}}\",[]]Bm[\"{{{AIAj{AIMl}}LFd}{{LF`{{Nh{AIN`}}}}}}\",[]]Bo[\"{{{AIAj{AIMn}}LFf}{{LF`{{AIAj{AINb}}}}}}\",[]]A`[\"{AINhCId}\",[]]A`[\"{AINjCId}\",[]]Aj[\"{{{AIAj{AIMl}}}HJ`}\",[]]Am[\"{{{AIAj{CBfAIMn}}}HJ`}\",[]]Be[\"{{{AIAj{AILd}}}{{LFj{OnJGh}}}}\",[]]Bg[\"{{{AIAj{AILd}}}{{LFj{AHF`JGh}}}}\",[]]Bf[\"{{{AIAj{AILd}}}{{LFj{A@`JGh}}}}\",[]]Bf[\"{{{AIAj{AILd}}}{{LFj{A@bJGh}}}}\",[]]Be[\"{{{AIAj{AILd}}}{{LFj{NlJGh}}}}\",[]]Bg[\"{{{AIAj{AILd}}}{{LFj{ABJlJGh}}}}\",[]]Ak[\"{{{AIAj{BBGf}}}B@Fn}\",[]]Cf[\"{{{AIAj{CBfBCE`}}{LF`{AOCn}}}{{AIAj{CBfBCE`}}}}\",[]]Cf[\"{{{AIAj{CBfBCEb}}{LF`{AOD`}}}{{AIAj{CBfBCEb}}}}\",[]]<;Aj[\"{{{AIAj{ABKn}}}LBd}\",[]]Aj[\"{{{AIAj{ABL`}}}LBd}\",[]]Bc[\"{{{AIAj{AIMl}}AJB`AJ@d}ABMl}\",[]]Co[\"{{{AIAj{CBfAIMn}}AHFnAJ@fOHd}{{LFj{{LBb{LFfCMn}}AHHj}}}}\",[]]Bn[\"{{{AIAj{CBfBCE`}}CIb}{{AIAj{CBfBCE`}}}}\",[]]Bn[\"{{{AIAj{CBfBCEb}}CIb}{{AIAj{CBfBCEb}}}}\",[]]Ai[\"{AIMj{{LFn{HJ`}}}}\",[]]Bg[\"{{{AIAj{BBGf}}AJCd}{{LFl{LBd}}}}\",[]]A`[\"{AHF`CId}\",[]]10Ai[\"{{{AIAj{On}}}BCDn}\",[]]Ce[\"{{{AIAj{CBfB@I`}}{N`{BCE`}}}{{AIAj{CBfB@I`}}}}\",[]]Ce[\"{{{AIAj{CBfB@C`}}{N`{BCE`}}}{{AIAj{CBfB@C`}}}}\",[]]Ce[\"{{{AIAj{CBfB@Id}}{N`{BCEb}}}{{AIAj{CBfB@Id}}}}\",[]]Ce[\"{{{AIAj{CBfB@Cd}}{N`{BCEb}}}{{AIAj{CBfB@Cd}}}}\",[]]Aa[\"{B@I`BG@j}\",[]]Aa[\"{B@IdBG@l}\",[]]Bj[\"{{{A@l{BBBd}}BAHj}{{LFj{B@I`JGj}}}}\",[]]Bj[\"{{{A@l{BBBd}}BAHj}{{LFj{B@IdJGl}}}}\",[]]Co[\"{{{AIAj{CBfAJAj}}{AIAj{CBf{L@`{JEf}}}}}{{LFj{HJ`AJCf}}}}\",[]]A`[\"{AHIbCId}\",[]]A`[\"{AHIdCId}\",[]]A`[\"{BEDjCId}\",[]]A`[\"{BEDlCId}\",[]]Bc[\"{{{AIAj{AIMl}}}{{LF`{LBd}}}}\",[]]A`[\"{AINhCId}\",[]]A`[\"{AINjCId}\",[]]10Aj[\"{{{AIAj{AHFf}}}LBd}\",[]]Be[\"{{{AIAj{ABKn}}{LF`{B@I`}}}HJ`}\",[]]Bn[\"{{{AIAj{CBfABL`}}{LF`{{N`{B@Id}}}}}HJ`}\",[]]Bd[\"{{{AIAj{BFAd}}}{{LF`{BAHh}}}}\",[]]o[\"{{}AIAj}\",[]]n[\"{{}OG`}\",[]]0000Bn[\"{{{AIAj{CBfBCE`}}LBd}{{AIAj{CBfBCE`}}}}\",[]]Bn[\"{{{AIAj{CBfBCEb}}LBd}{{AIAj{CBfBCEb}}}}\",[]]o[\"{CIdLHf}\",[]]o[\"{CIdLHh}\",[]]A`[\"{BAEfCId}\",[]]Bo[\"{{{AIAj{CBfBBCj}}ABKj}{{AIAj{CBfBBCj}}}}\",[]]Bo[\"{{{AIAj{CBfBBCl}}ABKj}{{AIAj{CBfBBCl}}}}\",[]]Ae[\"{{LBdCId}BADd}\",[]]Ae[\"{{LBdCId}BADf}\",[]]A`[\"{AINhCId}\",[]]A`[\"{AINjCId}\",[]]6Bg[\"{{{AIAj{AIMn}}LFf}{{LF`{AJ@f}}}}\",[]]An[\"{{{AIAj{AIMl}}JEf}B@Hj}\",[]]Am[\"{{{AIAj{AIMl}}LHf}HJ`}\",[]]B`[\"{{{AIAj{CBfAIMn}}LHh}HJ`}\",[]]Ce[\"{{{AIAj{CBfBBCj}}{A@l{CIb}}}{{AIAj{CBfBBCj}}}}\",[]]Ce[\"{{{AIAj{CBfBBCl}}{A@l{CIb}}}{{AIAj{CBfBBCl}}}}\",[]]Fg[\"{{{AIAj{BGDh}}{AIAj{BBBd}}{AIAj{{L@`{BBBd}}}}{AIAj{AJAn}}{AIAj{{L@`{Mh}}}}AC@h}{{LFj{BELbJFn}}}}\",[]]Af[\"{{BCDbOHd}BCDb}\",[]]Af[\"{{BCDdOHd}BCDd}\",[]]?Al[\"{B@J`{{LFj{CLjJGf}}}}\",[]]Ak[\"{B@J`{{LFj{NnJGf}}}}\",[]]Am[\"{B@J`{{LFj{ABNlJGf}}}}\",[]]Ai[\"{B@J`{{LG`{CLl}}}}\",[]]Ah[\"{B@J`{{LG`{O`}}}}\",[]]Aj[\"{B@J`{{LG`{ABNn}}}}\",[]]o[\"{OG`OG`}\",[]]Bo[\"{{{AIAj{CBfBEJh}}ABKj}{{AIAj{CBfBEJh}}}}\",[]]Bo[\"{{{AIAj{CBfBEJj}}ABKj}{{AIAj{CBfBEJj}}}}\",[]]Bb[\"{{{AIAj{OJj}}}{{LF`{CMn}}}}\",[]]Bc[\"{{{AIAj{AJBl}}}{{LF`{CMn}}}}\",[]]Bb[\"{{{AIAj{OJl}}}{{LF`{CMn}}}}\",[]]Bc[\"{{{AIAj{AJBn}}}{{LF`{CMn}}}}\",[]]Bg[\"{{{AIAj{AIMl}}}{{LFj{HJ`BCBf}}}}\",[]]Cf[\"{{{AIAj{CBfBCE`}}{LF`{ABKj}}}{{AIAj{CBfBCE`}}}}\",[]]Cf[\"{{{AIAj{CBfBCEb}}{LF`{ABKj}}}{{AIAj{CBfBCEb}}}}\",[]]A`[\"{AHIbCId}\",[]]A`[\"{AHIdCId}\",[]]Bl[\"{{{AIAj{CBfAIN`}}OHdOHdCMnCMnCId}HJ`}\",[]]Bj[\"{{{AIAj{CBfNb}}OHdOHdCMnCMnCId}HJ`}\",[]]Bk[\"{{{AIAj{CBfJF`}}OHdOHdCMnCMnCId}HJ`}\",[]]Bk[\"{{{AIAj{CBfOI`}}OHdOHdCMnCMnCId}HJ`}\",[]]Bl[\"{{{AIAj{CBfAINb}}OHdOHdCMnCMnCId}HJ`}\",[]]Bj[\"{{{AIAj{CBfNd}}OHdOHdCMnCMnCId}HJ`}\",[]]Bk[\"{{{AIAj{CBfJFb}}OHdOHdCMnCMnCId}HJ`}\",[]]Bk[\"{{{AIAj{CBfOIb}}OHdOHdCMnCMnCId}HJ`}\",[]]A`[\"{BAEfCId}\",[]]Ak[\"{{{AIAj{OKh}}O`}CId}\",[]]Bi[\"{{{AIAj{CBfAJAh}}CId}{{LFn{HJ`}}}}\",[]]<;A`[\"{AINhCId}\",[]]A`[\"{AINjCId}\",[]]10Cf[\"{{{AIAj{CBfBCE`}}{LF`{BEHj}}}{{AIAj{CBfBCE`}}}}\",[]]Cf[\"{{{AIAj{CBfBCEb}}{LF`{BEHl}}}{{AIAj{CBfBCEb}}}}\",[]]A`[\"{AHIbCId}\",[]]A`[\"{AHIdCId}\",[]]Bh[\"{{{AIAj{CBfAILd}}}{{LFj{OnJGh}}}}\",[]]Bj[\"{{{AIAj{CBfAILd}}}{{LFj{AHF`JGh}}}}\",[]]Bi[\"{{{AIAj{CBfAILd}}}{{LFj{A@`JGh}}}}\",[]]Bi[\"{{{AIAj{CBfAILd}}}{{LFj{A@bJGh}}}}\",[]]Bh[\"{{{AIAj{CBfAILd}}}{{LFj{NlJGh}}}}\",[]]Bj[\"{{{AIAj{CBfAILd}}}{{LFj{ABJlJGh}}}}\",[]]Cc[\"{{{N`{AIMj}}CIdCMn}{{LFn{{LBb{BBFnBBFn}}}}}}\",[]]Bn[\"{{{AIAj{CBfB@I`}}CId}{{AIAj{CBfB@I`}}}}\",[]]Bn[\"{{{AIAj{CBfB@Id}}CId}{{AIAj{CBfB@Id}}}}\",[]]Aj[\"{{{AIAj{AIMl}}}CMn}\",[]]Ak[\"{{{AIAj{BBBb}}}B@Fn}\",[]]0Ci[\"{{{AIAj{CBfBBCj}}CI`}{{LFj{{AIAj{CBfBBCj}}AOBj}}}}\",[]]Ci[\"{{{AIAj{CBfBBCl}}CI`}{{LFj{{AIAj{CBfBBCl}}AOBl}}}}\",[]]A`[\"{AHF`CI`}\",[]]Cf[\"{{{AIAj{CBfBCE`}}{LF`{BEJh}}}{{AIAj{CBfBCE`}}}}\",[]]Cf[\"{{{AIAj{CBfBCEb}}{LF`{BEJj}}}{{AIAj{CBfBCEb}}}}\",[]]Bg[\"{{{AIAj{CBfAIMn}}}{{LF`{BAEd}}}}\",[]]Cf[\"{{{AIAj{CBfB@I`}}{LF`{B@Ih}}}{{AIAj{CBfB@I`}}}}\",[]]Cf[\"{{{AIAj{CBfB@Id}}{LF`{B@Ih}}}{{AIAj{CBfB@Id}}}}\",[]]Cf[\"{{{AIAj{CBfB@I`}}{LF`{B@Ij}}}{{AIAj{CBfB@I`}}}}\",[]]Cf[\"{{{AIAj{CBfB@Id}}{LF`{B@Ij}}}{{AIAj{CBfB@Id}}}}\",[]]Cc[\"{{}{{LFj{{LBb{{A@l{BBBd}}BAHj}}{Nh{JFl}}}}}}\",[]]Bn[\"{{{AIAj{CBfBEHj}}LHf}{{AIAj{CBfBEHj}}}}\",[]]Bn[\"{{{AIAj{CBfBEHl}}LHh}{{AIAj{CBfBEHl}}}}\",[]]A`[\"{AINhCId}\",[]]A`[\"{AINjCId}\",[]]Bo[\"{{{AIAj{CBfB@I`}}ABKj}{{AIAj{CBfB@I`}}}}\",[]]Bo[\"{{{AIAj{CBfB@Id}}ABKj}{{AIAj{CBfB@Id}}}}\",[]]Ci[\"{{{AIAj{CKl}}{LF`{ABKj}}}{{LFj{{LF`{ABKj}}AILn}}}}\",[]]Bj[\"{{{AIAj{BBGf}}AJCdLBd}{{LFl{HJ`}}}}\",[]]054Bm[\"{{{AIAj{OJj}}}{{LFj{{LF`{BFBb}}JGd}}}}\",[]]Bn[\"{{{AIAj{AJBl}}}{{LFj{{LF`{BFBb}}JGd}}}}\",[]]Bn[\"{{{AIAj{OJl}}}{{LFj{{LF`{BFBb}}BBGd}}}}\",[]]Bo[\"{{{AIAj{AJBn}}}{{LFj{{LF`{BFBb}}BBGd}}}}\",[]]Aj[\"{{{AIAj{AHHd}}}CId}\",[]]Aj[\"{{{AIAj{AHHf}}}CId}\",[]]Aj[\"{{{AIAj{ABL`}}}CId}\",[]]Bf[\"{{{AIAj{AHFn}}{AIAj{AHFn}}}CMn}\",[]]Am[\"{{{AIAj{CBfAIMn}}}HJ`}\",[]]Bn[\"{{{AIAj{CBfBAGl}}ADh}{{AIAj{CBfBAGl}}}}\",[]]Bn[\"{{{AIAj{CBfBAGn}}ADh}{{AIAj{CBfBAGn}}}}\",[]]Ak[\"{{{AIAj{AHIn}}}B@Fn}\",[]]0Bd[\"{{{AIAj{AIMl}}}{{ABNd{JHf}}}}\",[]]Cb[\"{{{AIAj{AIMn}}LFf}{{LFj{{LF`{AJB`}}AIMd}}}}\",[]]A`[\"{AINhCId}\",[]]A`[\"{AINjCId}\",[]]Bn[\"{{{AIAj{CBfBCE`}}LHf}{{AIAj{CBfBCE`}}}}\",[]]Bn[\"{{{AIAj{CBfBCEb}}LHh}{{AIAj{CBfBCEb}}}}\",[]]A`[\"{AHF`LF`}\",[]]Bo[\"{{{AIAj{AHF`}}{AIAj{CHn}}}{{LFl{BCDn}}}}\",[]]Em[\"{{{AIAj{AIMl}}{AIAj{CBf{L@`{Mh}}}}{AIAj{{L@`{Mh}}}}{AIAj{{L@`{Mh}}}}}{{LFj{HJ`BGKl}}}}\",[]]El[\"{{{AIAj{OJj}}{AIAj{CBf{L@`{Mh}}}}{AIAj{{L@`{Mh}}}}{AIAj{{L@`{Mh}}}}}{{LFj{HJ`BGKl}}}}\",[]]Em[\"{{{AIAj{AJBl}}{AIAj{CBf{L@`{Mh}}}}{AIAj{{L@`{Mh}}}}{AIAj{{L@`{Mh}}}}}{{LFj{HJ`BGKl}}}}\",[]]El[\"{{{AIAj{OJl}}{AIAj{CBf{L@`{Mh}}}}{AIAj{{L@`{Mh}}}}{AIAj{{L@`{Mh}}}}}{{LFj{HJ`BGKn}}}}\",[]]Em[\"{{{AIAj{AJBn}}{AIAj{CBf{L@`{Mh}}}}{AIAj{{L@`{Mh}}}}{AIAj{{L@`{Mh}}}}}{{LFj{HJ`BGKn}}}}\",[]]Am[\"{{{AIAj{CBfAHFd}}}HJ`}\",[]]0Al[\"{{{AIAj{AIMn}}O`}CId}\",[]]Bl[\"{{{AIAj{AIMl}}}{{ABNf{{LF`{AJB`}}}}}}\",[]]Bg[\"{{{AIAj{CKl}}}{{LFj{BDIdAILn}}}}\",[]]>=E`[\"{{{AIAj{BGDh}}{AIAj{{L@`{Mh}}}}{AIAj{BBBd}}{AIAj{BFOl}}}{{LFj{BGFnJFn}}}}\",[]]0Bf[\"{{{N`{BAIb}}}{{LFj{B@C`BFIl}}}}\",[]]Bf[\"{{{N`{BAIb}}}{{LFj{B@CdBFIl}}}}\",[]]Bn[\"{{{AIAj{CBfBEHj}}LHf}{{AIAj{CBfBEHj}}}}\",[]]Bn[\"{{{AIAj{CBfBEHl}}LHh}{{AIAj{CBfBEHl}}}}\",[]]o[\"{OG`OG`}\",[]]0000Aj[\"{{{AIAj{AIMn}}}CMn}\",[]]0Ci[\"{{{AIAj{CKl}}{LF`{ABKj}}}{{LFj{{LF`{ABKj}}AILn}}}}\",[]]Cc[\"{{{AIAj{CBfOn}}{AIAj{AILd}}}{{LFj{HJ`JGh}}}}\",[]]Ce[\"{{{AIAj{CBfAHF`}}{AIAj{AILd}}}{{LFj{HJ`JGh}}}}\",[]]Cd[\"{{{AIAj{CBfA@`}}{AIAj{AILd}}}{{LFj{HJ`JGh}}}}\",[]]Cd[\"{{{AIAj{CBfA@b}}{AIAj{AILd}}}{{LFj{HJ`JGh}}}}\",[]]Cc[\"{{{AIAj{CBfNl}}{AIAj{AILd}}}{{LFj{HJ`JGh}}}}\",[]]Ce[\"{{{AIAj{CBfABJl}}{AIAj{AILd}}}{{LFj{HJ`JGh}}}}\",[]]Bo[\"{{{AIAj{CBfB@I`}}BG@j}{{AIAj{CBfB@I`}}}}\",[]]Bo[\"{{{AIAj{CBfB@Id}}BG@l}{{AIAj{CBfB@Id}}}}\",[]]Aj[\"{{{AIAj{BBCj}}}CId}\",[]]Aj[\"{{{AIAj{BBCl}}}CId}\",[]]Cc[\"{{{AIAj{CBfB@C`}}{N`{A`}}}{{AIAj{CBfB@C`}}}}\",[]]Cc[\"{{{AIAj{CBfB@Cd}}{N`{A`}}}{{AIAj{CBfB@Cd}}}}\",[]]Cj[\"{{BBCj{LF`{B@I`}}{Nh{BBBb}}{N`{OJh}}}{{LFl{ABKn}}}}\",[]]Aj[\"{{{AIAj{ABLf}}}CMn}\",[]]Aj[\"{{{AIAj{ABLh}}}CMn}\",[]]Ca[\"{{{AIAj{CBfAIMn}}OHdAIOj}{{LFj{HJ`BGD`}}}}\",[]]Bd[\"{{{AIAj{BGDh}}}{{A@l{BCDf}}}}\",[]]Bj[\"{{{AIAj{AIMl}}AJB`}{{LFj{HJ`JH`}}}}\",[]]Bm[\"{{{AIAj{CBfAIMn}}AJB`}{{LFj{HJ`JH`}}}}\",[]]Bn[\"{{{AIAj{CBfBCE`}}LBd}{{AIAj{CBfBCE`}}}}\",[]]Bn[\"{{{AIAj{CBfBCEb}}LBd}{{AIAj{CBfBCEb}}}}\",[]]Bl[\"{{}{{LFj{{LBb{BBBdBEKd}}{Nh{JFl}}}}}}\",[]]Ai[\"{AIMj{{LFn{HJ`}}}}\",[]]A`[\"{AINhCId}\",[]]A`[\"{AINjCId}\",[]]An[\"{{{AIAj{ABKn}}B@C`}HJ`}\",[]]D`[\"{{{AIAj{CBfAIMn}}LFf{LF`{ABKj}}}{{LFj{{LF`{ABKj}}AIMd}}}}\",[]]o[\"{{}AIAj}\",[]]Aj[\"{{{AIAj{AIMl}}}LBd}\",[]]Bn[\"{{{AIAj{CBfB@I`}}CId}{{AIAj{CBfB@I`}}}}\",[]]Bn[\"{{{AIAj{CBfB@Id}}CId}{{AIAj{CBfB@Id}}}}\",[]]Bn[\"{{{AIAj{CBfBCE`}}LHf}{{AIAj{CBfBCE`}}}}\",[]]Bn[\"{{{AIAj{CBfBCEb}}LHh}{{AIAj{CBfBCEb}}}}\",[]]:Bb[\"{{{AIAj{CBfAIMn}}O`LHh}HJ`}\",[]]Ak[\"{{}{{LFj{B@C`JGj}}}}\",[]]Ak[\"{{}{{LFj{B@CdJGl}}}}\",[]]Bn[\"{{{AIAj{CBfBCE`}}CMn}{{AIAj{CBfBCE`}}}}\",[]]Bn[\"{{{AIAj{CBfBCEb}}CMn}{{AIAj{CBfBCEb}}}}\",[]]65Cf[\"{{{AIAj{CBfOn}}{AIAj{CBfAILd}}}{{LFj{HJ`JGh}}}}\",[]]Ch[\"{{{AIAj{CBfAHF`}}{AIAj{CBfAILd}}}{{LFj{HJ`JGh}}}}\",[]]Cg[\"{{{AIAj{CBfA@`}}{AIAj{CBfAILd}}}{{LFj{HJ`JGh}}}}\",[]]Cg[\"{{{AIAj{CBfA@b}}{AIAj{CBfAILd}}}{{LFj{HJ`JGh}}}}\",[]]Cf[\"{{{AIAj{CBfNl}}{AIAj{CBfAILd}}}{{LFj{HJ`JGh}}}}\",[]]Ch[\"{{{AIAj{CBfABJl}}{AIAj{CBfAILd}}}{{LFj{HJ`JGh}}}}\",[]]Bi[\"{{{AIAj{CBfAHFn}}{AIAj{AHFn}}}CMn}\",[]]n[\"{{}HJ`}\",[]]Ce[\"{{{AIAj{CBfBCE`}}{LF`{LBd}}}{{AIAj{CBfBCE`}}}}\",[]]Ce[\"{{{AIAj{CBfBCEb}}{LF`{LBd}}}{{AIAj{CBfBCEb}}}}\",[]]Bn[\"{{{AIAj{AIMl}}}{{LFj{{A@l{AJB`}}JH`}}}}\",[]]Cd[\"{{{AIAj{CBfAIMn}}OHd}{{LFj{{A@l{AJB`}}JH`}}}}\",[]]Am[\"{{{AIAj{CBfAIN`}}}HJ`}\",[]]Al[\"{{{AIAj{CBfJF`}}}HJ`}\",[]]Am[\"{{{AIAj{CBfAINb}}}HJ`}\",[]]Al[\"{{{AIAj{CBfJFb}}}HJ`}\",[]]Ai[\"{AIMj{{LFn{HJ`}}}}\",[]]Bj[\"{{{AIAj{AIMl}}AJB`}{{LFj{HJ`JH`}}}}\",[]]Bm[\"{{{AIAj{CBfAIMn}}AJB`}{{LFj{HJ`JH`}}}}\",[]]D`[\"{{{AIAj{CBfAIMn}}LFf{LF`{ABKj}}}{{LFj{{LF`{ABKj}}AIMd}}}}\",[]]Ce[\"{{{AIAj{CBfBCE`}}{N`{BEDf}}}{{AIAj{CBfBCE`}}}}\",[]]Ce[\"{{{AIAj{CBfBCEb}}{N`{BEDh}}}{{AIAj{CBfBCEb}}}}\",[]]Cf[\"{{{AIAj{CBfBCE`}}{LF`{ABKj}}}{{AIAj{CBfBCE`}}}}\",[]]Cf[\"{{{AIAj{CBfBCEb}}{LF`{ABKj}}}{{AIAj{CBfBCEb}}}}\",[]]Aa[\"{BAEjAIOh}\",[]]Aa[\"{BAElAIOh}\",[]]9Bn[\"{{{AIAj{CBfBCE`}}CMn}{{AIAj{CBfBCE`}}}}\",[]]Bn[\"{{{AIAj{CBfBCEb}}CMn}{{AIAj{CBfBCEb}}}}\",[]]Am[\"{{{AIAj{AIMl}}LHf}HJ`}\",[]]o[\"{OG`OG`}\",[]]Bn[\"{{{AIAj{CBfBCE`}}CIb}{{AIAj{CBfBCE`}}}}\",[]]Bn[\"{{{AIAj{CBfBCEb}}CIb}{{AIAj{CBfBCEb}}}}\",[]]3109854Bn[\"{{{AIAj{AIMl}}}{{LFj{{A@l{AJB`}}JH`}}}}\",[]]Bn[\"{{{AIAj{AIMn}}}{{LFj{{A@l{AJB`}}JH`}}}}\",[]]10A`[\"{BFBbLF`}\",[]]Bm[\"{{{AIAj{CBfBCE`}}Mh}{{AIAj{CBfBCE`}}}}\",[]]Bm[\"{{{AIAj{CBfBCEb}}Mh}{{AIAj{CBfBCEb}}}}\",[]]o[\"{{}AIOj}\",[]]") \ No newline at end of file +rd_("Bf[\"{{{AIAj{AOBd}}{AIAj{AOBd}}}CMn}\",[]]Bf[\"{{{AIAj{BEEj}}{AIAj{BEEj}}}CMn}\",[]]Bf[\"{{{AIAj{BBFj}}{AIAj{BBFj}}}CMn}\",[]]Bf[\"{{{AIAj{AHIh}}{AIAj{AHIh}}}CMn}\",[]]Bf[\"{{{AIAj{AJAb}}{AIAj{AJAb}}}CMn}\",[]]Bf[\"{{{AIAj{BBFh}}{AIAj{BBFh}}}CMn}\",[]]Bf[\"{{{AIAj{AJCf}}{AIAj{AJCf}}}CMn}\",[]]Bf[\"{{{AIAj{B@Il}}{AIAj{B@Il}}}CMn}\",[]]Bd[\"{{{AIAj{LHf}}{AIAj{LHf}}}CMn}\",[]]Bf[\"{{{AIAj{BFIh}}{AIAj{BFIh}}}CMn}\",[]]Bd[\"{{{AIAj{JEh}}{AIAj{JEh}}}CMn}\",[]]Bd[\"{{{AIAj{LFd}}{AIAj{LFd}}}CMn}\",[]]Bf[\"{{{AIAj{AC@d}}{AIAj{AC@d}}}CMn}\",[]]Bf[\"{{{AIAj{AHIb}}{AIAj{AHIb}}}CMn}\",[]]Bd[\"{{{AIAj{OLd}}{AIAj{OLd}}}CMn}\",[]]Bf[\"{{{AIAj{B@Cl}}{AIAj{B@Cl}}}CMn}\",[]]Bf[\"{{{AIAj{BCBf}}{AIAj{BCBf}}}CMn}\",[]]Bf[\"{{{AIAj{AOCn}}{AIAj{AOCn}}}CMn}\",[]]Bf[\"{{{AIAj{AOBj}}{AIAj{AOBj}}}CMn}\",[]]Bf[\"{{{AIAj{AHG`}}{AIAj{AHG`}}}CMn}\",[]]Bf[\"{{{AIAj{BCB`}}{AIAj{BCB`}}}CMn}\",[]]Bf[\"{{{AIAj{BDIh}}{AIAj{BDIh}}}CMn}\",[]]Bf[\"{{{AIAj{B@Dh}}{AIAj{B@Dh}}}CMn}\",[]]Bf[\"{{{AIAj{B@Dn}}{AIAj{B@Dn}}}CMn}\",[]]Bf[\"{{{AIAj{B@Eh}}{AIAj{B@Eh}}}CMn}\",[]]Bf[\"{{{AIAj{BELn}}{AIAj{BELn}}}CMn}\",[]]Bd[\"{{{AIAj{CLj}}{AIAj{CLj}}}CMn}\",[]]Bb[\"{{{AIAj{Nn}}{AIAj{Nn}}}CMn}\",[]]Bf[\"{{{AIAj{ABNl}}{AIAj{ABNl}}}CMn}\",[]]Bf[\"{{{AIAj{BGKl}}{AIAj{BGKl}}}CMn}\",[]]Bd[\"{{{AIAj{JGj}}{AIAj{JGj}}}CMn}\",[]]Bd[\"{{{AIAj{LHh}}{AIAj{LHh}}}CMn}\",[]]Bf[\"{{{AIAj{BFIj}}{AIAj{BFIj}}}CMn}\",[]]Bd[\"{{{AIAj{JEj}}{AIAj{JEj}}}CMn}\",[]]Bf[\"{{{AIAj{BEEl}}{AIAj{BEEl}}}CMn}\",[]]Bd[\"{{{AIAj{LFf}}{AIAj{LFf}}}CMn}\",[]]Bf[\"{{{AIAj{AJ@f}}{AIAj{AJ@f}}}CMn}\",[]]Bf[\"{{{AIAj{AHI`}}{AIAj{AHI`}}}CMn}\",[]]Bf[\"{{{AIAj{BELh}}{AIAj{BELh}}}CMn}\",[]]Bf[\"{{{AIAj{AIMd}}{AIAj{AIMd}}}CMn}\",[]]Bf[\"{{{AIAj{AC@f}}{AIAj{AC@f}}}CMn}\",[]]Bf[\"{{{AIAj{AHId}}{AIAj{AHId}}}CMn}\",[]]Bf[\"{{{AIAj{AHIj}}{AIAj{AHIj}}}CMn}\",[]]Bf[\"{{{AIAj{BAHl}}{AIAj{BAHl}}}CMn}\",[]]Bd[\"{{{AIAj{OLf}}{AIAj{OLf}}}CMn}\",[]]Bf[\"{{{AIAj{AJCh}}{AIAj{AJCh}}}CMn}\",[]]Bf[\"{{{AIAj{AOCl}}{AIAj{AOCl}}}CMn}\",[]]Bf[\"{{{AIAj{AOF`}}{AIAj{AOF`}}}CMn}\",[]]Bf[\"{{{AIAj{BBFl}}{AIAj{BBFl}}}CMn}\",[]]Bf[\"{{{AIAj{B@Dd}}{AIAj{B@Dd}}}CMn}\",[]]Bf[\"{{{AIAj{BCBh}}{AIAj{BCBh}}}CMn}\",[]]Bf[\"{{{AIAj{AHHj}}{AIAj{AHHj}}}CMn}\",[]]Bf[\"{{{AIAj{BBBh}}{AIAj{BBBh}}}CMn}\",[]]Bf[\"{{{AIAj{AOD`}}{AIAj{AOD`}}}CMn}\",[]]Bf[\"{{{AIAj{AOBl}}{AIAj{AOBl}}}CMn}\",[]]Bf[\"{{{AIAj{AHGb}}{AIAj{AHGb}}}CMn}\",[]]Bf[\"{{{AIAj{BBDf}}{AIAj{BBDf}}}CMn}\",[]]Bf[\"{{{AIAj{AIOf}}{AIAj{AIOf}}}CMn}\",[]]Bf[\"{{{AIAj{AJBb}}{AIAj{AJBb}}}CMn}\",[]]Bf[\"{{{AIAj{B@Eb}}{AIAj{B@Eb}}}CMn}\",[]]Bf[\"{{{AIAj{BCBd}}{AIAj{BCBd}}}CMn}\",[]]Bf[\"{{{AIAj{BDIl}}{AIAj{BDIl}}}CMn}\",[]]Bf[\"{{{AIAj{BDJd}}{AIAj{BDJd}}}CMn}\",[]]Bf[\"{{{AIAj{B@Dj}}{AIAj{B@Dj}}}CMn}\",[]]Bf[\"{{{AIAj{ABLl}}{AIAj{ABLl}}}CMn}\",[]]Bf[\"{{{AIAj{BEEh}}{AIAj{BEEh}}}CMn}\",[]]Bf[\"{{{AIAj{B@E`}}{AIAj{B@E`}}}CMn}\",[]]Bf[\"{{{AIAj{B@Ej}}{AIAj{B@Ej}}}CMn}\",[]]Bf[\"{{{AIAj{BBGd}}{AIAj{BBGd}}}CMn}\",[]]Bf[\"{{{AIAj{BEM`}}{AIAj{BEM`}}}CMn}\",[]]Bd[\"{{{AIAj{CLl}}{AIAj{CLl}}}CMn}\",[]]Bb[\"{{{AIAj{O`}}{AIAj{O`}}}CMn}\",[]]Bf[\"{{{AIAj{ABNn}}{AIAj{ABNn}}}CMn}\",[]]Bf[\"{{{AIAj{AHFn}}{AIAj{AHFn}}}CMn}\",[]]Bf[\"{{{AIAj{BAIh}}{AIAj{BAIh}}}CMn}\",[]]Bf[\"{{{AIAj{BFBb}}{AIAj{BFBb}}}CMn}\",[]]Bd[\"{{{AIAj{JGn}}{AIAj{JGn}}}CMn}\",[]]Bf[\"{{{AIAj{BGKn}}{AIAj{BGKn}}}CMn}\",[]]Bd[\"{{{AIAj{JGl}}{AIAj{JGl}}}CMn}\",[]]Bf[\"{{{AIAj{B@El}}{AIAj{B@El}}}CMn}\",[]]Ai[\"{{{AIAj{CKl}}}LFd}\",[]]Ak[\"{{{AIAj{AJ@n}}}ABNl}\",[]]Ak[\"{{{AIAj{BFBd}}}ABNl}\",[]]Ak[\"{{{AIAj{AJAj}}}ABNl}\",[]]o[\"{LEhLFf}\",[]]o[\"{LDdLFf}\",[]]A`[\"{AHDfLFf}\",[]]A`[\"{BAFjLFf}\",[]]A`[\"{B@HbLFf}\",[]]A`[\"{B@GdLFf}\",[]]Aa[\"{ABN`ABNn}\",[]]Aa[\"{AC@jABNn}\",[]]Aa[\"{ABLbABNn}\",[]]A`[\"{OJnABNn}\",[]]n[\"{{}OJf}\",[]]A`[\"{CKdABLl}\",[]]Be[\"{{{AIAj{LHf}}{AIAj{LHf}}}ABMn}\",[]]Be[\"{{{AIAj{LFd}}{AIAj{LFd}}}ABMn}\",[]]Bg[\"{{{AIAj{AOCn}}{AIAj{AOCn}}}ABMn}\",[]]Bg[\"{{{AIAj{B@Dn}}{AIAj{B@Dn}}}ABMn}\",[]]Be[\"{{{AIAj{CLj}}{AIAj{CLj}}}ABMn}\",[]]Bc[\"{{{AIAj{Nn}}{AIAj{Nn}}}ABMn}\",[]]Bg[\"{{{AIAj{ABNl}}{AIAj{ABNl}}}ABMn}\",[]]Be[\"{{{AIAj{LHh}}{AIAj{LHh}}}ABMn}\",[]]Bg[\"{{{AIAj{BEEl}}{AIAj{BEEl}}}ABMn}\",[]]Be[\"{{{AIAj{LFf}}{AIAj{LFf}}}ABMn}\",[]]Bg[\"{{{AIAj{AHIj}}{AIAj{AHIj}}}ABMn}\",[]]Bg[\"{{{AIAj{BAHl}}{AIAj{BAHl}}}ABMn}\",[]]Bg[\"{{{AIAj{AJCh}}{AIAj{AJCh}}}ABMn}\",[]]Bg[\"{{{AIAj{AOD`}}{AIAj{AOD`}}}ABMn}\",[]]Bg[\"{{{AIAj{BDJd}}{AIAj{BDJd}}}ABMn}\",[]]Bg[\"{{{AIAj{BEEh}}{AIAj{BEEh}}}ABMn}\",[]]Bg[\"{{{AIAj{B@E`}}{AIAj{B@E`}}}ABMn}\",[]]Be[\"{{{AIAj{CLl}}{AIAj{CLl}}}ABMn}\",[]]Bc[\"{{{AIAj{O`}}{AIAj{O`}}}ABMn}\",[]]Bg[\"{{{AIAj{ABNn}}{AIAj{ABNn}}}ABMn}\",[]]o[\"{ABNlNn}\",[]]o[\"{ABNnO`}\",[]]n[\"{LEjO`}\",[]]o[\"{AHEbO`}\",[]]A`[\"{ABOnLF`}\",[]]A`[\"{AC@`LF`}\",[]]A`[\"{ABNhLF`}\",[]]A`[\"{AC@bLF`}\",[]]Bg[\"{{{AIAj{On}}{AIAj{CBfAHFl}}}LFh}\",[]]Bi[\"{{{AIAj{AOBd}}{AIAj{CBfAHFl}}}LFh}\",[]]Bi[\"{{{AIAj{BBFn}}{AIAj{CBfAHFl}}}LFh}\",[]]Bi[\"{{{AIAj{BGDh}}{AIAj{CBfAHFl}}}LFh}\",[]]Bi[\"{{{AIAj{AIMh}}{AIAj{CBfAHFl}}}LFh}\",[]]Bi[\"{{{AIAj{AIMl}}{AIAj{CBfAHFl}}}LFh}\",[]]Bi[\"{{{AIAj{BFIn}}{AIAj{CBfAHFl}}}LFh}\",[]]Bi[\"{{{AIAj{BEEj}}{AIAj{CBfAHFl}}}LFh}\",[]]0Bi[\"{{{AIAj{ABKn}}{AIAj{CBfAHFl}}}LFh}\",[]]Bi[\"{{{AIAj{BAEf}}{AIAj{CBfAHFl}}}LFh}\",[]]Bi[\"{{{AIAj{ABLf}}{AIAj{CBfAHFl}}}LFh}\",[]]Bi[\"{{{AIAj{AJAd}}{AIAj{CBfAHFl}}}LFh}\",[]]0Bi[\"{{{AIAj{BBDd}}{AIAj{CBfAHFl}}}LFh}\",[]]Bh[\"{{{AIAj{CKl}}{AIAj{CBfAHFl}}}LFh}\",[]]Bi[\"{{{AIAj{AJ@n}}{AIAj{CBfAHFl}}}LFh}\",[]]Bi[\"{{{AIAj{BFBd}}{AIAj{CBfAHFl}}}LFh}\",[]]Bi[\"{{{AIAj{BBFj}}{AIAj{CBfAHFl}}}LFh}\",[]]0Bi[\"{{{AIAj{AHIh}}{AIAj{CBfAHFl}}}LFh}\",[]]0Bi[\"{{{AIAj{AJAb}}{AIAj{CBfAHFl}}}LFh}\",[]]0Bi[\"{{{AIAj{BBFh}}{AIAj{CBfAHFl}}}LFh}\",[]]0Bi[\"{{{AIAj{B@In}}{AIAj{CBfAHFl}}}LFh}\",[]]Bi[\"{{{AIAj{AOEh}}{AIAj{CBfAHFl}}}LFh}\",[]]Bi[\"{{{AIAj{AJAj}}{AIAj{CBfAHFl}}}LFh}\",[]]Bi[\"{{{AIAj{AJCf}}{AIAj{CBfAHFl}}}LFh}\",[]]0Bi[\"{{{AIAj{B@Il}}{AIAj{CBfAHFl}}}LFh}\",[]]0Cd[\"{{{AIAj{LHf}}{AIAj{CBfAHFl}}}{{LFj{HJ`JFj}}}}\",[]]0Ce[\"{{{AIAj{BFIh}}{AIAj{CBfAHFl}}}{{LFj{HJ`JFj}}}}\",[]]0Cd[\"{{{AIAj{JEh}}{AIAj{CBfAHFl}}}{{LFj{HJ`JFj}}}}\",[]]Cd[\"{{{AIAj{LFd}}{AIAj{CBfAHFl}}}{{LFj{HJ`JFj}}}}\",[]]0Ce[\"{{{AIAj{AC@d}}{AIAj{CBfAHFl}}}{{LFj{HJ`JFj}}}}\",[]]Ce[\"{{{AIAj{AINh}}{AIAj{CBfAHFl}}}{{LFj{HJ`JFj}}}}\",[]]Ce[\"{{{AIAj{AHIb}}{AIAj{CBfAHFl}}}{{LFj{HJ`JFj}}}}\",[]]Ce[\"{{{AIAj{BCBn}}{AIAj{CBfAHFl}}}{{LFj{HJ`JFj}}}}\",[]]Cd[\"{{{AIAj{OLd}}{AIAj{CBfAHFl}}}{{LFj{HJ`JFj}}}}\",[]]Ce[\"{{{AIAj{B@Cl}}{AIAj{CBfAHFl}}}{{LFj{HJ`JFj}}}}\",[]]0Ce[\"{{{AIAj{BCBf}}{AIAj{CBfAHFl}}}{{LFj{HJ`JFj}}}}\",[]]0Ce[\"{{{AIAj{BCDb}}{AIAj{CBfAHFl}}}{{LFj{HJ`JFj}}}}\",[]]Ce[\"{{{AIAj{BCE`}}{AIAj{CBfAHFl}}}{{LFj{HJ`JFj}}}}\",[]]Ce[\"{{{AIAj{BEHj}}{AIAj{CBfAHFl}}}{{LFj{HJ`JFj}}}}\",[]]Ce[\"{{{AIAj{BEJh}}{AIAj{CBfAHFl}}}{{LFj{HJ`JFj}}}}\",[]]Ce[\"{{{AIAj{AOCn}}{AIAj{CBfAHFl}}}{{LFj{HJ`JFj}}}}\",[]]Ce[\"{{{AIAj{BBCj}}{AIAj{CBfAHFl}}}{{LFj{HJ`JFj}}}}\",[]]Ce[\"{{{AIAj{B@I`}}{AIAj{CBfAHFl}}}{{LFj{HJ`JFj}}}}\",[]]Ce[\"{{{AIAj{BG@j}}{AIAj{CBfAHFl}}}{{LFj{HJ`JFj}}}}\",[]]Ce[\"{{{AIAj{B@C`}}{AIAj{CBfAHFl}}}{{LFj{HJ`JFj}}}}\",[]]Ce[\"{{{AIAj{AOBj}}{AIAj{CBfAHFl}}}{{LFj{HJ`JFj}}}}\",[]]0Ce[\"{{{AIAj{AHG`}}{AIAj{CBfAHFl}}}{{LFj{HJ`JFj}}}}\",[]]0Ce[\"{{{AIAj{BCB`}}{AIAj{CBfAHFl}}}{{LFj{HJ`JFj}}}}\",[]]0Ce[\"{{{AIAj{BDIh}}{AIAj{CBfAHFl}}}{{LFj{HJ`JFj}}}}\",[]]0Ce[\"{{{AIAj{B@Dh}}{AIAj{CBfAHFl}}}{{LFj{HJ`JFj}}}}\",[]]0Ce[\"{{{AIAj{B@Dn}}{AIAj{CBfAHFl}}}{{LFj{HJ`JFj}}}}\",[]]0Ce[\"{{{AIAj{B@Eh}}{AIAj{CBfAHFl}}}{{LFj{HJ`JFj}}}}\",[]]Ce[\"{{{AIAj{BELn}}{AIAj{CBfAHFl}}}{{LFj{HJ`JFj}}}}\",[]]0Ce[\"{{{AIAj{AINn}}{AIAj{CBfAHFl}}}{{LFj{HJ`JFj}}}}\",[]]Ce[\"{{{AIAj{BDMf}}{AIAj{CBfAHFl}}}{{LFj{HJ`JFj}}}}\",[]]Cd[\"{{{AIAj{CLj}}{AIAj{CBfAHFl}}}{{LFj{HJ`JFj}}}}\",[]]Cc[\"{{{AIAj{Nn}}{AIAj{CBfAHFl}}}{{LFj{HJ`JFj}}}}\",[]]0Ce[\"{{{AIAj{ABNl}}{AIAj{CBfAHFl}}}{{LFj{HJ`JFj}}}}\",[]]0Ce[\"{{{AIAj{ABOn}}{AIAj{CBfAHFl}}}{{LFj{HJ`JFj}}}}\",[]]Cc[\"{{{AIAj{Nb}}{AIAj{CBfAHFl}}}{{LFj{HJ`JFj}}}}\",[]]Ce[\"{{{AIAj{AHEh}}{AIAj{CBfAHFl}}}{{LFj{HJ`JFj}}}}\",[]]Cd[\"{{{AIAj{JF`}}{AIAj{CBfAHFl}}}{{LFj{HJ`JFj}}}}\",[]]Ce[\"{{{AIAj{AOCd}}{AIAj{CBfAHFl}}}{{LFj{HJ`JFj}}}}\",[]]Cd[\"{{{AIAj{OI`}}{AIAj{CBfAHFl}}}{{LFj{HJ`JFj}}}}\",[]]Ce[\"{{{AIAj{BAGl}}{AIAj{CBfAHFl}}}{{LFj{HJ`JFj}}}}\",[]]Ce[\"{{{AIAj{BEDj}}{AIAj{CBfAHFl}}}{{LFj{HJ`JFj}}}}\",[]]Ce[\"{{{AIAj{BGKl}}{AIAj{CBfAHFl}}}{{LFj{HJ`JFj}}}}\",[]]Ce[\"{{{AIAj{AOC`}}{AIAj{CBfAHFl}}}{{LFj{HJ`JFj}}}}\",[]]Ce[\"{{{AIAj{BEMf}}{AIAj{CBfAHFl}}}{{LFj{HJ`JFj}}}}\",[]]Ce[\"{{{AIAj{BFI`}}{AIAj{CBfAHFl}}}{{LFj{HJ`JFj}}}}\",[]]0Cd[\"{{{AIAj{JGj}}{AIAj{CBfAHFl}}}{{LFj{HJ`JFj}}}}\",[]]0Bi[\"{{{AIAj{AIMn}}{AIAj{CBfAHFl}}}LFh}\",[]]Bi[\"{{{AIAj{ABL`}}{AIAj{CBfAHFl}}}LFh}\",[]]Bh[\"{{{AIAj{LHh}}{AIAj{CBfAHFl}}}LFh}\",[]]0Bi[\"{{{AIAj{BFIj}}{AIAj{CBfAHFl}}}LFh}\",[]]0Bh[\"{{{AIAj{JEj}}{AIAj{CBfAHFl}}}LFh}\",[]]Bi[\"{{{AIAj{BEEl}}{AIAj{CBfAHFl}}}LFh}\",[]]0Bh[\"{{{AIAj{LFf}}{AIAj{CBfAHFl}}}LFh}\",[]]0Bi[\"{{{AIAj{B@Hh}}{AIAj{CBfAHFl}}}LFh}\",[]]Bi[\"{{{AIAj{AJ@f}}{AIAj{CBfAHFl}}}LFh}\",[]]Bi[\"{{{AIAj{AHI`}}{AIAj{CBfAHFl}}}LFh}\",[]]Bi[\"{{{AIAj{BELh}}{AIAj{CBfAHFl}}}LFh}\",[]]0Bi[\"{{{AIAj{AIMd}}{AIAj{CBfAHFl}}}LFh}\",[]]0Bi[\"{{{AIAj{AC@f}}{AIAj{CBfAHFl}}}LFh}\",[]]Bi[\"{{{AIAj{AINj}}{AIAj{CBfAHFl}}}LFh}\",[]]Bi[\"{{{AIAj{AHId}}{AIAj{CBfAHFl}}}LFh}\",[]]Bi[\"{{{AIAj{BCC`}}{AIAj{CBfAHFl}}}LFh}\",[]]Bi[\"{{{AIAj{AHIj}}{AIAj{CBfAHFl}}}LFh}\",[]]0Bi[\"{{{AIAj{BAHl}}{AIAj{CBfAHFl}}}LFh}\",[]]0Bh[\"{{{AIAj{OLf}}{AIAj{CBfAHFl}}}LFh}\",[]]Bi[\"{{{AIAj{AJCh}}{AIAj{CBfAHFl}}}LFh}\",[]]0Bi[\"{{{AIAj{AOCl}}{AIAj{CBfAHFl}}}LFh}\",[]]0Bi[\"{{{AIAj{AOF`}}{AIAj{CBfAHFl}}}LFh}\",[]]Bi[\"{{{AIAj{BBFl}}{AIAj{CBfAHFl}}}LFh}\",[]]Bi[\"{{{AIAj{B@Dd}}{AIAj{CBfAHFl}}}LFh}\",[]]0Bi[\"{{{AIAj{BCBh}}{AIAj{CBfAHFl}}}LFh}\",[]]0Bi[\"{{{AIAj{AHHj}}{AIAj{CBfAHFl}}}LFh}\",[]]0Bi[\"{{{AIAj{BBBh}}{AIAj{CBfAHFl}}}LFh}\",[]]0Bi[\"{{{AIAj{BGD`}}{AIAj{CBfAHFl}}}LFh}\",[]]0Bh[\"{{{AIAj{JHd}}{AIAj{CBfAHFl}}}LFh}\",[]]Bi[\"{{{AIAj{BCDd}}{AIAj{CBfAHFl}}}LFh}\",[]]Bi[\"{{{AIAj{BCEb}}{AIAj{CBfAHFl}}}LFh}\",[]]Bi[\"{{{AIAj{BEHl}}{AIAj{CBfAHFl}}}LFh}\",[]]Bi[\"{{{AIAj{BEJj}}{AIAj{CBfAHFl}}}LFh}\",[]]Bi[\"{{{AIAj{AOD`}}{AIAj{CBfAHFl}}}LFh}\",[]]Bi[\"{{{AIAj{BBCl}}{AIAj{CBfAHFl}}}LFh}\",[]]Bi[\"{{{AIAj{B@Id}}{AIAj{CBfAHFl}}}LFh}\",[]]Bi[\"{{{AIAj{BG@l}}{AIAj{CBfAHFl}}}LFh}\",[]]Bi[\"{{{AIAj{B@Cd}}{AIAj{CBfAHFl}}}LFh}\",[]]Bi[\"{{{AIAj{AOBl}}{AIAj{CBfAHFl}}}LFh}\",[]]0Bi[\"{{{AIAj{AHGb}}{AIAj{CBfAHFl}}}LFh}\",[]]0Bi[\"{{{AIAj{BBDf}}{AIAj{CBfAHFl}}}LFh}\",[]]0Bi[\"{{{AIAj{AIOf}}{AIAj{CBfAHFl}}}LFh}\",[]]0Bi[\"{{{AIAj{AJBb}}{AIAj{CBfAHFl}}}LFh}\",[]]0Bi[\"{{{AIAj{B@Eb}}{AIAj{CBfAHFl}}}LFh}\",[]]0Bi[\"{{{AIAj{BCBd}}{AIAj{CBfAHFl}}}LFh}\",[]]0Bi[\"{{{AIAj{BDIl}}{AIAj{CBfAHFl}}}LFh}\",[]]0Bi[\"{{{AIAj{ABKb}}{AIAj{CBfAHFl}}}LFh}\",[]]0Bi[\"{{{AIAj{BDJd}}{AIAj{CBfAHFl}}}LFh}\",[]]Bi[\"{{{AIAj{ABLh}}{AIAj{CBfAHFl}}}LFh}\",[]]Bi[\"{{{AIAj{B@Dj}}{AIAj{CBfAHFl}}}LFh}\",[]]0Bi[\"{{{AIAj{AOB`}}{AIAj{CBfAHFl}}}LFh}\",[]]Bi[\"{{{AIAj{AJAf}}{AIAj{CBfAHFl}}}LFh}\",[]]0Bi[\"{{{AIAj{BAHb}}{AIAj{CBfAHFl}}}LFh}\",[]]Bi[\"{{{AIAj{BCD`}}{AIAj{CBfAHFl}}}LFh}\",[]]Bi[\"{{{AIAj{BGDf}}{AIAj{CBfAHFl}}}LFh}\",[]]Bi[\"{{{AIAj{ABLl}}{AIAj{CBfAHFl}}}LFh}\",[]]Bi[\"{{{AIAj{BEEh}}{AIAj{CBfAHFl}}}LFh}\",[]]0Bi[\"{{{AIAj{BCBl}}{AIAj{CBfAHFl}}}LFh}\",[]]Bi[\"{{{AIAj{BAEd}}{AIAj{CBfAHFl}}}LFh}\",[]]Bi[\"{{{AIAj{B@E`}}{AIAj{CBfAHFl}}}LFh}\",[]]0Bi[\"{{{AIAj{B@Ej}}{AIAj{CBfAHFl}}}LFh}\",[]]Bi[\"{{{AIAj{BBGd}}{AIAj{CBfAHFl}}}LFh}\",[]]0Bi[\"{{{AIAj{BEM`}}{AIAj{CBfAHFl}}}LFh}\",[]]0Bi[\"{{{AIAj{AIO`}}{AIAj{CBfAHFl}}}LFh}\",[]]Bi[\"{{{AIAj{BH@`}}{AIAj{CBfAHFl}}}LFh}\",[]]Bi[\"{{{AIAj{BDMh}}{AIAj{CBfAHFl}}}LFh}\",[]]Bh[\"{{{AIAj{CLl}}{AIAj{CBfAHFl}}}LFh}\",[]]Bg[\"{{{AIAj{O`}}{AIAj{CBfAHFl}}}LFh}\",[]]0Bi[\"{{{AIAj{ABNn}}{AIAj{CBfAHFl}}}LFh}\",[]]0Bi[\"{{{AIAj{AC@`}}{AIAj{CBfAHFl}}}LFh}\",[]]Bi[\"{{{AIAj{AHFn}}{AIAj{CBfAHFl}}}LFh}\",[]]0Bi[\"{{{AIAj{BAIh}}{AIAj{CBfAHFl}}}LFh}\",[]]0Bi[\"{{{AIAj{BFBb}}{AIAj{CBfAHFl}}}LFh}\",[]]Bh[\"{{{AIAj{JGn}}{AIAj{CBfAHFl}}}LFh}\",[]]0Bi[\"{{{AIAj{BGKn}}{AIAj{CBfAHFl}}}LFh}\",[]]Bi[\"{{{AIAj{AOCb}}{AIAj{CBfAHFl}}}LFh}\",[]]Bi[\"{{{AIAj{BEMl}}{AIAj{CBfAHFl}}}LFh}\",[]]Bi[\"{{{AIAj{BFIb}}{AIAj{CBfAHFl}}}LFh}\",[]]0Cd[\"{{{AIAj{JGl}}{AIAj{CBfAHFl}}}{{LFj{HJ`JFj}}}}\",[]]0Bg[\"{{{AIAj{Nd}}{AIAj{CBfAHFl}}}LFh}\",[]]Bi[\"{{{AIAj{AHEj}}{AIAj{CBfAHFl}}}LFh}\",[]]Bh[\"{{{AIAj{JFb}}{AIAj{CBfAHFl}}}LFh}\",[]]Bi[\"{{{AIAj{AOCf}}{AIAj{CBfAHFl}}}LFh}\",[]]Bh[\"{{{AIAj{OIb}}{AIAj{CBfAHFl}}}LFh}\",[]]Bi[\"{{{AIAj{BAGn}}{AIAj{CBfAHFl}}}LFh}\",[]]Bi[\"{{{AIAj{BEDl}}{AIAj{CBfAHFl}}}LFh}\",[]]Bh[\"{{{AIAj{JH`}}{AIAj{CBfAHFl}}}LFh}\",[]]0Bh[\"{{{AIAj{JHf}}{AIAj{CBfAHFl}}}LFh}\",[]]Bi[\"{{{AIAj{BBGf}}{AIAj{CBfAHFl}}}LFh}\",[]]Bi[\"{{{AIAj{ABNh}}{AIAj{CBfAHFl}}}LFh}\",[]]Bi[\"{{{AIAj{AC@b}}{AIAj{CBfAHFl}}}LFh}\",[]]Bi[\"{{{AIAj{B@El}}{AIAj{CBfAHFl}}}LFh}\",[]]Ak[\"{{{AIAj{B@Hh}}}ABKj}\",[]]A`[\"{AC@dCId}\",[]]A`[\"{AC@fCId}\",[]]Aj[\"{{{AIAj{BAHb}}}LBd}\",[]]A`[\"{BGDfCId}\",[]]o[\"{CKdCId}\",[]]A`[\"{ABNhLBd}\",[]]Ce[\"{{{AIAj{CBfBG@j}}{N`{ABOf}}}{{AIAj{CBfBG@j}}}}\",[]]Ce[\"{{{AIAj{CBfBG@l}}{N`{ABOh}}}{{AIAj{CBfBG@l}}}}\",[]]8Af[\"{{ABKjCId}BBFn}\",[]]Ag[\"{{}{{N`{BGDh}}}}\",[]]Ae[\"{{LBdCIb}BADd}\",[]]Cd[\"{{BBCj{LF`{B@I`}}AHJ`{N`{OJh}}}{{LFl{ABKn}}}}\",[]]Ah[\"{{{Nh{JJh}}}AJ@h}\",[]]A`[\"{OJ`BCDb}\",[]]Ah[\"{{{N`{OGn}}}BBCj}\",[]]Bc[\"{{{N`{B@Ib}}{N`{BEDn}}}B@I`}\",[]]Ai[\"{{{N`{B@Cb}}}B@C`}\",[]]B`[\"{{{AIAj{{L@`{Mh}}}}}B@Dn}\",[]]Ae[\"{{CIbLBd}BDMf}\",[]]Ag[\"{{CLjNnCId}ABNl}\",[]]Aj[\"{{{N`{AHEh}}CI`}Nb}\",[]]An[\"{{{N`{AOCd}}OHdCI`}JF`}\",[]]An[\"{{{N`{BAGl}}OHdCI`}OI`}\",[]]Ae[\"{{LBdCIb}BADf}\",[]]Ah[\"{{{Nh{JJh}}}AJ@j}\",[]]Bm[\"{{{N`{BBCl}}{LF`{{N`{B@Id}}}}CMn}ABL`}\",[]]A`[\"{LBdBHCb}\",[]]o[\"{{}BGOf}\",[]]A`[\"{OJ`BCDd}\",[]]Ah[\"{{{N`{OH`}}}BBCl}\",[]]Bc[\"{{{N`{B@If}}{N`{BEE`}}}B@Id}\",[]]Ai[\"{{{N`{B@Cf}}}B@Cd}\",[]]Ek[\"{{ABJh{AIAj{c}}{AIAj{{L@`{CIb}}}}CMn}{{LFj{{LBb{BAHb{LF`{ABJh}}}}BEEh}}}{BEIfJJ`}}\",[\"\"]]B`[\"{{{AIAj{{L@`{Mh}}}}}B@E`}\",[]]Af[\"{{BEM`LHb}BBGd}\",[]]A`[\"{LBdBH@`}\",[]]Ae[\"{{CIbLBd}BDMh}\",[]]Ag[\"{{CLlO`CId}ABNn}\",[]]Aj[\"{{{N`{AHEj}}CI`}Nd}\",[]]An[\"{{{N`{AOCf}}OHdCI`}JFb}\",[]]An[\"{{{N`{BAGn}}OHdCI`}OIb}\",[]]Aj[\"{AJCd{{LFl{BBGf}}}}\",[]]Ai[\"{{{N`{BDM`}}}BGJ`}\",[]]Ai[\"{{{N`{BDMd}}}BGJb}\",[]]o[\"{CLjCLj}\",[]]o[\"{CLlCLl}\",[]]Ak[\"{{{AIAj{AJBh}}}AJBf}\",[]]Ai[\"{{{AIAj{OJh}}}OHd}\",[]]0Aj[\"{{{AIAj{B@In}}}OHd}\",[]]Ak[\"{{{AIAj{BAId}}}AJBf}\",[]]Ak[\"{{{AIAj{AJBj}}}AJBf}\",[]]Ak[\"{{{AIAj{BAIf}}}AJBf}\",[]]Bg[\"{{{AIAj{AIMl}}LFd}{{LF`{ABKj}}}}\",[]]Aa[\"{AHIbABKj}\",[]]Bg[\"{{{AIAj{AIMn}}LFf}{{LF`{ABKj}}}}\",[]]Aa[\"{AHIdABKj}\",[]]Ah[\"{A@`{{LFn{HJ`}}}}\",[]]Ah[\"{A@b{{LFn{HJ`}}}}\",[]]A`[\"{AINhCId}\",[]]A`[\"{AINjCId}\",[]]Aa[\"{B@GdAJB`}\",[]]Aa[\"{ABNhAJB`}\",[]]Aa[\"{BBGdBEM`}\",[]]A`[\"{AHIbCId}\",[]]A`[\"{AHIdCId}\",[]]A`[\"{ABKbJEf}\",[]]Am[\"{{{AIAj{CBfABMj}}}HJ`}\",[]]Am[\"{{{AIAj{CBfABLf}}}HJ`}\",[]]Am[\"{{{AIAj{CBfAJ@n}}}HJ`}\",[]]Am[\"{{{AIAj{CBfAJAj}}}HJ`}\",[]]Al[\"{{{AIAj{CBfLCl}}}HJ`}\",[]]A`[\"{cc{}}\",[\"T\"]]000000000000000000000Aa[\"{BCBfBEEj}\",[]]1111111111Aa[\"{AHIhBBFj}\",[]]2Aa[\"{BCBfAHIh}\",[]]3Aa[\"{AJAbAHIh}\",[]]Aa[\"{BCBfAJAb}\",[]]5Aa[\"{AHIhBBFh}\",[]]6666Aa[\"{BCBfAJCf}\",[]]7Aa[\"{B@ClAJCf}\",[]]Aa[\"{B@IlAJCf}\",[]]9Aa[\"{BCBfB@Il}\",[]]:::::o[\"{CIbLHf}\",[]]n[\"{MhLHf}\",[]]o[\"{CI`LHf}\",[]]A`[\"{ABNlLHf}\",[]]>A`[\"{BELnLHf}\",[]]??Al[\"{cLFd{{CJn{CIb}}}}\",[\"T\"]]A`[\"{cc{}}\",[\"T\"]]0000000Aa[\"{AOBhBCBf}\",[]]A`[\"{JGfBCBf}\",[]]A`[\"{JEnBCBf}\",[]]3333A`[\"{LHfAOCn}\",[]]44444Aa[\"{BFIhAOBj}\",[]]Aa[\"{BCEdAOBj}\",[]]66A`[\"{JGfBCB`}\",[]]77Aa[\"{BEMfB@Dh}\",[]]888A`[\"{LHfBELn}\",[]]999999A`[\"{LHfABNl}\",[]]:::::::::::Aa[\"{AOFfAOC`}\",[]];;;;;;;A`[\"{BDK`JGj}\",[]]A`[\"{BGLlJGj}\",[]]A`[\"{AIOlJGj}\",[]]A`[\"{BCCbJGj}\",[]]?A`[\"{BCDhJGj}\",[]]A`[\"{BGKjJGj}\",[]]A`[\"{BGFlJGj}\",[]]A`[\"{BDInJGj}\",[]]A`[\"{BDLhJGj}\",[]]A`[\"{BBDhJGj}\",[]]A`[\"{BBEjJGj}\",[]]A`[\"{cc{}}\",[\"T\"]]000000000000000n[\"{MhLHh}\",[]]o[\"{CI`LHh}\",[]]o[\"{CIbLHh}\",[]]A`[\"{ABNnLHh}\",[]]A`[\"{BEM`LHh}\",[]]5555Al[\"{cLFf{{CJn{CIb}}}}\",[\"T\"]]666666666666666666Aa[\"{BBGdBCBh}\",[]]77777A`[\"{AHI`JHd}\",[]]8888A`[\"{LHhAOD`}\",[]]99999Aa[\"{BFIjAOBl}\",[]]:Aa[\"{BCEdAOBl}\",[]];;;;;Aa[\"{BBGdBCBd}\",[]]<<<<<>>>>A`[\"{JGnBBGd}\",[]]?A`[\"{LHhBEM`}\",[]]A`[\"{cc{}}\",[\"T\"]]0000A`[\"{LHhABNn}\",[]]11111A`[\"{BAIhJGn}\",[]]22222Aa[\"{AOFfAOCb}\",[]]3333333A`[\"{BBEjJGl}\",[]]A`[\"{BCDhJGl}\",[]]A`[\"{BGFlJGl}\",[]]A`[\"{BCCbJGl}\",[]]A`[\"{BDInJGl}\",[]]A`[\"{AIOlJGl}\",[]]A`[\"{BGLlJGl}\",[]]A`[\"{BDK`JGl}\",[]]A`[\"{BDLhJGl}\",[]]A`[\"{BBDhJGl}\",[]]A`[\"{BGKjJGl}\",[]]>>>>>>>>>An[\"{{{AIAj{c}}}AJCdCIj}\",[\"S\"]]????????????????Bm[\"{{{AIAj{LHf}}{AIAj{CBfc}}}HJ`LEb}\",[\"__H\"]]Bk[\"{{{AIAj{LFd}}{AIAj{CBfc}}}HJ`LEb}\",[\"H\"]]Bn[\"{{{AIAj{AOCn}}{AIAj{CBfc}}}HJ`LEb}\",[\"__H\"]]Bn[\"{{{AIAj{B@Dn}}{AIAj{CBfc}}}HJ`LEb}\",[\"__H\"]]Bm[\"{{{AIAj{CLj}}{AIAj{CBfc}}}HJ`LEb}\",[\"__H\"]]Bl[\"{{{AIAj{Nn}}{AIAj{CBfc}}}HJ`LEb}\",[\"__H\"]]Bn[\"{{{AIAj{ABNl}}{AIAj{CBfc}}}HJ`LEb}\",[\"__H\"]]Bm[\"{{{AIAj{LHh}}{AIAj{CBfc}}}HJ`LEb}\",[\"__H\"]]Bn[\"{{{AIAj{BEEl}}{AIAj{CBfc}}}HJ`LEb}\",[\"__H\"]]Bk[\"{{{AIAj{LFf}}{AIAj{CBfc}}}HJ`LEb}\",[\"H\"]]Bn[\"{{{AIAj{AHIj}}{AIAj{CBfc}}}HJ`LEb}\",[\"__H\"]]Bn[\"{{{AIAj{BAHl}}{AIAj{CBfc}}}HJ`LEb}\",[\"__H\"]]Bn[\"{{{AIAj{AJCh}}{AIAj{CBfc}}}HJ`LEb}\",[\"__H\"]]Bn[\"{{{AIAj{AOD`}}{AIAj{CBfc}}}HJ`LEb}\",[\"__H\"]]Bn[\"{{{AIAj{BDJd}}{AIAj{CBfc}}}HJ`LEb}\",[\"__H\"]]Bn[\"{{{AIAj{BEEh}}{AIAj{CBfc}}}HJ`LEb}\",[\"__H\"]]Bn[\"{{{AIAj{B@E`}}{AIAj{CBfc}}}HJ`LEb}\",[\"__H\"]]Bm[\"{{{AIAj{CLl}}{AIAj{CBfc}}}HJ`LEb}\",[\"__H\"]]Bl[\"{{{AIAj{O`}}{AIAj{CBfc}}}HJ`LEb}\",[\"__H\"]]Bn[\"{{{AIAj{ABNn}}{AIAj{CBfc}}}HJ`LEb}\",[\"__H\"]]Bn[\"{{{AIAj{AHFn}}{AIAj{CBfc}}}HJ`LEb}\",[\"__H\"]]Aa[\"{{}c{}}\",[\"U\"]]00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000n[\"{{}HJ`}\",[]]0000Cc[\"{{{AIAj{CBfLCl}}LBd}{{LFj{{LF`{JEj}}AHIj}}}}\",[]]El[\"{{{AIAj{OFf}}{AIAj{CBf{L@`{Mh}}}}{AIAj{{L@`{Mh}}}}}{{LFj{{AIAj{CBf{L@`{Mh}}}}AOC`}}}}\",[]]Bh[\"{{{AIAj{CBfOKh}}O`}{{LF`{ABNn}}}}\",[]]El[\"{{{AIAj{OFh}}{AIAj{CBf{L@`{Mh}}}}{AIAj{{L@`{Mh}}}}}{{LFj{{AIAj{CBf{L@`{Mh}}}}AOCb}}}}\",[]]Bf[\"{{{AIAj{AIMl}}LFd}{{LF`{CKl}}}}\",[]]Bf[\"{{{AIAj{CKl}}}{{LFj{HJ`AILn}}}}\",[]]A`[\"{AINhCId}\",[]]Am[\"{{{AIAj{CBfAIMn}}}HJ`}\",[]]A`[\"{AINjCId}\",[]]Ck[\"{{{A@f{{AIAj{CBfAILf}}}}{AIAj{CBfOGb}}}{{CLd{HJ`}}}}\",[]]Dk[\"{{{A@f{{AIAj{CBfBCEj}}}}{AIAj{CBfOGb}}}{{CLd{c}}}{}}\",[\"Future::Output\"]]Dk[\"{{{A@f{{AIAj{CBfABMj}}}}{AIAj{CBfOGb}}}{{CLd{c}}}{}}\",[\"Future::Output\"]]Dk[\"{{{A@f{{AIAj{CBfABMl}}}}{AIAj{CBfOGb}}}{{CLd{c}}}{}}\",[\"Future::Output\"]]Dk[\"{{{A@f{{AIAj{CBfAHEn}}}}{AIAj{CBfOGb}}}{{CLd{c}}}{}}\",[\"Future::Output\"]]Dk[\"{{{A@f{{AIAj{CBfAIMh}}}}{AIAj{CBfOGb}}}{{CLd{c}}}{}}\",[\"Future::Output\"]]Dj[\"{{{A@f{{AIAj{CBfOIf}}}}{AIAj{CBfOGb}}}{{CLd{c}}}{}}\",[\"Future::Output\"]]Dj[\"{{{A@f{{AIAj{CBfLEf}}}}{AIAj{CBfOGb}}}{{CLd{c}}}{}}\",[\"Future::Output\"]]Dk[\"{{{A@f{{AIAj{CBfAHDj}}}}{AIAj{CBfOGb}}}{{CLd{c}}}{}}\",[\"Future::Output\"]]Dk[\"{{{A@f{{AIAj{CBfABJf}}}}{AIAj{CBfOGb}}}{{CLd{c}}}{}}\",[\"Future::Output\"]]Dk[\"{{{A@f{{AIAj{CBfB@H`}}}}{AIAj{CBfOGb}}}{{CLd{c}}}{}}\",[\"Future::Output\"]]Dk[\"{{{A@f{{AIAj{CBfB@Hj}}}}{AIAj{CBfOGb}}}{{CLd{c}}}{}}\",[\"Future::Output\"]]Dj[\"{{{A@f{{AIAj{CBfLBl}}}}{AIAj{CBfOGb}}}{{CLd{c}}}{}}\",[\"Future::Output\"]]Dk[\"{{{A@f{{AIAj{CBfBBDd}}}}{AIAj{CBfOGb}}}{{CLd{c}}}{}}\",[\"Future::Output\"]]Bf[\"{{{AIAj{CBfAIMn}}}{{LF`{JHd}}}}\",[]]De[\"{{{AIAj{CBfAJ@n}}{AIAj{CBf{L@`{Mh}}}}}{{LFj{{LF`{LBd}}AHIh}}}}\",[]]Bm[\"{{{AIAj{CBfAJA`}}CMn}{{LFj{LClBAHl}}}}\",[]]Bo[\"{{CLl{AIAj{CBfc}}}{{LFj{BFBbJGn}}}Nj}\",[\"R\"]]Bf[\"{{{AIAj{CBfAHFf}}}{{LF`{JEf}}}}\",[]]Ec[\"{{{AIAj{BBGf}}AJCd{AIAj{CBf{L@`{AIOb}}}}{AIAj{CBf{L@`{ABNh}}}}}{{LFl{LBd}}}}\",[]]Dk[\"{{{AIAj{OFf}}{AIAj{CBf{A@l{Mh}}}}{AIAj{{L@`{Mh}}}}}{{LFj{HJ`AOC`}}}}\",[]]Dk[\"{{{AIAj{OFh}}{AIAj{CBf{A@l{Mh}}}}{AIAj{{L@`{Mh}}}}}{{LFj{HJ`AOCb}}}}\",[]]C`[\"{{{AIAj{CBfAHFf}}JEfCMn}{{LFj{HJ`BEEl}}}}\",[]]Cc[\"{{{AIAj{BBGf}}AJCd{AIAj{AC@b}}}{{LFl{HJ`}}}}\",[]]Bn[\"{{{AIAj{CBfBG@j}}CIb}{{AIAj{CBfBG@j}}}}\",[]]Bn[\"{{{AIAj{CBfBG@l}}CIb}{{AIAj{CBfBG@l}}}}\",[]]Aj[\"{{{AIAj{AIMl}}}CLj}\",[]]Aj[\"{{{AIAj{AIMn}}}CLl}\",[]]Cn[\"{{{AIAj{OGn}}{AIAj{{L@`{Mh}}}}{AIAj{CBf{L@`{Mh}}}}}HJ`}\",[]]Cn[\"{{{AIAj{OH`}}{AIAj{{L@`{Mh}}}}{AIAj{CBf{L@`{Mh}}}}}HJ`}\",[]]A`[\"{BBFnCId}\",[]]A`[\"{ABOnLBd}\",[]]A`[\"{AC@`LBd}\",[]]o[\"{JIlCMn}\",[]]Bm[\"{{{AIAj{CBfAJ@n}}LHf}{{LFj{HJ`B@Cl}}}}\",[]]Bm[\"{{{AIAj{CBfBFBd}}LHf}{{LFj{HJ`B@Cl}}}}\",[]]Bm[\"{{{AIAj{CBfAJA`}}LHh}{{LFj{HJ`B@Dd}}}}\",[]]Bn[\"{{{AIAj{AJC`}}{AIAj{CHn}}}{{LF`{JEf}}}}\",[]]Bn[\"{{{AIAj{BBEf}}{AIAj{CHn}}}{{LF`{JEf}}}}\",[]]Bn[\"{{{AIAj{BDMf}}{AIAj{CHn}}}{{LF`{JEf}}}}\",[]]Bn[\"{{{AIAj{AJCb}}{AIAj{CHn}}}{{LF`{JEf}}}}\",[]]Bn[\"{{{AIAj{BBEh}}{AIAj{CHn}}}{{LF`{JEf}}}}\",[]]Bn[\"{{{AIAj{BDMh}}{AIAj{CHn}}}{{LF`{JEf}}}}\",[]]Aa[\"{{}c{}}\",[\"V\"]]000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000Bg[\"{{{N`{BEDf}}OHdCI`}{{Nh{AIN`}}}}\",[]]Bg[\"{{{N`{AHEh}}OHdCI`}{{Nh{AIN`}}}}\",[]]Bg[\"{{{N`{AOCd}}OHdCI`}{{Nh{AIN`}}}}\",[]]Bg[\"{{{N`{BAGl}}OHdCI`}{{Nh{AIN`}}}}\",[]]Bg[\"{{{N`{BEDh}}OHdCI`}{{Nh{AINb}}}}\",[]]Bg[\"{{{N`{AHEj}}OHdCI`}{{Nh{AINb}}}}\",[]]Bg[\"{{{N`{AOCf}}OHdCI`}{{Nh{AINb}}}}\",[]]Bg[\"{{{N`{BAGn}}OHdCI`}{{Nh{AINb}}}}\",[]]Ai[\"{BFAd{{N`{BEDh}}}}\",[]]o[\"{JEhJEf}\",[]]A`[\"{AC@dCId}\",[]]o[\"{OLdLBd}\",[]]o[\"{JEjJEf}\",[]]A`[\"{AC@fCId}\",[]]o[\"{OLfLBd}\",[]]Aa[\"{AOB`BCBh}\",[]]Ag[\"{{{AIAj{On}}}On}\",[]]Ak[\"{{{AIAj{AOBd}}}AOBd}\",[]]Ak[\"{{{AIAj{AIMl}}}AIMl}\",[]]Ak[\"{{{AIAj{BFIn}}}BFIn}\",[]]Ak[\"{{{AIAj{BEEj}}}BEEj}\",[]]Ak[\"{{{AIAj{ABKn}}}ABKn}\",[]]Ak[\"{{{AIAj{BAEf}}}BAEf}\",[]]Ak[\"{{{AIAj{BBFj}}}BBFj}\",[]]Ak[\"{{{AIAj{AHIh}}}AHIh}\",[]]Ak[\"{{{AIAj{AJAb}}}AJAb}\",[]]Ak[\"{{{AIAj{BBFh}}}BBFh}\",[]]Ak[\"{{{AIAj{AJCf}}}AJCf}\",[]]Ak[\"{{{AIAj{B@Il}}}B@Il}\",[]]Ai[\"{{{AIAj{LHf}}}LHf}\",[]]Ak[\"{{{AIAj{BFIh}}}BFIh}\",[]]Ai[\"{{{AIAj{LFd}}}LFd}\",[]]Ak[\"{{{AIAj{AC@d}}}AC@d}\",[]]Ak[\"{{{AIAj{AINh}}}AINh}\",[]]Ak[\"{{{AIAj{AHIb}}}AHIb}\",[]]Ak[\"{{{AIAj{BCBn}}}BCBn}\",[]]Ai[\"{{{AIAj{OLd}}}OLd}\",[]]Ak[\"{{{AIAj{B@Cl}}}B@Cl}\",[]]Ak[\"{{{AIAj{BCBf}}}BCBf}\",[]]Ak[\"{{{AIAj{BCE`}}}BCE`}\",[]]Ak[\"{{{AIAj{BEHj}}}BEHj}\",[]]Ak[\"{{{AIAj{BEJh}}}BEJh}\",[]]Ak[\"{{{AIAj{AOCn}}}AOCn}\",[]]Ak[\"{{{AIAj{BBCj}}}BBCj}\",[]]Ak[\"{{{AIAj{B@I`}}}B@I`}\",[]]Ak[\"{{{AIAj{BG@j}}}BG@j}\",[]]Ak[\"{{{AIAj{B@C`}}}B@C`}\",[]]Ak[\"{{{AIAj{AOBj}}}AOBj}\",[]]Ak[\"{{{AIAj{AHG`}}}AHG`}\",[]]Ak[\"{{{AIAj{BCB`}}}BCB`}\",[]]Ak[\"{{{AIAj{BDIh}}}BDIh}\",[]]Ak[\"{{{AIAj{B@Dh}}}B@Dh}\",[]]Ak[\"{{{AIAj{B@Dn}}}B@Dn}\",[]]Ak[\"{{{AIAj{B@Eh}}}B@Eh}\",[]]Ak[\"{{{AIAj{BELn}}}BELn}\",[]]Ak[\"{{{AIAj{AINn}}}AINn}\",[]]Ai[\"{{{AIAj{CLj}}}CLj}\",[]]Ag[\"{{{AIAj{Nn}}}Nn}\",[]]Ak[\"{{{AIAj{ABNl}}}ABNl}\",[]]Ag[\"{{{AIAj{Nb}}}Nb}\",[]]Ak[\"{{{AIAj{AHEh}}}AHEh}\",[]]Ai[\"{{{AIAj{JF`}}}JF`}\",[]]Ak[\"{{{AIAj{AOCd}}}AOCd}\",[]]Ai[\"{{{AIAj{OI`}}}OI`}\",[]]Ak[\"{{{AIAj{BAGl}}}BAGl}\",[]]Ak[\"{{{AIAj{BFI`}}}BFI`}\",[]]Ai[\"{{{AIAj{JGj}}}JGj}\",[]]Ai[\"{{{AIAj{LHh}}}LHh}\",[]]Ak[\"{{{AIAj{BFIj}}}BFIj}\",[]]Ak[\"{{{AIAj{BEEl}}}BEEl}\",[]]Ai[\"{{{AIAj{LFf}}}LFf}\",[]]Ak[\"{{{AIAj{B@Hh}}}B@Hh}\",[]]Ak[\"{{{AIAj{AJ@f}}}AJ@f}\",[]]Ak[\"{{{AIAj{AHI`}}}AHI`}\",[]]Ak[\"{{{AIAj{BELh}}}BELh}\",[]]Ak[\"{{{AIAj{AIMd}}}AIMd}\",[]]Ak[\"{{{AIAj{AC@f}}}AC@f}\",[]]Ak[\"{{{AIAj{AINj}}}AINj}\",[]]Ak[\"{{{AIAj{AHId}}}AHId}\",[]]Ak[\"{{{AIAj{BCC`}}}BCC`}\",[]]Ak[\"{{{AIAj{AHIj}}}AHIj}\",[]]Ak[\"{{{AIAj{BAHl}}}BAHl}\",[]]Ai[\"{{{AIAj{OLf}}}OLf}\",[]]Ak[\"{{{AIAj{AJCh}}}AJCh}\",[]]Ak[\"{{{AIAj{AOCl}}}AOCl}\",[]]Ak[\"{{{AIAj{BBFl}}}BBFl}\",[]]Ak[\"{{{AIAj{B@Dd}}}B@Dd}\",[]]Ak[\"{{{AIAj{BCBh}}}BCBh}\",[]]Ak[\"{{{AIAj{AHHj}}}AHHj}\",[]]Ak[\"{{{AIAj{BBBh}}}BBBh}\",[]]Ak[\"{{{AIAj{BGD`}}}BGD`}\",[]]Ak[\"{{{AIAj{BCEb}}}BCEb}\",[]]Ak[\"{{{AIAj{BEHl}}}BEHl}\",[]]Ak[\"{{{AIAj{BEJj}}}BEJj}\",[]]Ak[\"{{{AIAj{AOD`}}}AOD`}\",[]]Ak[\"{{{AIAj{BBCl}}}BBCl}\",[]]Ak[\"{{{AIAj{B@Id}}}B@Id}\",[]]Ak[\"{{{AIAj{BG@l}}}BG@l}\",[]]Ak[\"{{{AIAj{B@Cd}}}B@Cd}\",[]]Ak[\"{{{AIAj{AOBl}}}AOBl}\",[]]Ak[\"{{{AIAj{AHGb}}}AHGb}\",[]]Ak[\"{{{AIAj{AIOf}}}AIOf}\",[]]Ak[\"{{{AIAj{AJBb}}}AJBb}\",[]]Ak[\"{{{AIAj{B@Eb}}}B@Eb}\",[]]Ak[\"{{{AIAj{BCBd}}}BCBd}\",[]]Ak[\"{{{AIAj{BDIl}}}BDIl}\",[]]Ak[\"{{{AIAj{ABKb}}}ABKb}\",[]]Ak[\"{{{AIAj{BDJd}}}BDJd}\",[]]Ak[\"{{{AIAj{B@Dj}}}B@Dj}\",[]]Ak[\"{{{AIAj{BCD`}}}BCD`}\",[]]Ak[\"{{{AIAj{BGDf}}}BGDf}\",[]]Ak[\"{{{AIAj{ABLl}}}ABLl}\",[]]Ak[\"{{{AIAj{BEEh}}}BEEh}\",[]]Ak[\"{{{AIAj{B@E`}}}B@E`}\",[]]Ak[\"{{{AIAj{B@Ej}}}B@Ej}\",[]]Ak[\"{{{AIAj{BBGd}}}BBGd}\",[]]Ak[\"{{{AIAj{BEM`}}}BEM`}\",[]]Ak[\"{{{AIAj{AIO`}}}AIO`}\",[]]Ak[\"{{{AIAj{BH@`}}}BH@`}\",[]]Ai[\"{{{AIAj{CLl}}}CLl}\",[]]Ag[\"{{{AIAj{O`}}}O`}\",[]]Ak[\"{{{AIAj{ABNn}}}ABNn}\",[]]Ak[\"{{{AIAj{AHFn}}}AHFn}\",[]]Ak[\"{{{AIAj{BAIh}}}BAIh}\",[]]Ak[\"{{{AIAj{BFBb}}}BFBb}\",[]]Ai[\"{{{AIAj{JGn}}}JGn}\",[]]Ak[\"{{{AIAj{BFIb}}}BFIb}\",[]]Ai[\"{{{AIAj{JGl}}}JGl}\",[]]Ag[\"{{{AIAj{Nd}}}Nd}\",[]]Ak[\"{{{AIAj{AHEj}}}AHEj}\",[]]Ai[\"{{{AIAj{JFb}}}JFb}\",[]]Ak[\"{{{AIAj{AOCf}}}AOCf}\",[]]Ai[\"{{{AIAj{OIb}}}OIb}\",[]]Ak[\"{{{AIAj{BAGn}}}BAGn}\",[]]Ai[\"{{{AIAj{JHf}}}JHf}\",[]]Ak[\"{{{AIAj{ABNh}}}ABNh}\",[]]Ak[\"{{{AIAj{AC@b}}}AC@b}\",[]]Ak[\"{{{AIAj{B@El}}}B@El}\",[]]Ak[\"{{{AIAj{BFAd}}}BFAd}\",[]]Ak[\"{{{AIAj{BCCh}}}BCCh}\",[]]Bn[\"{{{AIAj{AIMl}}LHf{AIAj{{L@`{Mh}}}}}HJ`}\",[]]Bn[\"{{{AIAj{ABKn}}LHf{AIAj{{L@`{Mh}}}}}HJ`}\",[]]Bg[\"{{{AIAj{CKl}}}{{LFj{AHEnBBBf}}}}\",[]]Bf[\"{{{AIAj{CBfAIMn}}OHdLHhJEf}HJ`}\",[]]Bj[\"{{{AIAj{B@Dn}}}{{AIAj{{L@`{Mh}}}}}}\",[]]Bj[\"{{{AIAj{B@E`}}}{{AIAj{{L@`{Mh}}}}}}\",[]]Aa[\"{BAFjAHHj}\",[]]Aa[\"{BBGdAIOf}\",[]]A`[\"{ABNlCId}\",[]]A`[\"{ABNnCId}\",[]]A`[\"{B@EhCMn}\",[]]A`[\"{B@EjCMn}\",[]]l[\"{OHf}\",[]]l[\"{OHh}\",[]]Ce[\"{{{AIAj{BEIf}}{AIAj{CBfNj}}}{{LFj{B@E`BEEh}}}}\",[]]Ce[\"{{{AIAj{BHCb}}{AIAj{CBfNj}}}{{LFj{B@E`BEEh}}}}\",[]]Bc[\"{{{AIAj{AIMn}}}{{A@l{LFf}}}}\",[]]Bd[\"{{{AIAj{JJb}}{AIAj{CHn}}}HJ`}\",[]]Am[\"{{{AIAj{AOBf}}LBd}HJ`}\",[]]Ai[\"{{{AIAj{JJd}}}HJ`}\",[]]Bg[\"{{{A@f{{AIAj{CBfAILf}}}}OHd}HJ`}\",[]]Bm[\"{{{AIAj{CBfAJAj}}LHf}{{LFj{HJ`B@Cl}}}}\",[]]Bm[\"{{{AIAj{CBfAJAl}}LHh}{{LFj{HJ`B@Dd}}}}\",[]]Am[\"{ABLf{{LFj{HJ`AJAd}}}}\",[]]Dc[\"{{{AIAj{CBfABL`}}ABLh{AIAj{CBf{A@l{Mh}}}}}{{LFj{AC@`AJAf}}}}\",[]]Bi[\"{{{AIAj{OJh}}{A@f{{Nh{LE`}}}}}HJ`}\",[]]Bj[\"{{{AIAj{B@In}}{A@f{{Nh{LE`}}}}}HJ`}\",[]]Bj[\"{{{AIAj{AOEh}}{A@f{{Nh{LE`}}}}}HJ`}\",[]]n[\"{OnCMn}\",[]]Ak[\"{{{AIAj{AIMl}}}BCBn}\",[]]Ak[\"{{{AIAj{ABKn}}}BAEf}\",[]]An[\"{{{AIAj{CBfAIMn}}}BCC`}\",[]]Ce[\"{{{AIAj{CBfAJ@h}}{LF`{LHb}}}{{AIAj{CBfAJ@h}}}}\",[]]Ce[\"{{{AIAj{CBfAJ@j}}{LF`{LHb}}}{{AIAj{CBfAJ@j}}}}\",[]]Ck[\"{{{AIAj{CBfAJAj}}{AIAj{{L@`{Mh}}}}}{{LFj{LBdAJCf}}}}\",[]]Ck[\"{{{AIAj{CBfAJAl}}{AIAj{{L@`{Mh}}}}}{{LFj{LBdAJCh}}}}\",[]]Bl[\"{{{AIAj{BFBb}}{AIAj{CBfc}}}HJ`LCj}\",[\"W\"]]Aj[\"{{{AIAj{ABKn}}}LBl}\",[]]An[\"{ABLf{{LFj{AIMhBCBf}}}}\",[]]Bh[\"{{{AIAj{CBfOKh}}O`}{{LF`{ABNn}}}}\",[]]Fh[\"{{{AIAj{CBfABL`}}ABLhOHd{AIAj{CBf{A@l{Mh}}}}{LF`{{N`{B@Id}}}}}{{LFj{{LBb{BDJdAIMn}}{Nh{AOB`}}}}}}\",[]]Am[\"{AIAj{{AIAj{c}}}{}}\",[\"T\"]]00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000o[\"{OLdLBd}\",[]]o[\"{OLfLBd}\",[]]o[\"{OnAOBd}\",[]]Bb[\"{{AJB`BBBdOn}{{LFn{AOBf}}}}\",[]]Aj[\"{AJB`{{LFl{ABKn}}}}\",[]]B`[\"{{}{{LFj{HJ`{Nh{JFl}}}}}}\",[]]Ak[\"{{{AIAj{AIMl}}}BCBf}\",[]]Be[\"{{{AIAj{ABL`}}}{{AIAj{BBCl}}}}\",[]]o[\"{MhBELn}\",[]]A`[\"{AINhCId}\",[]]o[\"{B@I`N`}\",[]]o[\"{MhBEM`}\",[]]A`[\"{AINjCId}\",[]]o[\"{B@IdN`}\",[]]A`[\"{BBGdLF`}\",[]]Bl[\"{{{AIAj{CBfc}}}{{LFj{LHfBAIh}}}Nj}\",[\"B\"]]Bl[\"{{{AIAj{CBfc}}}{{LFj{LFdBAIh}}}Nj}\",[\"B\"]]Bm[\"{{{AIAj{CBfc}}}{{LFj{AHG`BAIh}}}Nj}\",[\"B\"]]Bm[\"{{{AIAj{CBfc}}}{{LFj{BELnBAIh}}}Nj}\",[\"B\"]]Bm[\"{{{AIAj{CBfc}}}{{LFj{ABNlBAIh}}}Nj}\",[\"B\"]]Bh[\"{{{AIAj{CBfc}}}{{LGb{LHh}}}Nj}\",[\"B\"]]Bh[\"{{{AIAj{CBfc}}}{{LGb{LFf}}}Nj}\",[\"B\"]]Bi[\"{{{AIAj{CBfc}}}{{LGb{AHGb}}}Nj}\",[\"B\"]]Bi[\"{{{AIAj{CBfc}}}{{LGb{AIOf}}}Nj}\",[\"B\"]]Ek[\"{{{AIAj{CBf{LDn{ABJh}}}}{AIAj{c}}{AIAj{{L@`{CIb}}}}CMn}{{LFj{BCD`BEEh}}}{BEIfJJ`}}\",[\"\"]]Bi[\"{{{AIAj{CBfc}}}{{LGb{BEM`}}}Nj}\",[\"B\"]]Bi[\"{{{AIAj{CBfc}}}{{LGb{ABNn}}}Nj}\",[\"B\"]]Bi[\"{{{AIAj{CBfc}}}{{LGb{AHFh}}}Nj}\",[\"B\"]]A`[\"{ABNhLF`}\",[]]Bk[\"{{{AIAj{LHf}}{AIAj{CBfc}}}HJ`LCj}\",[\"B\"]]Bk[\"{{{AIAj{LFd}}{AIAj{CBfc}}}HJ`LCj}\",[\"B\"]]Bl[\"{{{AIAj{AHG`}}{AIAj{CBfc}}}HJ`LCj}\",[\"B\"]]Bl[\"{{{AIAj{BELn}}{AIAj{CBfc}}}HJ`LCj}\",[\"B\"]]Bl[\"{{{AIAj{ABNl}}{AIAj{CBfc}}}HJ`LCj}\",[\"B\"]]Bk[\"{{{AIAj{LHh}}{AIAj{CBfc}}}HJ`LCj}\",[\"B\"]]Bk[\"{{{AIAj{LFf}}{AIAj{CBfc}}}HJ`LCj}\",[\"B\"]]Bl[\"{{{AIAj{AHGb}}{AIAj{CBfc}}}HJ`LCj}\",[\"B\"]]Bl[\"{{{AIAj{AIOf}}{AIAj{CBfc}}}HJ`LCj}\",[\"B\"]]Bl[\"{{{AIAj{ABKb}}{AIAj{CBfc}}}HJ`LCj}\",[\"B\"]]Bl[\"{{{AIAj{BEM`}}{AIAj{CBfc}}}HJ`LCj}\",[\"B\"]]Bl[\"{{{AIAj{ABNn}}{AIAj{CBfc}}}HJ`LCj}\",[\"B\"]]Bl[\"{{{AIAj{AHFj}}{AIAj{CBfc}}}HJ`LCj}\",[\"B\"]]Bj[\"{{{AIAj{CBfAJAj}}}{{LFj{HJ`B@Cl}}}}\",[]]Bj[\"{{{AIAj{CBfAJAl}}}{{LFj{HJ`AOCl}}}}\",[]]An[\"{{{AIAj{AOFd}}ABKj}HJ`}\",[]]Ea[\"{{{AIAj{CBfABL`}}OHdAHFn{LF`{B@Ej}}ABJh{AIAj{CBf{A@l{Mh}}}}}{{LF`{BAEb}}}}\",[]]o[\"{CK`OHf}\",[]]o[\"{CKbOHh}\",[]]A`[\"{ABLfHJ`}\",[]]Ba[\"{{{AIAj{CBfABL`}}ABLh}HJ`}\",[]]Bh[\"{{{AIAj{AJC`}}{AIAj{CHn}}JEf}HJ`}\",[]]Bh[\"{{{AIAj{BBEf}}{AIAj{CHn}}JEf}HJ`}\",[]]Bh[\"{{{AIAj{BDMf}}{AIAj{CHn}}JEf}HJ`}\",[]]Bh[\"{{{AIAj{AJCb}}{AIAj{CHn}}JEf}HJ`}\",[]]Bh[\"{{{AIAj{BBEh}}{AIAj{CHn}}JEf}HJ`}\",[]]Bh[\"{{{AIAj{BDMh}}{AIAj{CHn}}JEf}HJ`}\",[]]A`[\"{AHF`CMn}\",[]]o[\"{JEhCId}\",[]]o[\"{JEjCId}\",[]]Ce[\"{{{AIAj{CBfAIN`}}OHdOHdCIdCMn{AIAj{B@Hf}}}HJ`}\",[]]Cc[\"{{{AIAj{CBfNb}}OHdOHdCIdCMn{AIAj{B@Hf}}}HJ`}\",[]]Cd[\"{{{AIAj{CBfJF`}}OHdOHdCIdCMn{AIAj{B@Hf}}}HJ`}\",[]]Cd[\"{{{AIAj{CBfOI`}}OHdOHdCIdCMn{AIAj{B@Hf}}}HJ`}\",[]]Ce[\"{{{AIAj{CBfAINb}}OHdOHdCIdCMn{AIAj{B@Hh}}}HJ`}\",[]]Cc[\"{{{AIAj{CBfNd}}OHdOHdCIdCMn{AIAj{B@Hh}}}HJ`}\",[]]Cd[\"{{{AIAj{CBfJFb}}OHdOHdCIdCMn{AIAj{B@Hh}}}HJ`}\",[]]Cd[\"{{{AIAj{CBfOIb}}OHdOHdCIdCMn{AIAj{B@Hh}}}HJ`}\",[]]o[\"{CK`OHf}\",[]]o[\"{CKbOHh}\",[]]o[\"{BDMnMh}\",[]]A`[\"{BCB`JEf}\",[]]A`[\"{BDIhJEf}\",[]]A`[\"{BCBdJEf}\",[]]A`[\"{BDIlJEf}\",[]]A`[\"{BBGdLHb}\",[]]Aa[\"{BBBlBCBh}\",[]]Bg[\"{{{AIAj{ABKn}}AHJ`}{{LFl{HJ`}}}}\",[]]A`[\"{ABLfHJ`}\",[]]Cf[\"{{{AIAj{CBfABL`}}ABLh{AIAj{CBf{A@l{Mh}}}}}AC@`}\",[]]l[\"{OHf}\",[]]Aa[\"{AHFnAJB`}\",[]]l[\"{OHh}\",[]]Am[\"{{ABKlOn}{{LFn{HJ`}}}}\",[]]B`[\"{{B@I`AJB`}{{LFl{ABKn}}}}\",[]]Bb[\"{B@Hn{{LFj{HJ`{Nh{JFl}}}}}}\",[]]Bk[\"{{{AIAj{BEEj}}}{{LF`{{AIAj{JFl}}}}}}\",[]]Bk[\"{{{AIAj{BBFj}}}{{LF`{{AIAj{JFl}}}}}}\",[]]Bk[\"{{{AIAj{AHIh}}}{{LF`{{AIAj{JFl}}}}}}\",[]]Bk[\"{{{AIAj{AJAb}}}{{LF`{{AIAj{JFl}}}}}}\",[]]Bk[\"{{{AIAj{BBFh}}}{{LF`{{AIAj{JFl}}}}}}\",[]]Bk[\"{{{AIAj{AJCf}}}{{LF`{{AIAj{JFl}}}}}}\",[]]Bk[\"{{{AIAj{B@Il}}}{{LF`{{AIAj{JFl}}}}}}\",[]]Bk[\"{{{AIAj{BCBf}}}{{LF`{{AIAj{JFl}}}}}}\",[]]Bk[\"{{{AIAj{BCBh}}}{{LF`{{AIAj{JFl}}}}}}\",[]]A`[\"{ABOnLF`}\",[]]A`[\"{AC@`LF`}\",[]]A`[\"{AC@bLF`}\",[]]Bg[\"{{{AIAj{CKl}}}{{LFj{AJ@dAILn}}}}\",[]]Aa[\"{B@HbAJ@f}\",[]]A`[\"{AINhCId}\",[]]A`[\"{AINjCId}\",[]]A`[\"{ABNhLBd}\",[]]Aa[\"{AHIbAC@d}\",[]]Aa[\"{BCBnAC@d}\",[]]Aa[\"{AHIdAC@f}\",[]]Aa[\"{BCC`AC@f}\",[]]3210Dh[\"{{{AIAj{OGn}}{AIAj{{L@`{Mh}}}}{AIAj{{L@`{Mh}}}}}{{LFj{HJ`AOC`}}}}\",[]]Dh[\"{{{AIAj{OH`}}{AIAj{{L@`{Mh}}}}{AIAj{{L@`{Mh}}}}}{{LFj{HJ`AOCb}}}}\",[]]Aj[\"{{{AIAj{AIN`}}}CId}\",[]]Ah[\"{{{AIAj{Nb}}}CId}\",[]]Ai[\"{{{AIAj{JF`}}}CId}\",[]]Ai[\"{{{AIAj{OI`}}}CId}\",[]]Aj[\"{{{AIAj{AINb}}}CId}\",[]]Ah[\"{{{AIAj{Nd}}}CId}\",[]]Ai[\"{{{AIAj{JFb}}}CId}\",[]]Ai[\"{{{AIAj{OIb}}}CId}\",[]]Aj[\"{{{AIAj{BFOh}}}LBd}\",[]]Aj[\"{{{AIAj{BFOj}}}LBd}\",[]]Aj[\"{{{AIAj{BGOf}}}LBd}\",[]]Aj[\"{{{AIAj{BH@`}}}LBd}\",[]]n[\"{OnLBd}\",[]]n[\"{{}OG`}\",[]]0000o[\"{NlABJl}\",[]]Ba[\"{{AIAj{AIAj{c}}}ABMn{}}\",[\"K\"]]0000000000000000000Cg[\"{{{AIAj{ABKn}}AJB`{AIAj{CHn}}}{{LFj{AIMhB@Dh}}}}\",[]]Dl[\"{{{AIAj{CBfABL`}}OHdB@CdAJB`{AIAj{CHn}}}{{LFj{{LBb{BDJdAIMn}}B@Dj}}}}\",[]]Dm[\"{{{AIAj{AHHd}}LFdCId{AIAj{{L@`{Mh}}}}{AIAj{CBfABJh}}}{{LFj{HJ`AOC`}}}}\",[]]Ca[\"{{{AIAj{AHGf}}LBd{AIAj{CBf{L@`{Mh}}}}}HJ`}\",[]]Dm[\"{{{AIAj{AHHf}}LFfCId{AIAj{{L@`{Mh}}}}{AIAj{CBfABJh}}}{{LFj{HJ`AOCb}}}}\",[]]Ca[\"{{{AIAj{AHGh}}LBd{AIAj{CBf{L@`{Mh}}}}}HJ`}\",[]]o[\"{{}AOFb}\",[]]n[\"{{}JJb}\",[]]o[\"{{}AOBf}\",[]]o[\"{{}BADd}\",[]]o[\"{{}BAEf}\",[]]n[\"{{}LHf}\",[]]n[\"{{}LFd}\",[]]o[\"{{}AC@d}\",[]]o[\"{{}AINh}\",[]]o[\"{{}AHIb}\",[]]o[\"{{}BCBn}\",[]]n[\"{{}OLd}\",[]]o[\"{{}B@Cl}\",[]]o[\"{{}BCE`}\",[]]o[\"{{}BEHj}\",[]]o[\"{{}BEJh}\",[]]o[\"{{}AOCn}\",[]]o[\"{{}BBCj}\",[]]o[\"{{}BG@j}\",[]]o[\"{{}BDMf}\",[]]o[\"{{}AHEh}\",[]]o[\"{{}AOCd}\",[]]o[\"{{}BAGl}\",[]]o[\"{{}BEDj}\",[]]o[\"{{}BADf}\",[]]o[\"{{}BGOf}\",[]]n[\"{{}LHh}\",[]]n[\"{{}LFf}\",[]]o[\"{{}AJ@f}\",[]]o[\"{{}AIMd}\",[]]o[\"{{}AC@f}\",[]]o[\"{{}AINj}\",[]]o[\"{{}AHId}\",[]]o[\"{{}BCC`}\",[]]n[\"{{}OLf}\",[]]o[\"{{}BBFl}\",[]]o[\"{{}B@Dd}\",[]]o[\"{{}BCEb}\",[]]o[\"{{}BEHl}\",[]]o[\"{{}BEJj}\",[]]o[\"{{}AOD`}\",[]]o[\"{{}BBCl}\",[]]o[\"{{}BG@l}\",[]]o[\"{{}BH@`}\",[]]o[\"{{}BDMh}\",[]]o[\"{{}AHEj}\",[]]o[\"{{}AOCf}\",[]]o[\"{{}BAGn}\",[]]o[\"{{}BEDl}\",[]]o[\"{{}ABNh}\",[]]n[\"{{}JJd}\",[]]o[\"{{}BCCh}\",[]]o[\"{{}BAEd}\",[]]Ak[\"{{{AIAj{BAHb}}}B@E`}\",[]]Ak[\"{{{AIAj{BCD`}}}B@E`}\",[]]Aa[\"{BGDfB@E`}\",[]]Aa[\"{BEMbB@E`}\",[]]A`[\"{CKdB@E`}\",[]]A`[\"{JIhB@E`}\",[]]A`[\"{JIlB@E`}\",[]]Aa[\"{BDMnB@E`}\",[]]Cg[\"{{{AIAj{AHHd}}LFdCId{AIAj{CBf{L@`{Mh}}}}LBd}HJ`}\",[]]Ca[\"{{{AIAj{AHGf}}LBd{AIAj{CBf{L@`{Mh}}}}}HJ`}\",[]]Cg[\"{{{AIAj{AHHf}}LFfCId{AIAj{CBf{L@`{Mh}}}}LBd}HJ`}\",[]]Ca[\"{{{AIAj{AHGh}}LBd{AIAj{CBf{L@`{Mh}}}}}HJ`}\",[]]Aj[\"{{{AIAj{AJ@n}}}CMn}\",[]]Aj[\"{{{AIAj{BFBd}}}CMn}\",[]]Ak[\"{{{AIAj{AIN`}}}BEDj}\",[]]Ai[\"{{{AIAj{Nb}}}BEDj}\",[]]Aj[\"{{{AIAj{JF`}}}BEDj}\",[]]Aj[\"{{{AIAj{OI`}}}BEDj}\",[]]Ak[\"{{{AIAj{AINb}}}BEDl}\",[]]Ai[\"{{{AIAj{Nd}}}BEDl}\",[]]Aj[\"{{{AIAj{JFb}}}BEDl}\",[]]Aj[\"{{{AIAj{OIb}}}BEDl}\",[]]Bn[\"{{{AIAj{CBfBCE`}}CI`}{{AIAj{CBfBCE`}}}}\",[]]Bn[\"{{{AIAj{CBfBCEb}}CI`}{{AIAj{CBfBCEb}}}}\",[]]Bf[\"{{{AIAj{CBfAIN`}}OHdCIdCId}HJ`}\",[]]Bd[\"{{{AIAj{CBfNb}}OHdCIdCId}HJ`}\",[]]Bf[\"{{{AIAj{CBfAINb}}OHdCIdCId}HJ`}\",[]]Bd[\"{{{AIAj{CBfNd}}OHdCIdCId}HJ`}\",[]]Aj[\"{{{AIAj{AIMl}}}LEf}\",[]]Bc[\"{{{AIAj{ABMl}}}{{LF`{LFd}}}}\",[]]Aa[\"{BGDfB@E`}\",[]]Aa[\"{BEMbB@E`}\",[]]A`[\"{CKdB@E`}\",[]]A`[\"{JIhB@E`}\",[]]Aa[\"{BDMnB@E`}\",[]]Di[\"{{{AIAj{AJAj}}}{{`{{LE`{}{{LFb{{LFj{{LF`{LHf}}B@Il}}}}}}CLhCLn}}}}\",[]]Bn[\"{{{AIAj{AJAl}}}{{LFj{{LF`{LHh}}B@Dd}}}}\",[]]n[\"{OnLBd}\",[]]o[\"{JJbLBd}\",[]]Am[\"{{{AIAj{CBfAIMn}}}OKh}\",[]]Aj[\"{{{AIAj{AHHd}}}LBd}\",[]]Aj[\"{{{AIAj{AHHf}}}LBd}\",[]]A`[\"{AIAjLHd}\",[]]00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000Bd[\"{{{AIAj{BFIn}}}{{LF`{AIMl}}}}\",[]]Bn[\"{{{AIAj{CBfB@C`}}CIb}{{AIAj{CBfB@C`}}}}\",[]]Bn[\"{{{AIAj{CBfB@Cd}}CIb}{{AIAj{CBfB@Cd}}}}\",[]]A`[\"{BGDfCIb}\",[]]A`[\"{BEMbCIb}\",[]]o[\"{CKdCIb}\",[]]o[\"{JIhCIb}\",[]]A`[\"{AHF`LF`}\",[]]Aa[\"{AC@bAIAj}\",[]]A`[\"{AINhCId}\",[]]A`[\"{AINjCId}\",[]]Aa[\"{BBFnABKj}\",[]]A`[\"{LClBBFl}\",[]]Aa[\"{BCBnAINh}\",[]]Aa[\"{BCC`AINj}\",[]]10Bg[\"{{{AIAj{CBfc}}LBd}B@Dn{NjJJ`}}\",[\"\"]]Bg[\"{{{AIAj{CBfc}}LBd}B@E`{NjJJ`}}\",[\"\"]]o[\"{{}BCDb}\",[]]o[\"{{}BCDd}\",[]]A`[\"{CIdBGOf}\",[]]Cd[\"{{{AIAj{CHn}}}{{LFn{AOBdc}}}{}}\",[\"FromStr::Err\"]]o[\"{CIbLHf}\",[]]o[\"{CIbLHh}\",[]]Al[\"{CId{{LFj{LHfBFIh}}}}\",[]]Al[\"{CId{{LFj{LHhBFIj}}}}\",[]]Aa[\"{BFHbAOBn}\",[]]Aa[\"{BHCdBAFb}\",[]]Aa[\"{BFHdAOBn}\",[]]Aa[\"{BHCfBAFb}\",[]]Af[\"{{}{{LF`{Ab}}}}\",[]]0000Aj[\"{{{AIAj{AIMn}}}CMn}\",[]]Bo[\"{{{AIAj{CBfBEJh}}ABKj}{{AIAj{CBfBEJh}}}}\",[]]Bo[\"{{{AIAj{CBfBEJj}}ABKj}{{AIAj{CBfBEJj}}}}\",[]]Ao[\"{{{Nh{AIN`}}}{{Nh{Mn}}}}\",[]]Am[\"{{{Nh{Nb}}}{{Nh{Mn}}}}\",[]]An[\"{{{Nh{JF`}}}{{Nh{Mn}}}}\",[]]An[\"{{{Nh{OI`}}}{{Nh{Mn}}}}\",[]]Ao[\"{{{Nh{AINb}}}{{Nh{Mn}}}}\",[]]Am[\"{{{Nh{Nd}}}{{Nh{Mn}}}}\",[]]An[\"{{{Nh{JFb}}}{{Nh{Mn}}}}\",[]]An[\"{{{Nh{OIb}}}{{Nh{Mn}}}}\",[]]Aj[\"{{{AIAj{BFIn}}}CMn}\",[]]Bo[\"{{{AIAj{CBfBG@j}}ABKj}{{AIAj{CBfBG@j}}}}\",[]]Bo[\"{{{AIAj{CBfBG@l}}ABKj}{{AIAj{CBfBG@l}}}}\",[]]Bc[\"{{{AIAj{AIMh}}}{{LF`{LEd}}}}\",[]]Bc[\"{{{AIAj{AIMl}}}{{LF`{LEd}}}}\",[]]Bc[\"{{{AIAj{ABLf}}}{{LF`{LEd}}}}\",[]]Bc[\"{{{AIAj{ABLh}}}{{LF`{LEd}}}}\",[]]A`[\"{AHFnLF`}\",[]]A`[\"{AINhCId}\",[]]A`[\"{AINjCId}\",[]]Bc[\"{{{AIAj{AHFf}}}{{LF`{LBd}}}}\",[]]Am[\"{{{AIAj{AOFd}}LBd}HJ`}\",[]]Aj[\"{{{AIAj{AIMl}}}OIf}\",[]]Bg[\"{{{AIAj{AJAj}}}{{LFj{CA`B@Cl}}}}\",[]]Bg[\"{{{AIAj{AJAl}}}{{LFj{CA`B@Dd}}}}\",[]]A`[\"{BAEjLF`}\",[]]A`[\"{BAElLF`}\",[]]A`[\"{AHF`LF`}\",[]]A`[\"{AOB`LF`}\",[]]Ck[\"{{{AIAj{CBfBBCj}}{LF`{{JJj{Mh}}}}}{{AIAj{CBfBBCj}}}}\",[]]Ck[\"{{{AIAj{CBfBBCl}}{LF`{{JJj{Mh}}}}}{{AIAj{CBfBBCl}}}}\",[]]A`[\"{BEDjLF`}\",[]]A`[\"{BEDlLF`}\",[]]Ac[\"{AIAjc{}}\",[\"T\"]]000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000Ao[\"{c{{LFj{e}}}{}{}}\",[\"U\",\"T\"]]000000000000000000000000000000000000000000000Al[\"{LBd{{LFj{LHfBFIh}}}}\",[]]Al[\"{HIn{{LFj{LHfBFIh}}}}\",[]]Al[\"{CId{{LFj{LHfBFIh}}}}\",[]]333333333333333Aj[\"{ABKj{{LFj{AOCn}}}}\",[]]444444Ai[\"{CId{{LFj{AHG`}}}}\",[]]555555555555555555555555555Bb[\"{{{N`{B@Bl}}}{{LFj{BDLn}}}}\",[]]6Aj[\"{B@Bl{{LFj{BDLn}}}}\",[]]Bb[\"{{{N`{B@Hl}}}{{LFj{BDMb}}}}\",[]]Aj[\"{B@Hl{{LFj{BDMb}}}}\",[]]99999999999999999999Al[\"{CId{{LFj{LHhBFIj}}}}\",[]]Al[\"{HIn{{LFj{LHhBFIj}}}}\",[]]Al[\"{LBd{{LFj{LHhBFIj}}}}\",[]]<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>Bm[\"{B@Bl{{LFj{BDM`c}}}{}}\",[\"TryFrom::Error\"]]Ce[\"{{{N`{B@Bl}}}{{LFj{BDM`c}}}{}}\",[\"TryFrom::Error\"]]Ao[\"{c{{LFj{e}}}{}{}}\",[\"U\",\"T\"]]Ce[\"{{{N`{B@Hl}}}{{LFj{BDMdc}}}{}}\",[\"TryFrom::Error\"]]Bm[\"{B@Hl{{LFj{BDMdc}}}{}}\",[\"TryFrom::Error\"]]2222222222222222222222222222Aj[\"{{}{{LFj{c}}}{}}\",[\"U\"]]00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000Cd[\"{{{A@f{{AIAj{CBfc}}}}{AIAj{CBfOGb}}}CLd{}}\",[\"F\"]]000000000Cc[\"{{{AIAj{BBGf}}AJCd{AIAj{AC@b}}}{{LFl{HJ`}}}}\",[]]Bk[\"{{{AIAj{BFOh}}B@Dn}{{LFj{HJ`AINn}}}}\",[]]Bk[\"{{{AIAj{BFOj}}B@E`}{{LFj{HJ`AIO`}}}}\",[]]0Bk[\"{{{AIAj{BGOf}}B@E`}{{LFj{HJ`AIO`}}}}\",[]]Ak[\"{{{AIAj{AIMl}}}ABJf}\",[]]Bi[\"{{{AIAj{CBfB@J`}}}{{LFj{LHfJGh}}}}\",[]]Bi[\"{{{AIAj{CBfB@J`}}}{{LFj{CLjJGh}}}}\",[]]Bh[\"{{{AIAj{CBfB@J`}}}{{LFj{NnJGh}}}}\",[]]Bj[\"{{{AIAj{CBfB@J`}}}{{LFj{ABNlJGh}}}}\",[]]Bf[\"{{{AIAj{CBfB@J`}}}{{LG`{LHh}}}}\",[]]Bf[\"{{{AIAj{CBfB@J`}}}{{LG`{CLl}}}}\",[]]Be[\"{{{AIAj{CBfB@J`}}}{{LG`{O`}}}}\",[]]Bg[\"{{{AIAj{CBfB@J`}}}{{LG`{ABNn}}}}\",[]]Aa[\"{AOBdBFIf}\",[]]Bc[\"{{{AIAj{AIN`}}}{{Nh{AIN`}}}}\",[]]Ba[\"{{{AIAj{Nb}}}{{Nh{AIN`}}}}\",[]]Bb[\"{{{AIAj{JF`}}}{{Nh{AIN`}}}}\",[]]Bb[\"{{{AIAj{OI`}}}{{Nh{AIN`}}}}\",[]]Bc[\"{{{AIAj{AINb}}}{{Nh{AINb}}}}\",[]]Ba[\"{{{AIAj{Nd}}}{{Nh{AINb}}}}\",[]]Bb[\"{{{AIAj{JFb}}}{{Nh{AINb}}}}\",[]]Bb[\"{{{AIAj{OIb}}}{{Nh{AINb}}}}\",[]]A`[\"{AC@dCId}\",[]]An[\"{{{AIAj{CBfAIMn}}}AHFf}\",[]]A`[\"{AC@fCId}\",[]]C`[\"{{{AIAj{CBfB@Dn}}}{{AIAj{CBf{L@`{Mh}}}}}}\",[]]C`[\"{{{AIAj{CBfB@E`}}}{{AIAj{CBf{L@`{Mh}}}}}}\",[]]Ah[\"{Mh{{LF`{B@Eh}}}}\",[]]Ah[\"{Mh{{LF`{B@Ej}}}}\",[]]Ah[\"{Mh{{LF`{B@El}}}}\",[]]A`[\"{ABNlCLj}\",[]]A`[\"{ABNnCLl}\",[]]Bi[\"{AIMh{{LFj{{LBb{AIMlBCEj}}AIMh}}}}\",[]]o[\"{CLjCMn}\",[]]o[\"{CLlCMn}\",[]]Aj[\"{{{AIAj{AIMn}}}CMn}\",[]]21Aj[\"{{{AIAj{ABLf}}}CMn}\",[]]Aj[\"{{{AIAj{ABLh}}}CMn}\",[]]Bn[\"{{{AIAj{CBfB@I`}}CMn}{{AIAj{CBfB@I`}}}}\",[]]Bn[\"{{{AIAj{CBfB@Id}}CMn}{{AIAj{CBfB@Id}}}}\",[]]Bl[\"{{{AIAj{OJh}}OHd}{{A@f{{Nh{AILf}}}}}}\",[]]Bm[\"{{{AIAj{B@In}}OHd}{{A@f{{Nh{AILf}}}}}}\",[]]Bm[\"{{{AIAj{AOEh}}OHd}{{A@f{{Nh{AILf}}}}}}\",[]]A`[\"{AINhCId}\",[]]A`[\"{AINjCId}\",[]]Ak[\"{{{AIAj{AIMl}}}ABMj}\",[]]Bc[\"{{{AIAj{AIMl}}AJB`AJ@d}ABMl}\",[]]Ce[\"{{{AIAj{CBfAIMn}}AHFnAJ@fOHd}{{LFj{LFfAHHj}}}}\",[]]43Bm[\"{{{AIAj{CBfAIMn}}LFf}{{LFj{HJ`AIMd}}}}\",[]]E`[\"{{{A@f{{AIAj{CBfBDId}}}}{AIAj{CBfOGb}}}{{CLd{{LF`{c}}}}}{}}\",[\"Stream::Item\"]]Ef[\"{{{A@f{{AIAj{CBfAJ@n}}}}{AIAj{CBfOGb}}{AIAj{CBf{L@`{Mh}}}}}{{CLd{{LFl{LBd}}}}}}\",[]]Ec[\"{{{AIAj{CBfAJ@n}}{AIAj{CBfOGb}}{AIAj{CBf{L@`{Mh}}}}}{{CLd{{LFj{LBdAHIh}}}}}}\",[]]E`[\"{{{A@f{{AIAj{CBfAJ@n}}}}{AIAj{CBfOGb}}{AIAj{CBfOJb}}}{{CLd{{LFl{HJ`}}}}}}\",[]]Fg[\"{{{AIAj{CBfBBBb}}{AIAj{CBfOGb}}{AIAj{CBf{L@`{AIOb}}}}{AIAj{CBf{L@`{ABNh}}}}}{{CLd{{LFl{LBd}}}}}}\",[]]Dn[\"{{{A@f{{AIAj{CBfAHIn}}}}{AIAj{AC@b}}{AIAj{CBfOGb}}}{{CLd{{LFl{HJ`}}}}}}\",[]];:Cd[\"{{{AIAj{CBfBBCj}}{N`{OGn}}}{{AIAj{CBfBBCj}}}}\",[]]Cd[\"{{{AIAj{CBfBBCl}}{N`{OH`}}}{{AIAj{CBfBBCl}}}}\",[]]Cj[\"{{{AIAj{B@Ib}}CIbB@Dn{AIAj{{L@`{Mh}}}}}{{JJj{Mh}}}}\",[]]Cj[\"{{{AIAj{BDMb}}CIbB@Dn{AIAj{{L@`{Mh}}}}}{{JJj{Mh}}}}\",[]]Cj[\"{{{AIAj{B@If}}CIbB@E`{AIAj{{L@`{Mh}}}}}{{JJj{Mh}}}}\",[]]Cj[\"{{{AIAj{BDMd}}CIbB@E`{AIAj{{L@`{Mh}}}}}{{JJj{Mh}}}}\",[]]Cj[\"{{{AIAj{BGJb}}CIbB@Dl{AIAj{{L@`{Mh}}}}}{{JJj{Mh}}}}\",[]]Bb[\"{LBd{{LBb{LBd{LF`{LBd}}}}}}\",[]]00000Aj[\"{{{AIAj{AIMl}}}LBd}\",[]]A`[\"{AIAjLHb}\",[]]0000000000000000000000000000000000000000000000000000000000000Ce[\"{{{AIAj{CBfB@I`}}{N`{BEDn}}}{{AIAj{CBfB@I`}}}}\",[]]Ce[\"{{{AIAj{CBfB@Id}}{N`{BEE`}}}{{AIAj{CBfB@Id}}}}\",[]]A`[\"{BGDfJHn}\",[]]o[\"{B@I`N`}\",[]]o[\"{B@IdN`}\",[]]Aj[\"{{{AIAj{ABKn}}}HJ`}\",[]]Ck[\"{{{AIAj{CBfAJAj}}{AIAj{{L@`{Mh}}}}}{{LFj{HJ`AJCf}}}}\",[]]n[\"{{}LBd}\",[]]Ak[\"{{{AIAj{AIMl}}}AHDj}\",[]]Bn[\"{{{AIAj{CBfBCE`}}CMn}{{AIAj{CBfBCE`}}}}\",[]]Bn[\"{{{AIAj{CBfBCEb}}CMn}{{AIAj{CBfBCEb}}}}\",[]]Bi[\"{{{AIAj{CBf}}}{{AIAj{CBfc}}}{}}\",[\"T\"]]00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000Bc[\"{{AIAj{AIAj{CBfc}}}HJ`{}}\",[\"T\"]]000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000Cc[\"{{{AIAj{CBfAIMn}}OHdLFfLHh}{{LFj{HJ`BBBh}}}}\",[]]A`[\"{AHF`CMn}\",[]]B`[\"{{AIAj{AIAj{c}}}CMn{}}\",[\"K\"]]00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000Aa[\"{BCB`BELn}\",[]]A`[\"{BDIhLHf}\",[]]Aa[\"{BCBdBEM`}\",[]]A`[\"{BDIlLHh}\",[]]o[\"{LDdLHh}\",[]]o[\"{OJnLHh}\",[]]Aa[\"{BCB`AIOd}\",[]]Aa[\"{BCBdAIOf}\",[]]o[\"{LHfCId}\",[]]o[\"{LHhCId}\",[]]Aj[\"{{{AIAj{AIMn}}}CMn}\",[]]Aj[\"{{{AIAj{BAEd}}}CMn}\",[]]Bd[\"{{{AIAj{BBBb}}}{{LFl{AJB`}}}}\",[]]Bd[\"{{{AIAj{ABKn}}}{{LFl{AJB`}}}}\",[]]A`[\"{AHIbCId}\",[]]A`[\"{AHIdCId}\",[]]Cb[\"{{{AIAj{BCCh}}{AIAj{AJAh}}CId}{{N`{AOFd}}}}\",[]]Bn[\"{{{AIAj{CBfBCE`}}CMn}{{AIAj{CBfBCE`}}}}\",[]]Bn[\"{{{AIAj{CBfBCEb}}CMn}{{AIAj{CBfBCEb}}}}\",[]]Bg[\"{{{AIAj{AIMl}}LFd}{{LF`{AHIb}}}}\",[]]Bj[\"{{{AIAj{CBfAIMn}}LFf}{{LF`{AHId}}}}\",[]]Aa[\"{AHDfAHId}\",[]]Db[\"{{{A@f{{AIAj{CBfAJAj}}}}{AIAj{CBfOGb}}}{{CLd{{LFl{HJ`}}}}}}\",[]]00Ec[\"{{{A@f{{AIAj{CBfAJAj}}}}{AIAj{CBfOGb}}{AIAj{{L@`{Mh}}}}}{{CLd{{LFl{LBd}}}}}}\",[]]0Eg[\"{{{A@f{{AIAj{CBfAJAj}}}}{AIAj{CBfOGb}}{AIAj{{L@`{Mh}}}}}{{CLd{{LFj{LBdAJCf}}}}}}\",[]]Bm[\"{{{AIAj{JJd}}{AIAj{CKj}}}{{LFl{HJ`}}}}\",[]]Cd[\"{{{AIAj{CBfAJ@n}}LBd}{{LFj{{LF`{JEh}}AHIh}}}}\",[]]Cd[\"{{{AIAj{CBfBFBd}}LBd}{{LFj{{LF`{JEh}}AHIh}}}}\",[]]Cn[\"{{{AIAj{CBfAJ@n}}{AIAj{CBf{L@`{Mh}}}}}{{LFj{HJ`BBFh}}}}\",[]]Bj[\"{{{AIAj{CKl}}AJ@d}{{LFj{HJ`BELf}}}}\",[]]Bn[\"{{{AIAj{CBfAJ@h}}OHd}{{AIAj{CBfAJ@h}}}}\",[]]Bn[\"{{{AIAj{CBfAJ@j}}OHd}{{AIAj{CBfAJ@j}}}}\",[]]A`[\"{BBFnADj}\",[]]o[\"{JJbCId}\",[]]o[\"{{}AJB`}\",[]]0o[\"{{}AIAj}\",[]]Bj[\"{{ABLf{N`{B@I`}}}{{LFj{AIMhBCBf}}}}\",[]]A`[\"{AINhCId}\",[]]A`[\"{AINjCId}\",[]]Bh[\"{{{AIAj{AHF`}}AJB`}{{LFn{AHJ`}}}}\",[]]A`[\"{AHIbCI`}\",[]]Aj[\"{{{AIAj{AIMn}}}CI`}\",[]]A`[\"{AHIdCI`}\",[]]Ce[\"{{{AIAj{CBfAJ@h}}{LF`{LHb}}}{{AIAj{CBfAJ@h}}}}\",[]]Ce[\"{{{AIAj{CBfAJ@j}}{LF`{LHb}}}{{AIAj{CBfAJ@j}}}}\",[]]Aa[\"{ABOnAJB`}\",[]]Aa[\"{AC@`AJB`}\",[]]Aa[\"{AC@bAJB`}\",[]]n[\"{OnCI`}\",[]]Bn[\"{{{AIAj{CBfBCE`}}CI`}{{AIAj{CBfBCE`}}}}\",[]]Bn[\"{{{AIAj{CBfBCEb}}CI`}{{AIAj{CBfBCEb}}}}\",[]]A`[\"{AHF`CI`}\",[]]Bo[\"{{{AIAj{CBfBCE`}}ABKj}{{AIAj{CBfBCE`}}}}\",[]]Bo[\"{{{AIAj{CBfBCEb}}ABKj}{{AIAj{CBfBCEb}}}}\",[]]A`[\"{AHF`LF`}\",[]]k[\"{{}}\",[]]00000000000Bh[\"{ABLfc{}}\",[\"IntoFuture::IntoFuture\"]]1A`[\"{AINhCId}\",[]]A`[\"{AINjCId}\",[]]n[\"{OnLBd}\",[]]Ao[\"{{AIAjc}{{OHj{c}}}{}}\",[\"S\"]]0C`[\"{{{AIAj{CBfAIN`}}OHdCIdCMn{LF`{CId}}}HJ`}\",[]]Bn[\"{{{AIAj{CBfNb}}OHdCIdCMn{LF`{CId}}}HJ`}\",[]]C`[\"{{{AIAj{CBfAINb}}OHdCIdCMn{LF`{CId}}}HJ`}\",[]]Bn[\"{{{AIAj{CBfNd}}OHdCIdCMn{LF`{CId}}}HJ`}\",[]]Bk[\"{{{AIAj{CBfJJd}}OHd{AIAj{BCCh}}}HJ`}\",[]]A`[\"{BEDjLF`}\",[]]A`[\"{BEDlLF`}\",[]]Bn[\"{{{AIAj{LHf}}{AIAj{LHf}}}{{LF`{ABMn}}}}\",[]]Bn[\"{{{AIAj{LFd}}{AIAj{LFd}}}{{LF`{ABMn}}}}\",[]]C`[\"{{{AIAj{AOCn}}{AIAj{AOCn}}}{{LF`{ABMn}}}}\",[]]C`[\"{{{AIAj{B@Dn}}{AIAj{B@Dn}}}{{LF`{ABMn}}}}\",[]]Bn[\"{{{AIAj{CLj}}{AIAj{CLj}}}{{LF`{ABMn}}}}\",[]]Bl[\"{{{AIAj{Nn}}{AIAj{Nn}}}{{LF`{ABMn}}}}\",[]]C`[\"{{{AIAj{ABNl}}{AIAj{ABNl}}}{{LF`{ABMn}}}}\",[]]Bn[\"{{{AIAj{LHh}}{AIAj{LHh}}}{{LF`{ABMn}}}}\",[]]C`[\"{{{AIAj{BEEl}}{AIAj{BEEl}}}{{LF`{ABMn}}}}\",[]]Bn[\"{{{AIAj{LFf}}{AIAj{LFf}}}{{LF`{ABMn}}}}\",[]]C`[\"{{{AIAj{AHIj}}{AIAj{AHIj}}}{{LF`{ABMn}}}}\",[]]C`[\"{{{AIAj{BAHl}}{AIAj{BAHl}}}{{LF`{ABMn}}}}\",[]]C`[\"{{{AIAj{AJCh}}{AIAj{AJCh}}}{{LF`{ABMn}}}}\",[]]C`[\"{{{AIAj{AOD`}}{AIAj{AOD`}}}{{LF`{ABMn}}}}\",[]]C`[\"{{{AIAj{BDJd}}{AIAj{BDJd}}}{{LF`{ABMn}}}}\",[]]C`[\"{{{AIAj{BEEh}}{AIAj{BEEh}}}{{LF`{ABMn}}}}\",[]]C`[\"{{{AIAj{B@E`}}{AIAj{B@E`}}}{{LF`{ABMn}}}}\",[]]Bn[\"{{{AIAj{CLl}}{AIAj{CLl}}}{{LF`{ABMn}}}}\",[]]Bl[\"{{{AIAj{O`}}{AIAj{O`}}}{{LF`{ABMn}}}}\",[]]C`[\"{{{AIAj{ABNn}}{AIAj{ABNn}}}{{LF`{ABMn}}}}\",[]]Be[\"{{{AIAj{AIMl}}}{{ABNd{AHHn}}}}\",[]]Bk[\"{{{AIAj{AIMn}}LFf}{{LFj{AJ@fAIMd}}}}\",[]]Df[\"{{{AIAj{CBfAJ@n}}{AIAj{CBf{L@`{JEf}}}}}{{LFj{{LF`{LBd}}AHIh}}}}\",[]]Cc[\"{{{AIAj{CBfAJ@n}}LBd}{{LFj{{A@l{Mh}}BBFj}}}}\",[]]Bb[\"{{{AIAj{CBfAIMn}}ABNn}AJA`}\",[]]Aj[\"{{{AIAj{AHGf}}}LBd}\",[]]Aj[\"{{{AIAj{AHGh}}}LBd}\",[]]Bb[\"{{{AIAj{CBfAIMn}}ABNn}AJAl}\",[]]Bn[\"{{{AIAj{CBfBCE`}}CId}{{AIAj{CBfBCE`}}}}\",[]]Bn[\"{{{AIAj{CBfBCEb}}CId}{{AIAj{CBfBCEb}}}}\",[]]A`[\"{AHF`LF`}\",[]]A`[\"{BAEjLF`}\",[]]A`[\"{BAElLF`}\",[]]Ce[\"{{{AIAj{CBfB@I`}}{N`{AJBh}}}{{AIAj{CBfB@I`}}}}\",[]]Ce[\"{{{AIAj{CBfB@Id}}{N`{AJBj}}}{{AIAj{CBfB@Id}}}}\",[]]Ce[\"{{{AIAj{CBfB@C`}}{N`{AJC`}}}{{AIAj{CBfB@C`}}}}\",[]]Ce[\"{{{AIAj{CBfB@Cd}}{N`{AJCb}}}{{AIAj{CBfB@Cd}}}}\",[]]n[\"{OnCId}\",[]]Bn[\"{{{AIAj{CBfBEJh}}CI`}{{AIAj{CBfBEJh}}}}\",[]]Bn[\"{{{AIAj{CBfBEJj}}CI`}{{AIAj{CBfBEJj}}}}\",[]]Ak[\"{{{AIAj{AIMl}}}BFIn}\",[]]Ai[\"{{{N`{B@Ib}}}B@I`}\",[]]Ai[\"{{{N`{B@If}}}B@Id}\",[]]Aj[\"{{BCDbc}BCDbABOd}\",[\"\"]]Aj[\"{{BCDdc}BCDdABOd}\",[\"\"]]Bm[\"{{{AIAj{CBfAJAj}}JEf}{{LFj{HJ`AJCf}}}}\",[]]n[\"{{}LEd}\",[]]o[\"{OG`OG`}\",[]]0000Bd[\"{{{AIAj{BFOh}}}{{LF`{ABKj}}}}\",[]]Bd[\"{{{AIAj{BFOj}}}{{LF`{ABKj}}}}\",[]]Bd[\"{{{AIAj{BGOf}}}{{LF`{ABKj}}}}\",[]]Bd[\"{{{AIAj{BH@`}}}{{LF`{ABKj}}}}\",[]]Bd[\"{{{AIAj{AIMl}}}{{LF`{BCBf}}}}\",[]]Ck[\"{{{AIAj{ABKn}}B@C`AJB`{AIAj{CHn}}}{{LFj{AIMhB@Dh}}}}\",[]]Ak[\"{{{AIAj{B@Hh}}}ABKj}\",[]]A`[\"{AINhCId}\",[]]A`[\"{AINjCId}\",[]]An[\"{{AJ@lCMn}{{LFn{LBd}}}}\",[]]Cj[\"{{{AIAj{OJj}}}{{LF`{{LBb{{Nh{AHGf}}{Nh{AHHd}}}}}}}}\",[]]Ck[\"{{{AIAj{AJBl}}}{{LF`{{LBb{{Nh{AHGf}}{Nh{AHHd}}}}}}}}\",[]]Cj[\"{{{AIAj{OJl}}}{{LF`{{LBb{{Nh{AHGh}}{Nh{AHHf}}}}}}}}\",[]]Ck[\"{{{AIAj{AJBn}}}{{LF`{{LBb{{Nh{AHGh}}{Nh{AHHf}}}}}}}}\",[]]A`[\"{BFHbA@l}\",[]]A`[\"{BHCdA@l}\",[]]A`[\"{BFHdA@l}\",[]]A`[\"{BHCfA@l}\",[]]An[\"{{{AIAj{CBfBFOh}}}B@Dn}\",[]]An[\"{{{AIAj{CBfBFOj}}}B@E`}\",[]]An[\"{{{AIAj{CBfBGOf}}}B@E`}\",[]]An[\"{{{AIAj{CBfBH@`}}}B@E`}\",[]]Ak[\"{{{AIAj{BBGf}}}B@Fn}\",[]]Ba[\"{{{AIAj{CBfAIMn}}BCBl}HJ`}\",[]]Bo[\"{{{AIAj{CBfABL`}}BDJdBAEd}{{LF`{BCBl}}}}\",[]]B`[\"{{{AIAj{OJj}}B@DnCLj}CK`}\",[]]Bn[\"{{{AIAj{B@Ib}}CIbB@Dn}{{LFj{CK`BEMf}}}}\",[]]Ba[\"{{{AIAj{AJBl}}B@DnCLj}CK`}\",[]]Bn[\"{{{AIAj{BDMb}}CIbB@Dn}{{LFj{CK`BEMf}}}}\",[]]B`[\"{{{AIAj{OJl}}B@E`CLl}CKb}\",[]]Bn[\"{{{AIAj{B@If}}CIbB@E`}{{LFj{CKbBEMl}}}}\",[]]Ba[\"{{{AIAj{AJBn}}B@E`CLl}CKb}\",[]]Bn[\"{{{AIAj{BDMd}}CIbB@E`}{{LFj{CKbBEMl}}}}\",[]]Bn[\"{{{AIAj{BGJb}}CIbB@Dl}{{LFj{CKbBEMl}}}}\",[]]Aj[\"{{}{{OJd{c}}}{}}\",[\"T\"]]0A`[\"{AHIbCId}\",[]]A`[\"{AHIdCId}\",[]]Bn[\"{{{AIAj{CBfB@I`}}LBd}{{AIAj{CBfB@I`}}}}\",[]]Bn[\"{{{AIAj{CBfB@Id}}LBd}{{AIAj{CBfB@Id}}}}\",[]]Aj[\"{{{AIAj{BBBb}}}CMn}\",[]]0Aj[\"{{{AIAj{BBGf}}}CMn}\",[]]Bk[\"{{{AIAj{AIMn}}LFf}{{LFj{AHFnAIMd}}}}\",[]]Cb[\"{{{AIAj{BCCh}}{AIAj{AJ@l}}CId}{{N`{AOFd}}}}\",[]]Ak[\"{{{AIAj{ABLf}}}B@Dn}\",[]]Ak[\"{{{AIAj{ABLh}}}B@E`}\",[]]A`[\"{AINhCId}\",[]]A`[\"{AINjCId}\",[]]Bf[\"{{{AIAj{CBfAIMn}}}{{LF`{OHd}}}}\",[]]Ce[\"{{{AIAj{CBfBCE`}}{N`{AODl}}}{{AIAj{CBfBCE`}}}}\",[]]Ce[\"{{{AIAj{CBfBCEb}}{N`{AODn}}}{{AIAj{CBfBCEb}}}}\",[]]43A`[\"{ABOnLF`}\",[]]A`[\"{AC@`LF`}\",[]]A`[\"{AC@bLF`}\",[]]Ai[\"{{{AIAj{OKh}}}LBd}\",[]]Bo[\"{{{AIAj{CBfBGOf}}ABKj}{{AIAj{CBfBGOf}}}}\",[]]Bo[\"{{{AIAj{CBfBH@`}}ABKj}{{AIAj{CBfBH@`}}}}\",[]]Bj[\"{{{AIAj{AJAj}}CA`}{{LFj{HJ`B@Cl}}}}\",[]]Bm[\"{{{AIAj{CBfAJAl}}CA`}{{LFj{HJ`B@Dd}}}}\",[]]<;A`[\"{JJbAOFb}\",[]]A`[\"{AOBfJJb}\",[]]Bi[\"{{{N`{B@Bl}}JJf}{{LFj{BDLnBFI`}}}}\",[]]Bi[\"{{{N`{B@Hl}}JJf}{{LFj{BDMbBFI`}}}}\",[]]Bi[\"{{{N`{B@Bl}}JJf}{{LFj{BDM`BFIb}}}}\",[]]Bi[\"{{{N`{B@Hl}}JJf}{{LFj{BDMdBFIb}}}}\",[]]Co[\"{{{AIAj{CBfAJAj}}{AIAj{CBf{L@`{JEf}}}}}{{LFj{OLdAJCf}}}}\",[]]Co[\"{{{AIAj{CBfAJAl}}{AIAj{CBf{L@`{JEf}}}}}{{LFj{OLfAJCh}}}}\",[]]Aj[\"{{{AIAj{AIMn}}}CMn}\",[]]A`[\"{AINhCId}\",[]]A`[\"{AINjCId}\",[]]A`[\"{AHF`CMn}\",[]]E`[\"{{{AIAj{CBfBBCj}}c}{{AIAj{CBfBBCj}}}{{A`{}{{LFb{{Nh{BFOh}}}}}}CLhCLn}}\",[\"F\"]]E`[\"{{{AIAj{CBfBBCl}}c}{{AIAj{CBfBBCl}}}{{A`{}{{LFb{{Nh{BFOj}}}}}}CLhCLn}}\",[\"F\"]]Bj[\"{{{AIAj{BBBb}}}{{A@f{{Nh{AHIn}}}}}}\",[]]n[\"{OnCId}\",[]]Aa[\"{AOFbAHGj}\",[]]76Aa[\"{AJAdABLf}\",[]]Aa[\"{AJAfABLh}\",[]]Cf[\"{{{AIAj{CBfBEHj}}{LF`{ABKj}}}{{AIAj{CBfBEHj}}}}\",[]]Cf[\"{{{AIAj{CBfBEHl}}{LF`{ABKj}}}{{AIAj{CBfBEHl}}}}\",[]]9;:An[\"{{{AIAj{AOFd}}ABKj}HJ`}\",[]]B`[\"{{{AIAj{CBfAIN`}}CI`}HJ`}\",[]]An[\"{{{AIAj{CBfNb}}CI`}HJ`}\",[]]Ao[\"{{{AIAj{CBfJF`}}CI`}HJ`}\",[]]Ao[\"{{{AIAj{CBfOI`}}CI`}HJ`}\",[]]B`[\"{{{AIAj{CBfAINb}}CI`}HJ`}\",[]]An[\"{{{AIAj{CBfNd}}CI`}HJ`}\",[]]Ao[\"{{{AIAj{CBfJFb}}CI`}HJ`}\",[]]Ao[\"{{{AIAj{CBfOIb}}CI`}HJ`}\",[]]A`[\"{AINhCId}\",[]]A`[\"{AINjCId}\",[]]10Bh[\"{{{AIAj{AIMl}}}{{LF`{{Nh{Mn}}}}}}\",[]]Bg[\"{{{AIAj{OJj}}}{{LF`{{Nh{Mn}}}}}}\",[]]Bh[\"{{{AIAj{AJBl}}}{{LF`{{Nh{Mn}}}}}}\",[]]Bg[\"{{{AIAj{OJl}}}{{LF`{{Nh{Mn}}}}}}\",[]]Bh[\"{{{AIAj{AJBn}}}{{LF`{{Nh{Mn}}}}}}\",[]]Dm[\"{{{AIAj{CBfAJ@n}}{AIAj{CBfOGb}}{AIAj{CBfOJb}}}{{CLd{{LFj{HJ`AHIh}}}}}}\",[]]Db[\"{{{A@f{{AIAj{CBfAJAj}}}}{AIAj{CBfOGb}}}{{CLd{{LFl{HJ`}}}}}}\",[]]Db[\"{{{AIAj{CBfAIMn}}OHdB@Fn{AIAj{CBf{A@l{Mh}}}}}{{LF`{AC@`}}}}\",[]]Cf[\"{{{AIAj{CBfBCE`}}{AIAj{CHn}}}{{AIAj{CBfBCE`}}}}\",[]]Cf[\"{{{AIAj{CBfBCEb}}{AIAj{CHn}}}{{AIAj{CBfBCEb}}}}\",[]]Ak[\"{{{AIAj{AIMl}}}B@H`}\",[]]Bj[\"{{{AIAj{AIMl}}JEf}{{LFj{HJ`BEEj}}}}\",[]]Bn[\"{{{AIAj{CBfBCE`}}CMn}{{AIAj{CBfBCE`}}}}\",[]]Bn[\"{{{AIAj{CBfBCEb}}CMn}{{AIAj{CBfBCEb}}}}\",[]]Ai[\"{{{AIAj{OGn}}}LBd}\",[]]Ai[\"{{{AIAj{OH`}}}LBd}\",[]]De[\"{{{N`{B@Cb}}CIb{AIAj{CHn}}{AIAj{BFBb}}}{{LFj{{Nh{OJj}}B@Dh}}}}\",[]]Bo[\"{{{N`{B@Ib}}CIb{AIAj{BFBb}}}{{Nh{OJj}}}}\",[]]De[\"{{{N`{BDLn}}CIb{AIAj{CHn}}{AIAj{BFBb}}}{{LFj{{Nh{OJj}}B@Dh}}}}\",[]]Bo[\"{{{N`{BDMb}}CIb{AIAj{BFBb}}}{{Nh{OJj}}}}\",[]]De[\"{{{N`{B@Cf}}CIb{AIAj{CHn}}{AIAj{BFBb}}}{{LFj{{Nh{OJl}}B@Dj}}}}\",[]]Bo[\"{{{N`{B@If}}CIb{AIAj{BFBb}}}{{Nh{OJl}}}}\",[]]De[\"{{{N`{BDM`}}CIb{AIAj{CHn}}{AIAj{BFBb}}}{{LFj{{Nh{OJl}}B@Dj}}}}\",[]]Bo[\"{{{N`{BDMd}}CIb{AIAj{BFBb}}}{{Nh{OJl}}}}\",[]]De[\"{{{N`{BGJ`}}CIb{AIAj{CHn}}{AIAj{BFBb}}}{{LFj{{Nh{OJl}}B@Df}}}}\",[]]Bo[\"{{{N`{BGJb}}CIb{AIAj{BFBb}}}{{Nh{OJl}}}}\",[]]Bm[\"{LBd{{LFj{{LBb{LBd{LF`{LBd}}}}BFAf}}}}\",[]]0Cc[\"{{{AIAj{BEDn}}{AIAj{{L@`{Mh}}}}}{{Nh{OFf}}}}\",[]]Cc[\"{{{AIAj{BEE`}}{AIAj{{L@`{Mh}}}}}{{Nh{OFh}}}}\",[]]Bm[\"{{AJB`BBBdOn}{{LFn{{LBb{ABKlAIMj}}}}}}\",[]]Bd[\"{{{AIAj{AIMn}}}{{AIAj{OJl}}}}\",[]]A`[\"{AOBfJJb}\",[]]Cb[\"{{{AIAj{AODl}}CLjAJB`B@DnOHd}{{LF`{AJ@h}}}}\",[]]Cb[\"{{{AIAj{BCDb}}CLjAJB`B@DnOHd}{{LF`{AJ@h}}}}\",[]]Cb[\"{{{AIAj{AODn}}CLlAJB`B@E`OHd}{{LF`{AJ@j}}}}\",[]]Cb[\"{{{AIAj{BCDd}}CLlAJB`B@E`OHd}{{LF`{AJ@j}}}}\",[]]B`[\"{{{AIAj{CBfAIMn}}OHd}HJ`}\",[]]Bo[\"{{{AIAj{CBfAIMh}}}{{LFj{{Nh{Mn}}BCBf}}}}\",[]]Bh[\"{{{AIAj{AIMl}}}{{LF`{{Nh{Mn}}}}}}\",[]]Bg[\"{{{AIAj{OJj}}}{{LF`{{Nh{Mn}}}}}}\",[]]Bh[\"{{{AIAj{AJBl}}}{{LF`{{Nh{Mn}}}}}}\",[]]Bg[\"{{{AIAj{OJl}}}{{LF`{{Nh{Mn}}}}}}\",[]]Bh[\"{{{AIAj{AJBn}}}{{LF`{{Nh{Mn}}}}}}\",[]]o[\"{AINhMh}\",[]]o[\"{AINjMh}\",[]]Ai[\"{{{AIAj{CHn}}}CMn}\",[]]Aj[\"{{{AIAj{AIN`}}}CId}\",[]]Ah[\"{{{AIAj{Nb}}}CId}\",[]]Bn[\"{{{AIAj{CBfAHEh}}CId}{{AIAj{CBfAHEh}}}}\",[]]Ai[\"{{{AIAj{JF`}}}CId}\",[]]Bn[\"{{{AIAj{CBfAOCd}}CId}{{AIAj{CBfAOCd}}}}\",[]]Ai[\"{{{AIAj{OI`}}}CId}\",[]]Bn[\"{{{AIAj{CBfBAGl}}CId}{{AIAj{CBfBAGl}}}}\",[]]Aj[\"{{{AIAj{AINb}}}CId}\",[]]Ah[\"{{{AIAj{Nd}}}CId}\",[]]Bn[\"{{{AIAj{CBfAHEj}}CId}{{AIAj{CBfAHEj}}}}\",[]]Ai[\"{{{AIAj{JFb}}}CId}\",[]]Bn[\"{{{AIAj{CBfAOCf}}CId}{{AIAj{CBfAOCf}}}}\",[]]Ai[\"{{{AIAj{OIb}}}CId}\",[]]Bn[\"{{{AIAj{CBfBAGn}}CId}{{AIAj{CBfBAGn}}}}\",[]]Aa[\"{AJ@nBFBd}\",[]]Ai[\"{{{AIAj{OJj}}}CMn}\",[]]Aj[\"{{{AIAj{AJBl}}}CMn}\",[]]Aj[\"{{{AIAj{AIMn}}}CMn}\",[]]Ai[\"{{{AIAj{OJl}}}CMn}\",[]]Aj[\"{{{AIAj{AJBn}}}CMn}\",[]]Co[\"{{{AIAj{OJj}}B@Dn{AIAj{{L@`{Mh}}}}{AIAj{{L@`{Mh}}}}}CMn}\",[]]D`[\"{{{AIAj{AJBl}}B@Dn{AIAj{{L@`{Mh}}}}{AIAj{{L@`{Mh}}}}}CMn}\",[]]Co[\"{{{AIAj{OJl}}B@E`{AIAj{{L@`{Mh}}}}{AIAj{{L@`{Mh}}}}}CMn}\",[]]D`[\"{{{AIAj{AJBn}}B@E`{AIAj{{L@`{Mh}}}}{AIAj{{L@`{Mh}}}}}CMn}\",[]]Bn[\"{{{AIAj{CBfBEJh}}CI`}{{AIAj{CBfBEJh}}}}\",[]]Bn[\"{{{AIAj{CBfBEJj}}CI`}{{AIAj{CBfBEJj}}}}\",[]]Cc[\"{{{AIAj{CBfOJj}}}{{LF`{{OHf{{Nh{AHHd}}}}}}}}\",[]]Cd[\"{{{AIAj{CBfAJBl}}}{{LF`{{OHf{{Nh{AHHd}}}}}}}}\",[]]Cc[\"{{{AIAj{CBfOJl}}}{{LF`{{OHh{{Nh{AHHf}}}}}}}}\",[]]Cd[\"{{{AIAj{CBfAJBn}}}{{LF`{{OHh{{Nh{AHHf}}}}}}}}\",[]]A`[\"{AINhCId}\",[]]A`[\"{AINjCId}\",[]]De[\"{{{AIAj{CBfBCE`}}c{AIAj{CHn}}}{{AIAj{CBfBCE`}}}{{JEd{CKj}}}}\",[\"\"]]De[\"{{{AIAj{CBfBCEb}}c{AIAj{CHn}}}{{AIAj{CBfBCEb}}}{{JEd{CKj}}}}\",[\"\"]]Ci[\"{{{AIAj{CBfOJj}}{AIAj{{L@`{Mh}}}}}{{LFj{CMnJGf}}}}\",[]]Cj[\"{{{AIAj{CBfAJBl}}{AIAj{{L@`{Mh}}}}}{{LFj{CMnJGf}}}}\",[]]Cj[\"{{{AIAj{CBfOJl}}{AIAj{{L@`{Mh}}}}}{{LFj{CMnBBGd}}}}\",[]]Ck[\"{{{AIAj{CBfAJBn}}{AIAj{{L@`{Mh}}}}}{{LFj{CMnBBGd}}}}\",[]]n[\"{OnCMn}\",[]]Bn[\"{{{AIAj{CBfBCE`}}LHf}{{AIAj{CBfBCE`}}}}\",[]]Bn[\"{{{AIAj{CBfBCEb}}LHh}{{AIAj{CBfBCEb}}}}\",[]]A`[\"{AHF`LF`}\",[]]Ca[\"{{{AIAj{CBfAJ@n}}}{{LFj{{LF`{LHf}}AJAb}}}}\",[]]Ca[\"{{{AIAj{CBfBFBd}}}{{LFj{{LF`{LHf}}AJAb}}}}\",[]]Ca[\"{{{AIAj{CBfAJA`}}}{{LFj{{LF`{LHh}}B@Dd}}}}\",[]]Ak[\"{{{AIAj{AIMh}}}AJB`}\",[]]Ak[\"{{{AIAj{AIMl}}}AJB`}\",[]]Ak[\"{{{AIAj{ABLf}}}AJB`}\",[]]Bg[\"{{{AIAj{CKl}}}{{LFj{AJB`AILn}}}}\",[]]Ak[\"{{{AIAj{ABLh}}}AJB`}\",[]]A`[\"{AINhCId}\",[]]A`[\"{AINjCId}\",[]]B`[\"{{LHfc}LHf{{CJn{LHf}}}}\",[\"\"]]B`[\"{{LFdc}LFd{{CJn{LFd}}}}\",[\"\"]]B`[\"{{LHhc}LHh{{CJn{LHh}}}}\",[\"\"]]B`[\"{{LFfc}LFf{{CJn{LFf}}}}\",[\"\"]]20Ae[\"{{ABKjCId}ADj}\",[]]Bn[\"{{{AIAj{CBfBCE`}}ADh}{{AIAj{CBfBCE`}}}}\",[]]Bn[\"{{{AIAj{CBfBCEb}}ADh}{{AIAj{CBfBCEb}}}}\",[]]A`[\"{JJbABKj}\",[]]B`[\"{{}{{AIAj{{L@`{BFAd}}}}}}\",[]]Ao[\"{{AIAj{A@Kn{CBfMh}}}HJ`}\",[]]000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000Am[\"{{}{{LF`{{N`{OJh}}}}}}\",[]]Bn[\"{{{AIAj{CBfBBCj}}CMn}{{AIAj{CBfBBCj}}}}\",[]]Bn[\"{{{AIAj{CBfBBCl}}CMn}{{AIAj{CBfBBCl}}}}\",[]]Aj[\"{{{AIAj{AHHd}}}CId}\",[]]Aj[\"{{{AIAj{AHHf}}}CId}\",[]]A`[\"{ABNhLF`}\",[]]A`[\"{AINhCId}\",[]]A`[\"{AINjCId}\",[]]10Bf[\"{{{AIAj{CHn}}}{{LFn{CIdBAH`}}}}\",[]]Bm[\"{{{AIAj{ABKn}}{Nh{BBBb}}}{{LFl{HJ`}}}}\",[]]Ai[\"{AIMj{{LFn{HJ`}}}}\",[]]Ci[\"{{{AIAj{OJf}}BBBdBAHj{AIAj{On}}}{{LBb{AJB`ABKl}}}}\",[]]Cb[\"{{{AIAj{CBfAIMn}}LFfAJ@f}{{LFj{AJ@fBELh}}}}\",[]]Am[\"{{{AIAj{AIMl}}CId}HJ`}\",[]]B`[\"{{{AIAj{CBfAIMn}}CId}HJ`}\",[]]A`[\"{BBFlCMn}\",[]]B`[\"{{{AIAj{CBfJJb}}BBFn}HJ`}\",[]]Aa[\"{AOFbAHGj}\",[]]Bm[\"{{{AIAj{OJh}}AHJ`}{{LFl{{Nh{BBBb}}}}}}\",[]]Bn[\"{{{AIAj{B@In}}AHJ`}{{LFl{{Nh{BBBb}}}}}}\",[]]Bn[\"{{{AIAj{AOEh}}AHJ`}{{LFl{{Nh{BBBb}}}}}}\",[]]Ci[\"{{{AIAj{CBfOJj}}{AIAj{CBf{A@l{Mh}}}}}{{LF`{CK`}}}}\",[]]Cj[\"{{{AIAj{CBfAJBl}}{AIAj{CBf{A@l{Mh}}}}}{{LF`{CK`}}}}\",[]]Ci[\"{{{AIAj{CBfOJl}}{AIAj{CBf{A@l{Mh}}}}}{{LF`{CKb}}}}\",[]]Cj[\"{{{AIAj{CBfAJBn}}{AIAj{CBf{A@l{Mh}}}}}{{LF`{CKb}}}}\",[]]Cb[\"{{{AIAj{ABOf}}HInAJBfABKj}{{LFj{HJ`BCDj}}}}\",[]]Cb[\"{{{AIAj{BADd}}HInAJBfABKj}{{LFj{HJ`BCDj}}}}\",[]]Cb[\"{{{AIAj{B@G`}}HInAJBfABKj}{{LFj{HJ`BCDj}}}}\",[]]Cb[\"{{{AIAj{ABOh}}HInAJBfABKj}{{LFj{HJ`BCDl}}}}\",[]]Cb[\"{{{AIAj{BADf}}HInAJBfABKj}{{LFj{HJ`BCDl}}}}\",[]]Cb[\"{{{AIAj{B@Gb}}HInAJBfABKj}{{LFj{HJ`BCDl}}}}\",[]]Al[\"{{}{{LFj{B@BnBFIb}}}}\",[]]Bm[\"{{{AIAj{AIMl}}LFd}{{LF`{{Nh{AIN`}}}}}}\",[]]Bo[\"{{{AIAj{AIMn}}LFf}{{LF`{{AIAj{AINb}}}}}}\",[]]A`[\"{AINhCId}\",[]]A`[\"{AINjCId}\",[]]Aj[\"{{{AIAj{AIMl}}}HJ`}\",[]]Am[\"{{{AIAj{CBfAIMn}}}HJ`}\",[]]Be[\"{{{AIAj{AILd}}}{{LFj{OnJG`}}}}\",[]]Bg[\"{{{AIAj{AILd}}}{{LFj{AHF`JG`}}}}\",[]]Bf[\"{{{AIAj{AILd}}}{{LFj{A@`JG`}}}}\",[]]Bf[\"{{{AIAj{AILd}}}{{LFj{A@bJG`}}}}\",[]]Be[\"{{{AIAj{AILd}}}{{LFj{NlJG`}}}}\",[]]Bg[\"{{{AIAj{AILd}}}{{LFj{ABJlJG`}}}}\",[]]Ak[\"{{{AIAj{BBGf}}}B@Fn}\",[]]Cf[\"{{{AIAj{CBfBCE`}}{LF`{AOCn}}}{{AIAj{CBfBCE`}}}}\",[]]Cf[\"{{{AIAj{CBfBCEb}}{LF`{AOD`}}}{{AIAj{CBfBCEb}}}}\",[]]<;Aj[\"{{{AIAj{ABKn}}}LBd}\",[]]Aj[\"{{{AIAj{ABL`}}}LBd}\",[]]Bc[\"{{{AIAj{AIMl}}AJB`AJ@d}ABMl}\",[]]Co[\"{{{AIAj{CBfAIMn}}AHFnAJ@fOHd}{{LFj{{LBb{LFfCMn}}AHHj}}}}\",[]]Bn[\"{{{AIAj{CBfBCE`}}CIb}{{AIAj{CBfBCE`}}}}\",[]]Bn[\"{{{AIAj{CBfBCEb}}CIb}{{AIAj{CBfBCEb}}}}\",[]]Ai[\"{AIMj{{LFn{HJ`}}}}\",[]]Bg[\"{{{AIAj{BBGf}}AJCd}{{LFl{LBd}}}}\",[]]A`[\"{AHF`CId}\",[]]10Ai[\"{{{AIAj{On}}}BCDn}\",[]]Ce[\"{{{AIAj{CBfB@I`}}{N`{BCE`}}}{{AIAj{CBfB@I`}}}}\",[]]Ce[\"{{{AIAj{CBfB@C`}}{N`{BCE`}}}{{AIAj{CBfB@C`}}}}\",[]]Ce[\"{{{AIAj{CBfB@Id}}{N`{BCEb}}}{{AIAj{CBfB@Id}}}}\",[]]Ce[\"{{{AIAj{CBfB@Cd}}{N`{BCEb}}}{{AIAj{CBfB@Cd}}}}\",[]]Aa[\"{B@I`BG@j}\",[]]Aa[\"{B@IdBG@l}\",[]]Bj[\"{{{A@l{BBBd}}BAHj}{{LFj{B@I`JGj}}}}\",[]]Bj[\"{{{A@l{BBBd}}BAHj}{{LFj{B@IdJGl}}}}\",[]]Co[\"{{{AIAj{CBfAJAj}}{AIAj{CBf{L@`{JEf}}}}}{{LFj{HJ`AJCf}}}}\",[]]A`[\"{AHIbCId}\",[]]A`[\"{AHIdCId}\",[]]A`[\"{BEDjCId}\",[]]A`[\"{BEDlCId}\",[]]Bc[\"{{{AIAj{AIMl}}}{{LF`{LBd}}}}\",[]]A`[\"{AINhCId}\",[]]A`[\"{AINjCId}\",[]]10Aj[\"{{{AIAj{AHFf}}}LBd}\",[]]Be[\"{{{AIAj{ABKn}}{LF`{B@I`}}}HJ`}\",[]]Bn[\"{{{AIAj{CBfABL`}}{LF`{{N`{B@Id}}}}}HJ`}\",[]]Bd[\"{{{AIAj{BFAd}}}{{LF`{BAHh}}}}\",[]]o[\"{{}AIAj}\",[]]n[\"{{}OG`}\",[]]0000Bn[\"{{{AIAj{CBfBCE`}}LBd}{{AIAj{CBfBCE`}}}}\",[]]Bn[\"{{{AIAj{CBfBCEb}}LBd}{{AIAj{CBfBCEb}}}}\",[]]o[\"{CIdLHf}\",[]]o[\"{CIdLHh}\",[]]A`[\"{BAEfCId}\",[]]Bo[\"{{{AIAj{CBfBBCj}}ABKj}{{AIAj{CBfBBCj}}}}\",[]]Bo[\"{{{AIAj{CBfBBCl}}ABKj}{{AIAj{CBfBBCl}}}}\",[]]Ae[\"{{LBdCId}BADd}\",[]]Ae[\"{{LBdCId}BADf}\",[]]A`[\"{AINhCId}\",[]]A`[\"{AINjCId}\",[]]6Bg[\"{{{AIAj{AIMn}}LFf}{{LF`{AJ@f}}}}\",[]]An[\"{{{AIAj{AIMl}}JEf}B@Hj}\",[]]Am[\"{{{AIAj{AIMl}}LHf}HJ`}\",[]]B`[\"{{{AIAj{CBfAIMn}}LHh}HJ`}\",[]]Ce[\"{{{AIAj{CBfBBCj}}{A@l{CIb}}}{{AIAj{CBfBBCj}}}}\",[]]Ce[\"{{{AIAj{CBfBBCl}}{A@l{CIb}}}{{AIAj{CBfBBCl}}}}\",[]]Fg[\"{{{AIAj{BGDh}}{AIAj{BBBd}}{AIAj{{L@`{BBBd}}}}{AIAj{AJAn}}{AIAj{{L@`{Mh}}}}AC@h}{{LFj{BELbJFn}}}}\",[]]Af[\"{{BCDbOHd}BCDb}\",[]]Af[\"{{BCDdOHd}BCDd}\",[]]?Al[\"{B@J`{{LFj{CLjJGh}}}}\",[]]Ak[\"{B@J`{{LFj{NnJGh}}}}\",[]]Am[\"{B@J`{{LFj{ABNlJGh}}}}\",[]]Ai[\"{B@J`{{LG`{CLl}}}}\",[]]Ah[\"{B@J`{{LG`{O`}}}}\",[]]Aj[\"{B@J`{{LG`{ABNn}}}}\",[]]o[\"{OG`OG`}\",[]]Bo[\"{{{AIAj{CBfBEJh}}ABKj}{{AIAj{CBfBEJh}}}}\",[]]Bo[\"{{{AIAj{CBfBEJj}}ABKj}{{AIAj{CBfBEJj}}}}\",[]]Bb[\"{{{AIAj{OJj}}}{{LF`{CMn}}}}\",[]]Bc[\"{{{AIAj{AJBl}}}{{LF`{CMn}}}}\",[]]Bb[\"{{{AIAj{OJl}}}{{LF`{CMn}}}}\",[]]Bc[\"{{{AIAj{AJBn}}}{{LF`{CMn}}}}\",[]]Bg[\"{{{AIAj{AIMl}}}{{LFj{HJ`BCBf}}}}\",[]]Cf[\"{{{AIAj{CBfBCE`}}{LF`{ABKj}}}{{AIAj{CBfBCE`}}}}\",[]]Cf[\"{{{AIAj{CBfBCEb}}{LF`{ABKj}}}{{AIAj{CBfBCEb}}}}\",[]]A`[\"{AHIbCId}\",[]]A`[\"{AHIdCId}\",[]]Bl[\"{{{AIAj{CBfAIN`}}OHdOHdCMnCMnCId}HJ`}\",[]]Bj[\"{{{AIAj{CBfNb}}OHdOHdCMnCMnCId}HJ`}\",[]]Bk[\"{{{AIAj{CBfJF`}}OHdOHdCMnCMnCId}HJ`}\",[]]Bk[\"{{{AIAj{CBfOI`}}OHdOHdCMnCMnCId}HJ`}\",[]]Bl[\"{{{AIAj{CBfAINb}}OHdOHdCMnCMnCId}HJ`}\",[]]Bj[\"{{{AIAj{CBfNd}}OHdOHdCMnCMnCId}HJ`}\",[]]Bk[\"{{{AIAj{CBfJFb}}OHdOHdCMnCMnCId}HJ`}\",[]]Bk[\"{{{AIAj{CBfOIb}}OHdOHdCMnCMnCId}HJ`}\",[]]A`[\"{BAEfCId}\",[]]Ak[\"{{{AIAj{OKh}}O`}CId}\",[]]Bi[\"{{{AIAj{CBfAJAh}}CId}{{LFn{HJ`}}}}\",[]]<;A`[\"{AINhCId}\",[]]A`[\"{AINjCId}\",[]]10Cf[\"{{{AIAj{CBfBCE`}}{LF`{BEHj}}}{{AIAj{CBfBCE`}}}}\",[]]Cf[\"{{{AIAj{CBfBCEb}}{LF`{BEHl}}}{{AIAj{CBfBCEb}}}}\",[]]A`[\"{AHIbCId}\",[]]A`[\"{AHIdCId}\",[]]Bh[\"{{{AIAj{CBfAILd}}}{{LFj{OnJG`}}}}\",[]]Bj[\"{{{AIAj{CBfAILd}}}{{LFj{AHF`JG`}}}}\",[]]Bi[\"{{{AIAj{CBfAILd}}}{{LFj{A@`JG`}}}}\",[]]Bi[\"{{{AIAj{CBfAILd}}}{{LFj{A@bJG`}}}}\",[]]Bh[\"{{{AIAj{CBfAILd}}}{{LFj{NlJG`}}}}\",[]]Bj[\"{{{AIAj{CBfAILd}}}{{LFj{ABJlJG`}}}}\",[]]Cc[\"{{{N`{AIMj}}CIdCMn}{{LFn{{LBb{BBFnBBFn}}}}}}\",[]]Bn[\"{{{AIAj{CBfB@I`}}CId}{{AIAj{CBfB@I`}}}}\",[]]Bn[\"{{{AIAj{CBfB@Id}}CId}{{AIAj{CBfB@Id}}}}\",[]]Aj[\"{{{AIAj{AIMl}}}CMn}\",[]]Ak[\"{{{AIAj{BBBb}}}B@Fn}\",[]]0Ci[\"{{{AIAj{CBfBBCj}}CI`}{{LFj{{AIAj{CBfBBCj}}AOBj}}}}\",[]]Ci[\"{{{AIAj{CBfBBCl}}CI`}{{LFj{{AIAj{CBfBBCl}}AOBl}}}}\",[]]A`[\"{AHF`CI`}\",[]]Cf[\"{{{AIAj{CBfBCE`}}{LF`{BEJh}}}{{AIAj{CBfBCE`}}}}\",[]]Cf[\"{{{AIAj{CBfBCEb}}{LF`{BEJj}}}{{AIAj{CBfBCEb}}}}\",[]]Bg[\"{{{AIAj{CBfAIMn}}}{{LF`{BAEd}}}}\",[]]Cf[\"{{{AIAj{CBfB@I`}}{LF`{B@Ih}}}{{AIAj{CBfB@I`}}}}\",[]]Cf[\"{{{AIAj{CBfB@Id}}{LF`{B@Ih}}}{{AIAj{CBfB@Id}}}}\",[]]Cf[\"{{{AIAj{CBfB@I`}}{LF`{B@Ij}}}{{AIAj{CBfB@I`}}}}\",[]]Cf[\"{{{AIAj{CBfB@Id}}{LF`{B@Ij}}}{{AIAj{CBfB@Id}}}}\",[]]Cc[\"{{}{{LFj{{LBb{{A@l{BBBd}}BAHj}}{Nh{JFl}}}}}}\",[]]Bn[\"{{{AIAj{CBfBEHj}}LHf}{{AIAj{CBfBEHj}}}}\",[]]Bn[\"{{{AIAj{CBfBEHl}}LHh}{{AIAj{CBfBEHl}}}}\",[]]A`[\"{AINhCId}\",[]]A`[\"{AINjCId}\",[]]Bo[\"{{{AIAj{CBfB@I`}}ABKj}{{AIAj{CBfB@I`}}}}\",[]]Bo[\"{{{AIAj{CBfB@Id}}ABKj}{{AIAj{CBfB@Id}}}}\",[]]Ci[\"{{{AIAj{CKl}}{LF`{ABKj}}}{{LFj{{LF`{ABKj}}AILn}}}}\",[]]Bj[\"{{{AIAj{BBGf}}AJCdLBd}{{LFl{HJ`}}}}\",[]]054Bm[\"{{{AIAj{OJj}}}{{LFj{{LF`{BFBb}}JGf}}}}\",[]]Bn[\"{{{AIAj{AJBl}}}{{LFj{{LF`{BFBb}}JGf}}}}\",[]]Bn[\"{{{AIAj{OJl}}}{{LFj{{LF`{BFBb}}BBGd}}}}\",[]]Bo[\"{{{AIAj{AJBn}}}{{LFj{{LF`{BFBb}}BBGd}}}}\",[]]Aj[\"{{{AIAj{AHHd}}}CId}\",[]]Aj[\"{{{AIAj{AHHf}}}CId}\",[]]Aj[\"{{{AIAj{ABL`}}}CId}\",[]]Bf[\"{{{AIAj{AHFn}}{AIAj{AHFn}}}CMn}\",[]]Am[\"{{{AIAj{CBfAIMn}}}HJ`}\",[]]Bn[\"{{{AIAj{CBfBAGl}}ADh}{{AIAj{CBfBAGl}}}}\",[]]Bn[\"{{{AIAj{CBfBAGn}}ADh}{{AIAj{CBfBAGn}}}}\",[]]Ak[\"{{{AIAj{AHIn}}}B@Fn}\",[]]0Bd[\"{{{AIAj{AIMl}}}{{ABNd{JHf}}}}\",[]]Cb[\"{{{AIAj{AIMn}}LFf}{{LFj{{LF`{AJB`}}AIMd}}}}\",[]]A`[\"{AINhCId}\",[]]A`[\"{AINjCId}\",[]]Bn[\"{{{AIAj{CBfBCE`}}LHf}{{AIAj{CBfBCE`}}}}\",[]]Bn[\"{{{AIAj{CBfBCEb}}LHh}{{AIAj{CBfBCEb}}}}\",[]]A`[\"{AHF`LF`}\",[]]Bo[\"{{{AIAj{AHF`}}{AIAj{CHn}}}{{LFl{BCDn}}}}\",[]]Em[\"{{{AIAj{AIMl}}{AIAj{CBf{L@`{Mh}}}}{AIAj{{L@`{Mh}}}}{AIAj{{L@`{Mh}}}}}{{LFj{HJ`BGKl}}}}\",[]]El[\"{{{AIAj{OJj}}{AIAj{CBf{L@`{Mh}}}}{AIAj{{L@`{Mh}}}}{AIAj{{L@`{Mh}}}}}{{LFj{HJ`BGKl}}}}\",[]]Em[\"{{{AIAj{AJBl}}{AIAj{CBf{L@`{Mh}}}}{AIAj{{L@`{Mh}}}}{AIAj{{L@`{Mh}}}}}{{LFj{HJ`BGKl}}}}\",[]]El[\"{{{AIAj{OJl}}{AIAj{CBf{L@`{Mh}}}}{AIAj{{L@`{Mh}}}}{AIAj{{L@`{Mh}}}}}{{LFj{HJ`BGKn}}}}\",[]]Em[\"{{{AIAj{AJBn}}{AIAj{CBf{L@`{Mh}}}}{AIAj{{L@`{Mh}}}}{AIAj{{L@`{Mh}}}}}{{LFj{HJ`BGKn}}}}\",[]]Am[\"{{{AIAj{CBfAHFd}}}HJ`}\",[]]0Al[\"{{{AIAj{AIMn}}O`}CId}\",[]]Bl[\"{{{AIAj{AIMl}}}{{ABNf{{LF`{AJB`}}}}}}\",[]]Bg[\"{{{AIAj{CKl}}}{{LFj{BDIdAILn}}}}\",[]]>=E`[\"{{{AIAj{BGDh}}{AIAj{{L@`{Mh}}}}{AIAj{BBBd}}{AIAj{BFOl}}}{{LFj{BGFnJFn}}}}\",[]]0Bf[\"{{{N`{BAIb}}}{{LFj{B@C`BFIl}}}}\",[]]Bf[\"{{{N`{BAIb}}}{{LFj{B@CdBFIl}}}}\",[]]Bn[\"{{{AIAj{CBfBEHj}}LHf}{{AIAj{CBfBEHj}}}}\",[]]Bn[\"{{{AIAj{CBfBEHl}}LHh}{{AIAj{CBfBEHl}}}}\",[]]o[\"{OG`OG`}\",[]]0000Aj[\"{{{AIAj{AIMn}}}CMn}\",[]]0Ci[\"{{{AIAj{CKl}}{LF`{ABKj}}}{{LFj{{LF`{ABKj}}AILn}}}}\",[]]Cc[\"{{{AIAj{CBfOn}}{AIAj{AILd}}}{{LFj{HJ`JG`}}}}\",[]]Ce[\"{{{AIAj{CBfAHF`}}{AIAj{AILd}}}{{LFj{HJ`JG`}}}}\",[]]Cd[\"{{{AIAj{CBfA@`}}{AIAj{AILd}}}{{LFj{HJ`JG`}}}}\",[]]Cd[\"{{{AIAj{CBfA@b}}{AIAj{AILd}}}{{LFj{HJ`JG`}}}}\",[]]Cc[\"{{{AIAj{CBfNl}}{AIAj{AILd}}}{{LFj{HJ`JG`}}}}\",[]]Ce[\"{{{AIAj{CBfABJl}}{AIAj{AILd}}}{{LFj{HJ`JG`}}}}\",[]]Bo[\"{{{AIAj{CBfB@I`}}BG@j}{{AIAj{CBfB@I`}}}}\",[]]Bo[\"{{{AIAj{CBfB@Id}}BG@l}{{AIAj{CBfB@Id}}}}\",[]]Aj[\"{{{AIAj{BBCj}}}CId}\",[]]Aj[\"{{{AIAj{BBCl}}}CId}\",[]]Cc[\"{{{AIAj{CBfB@C`}}{N`{A`}}}{{AIAj{CBfB@C`}}}}\",[]]Cc[\"{{{AIAj{CBfB@Cd}}{N`{A`}}}{{AIAj{CBfB@Cd}}}}\",[]]Cj[\"{{BBCj{LF`{B@I`}}{Nh{BBBb}}{N`{OJh}}}{{LFl{ABKn}}}}\",[]]Aj[\"{{{AIAj{ABLf}}}CMn}\",[]]Aj[\"{{{AIAj{ABLh}}}CMn}\",[]]Ca[\"{{{AIAj{CBfAIMn}}OHdAIOj}{{LFj{HJ`BGD`}}}}\",[]]Bd[\"{{{AIAj{BGDh}}}{{A@l{BCDf}}}}\",[]]Bj[\"{{{AIAj{AIMl}}AJB`}{{LFj{HJ`JH`}}}}\",[]]Bm[\"{{{AIAj{CBfAIMn}}AJB`}{{LFj{HJ`JH`}}}}\",[]]Bn[\"{{{AIAj{CBfBCE`}}LBd}{{AIAj{CBfBCE`}}}}\",[]]Bn[\"{{{AIAj{CBfBCEb}}LBd}{{AIAj{CBfBCEb}}}}\",[]]Bl[\"{{}{{LFj{{LBb{BBBdBEKd}}{Nh{JFl}}}}}}\",[]]Ai[\"{AIMj{{LFn{HJ`}}}}\",[]]A`[\"{AINhCId}\",[]]A`[\"{AINjCId}\",[]]An[\"{{{AIAj{ABKn}}B@C`}HJ`}\",[]]D`[\"{{{AIAj{CBfAIMn}}LFf{LF`{ABKj}}}{{LFj{{LF`{ABKj}}AIMd}}}}\",[]]o[\"{{}AIAj}\",[]]Aj[\"{{{AIAj{AIMl}}}LBd}\",[]]Bn[\"{{{AIAj{CBfB@I`}}CId}{{AIAj{CBfB@I`}}}}\",[]]Bn[\"{{{AIAj{CBfB@Id}}CId}{{AIAj{CBfB@Id}}}}\",[]]Bn[\"{{{AIAj{CBfBCE`}}LHf}{{AIAj{CBfBCE`}}}}\",[]]Bn[\"{{{AIAj{CBfBCEb}}LHh}{{AIAj{CBfBCEb}}}}\",[]]:Bb[\"{{{AIAj{CBfAIMn}}O`LHh}HJ`}\",[]]Ak[\"{{}{{LFj{B@C`JGj}}}}\",[]]Ak[\"{{}{{LFj{B@CdJGl}}}}\",[]]Bn[\"{{{AIAj{CBfBCE`}}CMn}{{AIAj{CBfBCE`}}}}\",[]]Bn[\"{{{AIAj{CBfBCEb}}CMn}{{AIAj{CBfBCEb}}}}\",[]]65Cf[\"{{{AIAj{CBfOn}}{AIAj{CBfAILd}}}{{LFj{HJ`JG`}}}}\",[]]Ch[\"{{{AIAj{CBfAHF`}}{AIAj{CBfAILd}}}{{LFj{HJ`JG`}}}}\",[]]Cg[\"{{{AIAj{CBfA@`}}{AIAj{CBfAILd}}}{{LFj{HJ`JG`}}}}\",[]]Cg[\"{{{AIAj{CBfA@b}}{AIAj{CBfAILd}}}{{LFj{HJ`JG`}}}}\",[]]Cf[\"{{{AIAj{CBfNl}}{AIAj{CBfAILd}}}{{LFj{HJ`JG`}}}}\",[]]Ch[\"{{{AIAj{CBfABJl}}{AIAj{CBfAILd}}}{{LFj{HJ`JG`}}}}\",[]]Bi[\"{{{AIAj{CBfAHFn}}{AIAj{AHFn}}}CMn}\",[]]n[\"{{}HJ`}\",[]]Ce[\"{{{AIAj{CBfBCE`}}{LF`{LBd}}}{{AIAj{CBfBCE`}}}}\",[]]Ce[\"{{{AIAj{CBfBCEb}}{LF`{LBd}}}{{AIAj{CBfBCEb}}}}\",[]]Bn[\"{{{AIAj{AIMl}}}{{LFj{{A@l{AJB`}}JH`}}}}\",[]]Cd[\"{{{AIAj{CBfAIMn}}OHd}{{LFj{{A@l{AJB`}}JH`}}}}\",[]]Am[\"{{{AIAj{CBfAIN`}}}HJ`}\",[]]Al[\"{{{AIAj{CBfJF`}}}HJ`}\",[]]Am[\"{{{AIAj{CBfAINb}}}HJ`}\",[]]Al[\"{{{AIAj{CBfJFb}}}HJ`}\",[]]Ai[\"{AIMj{{LFn{HJ`}}}}\",[]]Bj[\"{{{AIAj{AIMl}}AJB`}{{LFj{HJ`JH`}}}}\",[]]Bm[\"{{{AIAj{CBfAIMn}}AJB`}{{LFj{HJ`JH`}}}}\",[]]D`[\"{{{AIAj{CBfAIMn}}LFf{LF`{ABKj}}}{{LFj{{LF`{ABKj}}AIMd}}}}\",[]]Ce[\"{{{AIAj{CBfBCE`}}{N`{BEDf}}}{{AIAj{CBfBCE`}}}}\",[]]Ce[\"{{{AIAj{CBfBCEb}}{N`{BEDh}}}{{AIAj{CBfBCEb}}}}\",[]]Cf[\"{{{AIAj{CBfBCE`}}{LF`{ABKj}}}{{AIAj{CBfBCE`}}}}\",[]]Cf[\"{{{AIAj{CBfBCEb}}{LF`{ABKj}}}{{AIAj{CBfBCEb}}}}\",[]]Aa[\"{BAEjAIOh}\",[]]Aa[\"{BAElAIOh}\",[]]9Bn[\"{{{AIAj{CBfBCE`}}CMn}{{AIAj{CBfBCE`}}}}\",[]]Bn[\"{{{AIAj{CBfBCEb}}CMn}{{AIAj{CBfBCEb}}}}\",[]]Am[\"{{{AIAj{AIMl}}LHf}HJ`}\",[]]o[\"{OG`OG`}\",[]]Bn[\"{{{AIAj{CBfBCE`}}CIb}{{AIAj{CBfBCE`}}}}\",[]]Bn[\"{{{AIAj{CBfBCEb}}CIb}{{AIAj{CBfBCEb}}}}\",[]]3109854Bn[\"{{{AIAj{AIMl}}}{{LFj{{A@l{AJB`}}JH`}}}}\",[]]Bn[\"{{{AIAj{AIMn}}}{{LFj{{A@l{AJB`}}JH`}}}}\",[]]10A`[\"{BFBbLF`}\",[]]Bm[\"{{{AIAj{CBfBCE`}}Mh}{{AIAj{CBfBCE`}}}}\",[]]Bm[\"{{{AIAj{CBfBCEb}}Mh}{{AIAj{CBfBCEb}}}}\",[]]o[\"{{}AIOj}\",[]]") \ No newline at end of file diff --git a/pr/338/docs/search.index/path/f16d052caa1a.js b/pr/338/docs/search.index/path/3e0347ff70ce.js similarity index 97% rename from pr/338/docs/search.index/path/f16d052caa1a.js rename to pr/338/docs/search.index/path/3e0347ff70ce.js index 7db732c7a..d0e27c655 100644 --- a/pr/338/docs/search.index/path/f16d052caa1a.js +++ b/pr/338/docs/search.index/path/3e0347ff70ce.js @@ -1 +1 @@ -rd_("f[1,\"\"]0Al[10,\"core::ops\",\"core::ops\"]Ce[5,\"clap_builder::util::id\",\"clap_builder::util::id\"]22A`[10,\"core::any\"]Ao[5,\"alloc::sync\",\"alloc::sync\"]Al[5,\"iroh_quinn::congestion\"]Df[5,\"iroh_quinn_proto::congestion\",\"iroh_quinn_proto::congestion::bbr\"]Ba[5,\"alloc::boxed\",\"alloc::boxed\"]Cb[10,\"bytes::buf::buf_impl\",\"bytes::buf::buf_impl\"]Am[5,\"quinn_perf\",\"quinn_perf\"]A`[6,\"iroh_quinn\"]Bi[6,\"iroh_quinn_proto\",\"iroh_quinn_proto\"]Ae[10,\"core::ops::bit\"]Ac[5,\"bench\",\"bench\"]Ba[5,\"perf::client\",\"perf::client\"]Ba[5,\"perf::server\",\"perf::server\"]A`[10,\"core::cmp\"]Ak[5,\"core::pin\",\"core::pin\"]Am[5,\"alloc::vec\",\"alloc::vec\"]Bb[2,\"iroh_quinn_proto::congestion\"]f[1,\"\"]00Ad[2,\"iroh_quinn_udp\"]f[0,\"\"]2222Ak[10,\"clap_builder::derive\"]Bn[10,\"std::os::fd::owned\",\"std::os::fd::owned\"]Af[10,\"core::ops::drop\"]Ad[10,\"core::convert\"]Aa[10,\"core::hash\"]1Ah[5,\"iroh_quinn::crypto\"]Ci[5,\"iroh_quinn_proto::crypto\",\"iroh_quinn_proto::crypto\"]Bh[15,\"iroh_quinn_proto::ProtectedHeader\"]Ak[5,\"std::path\",\"std::path\"]Bc[5,\"iroh_quinn\",\"iroh_quinn::path\"]Bi[6,\"core::task::poll\",\"core::task::poll\"]Bb[10,\"core::marker\",\"core::marker\"]A`[6,\"iroh_quinn\"]Bi[6,\"iroh_quinn_proto\",\"iroh_quinn_proto\"]2Ah[10,\"ppv_lite86::types\"]f[1,\"\"]f[3,\"\"]A`[2,\"iroh_quinn\"]1An[2,\"iroh_quinn_proto::config\"]Bk[2,\"iroh_quinn_proto::connection::streams\"]0Ai[2,\"iroh_quinn::runtime\"]55Bd[10,\"core::convert\",\"core::convert\"]Ba[5,\"bytes::bytes\",\"bytes::bytes\"]A`[5,\"iroh_quinn\"]D`[5,\"iroh_quinn_proto\",\"iroh_quinn_proto::connection::assembler\"]Ab[10,\"core::clone\"]Cg[6,\"iroh_quinn_proto::frame\",\"iroh_quinn_proto::frame\"]Al[5,\"iroh_quinn::congestion\"]Dh[5,\"iroh_quinn_proto::congestion\",\"iroh_quinn_proto::congestion::cubic\"]A`[10,\"core::fmt\"]Ag[10,\"core::ops::deref\"]Ak[5,\"core::fmt\",\"core::fmt\"]Ab[10,\"core::error\"]Bc[6,\"rustls::error\",\"rustls::error\"]B`[2,\"iroh_quinn::crypto::rustls\"]Bf[2,\"iroh_quinn_proto::crypto::rustls\"]Dk[5,\"iroh_quinn_proto::transport_error\",\"iroh_quinn_proto::transport_error\"]Bi[6,\"arbitrary::error\",\"arbitrary::error\"]Ba[8,\"clap_builder\",\"clap_builder\"]B`[6,\"iroh_quinn::crypto::rustls\"]Bf[6,\"iroh_quinn_proto::crypto::rustls\"]Ee[6,\"iroh_quinn_proto::transport_parameters\",\"iroh_quinn_proto::transport_parameters\"]Ck[6,\"iroh_quinn_proto::iroh_hp\",\"iroh_quinn_proto::iroh_hp\"]Af[2,\"iroh_quinn_proto\"]Ce[6,\"iroh_quinn_proto\",\"iroh_quinn_proto::connection\"]2Bi[5,\"core::ops::range\",\"core::ops::range\"]Bh[15,\"iroh_quinn_proto::ProtectedHeader\"]0Bb[10,\"core::marker\",\"core::marker\"]Ba[5,\"bench::stats\",\"bench::stats\"]Ao[5,\"perf::stats\",\"perf::stats\"]Ba[5,\"rustls::quic\",\"rustls::quic\"]Ah[10,\"std::io\",\"std::io\"]f[1,\"\"]f[3,\"\"]Bb[2,\"iroh_quinn_proto::congestion\"]l[2,\"rustls\"]A`[5,\"iroh_quinn\"]Cl[5,\"iroh_quinn_proto\",\"iroh_quinn_proto::config::transport\"]Ae[10,\"tonic::request\"]Aa[10,\"iroh_quinn\"]Ch[10,\"iroh_quinn_proto\",\"iroh_quinn_proto::config::qlog\"]Bl[5,\"iroh_quinn\",\"iroh_quinn::runtime::smol\"]Af[2,\"iroh_quinn_proto\"]Cn[6,\"iroh_quinn_proto\",\"iroh_quinn_proto::connection::streams\"]Ba[5,\"bench::stats\",\"bench::stats\"]Ao[5,\"perf::stats\",\"perf::stats\"]Ci[5,\"ring::error::unspecified\",\"ring::error::unspecified\"]f[3,\"\"]A`[2,\"iroh_quinn\"]Bb[2,\"iroh_quinn_proto::connection\"]1Co[5,\"rustls::client::client_conn\",\"rustls::client::client_conn\"]Ci[5,\"iroh_quinn_proto::config\",\"iroh_quinn_proto::config\"]?Ai[10,\"iroh_quinn::crypto\"]Ca[5,\"iroh_quinn_proto\",\"iroh_quinn_proto::config\"]Cj[10,\"iroh_quinn_proto::crypto\",\"iroh_quinn_proto::crypto\"]A`[5,\"iroh_quinn\"]Cn[5,\"iroh_quinn_proto\",\"iroh_quinn_proto::connection::streams\"]Cm[6,\"iroh_quinn_proto::endpoint\",\"iroh_quinn_proto::endpoint\"]A`[6,\"iroh_quinn\"]Cc[6,\"iroh_quinn_proto\",\"iroh_quinn_proto::endpoint\"]Ci[5,\"iroh_quinn_proto::shared\",\"iroh_quinn_proto::shared\"]5Ca[5,\"iroh_quinn_proto\",\"iroh_quinn_proto::shared\"]C`[5,\"iroh_quinn_proto\",\"iroh_quinn_proto::frame\"]4Ca[6,\"iroh_quinn_proto\",\"iroh_quinn_proto::shared\"]Be[6,\"iroh_quinn_udp\",\"iroh_quinn_udp\"]Bm[8,\"core::num::nonzero\",\"core::num::nonzero\"]:C`[5,\"iroh_quinn_proto\",\"iroh_quinn_proto::token\"]Bb[15,\"iroh_quinn_proto::PathEvent\"]Bi[5,\"iroh_quinn\",\"iroh_quinn::connection\"]1Do[5,\"iroh_quinn_proto::connection::paths\",\"iroh_quinn_proto::connection::paths\"]Cl[5,\"iroh_quinn_proto\",\"iroh_quinn_proto::connection::paths\"]2Co[5,\"rustls::server::server_conn\",\"rustls::server::server_conn\"]Ci[5,\"iroh_quinn_proto::config\",\"iroh_quinn_proto::config\"]A`[5,\"iroh_quinn\"]Ai[10,\"iroh_quinn::crypto\"]Ca[5,\"iroh_quinn_proto\",\"iroh_quinn_proto::config\"]Cj[10,\"iroh_quinn_proto::crypto\",\"iroh_quinn_proto::crypto\"]Ce[5,\"core::net::socket_addr\",\"core::net::socket_addr\"]0Bj[6,\"iroh_quinn\",\"iroh_quinn::send_stream\"]Bm[5,\"iroh_quinn\",\"iroh_quinn::runtime::tokio\"]Cg[5,\"arbitrary::unstructured\",\"arbitrary::unstructured\"]j[2,\"perf\"]8Cj[5,\"iroh_quinn_proto\",\"iroh_quinn_proto::bloom_token_log\"]Ab[10,\"core::clone\"]Cc[6,\"iroh_quinn_proto\",\"iroh_quinn_proto::endpoint\"]Ca[5,\"iroh_quinn_proto\",\"iroh_quinn_proto::shared\"]Bg[5,\"iroh_quinn\",\"iroh_quinn::endpoint\"]B`[5,\"iroh_quinn::crypto::rustls\"]Di[5,\"iroh_quinn_proto::crypto::rustls\",\"iroh_quinn_proto::crypto::rustls\"]Bc[6,\"rustls::enums\",\"rustls::enums\"]Bb[15,\"iroh_quinn_proto::PathEvent\"]Al[5,\"iroh_quinn::congestion\"]Dk[5,\"iroh_quinn_proto::congestion\",\"iroh_quinn_proto::congestion::new_reno\"]Bi[5,\"core::num::error\",\"core::num::error\"]Ca[5,\"iroh_quinn_proto\",\"iroh_quinn_proto::packet\"]Ec[5,\"clap_builder::builder::possible_value\",\"clap_builder::builder::possible_value\"]Bi[6,\"rustls_pki_types\",\"rustls_pki_types\"]Dd[6,\"iroh_quinn_proto\",\"iroh_quinn_proto::connection::streams::recv\"]Cg[5,\"rustls::webpki::anchors\",\"rustls::webpki::anchors\"]A`[5,\"iroh_quinn\"]Ca[5,\"iroh_quinn_proto\",\"iroh_quinn_proto::config\"]Ci[5,\"iroh_quinn_proto::coding\",\"iroh_quinn_proto::coding\"]Af[2,\"iroh_quinn_proto\"]0f[3,\"\"]Bg[10,\"iroh_quinn\",\"iroh_quinn::runtime\"]Bi[5,\"rustls_pki_types\",\"rustls_pki_types\"]Da[6,\"iroh_quinn_proto::connection\",\"iroh_quinn_proto::connection\"]Ce[6,\"iroh_quinn_proto\",\"iroh_quinn_proto::connection\"]Ak[10,\"clap_builder::derive\"]An[15,\"iroh_quinn_proto::Event\"]:91Bg[5,\"iroh_quinn\",\"iroh_quinn::incoming\"]C`[5,\"iroh_quinn_proto\",\"iroh_quinn_proto::frame\"]Bc[6,\"rustls::error\",\"rustls::error\"]=C`[5,\"iroh_quinn_proto\",\"iroh_quinn_proto::token\"]1Bj[6,\"iroh_quinn\",\"iroh_quinn::recv_stream\"]0Cn[5,\"iroh_quinn_proto\",\"iroh_quinn_proto::connection::streams\"]Ba[5,\"bench::stats\",\"bench::stats\"]Af[5,\"iroh_quinn_proto\"]Bj[5,\"iroh_quinn_udp\",\"iroh_quinn_udp::imp\"]?A`[5,\"iroh_quinn\"]8A`[6,\"iroh_quinn\"]=Ca[5,\"iroh_quinn_proto\",\"iroh_quinn_proto::shared\"]2Cl[5,\"iroh_quinn_proto\",\"iroh_quinn_proto::connection::stats\"]Ba[5,\"rustls::rand\",\"rustls::rand\"]Ao[5,\"perf::stats\",\"perf::stats\"]Af[2,\"iroh_quinn_proto\"]Ca[6,\"iroh_quinn_proto\",\"iroh_quinn_proto::packet\"]7Cg[5,\"iroh_quinn_proto\",\"iroh_quinn_proto::config::qlog\"]Bc[6,\"rustls::enums\",\"rustls::enums\"]Ak[5,\"std::time\",\"std::time\"]:C`[5,\"iroh_quinn_proto\",\"iroh_quinn_proto::token\"]Do[5,\"iroh_quinn_proto::config::transport\",\"iroh_quinn_proto::config::transport\"]A`[5,\"iroh_quinn\"]Cl[5,\"iroh_quinn_proto\",\"iroh_quinn_proto::config::transport\"]Ae[10,\"tonic::request\"]Aa[10,\"iroh_quinn\"]Ch[10,\"iroh_quinn_proto\",\"iroh_quinn_proto::config::qlog\"]Bl[5,\"iroh_quinn\",\"iroh_quinn::runtime::smol\"]Af[2,\"iroh_quinn_proto\"]Cn[6,\"iroh_quinn_proto\",\"iroh_quinn_proto::connection::streams\"]Ba[5,\"bench::stats\",\"bench::stats\"]Ao[5,\"perf::stats\",\"perf::stats\"]Ci[5,\"ring::error::unspecified\",\"ring::error::unspecified\"]f[3,\"\"]A`[2,\"iroh_quinn\"]Bb[2,\"iroh_quinn_proto::connection\"]1Co[5,\"rustls::client::client_conn\",\"rustls::client::client_conn\"]Ci[5,\"iroh_quinn_proto::config\",\"iroh_quinn_proto::config\"]?Ai[10,\"iroh_quinn::crypto\"]Ca[5,\"iroh_quinn_proto\",\"iroh_quinn_proto::config\"]Cj[10,\"iroh_quinn_proto::crypto\",\"iroh_quinn_proto::crypto\"]A`[5,\"iroh_quinn\"]Cn[5,\"iroh_quinn_proto\",\"iroh_quinn_proto::connection::streams\"]Cm[6,\"iroh_quinn_proto::endpoint\",\"iroh_quinn_proto::endpoint\"]A`[6,\"iroh_quinn\"]Cc[6,\"iroh_quinn_proto\",\"iroh_quinn_proto::endpoint\"]Ci[5,\"iroh_quinn_proto::shared\",\"iroh_quinn_proto::shared\"]5Ca[5,\"iroh_quinn_proto\",\"iroh_quinn_proto::shared\"]C`[5,\"iroh_quinn_proto\",\"iroh_quinn_proto::frame\"]4Ca[6,\"iroh_quinn_proto\",\"iroh_quinn_proto::shared\"]Be[6,\"iroh_quinn_udp\",\"iroh_quinn_udp\"]Bm[8,\"core::num::nonzero\",\"core::num::nonzero\"]:C`[5,\"iroh_quinn_proto\",\"iroh_quinn_proto::token\"]Bb[15,\"iroh_quinn_proto::PathEvent\"]Bi[5,\"iroh_quinn\",\"iroh_quinn::connection\"]1Do[5,\"iroh_quinn_proto::connection::paths\",\"iroh_quinn_proto::connection::paths\"]Cl[5,\"iroh_quinn_proto\",\"iroh_quinn_proto::connection::paths\"]2Co[5,\"rustls::server::server_conn\",\"rustls::server::server_conn\"]Ci[5,\"iroh_quinn_proto::config\",\"iroh_quinn_proto::config\"]A`[5,\"iroh_quinn\"]Ai[10,\"iroh_quinn::crypto\"]Ca[5,\"iroh_quinn_proto\",\"iroh_quinn_proto::config\"]Cj[10,\"iroh_quinn_proto::crypto\",\"iroh_quinn_proto::crypto\"]Ce[5,\"core::net::socket_addr\",\"core::net::socket_addr\"]0Bj[6,\"iroh_quinn\",\"iroh_quinn::send_stream\"]Bm[5,\"iroh_quinn\",\"iroh_quinn::runtime::tokio\"]Cg[5,\"arbitrary::unstructured\",\"arbitrary::unstructured\"]j[2,\"perf\"]8Cj[5,\"iroh_quinn_proto\",\"iroh_quinn_proto::bloom_token_log\"]Ab[10,\"core::clone\"]Cc[6,\"iroh_quinn_proto\",\"iroh_quinn_proto::endpoint\"]Ca[5,\"iroh_quinn_proto\",\"iroh_quinn_proto::shared\"]Bg[5,\"iroh_quinn\",\"iroh_quinn::endpoint\"]B`[5,\"iroh_quinn::crypto::rustls\"]Di[5,\"iroh_quinn_proto::crypto::rustls\",\"iroh_quinn_proto::crypto::rustls\"]Bc[6,\"rustls::enums\",\"rustls::enums\"]Bb[15,\"iroh_quinn_proto::PathEvent\"]Al[5,\"iroh_quinn::congestion\"]Dk[5,\"iroh_quinn_proto::congestion\",\"iroh_quinn_proto::congestion::new_reno\"]Bi[5,\"core::num::error\",\"core::num::error\"]Ca[5,\"iroh_quinn_proto\",\"iroh_quinn_proto::packet\"]Ec[5,\"clap_builder::builder::possible_value\",\"clap_builder::builder::possible_value\"]Bi[6,\"rustls_pki_types\",\"rustls_pki_types\"]Dd[6,\"iroh_quinn_proto\",\"iroh_quinn_proto::connection::streams::recv\"]Cg[5,\"rustls::webpki::anchors\",\"rustls::webpki::anchors\"]A`[5,\"iroh_quinn\"]Ca[5,\"iroh_quinn_proto\",\"iroh_quinn_proto::config\"]Ci[5,\"iroh_quinn_proto::coding\",\"iroh_quinn_proto::coding\"]Af[2,\"iroh_quinn_proto\"]0f[3,\"\"]Bg[10,\"iroh_quinn\",\"iroh_quinn::runtime\"]Bi[5,\"rustls_pki_types\",\"rustls_pki_types\"]Da[6,\"iroh_quinn_proto::connection\",\"iroh_quinn_proto::connection\"]Ce[6,\"iroh_quinn_proto\",\"iroh_quinn_proto::connection\"]Ak[10,\"clap_builder::derive\"]An[15,\"iroh_quinn_proto::Event\"]:91Bg[5,\"iroh_quinn\",\"iroh_quinn::incoming\"]C`[5,\"iroh_quinn_proto\",\"iroh_quinn_proto::frame\"]Bc[6,\"rustls::error\",\"rustls::error\"]=C`[5,\"iroh_quinn_proto\",\"iroh_quinn_proto::token\"]1Bj[6,\"iroh_quinn\",\"iroh_quinn::recv_stream\"]0Cn[5,\"iroh_quinn_proto\",\"iroh_quinn_proto::connection::streams\"]Ba[5,\"bench::stats\",\"bench::stats\"]Af[5,\"iroh_quinn_proto\"]Bj[5,\"iroh_quinn_udp\",\"iroh_quinn_udp::imp\"]?A`[5,\"iroh_quinn\"]8A`[6,\"iroh_quinn\"]=Ca[5,\"iroh_quinn_proto\",\"iroh_quinn_proto::shared\"]2Cl[5,\"iroh_quinn_proto\",\"iroh_quinn_proto::connection::stats\"]Ba[5,\"rustls::rand\",\"rustls::rand\"]Ao[5,\"perf::stats\",\"perf::stats\"]Af[2,\"iroh_quinn_proto\"]Ca[6,\"iroh_quinn_proto\",\"iroh_quinn_proto::packet\"]7Cg[5,\"iroh_quinn_proto\",\"iroh_quinn_proto::config::qlog\"]Bc[6,\"rustls::enums\",\"rustls::enums\"]Ak[5,\"std::time\",\"std::time\"]:C`[5,\"iroh_quinn_proto\",\"iroh_quinn_proto::token\"]Do[5,\"iroh_quinn_proto::config::transport\",\"iroh_quinn_proto::config::transport\"]Settings

All

Rustdoc settings

Back
\ No newline at end of file +Settings

All

Rustdoc settings

Back
\ No newline at end of file diff --git a/pr/338/docs/src/iroh_quinn_proto/connection/mod.rs.html b/pr/338/docs/src/iroh_quinn_proto/connection/mod.rs.html index f50c7cf3c..7923194ce 100644 --- a/pr/338/docs/src/iroh_quinn_proto/connection/mod.rs.html +++ b/pr/338/docs/src/iroh_quinn_proto/connection/mod.rs.html @@ -226,7 +226,7 @@ 226 // Queued non-retransmittable 1-RTT data 227 // 228 /// If the CONNECTION_CLOSE frame needs to be sent -229 close: bool, +229 connection_close_pending: bool, 230 231 // 232 // ACK frequency @@ -342,6599 +342,6643 @@ 342 343#[derive(Debug)] 344enum PollPathSpaceOutcome { -345 /// One or more datagrams have been written into the [`TransmitBuf`]. -346 Send { -347 /// The highest packet number. -348 last_packet_number: u64, -349 /// Whether a next packet may be coalesced into the current datagram. -350 /// -351 /// If `Some` this signals that there is still enough space in the current datagram -352 /// of the [`TransmitBuf`] for another packet and the packets written so far allow -353 /// coalescing. -354 /// -355 /// The [`PadDatagram`] value indicates whether the final datagram containing the -356 /// coalesced packets must have an exact size. -357 may_coalesce: Option<PadDatagram>, -358 }, -359 /// Send a transmit directly, usually a hack to send off-path datagrams. -360 SendTransmit { transmit: Transmit }, -361 /// Nothing to send, nothing was written into the [`TransmitBuf`]. -362 // TODO: consider splitting this: NothingToSend, CongestionBlocked, TransmitFull -363 NothingToSend { -364 /// If true there was data to send but congestion control did not allow so. -365 congestion_blocked: bool, -366 }, -367} -368 -369impl Connection { -370 pub(crate) fn new( -371 endpoint_config: Arc<EndpointConfig>, -372 config: Arc<TransportConfig>, -373 init_cid: ConnectionId, -374 loc_cid: ConnectionId, -375 rem_cid: ConnectionId, -376 network_path: FourTuple, -377 crypto: Box<dyn crypto::Session>, -378 cid_gen: &dyn ConnectionIdGenerator, -379 now: Instant, -380 version: u32, -381 allow_mtud: bool, -382 rng_seed: [u8; 32], -383 side_args: SideArgs, -384 qlog: QlogSink, -385 ) -> Self { -386 let pref_addr_cid = side_args.pref_addr_cid(); -387 let path_validated = side_args.path_validated(); -388 let connection_side = ConnectionSide::from(side_args); -389 let side = connection_side.side(); -390 let mut rng = StdRng::from_seed(rng_seed); -391 let initial_space = { -392 let mut space = PacketSpace::new(now, SpaceId::Initial, &mut rng); -393 space.crypto = Some(crypto.initial_keys(init_cid, side)); -394 space -395 }; -396 let handshake_space = PacketSpace::new(now, SpaceId::Handshake, &mut rng); -397 #[cfg(test)] -398 let data_space = match config.deterministic_packet_numbers { -399 true => PacketSpace::new_deterministic(now, SpaceId::Data), -400 false => PacketSpace::new(now, SpaceId::Data, &mut rng), -401 }; -402 #[cfg(not(test))] -403 let data_space = PacketSpace::new(now, SpaceId::Data, &mut rng); -404 let state = State::handshake(state::Handshake { -405 rem_cid_set: side.is_server(), -406 expected_token: Bytes::new(), -407 client_hello: None, -408 allow_server_migration: side.is_client(), -409 }); -410 let local_cid_state = FxHashMap::from_iter([( -411 PathId::ZERO, -412 CidState::new( -413 cid_gen.cid_len(), -414 cid_gen.cid_lifetime(), -415 now, -416 if pref_addr_cid.is_some() { 2 } else { 1 }, -417 ), -418 )]); -419 -420 let mut path = PathData::new(network_path, allow_mtud, None, 0, now, &config); -421 // TODO(@divma): consider if we want to delay this until the path is validated -422 path.open = true; -423 let mut this = Self { -424 endpoint_config, -425 crypto, -426 handshake_cid: loc_cid, -427 rem_handshake_cid: rem_cid, -428 local_cid_state, -429 paths: BTreeMap::from_iter([( -430 PathId::ZERO, -431 PathState { -432 data: path, -433 prev: None, -434 }, -435 )]), -436 path_generation_counter: 0, -437 allow_mtud, -438 state, -439 side: connection_side, -440 zero_rtt_enabled: false, -441 zero_rtt_crypto: None, -442 key_phase: false, -443 // A small initial key phase size ensures peers that don't handle key updates correctly -444 // fail sooner rather than later. It's okay for both peers to do this, as the first one -445 // to perform an update will reset the other's key phase size in `update_keys`, and a -446 // simultaneous key update by both is just like a regular key update with a really fast -447 // response. Inspired by quic-go's similar behavior of performing the first key update -448 // at the 100th short-header packet. -449 key_phase_size: rng.random_range(10..1000), -450 peer_params: TransportParameters::default(), -451 orig_rem_cid: rem_cid, -452 initial_dst_cid: init_cid, -453 retry_src_cid: None, -454 events: VecDeque::new(), -455 endpoint_events: VecDeque::new(), -456 spin_enabled: config.allow_spin && rng.random_ratio(7, 8), -457 spin: false, -458 spaces: [initial_space, handshake_space, data_space], -459 highest_space: SpaceId::Initial, -460 prev_crypto: None, -461 next_crypto: None, -462 accepted_0rtt: false, -463 permit_idle_reset: true, -464 idle_timeout: match config.max_idle_timeout { -465 None | Some(VarInt(0)) => None, -466 Some(dur) => Some(Duration::from_millis(dur.0)), -467 }, -468 timers: TimerTable::default(), -469 authentication_failures: 0, -470 close: false, -471 -472 ack_frequency: AckFrequencyState::new(get_max_ack_delay( -473 &TransportParameters::default(), -474 )), -475 -476 app_limited: false, -477 receiving_ecn: false, -478 total_authed_packets: 0, -479 -480 next_observed_addr_seq_no: 0u32.into(), -481 -482 streams: StreamsState::new( -483 side, -484 config.max_concurrent_uni_streams, -485 config.max_concurrent_bidi_streams, -486 config.send_window, -487 config.receive_window, -488 config.stream_receive_window, -489 ), -490 datagrams: DatagramState::default(), -491 config, -492 rem_cids: FxHashMap::from_iter([(PathId::ZERO, CidQueue::new(rem_cid))]), -493 rng, -494 stats: ConnectionStats::default(), -495 path_stats: Default::default(), -496 version, -497 -498 // peer params are not yet known, so multipath is not enabled -499 max_concurrent_paths: NonZeroU32::MIN, -500 local_max_path_id: PathId::ZERO, -501 remote_max_path_id: PathId::ZERO, -502 max_path_id_with_cids: PathId::ZERO, -503 abandoned_paths: Default::default(), -504 -505 // iroh's nat traversal -506 iroh_hp: Default::default(), -507 qlog, -508 }; -509 if path_validated { -510 this.on_path_validated(PathId::ZERO); -511 } -512 if side.is_client() { -513 // Kick off the connection -514 this.write_crypto(); -515 this.init_0rtt(now); -516 } -517 this.qlog -518 .emit_tuple_assigned(PathId::ZERO, network_path, now); -519 this -520 } -521 -522 /// Returns the next time at which `handle_timeout` should be called -523 /// -524 /// The value returned may change after: -525 /// - the application performed some I/O on the connection -526 /// - a call was made to `handle_event` -527 /// - a call to `poll_transmit` returned `Some` -528 /// - a call was made to `handle_timeout` -529 #[must_use] -530 pub fn poll_timeout(&mut self) -> Option<Instant> { -531 self.timers.peek() -532 } -533 -534 /// Returns application-facing events -535 /// -536 /// Connections should be polled for events after: -537 /// - a call was made to `handle_event` -538 /// - a call was made to `handle_timeout` -539 #[must_use] -540 pub fn poll(&mut self) -> Option<Event> { -541 if let Some(x) = self.events.pop_front() { -542 return Some(x); -543 } -544 -545 if let Some(event) = self.streams.poll() { -546 return Some(Event::Stream(event)); -547 } -548 -549 if let Some(reason) = self.state.take_error() { -550 return Some(Event::ConnectionLost { reason }); -551 } -552 -553 None -554 } -555 -556 /// Return endpoint-facing events -557 #[must_use] -558 pub fn poll_endpoint_events(&mut self) -> Option<EndpointEvent> { -559 self.endpoint_events.pop_front().map(EndpointEvent) -560 } -561 -562 /// Provide control over streams -563 #[must_use] -564 pub fn streams(&mut self) -> Streams<'_> { -565 Streams { -566 state: &mut self.streams, -567 conn_state: &self.state, -568 } -569 } -570 -571 /// Provide control over streams -572 #[must_use] -573 pub fn recv_stream(&mut self, id: StreamId) -> RecvStream<'_> { -574 assert!(id.dir() == Dir::Bi || id.initiator() != self.side.side()); -575 RecvStream { -576 id, -577 state: &mut self.streams, -578 pending: &mut self.spaces[SpaceId::Data].pending, -579 } -580 } -581 -582 /// Provide control over streams -583 #[must_use] -584 pub fn send_stream(&mut self, id: StreamId) -> SendStream<'_> { -585 assert!(id.dir() == Dir::Bi || id.initiator() == self.side.side()); -586 SendStream { -587 id, -588 state: &mut self.streams, -589 pending: &mut self.spaces[SpaceId::Data].pending, -590 conn_state: &self.state, -591 } -592 } -593 -594 /// Opens a new path only if no path on the same network path currently exists. -595 /// -596 /// This comparison will use [`FourTuple::is_probably_same_path`] on the given `network_path` -597 /// and pass it existing path's network paths. -598 /// -599 /// This means that you can pass `local_ip: None` to make the comparison only compare -600 /// remote addresses. -601 /// -602 /// This avoids having to guess which local interface will be used to communicate with the -603 /// remote, should it not be known yet. We assume that if we already have a path to the remote, -604 /// the OS is likely to use the same interface to talk to said remote. -605 /// -606 /// See also [`open_path`]. Returns `(path_id, true)` if the path already existed. `(path_id, -607 /// false)` if was opened. -608 /// -609 /// [`open_path`]: Connection::open_path -610 pub fn open_path_ensure( -611 &mut self, -612 network_path: FourTuple, -613 initial_status: PathStatus, -614 now: Instant, -615 ) -> Result<(PathId, bool), PathError> { -616 let existing_open_path = self.paths.iter().find(|(id, path)| { -617 network_path.is_probably_same_path(&path.data.network_path) -618 && !self.abandoned_paths.contains(*id) -619 }); -620 match existing_open_path { -621 Some((path_id, _state)) => Ok((*path_id, true)), -622 None => Ok((self.open_path(network_path, initial_status, now)?, false)), -623 } -624 } -625 -626 /// Opens a new path -627 /// -628 /// Further errors might occur and they will be emitted in [`PathEvent::LocallyClosed`] events. -629 /// When the path is opened it will be reported as an [`PathEvent::Opened`]. -630 pub fn open_path( -631 &mut self, -632 network_path: FourTuple, -633 initial_status: PathStatus, -634 now: Instant, -635 ) -> Result<PathId, PathError> { -636 if !self.is_multipath_negotiated() { -637 return Err(PathError::MultipathNotNegotiated); -638 } -639 if self.side().is_server() { -640 return Err(PathError::ServerSideNotAllowed); -641 } -642 -643 let max_abandoned = self.abandoned_paths.iter().max().copied(); -644 let max_used = self.paths.keys().last().copied(); -645 let path_id = max_abandoned -646 .max(max_used) -647 .unwrap_or(PathId::ZERO) -648 .saturating_add(1u8); -649 -650 if Some(path_id) > self.max_path_id() { -651 return Err(PathError::MaxPathIdReached); +345 /// Nothing to send in the space, nothing was written into the [`TransmitBuf`]. +346 NothingToSend { +347 /// If true there was data to send but congestion control did not allow so. +348 congestion_blocked: bool, +349 }, +350 /// One or more packets have been written into the [`TransmitBuf`]. +351 WrotePacket { +352 /// The highest packet number. +353 last_packet_number: u64, +354 /// Whether to pad an already started datagram in the next packet. +355 /// +356 /// When packets in Initial, 0-RTT or Handhake packet do not fill the entire +357 /// datagram they may decide to coalesce with the next packet from a higher +358 /// encryption level on the same path. But the earlier packet may require specific +359 /// size requirements for the datagram they are sent in. +360 /// +361 /// If a space did not complete the datagram, they use this to request the correct +362 /// padding in the final packet of the datagram so that the final datagram will have +363 /// the correct size. +364 /// +365 /// If a space did fill an entire datagram, it leaves this to the default of +366 /// [`PadDatagram::No`]. +367 pad_datagram: PadDatagram, +368 }, +369 /// Send the contents of the transmit immediately. +370 /// +371 /// Packets were written and the GSO batch must end now, regardless from whether higher +372 /// spaces still have frames to write. This is used when the last datagram written would +373 /// require too much padding to continue a GSO batch, which would waste space on the +374 /// wire. +375 Send { +376 /// The highest packet number written into the transmit. +377 last_packet_number: u64, +378 }, +379 /// Send a transmit directly, usually a hack to send off-path datagrams. +380 SendTransmit { transmit: Transmit }, +381} +382 +383impl Connection { +384 pub(crate) fn new( +385 endpoint_config: Arc<EndpointConfig>, +386 config: Arc<TransportConfig>, +387 init_cid: ConnectionId, +388 loc_cid: ConnectionId, +389 rem_cid: ConnectionId, +390 network_path: FourTuple, +391 crypto: Box<dyn crypto::Session>, +392 cid_gen: &dyn ConnectionIdGenerator, +393 now: Instant, +394 version: u32, +395 allow_mtud: bool, +396 rng_seed: [u8; 32], +397 side_args: SideArgs, +398 qlog: QlogSink, +399 ) -> Self { +400 let pref_addr_cid = side_args.pref_addr_cid(); +401 let path_validated = side_args.path_validated(); +402 let connection_side = ConnectionSide::from(side_args); +403 let side = connection_side.side(); +404 let mut rng = StdRng::from_seed(rng_seed); +405 let initial_space = { +406 let mut space = PacketSpace::new(now, SpaceId::Initial, &mut rng); +407 space.crypto = Some(crypto.initial_keys(init_cid, side)); +408 space +409 }; +410 let handshake_space = PacketSpace::new(now, SpaceId::Handshake, &mut rng); +411 #[cfg(test)] +412 let data_space = match config.deterministic_packet_numbers { +413 true => PacketSpace::new_deterministic(now, SpaceId::Data), +414 false => PacketSpace::new(now, SpaceId::Data, &mut rng), +415 }; +416 #[cfg(not(test))] +417 let data_space = PacketSpace::new(now, SpaceId::Data, &mut rng); +418 let state = State::handshake(state::Handshake { +419 rem_cid_set: side.is_server(), +420 expected_token: Bytes::new(), +421 client_hello: None, +422 allow_server_migration: side.is_client(), +423 }); +424 let local_cid_state = FxHashMap::from_iter([( +425 PathId::ZERO, +426 CidState::new( +427 cid_gen.cid_len(), +428 cid_gen.cid_lifetime(), +429 now, +430 if pref_addr_cid.is_some() { 2 } else { 1 }, +431 ), +432 )]); +433 +434 let mut path = PathData::new(network_path, allow_mtud, None, 0, now, &config); +435 // TODO(@divma): consider if we want to delay this until the path is validated +436 path.open = true; +437 let mut this = Self { +438 endpoint_config, +439 crypto, +440 handshake_cid: loc_cid, +441 rem_handshake_cid: rem_cid, +442 local_cid_state, +443 paths: BTreeMap::from_iter([( +444 PathId::ZERO, +445 PathState { +446 data: path, +447 prev: None, +448 }, +449 )]), +450 path_generation_counter: 0, +451 allow_mtud, +452 state, +453 side: connection_side, +454 zero_rtt_enabled: false, +455 zero_rtt_crypto: None, +456 key_phase: false, +457 // A small initial key phase size ensures peers that don't handle key updates correctly +458 // fail sooner rather than later. It's okay for both peers to do this, as the first one +459 // to perform an update will reset the other's key phase size in `update_keys`, and a +460 // simultaneous key update by both is just like a regular key update with a really fast +461 // response. Inspired by quic-go's similar behavior of performing the first key update +462 // at the 100th short-header packet. +463 key_phase_size: rng.random_range(10..1000), +464 peer_params: TransportParameters::default(), +465 orig_rem_cid: rem_cid, +466 initial_dst_cid: init_cid, +467 retry_src_cid: None, +468 events: VecDeque::new(), +469 endpoint_events: VecDeque::new(), +470 spin_enabled: config.allow_spin && rng.random_ratio(7, 8), +471 spin: false, +472 spaces: [initial_space, handshake_space, data_space], +473 highest_space: SpaceId::Initial, +474 prev_crypto: None, +475 next_crypto: None, +476 accepted_0rtt: false, +477 permit_idle_reset: true, +478 idle_timeout: match config.max_idle_timeout { +479 None | Some(VarInt(0)) => None, +480 Some(dur) => Some(Duration::from_millis(dur.0)), +481 }, +482 timers: TimerTable::default(), +483 authentication_failures: 0, +484 connection_close_pending: false, +485 +486 ack_frequency: AckFrequencyState::new(get_max_ack_delay( +487 &TransportParameters::default(), +488 )), +489 +490 app_limited: false, +491 receiving_ecn: false, +492 total_authed_packets: 0, +493 +494 next_observed_addr_seq_no: 0u32.into(), +495 +496 streams: StreamsState::new( +497 side, +498 config.max_concurrent_uni_streams, +499 config.max_concurrent_bidi_streams, +500 config.send_window, +501 config.receive_window, +502 config.stream_receive_window, +503 ), +504 datagrams: DatagramState::default(), +505 config, +506 rem_cids: FxHashMap::from_iter([(PathId::ZERO, CidQueue::new(rem_cid))]), +507 rng, +508 stats: ConnectionStats::default(), +509 path_stats: Default::default(), +510 version, +511 +512 // peer params are not yet known, so multipath is not enabled +513 max_concurrent_paths: NonZeroU32::MIN, +514 local_max_path_id: PathId::ZERO, +515 remote_max_path_id: PathId::ZERO, +516 max_path_id_with_cids: PathId::ZERO, +517 abandoned_paths: Default::default(), +518 +519 // iroh's nat traversal +520 iroh_hp: Default::default(), +521 qlog, +522 }; +523 if path_validated { +524 this.on_path_validated(PathId::ZERO); +525 } +526 if side.is_client() { +527 // Kick off the connection +528 this.write_crypto(); +529 this.init_0rtt(now); +530 } +531 this.qlog +532 .emit_tuple_assigned(PathId::ZERO, network_path, now); +533 this +534 } +535 +536 /// Returns the next time at which `handle_timeout` should be called +537 /// +538 /// The value returned may change after: +539 /// - the application performed some I/O on the connection +540 /// - a call was made to `handle_event` +541 /// - a call to `poll_transmit` returned `Some` +542 /// - a call was made to `handle_timeout` +543 #[must_use] +544 pub fn poll_timeout(&mut self) -> Option<Instant> { +545 self.timers.peek() +546 } +547 +548 /// Returns application-facing events +549 /// +550 /// Connections should be polled for events after: +551 /// - a call was made to `handle_event` +552 /// - a call was made to `handle_timeout` +553 #[must_use] +554 pub fn poll(&mut self) -> Option<Event> { +555 if let Some(x) = self.events.pop_front() { +556 return Some(x); +557 } +558 +559 if let Some(event) = self.streams.poll() { +560 return Some(Event::Stream(event)); +561 } +562 +563 if let Some(reason) = self.state.take_error() { +564 return Some(Event::ConnectionLost { reason }); +565 } +566 +567 None +568 } +569 +570 /// Return endpoint-facing events +571 #[must_use] +572 pub fn poll_endpoint_events(&mut self) -> Option<EndpointEvent> { +573 self.endpoint_events.pop_front().map(EndpointEvent) +574 } +575 +576 /// Provide control over streams +577 #[must_use] +578 pub fn streams(&mut self) -> Streams<'_> { +579 Streams { +580 state: &mut self.streams, +581 conn_state: &self.state, +582 } +583 } +584 +585 /// Provide control over streams +586 #[must_use] +587 pub fn recv_stream(&mut self, id: StreamId) -> RecvStream<'_> { +588 assert!(id.dir() == Dir::Bi || id.initiator() != self.side.side()); +589 RecvStream { +590 id, +591 state: &mut self.streams, +592 pending: &mut self.spaces[SpaceId::Data].pending, +593 } +594 } +595 +596 /// Provide control over streams +597 #[must_use] +598 pub fn send_stream(&mut self, id: StreamId) -> SendStream<'_> { +599 assert!(id.dir() == Dir::Bi || id.initiator() == self.side.side()); +600 SendStream { +601 id, +602 state: &mut self.streams, +603 pending: &mut self.spaces[SpaceId::Data].pending, +604 conn_state: &self.state, +605 } +606 } +607 +608 /// Opens a new path only if no path on the same network path currently exists. +609 /// +610 /// This comparison will use [`FourTuple::is_probably_same_path`] on the given `network_path` +611 /// and pass it existing path's network paths. +612 /// +613 /// This means that you can pass `local_ip: None` to make the comparison only compare +614 /// remote addresses. +615 /// +616 /// This avoids having to guess which local interface will be used to communicate with the +617 /// remote, should it not be known yet. We assume that if we already have a path to the remote, +618 /// the OS is likely to use the same interface to talk to said remote. +619 /// +620 /// See also [`open_path`]. Returns `(path_id, true)` if the path already existed. `(path_id, +621 /// false)` if was opened. +622 /// +623 /// [`open_path`]: Connection::open_path +624 pub fn open_path_ensure( +625 &mut self, +626 network_path: FourTuple, +627 initial_status: PathStatus, +628 now: Instant, +629 ) -> Result<(PathId, bool), PathError> { +630 let existing_open_path = self.paths.iter().find(|(id, path)| { +631 network_path.is_probably_same_path(&path.data.network_path) +632 && !self.abandoned_paths.contains(*id) +633 }); +634 match existing_open_path { +635 Some((path_id, _state)) => Ok((*path_id, true)), +636 None => Ok((self.open_path(network_path, initial_status, now)?, false)), +637 } +638 } +639 +640 /// Opens a new path +641 /// +642 /// Further errors might occur and they will be emitted in [`PathEvent::LocallyClosed`] events. +643 /// When the path is opened it will be reported as an [`PathEvent::Opened`]. +644 pub fn open_path( +645 &mut self, +646 network_path: FourTuple, +647 initial_status: PathStatus, +648 now: Instant, +649 ) -> Result<PathId, PathError> { +650 if !self.is_multipath_negotiated() { +651 return Err(PathError::MultipathNotNegotiated); 652 } -653 if path_id > self.remote_max_path_id { -654 self.spaces[SpaceId::Data].pending.paths_blocked = true; -655 return Err(PathError::MaxPathIdReached); -656 } -657 if self.rem_cids.get(&path_id).map(CidQueue::active).is_none() { -658 self.spaces[SpaceId::Data] -659 .pending -660 .path_cids_blocked -661 .insert(path_id); -662 return Err(PathError::RemoteCidsExhausted); -663 } -664 -665 let path = self.ensure_path(path_id, network_path, now, None); -666 path.status.local_update(initial_status); -667 -668 Ok(path_id) -669 } -670 -671 /// Closes a path by sending a PATH_ABANDON frame -672 /// -673 /// This will not allow closing the last path. It does allow closing paths which have -674 /// not yet been opened, as e.g. is the case when receiving a PATH_ABANDON from the peer -675 /// for a path that was never opened locally. -676 pub fn close_path( -677 &mut self, -678 now: Instant, -679 path_id: PathId, -680 error_code: VarInt, -681 ) -> Result<(), ClosePathError> { -682 if self.abandoned_paths.contains(&path_id) -683 || Some(path_id) > self.max_path_id() -684 || !self.paths.contains_key(&path_id) -685 { -686 return Err(ClosePathError::ClosedPath); -687 } -688 if self -689 .paths -690 .iter() -691 // Would there be any remaining, non-abandoned, validated paths -692 .any(|(id, path)| { -693 *id != path_id && !self.abandoned_paths.contains(id) && path.data.validated -694 }) -695 .not() -696 { -697 return Err(ClosePathError::LastOpenPath); -698 } -699 -700 // Send PATH_ABANDON -701 self.spaces[SpaceId::Data] -702 .pending -703 .path_abandon -704 .insert(path_id, error_code.into()); -705 -706 // Remove pending NEW CIDs for this path -707 let pending_space = &mut self.spaces[SpaceId::Data].pending; -708 pending_space.new_cids.retain(|cid| cid.path_id != path_id); -709 pending_space.path_cids_blocked.retain(|&id| id != path_id); -710 pending_space.path_status.retain(|&id| id != path_id); -711 -712 // Cleanup retransmits across ALL paths (CIDs for path_id may have been transmitted on other paths) -713 for space in self.spaces[SpaceId::Data].iter_paths_mut() { -714 for sent_packet in space.sent_packets.values_mut() { -715 if let Some(retransmits) = sent_packet.retransmits.get_mut() { -716 retransmits.new_cids.retain(|cid| cid.path_id != path_id); -717 retransmits.path_cids_blocked.retain(|&id| id != path_id); -718 retransmits.path_status.retain(|&id| id != path_id); -719 } -720 } -721 } -722 -723 // Consider remotely issued CIDs as retired. -724 // Technically we don't have to do this just yet. We only need to do this *after* -725 // the ABANDON_PATH frame is sent, allowing us to still send it on the -726 // to-be-abandoned path. However it is recommended to send it on another path, and -727 // we do not allow abandoning the last path anyway. -728 self.rem_cids.remove(&path_id); -729 self.endpoint_events -730 .push_back(EndpointEventInner::RetireResetToken(path_id)); -731 -732 self.abandoned_paths.insert(path_id); -733 -734 self.set_max_path_id(now, self.local_max_path_id.saturating_add(1u8)); -735 -736 Ok(()) -737 } -738 -739 /// Gets the [`PathData`] for a known [`PathId`]. -740 /// -741 /// Will panic if the path_id does not reference any known path. -742 #[track_caller] -743 fn path_data(&self, path_id: PathId) -> &PathData { -744 if let Some(data) = self.paths.get(&path_id) { -745 &data.data -746 } else { -747 panic!( -748 "unknown path: {path_id}, currently known paths: {:?}", -749 self.paths.keys().collect::<Vec<_>>() -750 ); -751 } -752 } -753 -754 /// Gets a reference to the [`PathData`] for a [`PathId`] -755 fn path(&self, path_id: PathId) -> Option<&PathData> { -756 self.paths.get(&path_id).map(|path_state| &path_state.data) -757 } -758 -759 /// Gets a mutable reference to the [`PathData`] for a [`PathId`] -760 fn path_mut(&mut self, path_id: PathId) -> Option<&mut PathData> { -761 self.paths -762 .get_mut(&path_id) -763 .map(|path_state| &mut path_state.data) -764 } -765 -766 /// Returns all known paths. -767 /// -768 /// There is no guarantee any of these paths are open or usable. -769 pub fn paths(&self) -> Vec<PathId> { -770 self.paths.keys().copied().collect() +653 if self.side().is_server() { +654 return Err(PathError::ServerSideNotAllowed); +655 } +656 +657 let max_abandoned = self.abandoned_paths.iter().max().copied(); +658 let max_used = self.paths.keys().last().copied(); +659 let path_id = max_abandoned +660 .max(max_used) +661 .unwrap_or(PathId::ZERO) +662 .saturating_add(1u8); +663 +664 if Some(path_id) > self.max_path_id() { +665 return Err(PathError::MaxPathIdReached); +666 } +667 if path_id > self.remote_max_path_id { +668 self.spaces[SpaceId::Data].pending.paths_blocked = true; +669 return Err(PathError::MaxPathIdReached); +670 } +671 if self.rem_cids.get(&path_id).map(CidQueue::active).is_none() { +672 self.spaces[SpaceId::Data] +673 .pending +674 .path_cids_blocked +675 .insert(path_id); +676 return Err(PathError::RemoteCidsExhausted); +677 } +678 +679 let path = self.ensure_path(path_id, network_path, now, None); +680 path.status.local_update(initial_status); +681 +682 Ok(path_id) +683 } +684 +685 /// Closes a path by sending a PATH_ABANDON frame +686 /// +687 /// This will not allow closing the last path. It does allow closing paths which have +688 /// not yet been opened, as e.g. is the case when receiving a PATH_ABANDON from the peer +689 /// for a path that was never opened locally. +690 pub fn close_path( +691 &mut self, +692 now: Instant, +693 path_id: PathId, +694 error_code: VarInt, +695 ) -> Result<(), ClosePathError> { +696 if self.abandoned_paths.contains(&path_id) +697 || Some(path_id) > self.max_path_id() +698 || !self.paths.contains_key(&path_id) +699 { +700 return Err(ClosePathError::ClosedPath); +701 } +702 if self +703 .paths +704 .iter() +705 // Would there be any remaining, non-abandoned, validated paths +706 .any(|(id, path)| { +707 *id != path_id && !self.abandoned_paths.contains(id) && path.data.validated +708 }) +709 .not() +710 { +711 return Err(ClosePathError::LastOpenPath); +712 } +713 +714 // Send PATH_ABANDON +715 self.spaces[SpaceId::Data] +716 .pending +717 .path_abandon +718 .insert(path_id, error_code.into()); +719 +720 // Remove pending NEW CIDs for this path +721 let pending_space = &mut self.spaces[SpaceId::Data].pending; +722 pending_space.new_cids.retain(|cid| cid.path_id != path_id); +723 pending_space.path_cids_blocked.retain(|&id| id != path_id); +724 pending_space.path_status.retain(|&id| id != path_id); +725 +726 // Cleanup retransmits across ALL paths (CIDs for path_id may have been transmitted on other paths) +727 for space in self.spaces[SpaceId::Data].iter_paths_mut() { +728 for sent_packet in space.sent_packets.values_mut() { +729 if let Some(retransmits) = sent_packet.retransmits.get_mut() { +730 retransmits.new_cids.retain(|cid| cid.path_id != path_id); +731 retransmits.path_cids_blocked.retain(|&id| id != path_id); +732 retransmits.path_status.retain(|&id| id != path_id); +733 } +734 } +735 } +736 +737 // Consider remotely issued CIDs as retired. +738 // Technically we don't have to do this just yet. We only need to do this *after* +739 // the ABANDON_PATH frame is sent, allowing us to still send it on the +740 // to-be-abandoned path. However it is recommended to send it on another path, and +741 // we do not allow abandoning the last path anyway. +742 self.rem_cids.remove(&path_id); +743 self.endpoint_events +744 .push_back(EndpointEventInner::RetireResetToken(path_id)); +745 +746 self.abandoned_paths.insert(path_id); +747 +748 self.set_max_path_id(now, self.local_max_path_id.saturating_add(1u8)); +749 +750 Ok(()) +751 } +752 +753 /// Gets the [`PathData`] for a known [`PathId`]. +754 /// +755 /// Will panic if the path_id does not reference any known path. +756 #[track_caller] +757 fn path_data(&self, path_id: PathId) -> &PathData { +758 if let Some(data) = self.paths.get(&path_id) { +759 &data.data +760 } else { +761 panic!( +762 "unknown path: {path_id}, currently known paths: {:?}", +763 self.paths.keys().collect::<Vec<_>>() +764 ); +765 } +766 } +767 +768 /// Gets a reference to the [`PathData`] for a [`PathId`] +769 fn path(&self, path_id: PathId) -> Option<&PathData> { +770 self.paths.get(&path_id).map(|path_state| &path_state.data) 771 } 772 -773 /// Gets the local [`PathStatus`] for a known [`PathId`] -774 pub fn path_status(&self, path_id: PathId) -> Result<PathStatus, ClosedPath> { -775 self.path(path_id) -776 .map(PathData::local_status) -777 .ok_or(ClosedPath { _private: () }) +773 /// Gets a mutable reference to the [`PathData`] for a [`PathId`] +774 fn path_mut(&mut self, path_id: PathId) -> Option<&mut PathData> { +775 self.paths +776 .get_mut(&path_id) +777 .map(|path_state| &mut path_state.data) 778 } 779 -780 /// Returns the path's network path represented as a 4-tuple. -781 pub fn network_path(&self, path_id: PathId) -> Result<FourTuple, ClosedPath> { -782 self.path(path_id) -783 .map(|path| path.network_path) -784 .ok_or(ClosedPath { _private: () }) +780 /// Returns all known paths. +781 /// +782 /// There is no guarantee any of these paths are open or usable. +783 pub fn paths(&self) -> Vec<PathId> { +784 self.paths.keys().copied().collect() 785 } 786 -787 /// Sets the [`PathStatus`] for a known [`PathId`] -788 /// -789 /// Returns the previous path status on success. -790 pub fn set_path_status( -791 &mut self, -792 path_id: PathId, -793 status: PathStatus, -794 ) -> Result<PathStatus, SetPathStatusError> { -795 if !self.is_multipath_negotiated() { -796 return Err(SetPathStatusError::MultipathNotNegotiated); -797 } -798 let path = self -799 .path_mut(path_id) -800 .ok_or(SetPathStatusError::ClosedPath)?; -801 let prev = match path.status.local_update(status) { -802 Some(prev) => { -803 self.spaces[SpaceId::Data] -804 .pending -805 .path_status -806 .insert(path_id); -807 prev -808 } -809 None => path.local_status(), -810 }; -811 Ok(prev) -812 } -813 -814 /// Returns the remote path status -815 // TODO(flub): Probably should also be some kind of path event? Not even sure if I like -816 // this as an API, but for now it allows me to write a test easily. -817 // TODO(flub): Technically this should be a Result<Option<PathSTatus>>? -818 pub fn remote_path_status(&self, path_id: PathId) -> Option<PathStatus> { -819 self.path(path_id).and_then(|path| path.remote_status()) -820 } -821 -822 /// Sets the max_idle_timeout for a specific path -823 /// -824 /// See [`TransportConfig::default_path_max_idle_timeout`] for details. -825 /// -826 /// Returns the previous value of the setting. -827 pub fn set_path_max_idle_timeout( -828 &mut self, -829 path_id: PathId, -830 timeout: Option<Duration>, -831 ) -> Result<Option<Duration>, ClosedPath> { -832 let path = self -833 .paths -834 .get_mut(&path_id) -835 .ok_or(ClosedPath { _private: () })?; -836 Ok(std::mem::replace(&mut path.data.idle_timeout, timeout)) -837 } -838 -839 /// Sets the keep_alive_interval for a specific path -840 /// -841 /// See [`TransportConfig::default_path_keep_alive_interval`] for details. -842 /// -843 /// Returns the previous value of the setting. -844 pub fn set_path_keep_alive_interval( -845 &mut self, -846 path_id: PathId, -847 interval: Option<Duration>, -848 ) -> Result<Option<Duration>, ClosedPath> { -849 let path = self -850 .paths -851 .get_mut(&path_id) -852 .ok_or(ClosedPath { _private: () })?; -853 Ok(std::mem::replace(&mut path.data.keep_alive, interval)) -854 } -855 -856 /// Gets the [`PathData`] for a known [`PathId`]. -857 /// -858 /// Will panic if the path_id does not reference any known path. -859 #[track_caller] -860 fn path_data_mut(&mut self, path_id: PathId) -> &mut PathData { -861 &mut self.paths.get_mut(&path_id).expect("known path").data -862 } -863 -864 /// Find an open, validated path that's on the same network path as the given network path. -865 /// -866 /// Returns the first path matching, even if there's multiple. -867 fn find_validated_path_on_network_path( -868 &self, -869 network_path: FourTuple, -870 ) -> Option<(&PathId, &PathState)> { -871 self.paths.iter().find(|(path_id, path_state)| { -872 path_state.data.validated -873 // Would this use the same network path, if network_path were used to send right now? -874 && network_path.is_probably_same_path(&path_state.data.network_path) -875 && !self.abandoned_paths.contains(path_id) -876 }) -877 // TODO(@divma): we might want to ensure the path has been recently active to consider the -878 // address validated -879 // matheus23: Perhaps looking at !self.abandoned_paths.contains(path_id) is enough, given keep-alives? -880 } -881 -882 fn ensure_path( -883 &mut self, -884 path_id: PathId, -885 network_path: FourTuple, -886 now: Instant, -887 pn: Option<u64>, -888 ) -> &mut PathData { -889 let valid_path = self.find_validated_path_on_network_path(network_path); -890 let validated = valid_path.is_some(); -891 let initial_rtt = valid_path.map(|(_, path)| path.data.rtt.conservative()); -892 let vacant_entry = match self.paths.entry(path_id) { -893 btree_map::Entry::Vacant(vacant_entry) => vacant_entry, -894 btree_map::Entry::Occupied(occupied_entry) => { -895 return &mut occupied_entry.into_mut().data; -896 } -897 }; -898 -899 debug!(%validated, %path_id, %network_path, "path added"); -900 let peer_max_udp_payload_size = -901 u16::try_from(self.peer_params.max_udp_payload_size.into_inner()).unwrap_or(u16::MAX); -902 self.path_generation_counter = self.path_generation_counter.wrapping_add(1); -903 let mut data = PathData::new( -904 network_path, -905 self.allow_mtud, -906 Some(peer_max_udp_payload_size), -907 self.path_generation_counter, -908 now, -909 &self.config, -910 ); -911 -912 data.validated = validated; -913 if let Some(initial_rtt) = initial_rtt { -914 data.rtt.reset_initial_rtt(initial_rtt); -915 } -916 -917 let pto = self.ack_frequency.max_ack_delay_for_pto() + data.rtt.pto_base(); -918 self.timers.set( -919 Timer::PerPath(path_id, PathTimer::PathOpen), -920 now + 3 * pto, -921 self.qlog.with_time(now), -922 ); -923 -924 // for the path to be opened we need to send a packet on the path. Sending a challenge -925 // guarantees this -926 data.send_new_challenge = true; -927 -928 let path = vacant_entry.insert(PathState { data, prev: None }); -929 -930 let mut pn_space = spaces::PacketNumberSpace::new(now, SpaceId::Data, &mut self.rng); -931 if let Some(pn) = pn { -932 pn_space.dedup.insert(pn); -933 } -934 self.spaces[SpaceId::Data] -935 .number_spaces -936 .insert(path_id, pn_space); -937 self.qlog.emit_tuple_assigned(path_id, network_path, now); -938 &mut path.data -939 } -940 -941 /// Returns packets to transmit -942 /// -943 /// Connections should be polled for transmit after: -944 /// - the application performed some I/O on the connection -945 /// - a call was made to `handle_event` -946 /// - a call was made to `handle_timeout` -947 /// -948 /// `max_datagrams` specifies how many datagrams can be returned inside a -949 /// single Transmit using GSO. This must be at least 1. -950 #[must_use] -951 pub fn poll_transmit( -952 &mut self, -953 now: Instant, -954 max_datagrams: NonZeroUsize, -955 buf: &mut Vec<u8>, -956 ) -> Option<Transmit> { -957 if let Some(probing) = self -958 .iroh_hp -959 .server_side_mut() -960 .ok() -961 .and_then(iroh_hp::ServerState::next_probe) -962 { -963 let destination = probing.remote(); -964 trace!(%destination, "RAND_DATA packet"); -965 let token: u64 = self.rng.random(); -966 buf.put_u64(token); -967 probing.finish(token); -968 return Some(Transmit { -969 destination, -970 ecn: None, -971 size: 8, -972 segment_size: None, -973 src_ip: None, -974 }); -975 } -976 -977 let max_datagrams = match self.config.enable_segmentation_offload { -978 false => NonZeroUsize::MIN, -979 true => max_datagrams, -980 }; -981 -982 // Each call to poll_transmit can only send datagrams to one destination, because -983 // all datagrams in a GSO batch are for the same destination. Therefore only -984 // datagrams for one destination address are produced for each poll_transmit call. -985 -986 // Check whether we need to send a close message -987 let close = match self.state.as_type() { -988 StateType::Drained => { -989 self.app_limited = true; -990 return None; -991 } -992 StateType::Draining | StateType::Closed => { -993 // self.close is only reset once the associated packet had been -994 // encoded successfully -995 if !self.close { -996 self.app_limited = true; -997 return None; -998 } -999 true -1000 } -1001 _ => false, -1002 }; -1003 -1004 // Schedule an ACK_FREQUENCY frame if a new one needs to be sent. -1005 if let Some(config) = &self.config.ack_frequency_config { -1006 let rtt = self -1007 .paths -1008 .values() -1009 .map(|p| p.data.rtt.get()) -1010 .min() -1011 .expect("one path exists"); -1012 self.spaces[SpaceId::Data].pending.ack_frequency = self -1013 .ack_frequency -1014 .should_send_ack_frequency(rtt, config, &self.peer_params) -1015 && self.highest_space == SpaceId::Data -1016 && self.peer_supports_ack_frequency(); -1017 } -1018 -1019 // Path scheduling logic is currently as such: -1020 // -1021 // - For any un-validated paths we only send frames that *must* be sent on that -1022 // path. E.g. PATH_CHALLENGE, PATH_RESPONSE. -1023 // -1024 // - If there are any paths with PathStatus::Available we only send any frames that -1025 // can be sent on any path, e.g. STREAM, DATAGRAM, on these available paths. -1026 // -1027 // - If there are any paths with PathStatus::Available we only send frames that -1028 // *must* be sent on a specific path to any other paths, e.g. a tail-loss probe for -1029 // that path, PMTU probe, a keep-alive PING. -1030 // -1031 // For all this we use the *path_exclusive_only* boolean: If set to true, only -1032 // frames that must be sent on the path will be built into the packet. -1033 -1034 // Is there any open, validated and status available path with dst CIDs? If so we'll -1035 // want to set path_exclusive_only for any other paths. -1036 let have_available_path = self.paths.iter().any(|(id, path)| { -1037 path.data.validated -1038 && path.data.local_status() == PathStatus::Available -1039 && self.rem_cids.contains_key(id) -1040 }); -1041 -1042 // TODO: how to avoid the allocation? Cannot use a for loop because of -1043 // borrowing. Maybe SmallVec or similar. -1044 let path_ids: Vec<_> = self.paths.keys().copied().collect(); -1045 -1046 let mut transmit = TransmitBuf::new( -1047 buf, -1048 max_datagrams, -1049 self.path_data(path_ids[0]).current_mtu().into(), -1050 ); -1051 -1052 // If we end up not sending anything, we need to know if that was because there was -1053 // nothing to send or because we were congestion blocked. -1054 let mut congestion_blocked = false; +787 /// Gets the local [`PathStatus`] for a known [`PathId`] +788 pub fn path_status(&self, path_id: PathId) -> Result<PathStatus, ClosedPath> { +789 self.path(path_id) +790 .map(PathData::local_status) +791 .ok_or(ClosedPath { _private: () }) +792 } +793 +794 /// Returns the path's network path represented as a 4-tuple. +795 pub fn network_path(&self, path_id: PathId) -> Result<FourTuple, ClosedPath> { +796 self.path(path_id) +797 .map(|path| path.network_path) +798 .ok_or(ClosedPath { _private: () }) +799 } +800 +801 /// Sets the [`PathStatus`] for a known [`PathId`] +802 /// +803 /// Returns the previous path status on success. +804 pub fn set_path_status( +805 &mut self, +806 path_id: PathId, +807 status: PathStatus, +808 ) -> Result<PathStatus, SetPathStatusError> { +809 if !self.is_multipath_negotiated() { +810 return Err(SetPathStatusError::MultipathNotNegotiated); +811 } +812 let path = self +813 .path_mut(path_id) +814 .ok_or(SetPathStatusError::ClosedPath)?; +815 let prev = match path.status.local_update(status) { +816 Some(prev) => { +817 self.spaces[SpaceId::Data] +818 .pending +819 .path_status +820 .insert(path_id); +821 prev +822 } +823 None => path.local_status(), +824 }; +825 Ok(prev) +826 } +827 +828 /// Returns the remote path status +829 // TODO(flub): Probably should also be some kind of path event? Not even sure if I like +830 // this as an API, but for now it allows me to write a test easily. +831 // TODO(flub): Technically this should be a Result<Option<PathSTatus>>? +832 pub fn remote_path_status(&self, path_id: PathId) -> Option<PathStatus> { +833 self.path(path_id).and_then(|path| path.remote_status()) +834 } +835 +836 /// Sets the max_idle_timeout for a specific path +837 /// +838 /// See [`TransportConfig::default_path_max_idle_timeout`] for details. +839 /// +840 /// Returns the previous value of the setting. +841 pub fn set_path_max_idle_timeout( +842 &mut self, +843 path_id: PathId, +844 timeout: Option<Duration>, +845 ) -> Result<Option<Duration>, ClosedPath> { +846 let path = self +847 .paths +848 .get_mut(&path_id) +849 .ok_or(ClosedPath { _private: () })?; +850 Ok(std::mem::replace(&mut path.data.idle_timeout, timeout)) +851 } +852 +853 /// Sets the keep_alive_interval for a specific path +854 /// +855 /// See [`TransportConfig::default_path_keep_alive_interval`] for details. +856 /// +857 /// Returns the previous value of the setting. +858 pub fn set_path_keep_alive_interval( +859 &mut self, +860 path_id: PathId, +861 interval: Option<Duration>, +862 ) -> Result<Option<Duration>, ClosedPath> { +863 let path = self +864 .paths +865 .get_mut(&path_id) +866 .ok_or(ClosedPath { _private: () })?; +867 Ok(std::mem::replace(&mut path.data.keep_alive, interval)) +868 } +869 +870 /// Gets the [`PathData`] for a known [`PathId`]. +871 /// +872 /// Will panic if the path_id does not reference any known path. +873 #[track_caller] +874 fn path_data_mut(&mut self, path_id: PathId) -> &mut PathData { +875 &mut self.paths.get_mut(&path_id).expect("known path").data +876 } +877 +878 /// Find an open, validated path that's on the same network path as the given network path. +879 /// +880 /// Returns the first path matching, even if there's multiple. +881 fn find_validated_path_on_network_path( +882 &self, +883 network_path: FourTuple, +884 ) -> Option<(&PathId, &PathState)> { +885 self.paths.iter().find(|(path_id, path_state)| { +886 path_state.data.validated +887 // Would this use the same network path, if network_path were used to send right now? +888 && network_path.is_probably_same_path(&path_state.data.network_path) +889 && !self.abandoned_paths.contains(path_id) +890 }) +891 // TODO(@divma): we might want to ensure the path has been recently active to consider the +892 // address validated +893 // matheus23: Perhaps looking at !self.abandoned_paths.contains(path_id) is enough, given keep-alives? +894 } +895 +896 fn ensure_path( +897 &mut self, +898 path_id: PathId, +899 network_path: FourTuple, +900 now: Instant, +901 pn: Option<u64>, +902 ) -> &mut PathData { +903 let valid_path = self.find_validated_path_on_network_path(network_path); +904 let validated = valid_path.is_some(); +905 let initial_rtt = valid_path.map(|(_, path)| path.data.rtt.conservative()); +906 let vacant_entry = match self.paths.entry(path_id) { +907 btree_map::Entry::Vacant(vacant_entry) => vacant_entry, +908 btree_map::Entry::Occupied(occupied_entry) => { +909 return &mut occupied_entry.into_mut().data; +910 } +911 }; +912 +913 debug!(%validated, %path_id, %network_path, "path added"); +914 let peer_max_udp_payload_size = +915 u16::try_from(self.peer_params.max_udp_payload_size.into_inner()).unwrap_or(u16::MAX); +916 self.path_generation_counter = self.path_generation_counter.wrapping_add(1); +917 let mut data = PathData::new( +918 network_path, +919 self.allow_mtud, +920 Some(peer_max_udp_payload_size), +921 self.path_generation_counter, +922 now, +923 &self.config, +924 ); +925 +926 data.validated = validated; +927 if let Some(initial_rtt) = initial_rtt { +928 data.rtt.reset_initial_rtt(initial_rtt); +929 } +930 +931 let pto = self.ack_frequency.max_ack_delay_for_pto() + data.rtt.pto_base(); +932 self.timers.set( +933 Timer::PerPath(path_id, PathTimer::PathOpen), +934 now + 3 * pto, +935 self.qlog.with_time(now), +936 ); +937 +938 // for the path to be opened we need to send a packet on the path. Sending a challenge +939 // guarantees this +940 data.send_new_challenge = true; +941 +942 let path = vacant_entry.insert(PathState { data, prev: None }); +943 +944 let mut pn_space = spaces::PacketNumberSpace::new(now, SpaceId::Data, &mut self.rng); +945 if let Some(pn) = pn { +946 pn_space.dedup.insert(pn); +947 } +948 self.spaces[SpaceId::Data] +949 .number_spaces +950 .insert(path_id, pn_space); +951 self.qlog.emit_tuple_assigned(path_id, network_path, now); +952 &mut path.data +953 } +954 +955 /// Returns packets to transmit +956 /// +957 /// Connections should be polled for transmit after: +958 /// - the application performed some I/O on the connection +959 /// - a call was made to `handle_event` +960 /// - a call was made to `handle_timeout` +961 /// +962 /// `max_datagrams` specifies how many datagrams can be returned inside a +963 /// single Transmit using GSO. This must be at least 1. +964 #[must_use] +965 pub fn poll_transmit( +966 &mut self, +967 now: Instant, +968 max_datagrams: NonZeroUsize, +969 buf: &mut Vec<u8>, +970 ) -> Option<Transmit> { +971 if let Some(probing) = self +972 .iroh_hp +973 .server_side_mut() +974 .ok() +975 .and_then(iroh_hp::ServerState::next_probe) +976 { +977 let destination = probing.remote(); +978 trace!(%destination, "RAND_DATA packet"); +979 let token: u64 = self.rng.random(); +980 buf.put_u64(token); +981 probing.finish(token); +982 return Some(Transmit { +983 destination, +984 ecn: None, +985 size: 8, +986 segment_size: None, +987 src_ip: None, +988 }); +989 } +990 +991 let max_datagrams = match self.config.enable_segmentation_offload { +992 false => NonZeroUsize::MIN, +993 true => max_datagrams, +994 }; +995 +996 // Each call to poll_transmit can only send datagrams to one destination, because +997 // all datagrams in a GSO batch are for the same destination. Therefore only +998 // datagrams for one destination address are produced for each poll_transmit call. +999 +1000 // Check whether we need to send a close message +1001 let close = match self.state.as_type() { +1002 StateType::Drained => { +1003 self.app_limited = true; +1004 return None; +1005 } +1006 StateType::Draining | StateType::Closed => { +1007 // self.close is only reset once the associated packet had been +1008 // encoded successfully +1009 if !self.connection_close_pending { +1010 self.app_limited = true; +1011 return None; +1012 } +1013 true +1014 } +1015 _ => false, +1016 }; +1017 +1018 // Schedule an ACK_FREQUENCY frame if a new one needs to be sent. +1019 if let Some(config) = &self.config.ack_frequency_config { +1020 let rtt = self +1021 .paths +1022 .values() +1023 .map(|p| p.data.rtt.get()) +1024 .min() +1025 .expect("one path exists"); +1026 self.spaces[SpaceId::Data].pending.ack_frequency = self +1027 .ack_frequency +1028 .should_send_ack_frequency(rtt, config, &self.peer_params) +1029 && self.highest_space == SpaceId::Data +1030 && self.peer_supports_ack_frequency(); +1031 } +1032 +1033 // Path scheduling logic is currently as such: +1034 // +1035 // - For any un-validated paths we only send frames that *must* be sent on that +1036 // path. E.g. PATH_CHALLENGE, PATH_RESPONSE. +1037 // +1038 // - If there are any paths with PathStatus::Available we only send any frames that +1039 // can be sent on any path, e.g. STREAM, DATAGRAM, on these available paths. +1040 // +1041 // - If there are any paths with PathStatus::Available we only send frames that +1042 // *must* be sent on a specific path to any other paths, e.g. a tail-loss probe for +1043 // that path, PMTU probe, a keep-alive PING. +1044 // +1045 // For all this we use the *path_exclusive_only* boolean: If set to true, only +1046 // frames that must be sent on the path will be built into the packet. +1047 +1048 // Is there any open, validated and status available path with dst CIDs? If so we'll +1049 // want to set path_exclusive_only for any other paths. +1050 let have_available_path = self.paths.iter().any(|(id, path)| { +1051 path.data.validated +1052 && path.data.local_status() == PathStatus::Available +1053 && self.rem_cids.contains_key(id) +1054 }); 1055 -1056 for &path_id in &path_ids { -1057 // Set the segment size to this path's MTU. -1058 transmit.set_segment_size(self.path_data(path_id).current_mtu().into()); +1056 // TODO: how to avoid the allocation? Cannot use a for loop because of +1057 // borrowing. Maybe SmallVec or similar. +1058 let path_ids: Vec<_> = self.paths.keys().copied().collect(); 1059 -1060 // Poll (some) off-path transmits first. -1061 if let Some(challenge) = self.send_prev_path_challenge(now, &mut transmit, path_id) { -1062 return Some(challenge); -1063 } -1064 -1065 // Poll for (mostly) on-path transmits. -1066 match self.poll_transmit_path(now, &mut transmit, path_id, have_available_path, close) { -1067 PollPathStatus::SendTransmit { transmit } => { -1068 return Some(transmit); -1069 } -1070 PollPathStatus::Send => { -1071 let transmit = self.build_transmit(path_id, transmit); -1072 return Some(transmit); -1073 } -1074 PollPathStatus::NothingToSend { -1075 congestion_blocked: cb, -1076 } => { -1077 congestion_blocked |= cb; -1078 // Continue checking other paths, tail-loss probes may need to be sent -1079 // in all spaces. -1080 debug_assert!( -1081 transmit.is_empty(), -1082 "nothing to send on path but transmit not empty" -1083 ); -1084 } -1085 } -1086 } -1087 -1088 // We didn't produce any application data packet -1089 debug_assert!( -1090 transmit.is_empty(), -1091 "there was data in the transmit, but it was not sent" -1092 ); -1093 -1094 self.app_limited = !congestion_blocked; -1095 -1096 if self.state.is_established() { -1097 // Try MTU probing now -1098 for path_id in path_ids { -1099 // Update per path state -1100 transmit.set_segment_size(self.path_data(path_id).current_mtu().into()); -1101 self.poll_transmit_mtu_probe(now, &mut transmit, path_id); -1102 if !transmit.is_empty() { -1103 let transmit = self.build_transmit(path_id, transmit); -1104 return Some(transmit); -1105 } -1106 } -1107 } -1108 -1109 None -1110 } -1111 -1112 fn build_transmit(&mut self, path_id: PathId, transmit: TransmitBuf<'_>) -> Transmit { -1113 debug_assert!( -1114 !transmit.is_empty(), -1115 "must not be called with an empty transmit buffer" -1116 ); -1117 -1118 let network_path = self.path_data(path_id).network_path; -1119 trace!( -1120 segment_size = transmit.segment_size(), -1121 last_datagram_len = transmit.len() % transmit.segment_size(), -1122 %network_path, -1123 "sending {} bytes in {} datagrams", -1124 transmit.len(), -1125 transmit.num_datagrams() -1126 ); -1127 self.path_data_mut(path_id) -1128 .inc_total_sent(transmit.len() as u64); -1129 -1130 self.stats -1131 .udp_tx -1132 .on_sent(transmit.num_datagrams() as u64, transmit.len()); -1133 // TODO(flub): check https://github.com/n0-computer/quinn/pull/332 changes -1134 -1135 Transmit { -1136 destination: network_path.remote, -1137 size: transmit.len(), -1138 ecn: if self.path_data(path_id).sending_ecn { -1139 Some(EcnCodepoint::Ect0) -1140 } else { -1141 None -1142 }, -1143 segment_size: match transmit.num_datagrams() { -1144 1 => None, -1145 _ => Some(transmit.segment_size()), -1146 }, -1147 src_ip: network_path.local_ip, -1148 } -1149 } -1150 -1151 /// poll_transmit logic for a specific [`PathState::data`]. -1152 /// -1153 /// This is not quite the same as for a multipath packet space, since [`PathId::ZERO`] -1154 /// has 3 packet spaces, which this handles. -1155 /// -1156 /// This does not handle sending for [`PathState::prev`] which is handled by -1157 /// [`Self::send_prev_path_challenge`] called directly from [`Self::poll_transmit`]. -1158 #[must_use] -1159 fn poll_transmit_path( -1160 &mut self, -1161 now: Instant, -1162 transmit: &mut TransmitBuf<'_>, -1163 path_id: PathId, -1164 have_available_path: bool, -1165 close: bool, -1166 ) -> PollPathStatus { -1167 // Check if there is at least one active CID to use for sending -1168 let Some(remote_cid) = self.rem_cids.get(&path_id).map(CidQueue::active) else { -1169 if self.abandoned_paths.contains(&path_id) { -1170 trace!(%path_id, "remote CIDs retired for abandoned path"); -1171 } else { -1172 debug!(%path_id, "no remote CIDs for path"); -1173 } -1174 return PollPathStatus::NothingToSend { -1175 congestion_blocked: false, -1176 }; -1177 }; -1178 -1179 // Whether the last packet in the datagram must be padded so the datagram takes up -1180 // an exact size. -1181 let mut pad_datagram = PadDatagram::No; -1182 -1183 // The packet number of the last built packet. This is kept kept across spaces. This -1184 // is only relevant for the Initial and Handshake spaces as only those can coalesce -1185 // packets with the next space. QUIC is supposed to have a single congestion -1186 // controller for the Initial, Handshake and Data(PathId::ZERO) spaces. -1187 let mut last_packet_number = None; -1188 -1189 // If we end up not sending anything, we need to know if that was because there was -1190 // nothing to send or because we were congestion blocked. -1191 let mut congestion_blocked = false; -1192 -1193 // Iterate over the available spaces -1194 for space_id in SpaceId::iter() { -1195 // Only Path0 uses non Data space ids -1196 if path_id != PathId::ZERO && space_id != SpaceId::Data { -1197 continue; -1198 } -1199 tracing::warn!(?space_id, %path_id, "A SPACE"); -1200 -1201 let res = self.poll_transmit_path_space( -1202 now, -1203 transmit, -1204 path_id, -1205 space_id, -1206 remote_cid, -1207 have_available_path, -1208 close, -1209 pad_datagram, -1210 ); -1211 trace!(%path_id, ?space_id, ?res, "poll_transmit_space"); -1212 match res { -1213 PollPathSpaceOutcome::Send { -1214 last_packet_number: lp, -1215 may_coalesce, -1216 } => { -1217 debug_assert!(!transmit.is_empty(), "transmit must contain packets"); -1218 last_packet_number = Some(lp); -1219 match may_coalesce { -1220 Some(should_pad) => { -1221 tracing::warn!("LETS MOVE ON"); -1222 pad_datagram = should_pad; -1223 continue; -1224 } -1225 None => break, -1226 } -1227 } -1228 PollPathSpaceOutcome::SendTransmit { transmit } => { -1229 return PollPathStatus::SendTransmit { transmit }; -1230 } -1231 PollPathSpaceOutcome::NothingToSend { -1232 congestion_blocked: cb, -1233 } => { -1234 congestion_blocked = cb; -1235 // Continue checking other spaces, tail-loss probes may need to be sent -1236 // in all spaces. -1237 } -1238 } -1239 } -1240 -1241 if last_packet_number.is_some() || congestion_blocked { -1242 self.qlog.emit_recovery_metrics( -1243 path_id, -1244 &mut self.paths.get_mut(&path_id).unwrap().data, -1245 now, -1246 ); -1247 } -1248 -1249 match last_packet_number { -1250 Some(last_packet_number) => { -1251 debug_assert!(!transmit.is_empty(), "packet number but transmit is empty"); -1252 // Note that when sending in multiple packet spaces the last packet number will -1253 // be the one from the highest packet space. -1254 self.path_data_mut(path_id).congestion.on_sent( -1255 now, -1256 transmit.len() as u64, -1257 last_packet_number, -1258 ); -1259 -1260 PollPathStatus::Send -1261 } -1262 None => PollPathStatus::NothingToSend { congestion_blocked }, -1263 } -1264 } -1265 -1266 /// poll_transmit logic for a QUIC-MULTIPATH packet number space (PathID + SpaceId). -1267 #[must_use] -1268 fn poll_transmit_path_space( -1269 &mut self, -1270 now: Instant, -1271 transmit: &mut TransmitBuf<'_>, -1272 path_id: PathId, -1273 space_id: SpaceId, -1274 remote_cid: ConnectionId, -1275 // If any other packet space has a usable path with PathStatus::Available. -1276 have_available_path: bool, -1277 // If we need to send a CONNECTION_CLOSE frame. -1278 close: bool, -1279 // Whether the current datagram needs to be padded if no more packets can be -1280 // coalesced into it. -1281 mut pad_datagram: PadDatagram, -1282 ) -> PollPathSpaceOutcome { -1283 let mut last_packet_number = None; -1284 let mut coalesce = true; -1285 tracing::warn!("HELLO"); -1286 -1287 // Each loop of this may build one packet. If the packet allows coalescing and there -1288 // is still enough space in the current datagram the function will return and the -1289 // caller will call us again for the next space to fill up the remainder of the -1290 // datagram. Otherwise the loop will restart and if there is still more data to send -1291 // and more space in the GSO batch new datagrams will be started and new packets -1292 // will be written. -1293 loop { -1294 // Determine if anything can be sent in this packet number space (SpaceId + PathId). -1295 let max_packet_size = if transmit.datagram_remaining_mut() > 0 { -1296 // A datagram is started already, we are trying to coalesce another packet -1297 // into this datagram. -1298 transmit.datagram_remaining_mut() -1299 } else { -1300 // A new datagram needs to be started. -1301 transmit.segment_size() -1302 }; -1303 -1304 let can_send = self.space_can_send(space_id, path_id, max_packet_size, close); +1060 let mut transmit = TransmitBuf::new( +1061 buf, +1062 max_datagrams, +1063 self.path_data(path_ids[0]).current_mtu().into(), +1064 ); +1065 +1066 // If we end up not sending anything, we need to know if that was because there was +1067 // nothing to send or because we were congestion blocked. +1068 let mut congestion_blocked = false; +1069 +1070 for &path_id in &path_ids { +1071 // Set the segment size to this path's MTU. +1072 transmit.set_segment_size(self.path_data(path_id).current_mtu().into()); +1073 +1074 // Poll (some) off-path transmits first. +1075 if let Some(challenge) = self.send_prev_path_challenge(now, &mut transmit, path_id) { +1076 return Some(challenge); +1077 } +1078 +1079 // Poll for (mostly) on-path transmits. +1080 match self.poll_transmit_path(now, &mut transmit, path_id, have_available_path, close) { +1081 PollPathStatus::SendTransmit { transmit } => { +1082 return Some(transmit); +1083 } +1084 PollPathStatus::Send => { +1085 let transmit = self.build_transmit(path_id, transmit); +1086 return Some(transmit); +1087 } +1088 PollPathStatus::NothingToSend { +1089 congestion_blocked: cb, +1090 } => { +1091 congestion_blocked |= cb; +1092 // Continue checking other paths, tail-loss probes may need to be sent +1093 // in all spaces. +1094 debug_assert!( +1095 transmit.is_empty(), +1096 "nothing to send on path but transmit not empty" +1097 ); +1098 } +1099 } +1100 } +1101 +1102 // We didn't produce any application data packet +1103 debug_assert!( +1104 transmit.is_empty(), +1105 "there was data in the transmit, but it was not sent" +1106 ); +1107 +1108 self.app_limited = !congestion_blocked; +1109 +1110 if self.state.is_established() { +1111 // Try MTU probing now +1112 for path_id in path_ids { +1113 // Update per path state +1114 transmit.set_segment_size(self.path_data(path_id).current_mtu().into()); +1115 self.poll_transmit_mtu_probe(now, &mut transmit, path_id); +1116 if !transmit.is_empty() { +1117 let transmit = self.build_transmit(path_id, transmit); +1118 return Some(transmit); +1119 } +1120 } +1121 } +1122 +1123 None +1124 } +1125 +1126 fn build_transmit(&mut self, path_id: PathId, transmit: TransmitBuf<'_>) -> Transmit { +1127 debug_assert!( +1128 !transmit.is_empty(), +1129 "must not be called with an empty transmit buffer" +1130 ); +1131 +1132 let network_path = self.path_data(path_id).network_path; +1133 trace!( +1134 segment_size = transmit.segment_size(), +1135 last_datagram_len = transmit.len() % transmit.segment_size(), +1136 %network_path, +1137 "sending {} bytes in {} datagrams", +1138 transmit.len(), +1139 transmit.num_datagrams() +1140 ); +1141 self.path_data_mut(path_id) +1142 .inc_total_sent(transmit.len() as u64); +1143 +1144 self.stats +1145 .udp_tx +1146 .on_sent(transmit.num_datagrams() as u64, transmit.len()); +1147 // TODO(flub): check https://github.com/n0-computer/quinn/pull/332 changes +1148 +1149 Transmit { +1150 destination: network_path.remote, +1151 size: transmit.len(), +1152 ecn: if self.path_data(path_id).sending_ecn { +1153 Some(EcnCodepoint::Ect0) +1154 } else { +1155 None +1156 }, +1157 segment_size: match transmit.num_datagrams() { +1158 1 => None, +1159 _ => Some(transmit.segment_size()), +1160 }, +1161 src_ip: network_path.local_ip, +1162 } +1163 } +1164 +1165 /// poll_transmit logic for a specific [`PathState::data`]. +1166 /// +1167 /// This is not quite the same as for a multipath packet space, since [`PathId::ZERO`] +1168 /// has 3 packet spaces, which this handles. +1169 /// +1170 /// This does not handle sending for [`PathState::prev`] which is handled by +1171 /// [`Self::send_prev_path_challenge`] called directly from +1172 /// [`Self::poll_transmit`]. Eventually we'd like this to only produce on-path +1173 /// transmits. +1174 #[must_use] +1175 fn poll_transmit_path( +1176 &mut self, +1177 now: Instant, +1178 transmit: &mut TransmitBuf<'_>, +1179 path_id: PathId, +1180 have_available_path: bool, +1181 close: bool, +1182 ) -> PollPathStatus { +1183 // Check if there is at least one active CID to use for sending +1184 let Some(remote_cid) = self.rem_cids.get(&path_id).map(CidQueue::active) else { +1185 if self.abandoned_paths.contains(&path_id) { +1186 trace!(%path_id, "remote CIDs retired for abandoned path"); +1187 } else { +1188 debug!(%path_id, "no remote CIDs for path"); +1189 } +1190 return PollPathStatus::NothingToSend { +1191 congestion_blocked: false, +1192 }; +1193 }; +1194 +1195 // Whether the last packet in the datagram must be padded so the datagram takes up +1196 // an exact size. An earlier space can decide to not fill an entire datagram and +1197 // require the next space to fill it further. But may need a specific size of the +1198 // datagram containing the packet. The final packet built in the datagram must pad +1199 // to this size. +1200 let mut pad_datagram = PadDatagram::No; +1201 +1202 // The packet number of the last built packet. This is kept kept across spaces. +1203 // QUIC is supposed to have a single congestion controller for the Initial, +1204 // Handshake and Data(PathId::ZERO) spaces. +1205 let mut last_packet_number = None; +1206 +1207 // If we end up not sending anything, we need to know if that was because there was +1208 // nothing to send or because we were congestion blocked. +1209 let mut congestion_blocked = false; +1210 +1211 // Iterate over the available spaces. +1212 for space_id in SpaceId::iter() { +1213 // Only PathId::ZERO uses non Data space ids. +1214 if path_id != PathId::ZERO && space_id != SpaceId::Data { +1215 continue; +1216 } +1217 let res = self.poll_transmit_path_space( +1218 now, +1219 transmit, +1220 path_id, +1221 space_id, +1222 remote_cid, +1223 have_available_path, +1224 close, +1225 pad_datagram, +1226 ); +1227 trace!(%path_id, ?space_id, ?res, "poll_transmit_space"); +1228 match res { +1229 PollPathSpaceOutcome::NothingToSend { +1230 congestion_blocked: cb, +1231 } => { +1232 congestion_blocked |= cb; +1233 // Continue checking other spaces, tail-loss probes may need to be sent +1234 // in all spaces. +1235 } +1236 PollPathSpaceOutcome::WrotePacket { +1237 last_packet_number: pn, +1238 pad_datagram: pad, +1239 } => { +1240 debug_assert!(!transmit.is_empty(), "transmit must contain packets"); +1241 last_packet_number = Some(pn); +1242 pad_datagram = pad; +1243 // Always check higher spaces. If the transmit is full or they have +1244 // nothing to send they will not write packets. But if they can, they +1245 // should always be allowed to add to this transmit because it is all +1246 // sent to the same remote. +1247 continue; +1248 } +1249 PollPathSpaceOutcome::Send { +1250 last_packet_number: pn, +1251 } => { +1252 debug_assert!(!transmit.is_empty(), "transmit must contain packets"); +1253 last_packet_number = Some(pn); +1254 break; +1255 } +1256 PollPathSpaceOutcome::SendTransmit { transmit } => { +1257 return PollPathStatus::SendTransmit { transmit }; +1258 } +1259 } +1260 } +1261 +1262 if last_packet_number.is_some() || congestion_blocked { +1263 self.qlog.emit_recovery_metrics( +1264 path_id, +1265 &mut self.paths.get_mut(&path_id).unwrap().data, +1266 now, +1267 ); +1268 } +1269 +1270 match last_packet_number { +1271 Some(last_packet_number) => { +1272 // Note that when sending in multiple spaces the last packet number will be +1273 // the one from the highest space. +1274 self.path_data_mut(path_id).congestion.on_sent( +1275 now, +1276 transmit.len() as u64, +1277 last_packet_number, +1278 ); +1279 +1280 PollPathStatus::Send +1281 } +1282 None => PollPathStatus::NothingToSend { congestion_blocked }, +1283 } +1284 } +1285 +1286 /// poll_transmit logic for a QUIC-MULTIPATH packet number space (PathID + SpaceId). +1287 #[must_use] +1288 fn poll_transmit_path_space( +1289 &mut self, +1290 now: Instant, +1291 transmit: &mut TransmitBuf<'_>, +1292 path_id: PathId, +1293 space_id: SpaceId, +1294 remote_cid: ConnectionId, +1295 // If any other packet space has a usable path with PathStatus::Available. +1296 have_available_path: bool, +1297 // If we need to send a CONNECTION_CLOSE frame. +1298 connection_close_pending: bool, +1299 // Whether the current datagram needs to be padded to a certain size. +1300 mut pad_datagram: PadDatagram, +1301 ) -> PollPathSpaceOutcome { +1302 // Keep track of the last packet number we wrote. If None we did not write any +1303 // packets. +1304 let mut last_packet_number = None; 1305 -1306 // Whether we would like to send any frames on this packet space. See the packet -1307 // scheduling described in poll_transmit. -1308 let space_should_send = { -1309 let path_exclusive_only = space_id == SpaceId::Data -1310 && have_available_path -1311 && self.path_data(path_id).local_status() == PathStatus::Backup; -1312 let path_should_send = if path_exclusive_only { -1313 can_send.path_exclusive -1314 } else { -1315 !can_send.is_empty() -1316 }; -1317 let needs_loss_probe = self.spaces[space_id].for_path(path_id).loss_probes > 0; -1318 path_should_send || needs_loss_probe -1319 }; -1320 -1321 if !space_should_send { -1322 // Nothing more to send. Previous iterations of this loop may have built -1323 // packets already. -1324 return match last_packet_number { -1325 Some(pn) => PollPathSpaceOutcome::Send { -1326 last_packet_number: pn, -1327 may_coalesce: if coalesce { Some(pad_datagram) } else { None }, -1328 }, -1329 None => { -1330 // If the crypto for the Initial and Handshake spaces is None then those -1331 // spaces are done with forever, no need to log them. -1332 if space_id == SpaceId::Data || self.spaces[space_id].crypto.is_some() { -1333 trace!(?space_id, %path_id, "nothing to send in space"); -1334 } -1335 return PollPathSpaceOutcome::NothingToSend { -1336 congestion_blocked: false, -1337 }; -1338 } -1339 }; -1340 } -1341 -1342 // We want to send on this space, check congestion control if we can. But only -1343 // if we will need to start a new datagram. If we are coalescing into an already -1344 // started datagram we do not need to check congestion control again. -1345 if transmit.datagram_remaining_mut() == 0 { -1346 let congestion_blocked = -1347 self.path_congestion_check(space_id, path_id, transmit, &can_send, now); -1348 if congestion_blocked != PathBlocked::No { -1349 trace!(?space_id, %path_id, ?congestion_blocked, "congestion blocked"); -1350 // Previous iterations of this loop may have built packets already. -1351 return match last_packet_number { -1352 Some(pn) => PollPathSpaceOutcome::Send { -1353 last_packet_number: pn, -1354 may_coalesce: if coalesce { Some(pad_datagram) } else { None }, -1355 }, -1356 None => { -1357 // If the crypto for the Initial and Handshake spaces is None then those -1358 // spaces are done with forever, no need to log them. -1359 if space_id == SpaceId::Data || self.spaces[space_id].crypto.is_some() { -1360 trace!(?space_id, %path_id, "nothing to send in space"); -1361 } -1362 return PollPathSpaceOutcome::NothingToSend { -1363 congestion_blocked: true, -1364 }; -1365 } -1366 }; -1367 } -1368 } -1369 -1370 // If the datagram is full (or there never was one started), we need to start a -1371 // new one. +1306 // Each loop of this may build one packet. It works logically as follows: +1307 // +1308 // - Check if something *needs* to be sent in this space and *can* be sent. +1309 // - If not, return to the caller who will call us again for the next space. +1310 // - Start a new datagram. +1311 // - Unless coalescing the packet into an existing datagram. +1312 // - Write the packet header and payload. +1313 // - Check if coalescing a next packet into the datagram is possible. +1314 // - If coalescing, finish packet without padding to leave space in the datagram. +1315 // - If not coalescing, complete the datagram: +1316 // - Finish packet with padding. +1317 // - Set the transmit segment size if this is the first datagram. +1318 // - Loop: next iteration will exit the loop if nothing more to send in this +1319 // space. The TransmitBuf will contain a started datagram with space if +1320 // coalescing, or completely filled datagram if not coalescing. +1321 loop { +1322 // Determine if anything can be sent in this packet number space (SpaceId + PathId). +1323 let max_packet_size = if transmit.datagram_remaining_mut() > 0 { +1324 // A datagram is started already, we are coalescing another packet into it. +1325 transmit.datagram_remaining_mut() +1326 } else { +1327 // A new datagram needs to be started. +1328 transmit.segment_size() +1329 }; +1330 let can_send = +1331 self.space_can_send(space_id, path_id, max_packet_size, connection_close_pending); +1332 +1333 // Whether we would like to send any frames on this packet space. See the packet +1334 // scheduling described in poll_transmit. +1335 let space_should_send = { +1336 let path_exclusive_only = space_id == SpaceId::Data +1337 && have_available_path +1338 && self.path_data(path_id).local_status() == PathStatus::Backup; +1339 let path_should_send = if path_exclusive_only { +1340 can_send.path_exclusive +1341 } else { +1342 !can_send.is_empty() +1343 }; +1344 let needs_loss_probe = self.spaces[space_id].for_path(path_id).loss_probes > 0; +1345 path_should_send || needs_loss_probe +1346 }; +1347 +1348 if !space_should_send { +1349 // Nothing more to send. Previous iterations of this loop may have built +1350 // packets already. +1351 return match last_packet_number { +1352 Some(pn) => PollPathSpaceOutcome::WrotePacket { +1353 last_packet_number: pn, +1354 pad_datagram, +1355 }, +1356 None => { +1357 // If the crypto for the Initial and Handshake spaces is None then those +1358 // spaces are done with forever, no need to log them. +1359 if space_id == SpaceId::Data || self.spaces[space_id].crypto.is_some() { +1360 trace!(?space_id, %path_id, "nothing to send in space"); +1361 } +1362 return PollPathSpaceOutcome::NothingToSend { +1363 congestion_blocked: false, +1364 }; +1365 } +1366 }; +1367 } +1368 +1369 // We want to send on this space, check congestion control if we can. But only +1370 // if we will need to start a new datagram. If we are coalescing into an already +1371 // started datagram we do not need to check congestion control again. 1372 if transmit.datagram_remaining_mut() == 0 { -1373 if transmit.num_datagrams() >= transmit.max_datagrams().get() { -1374 // No more datagrams allowed. -1375 return match last_packet_number { -1376 Some(pn) => PollPathSpaceOutcome::Send { -1377 last_packet_number: pn, -1378 may_coalesce: None, -1379 }, -1380 // TODO: Could consider a new return value here? -1381 None => PollPathSpaceOutcome::NothingToSend { -1382 congestion_blocked: false, -1383 }, -1384 }; -1385 } -1386 -1387 match self.spaces[space_id].for_path(path_id).loss_probes { -1388 0 => transmit.start_new_datagram(), -1389 _ => { -1390 // We need something to send for a tail-loss probe. -1391 let request_immediate_ack = -1392 space_id == SpaceId::Data && self.peer_supports_ack_frequency(); -1393 self.spaces[space_id].maybe_queue_probe( -1394 path_id, -1395 request_immediate_ack, -1396 &self.streams, -1397 ); -1398 -1399 self.spaces[space_id].for_path(path_id).loss_probes -= 1; -1400 -1401 // Clamp the datagram to at most the minimum MTU to ensure that loss -1402 // probes can get through and enable recovery even if the path MTU -1403 // has shrank unexpectedly. -1404 transmit.start_new_datagram_with_size(std::cmp::min( -1405 usize::from(INITIAL_MTU), -1406 transmit.segment_size(), -1407 )); -1408 } -1409 } -1410 trace!(count = transmit.num_datagrams(), "new datagram started"); -1411 -1412 // We started a new datagram, initialise as allowing coalescing packets and -1413 // no need for padding the datagram. -1414 coalesce = true; -1415 pad_datagram = PadDatagram::No; -1416 } -1417 -1418 // If coalescing another packet into the existing datagram, there should -1419 // still be enough space for a whole packet. -1420 if transmit.datagram_start_offset() < transmit.len() { -1421 debug_assert!(transmit.datagram_remaining_mut() >= MIN_PACKET_SPACE); -1422 } +1373 let congestion_blocked = +1374 self.path_congestion_check(space_id, path_id, transmit, &can_send, now); +1375 if congestion_blocked != PathBlocked::No { +1376 // Previous iterations of this loop may have built packets already. +1377 return match last_packet_number { +1378 Some(pn) => PollPathSpaceOutcome::WrotePacket { +1379 last_packet_number: pn, +1380 pad_datagram, +1381 }, +1382 None => { +1383 return PollPathSpaceOutcome::NothingToSend { +1384 congestion_blocked: true, +1385 }; +1386 } +1387 }; +1388 } +1389 } +1390 +1391 // If the datagram is full (or there never was one started), we need to start a +1392 // new one. +1393 if transmit.datagram_remaining_mut() == 0 { +1394 if transmit.num_datagrams() >= transmit.max_datagrams().get() { +1395 // No more datagrams allowed. +1396 // Previous iterations of this loop may have built packets already. +1397 return match last_packet_number { +1398 Some(pn) => PollPathSpaceOutcome::WrotePacket { +1399 last_packet_number: pn, +1400 pad_datagram, +1401 }, +1402 None => { +1403 return PollPathSpaceOutcome::NothingToSend { +1404 congestion_blocked: false, +1405 }; +1406 } +1407 }; +1408 } +1409 +1410 match self.spaces[space_id].for_path(path_id).loss_probes { +1411 0 => transmit.start_new_datagram(), +1412 _ => { +1413 // We need something to send for a tail-loss probe. +1414 let request_immediate_ack = +1415 space_id == SpaceId::Data && self.peer_supports_ack_frequency(); +1416 self.spaces[space_id].maybe_queue_probe( +1417 path_id, +1418 request_immediate_ack, +1419 &self.streams, +1420 ); +1421 +1422 self.spaces[space_id].for_path(path_id).loss_probes -= 1; 1423 -1424 // -1425 // From here on, we've determined that a packet will definitely be sent. -1426 // -1427 -1428 if self.spaces[SpaceId::Initial].crypto.is_some() -1429 && space_id == SpaceId::Handshake -1430 && self.side.is_client() -1431 { -1432 // A client stops both sending and processing Initial packets when it -1433 // sends its first Handshake packet. -1434 self.discard_space(now, SpaceId::Initial); -1435 } -1436 if let Some(ref mut prev) = self.prev_crypto { -1437 prev.update_unacked = false; -1438 } -1439 -1440 let Some(mut builder) = PacketBuilder::new( -1441 now, -1442 space_id, -1443 path_id, -1444 remote_cid, -1445 transmit, -1446 can_send.other, -1447 self, -1448 ) else { -1449 // Confidentiality limit is exceeded and the connection has been killed. We -1450 // should not send any other packets. This works in a roundabout way: We -1451 // have started a datagram but not written anything into it. So even if we -1452 // get called again for another space we will see an already started -1453 // datagram and try and start another packet here. Then be stopped by the -1454 // same confidentiality limit. -1455 return PollPathSpaceOutcome::NothingToSend { -1456 congestion_blocked: false, -1457 }; -1458 }; -1459 last_packet_number = Some(builder.exact_number); -1460 let last_pn = builder.exact_number; -1461 coalesce = coalesce && builder.can_coalesce; -1462 -1463 if space_id == SpaceId::Initial && (self.side.is_client() || can_send.other) { -1464 // https://www.rfc-editor.org/rfc/rfc9000.html#section-14.1 -1465 pad_datagram |= PadDatagram::ToMinMtu; -1466 } -1467 if space_id == SpaceId::Data && self.config.pad_to_mtu { -1468 pad_datagram |= PadDatagram::ToSegmentSize; -1469 } -1470 -1471 if can_send.close { -1472 trace!("sending CONNECTION_CLOSE"); -1473 // Encode ACKs before the ConnectionClose message, to give the receiver -1474 // a better approximate on what data has been processed. This is -1475 // especially important with ack delay, since the peer might not -1476 // have gotten any other ACK for the data earlier on. -1477 let is_multipath_negotiated = self.is_multipath_negotiated(); -1478 for path_id in self.spaces[space_id] -1479 .number_spaces -1480 .iter() -1481 .filter(|(_, pns)| !pns.pending_acks.ranges().is_empty()) -1482 .map(|(&path_id, _)| path_id) -1483 .collect::<Vec<_>>() -1484 { -1485 Self::populate_acks( -1486 now, -1487 self.receiving_ecn, -1488 path_id, -1489 space_id, -1490 &mut self.spaces[space_id], -1491 is_multipath_negotiated, -1492 &mut builder, -1493 &mut self.stats.frame_tx, -1494 ); -1495 } -1496 -1497 // Since there only 64 ACK frames there will always be enough space -1498 // to encode the ConnectionClose frame too. However we still have the -1499 // check here to prevent crashes if something changes. -1500 debug_assert!( -1501 builder.frame_space_remaining() > frame::ConnectionClose::SIZE_BOUND, -1502 "ACKs should leave space for ConnectionClose" -1503 ); -1504 let stats = &mut self.stats.frame_tx; -1505 if frame::ConnectionClose::SIZE_BOUND < builder.frame_space_remaining() { -1506 let max_frame_size = builder.frame_space_remaining(); -1507 let close: Close = match self.state.as_type() { -1508 StateType::Closed => { -1509 let reason: Close = -1510 self.state.as_closed().expect("checked").clone().into(); -1511 if space_id == SpaceId::Data || reason.is_transport_layer() { -1512 reason -1513 } else { -1514 TransportError::APPLICATION_ERROR("").into() -1515 } -1516 } -1517 StateType::Draining => TransportError::NO_ERROR("").into(), -1518 _ => unreachable!( -1519 "tried to make a close packet when the connection wasn't closed" -1520 ), -1521 }; -1522 builder.write_frame(close.encoder(max_frame_size), stats); -1523 } -1524 builder.finish_and_track(now, self, path_id, pad_datagram); -1525 if space_id == self.highest_space { -1526 // Don't send another close packet. Even with multipath we only send -1527 // CONNECTION_CLOSE on a single path since we expect our paths to work. -1528 self.close = false; -1529 } -1530 // Send a close frame in every possible space for robustness, per -1531 // RFC9000 "Immediate Close during the Handshake". Don't bother trying -1532 // to send anything else. -1533 // TODO(flub): This breaks during the handshake if we can not coalesce -1534 // packets due to space reasons: the next space would either fail a -1535 // debug_assert checking for enough packet space or produce an invalid -1536 // packet. That is an existing bug however. -1537 return PollPathSpaceOutcome::Send { -1538 last_packet_number: last_pn, -1539 may_coalesce: Some(pad_datagram), -1540 }; -1541 } -1542 -1543 // Send an off-path PATH_RESPONSE. Prioritized over on-path data to ensure that -1544 // path validation can occur while the link is saturated. -1545 // TODO(flub): This needs to be done outside of this function, e.g. together -1546 // with the off-path path challenges of Self::send_prev_path_challenge. -1547 if space_id == SpaceId::Data && builder.buf.num_datagrams() == 1 { -1548 let path = self.path_data_mut(path_id); -1549 if let Some((token, network_path)) = -1550 path.path_responses.pop_off_path(path.network_path) -1551 { -1552 // TODO(flub): We need to use the right CID! We shouldn't use the same -1553 // CID as the current active one for the path. Though see also -1554 // https://github.com/quinn-rs/quinn/issues/2184 -1555 // -1556 let stats = &mut self.stats.frame_tx; -1557 let frame = frame::PathResponse(token); -1558 builder.write_frame_with_log_msg(frame, stats, Some("(off-path)")); -1559 builder.finish_and_track(now, self, path_id, PadDatagram::ToMinMtu); -1560 self.stats.udp_tx.on_sent(1, transmit.len()); -1561 self.path_stats -1562 .entry(path_id) -1563 .or_default() -1564 .udp_tx -1565 .on_sent(1, transmit.len()); -1566 return PollPathSpaceOutcome::SendTransmit { -1567 transmit: Transmit { -1568 destination: network_path.remote, -1569 size: transmit.len(), -1570 ecn: None, -1571 segment_size: None, -1572 src_ip: network_path.local_ip, -1573 }, -1574 }; -1575 } -1576 } -1577 -1578 // If this boolean is true we only want to send frames which can not be sent on -1579 // any other path. See the path scheduling notes in Self::poll_transmit. -1580 let path_exclusive_only = -1581 have_available_path && self.path_data(path_id).local_status() == PathStatus::Backup; -1582 -1583 self.populate_packet(now, space_id, path_id, path_exclusive_only, &mut builder); -1584 -1585 // ACK-only packets should only be sent when explicitly allowed. If we write them due to -1586 // any other reason, there is a bug which leads to one component announcing write -1587 // readiness while not writing any data. This degrades performance. The condition is -1588 // only checked if the full MTU is available and when potentially large fixed-size -1589 // frames aren't queued, so that lack of space in the datagram isn't the reason for just -1590 // writing ACKs. -1591 debug_assert!( -1592 !(builder.sent_frames().is_ack_only(&self.streams) -1593 && !can_send.acks -1594 && can_send.other -1595 && builder.buf.segment_size() -1596 == self.path_data(path_id).current_mtu() as usize -1597 && self.datagrams.outgoing.is_empty()), -1598 "SendableFrames was {can_send:?}, but only ACKs have been written" -1599 ); -1600 if builder.sent_frames().requires_padding { -1601 pad_datagram |= PadDatagram::ToMinMtu; +1424 // Clamp the datagram to at most the minimum MTU to ensure that loss +1425 // probes can get through and enable recovery even if the path MTU +1426 // has shrank unexpectedly. +1427 transmit.start_new_datagram_with_size(std::cmp::min( +1428 usize::from(INITIAL_MTU), +1429 transmit.segment_size(), +1430 )); +1431 } +1432 } +1433 trace!(count = transmit.num_datagrams(), "new datagram started"); +1434 +1435 // We started a new datagram, we decide later if it needs padding. +1436 pad_datagram = PadDatagram::No; +1437 } +1438 +1439 // If coalescing another packet into the existing datagram, there should +1440 // still be enough space for a whole packet. +1441 if transmit.datagram_start_offset() < transmit.len() { +1442 debug_assert!(transmit.datagram_remaining_mut() >= MIN_PACKET_SPACE); +1443 } +1444 +1445 // +1446 // From here on, we've determined that a packet will definitely be sent. +1447 // +1448 +1449 if self.spaces[SpaceId::Initial].crypto.is_some() +1450 && space_id == SpaceId::Handshake +1451 && self.side.is_client() +1452 { +1453 // A client stops both sending and processing Initial packets when it +1454 // sends its first Handshake packet. +1455 self.discard_space(now, SpaceId::Initial); +1456 } +1457 if let Some(ref mut prev) = self.prev_crypto { +1458 prev.update_unacked = false; +1459 } +1460 +1461 let Some(mut builder) = PacketBuilder::new( +1462 now, +1463 space_id, +1464 path_id, +1465 remote_cid, +1466 transmit, +1467 can_send.other, +1468 self, +1469 ) else { +1470 // Confidentiality limit is exceeded and the connection has been killed. We +1471 // should not send any other packets. This works in a roundabout way: We +1472 // have started a datagram but not written anything into it. So even if we +1473 // get called again for another space we will see an already started +1474 // datagram and try and start another packet here. Then be stopped by the +1475 // same confidentiality limit. +1476 return PollPathSpaceOutcome::NothingToSend { +1477 congestion_blocked: false, +1478 }; +1479 }; +1480 last_packet_number = Some(builder.packet_number); +1481 +1482 if space_id == SpaceId::Initial && (self.side.is_client() || can_send.other) { +1483 // https://www.rfc-editor.org/rfc/rfc9000.html#section-14.1 +1484 pad_datagram |= PadDatagram::ToMinMtu; +1485 } +1486 if space_id == SpaceId::Data && self.config.pad_to_mtu { +1487 pad_datagram |= PadDatagram::ToSegmentSize; +1488 } +1489 +1490 if can_send.close { +1491 trace!("sending CONNECTION_CLOSE"); +1492 // Encode ACKs before the ConnectionClose message, to give the receiver +1493 // a better approximate on what data has been processed. This is +1494 // especially important with ack delay, since the peer might not +1495 // have gotten any other ACK for the data earlier on. +1496 let is_multipath_negotiated = self.is_multipath_negotiated(); +1497 for path_id in self.spaces[space_id] +1498 .number_spaces +1499 .iter() +1500 .filter(|(_, pns)| !pns.pending_acks.ranges().is_empty()) +1501 .map(|(&path_id, _)| path_id) +1502 .collect::<Vec<_>>() +1503 { +1504 Self::populate_acks( +1505 now, +1506 self.receiving_ecn, +1507 path_id, +1508 space_id, +1509 &mut self.spaces[space_id], +1510 is_multipath_negotiated, +1511 &mut builder, +1512 &mut self.stats.frame_tx, +1513 ); +1514 } +1515 +1516 // Since there only 64 ACK frames there will always be enough space +1517 // to encode the ConnectionClose frame too. However we still have the +1518 // check here to prevent crashes if something changes. +1519 // TODO(flub): This needs fixing for multipath. +1520 debug_assert!( +1521 builder.frame_space_remaining() > frame::ConnectionClose::SIZE_BOUND, +1522 "ACKs should leave space for ConnectionClose" +1523 ); +1524 let stats = &mut self.stats.frame_tx; +1525 if frame::ConnectionClose::SIZE_BOUND < builder.frame_space_remaining() { +1526 let max_frame_size = builder.frame_space_remaining(); +1527 let close: Close = match self.state.as_type() { +1528 StateType::Closed => { +1529 let reason: Close = +1530 self.state.as_closed().expect("checked").clone().into(); +1531 if space_id == SpaceId::Data || reason.is_transport_layer() { +1532 reason +1533 } else { +1534 TransportError::APPLICATION_ERROR("").into() +1535 } +1536 } +1537 StateType::Draining => TransportError::NO_ERROR("").into(), +1538 _ => unreachable!( +1539 "tried to make a close packet when the connection wasn't closed" +1540 ), +1541 }; +1542 builder.write_frame(close.encoder(max_frame_size), stats); +1543 } +1544 let last_pn = builder.packet_number; +1545 builder.finish_and_track(now, self, path_id, pad_datagram); +1546 if space_id == self.highest_space { +1547 // Don't send another close packet. Even with multipath we only send +1548 // CONNECTION_CLOSE on a single path since we expect our paths to work. +1549 self.connection_close_pending = false; +1550 } +1551 // Send a close frame in every possible space for robustness, per +1552 // RFC9000 "Immediate Close during the Handshake". Don't bother trying +1553 // to send anything else. +1554 // TODO(flub): This breaks during the handshake if we can not coalesce +1555 // packets due to space reasons: the next space would either fail a +1556 // debug_assert checking for enough packet space or produce an invalid +1557 // packet. We need to keep track of per-space pending CONNECTION_CLOSE to +1558 // be able to send these across multiple calls to poll_transmit. Then +1559 // check for coalescing space here because initial packets need to be in +1560 // padded datagrams. And also add space checks for CONNECTION_CLOSE in +1561 // space_can_send so it would stop a GSO batch if the datagram is too +1562 // small for another CONNECTION_CLOSE packet. +1563 return PollPathSpaceOutcome::WrotePacket { +1564 last_packet_number: last_pn, +1565 pad_datagram, +1566 }; +1567 } +1568 +1569 // Send an off-path PATH_RESPONSE. Prioritized over on-path data to ensure that +1570 // path validation can occur while the link is saturated. +1571 // TODO(flub): This needs to be done outside of this function, e.g. together +1572 // with the off-path path challenges of Self::send_prev_path_challenge. +1573 if space_id == SpaceId::Data && builder.buf.num_datagrams() == 1 { +1574 let path = self.path_data_mut(path_id); +1575 if let Some((token, network_path)) = +1576 path.path_responses.pop_off_path(path.network_path) +1577 { +1578 // TODO(flub): We need to use the right CID! We shouldn't use the same +1579 // CID as the current active one for the path. Though see also +1580 // https://github.com/quinn-rs/quinn/issues/2184 +1581 // +1582 let stats = &mut self.stats.frame_tx; +1583 let frame = frame::PathResponse(token); +1584 builder.write_frame_with_log_msg(frame, stats, Some("(off-path)")); +1585 builder.finish_and_track(now, self, path_id, PadDatagram::ToMinMtu); +1586 self.stats.udp_tx.on_sent(1, transmit.len()); +1587 self.path_stats +1588 .entry(path_id) +1589 .or_default() +1590 .udp_tx +1591 .on_sent(1, transmit.len()); +1592 return PollPathSpaceOutcome::SendTransmit { +1593 transmit: Transmit { +1594 destination: network_path.remote, +1595 size: transmit.len(), +1596 ecn: None, +1597 segment_size: None, +1598 src_ip: network_path.local_ip, +1599 }, +1600 }; +1601 } 1602 } 1603 -1604 for (path_id, _pn) in builder.sent_frames().largest_acked.iter() { -1605 self.spaces[space_id] -1606 .for_path(*path_id) -1607 .pending_acks -1608 .acks_sent(); -1609 self.timers.stop( -1610 Timer::PerPath(*path_id, PathTimer::MaxAckDelay), -1611 self.qlog.with_time(now), -1612 ); -1613 } -1614 -1615 // Now we need to finish the packet. Before we do so we need to know if we will -1616 // be coalescing the next packet into this one, or will be ending the datagram -1617 // as well. Because if this is the last packet in the datagram more padding -1618 // might be needed because of the packet type, or to fill the GSO segment size. -1619 -1620 // Are we allowed to coalesce AND is there enough space for another *packet* in -1621 // this datagram AND is there another packet to send in the next space? -1622 // TODO(flub): We should only check this for the Initial and Handshake space. In -1623 // the Data spaces we never coalesce. -1624 if coalesce -1625 && builder -1626 .buf -1627 .datagram_remaining_mut() -1628 .saturating_sub(builder.predict_packet_end()) -1629 > MIN_PACKET_SPACE -1630 && self.has_next_send_space(space_id, path_id, builder.buf, close) -1631 { -1632 // We can append/coalesce the next packet into the current -1633 // datagram. Finish the current packet without adding extra padding. -1634 tracing::warn!("we think we can coalesce"); -1635 builder.finish_and_track(now, self, path_id, PadDatagram::No); -1636 } else { -1637 // We need a new datagram for the next packet. Finish the current -1638 // packet with padding. -1639 // TODO(flub): if there isn't any more data to be sent, this will still pad -1640 // to the segment size and only discover there is nothing to send before -1641 // starting the next packet. That is wasting up to 32 bytes. -1642 if builder.buf.num_datagrams() > 1 && matches!(pad_datagram, PadDatagram::No) { -1643 // If too many padding bytes would be required to continue the -1644 // GSO batch after this packet, end the GSO batch here. Ensures -1645 // that fixed-size frames with heterogeneous sizes -1646 // (e.g. application datagrams) won't inadvertently waste large -1647 // amounts of bandwidth. The exact threshold is a bit arbitrary -1648 // and might benefit from further tuning, though there's no -1649 // universally optimal value. -1650 const MAX_PADDING: usize = 32; -1651 if builder.buf.datagram_remaining_mut() -1652 > builder.predict_packet_end() + MAX_PADDING -1653 { -1654 trace!( -1655 "GSO truncated by demand for {} padding bytes", -1656 builder.buf.datagram_remaining_mut() - builder.predict_packet_end() -1657 ); -1658 builder.finish_and_track(now, self, path_id, PadDatagram::No); -1659 return PollPathSpaceOutcome::Send { -1660 last_packet_number: last_pn, -1661 may_coalesce: None, -1662 }; -1663 } -1664 -1665 // Pad the current datagram to GSO segment size so it can be -1666 // included in the GSO batch. -1667 builder.finish_and_track(now, self, path_id, PadDatagram::ToSegmentSize); -1668 } else { -1669 builder.finish_and_track(now, self, path_id, pad_datagram); -1670 } -1671 -1672 // If this is the first datagram we set the segment size to the size of the -1673 // first datagram. -1674 if transmit.num_datagrams() == 1 { -1675 transmit.clip_segment_size(); -1676 } -1677 } -1678 } -1679 } -1680 -1681 fn poll_transmit_mtu_probe( -1682 &mut self, -1683 now: Instant, -1684 transmit: &mut TransmitBuf<'_>, -1685 path_id: PathId, -1686 ) { -1687 let Some((active_cid, probe_size)) = self.get_mtu_probe_data(now, path_id) else { -1688 return; -1689 }; -1690 -1691 // We are definitely sending a DPLPMTUD probe. -1692 debug_assert_eq!(transmit.num_datagrams(), 0); -1693 transmit.start_new_datagram_with_size(probe_size as usize); -1694 -1695 let Some(mut builder) = PacketBuilder::new( -1696 now, -1697 SpaceId::Data, -1698 path_id, -1699 active_cid, -1700 transmit, -1701 true, -1702 self, -1703 ) else { -1704 return; -1705 }; -1706 -1707 // We implement MTU probes as ping packets padded up to the probe size -1708 trace!(?probe_size, "writing MTUD probe"); -1709 builder.write_frame(frame::Ping, &mut self.stats.frame_tx); -1710 -1711 // If supported by the peer, we want no delays to the probe's ACK -1712 if self.peer_supports_ack_frequency() { -1713 builder.write_frame(frame::ImmediateAck, &mut self.stats.frame_tx); -1714 } -1715 -1716 builder.finish_and_track(now, self, path_id, PadDatagram::ToSize(probe_size)); -1717 -1718 self.path_stats -1719 .entry(path_id) -1720 .or_default() -1721 .sent_plpmtud_probes += 1; -1722 } -1723 -1724 fn get_mtu_probe_data(&mut self, now: Instant, path_id: PathId) -> Option<(ConnectionId, u16)> { -1725 // We MTU probe all paths for which all of the following is true: -1726 // - We have an active destination CID for the path. -1727 // - The remote address *and* path are validated. -1728 // - The path is not abandoned. -1729 // - The MTU Discovery subsystem wants to probe the path. -1730 let active_cid = self.rem_cids.get(&path_id).map(CidQueue::active)?; -1731 let is_eligible = self.path_data(path_id).validated -1732 && !self.path_data(path_id).is_validating_path() -1733 && !self.abandoned_paths.contains(&path_id); +1604 // If this boolean is true we only want to send frames which can not be sent on +1605 // any other path. See the path scheduling notes in Self::poll_transmit. +1606 let path_exclusive_only = +1607 have_available_path && self.path_data(path_id).local_status() == PathStatus::Backup; +1608 +1609 self.populate_packet(now, space_id, path_id, path_exclusive_only, &mut builder); +1610 +1611 // ACK-only packets should only be sent when explicitly allowed. If we write them due to +1612 // any other reason, there is a bug which leads to one component announcing write +1613 // readiness while not writing any data. This degrades performance. The condition is +1614 // only checked if the full MTU is available and when potentially large fixed-size +1615 // frames aren't queued, so that lack of space in the datagram isn't the reason for just +1616 // writing ACKs. +1617 debug_assert!( +1618 !(builder.sent_frames().is_ack_only(&self.streams) +1619 && !can_send.acks +1620 && can_send.other +1621 && builder.buf.segment_size() +1622 == self.path_data(path_id).current_mtu() as usize +1623 && self.datagrams.outgoing.is_empty()), +1624 "SendableFrames was {can_send:?}, but only ACKs have been written" +1625 ); +1626 if builder.sent_frames().requires_padding { +1627 pad_datagram |= PadDatagram::ToMinMtu; +1628 } +1629 +1630 for (path_id, _pn) in builder.sent_frames().largest_acked.iter() { +1631 self.spaces[space_id] +1632 .for_path(*path_id) +1633 .pending_acks +1634 .acks_sent(); +1635 self.timers.stop( +1636 Timer::PerPath(*path_id, PathTimer::MaxAckDelay), +1637 self.qlog.with_time(now), +1638 ); +1639 } +1640 +1641 // Now we need to finish the packet. Before we do so we need to know if we will +1642 // be coalescing the next packet into this one, or will be ending the datagram +1643 // as well. Because if this is the last packet in the datagram more padding +1644 // might be needed because of the packet type, or to fill the GSO segment size. +1645 +1646 // Are we allowed to coalesce AND is there enough space for another *packet* in +1647 // this datagram AND will we definitely send another packet? +1648 if builder.can_coalesce && path_id == PathId::ZERO && { +1649 let max_packet_size = builder +1650 .buf +1651 .datagram_remaining_mut() +1652 .saturating_sub(builder.predict_packet_end()); +1653 max_packet_size > MIN_PACKET_SPACE +1654 && self.has_pending_packet(space_id, max_packet_size, connection_close_pending) +1655 } { +1656 // We can append/coalesce the next packet into the current +1657 // datagram. Finish the current packet without adding extra padding. +1658 trace!("will coalesce with next packet"); +1659 builder.finish_and_track(now, self, path_id, PadDatagram::No); +1660 } else { +1661 // We need a new datagram for the next packet. Finish the current +1662 // packet with padding. +1663 // TODO(flub): if there isn't any more data to be sent, this will still pad +1664 // to the segment size and only discover there is nothing to send before +1665 // starting the next packet. That is wasting up to 32 bytes. +1666 if builder.buf.num_datagrams() > 1 && matches!(pad_datagram, PadDatagram::No) { +1667 // If too many padding bytes would be required to continue the +1668 // GSO batch after this packet, end the GSO batch here. Ensures +1669 // that fixed-size frames with heterogeneous sizes +1670 // (e.g. application datagrams) won't inadvertently waste large +1671 // amounts of bandwidth. The exact threshold is a bit arbitrary +1672 // and might benefit from further tuning, though there's no +1673 // universally optimal value. +1674 const MAX_PADDING: usize = 32; +1675 if builder.buf.datagram_remaining_mut() +1676 > builder.predict_packet_end() + MAX_PADDING +1677 { +1678 trace!( +1679 "GSO truncated by demand for {} padding bytes", +1680 builder.buf.datagram_remaining_mut() - builder.predict_packet_end() +1681 ); +1682 let last_pn = builder.packet_number; +1683 builder.finish_and_track(now, self, path_id, PadDatagram::No); +1684 return PollPathSpaceOutcome::Send { +1685 last_packet_number: last_pn, +1686 }; +1687 } +1688 +1689 // Pad the current datagram to GSO segment size so it can be +1690 // included in the GSO batch. +1691 builder.finish_and_track(now, self, path_id, PadDatagram::ToSegmentSize); +1692 } else { +1693 builder.finish_and_track(now, self, path_id, pad_datagram); +1694 } +1695 +1696 // If this is the first datagram we set the segment size to the size of the +1697 // first datagram. +1698 if transmit.num_datagrams() == 1 { +1699 transmit.clip_segment_size(); +1700 } +1701 } +1702 } +1703 } +1704 +1705 fn poll_transmit_mtu_probe( +1706 &mut self, +1707 now: Instant, +1708 transmit: &mut TransmitBuf<'_>, +1709 path_id: PathId, +1710 ) { +1711 let Some((active_cid, probe_size)) = self.get_mtu_probe_data(now, path_id) else { +1712 return; +1713 }; +1714 +1715 // We are definitely sending a DPLPMTUD probe. +1716 debug_assert_eq!(transmit.num_datagrams(), 0); +1717 transmit.start_new_datagram_with_size(probe_size as usize); +1718 +1719 let Some(mut builder) = PacketBuilder::new( +1720 now, +1721 SpaceId::Data, +1722 path_id, +1723 active_cid, +1724 transmit, +1725 true, +1726 self, +1727 ) else { +1728 return; +1729 }; +1730 +1731 // We implement MTU probes as ping packets padded up to the probe size +1732 trace!(?probe_size, "writing MTUD probe"); +1733 builder.write_frame(frame::Ping, &mut self.stats.frame_tx); 1734 -1735 if !is_eligible { -1736 return None; -1737 } -1738 let next_pn = self.spaces[SpaceId::Data] -1739 .for_path(path_id) -1740 .peek_tx_number(); -1741 let probe_size = self -1742 .path_data_mut(path_id) -1743 .mtud -1744 .poll_transmit(now, next_pn)?; -1745 -1746 Some((active_cid, probe_size)) -1747 } -1748 -1749 /// Returns if there is a next packet space on the same path, which has data to send. -1750 /// -1751 /// This takes into account the space available to frames in the next datagram. -1752 // TODO(flub): This duplication is not nice. -1753 fn has_next_send_space( -1754 &mut self, -1755 mut current_space_id: SpaceId, -1756 path_id: PathId, -1757 buf: &TransmitBuf<'_>, -1758 close: bool, -1759 ) -> bool { -1760 // Number of bytes available for frames if this is a 1-RTT packet. We're guaranteed -1761 // to be able to send an individual frame at least this large in the next 1-RTT -1762 // packet. This could be generalized to support every space, but it's only needed to -1763 // handle large fixed-size frames, which only exist in 1-RTT (application -1764 // datagrams). We don't account for coalesced packets potentially occupying space -1765 // because frames can always spill into the next datagram. -1766 while let Some(space_id) = current_space_id.next() { -1767 let can_send = self.space_can_send(space_id, path_id, buf.segment_size(), close); -1768 if !can_send.is_empty() || (close && self.spaces[space_id].crypto.is_some()) { -1769 return true; -1770 } -1771 current_space_id = space_id; -1772 } -1773 false -1774 } -1775 -1776 /// Checks if creating a new datagram would be blocked by congestion control -1777 fn path_congestion_check( -1778 &mut self, -1779 space_id: SpaceId, -1780 path_id: PathId, -1781 transmit: &TransmitBuf<'_>, -1782 can_send: &SendableFrames, -1783 now: Instant, -1784 ) -> PathBlocked { -1785 // Anti-amplification is only based on `total_sent`, which gets updated after -1786 // the transmit is sent. Therefore we pass the amount of bytes for datagrams -1787 // that are already created, as well as 1 byte for starting another datagram. If -1788 // there is any anti-amplification budget left, we always allow a full MTU to be -1789 // sent (see https://github.com/quinn-rs/quinn/issues/1082). -1790 if self.side().is_server() -1791 && self -1792 .path_data(path_id) -1793 .anti_amplification_blocked(transmit.len() as u64 + 1) -1794 { -1795 trace!(?space_id, %path_id, "blocked by anti-amplification"); -1796 return PathBlocked::AntiAmplification; -1797 } -1798 -1799 // Congestion control check. -1800 // Tail loss probes must not be blocked by congestion, or a deadlock could arise. -1801 let bytes_to_send = transmit.segment_size() as u64; -1802 let need_loss_probe = self.spaces[space_id].for_path(path_id).loss_probes > 0; -1803 -1804 if can_send.other && !need_loss_probe && !can_send.close { -1805 let path = self.path_data(path_id); -1806 if path.in_flight.bytes + bytes_to_send >= path.congestion.window() { -1807 trace!(?space_id, %path_id, "blocked by congestion control"); -1808 return PathBlocked::Congestion; +1735 // If supported by the peer, we want no delays to the probe's ACK +1736 if self.peer_supports_ack_frequency() { +1737 builder.write_frame(frame::ImmediateAck, &mut self.stats.frame_tx); +1738 } +1739 +1740 builder.finish_and_track(now, self, path_id, PadDatagram::ToSize(probe_size)); +1741 +1742 self.path_stats +1743 .entry(path_id) +1744 .or_default() +1745 .sent_plpmtud_probes += 1; +1746 } +1747 +1748 fn get_mtu_probe_data(&mut self, now: Instant, path_id: PathId) -> Option<(ConnectionId, u16)> { +1749 // We MTU probe all paths for which all of the following is true: +1750 // - We have an active destination CID for the path. +1751 // - The remote address *and* path are validated. +1752 // - The path is not abandoned. +1753 // - The MTU Discovery subsystem wants to probe the path. +1754 let active_cid = self.rem_cids.get(&path_id).map(CidQueue::active)?; +1755 let is_eligible = self.path_data(path_id).validated +1756 && !self.path_data(path_id).is_validating_path() +1757 && !self.abandoned_paths.contains(&path_id); +1758 +1759 if !is_eligible { +1760 return None; +1761 } +1762 let next_pn = self.spaces[SpaceId::Data] +1763 .for_path(path_id) +1764 .peek_tx_number(); +1765 let probe_size = self +1766 .path_data_mut(path_id) +1767 .mtud +1768 .poll_transmit(now, next_pn)?; +1769 +1770 Some((active_cid, probe_size)) +1771 } +1772 +1773 /// Returns true if there is a further packet to send on [`PathId::ZERO`]. +1774 /// +1775 /// In other words this is predicting whether the next call to +1776 /// [`Connection::space_can_send`] issued will return some frames to be sent. Including +1777 /// having to predict which packet number space it will be invoked with. This depends on +1778 /// how both [`Connection::poll_transmit_path`] and +1779 /// [`Connection::poll_transmit_path_space`] behave. +1780 /// +1781 /// This is needed to determine if packet coalescing can happen. Because the last packet +1782 /// in a datagram may need to be padded and thus we must know if another packet will +1783 /// follow or not. +1784 /// +1785 /// The next packet can be either in the same space, or in one of the following spaces +1786 /// on the same path. Because a 0-RTT packet can be coalesced with a 1-RTT packet and +1787 /// both are in the Data(PathId::ZERO) space. Previous spaces are not checked, because +1788 /// packets are built from Initial to Handshake to Data spaces. +1789 fn has_pending_packet( +1790 &mut self, +1791 current_space_id: SpaceId, +1792 max_packet_size: usize, +1793 connection_close_pending: bool, +1794 ) -> bool { +1795 let mut space_id = current_space_id; +1796 loop { +1797 let can_send = self.space_can_send( +1798 space_id, +1799 PathId::ZERO, +1800 max_packet_size, +1801 connection_close_pending, +1802 ); +1803 if !can_send.is_empty() { +1804 return true; +1805 } +1806 match space_id.next() { +1807 Some(next_space_id) => space_id = next_space_id, +1808 None => break, 1809 } 1810 } -1811 -1812 // Pacing check. -1813 if let Some(delay) = self.path_data_mut(path_id).pacing_delay(bytes_to_send, now) { -1814 self.timers.set( -1815 Timer::PerPath(path_id, PathTimer::Pacing), -1816 delay, -1817 self.qlog.with_time(now), -1818 ); -1819 // Loss probes and CONNECTION_CLOSE should be subject to pacing, even though -1820 // they are not congestion controlled. -1821 trace!(?space_id, %path_id, "blocked by pacing"); -1822 return PathBlocked::Pacing; -1823 } -1824 -1825 PathBlocked::No -1826 } -1827 -1828 /// Send PATH_CHALLENGE for a previous path if necessary -1829 /// -1830 /// QUIC-TRANSPORT section 9.3.3 -1831 /// <https://www.rfc-editor.org/rfc/rfc9000.html#name-off-path-packet-forwarding> -1832 fn send_prev_path_challenge( -1833 &mut self, -1834 now: Instant, -1835 buf: &mut TransmitBuf<'_>, -1836 path_id: PathId, -1837 ) -> Option<Transmit> { -1838 let (prev_cid, prev_path) = self.paths.get_mut(&path_id)?.prev.as_mut()?; -1839 // TODO (matheus23): We could use !prev_path.is_validating() here instead to -1840 // (possibly) also re-send challenges when they get lost. -1841 if !prev_path.send_new_challenge { -1842 return None; -1843 }; -1844 prev_path.send_new_challenge = false; -1845 let network_path = prev_path.network_path; -1846 let token = self.rng.random(); -1847 let info = paths::SentChallengeInfo { -1848 sent_instant: now, -1849 network_path, -1850 }; -1851 prev_path.challenges_sent.insert(token, info); -1852 debug_assert_eq!( -1853 self.highest_space, -1854 SpaceId::Data, -1855 "PATH_CHALLENGE queued without 1-RTT keys" -1856 ); -1857 buf.start_new_datagram_with_size(MIN_INITIAL_SIZE as usize); -1858 -1859 // Use the previous CID to avoid linking the new path with the previous path. We -1860 // don't bother accounting for possible retirement of that prev_cid because this is -1861 // sent once, immediately after migration, when the CID is known to be valid. Even -1862 // if a post-migration packet caused the CID to be retired, it's fair to pretend -1863 // this is sent first. -1864 debug_assert_eq!(buf.datagram_start_offset(), 0); -1865 let mut builder = -1866 PacketBuilder::new(now, SpaceId::Data, path_id, *prev_cid, buf, false, self)?; -1867 let challenge = frame::PathChallenge(token); -1868 let stats = &mut self.stats.frame_tx; -1869 builder.write_frame_with_log_msg(challenge, stats, Some("validating previous path")); -1870 -1871 // An endpoint MUST expand datagrams that contain a PATH_CHALLENGE frame -1872 // to at least the smallest allowed maximum datagram size of 1200 bytes, -1873 // unless the anti-amplification limit for the path does not permit -1874 // sending a datagram of this size -1875 builder.pad_to(MIN_INITIAL_SIZE); -1876 -1877 builder.finish(self, now); -1878 self.stats.udp_tx.on_sent(1, buf.len()); -1879 self.path_stats -1880 .entry(path_id) -1881 .or_default() -1882 .udp_tx -1883 .on_sent(1, buf.len()); -1884 -1885 Some(Transmit { -1886 destination: network_path.remote, -1887 size: buf.len(), -1888 ecn: None, -1889 segment_size: None, -1890 src_ip: network_path.local_ip, -1891 }) -1892 } -1893 -1894 /// Indicate what types of frames are ready to send for the given space -1895 /// -1896 /// *packet_size* is the number of bytes available to build the next packet. -1897 /// *close* indicates whether a CONNECTION_CLOSE frame needs to be sent. -1898 fn space_can_send( -1899 &mut self, -1900 space_id: SpaceId, -1901 path_id: PathId, -1902 packet_size: usize, -1903 close: bool, -1904 ) -> SendableFrames { -1905 let space = &mut self.spaces[space_id]; -1906 let space_has_crypto = space.crypto.is_some(); -1907 -1908 if !space_has_crypto -1909 && (space_id != SpaceId::Data -1910 || self.zero_rtt_crypto.is_none() -1911 || self.side.is_server()) -1912 { -1913 // Nothing to send in this space -1914 return SendableFrames::empty(); -1915 } -1916 -1917 let mut can_send = space.can_send(path_id, &self.streams); -1918 -1919 if space_id == SpaceId::Data { -1920 // Check for 1RTT space. -1921 let pn = space.for_path(path_id).peek_tx_number(); -1922 let frame_space_1rtt = -1923 packet_size.saturating_sub(self.predict_1rtt_overhead(pn, path_id)); -1924 can_send |= self.can_send_1rtt(path_id, frame_space_1rtt); -1925 } -1926 -1927 can_send.close = close && space_has_crypto; -1928 -1929 can_send +1811 false +1812 } +1813 +1814 /// Checks if creating a new datagram would be blocked by congestion control +1815 fn path_congestion_check( +1816 &mut self, +1817 space_id: SpaceId, +1818 path_id: PathId, +1819 transmit: &TransmitBuf<'_>, +1820 can_send: &SendableFrames, +1821 now: Instant, +1822 ) -> PathBlocked { +1823 // Anti-amplification is only based on `total_sent`, which gets updated after +1824 // the transmit is sent. Therefore we pass the amount of bytes for datagrams +1825 // that are already created, as well as 1 byte for starting another datagram. If +1826 // there is any anti-amplification budget left, we always allow a full MTU to be +1827 // sent (see https://github.com/quinn-rs/quinn/issues/1082). +1828 if self.side().is_server() +1829 && self +1830 .path_data(path_id) +1831 .anti_amplification_blocked(transmit.len() as u64 + 1) +1832 { +1833 trace!(?space_id, %path_id, "blocked by anti-amplification"); +1834 return PathBlocked::AntiAmplification; +1835 } +1836 +1837 // Congestion control check. +1838 // Tail loss probes must not be blocked by congestion, or a deadlock could arise. +1839 let bytes_to_send = transmit.segment_size() as u64; +1840 let need_loss_probe = self.spaces[space_id].for_path(path_id).loss_probes > 0; +1841 +1842 if can_send.other && !need_loss_probe && !can_send.close { +1843 let path = self.path_data(path_id); +1844 if path.in_flight.bytes + bytes_to_send >= path.congestion.window() { +1845 trace!(?space_id, %path_id, "blocked by congestion control"); +1846 return PathBlocked::Congestion; +1847 } +1848 } +1849 +1850 // Pacing check. +1851 if let Some(delay) = self.path_data_mut(path_id).pacing_delay(bytes_to_send, now) { +1852 self.timers.set( +1853 Timer::PerPath(path_id, PathTimer::Pacing), +1854 delay, +1855 self.qlog.with_time(now), +1856 ); +1857 // Loss probes and CONNECTION_CLOSE should be subject to pacing, even though +1858 // they are not congestion controlled. +1859 trace!(?space_id, %path_id, "blocked by pacing"); +1860 return PathBlocked::Pacing; +1861 } +1862 +1863 PathBlocked::No +1864 } +1865 +1866 /// Send PATH_CHALLENGE for a previous path if necessary +1867 /// +1868 /// QUIC-TRANSPORT section 9.3.3 +1869 /// <https://www.rfc-editor.org/rfc/rfc9000.html#name-off-path-packet-forwarding> +1870 fn send_prev_path_challenge( +1871 &mut self, +1872 now: Instant, +1873 buf: &mut TransmitBuf<'_>, +1874 path_id: PathId, +1875 ) -> Option<Transmit> { +1876 let (prev_cid, prev_path) = self.paths.get_mut(&path_id)?.prev.as_mut()?; +1877 // TODO (matheus23): We could use !prev_path.is_validating() here instead to +1878 // (possibly) also re-send challenges when they get lost. +1879 if !prev_path.send_new_challenge { +1880 return None; +1881 }; +1882 prev_path.send_new_challenge = false; +1883 let network_path = prev_path.network_path; +1884 let token = self.rng.random(); +1885 let info = paths::SentChallengeInfo { +1886 sent_instant: now, +1887 network_path, +1888 }; +1889 prev_path.challenges_sent.insert(token, info); +1890 debug_assert_eq!( +1891 self.highest_space, +1892 SpaceId::Data, +1893 "PATH_CHALLENGE queued without 1-RTT keys" +1894 ); +1895 buf.start_new_datagram_with_size(MIN_INITIAL_SIZE as usize); +1896 +1897 // Use the previous CID to avoid linking the new path with the previous path. We +1898 // don't bother accounting for possible retirement of that prev_cid because this is +1899 // sent once, immediately after migration, when the CID is known to be valid. Even +1900 // if a post-migration packet caused the CID to be retired, it's fair to pretend +1901 // this is sent first. +1902 debug_assert_eq!(buf.datagram_start_offset(), 0); +1903 let mut builder = +1904 PacketBuilder::new(now, SpaceId::Data, path_id, *prev_cid, buf, false, self)?; +1905 let challenge = frame::PathChallenge(token); +1906 let stats = &mut self.stats.frame_tx; +1907 builder.write_frame_with_log_msg(challenge, stats, Some("validating previous path")); +1908 +1909 // An endpoint MUST expand datagrams that contain a PATH_CHALLENGE frame +1910 // to at least the smallest allowed maximum datagram size of 1200 bytes, +1911 // unless the anti-amplification limit for the path does not permit +1912 // sending a datagram of this size +1913 builder.pad_to(MIN_INITIAL_SIZE); +1914 +1915 builder.finish(self, now); +1916 self.stats.udp_tx.on_sent(1, buf.len()); +1917 self.path_stats +1918 .entry(path_id) +1919 .or_default() +1920 .udp_tx +1921 .on_sent(1, buf.len()); +1922 +1923 Some(Transmit { +1924 destination: network_path.remote, +1925 size: buf.len(), +1926 ecn: None, +1927 segment_size: None, +1928 src_ip: network_path.local_ip, +1929 }) 1930 } 1931 -1932 /// Process `ConnectionEvent`s generated by the associated `Endpoint` +1932 /// Indicate what types of frames are ready to send for the given space 1933 /// -1934 /// Will execute protocol logic upon receipt of a connection event, in turn preparing signals -1935 /// (including application `Event`s, `EndpointEvent`s and outgoing datagrams) that should be -1936 /// extracted through the relevant methods. -1937 pub fn handle_event(&mut self, event: ConnectionEvent) { -1938 use ConnectionEventInner::*; -1939 match event.0 { -1940 Datagram(DatagramConnectionEvent { -1941 now, -1942 network_path, -1943 path_id, -1944 ecn, -1945 first_decode, -1946 remaining, -1947 }) => { -1948 let span = trace_span!("pkt", %path_id); -1949 let _guard = span.enter(); -1950 -1951 if self.update_network_path_or_discard(network_path, path_id) { -1952 // A return value of true indicates we should discard this packet. -1953 return; -1954 } +1934 /// *packet_size* is the number of bytes available to build the next packet. +1935 /// *connection_close_pending* indicates whether a CONNECTION_CLOSE frame needs to be +1936 /// sent. +1937 fn space_can_send( +1938 &mut self, +1939 space_id: SpaceId, +1940 path_id: PathId, +1941 packet_size: usize, +1942 connection_close_pending: bool, +1943 ) -> SendableFrames { +1944 let space = &mut self.spaces[space_id]; +1945 let space_has_crypto = space.crypto.is_some(); +1946 +1947 if !space_has_crypto +1948 && (space_id != SpaceId::Data +1949 || self.zero_rtt_crypto.is_none() +1950 || self.side.is_server()) +1951 { +1952 // Nothing to send in this space +1953 return SendableFrames::empty(); +1954 } 1955 -1956 let was_anti_amplification_blocked = self -1957 .path(path_id) -1958 .map(|path| path.anti_amplification_blocked(1)) -1959 .unwrap_or(true); // if we don't know about this path it's eagerly considered as unvalidated -1960 // TODO(@divma): revisit this -1961 -1962 self.stats.udp_rx.datagrams += 1; -1963 self.stats.udp_rx.bytes += first_decode.len() as u64; -1964 let rx = &mut self.path_stats.entry(path_id).or_default().udp_rx; -1965 rx.datagrams += 1; -1966 rx.bytes += first_decode.len() as u64; -1967 let data_len = first_decode.len(); -1968 -1969 self.handle_decode(now, network_path, path_id, ecn, first_decode); -1970 // The current `path` might have changed inside `handle_decode` since the packet -1971 // could have triggered a migration. The packet might also belong to an unknown -1972 // path and have been rejected. Make sure the data received is accounted for the -1973 // most recent path by accessing `path` after `handle_decode`. -1974 if let Some(path) = self.path_mut(path_id) { -1975 path.inc_total_recvd(data_len as u64); -1976 } -1977 -1978 if let Some(data) = remaining { -1979 self.stats.udp_rx.bytes += data.len() as u64; -1980 self.path_stats.entry(path_id).or_default().udp_rx.bytes += data.len() as u64; -1981 self.handle_coalesced(now, network_path, path_id, ecn, data); -1982 } -1983 -1984 if let Some(path) = self.paths.get_mut(&path_id) { -1985 self.qlog -1986 .emit_recovery_metrics(path_id, &mut path.data, now); -1987 } -1988 -1989 if was_anti_amplification_blocked { -1990 // A prior attempt to set the loss detection timer may have failed due to -1991 // anti-amplification, so ensure it's set now. Prevents a handshake deadlock if -1992 // the server's first flight is lost. -1993 self.set_loss_detection_timer(now, path_id); -1994 } -1995 } -1996 NewIdentifiers(ids, now, cid_len, cid_lifetime) => { -1997 let path_id = ids.first().map(|issued| issued.path_id).unwrap_or_default(); -1998 debug_assert!(ids.iter().all(|issued| issued.path_id == path_id)); -1999 let cid_state = self -2000 .local_cid_state -2001 .entry(path_id) -2002 .or_insert_with(|| CidState::new(cid_len, cid_lifetime, now, 0)); -2003 cid_state.new_cids(&ids, now); -2004 -2005 ids.into_iter().rev().for_each(|frame| { -2006 self.spaces[SpaceId::Data].pending.new_cids.push(frame); -2007 }); -2008 // Always update Timer::PushNewCid -2009 self.reset_cid_retirement(now); -2010 } -2011 } -2012 } -2013 -2014 /// Updates the network path for `path_id`. -2015 /// -2016 /// Returns true if a packet coming in for this `path_id` over given `network_path` should be discarded. -2017 /// Returns false if the path was updated and the packet doesn't need to be discarded. -2018 fn update_network_path_or_discard(&mut self, network_path: FourTuple, path_id: PathId) -> bool { -2019 let remote_may_migrate = self.side.remote_may_migrate(&self.state); -2020 let local_ip_may_migrate = self.side.is_client(); -2021 // If this packet could initiate a migration and we're a client or a server that -2022 // forbids migration, drop the datagram. This could be relaxed to heuristically -2023 // permit NAT-rebinding-like migration. -2024 if let Some(known_path) = self.path_mut(path_id) { -2025 if network_path.remote != known_path.network_path.remote && !remote_may_migrate { -2026 trace!( -2027 %path_id, -2028 %network_path, -2029 %known_path.network_path, -2030 "discarding packet from unrecognized peer" -2031 ); -2032 return true; -2033 } -2034 -2035 if known_path.network_path.local_ip.is_some() -2036 && network_path.local_ip.is_some() -2037 && known_path.network_path.local_ip != network_path.local_ip -2038 && !local_ip_may_migrate -2039 { -2040 trace!( -2041 %path_id, -2042 %network_path, -2043 %known_path.network_path, -2044 "discarding packet sent to incorrect interface" -2045 ); -2046 return true; -2047 } -2048 // If the datagram indicates that we've changed our local IP, we update it. -2049 // This is alluded to in Section 5.2 of the Multipath RFC draft 18: -2050 // https://www.ietf.org/archive/id/draft-ietf-quic-multipath-18.html#name-using-multiple-paths-on-the -2051 // > Client receives the packet, recognizes a path migration, updates the source address of path 2 to 192.0.2.1. -2052 if let Some(local_ip) = network_path.local_ip { -2053 if known_path -2054 .network_path -2055 .local_ip -2056 .is_some_and(|ip| ip != local_ip) -2057 { -2058 debug!( -2059 %path_id, -2060 %network_path, -2061 %known_path.network_path, -2062 "path's local address seemingly migrated" -2063 ); -2064 } -2065 // We update the address without path validation on the client side. -2066 // https://www.ietf.org/archive/id/draft-ietf-quic-multipath-18.html#section-5.1 -2067 // > Servers observing a 4-tuple change will perform path validation (see Section 9 of [QUIC-TRANSPORT]). -2068 // This sounds like it's *only* the server endpoints that do this. -2069 // TODO(matheus23): We should still consider doing a proper migration on the client side in the future. -2070 // For now, this preserves the behavior of this code pre 4-tuple tracking. -2071 known_path.network_path.local_ip = Some(local_ip); -2072 } -2073 } -2074 false -2075 } -2076 -2077 /// Process timer expirations -2078 /// -2079 /// Executes protocol logic, potentially preparing signals (including application `Event`s, -2080 /// `EndpointEvent`s and outgoing datagrams) that should be extracted through the relevant -2081 /// methods. -2082 /// -2083 /// It is most efficient to call this immediately after the system clock reaches the latest -2084 /// `Instant` that was output by `poll_timeout`; however spurious extra calls will simply -2085 /// no-op and therefore are safe. -2086 pub fn handle_timeout(&mut self, now: Instant) { -2087 while let Some((timer, _time)) = self.timers.expire_before(now, &self.qlog) { -2088 // TODO(@divma): remove `at` when the unicorn is born -2089 trace!(?timer, at=?now, "timeout"); -2090 match timer { -2091 Timer::Conn(timer) => match timer { -2092 ConnTimer::Close => { -2093 self.state.move_to_drained(None); -2094 self.endpoint_events.push_back(EndpointEventInner::Drained); -2095 } -2096 ConnTimer::Idle => { -2097 self.kill(ConnectionError::TimedOut); -2098 } -2099 ConnTimer::KeepAlive => { -2100 trace!("sending keep-alive"); -2101 self.ping(); -2102 } -2103 ConnTimer::KeyDiscard => { -2104 self.zero_rtt_crypto = None; -2105 self.prev_crypto = None; -2106 } -2107 ConnTimer::PushNewCid => { -2108 while let Some((path_id, when)) = self.next_cid_retirement() { -2109 if when > now { -2110 break; -2111 } -2112 match self.local_cid_state.get_mut(&path_id) { -2113 None => error!(%path_id, "No local CID state for path"), -2114 Some(cid_state) => { -2115 // Update `retire_prior_to` field in NEW_CONNECTION_ID frame -2116 let num_new_cid = cid_state.on_cid_timeout().into(); -2117 if !self.state.is_closed() { -2118 trace!( -2119 "push a new CID to peer RETIRE_PRIOR_TO field {}", -2120 cid_state.retire_prior_to() -2121 ); -2122 self.endpoint_events.push_back( -2123 EndpointEventInner::NeedIdentifiers( -2124 path_id, -2125 now, -2126 num_new_cid, -2127 ), -2128 ); -2129 } -2130 } -2131 } -2132 } -2133 } -2134 }, -2135 // TODO: add path_id as span somehow -2136 Timer::PerPath(path_id, timer) => { -2137 let span = trace_span!("per-path timer fired", %path_id, ?timer); -2138 let _guard = span.enter(); -2139 match timer { -2140 PathTimer::PathIdle => { -2141 self.close_path(now, path_id, TransportErrorCode::NO_ERROR.into()) -2142 .ok(); -2143 } -2144 -2145 PathTimer::PathKeepAlive => { -2146 trace!("sending keep-alive on path"); -2147 self.ping_path(path_id).ok(); -2148 } -2149 PathTimer::LossDetection => { -2150 self.on_loss_detection_timeout(now, path_id); -2151 self.qlog.emit_recovery_metrics( -2152 path_id, -2153 &mut self.paths.get_mut(&path_id).unwrap().data, -2154 now, -2155 ); -2156 } -2157 PathTimer::PathValidation => { -2158 let Some(path) = self.paths.get_mut(&path_id) else { -2159 continue; -2160 }; -2161 self.timers.stop( -2162 Timer::PerPath(path_id, PathTimer::PathChallengeLost), -2163 self.qlog.with_time(now), -2164 ); -2165 debug!("path validation failed"); -2166 if let Some((_, prev)) = path.prev.take() { -2167 path.data = prev; -2168 } -2169 path.data.challenges_sent.clear(); -2170 path.data.send_new_challenge = false; -2171 } -2172 PathTimer::PathChallengeLost => { -2173 let Some(path) = self.paths.get_mut(&path_id) else { -2174 continue; -2175 }; -2176 trace!("path challenge deemed lost"); -2177 path.data.send_new_challenge = true; -2178 } -2179 PathTimer::PathOpen => { -2180 let Some(path) = self.paths.get_mut(&path_id) else { -2181 continue; -2182 }; -2183 path.data.challenges_sent.clear(); -2184 path.data.send_new_challenge = false; -2185 self.timers.stop( -2186 Timer::PerPath(path_id, PathTimer::PathChallengeLost), -2187 self.qlog.with_time(now), -2188 ); -2189 debug!("new path validation failed"); -2190 if let Err(err) = self.close_path( -2191 now, -2192 path_id, -2193 TransportErrorCode::PATH_UNSTABLE_OR_POOR.into(), -2194 ) { -2195 warn!(?err, "failed closing path"); -2196 } -2197 -2198 self.events.push_back(Event::Path(PathEvent::LocallyClosed { -2199 id: path_id, -2200 error: PathError::ValidationFailed, -2201 })); -2202 } -2203 PathTimer::Pacing => trace!("pacing timer expired"), -2204 PathTimer::MaxAckDelay => { -2205 trace!("max ack delay reached"); -2206 // This timer is only armed in the Data space -2207 self.spaces[SpaceId::Data] -2208 .for_path(path_id) -2209 .pending_acks -2210 .on_max_ack_delay_timeout() -2211 } -2212 PathTimer::DiscardPath => { -2213 // The path was abandoned and 3*PTO has expired since. Clean up all -2214 // remaining state and install stateless reset token. -2215 self.timers.stop_per_path(path_id, self.qlog.with_time(now)); -2216 if let Some(loc_cid_state) = self.local_cid_state.remove(&path_id) { -2217 let (min_seq, max_seq) = loc_cid_state.active_seq(); -2218 for seq in min_seq..=max_seq { -2219 self.endpoint_events.push_back( -2220 EndpointEventInner::RetireConnectionId( -2221 now, path_id, seq, false, -2222 ), -2223 ); -2224 } -2225 } -2226 self.discard_path(path_id, now); -2227 } -2228 } -2229 } -2230 } -2231 } -2232 } -2233 -2234 /// Close a connection immediately -2235 /// -2236 /// This does not ensure delivery of outstanding data. It is the application's responsibility to -2237 /// call this only when all important communications have been completed, e.g. by calling -2238 /// [`SendStream::finish`] on outstanding streams and waiting for the corresponding -2239 /// [`StreamEvent::Finished`] event. -2240 /// -2241 /// If [`Streams::send_streams`] returns 0, all outstanding stream data has been -2242 /// delivered. There may still be data from the peer that has not been received. -2243 /// -2244 /// [`StreamEvent::Finished`]: crate::StreamEvent::Finished -2245 pub fn close(&mut self, now: Instant, error_code: VarInt, reason: Bytes) { -2246 self.close_inner( -2247 now, -2248 Close::Application(frame::ApplicationClose { error_code, reason }), -2249 ) -2250 } -2251 -2252 fn close_inner(&mut self, now: Instant, reason: Close) { -2253 let was_closed = self.state.is_closed(); -2254 if !was_closed { -2255 self.close_common(); -2256 self.set_close_timer(now); -2257 self.close = true; -2258 self.state.move_to_closed_local(reason); -2259 } -2260 } -2261 -2262 /// Control datagrams -2263 pub fn datagrams(&mut self) -> Datagrams<'_> { -2264 Datagrams { conn: self } -2265 } -2266 -2267 /// Returns connection statistics -2268 pub fn stats(&mut self) -> ConnectionStats { -2269 self.stats.clone() -2270 } -2271 -2272 /// Returns path statistics -2273 pub fn path_stats(&mut self, path_id: PathId) -> Option<PathStats> { -2274 let path = self.paths.get(&path_id)?; -2275 let stats = self.path_stats.entry(path_id).or_default(); -2276 stats.rtt = path.data.rtt.get(); -2277 stats.cwnd = path.data.congestion.window(); -2278 stats.current_mtu = path.data.mtud.current_mtu(); -2279 Some(*stats) -2280 } -2281 -2282 /// Ping the remote endpoint -2283 /// -2284 /// Causes an ACK-eliciting packet to be transmitted on the connection. -2285 pub fn ping(&mut self) { -2286 // TODO(flub): This is very brute-force: it pings *all* the paths. Instead it would -2287 // be nice if we could only send a single packet for this. -2288 for path_data in self.spaces[self.highest_space].number_spaces.values_mut() { -2289 path_data.ping_pending = true; -2290 } -2291 } -2292 -2293 /// Ping the remote endpoint over a specific path -2294 /// -2295 /// Causes an ACK-eliciting packet to be transmitted on the path. -2296 pub fn ping_path(&mut self, path: PathId) -> Result<(), ClosedPath> { -2297 let path_data = self.spaces[self.highest_space] -2298 .number_spaces -2299 .get_mut(&path) -2300 .ok_or(ClosedPath { _private: () })?; -2301 path_data.ping_pending = true; -2302 Ok(()) -2303 } -2304 -2305 /// Update traffic keys spontaneously -2306 /// -2307 /// This can be useful for testing key updates, as they otherwise only happen infrequently. -2308 pub fn force_key_update(&mut self) { -2309 if !self.state.is_established() { -2310 debug!("ignoring forced key update in illegal state"); -2311 return; -2312 } -2313 if self.prev_crypto.is_some() { -2314 // We already just updated, or are currently updating, the keys. Concurrent key updates -2315 // are illegal. -2316 debug!("ignoring redundant forced key update"); -2317 return; -2318 } -2319 self.update_keys(None, false); -2320 } -2321 -2322 /// Get a session reference -2323 pub fn crypto_session(&self) -> &dyn crypto::Session { -2324 &*self.crypto -2325 } -2326 -2327 /// Whether the connection is in the process of being established -2328 /// -2329 /// If this returns `false`, the connection may be either established or closed, signaled by the -2330 /// emission of a `Connected` or `ConnectionLost` message respectively. -2331 pub fn is_handshaking(&self) -> bool { -2332 self.state.is_handshake() -2333 } -2334 -2335 /// Whether the connection is closed -2336 /// -2337 /// Closed connections cannot transport any further data. A connection becomes closed when -2338 /// either peer application intentionally closes it, or when either transport layer detects an -2339 /// error such as a time-out or certificate validation failure. -2340 /// -2341 /// A `ConnectionLost` event is emitted with details when the connection becomes closed. -2342 pub fn is_closed(&self) -> bool { -2343 self.state.is_closed() -2344 } -2345 -2346 /// Whether there is no longer any need to keep the connection around -2347 /// -2348 /// Closed connections become drained after a brief timeout to absorb any remaining in-flight -2349 /// packets from the peer. All drained connections have been closed. -2350 pub fn is_drained(&self) -> bool { -2351 self.state.is_drained() -2352 } -2353 -2354 /// For clients, if the peer accepted the 0-RTT data packets -2355 /// -2356 /// The value is meaningless until after the handshake completes. -2357 pub fn accepted_0rtt(&self) -> bool { -2358 self.accepted_0rtt -2359 } -2360 -2361 /// Whether 0-RTT is/was possible during the handshake -2362 pub fn has_0rtt(&self) -> bool { -2363 self.zero_rtt_enabled +1956 let mut can_send = space.can_send(path_id, &self.streams); +1957 +1958 // Check for 1RTT space. +1959 if space_id == SpaceId::Data { +1960 let pn = space.for_path(path_id).peek_tx_number(); +1961 // Number of bytes available for frames if this is a 1-RTT packet. We're +1962 // guaranteed to be able to send an individual frame at least this large in the +1963 // next 1-RTT packet. This could be generalized to support every space, but it's +1964 // only needed to handle large fixed-size frames, which only exist in 1-RTT +1965 // (application datagrams). +1966 let frame_space_1rtt = +1967 packet_size.saturating_sub(self.predict_1rtt_overhead(pn, path_id)); +1968 can_send |= self.can_send_1rtt(path_id, frame_space_1rtt); +1969 } +1970 +1971 can_send.close = connection_close_pending && space_has_crypto; +1972 +1973 can_send +1974 } +1975 +1976 /// Process `ConnectionEvent`s generated by the associated `Endpoint` +1977 /// +1978 /// Will execute protocol logic upon receipt of a connection event, in turn preparing signals +1979 /// (including application `Event`s, `EndpointEvent`s and outgoing datagrams) that should be +1980 /// extracted through the relevant methods. +1981 pub fn handle_event(&mut self, event: ConnectionEvent) { +1982 use ConnectionEventInner::*; +1983 match event.0 { +1984 Datagram(DatagramConnectionEvent { +1985 now, +1986 network_path, +1987 path_id, +1988 ecn, +1989 first_decode, +1990 remaining, +1991 }) => { +1992 let span = trace_span!("pkt", %path_id); +1993 let _guard = span.enter(); +1994 +1995 if self.update_network_path_or_discard(network_path, path_id) { +1996 // A return value of true indicates we should discard this packet. +1997 return; +1998 } +1999 +2000 let was_anti_amplification_blocked = self +2001 .path(path_id) +2002 .map(|path| path.anti_amplification_blocked(1)) +2003 .unwrap_or(true); // if we don't know about this path it's eagerly considered as unvalidated +2004 // TODO(@divma): revisit this +2005 +2006 self.stats.udp_rx.datagrams += 1; +2007 self.stats.udp_rx.bytes += first_decode.len() as u64; +2008 let rx = &mut self.path_stats.entry(path_id).or_default().udp_rx; +2009 rx.datagrams += 1; +2010 rx.bytes += first_decode.len() as u64; +2011 let data_len = first_decode.len(); +2012 +2013 self.handle_decode(now, network_path, path_id, ecn, first_decode); +2014 // The current `path` might have changed inside `handle_decode` since the packet +2015 // could have triggered a migration. The packet might also belong to an unknown +2016 // path and have been rejected. Make sure the data received is accounted for the +2017 // most recent path by accessing `path` after `handle_decode`. +2018 if let Some(path) = self.path_mut(path_id) { +2019 path.inc_total_recvd(data_len as u64); +2020 } +2021 +2022 if let Some(data) = remaining { +2023 self.stats.udp_rx.bytes += data.len() as u64; +2024 self.path_stats.entry(path_id).or_default().udp_rx.bytes += data.len() as u64; +2025 self.handle_coalesced(now, network_path, path_id, ecn, data); +2026 } +2027 +2028 if let Some(path) = self.paths.get_mut(&path_id) { +2029 self.qlog +2030 .emit_recovery_metrics(path_id, &mut path.data, now); +2031 } +2032 +2033 if was_anti_amplification_blocked { +2034 // A prior attempt to set the loss detection timer may have failed due to +2035 // anti-amplification, so ensure it's set now. Prevents a handshake deadlock if +2036 // the server's first flight is lost. +2037 self.set_loss_detection_timer(now, path_id); +2038 } +2039 } +2040 NewIdentifiers(ids, now, cid_len, cid_lifetime) => { +2041 let path_id = ids.first().map(|issued| issued.path_id).unwrap_or_default(); +2042 debug_assert!(ids.iter().all(|issued| issued.path_id == path_id)); +2043 let cid_state = self +2044 .local_cid_state +2045 .entry(path_id) +2046 .or_insert_with(|| CidState::new(cid_len, cid_lifetime, now, 0)); +2047 cid_state.new_cids(&ids, now); +2048 +2049 ids.into_iter().rev().for_each(|frame| { +2050 self.spaces[SpaceId::Data].pending.new_cids.push(frame); +2051 }); +2052 // Always update Timer::PushNewCid +2053 self.reset_cid_retirement(now); +2054 } +2055 } +2056 } +2057 +2058 /// Updates the network path for `path_id`. +2059 /// +2060 /// Returns true if a packet coming in for this `path_id` over given `network_path` should be discarded. +2061 /// Returns false if the path was updated and the packet doesn't need to be discarded. +2062 fn update_network_path_or_discard(&mut self, network_path: FourTuple, path_id: PathId) -> bool { +2063 let remote_may_migrate = self.side.remote_may_migrate(&self.state); +2064 let local_ip_may_migrate = self.side.is_client(); +2065 // If this packet could initiate a migration and we're a client or a server that +2066 // forbids migration, drop the datagram. This could be relaxed to heuristically +2067 // permit NAT-rebinding-like migration. +2068 if let Some(known_path) = self.path_mut(path_id) { +2069 if network_path.remote != known_path.network_path.remote && !remote_may_migrate { +2070 trace!( +2071 %path_id, +2072 %network_path, +2073 %known_path.network_path, +2074 "discarding packet from unrecognized peer" +2075 ); +2076 return true; +2077 } +2078 +2079 if known_path.network_path.local_ip.is_some() +2080 && network_path.local_ip.is_some() +2081 && known_path.network_path.local_ip != network_path.local_ip +2082 && !local_ip_may_migrate +2083 { +2084 trace!( +2085 %path_id, +2086 %network_path, +2087 %known_path.network_path, +2088 "discarding packet sent to incorrect interface" +2089 ); +2090 return true; +2091 } +2092 // If the datagram indicates that we've changed our local IP, we update it. +2093 // This is alluded to in Section 5.2 of the Multipath RFC draft 18: +2094 // https://www.ietf.org/archive/id/draft-ietf-quic-multipath-18.html#name-using-multiple-paths-on-the +2095 // > Client receives the packet, recognizes a path migration, updates the source address of path 2 to 192.0.2.1. +2096 if let Some(local_ip) = network_path.local_ip { +2097 if known_path +2098 .network_path +2099 .local_ip +2100 .is_some_and(|ip| ip != local_ip) +2101 { +2102 debug!( +2103 %path_id, +2104 %network_path, +2105 %known_path.network_path, +2106 "path's local address seemingly migrated" +2107 ); +2108 } +2109 // We update the address without path validation on the client side. +2110 // https://www.ietf.org/archive/id/draft-ietf-quic-multipath-18.html#section-5.1 +2111 // > Servers observing a 4-tuple change will perform path validation (see Section 9 of [QUIC-TRANSPORT]). +2112 // This sounds like it's *only* the server endpoints that do this. +2113 // TODO(matheus23): We should still consider doing a proper migration on the client side in the future. +2114 // For now, this preserves the behavior of this code pre 4-tuple tracking. +2115 known_path.network_path.local_ip = Some(local_ip); +2116 } +2117 } +2118 false +2119 } +2120 +2121 /// Process timer expirations +2122 /// +2123 /// Executes protocol logic, potentially preparing signals (including application `Event`s, +2124 /// `EndpointEvent`s and outgoing datagrams) that should be extracted through the relevant +2125 /// methods. +2126 /// +2127 /// It is most efficient to call this immediately after the system clock reaches the latest +2128 /// `Instant` that was output by `poll_timeout`; however spurious extra calls will simply +2129 /// no-op and therefore are safe. +2130 pub fn handle_timeout(&mut self, now: Instant) { +2131 while let Some((timer, _time)) = self.timers.expire_before(now, &self.qlog) { +2132 // TODO(@divma): remove `at` when the unicorn is born +2133 trace!(?timer, at=?now, "timeout"); +2134 match timer { +2135 Timer::Conn(timer) => match timer { +2136 ConnTimer::Close => { +2137 self.state.move_to_drained(None); +2138 self.endpoint_events.push_back(EndpointEventInner::Drained); +2139 } +2140 ConnTimer::Idle => { +2141 self.kill(ConnectionError::TimedOut); +2142 } +2143 ConnTimer::KeepAlive => { +2144 trace!("sending keep-alive"); +2145 self.ping(); +2146 } +2147 ConnTimer::KeyDiscard => { +2148 self.zero_rtt_crypto = None; +2149 self.prev_crypto = None; +2150 } +2151 ConnTimer::PushNewCid => { +2152 while let Some((path_id, when)) = self.next_cid_retirement() { +2153 if when > now { +2154 break; +2155 } +2156 match self.local_cid_state.get_mut(&path_id) { +2157 None => error!(%path_id, "No local CID state for path"), +2158 Some(cid_state) => { +2159 // Update `retire_prior_to` field in NEW_CONNECTION_ID frame +2160 let num_new_cid = cid_state.on_cid_timeout().into(); +2161 if !self.state.is_closed() { +2162 trace!( +2163 "push a new CID to peer RETIRE_PRIOR_TO field {}", +2164 cid_state.retire_prior_to() +2165 ); +2166 self.endpoint_events.push_back( +2167 EndpointEventInner::NeedIdentifiers( +2168 path_id, +2169 now, +2170 num_new_cid, +2171 ), +2172 ); +2173 } +2174 } +2175 } +2176 } +2177 } +2178 }, +2179 // TODO: add path_id as span somehow +2180 Timer::PerPath(path_id, timer) => { +2181 let span = trace_span!("per-path timer fired", %path_id, ?timer); +2182 let _guard = span.enter(); +2183 match timer { +2184 PathTimer::PathIdle => { +2185 self.close_path(now, path_id, TransportErrorCode::NO_ERROR.into()) +2186 .ok(); +2187 } +2188 +2189 PathTimer::PathKeepAlive => { +2190 trace!("sending keep-alive on path"); +2191 self.ping_path(path_id).ok(); +2192 } +2193 PathTimer::LossDetection => { +2194 self.on_loss_detection_timeout(now, path_id); +2195 self.qlog.emit_recovery_metrics( +2196 path_id, +2197 &mut self.paths.get_mut(&path_id).unwrap().data, +2198 now, +2199 ); +2200 } +2201 PathTimer::PathValidation => { +2202 let Some(path) = self.paths.get_mut(&path_id) else { +2203 continue; +2204 }; +2205 self.timers.stop( +2206 Timer::PerPath(path_id, PathTimer::PathChallengeLost), +2207 self.qlog.with_time(now), +2208 ); +2209 debug!("path validation failed"); +2210 if let Some((_, prev)) = path.prev.take() { +2211 path.data = prev; +2212 } +2213 path.data.challenges_sent.clear(); +2214 path.data.send_new_challenge = false; +2215 } +2216 PathTimer::PathChallengeLost => { +2217 let Some(path) = self.paths.get_mut(&path_id) else { +2218 continue; +2219 }; +2220 trace!("path challenge deemed lost"); +2221 path.data.send_new_challenge = true; +2222 } +2223 PathTimer::PathOpen => { +2224 let Some(path) = self.paths.get_mut(&path_id) else { +2225 continue; +2226 }; +2227 path.data.challenges_sent.clear(); +2228 path.data.send_new_challenge = false; +2229 self.timers.stop( +2230 Timer::PerPath(path_id, PathTimer::PathChallengeLost), +2231 self.qlog.with_time(now), +2232 ); +2233 debug!("new path validation failed"); +2234 if let Err(err) = self.close_path( +2235 now, +2236 path_id, +2237 TransportErrorCode::PATH_UNSTABLE_OR_POOR.into(), +2238 ) { +2239 warn!(?err, "failed closing path"); +2240 } +2241 +2242 self.events.push_back(Event::Path(PathEvent::LocallyClosed { +2243 id: path_id, +2244 error: PathError::ValidationFailed, +2245 })); +2246 } +2247 PathTimer::Pacing => trace!("pacing timer expired"), +2248 PathTimer::MaxAckDelay => { +2249 trace!("max ack delay reached"); +2250 // This timer is only armed in the Data space +2251 self.spaces[SpaceId::Data] +2252 .for_path(path_id) +2253 .pending_acks +2254 .on_max_ack_delay_timeout() +2255 } +2256 PathTimer::DiscardPath => { +2257 // The path was abandoned and 3*PTO has expired since. Clean up all +2258 // remaining state and install stateless reset token. +2259 self.timers.stop_per_path(path_id, self.qlog.with_time(now)); +2260 if let Some(loc_cid_state) = self.local_cid_state.remove(&path_id) { +2261 let (min_seq, max_seq) = loc_cid_state.active_seq(); +2262 for seq in min_seq..=max_seq { +2263 self.endpoint_events.push_back( +2264 EndpointEventInner::RetireConnectionId( +2265 now, path_id, seq, false, +2266 ), +2267 ); +2268 } +2269 } +2270 self.discard_path(path_id, now); +2271 } +2272 } +2273 } +2274 } +2275 } +2276 } +2277 +2278 /// Close a connection immediately +2279 /// +2280 /// This does not ensure delivery of outstanding data. It is the application's responsibility to +2281 /// call this only when all important communications have been completed, e.g. by calling +2282 /// [`SendStream::finish`] on outstanding streams and waiting for the corresponding +2283 /// [`StreamEvent::Finished`] event. +2284 /// +2285 /// If [`Streams::send_streams`] returns 0, all outstanding stream data has been +2286 /// delivered. There may still be data from the peer that has not been received. +2287 /// +2288 /// [`StreamEvent::Finished`]: crate::StreamEvent::Finished +2289 pub fn close(&mut self, now: Instant, error_code: VarInt, reason: Bytes) { +2290 self.close_inner( +2291 now, +2292 Close::Application(frame::ApplicationClose { error_code, reason }), +2293 ) +2294 } +2295 +2296 fn close_inner(&mut self, now: Instant, reason: Close) { +2297 let was_closed = self.state.is_closed(); +2298 if !was_closed { +2299 self.close_common(); +2300 self.set_close_timer(now); +2301 self.connection_close_pending = true; +2302 self.state.move_to_closed_local(reason); +2303 } +2304 } +2305 +2306 /// Control datagrams +2307 pub fn datagrams(&mut self) -> Datagrams<'_> { +2308 Datagrams { conn: self } +2309 } +2310 +2311 /// Returns connection statistics +2312 pub fn stats(&mut self) -> ConnectionStats { +2313 self.stats.clone() +2314 } +2315 +2316 /// Returns path statistics +2317 pub fn path_stats(&mut self, path_id: PathId) -> Option<PathStats> { +2318 let path = self.paths.get(&path_id)?; +2319 let stats = self.path_stats.entry(path_id).or_default(); +2320 stats.rtt = path.data.rtt.get(); +2321 stats.cwnd = path.data.congestion.window(); +2322 stats.current_mtu = path.data.mtud.current_mtu(); +2323 Some(*stats) +2324 } +2325 +2326 /// Ping the remote endpoint +2327 /// +2328 /// Causes an ACK-eliciting packet to be transmitted on the connection. +2329 pub fn ping(&mut self) { +2330 // TODO(flub): This is very brute-force: it pings *all* the paths. Instead it would +2331 // be nice if we could only send a single packet for this. +2332 for path_data in self.spaces[self.highest_space].number_spaces.values_mut() { +2333 path_data.ping_pending = true; +2334 } +2335 } +2336 +2337 /// Ping the remote endpoint over a specific path +2338 /// +2339 /// Causes an ACK-eliciting packet to be transmitted on the path. +2340 pub fn ping_path(&mut self, path: PathId) -> Result<(), ClosedPath> { +2341 let path_data = self.spaces[self.highest_space] +2342 .number_spaces +2343 .get_mut(&path) +2344 .ok_or(ClosedPath { _private: () })?; +2345 path_data.ping_pending = true; +2346 Ok(()) +2347 } +2348 +2349 /// Update traffic keys spontaneously +2350 /// +2351 /// This can be useful for testing key updates, as they otherwise only happen infrequently. +2352 pub fn force_key_update(&mut self) { +2353 if !self.state.is_established() { +2354 debug!("ignoring forced key update in illegal state"); +2355 return; +2356 } +2357 if self.prev_crypto.is_some() { +2358 // We already just updated, or are currently updating, the keys. Concurrent key updates +2359 // are illegal. +2360 debug!("ignoring redundant forced key update"); +2361 return; +2362 } +2363 self.update_keys(None, false); 2364 } 2365 -2366 /// Whether there are any pending retransmits -2367 pub fn has_pending_retransmits(&self) -> bool { -2368 !self.spaces[SpaceId::Data].pending.is_empty(&self.streams) +2366 /// Get a session reference +2367 pub fn crypto_session(&self) -> &dyn crypto::Session { +2368 &*self.crypto 2369 } 2370 -2371 /// Look up whether we're the client or server of this Connection -2372 pub fn side(&self) -> Side { -2373 self.side.side() -2374 } -2375 -2376 /// Get the address observed by the remote over the given path -2377 pub fn path_observed_address(&self, path_id: PathId) -> Result<Option<SocketAddr>, ClosedPath> { -2378 self.path(path_id) -2379 .map(|path_data| { -2380 path_data -2381 .last_observed_addr_report -2382 .as_ref() -2383 .map(|observed| observed.socket_addr()) -2384 }) -2385 .ok_or(ClosedPath { _private: () }) -2386 } -2387 -2388 /// Current best estimate of this connection's latency (round-trip-time) -2389 pub fn rtt(&self, path_id: PathId) -> Option<Duration> { -2390 self.path(path_id).map(|d| d.rtt.get()) -2391 } -2392 -2393 /// Current state of this connection's congestion controller, for debugging purposes -2394 pub fn congestion_state(&self, path_id: PathId) -> Option<&dyn Controller> { -2395 self.path(path_id).map(|d| d.congestion.as_ref()) +2371 /// Whether the connection is in the process of being established +2372 /// +2373 /// If this returns `false`, the connection may be either established or closed, signaled by the +2374 /// emission of a `Connected` or `ConnectionLost` message respectively. +2375 pub fn is_handshaking(&self) -> bool { +2376 self.state.is_handshake() +2377 } +2378 +2379 /// Whether the connection is closed +2380 /// +2381 /// Closed connections cannot transport any further data. A connection becomes closed when +2382 /// either peer application intentionally closes it, or when either transport layer detects an +2383 /// error such as a time-out or certificate validation failure. +2384 /// +2385 /// A `ConnectionLost` event is emitted with details when the connection becomes closed. +2386 pub fn is_closed(&self) -> bool { +2387 self.state.is_closed() +2388 } +2389 +2390 /// Whether there is no longer any need to keep the connection around +2391 /// +2392 /// Closed connections become drained after a brief timeout to absorb any remaining in-flight +2393 /// packets from the peer. All drained connections have been closed. +2394 pub fn is_drained(&self) -> bool { +2395 self.state.is_drained() 2396 } 2397 -2398 /// Modify the number of remotely initiated streams that may be concurrently open +2398 /// For clients, if the peer accepted the 0-RTT data packets 2399 /// -2400 /// No streams may be opened by the peer unless fewer than `count` are already open. Large -2401 /// `count`s increase both minimum and worst-case memory consumption. -2402 pub fn set_max_concurrent_streams(&mut self, dir: Dir, count: VarInt) { -2403 self.streams.set_max_concurrent(dir, count); -2404 // If the limit was reduced, then a flow control update previously deemed insignificant may -2405 // now be significant. -2406 let pending = &mut self.spaces[SpaceId::Data].pending; -2407 self.streams.queue_max_stream_id(pending); +2400 /// The value is meaningless until after the handshake completes. +2401 pub fn accepted_0rtt(&self) -> bool { +2402 self.accepted_0rtt +2403 } +2404 +2405 /// Whether 0-RTT is/was possible during the handshake +2406 pub fn has_0rtt(&self) -> bool { +2407 self.zero_rtt_enabled 2408 } 2409 -2410 /// Modify the number of open paths allowed when multipath is enabled -2411 /// -2412 /// When reducing the number of concurrent paths this will only affect delaying sending -2413 /// new MAX_PATH_ID frames until fewer than this number of paths are possible. To -2414 /// actively reduce paths they must be closed using [`Connection::close_path`], which -2415 /// can also be used to close not-yet-opened paths. -2416 /// -2417 /// If multipath is not negotiated (see the [`TransportConfig`]) this can not enable -2418 /// multipath and will fail. -2419 pub fn set_max_concurrent_paths( -2420 &mut self, -2421 now: Instant, -2422 count: NonZeroU32, -2423 ) -> Result<(), MultipathNotNegotiated> { -2424 if !self.is_multipath_negotiated() { -2425 return Err(MultipathNotNegotiated { _private: () }); -2426 } -2427 self.max_concurrent_paths = count; -2428 -2429 let in_use_count = self -2430 .local_max_path_id -2431 .next() -2432 .saturating_sub(self.abandoned_paths.len() as u32) -2433 .as_u32(); -2434 let extra_needed = count.get().saturating_sub(in_use_count); -2435 let new_max_path_id = self.local_max_path_id.saturating_add(extra_needed); +2410 /// Whether there are any pending retransmits +2411 pub fn has_pending_retransmits(&self) -> bool { +2412 !self.spaces[SpaceId::Data].pending.is_empty(&self.streams) +2413 } +2414 +2415 /// Look up whether we're the client or server of this Connection +2416 pub fn side(&self) -> Side { +2417 self.side.side() +2418 } +2419 +2420 /// Get the address observed by the remote over the given path +2421 pub fn path_observed_address(&self, path_id: PathId) -> Result<Option<SocketAddr>, ClosedPath> { +2422 self.path(path_id) +2423 .map(|path_data| { +2424 path_data +2425 .last_observed_addr_report +2426 .as_ref() +2427 .map(|observed| observed.socket_addr()) +2428 }) +2429 .ok_or(ClosedPath { _private: () }) +2430 } +2431 +2432 /// Current best estimate of this connection's latency (round-trip-time) +2433 pub fn rtt(&self, path_id: PathId) -> Option<Duration> { +2434 self.path(path_id).map(|d| d.rtt.get()) +2435 } 2436 -2437 self.set_max_path_id(now, new_max_path_id); -2438 -2439 Ok(()) +2437 /// Current state of this connection's congestion controller, for debugging purposes +2438 pub fn congestion_state(&self, path_id: PathId) -> Option<&dyn Controller> { +2439 self.path(path_id).map(|d| d.congestion.as_ref()) 2440 } 2441 -2442 /// If needed, issues a new MAX_PATH_ID frame and new CIDs for any newly allowed paths -2443 fn set_max_path_id(&mut self, now: Instant, max_path_id: PathId) { -2444 if max_path_id <= self.local_max_path_id { -2445 return; -2446 } -2447 -2448 self.local_max_path_id = max_path_id; -2449 self.spaces[SpaceId::Data].pending.max_path_id = true; -2450 -2451 self.issue_first_path_cids(now); +2442 /// Modify the number of remotely initiated streams that may be concurrently open +2443 /// +2444 /// No streams may be opened by the peer unless fewer than `count` are already open. Large +2445 /// `count`s increase both minimum and worst-case memory consumption. +2446 pub fn set_max_concurrent_streams(&mut self, dir: Dir, count: VarInt) { +2447 self.streams.set_max_concurrent(dir, count); +2448 // If the limit was reduced, then a flow control update previously deemed insignificant may +2449 // now be significant. +2450 let pending = &mut self.spaces[SpaceId::Data].pending; +2451 self.streams.queue_max_stream_id(pending); 2452 } 2453 -2454 /// Current number of remotely initiated streams that may be concurrently open +2454 /// Modify the number of open paths allowed when multipath is enabled 2455 /// -2456 /// If the target for this limit is reduced using [`set_max_concurrent_streams`](Self::set_max_concurrent_streams), -2457 /// it will not change immediately, even if fewer streams are open. Instead, it will -2458 /// decrement by one for each time a remotely initiated stream of matching directionality is closed. -2459 pub fn max_concurrent_streams(&self, dir: Dir) -> u64 { -2460 self.streams.max_concurrent(dir) -2461 } -2462 -2463 /// See [`TransportConfig::send_window()`] -2464 pub fn set_send_window(&mut self, send_window: u64) { -2465 self.streams.set_send_window(send_window); -2466 } -2467 -2468 /// See [`TransportConfig::receive_window()`] -2469 pub fn set_receive_window(&mut self, receive_window: VarInt) { -2470 if self.streams.set_receive_window(receive_window) { -2471 self.spaces[SpaceId::Data].pending.max_data = true; -2472 } -2473 } -2474 -2475 /// Whether the Multipath for QUIC extension is enabled. -2476 /// -2477 /// Multipath is only enabled after the handshake is completed and if it was enabled by both -2478 /// peers. -2479 pub fn is_multipath_negotiated(&self) -> bool { -2480 !self.is_handshaking() -2481 && self.config.max_concurrent_multipath_paths.is_some() -2482 && self.peer_params.initial_max_path_id.is_some() -2483 } -2484 -2485 fn on_ack_received( -2486 &mut self, -2487 now: Instant, -2488 space: SpaceId, -2489 ack: frame::Ack, -2490 ) -> Result<(), TransportError> { -2491 // All ACKs are referencing path 0 -2492 let path = PathId::ZERO; -2493 self.inner_on_ack_received(now, space, path, ack) -2494 } -2495 -2496 fn on_path_ack_received( -2497 &mut self, -2498 now: Instant, -2499 space: SpaceId, -2500 path_ack: frame::PathAck, -2501 ) -> Result<(), TransportError> { -2502 let (ack, path) = path_ack.into_ack(); -2503 self.inner_on_ack_received(now, space, path, ack) -2504 } -2505 -2506 /// Handles an ACK frame acknowledging packets sent on *path*. -2507 fn inner_on_ack_received( -2508 &mut self, -2509 now: Instant, -2510 space: SpaceId, -2511 path: PathId, -2512 ack: frame::Ack, -2513 ) -> Result<(), TransportError> { -2514 if self.abandoned_paths.contains(&path) { -2515 // See also https://www.ietf.org/archive/id/draft-ietf-quic-multipath-17.html#section-3.4.3-3 -2516 // > PATH_ACK frames received with an abandoned path ID are silently ignored, as specified in Section 4. -2517 trace!("silently ignoring PATH_ACK on abandoned path"); -2518 return Ok(()); -2519 } -2520 if ack.largest >= self.spaces[space].for_path(path).next_packet_number { -2521 return Err(TransportError::PROTOCOL_VIOLATION("unsent packet acked")); -2522 } -2523 let new_largest = { -2524 let space = &mut self.spaces[space].for_path(path); -2525 if space.largest_acked_packet.is_none_or(|pn| ack.largest > pn) { -2526 space.largest_acked_packet = Some(ack.largest); -2527 if let Some(info) = space.sent_packets.get(ack.largest) { -2528 // This should always succeed, but a misbehaving peer might ACK a packet we -2529 // haven't sent. At worst, that will result in us spuriously reducing the -2530 // congestion window. -2531 space.largest_acked_packet_sent = info.time_sent; -2532 } -2533 true -2534 } else { -2535 false -2536 } -2537 }; -2538 -2539 if self.detect_spurious_loss(&ack, space, path) { -2540 self.path_data_mut(path) -2541 .congestion -2542 .on_spurious_congestion_event(); -2543 } -2544 -2545 // Avoid DoS from unreasonably huge ack ranges by filtering out just the new acks. -2546 let mut newly_acked = ArrayRangeSet::new(); -2547 for range in ack.iter() { -2548 self.spaces[space].for_path(path).check_ack(range.clone())?; -2549 for (pn, _) in self.spaces[space] -2550 .for_path(path) -2551 .sent_packets -2552 .iter_range(range) -2553 { -2554 newly_acked.insert_one(pn); -2555 } -2556 } -2557 -2558 if newly_acked.is_empty() { -2559 return Ok(()); -2560 } -2561 -2562 let mut ack_eliciting_acked = false; -2563 for packet in newly_acked.elts() { -2564 if let Some(info) = self.spaces[space].for_path(path).take(packet) { -2565 for (acked_path_id, acked_pn) in info.largest_acked.iter() { -2566 // Assume ACKs for all packets below the largest acknowledged in -2567 // `packet` have been received. This can cause the peer to spuriously -2568 // retransmit if some of our earlier ACKs were lost, but allows for -2569 // simpler state tracking. See discussion at -2570 // https://www.rfc-editor.org/rfc/rfc9000.html#name-limiting-ranges-by-tracking -2571 if let Some(pns) = self.spaces[space].path_space_mut(*acked_path_id) { -2572 pns.pending_acks.subtract_below(*acked_pn); -2573 } -2574 } -2575 ack_eliciting_acked |= info.ack_eliciting; -2576 -2577 // Notify MTU discovery that a packet was acked, because it might be an MTU probe -2578 let path_data = self.path_data_mut(path); -2579 let mtu_updated = path_data.mtud.on_acked(space, packet, info.size); -2580 if mtu_updated { -2581 path_data -2582 .congestion -2583 .on_mtu_update(path_data.mtud.current_mtu()); -2584 } -2585 -2586 // Notify ack frequency that a packet was acked, because it might contain an ACK_FREQUENCY frame -2587 self.ack_frequency.on_acked(path, packet); +2456 /// When reducing the number of concurrent paths this will only affect delaying sending +2457 /// new MAX_PATH_ID frames until fewer than this number of paths are possible. To +2458 /// actively reduce paths they must be closed using [`Connection::close_path`], which +2459 /// can also be used to close not-yet-opened paths. +2460 /// +2461 /// If multipath is not negotiated (see the [`TransportConfig`]) this can not enable +2462 /// multipath and will fail. +2463 pub fn set_max_concurrent_paths( +2464 &mut self, +2465 now: Instant, +2466 count: NonZeroU32, +2467 ) -> Result<(), MultipathNotNegotiated> { +2468 if !self.is_multipath_negotiated() { +2469 return Err(MultipathNotNegotiated { _private: () }); +2470 } +2471 self.max_concurrent_paths = count; +2472 +2473 let in_use_count = self +2474 .local_max_path_id +2475 .next() +2476 .saturating_sub(self.abandoned_paths.len() as u32) +2477 .as_u32(); +2478 let extra_needed = count.get().saturating_sub(in_use_count); +2479 let new_max_path_id = self.local_max_path_id.saturating_add(extra_needed); +2480 +2481 self.set_max_path_id(now, new_max_path_id); +2482 +2483 Ok(()) +2484 } +2485 +2486 /// If needed, issues a new MAX_PATH_ID frame and new CIDs for any newly allowed paths +2487 fn set_max_path_id(&mut self, now: Instant, max_path_id: PathId) { +2488 if max_path_id <= self.local_max_path_id { +2489 return; +2490 } +2491 +2492 self.local_max_path_id = max_path_id; +2493 self.spaces[SpaceId::Data].pending.max_path_id = true; +2494 +2495 self.issue_first_path_cids(now); +2496 } +2497 +2498 /// Current number of remotely initiated streams that may be concurrently open +2499 /// +2500 /// If the target for this limit is reduced using [`set_max_concurrent_streams`](Self::set_max_concurrent_streams), +2501 /// it will not change immediately, even if fewer streams are open. Instead, it will +2502 /// decrement by one for each time a remotely initiated stream of matching directionality is closed. +2503 pub fn max_concurrent_streams(&self, dir: Dir) -> u64 { +2504 self.streams.max_concurrent(dir) +2505 } +2506 +2507 /// See [`TransportConfig::send_window()`] +2508 pub fn set_send_window(&mut self, send_window: u64) { +2509 self.streams.set_send_window(send_window); +2510 } +2511 +2512 /// See [`TransportConfig::receive_window()`] +2513 pub fn set_receive_window(&mut self, receive_window: VarInt) { +2514 if self.streams.set_receive_window(receive_window) { +2515 self.spaces[SpaceId::Data].pending.max_data = true; +2516 } +2517 } +2518 +2519 /// Whether the Multipath for QUIC extension is enabled. +2520 /// +2521 /// Multipath is only enabled after the handshake is completed and if it was enabled by both +2522 /// peers. +2523 pub fn is_multipath_negotiated(&self) -> bool { +2524 !self.is_handshaking() +2525 && self.config.max_concurrent_multipath_paths.is_some() +2526 && self.peer_params.initial_max_path_id.is_some() +2527 } +2528 +2529 fn on_ack_received( +2530 &mut self, +2531 now: Instant, +2532 space: SpaceId, +2533 ack: frame::Ack, +2534 ) -> Result<(), TransportError> { +2535 // All ACKs are referencing path 0 +2536 let path = PathId::ZERO; +2537 self.inner_on_ack_received(now, space, path, ack) +2538 } +2539 +2540 fn on_path_ack_received( +2541 &mut self, +2542 now: Instant, +2543 space: SpaceId, +2544 path_ack: frame::PathAck, +2545 ) -> Result<(), TransportError> { +2546 let (ack, path) = path_ack.into_ack(); +2547 self.inner_on_ack_received(now, space, path, ack) +2548 } +2549 +2550 /// Handles an ACK frame acknowledging packets sent on *path*. +2551 fn inner_on_ack_received( +2552 &mut self, +2553 now: Instant, +2554 space: SpaceId, +2555 path: PathId, +2556 ack: frame::Ack, +2557 ) -> Result<(), TransportError> { +2558 if self.abandoned_paths.contains(&path) { +2559 // See also https://www.ietf.org/archive/id/draft-ietf-quic-multipath-17.html#section-3.4.3-3 +2560 // > PATH_ACK frames received with an abandoned path ID are silently ignored, as specified in Section 4. +2561 trace!("silently ignoring PATH_ACK on abandoned path"); +2562 return Ok(()); +2563 } +2564 if ack.largest >= self.spaces[space].for_path(path).next_packet_number { +2565 return Err(TransportError::PROTOCOL_VIOLATION("unsent packet acked")); +2566 } +2567 let new_largest = { +2568 let space = &mut self.spaces[space].for_path(path); +2569 if space.largest_acked_packet.is_none_or(|pn| ack.largest > pn) { +2570 space.largest_acked_packet = Some(ack.largest); +2571 if let Some(info) = space.sent_packets.get(ack.largest) { +2572 // This should always succeed, but a misbehaving peer might ACK a packet we +2573 // haven't sent. At worst, that will result in us spuriously reducing the +2574 // congestion window. +2575 space.largest_acked_packet_sent = info.time_sent; +2576 } +2577 true +2578 } else { +2579 false +2580 } +2581 }; +2582 +2583 if self.detect_spurious_loss(&ack, space, path) { +2584 self.path_data_mut(path) +2585 .congestion +2586 .on_spurious_congestion_event(); +2587 } 2588 -2589 self.on_packet_acked(now, path, info); -2590 } -2591 } -2592 -2593 let largest_ackd = self.spaces[space].for_path(path).largest_acked_packet; -2594 let app_limited = self.app_limited; -2595 let path_data = self.path_data_mut(path); -2596 let in_flight = path_data.in_flight.bytes; -2597 -2598 path_data -2599 .congestion -2600 .on_end_acks(now, in_flight, app_limited, largest_ackd); +2589 // Avoid DoS from unreasonably huge ack ranges by filtering out just the new acks. +2590 let mut newly_acked = ArrayRangeSet::new(); +2591 for range in ack.iter() { +2592 self.spaces[space].for_path(path).check_ack(range.clone())?; +2593 for (pn, _) in self.spaces[space] +2594 .for_path(path) +2595 .sent_packets +2596 .iter_range(range) +2597 { +2598 newly_acked.insert_one(pn); +2599 } +2600 } 2601 -2602 if new_largest && ack_eliciting_acked { -2603 let ack_delay = if space != SpaceId::Data { -2604 Duration::from_micros(0) -2605 } else { -2606 cmp::min( -2607 self.ack_frequency.peer_max_ack_delay, -2608 Duration::from_micros(ack.delay << self.peer_params.ack_delay_exponent.0), -2609 ) -2610 }; -2611 let rtt = now.saturating_duration_since( -2612 self.spaces[space].for_path(path).largest_acked_packet_sent, -2613 ); -2614 -2615 let next_pn = self.spaces[space].for_path(path).next_packet_number; -2616 let path_data = self.path_data_mut(path); -2617 // TODO(@divma): should be a method of path, should be contained in a single place -2618 path_data.rtt.update(ack_delay, rtt); -2619 if path_data.first_packet_after_rtt_sample.is_none() { -2620 path_data.first_packet_after_rtt_sample = Some((space, next_pn)); -2621 } -2622 } -2623 -2624 // Must be called before crypto/pto_count are clobbered -2625 self.detect_lost_packets(now, space, path, true); -2626 -2627 if self.peer_completed_address_validation(path) { -2628 self.path_data_mut(path).pto_count = 0; -2629 } -2630 -2631 // Explicit congestion notification -2632 // TODO(@divma): this code is a good example of logic that should be contained in a single -2633 // place but it's split between the path data and the packet number space data, we should -2634 // find a way to make this work without two lookups -2635 if self.path_data(path).sending_ecn { -2636 if let Some(ecn) = ack.ecn { -2637 // We only examine ECN counters from ACKs that we are certain we received in transmit -2638 // order, allowing us to compute an increase in ECN counts to compare against the number -2639 // of newly acked packets that remains well-defined in the presence of arbitrary packet -2640 // reordering. -2641 if new_largest { -2642 let sent = self.spaces[space].for_path(path).largest_acked_packet_sent; -2643 self.process_ecn(now, space, path, newly_acked.len() as u64, ecn, sent); -2644 } -2645 } else { -2646 // We always start out sending ECN, so any ack that doesn't acknowledge it disables it. -2647 debug!("ECN not acknowledged by peer"); -2648 self.path_data_mut(path).sending_ecn = false; -2649 } -2650 } -2651 -2652 self.set_loss_detection_timer(now, path); -2653 Ok(()) -2654 } -2655 -2656 fn detect_spurious_loss(&mut self, ack: &frame::Ack, space: SpaceId, path: PathId) -> bool { -2657 let lost_packets = &mut self.spaces[space].for_path(path).lost_packets; +2602 if newly_acked.is_empty() { +2603 return Ok(()); +2604 } +2605 +2606 let mut ack_eliciting_acked = false; +2607 for packet in newly_acked.elts() { +2608 if let Some(info) = self.spaces[space].for_path(path).take(packet) { +2609 for (acked_path_id, acked_pn) in info.largest_acked.iter() { +2610 // Assume ACKs for all packets below the largest acknowledged in +2611 // `packet` have been received. This can cause the peer to spuriously +2612 // retransmit if some of our earlier ACKs were lost, but allows for +2613 // simpler state tracking. See discussion at +2614 // https://www.rfc-editor.org/rfc/rfc9000.html#name-limiting-ranges-by-tracking +2615 if let Some(pns) = self.spaces[space].path_space_mut(*acked_path_id) { +2616 pns.pending_acks.subtract_below(*acked_pn); +2617 } +2618 } +2619 ack_eliciting_acked |= info.ack_eliciting; +2620 +2621 // Notify MTU discovery that a packet was acked, because it might be an MTU probe +2622 let path_data = self.path_data_mut(path); +2623 let mtu_updated = path_data.mtud.on_acked(space, packet, info.size); +2624 if mtu_updated { +2625 path_data +2626 .congestion +2627 .on_mtu_update(path_data.mtud.current_mtu()); +2628 } +2629 +2630 // Notify ack frequency that a packet was acked, because it might contain an ACK_FREQUENCY frame +2631 self.ack_frequency.on_acked(path, packet); +2632 +2633 self.on_packet_acked(now, path, info); +2634 } +2635 } +2636 +2637 let largest_ackd = self.spaces[space].for_path(path).largest_acked_packet; +2638 let app_limited = self.app_limited; +2639 let path_data = self.path_data_mut(path); +2640 let in_flight = path_data.in_flight.bytes; +2641 +2642 path_data +2643 .congestion +2644 .on_end_acks(now, in_flight, app_limited, largest_ackd); +2645 +2646 if new_largest && ack_eliciting_acked { +2647 let ack_delay = if space != SpaceId::Data { +2648 Duration::from_micros(0) +2649 } else { +2650 cmp::min( +2651 self.ack_frequency.peer_max_ack_delay, +2652 Duration::from_micros(ack.delay << self.peer_params.ack_delay_exponent.0), +2653 ) +2654 }; +2655 let rtt = now.saturating_duration_since( +2656 self.spaces[space].for_path(path).largest_acked_packet_sent, +2657 ); 2658 -2659 if lost_packets.is_empty() { -2660 return false; -2661 } -2662 -2663 for range in ack.iter() { -2664 let spurious_losses: Vec<u64> = lost_packets -2665 .iter_range(range.clone()) -2666 .map(|(pn, _info)| pn) -2667 .collect(); -2668 -2669 for pn in spurious_losses { -2670 lost_packets.remove(pn); -2671 } -2672 } -2673 -2674 // If this ACK frame acknowledged all deemed lost packets, -2675 // then we have raised a spurious congestion event in the past. -2676 // We cannot conclude when there are remaining packets, -2677 // but future ACK frames might indicate a spurious loss detection. -2678 lost_packets.is_empty() -2679 } -2680 -2681 /// Drain lost packets that we reasonably think will never arrive -2682 /// -2683 /// The current criterion is copied from `msquic`: -2684 /// discard packets that were sent earlier than 2 probe timeouts ago. -2685 fn drain_lost_packets(&mut self, now: Instant, space: SpaceId, path: PathId) { -2686 let two_pto = 2 * self.path_data(path).rtt.pto_base(); -2687 -2688 let lost_packets = &mut self.spaces[space].for_path(path).lost_packets; -2689 lost_packets.retain(|_pn, info| now.saturating_duration_since(info.time_sent) <= two_pto); -2690 } -2691 -2692 /// Process a new ECN block from an in-order ACK -2693 fn process_ecn( -2694 &mut self, -2695 now: Instant, -2696 space: SpaceId, -2697 path: PathId, -2698 newly_acked: u64, -2699 ecn: frame::EcnCounts, -2700 largest_sent_time: Instant, -2701 ) { -2702 match self.spaces[space] -2703 .for_path(path) -2704 .detect_ecn(newly_acked, ecn) -2705 { -2706 Err(e) => { -2707 debug!("halting ECN due to verification failure: {}", e); -2708 -2709 self.path_data_mut(path).sending_ecn = false; -2710 // Wipe out the existing value because it might be garbage and could interfere with -2711 // future attempts to use ECN on new paths. -2712 self.spaces[space].for_path(path).ecn_feedback = frame::EcnCounts::ZERO; -2713 } -2714 Ok(false) => {} -2715 Ok(true) => { -2716 self.path_stats.entry(path).or_default().congestion_events += 1; -2717 self.path_data_mut(path).congestion.on_congestion_event( -2718 now, -2719 largest_sent_time, -2720 false, -2721 true, -2722 0, -2723 ); -2724 } -2725 } -2726 } -2727 -2728 // Not timing-aware, so it's safe to call this for inferred acks, such as arise from -2729 // high-latency handshakes -2730 fn on_packet_acked(&mut self, now: Instant, path_id: PathId, info: SentPacket) { -2731 self.paths -2732 .get_mut(&path_id) -2733 .expect("known path") -2734 .remove_in_flight(&info); -2735 let app_limited = self.app_limited; -2736 let path = self.path_data_mut(path_id); -2737 if info.ack_eliciting && !path.is_validating_path() { -2738 // Only pass ACKs to the congestion controller if we are not validating the current -2739 // path, so as to ignore any ACKs from older paths still coming in. -2740 let rtt = path.rtt; -2741 path.congestion -2742 .on_ack(now, info.time_sent, info.size.into(), app_limited, &rtt); -2743 } -2744 -2745 // Update state for confirmed delivery of frames -2746 if let Some(retransmits) = info.retransmits.get() { -2747 for (id, _) in retransmits.reset_stream.iter() { -2748 self.streams.reset_acked(*id); -2749 } -2750 } -2751 -2752 for frame in info.stream_frames { -2753 self.streams.received_ack_of(frame); -2754 } -2755 } -2756 -2757 fn set_key_discard_timer(&mut self, now: Instant, space: SpaceId) { -2758 let start = if self.zero_rtt_crypto.is_some() { -2759 now -2760 } else { -2761 self.prev_crypto -2762 .as_ref() -2763 .expect("no previous keys") -2764 .end_packet -2765 .as_ref() -2766 .expect("update not acknowledged yet") -2767 .1 -2768 }; -2769 -2770 // QUIC-MULTIPATH § 2.5 Key Phase Update Process: use largest PTO off all paths. -2771 self.timers.set( -2772 Timer::Conn(ConnTimer::KeyDiscard), -2773 start + self.pto_max_path(space, false) * 3, -2774 self.qlog.with_time(now), -2775 ); -2776 } -2777 -2778 /// Handle a [`PathTimer::LossDetection`] timeout. -2779 /// -2780 /// This timer expires for two reasons: -2781 /// - An ACK-eliciting packet we sent should be considered lost. -2782 /// - The PTO may have expired and a tail-loss probe needs to be scheduled. -2783 /// -2784 /// The former needs us to schedule re-transmission of the lost data. -2785 /// -2786 /// The latter means we have not received an ACK for an ack-eliciting packet we sent -2787 /// within the PTO time-window. We need to schedule a tail-loss probe, an ack-eliciting -2788 /// packet, to try and elicit new acknowledgements. These new acknowledgements will -2789 /// indicate whether the previously sent packets were lost or not. -2790 fn on_loss_detection_timeout(&mut self, now: Instant, path_id: PathId) { -2791 if let Some((_, pn_space)) = self.loss_time_and_space(path_id) { -2792 // Time threshold loss Detection -2793 self.detect_lost_packets(now, pn_space, path_id, false); -2794 self.set_loss_detection_timer(now, path_id); -2795 return; -2796 } -2797 -2798 let (_, space) = match self.pto_time_and_space(now, path_id) { -2799 Some(x) => x, -2800 None => { -2801 error!(%path_id, "PTO expired while unset"); -2802 return; -2803 } -2804 }; -2805 trace!( -2806 in_flight = self.path_data(path_id).in_flight.bytes, -2807 count = self.path_data(path_id).pto_count, -2808 ?space, -2809 %path_id, -2810 "PTO fired" -2811 ); -2812 -2813 let count = match self.path_data(path_id).in_flight.ack_eliciting { -2814 // A PTO when we're not expecting any ACKs must be due to handshake anti-amplification -2815 // deadlock preventions -2816 0 => { -2817 debug_assert!(!self.peer_completed_address_validation(path_id)); -2818 1 -2819 } -2820 // Conventional loss probe -2821 _ => 2, -2822 }; -2823 let pns = self.spaces[space].for_path(path_id); -2824 pns.loss_probes = pns.loss_probes.saturating_add(count); -2825 let path_data = self.path_data_mut(path_id); -2826 path_data.pto_count = path_data.pto_count.saturating_add(1); -2827 self.set_loss_detection_timer(now, path_id); -2828 } -2829 -2830 /// Detect any lost packets -2831 /// -2832 /// There are two cases in which we detects lost packets: -2833 /// -2834 /// - We received an ACK packet. -2835 /// - The [`PathTimer::LossDetection`] timer expired. So there is an un-acknowledged packet -2836 /// that was followed by an acknowledged packet. The loss timer for this -2837 /// un-acknowledged packet expired and we need to detect that packet as lost. -2838 /// -2839 /// Packets are lost if they are both (See RFC9002 §6.1): -2840 /// -2841 /// - Unacknowledged, in flight and sent prior to an acknowledged packet. -2842 /// - Old enough by either: -2843 /// - Having a packet number [`TransportConfig::packet_threshold`] lower then the last -2844 /// acknowledged packet. -2845 /// - Being sent [`TransportConfig::time_threshold`] * RTT in the past. -2846 fn detect_lost_packets( -2847 &mut self, -2848 now: Instant, -2849 pn_space: SpaceId, -2850 path_id: PathId, -2851 due_to_ack: bool, -2852 ) { -2853 let mut lost_packets = Vec::<u64>::new(); -2854 let mut lost_mtu_probe = None; -2855 let mut in_persistent_congestion = false; -2856 let mut size_of_lost_packets = 0u64; -2857 self.spaces[pn_space].for_path(path_id).loss_time = None; -2858 -2859 // Find all the lost packets, populating all variables initialised above. -2860 -2861 let path = self.path_data(path_id); -2862 let in_flight_mtu_probe = path.mtud.in_flight_mtu_probe(); -2863 let loss_delay = path -2864 .rtt -2865 .conservative() -2866 .mul_f32(self.config.time_threshold) -2867 .max(TIMER_GRANULARITY); -2868 let first_packet_after_rtt_sample = path.first_packet_after_rtt_sample; -2869 -2870 let largest_acked_packet = self.spaces[pn_space] -2871 .for_path(path_id) -2872 .largest_acked_packet -2873 .expect("detect_lost_packets only to be called if path received at least one ACK"); -2874 let packet_threshold = self.config.packet_threshold as u64; -2875 -2876 // InPersistentCongestion: Determine if all packets in the time period before the newest -2877 // lost packet, including the edges, are marked lost. PTO computation must always -2878 // include max ACK delay, i.e. operate as if in Data space (see RFC9001 §7.6.1). -2879 let congestion_period = self -2880 .pto(SpaceId::Data, path_id) -2881 .saturating_mul(self.config.persistent_congestion_threshold); -2882 let mut persistent_congestion_start: Option<Instant> = None; -2883 let mut prev_packet = None; -2884 let space = self.spaces[pn_space].for_path(path_id); -2885 -2886 for (packet, info) in space.sent_packets.iter_range(0..largest_acked_packet) { -2887 if prev_packet != Some(packet.wrapping_sub(1)) { -2888 // An intervening packet was acknowledged -2889 persistent_congestion_start = None; -2890 } -2891 -2892 // Packets sent before now - loss_delay are deemed lost. -2893 // However, we avoid subtraction as it can panic and there's no -2894 // saturating equivalent of this subtraction operation with a Duration. -2895 let packet_too_old = now.saturating_duration_since(info.time_sent) >= loss_delay; -2896 if packet_too_old || largest_acked_packet >= packet + packet_threshold { -2897 // The packet should be declared lost. -2898 if Some(packet) == in_flight_mtu_probe { -2899 // Lost MTU probes are not included in `lost_packets`, because they -2900 // should not trigger a congestion control response -2901 lost_mtu_probe = in_flight_mtu_probe; -2902 } else { -2903 lost_packets.push(packet); -2904 size_of_lost_packets += info.size as u64; -2905 if info.ack_eliciting && due_to_ack { -2906 match persistent_congestion_start { -2907 // Two ACK-eliciting packets lost more than -2908 // congestion_period apart, with no ACKed packets in between -2909 Some(start) if info.time_sent - start > congestion_period => { -2910 in_persistent_congestion = true; -2911 } -2912 // Persistent congestion must start after the first RTT sample -2913 None if first_packet_after_rtt_sample -2914 .is_some_and(|x| x < (pn_space, packet)) => -2915 { -2916 persistent_congestion_start = Some(info.time_sent); -2917 } -2918 _ => {} -2919 } -2920 } -2921 } -2922 } else { -2923 // The packet should not yet be declared lost. -2924 if space.loss_time.is_none() { -2925 // Since we iterate in order the lowest packet number's loss time will -2926 // always be the earliest. -2927 space.loss_time = Some(info.time_sent + loss_delay); -2928 } -2929 persistent_congestion_start = None; -2930 } -2931 -2932 prev_packet = Some(packet); -2933 } -2934 -2935 self.handle_lost_packets( -2936 pn_space, -2937 path_id, -2938 now, -2939 lost_packets, -2940 lost_mtu_probe, -2941 loss_delay, -2942 in_persistent_congestion, -2943 size_of_lost_packets, -2944 ); -2945 } -2946 -2947 /// Drops the path state, declaring any remaining in-flight packets as lost -2948 fn discard_path(&mut self, path_id: PathId, now: Instant) { -2949 trace!(%path_id, "dropping path state"); -2950 let path = self.path_data(path_id); -2951 let in_flight_mtu_probe = path.mtud.in_flight_mtu_probe(); -2952 -2953 let mut size_of_lost_packets = 0u64; // add to path_stats.lost_bytes; -2954 let lost_pns: Vec<_> = self.spaces[SpaceId::Data] -2955 .for_path(path_id) -2956 .sent_packets -2957 .iter() -2958 .filter(|(pn, _info)| Some(*pn) != in_flight_mtu_probe) -2959 .map(|(pn, info)| { -2960 size_of_lost_packets += info.size as u64; -2961 pn -2962 }) -2963 .collect(); -2964 -2965 if !lost_pns.is_empty() { -2966 trace!( -2967 %path_id, -2968 count = lost_pns.len(), -2969 lost_bytes = size_of_lost_packets, -2970 "packets lost on path abandon" -2971 ); -2972 self.handle_lost_packets( -2973 SpaceId::Data, -2974 path_id, -2975 now, -2976 lost_pns, -2977 in_flight_mtu_probe, -2978 Duration::ZERO, -2979 false, -2980 size_of_lost_packets, -2981 ); -2982 } -2983 self.paths.remove(&path_id); -2984 self.spaces[SpaceId::Data].number_spaces.remove(&path_id); -2985 -2986 let path_stats = self.path_stats.remove(&path_id).unwrap_or_default(); -2987 self.events.push_back( -2988 PathEvent::Abandoned { -2989 id: path_id, -2990 path_stats, -2991 } -2992 .into(), -2993 ); -2994 } -2995 -2996 fn handle_lost_packets( -2997 &mut self, -2998 pn_space: SpaceId, -2999 path_id: PathId, -3000 now: Instant, -3001 lost_packets: Vec<u64>, -3002 lost_mtu_probe: Option<u64>, -3003 loss_delay: Duration, -3004 in_persistent_congestion: bool, -3005 size_of_lost_packets: u64, -3006 ) { -3007 debug_assert!( -3008 { -3009 let mut sorted = lost_packets.clone(); -3010 sorted.sort(); -3011 sorted == lost_packets -3012 }, -3013 "lost_packets must be sorted" -3014 ); -3015 -3016 self.drain_lost_packets(now, pn_space, path_id); -3017 -3018 // OnPacketsLost -3019 if let Some(largest_lost) = lost_packets.last().cloned() { -3020 let old_bytes_in_flight = self.path_data_mut(path_id).in_flight.bytes; -3021 let largest_lost_sent = self.spaces[pn_space] -3022 .for_path(path_id) -3023 .sent_packets -3024 .get(largest_lost) -3025 .unwrap() -3026 .time_sent; -3027 let path_stats = self.path_stats.entry(path_id).or_default(); -3028 path_stats.lost_packets += lost_packets.len() as u64; -3029 path_stats.lost_bytes += size_of_lost_packets; -3030 trace!( -3031 %path_id, -3032 count = lost_packets.len(), -3033 lost_bytes = size_of_lost_packets, -3034 "packets lost", -3035 ); -3036 -3037 for &packet in &lost_packets { -3038 let Some(info) = self.spaces[pn_space].for_path(path_id).take(packet) else { -3039 continue; -3040 }; -3041 self.qlog -3042 .emit_packet_lost(packet, &info, loss_delay, pn_space, now); -3043 self.paths -3044 .get_mut(&path_id) -3045 .unwrap() -3046 .remove_in_flight(&info); -3047 -3048 for frame in info.stream_frames { -3049 self.streams.retransmit(frame); -3050 } -3051 self.spaces[pn_space].pending |= info.retransmits; -3052 self.path_data_mut(path_id) -3053 .mtud -3054 .on_non_probe_lost(packet, info.size); -3055 -3056 self.spaces[pn_space].for_path(path_id).lost_packets.insert( -3057 packet, -3058 LostPacket { -3059 time_sent: info.time_sent, -3060 }, -3061 ); -3062 } -3063 -3064 let path = self.path_data_mut(path_id); -3065 if path.mtud.black_hole_detected(now) { -3066 path.congestion.on_mtu_update(path.mtud.current_mtu()); -3067 if let Some(max_datagram_size) = self.datagrams().max_size() -3068 && self.datagrams.drop_oversized(max_datagram_size) -3069 && self.datagrams.send_blocked -3070 { -3071 self.datagrams.send_blocked = false; -3072 self.events.push_back(Event::DatagramsUnblocked); -3073 } -3074 self.path_stats -3075 .entry(path_id) -3076 .or_default() -3077 .black_holes_detected += 1; -3078 } -3079 -3080 // Don't apply congestion penalty for lost ack-only packets -3081 let lost_ack_eliciting = -3082 old_bytes_in_flight != self.path_data_mut(path_id).in_flight.bytes; -3083 -3084 if lost_ack_eliciting { -3085 self.path_stats -3086 .entry(path_id) -3087 .or_default() -3088 .congestion_events += 1; -3089 self.path_data_mut(path_id).congestion.on_congestion_event( -3090 now, -3091 largest_lost_sent, -3092 in_persistent_congestion, -3093 false, -3094 size_of_lost_packets, -3095 ); -3096 } -3097 } -3098 -3099 // Handle a lost MTU probe -3100 if let Some(packet) = lost_mtu_probe { -3101 let info = self.spaces[SpaceId::Data] -3102 .for_path(path_id) -3103 .take(packet) -3104 .unwrap(); // safe: lost_mtu_probe is omitted from lost_packets, and -3105 // therefore must not have been removed yet -3106 self.paths -3107 .get_mut(&path_id) -3108 .unwrap() -3109 .remove_in_flight(&info); -3110 self.path_data_mut(path_id).mtud.on_probe_lost(); -3111 self.path_stats -3112 .entry(path_id) -3113 .or_default() -3114 .lost_plpmtud_probes += 1; -3115 } -3116 } -3117 -3118 /// Returns the earliest time packets should be declared lost for all spaces on a path. -3119 /// -3120 /// If a path has an acknowledged packet with any prior un-acknowledged packets, the -3121 /// earliest un-acknowledged packet can be declared lost after a timeout has elapsed. -3122 /// The time returned is when this packet should be declared lost. -3123 fn loss_time_and_space(&self, path_id: PathId) -> Option<(Instant, SpaceId)> { -3124 SpaceId::iter() -3125 .filter_map(|id| { -3126 self.spaces[id] -3127 .number_spaces -3128 .get(&path_id) -3129 .and_then(|pns| pns.loss_time) -3130 .map(|time| (time, id)) -3131 }) -3132 .min_by_key(|&(time, _)| time) -3133 } -3134 -3135 /// Returns the earliest next PTO should fire for all spaces on a path. -3136 fn pto_time_and_space(&mut self, now: Instant, path_id: PathId) -> Option<(Instant, SpaceId)> { -3137 let path = self.path(path_id)?; -3138 let pto_count = path.pto_count; -3139 let backoff = 2u32.pow(pto_count.min(MAX_BACKOFF_EXPONENT)); -3140 let mut duration = path.rtt.pto_base() * backoff; -3141 -3142 if path_id == PathId::ZERO -3143 && path.in_flight.ack_eliciting == 0 -3144 && !self.peer_completed_address_validation(PathId::ZERO) -3145 { -3146 // Address Validation during Connection Establishment: -3147 // https://www.rfc-editor.org/rfc/rfc9000.html#section-8.1. To prevent a -3148 // deadlock if an Initial or Handshake packet from the server is lost and the -3149 // server can not send more due to its anti-amplification limit the client must -3150 // send another packet on PTO. -3151 let space = match self.highest_space { -3152 SpaceId::Handshake => SpaceId::Handshake, -3153 _ => SpaceId::Initial, -3154 }; -3155 -3156 return Some((now + duration, space)); -3157 } -3158 -3159 let mut result = None; -3160 for space in SpaceId::iter() { -3161 let Some(pns) = self.spaces[space].number_spaces.get(&path_id) else { -3162 continue; -3163 }; -3164 -3165 if !pns.has_in_flight() { -3166 continue; -3167 } -3168 if space == SpaceId::Data { -3169 // Skip ApplicationData until handshake completes. -3170 if self.is_handshaking() { -3171 return result; -3172 } -3173 // Include max_ack_delay and backoff for ApplicationData. -3174 duration += self.ack_frequency.max_ack_delay_for_pto() * backoff; -3175 } -3176 let Some(last_ack_eliciting) = pns.time_of_last_ack_eliciting_packet else { -3177 continue; -3178 }; -3179 let pto = last_ack_eliciting + duration; -3180 if result.is_none_or(|(earliest_pto, _)| pto < earliest_pto) { -3181 if path.anti_amplification_blocked(1) { -3182 // Nothing would be able to be sent. -3183 continue; -3184 } -3185 if path.in_flight.ack_eliciting == 0 { -3186 // Nothing ack-eliciting, no PTO to arm/fire. -3187 continue; -3188 } -3189 result = Some((pto, space)); -3190 } -3191 } -3192 result -3193 } -3194 -3195 fn peer_completed_address_validation(&self, path: PathId) -> bool { -3196 // TODO(flub): This logic needs updating for multipath -3197 if self.side.is_server() || self.state.is_closed() { -3198 return true; -3199 } -3200 // The server is guaranteed to have validated our address if any of our handshake or 1-RTT -3201 // packets are acknowledged or we've seen HANDSHAKE_DONE and discarded handshake keys. -3202 self.spaces[SpaceId::Handshake] -3203 .path_space(PathId::ZERO) -3204 .and_then(|pns| pns.largest_acked_packet) -3205 .is_some() -3206 || self.spaces[SpaceId::Data] -3207 .path_space(path) -3208 .and_then(|pns| pns.largest_acked_packet) -3209 .is_some() -3210 || (self.spaces[SpaceId::Data].crypto.is_some() -3211 && self.spaces[SpaceId::Handshake].crypto.is_none()) -3212 } -3213 -3214 /// Resets the the [`PathTimer::LossDetection`] timer to the next instant it may be needed -3215 /// -3216 /// The timer must fire if either: -3217 /// - An ack-eliciting packet we sent needs to be declared lost. -3218 /// - A tail-loss probe needs to be sent. -3219 /// -3220 /// See [`Connection::on_loss_detection_timeout`] for details. -3221 fn set_loss_detection_timer(&mut self, now: Instant, path_id: PathId) { -3222 if self.state.is_closed() { -3223 // No loss detection takes place on closed connections, and `close_common` already -3224 // stopped time timer. Ensure we don't restart it inadvertently, e.g. in response to a -3225 // reordered packet being handled by state-insensitive code. -3226 return; -3227 } -3228 -3229 if let Some((loss_time, _)) = self.loss_time_and_space(path_id) { -3230 // Time threshold loss detection. -3231 self.timers.set( -3232 Timer::PerPath(path_id, PathTimer::LossDetection), -3233 loss_time, -3234 self.qlog.with_time(now), -3235 ); -3236 return; -3237 } +2659 let next_pn = self.spaces[space].for_path(path).next_packet_number; +2660 let path_data = self.path_data_mut(path); +2661 // TODO(@divma): should be a method of path, should be contained in a single place +2662 path_data.rtt.update(ack_delay, rtt); +2663 if path_data.first_packet_after_rtt_sample.is_none() { +2664 path_data.first_packet_after_rtt_sample = Some((space, next_pn)); +2665 } +2666 } +2667 +2668 // Must be called before crypto/pto_count are clobbered +2669 self.detect_lost_packets(now, space, path, true); +2670 +2671 if self.peer_completed_address_validation(path) { +2672 self.path_data_mut(path).pto_count = 0; +2673 } +2674 +2675 // Explicit congestion notification +2676 // TODO(@divma): this code is a good example of logic that should be contained in a single +2677 // place but it's split between the path data and the packet number space data, we should +2678 // find a way to make this work without two lookups +2679 if self.path_data(path).sending_ecn { +2680 if let Some(ecn) = ack.ecn { +2681 // We only examine ECN counters from ACKs that we are certain we received in transmit +2682 // order, allowing us to compute an increase in ECN counts to compare against the number +2683 // of newly acked packets that remains well-defined in the presence of arbitrary packet +2684 // reordering. +2685 if new_largest { +2686 let sent = self.spaces[space].for_path(path).largest_acked_packet_sent; +2687 self.process_ecn(now, space, path, newly_acked.len() as u64, ecn, sent); +2688 } +2689 } else { +2690 // We always start out sending ECN, so any ack that doesn't acknowledge it disables it. +2691 debug!("ECN not acknowledged by peer"); +2692 self.path_data_mut(path).sending_ecn = false; +2693 } +2694 } +2695 +2696 self.set_loss_detection_timer(now, path); +2697 Ok(()) +2698 } +2699 +2700 fn detect_spurious_loss(&mut self, ack: &frame::Ack, space: SpaceId, path: PathId) -> bool { +2701 let lost_packets = &mut self.spaces[space].for_path(path).lost_packets; +2702 +2703 if lost_packets.is_empty() { +2704 return false; +2705 } +2706 +2707 for range in ack.iter() { +2708 let spurious_losses: Vec<u64> = lost_packets +2709 .iter_range(range.clone()) +2710 .map(|(pn, _info)| pn) +2711 .collect(); +2712 +2713 for pn in spurious_losses { +2714 lost_packets.remove(pn); +2715 } +2716 } +2717 +2718 // If this ACK frame acknowledged all deemed lost packets, +2719 // then we have raised a spurious congestion event in the past. +2720 // We cannot conclude when there are remaining packets, +2721 // but future ACK frames might indicate a spurious loss detection. +2722 lost_packets.is_empty() +2723 } +2724 +2725 /// Drain lost packets that we reasonably think will never arrive +2726 /// +2727 /// The current criterion is copied from `msquic`: +2728 /// discard packets that were sent earlier than 2 probe timeouts ago. +2729 fn drain_lost_packets(&mut self, now: Instant, space: SpaceId, path: PathId) { +2730 let two_pto = 2 * self.path_data(path).rtt.pto_base(); +2731 +2732 let lost_packets = &mut self.spaces[space].for_path(path).lost_packets; +2733 lost_packets.retain(|_pn, info| now.saturating_duration_since(info.time_sent) <= two_pto); +2734 } +2735 +2736 /// Process a new ECN block from an in-order ACK +2737 fn process_ecn( +2738 &mut self, +2739 now: Instant, +2740 space: SpaceId, +2741 path: PathId, +2742 newly_acked: u64, +2743 ecn: frame::EcnCounts, +2744 largest_sent_time: Instant, +2745 ) { +2746 match self.spaces[space] +2747 .for_path(path) +2748 .detect_ecn(newly_acked, ecn) +2749 { +2750 Err(e) => { +2751 debug!("halting ECN due to verification failure: {}", e); +2752 +2753 self.path_data_mut(path).sending_ecn = false; +2754 // Wipe out the existing value because it might be garbage and could interfere with +2755 // future attempts to use ECN on new paths. +2756 self.spaces[space].for_path(path).ecn_feedback = frame::EcnCounts::ZERO; +2757 } +2758 Ok(false) => {} +2759 Ok(true) => { +2760 self.path_stats.entry(path).or_default().congestion_events += 1; +2761 self.path_data_mut(path).congestion.on_congestion_event( +2762 now, +2763 largest_sent_time, +2764 false, +2765 true, +2766 0, +2767 ); +2768 } +2769 } +2770 } +2771 +2772 // Not timing-aware, so it's safe to call this for inferred acks, such as arise from +2773 // high-latency handshakes +2774 fn on_packet_acked(&mut self, now: Instant, path_id: PathId, info: SentPacket) { +2775 self.paths +2776 .get_mut(&path_id) +2777 .expect("known path") +2778 .remove_in_flight(&info); +2779 let app_limited = self.app_limited; +2780 let path = self.path_data_mut(path_id); +2781 if info.ack_eliciting && !path.is_validating_path() { +2782 // Only pass ACKs to the congestion controller if we are not validating the current +2783 // path, so as to ignore any ACKs from older paths still coming in. +2784 let rtt = path.rtt; +2785 path.congestion +2786 .on_ack(now, info.time_sent, info.size.into(), app_limited, &rtt); +2787 } +2788 +2789 // Update state for confirmed delivery of frames +2790 if let Some(retransmits) = info.retransmits.get() { +2791 for (id, _) in retransmits.reset_stream.iter() { +2792 self.streams.reset_acked(*id); +2793 } +2794 } +2795 +2796 for frame in info.stream_frames { +2797 self.streams.received_ack_of(frame); +2798 } +2799 } +2800 +2801 fn set_key_discard_timer(&mut self, now: Instant, space: SpaceId) { +2802 let start = if self.zero_rtt_crypto.is_some() { +2803 now +2804 } else { +2805 self.prev_crypto +2806 .as_ref() +2807 .expect("no previous keys") +2808 .end_packet +2809 .as_ref() +2810 .expect("update not acknowledged yet") +2811 .1 +2812 }; +2813 +2814 // QUIC-MULTIPATH § 2.5 Key Phase Update Process: use largest PTO off all paths. +2815 self.timers.set( +2816 Timer::Conn(ConnTimer::KeyDiscard), +2817 start + self.pto_max_path(space, false) * 3, +2818 self.qlog.with_time(now), +2819 ); +2820 } +2821 +2822 /// Handle a [`PathTimer::LossDetection`] timeout. +2823 /// +2824 /// This timer expires for two reasons: +2825 /// - An ACK-eliciting packet we sent should be considered lost. +2826 /// - The PTO may have expired and a tail-loss probe needs to be scheduled. +2827 /// +2828 /// The former needs us to schedule re-transmission of the lost data. +2829 /// +2830 /// The latter means we have not received an ACK for an ack-eliciting packet we sent +2831 /// within the PTO time-window. We need to schedule a tail-loss probe, an ack-eliciting +2832 /// packet, to try and elicit new acknowledgements. These new acknowledgements will +2833 /// indicate whether the previously sent packets were lost or not. +2834 fn on_loss_detection_timeout(&mut self, now: Instant, path_id: PathId) { +2835 if let Some((_, pn_space)) = self.loss_time_and_space(path_id) { +2836 // Time threshold loss Detection +2837 self.detect_lost_packets(now, pn_space, path_id, false); +2838 self.set_loss_detection_timer(now, path_id); +2839 return; +2840 } +2841 +2842 let (_, space) = match self.pto_time_and_space(now, path_id) { +2843 Some(x) => x, +2844 None => { +2845 error!(%path_id, "PTO expired while unset"); +2846 return; +2847 } +2848 }; +2849 trace!( +2850 in_flight = self.path_data(path_id).in_flight.bytes, +2851 count = self.path_data(path_id).pto_count, +2852 ?space, +2853 %path_id, +2854 "PTO fired" +2855 ); +2856 +2857 let count = match self.path_data(path_id).in_flight.ack_eliciting { +2858 // A PTO when we're not expecting any ACKs must be due to handshake anti-amplification +2859 // deadlock preventions +2860 0 => { +2861 debug_assert!(!self.peer_completed_address_validation(path_id)); +2862 1 +2863 } +2864 // Conventional loss probe +2865 _ => 2, +2866 }; +2867 let pns = self.spaces[space].for_path(path_id); +2868 pns.loss_probes = pns.loss_probes.saturating_add(count); +2869 let path_data = self.path_data_mut(path_id); +2870 path_data.pto_count = path_data.pto_count.saturating_add(1); +2871 self.set_loss_detection_timer(now, path_id); +2872 } +2873 +2874 /// Detect any lost packets +2875 /// +2876 /// There are two cases in which we detects lost packets: +2877 /// +2878 /// - We received an ACK packet. +2879 /// - The [`PathTimer::LossDetection`] timer expired. So there is an un-acknowledged packet +2880 /// that was followed by an acknowledged packet. The loss timer for this +2881 /// un-acknowledged packet expired and we need to detect that packet as lost. +2882 /// +2883 /// Packets are lost if they are both (See RFC9002 §6.1): +2884 /// +2885 /// - Unacknowledged, in flight and sent prior to an acknowledged packet. +2886 /// - Old enough by either: +2887 /// - Having a packet number [`TransportConfig::packet_threshold`] lower then the last +2888 /// acknowledged packet. +2889 /// - Being sent [`TransportConfig::time_threshold`] * RTT in the past. +2890 fn detect_lost_packets( +2891 &mut self, +2892 now: Instant, +2893 pn_space: SpaceId, +2894 path_id: PathId, +2895 due_to_ack: bool, +2896 ) { +2897 let mut lost_packets = Vec::<u64>::new(); +2898 let mut lost_mtu_probe = None; +2899 let mut in_persistent_congestion = false; +2900 let mut size_of_lost_packets = 0u64; +2901 self.spaces[pn_space].for_path(path_id).loss_time = None; +2902 +2903 // Find all the lost packets, populating all variables initialised above. +2904 +2905 let path = self.path_data(path_id); +2906 let in_flight_mtu_probe = path.mtud.in_flight_mtu_probe(); +2907 let loss_delay = path +2908 .rtt +2909 .conservative() +2910 .mul_f32(self.config.time_threshold) +2911 .max(TIMER_GRANULARITY); +2912 let first_packet_after_rtt_sample = path.first_packet_after_rtt_sample; +2913 +2914 let largest_acked_packet = self.spaces[pn_space] +2915 .for_path(path_id) +2916 .largest_acked_packet +2917 .expect("detect_lost_packets only to be called if path received at least one ACK"); +2918 let packet_threshold = self.config.packet_threshold as u64; +2919 +2920 // InPersistentCongestion: Determine if all packets in the time period before the newest +2921 // lost packet, including the edges, are marked lost. PTO computation must always +2922 // include max ACK delay, i.e. operate as if in Data space (see RFC9001 §7.6.1). +2923 let congestion_period = self +2924 .pto(SpaceId::Data, path_id) +2925 .saturating_mul(self.config.persistent_congestion_threshold); +2926 let mut persistent_congestion_start: Option<Instant> = None; +2927 let mut prev_packet = None; +2928 let space = self.spaces[pn_space].for_path(path_id); +2929 +2930 for (packet, info) in space.sent_packets.iter_range(0..largest_acked_packet) { +2931 if prev_packet != Some(packet.wrapping_sub(1)) { +2932 // An intervening packet was acknowledged +2933 persistent_congestion_start = None; +2934 } +2935 +2936 // Packets sent before now - loss_delay are deemed lost. +2937 // However, we avoid subtraction as it can panic and there's no +2938 // saturating equivalent of this subtraction operation with a Duration. +2939 let packet_too_old = now.saturating_duration_since(info.time_sent) >= loss_delay; +2940 if packet_too_old || largest_acked_packet >= packet + packet_threshold { +2941 // The packet should be declared lost. +2942 if Some(packet) == in_flight_mtu_probe { +2943 // Lost MTU probes are not included in `lost_packets`, because they +2944 // should not trigger a congestion control response +2945 lost_mtu_probe = in_flight_mtu_probe; +2946 } else { +2947 lost_packets.push(packet); +2948 size_of_lost_packets += info.size as u64; +2949 if info.ack_eliciting && due_to_ack { +2950 match persistent_congestion_start { +2951 // Two ACK-eliciting packets lost more than +2952 // congestion_period apart, with no ACKed packets in between +2953 Some(start) if info.time_sent - start > congestion_period => { +2954 in_persistent_congestion = true; +2955 } +2956 // Persistent congestion must start after the first RTT sample +2957 None if first_packet_after_rtt_sample +2958 .is_some_and(|x| x < (pn_space, packet)) => +2959 { +2960 persistent_congestion_start = Some(info.time_sent); +2961 } +2962 _ => {} +2963 } +2964 } +2965 } +2966 } else { +2967 // The packet should not yet be declared lost. +2968 if space.loss_time.is_none() { +2969 // Since we iterate in order the lowest packet number's loss time will +2970 // always be the earliest. +2971 space.loss_time = Some(info.time_sent + loss_delay); +2972 } +2973 persistent_congestion_start = None; +2974 } +2975 +2976 prev_packet = Some(packet); +2977 } +2978 +2979 self.handle_lost_packets( +2980 pn_space, +2981 path_id, +2982 now, +2983 lost_packets, +2984 lost_mtu_probe, +2985 loss_delay, +2986 in_persistent_congestion, +2987 size_of_lost_packets, +2988 ); +2989 } +2990 +2991 /// Drops the path state, declaring any remaining in-flight packets as lost +2992 fn discard_path(&mut self, path_id: PathId, now: Instant) { +2993 trace!(%path_id, "dropping path state"); +2994 let path = self.path_data(path_id); +2995 let in_flight_mtu_probe = path.mtud.in_flight_mtu_probe(); +2996 +2997 let mut size_of_lost_packets = 0u64; // add to path_stats.lost_bytes; +2998 let lost_pns: Vec<_> = self.spaces[SpaceId::Data] +2999 .for_path(path_id) +3000 .sent_packets +3001 .iter() +3002 .filter(|(pn, _info)| Some(*pn) != in_flight_mtu_probe) +3003 .map(|(pn, info)| { +3004 size_of_lost_packets += info.size as u64; +3005 pn +3006 }) +3007 .collect(); +3008 +3009 if !lost_pns.is_empty() { +3010 trace!( +3011 %path_id, +3012 count = lost_pns.len(), +3013 lost_bytes = size_of_lost_packets, +3014 "packets lost on path abandon" +3015 ); +3016 self.handle_lost_packets( +3017 SpaceId::Data, +3018 path_id, +3019 now, +3020 lost_pns, +3021 in_flight_mtu_probe, +3022 Duration::ZERO, +3023 false, +3024 size_of_lost_packets, +3025 ); +3026 } +3027 self.paths.remove(&path_id); +3028 self.spaces[SpaceId::Data].number_spaces.remove(&path_id); +3029 +3030 let path_stats = self.path_stats.remove(&path_id).unwrap_or_default(); +3031 self.events.push_back( +3032 PathEvent::Abandoned { +3033 id: path_id, +3034 path_stats, +3035 } +3036 .into(), +3037 ); +3038 } +3039 +3040 fn handle_lost_packets( +3041 &mut self, +3042 pn_space: SpaceId, +3043 path_id: PathId, +3044 now: Instant, +3045 lost_packets: Vec<u64>, +3046 lost_mtu_probe: Option<u64>, +3047 loss_delay: Duration, +3048 in_persistent_congestion: bool, +3049 size_of_lost_packets: u64, +3050 ) { +3051 debug_assert!( +3052 { +3053 let mut sorted = lost_packets.clone(); +3054 sorted.sort(); +3055 sorted == lost_packets +3056 }, +3057 "lost_packets must be sorted" +3058 ); +3059 +3060 self.drain_lost_packets(now, pn_space, path_id); +3061 +3062 // OnPacketsLost +3063 if let Some(largest_lost) = lost_packets.last().cloned() { +3064 let old_bytes_in_flight = self.path_data_mut(path_id).in_flight.bytes; +3065 let largest_lost_sent = self.spaces[pn_space] +3066 .for_path(path_id) +3067 .sent_packets +3068 .get(largest_lost) +3069 .unwrap() +3070 .time_sent; +3071 let path_stats = self.path_stats.entry(path_id).or_default(); +3072 path_stats.lost_packets += lost_packets.len() as u64; +3073 path_stats.lost_bytes += size_of_lost_packets; +3074 trace!( +3075 %path_id, +3076 count = lost_packets.len(), +3077 lost_bytes = size_of_lost_packets, +3078 "packets lost", +3079 ); +3080 +3081 for &packet in &lost_packets { +3082 let Some(info) = self.spaces[pn_space].for_path(path_id).take(packet) else { +3083 continue; +3084 }; +3085 self.qlog +3086 .emit_packet_lost(packet, &info, loss_delay, pn_space, now); +3087 self.paths +3088 .get_mut(&path_id) +3089 .unwrap() +3090 .remove_in_flight(&info); +3091 +3092 for frame in info.stream_frames { +3093 self.streams.retransmit(frame); +3094 } +3095 self.spaces[pn_space].pending |= info.retransmits; +3096 self.path_data_mut(path_id) +3097 .mtud +3098 .on_non_probe_lost(packet, info.size); +3099 +3100 self.spaces[pn_space].for_path(path_id).lost_packets.insert( +3101 packet, +3102 LostPacket { +3103 time_sent: info.time_sent, +3104 }, +3105 ); +3106 } +3107 +3108 let path = self.path_data_mut(path_id); +3109 if path.mtud.black_hole_detected(now) { +3110 path.congestion.on_mtu_update(path.mtud.current_mtu()); +3111 if let Some(max_datagram_size) = self.datagrams().max_size() +3112 && self.datagrams.drop_oversized(max_datagram_size) +3113 && self.datagrams.send_blocked +3114 { +3115 self.datagrams.send_blocked = false; +3116 self.events.push_back(Event::DatagramsUnblocked); +3117 } +3118 self.path_stats +3119 .entry(path_id) +3120 .or_default() +3121 .black_holes_detected += 1; +3122 } +3123 +3124 // Don't apply congestion penalty for lost ack-only packets +3125 let lost_ack_eliciting = +3126 old_bytes_in_flight != self.path_data_mut(path_id).in_flight.bytes; +3127 +3128 if lost_ack_eliciting { +3129 self.path_stats +3130 .entry(path_id) +3131 .or_default() +3132 .congestion_events += 1; +3133 self.path_data_mut(path_id).congestion.on_congestion_event( +3134 now, +3135 largest_lost_sent, +3136 in_persistent_congestion, +3137 false, +3138 size_of_lost_packets, +3139 ); +3140 } +3141 } +3142 +3143 // Handle a lost MTU probe +3144 if let Some(packet) = lost_mtu_probe { +3145 let info = self.spaces[SpaceId::Data] +3146 .for_path(path_id) +3147 .take(packet) +3148 .unwrap(); // safe: lost_mtu_probe is omitted from lost_packets, and +3149 // therefore must not have been removed yet +3150 self.paths +3151 .get_mut(&path_id) +3152 .unwrap() +3153 .remove_in_flight(&info); +3154 self.path_data_mut(path_id).mtud.on_probe_lost(); +3155 self.path_stats +3156 .entry(path_id) +3157 .or_default() +3158 .lost_plpmtud_probes += 1; +3159 } +3160 } +3161 +3162 /// Returns the earliest time packets should be declared lost for all spaces on a path. +3163 /// +3164 /// If a path has an acknowledged packet with any prior un-acknowledged packets, the +3165 /// earliest un-acknowledged packet can be declared lost after a timeout has elapsed. +3166 /// The time returned is when this packet should be declared lost. +3167 fn loss_time_and_space(&self, path_id: PathId) -> Option<(Instant, SpaceId)> { +3168 SpaceId::iter() +3169 .filter_map(|id| { +3170 self.spaces[id] +3171 .number_spaces +3172 .get(&path_id) +3173 .and_then(|pns| pns.loss_time) +3174 .map(|time| (time, id)) +3175 }) +3176 .min_by_key(|&(time, _)| time) +3177 } +3178 +3179 /// Returns the earliest next PTO should fire for all spaces on a path. +3180 fn pto_time_and_space(&mut self, now: Instant, path_id: PathId) -> Option<(Instant, SpaceId)> { +3181 let path = self.path(path_id)?; +3182 let pto_count = path.pto_count; +3183 let backoff = 2u32.pow(pto_count.min(MAX_BACKOFF_EXPONENT)); +3184 let mut duration = path.rtt.pto_base() * backoff; +3185 +3186 if path_id == PathId::ZERO +3187 && path.in_flight.ack_eliciting == 0 +3188 && !self.peer_completed_address_validation(PathId::ZERO) +3189 { +3190 // Address Validation during Connection Establishment: +3191 // https://www.rfc-editor.org/rfc/rfc9000.html#section-8.1. To prevent a +3192 // deadlock if an Initial or Handshake packet from the server is lost and the +3193 // server can not send more due to its anti-amplification limit the client must +3194 // send another packet on PTO. +3195 let space = match self.highest_space { +3196 SpaceId::Handshake => SpaceId::Handshake, +3197 _ => SpaceId::Initial, +3198 }; +3199 +3200 return Some((now + duration, space)); +3201 } +3202 +3203 let mut result = None; +3204 for space in SpaceId::iter() { +3205 let Some(pns) = self.spaces[space].number_spaces.get(&path_id) else { +3206 continue; +3207 }; +3208 +3209 if !pns.has_in_flight() { +3210 continue; +3211 } +3212 if space == SpaceId::Data { +3213 // Skip ApplicationData until handshake completes. +3214 if self.is_handshaking() { +3215 return result; +3216 } +3217 // Include max_ack_delay and backoff for ApplicationData. +3218 duration += self.ack_frequency.max_ack_delay_for_pto() * backoff; +3219 } +3220 let Some(last_ack_eliciting) = pns.time_of_last_ack_eliciting_packet else { +3221 continue; +3222 }; +3223 let pto = last_ack_eliciting + duration; +3224 if result.is_none_or(|(earliest_pto, _)| pto < earliest_pto) { +3225 if path.anti_amplification_blocked(1) { +3226 // Nothing would be able to be sent. +3227 continue; +3228 } +3229 if path.in_flight.ack_eliciting == 0 { +3230 // Nothing ack-eliciting, no PTO to arm/fire. +3231 continue; +3232 } +3233 result = Some((pto, space)); +3234 } +3235 } +3236 result +3237 } 3238 -3239 // Determine which PN space to arm PTO for. -3240 // Calculate PTO duration -3241 if let Some((timeout, _)) = self.pto_time_and_space(now, path_id) { -3242 self.timers.set( -3243 Timer::PerPath(path_id, PathTimer::LossDetection), -3244 timeout, -3245 self.qlog.with_time(now), -3246 ); -3247 } else { -3248 self.timers.stop( -3249 Timer::PerPath(path_id, PathTimer::LossDetection), -3250 self.qlog.with_time(now), -3251 ); -3252 } -3253 } -3254 -3255 /// The maximum probe timeout across all paths -3256 /// -3257 /// If `is_closing` is set to `true` it will filter out paths that have not yet been used. -3258 /// -3259 /// See [`Connection::pto`] -3260 fn pto_max_path(&self, space: SpaceId, is_closing: bool) -> Duration { -3261 match space { -3262 SpaceId::Initial | SpaceId::Handshake => self.pto(space, PathId::ZERO), -3263 SpaceId::Data => self -3264 .paths -3265 .iter() -3266 .filter_map(|(path_id, state)| { -3267 if is_closing && state.data.total_sent == 0 && state.data.total_recvd == 0 { -3268 // If we are closing and haven't sent anything yet, do not include -3269 None -3270 } else { -3271 let pto = self.pto(space, *path_id); -3272 Some(pto) -3273 } -3274 }) -3275 .max() -3276 .expect("there should be at least one path"), -3277 } -3278 } -3279 -3280 /// Probe Timeout -3281 /// -3282 /// The PTO is logically the time in which you'd expect to receive an acknowledgement -3283 /// for a packet. So approximately RTT + max_ack_delay. -3284 fn pto(&self, space: SpaceId, path_id: PathId) -> Duration { -3285 let max_ack_delay = match space { -3286 SpaceId::Initial | SpaceId::Handshake => Duration::ZERO, -3287 SpaceId::Data => self.ack_frequency.max_ack_delay_for_pto(), -3288 }; -3289 self.path_data(path_id).rtt.pto_base() + max_ack_delay -3290 } -3291 -3292 fn on_packet_authenticated( -3293 &mut self, -3294 now: Instant, -3295 space_id: SpaceId, -3296 path_id: PathId, -3297 ecn: Option<EcnCodepoint>, -3298 packet: Option<u64>, -3299 spin: bool, -3300 is_1rtt: bool, -3301 ) { -3302 self.total_authed_packets += 1; -3303 if let Some(AbandonState::ExpectingPathAbandon { deadline }) = self -3304 .paths -3305 .get(&path_id) -3306 .map(|path| &path.data.abandon_state) -3307 && now > *deadline -3308 { -3309 warn!("received data on path which we abandoned more than 3 * PTO ago"); -3310 // The peer failed to respond with a PATH_ABANDON in time. -3311 if !self.state.is_closed() { -3312 self.state -3313 .move_to_closed(TransportError::PROTOCOL_VIOLATION( -3314 "peer failed to respond with PATH_ABANDON in time", -3315 )); -3316 self.close_common(); -3317 self.set_close_timer(now); -3318 self.close = true; -3319 } -3320 return; +3239 fn peer_completed_address_validation(&self, path: PathId) -> bool { +3240 // TODO(flub): This logic needs updating for multipath +3241 if self.side.is_server() || self.state.is_closed() { +3242 return true; +3243 } +3244 // The server is guaranteed to have validated our address if any of our handshake or 1-RTT +3245 // packets are acknowledged or we've seen HANDSHAKE_DONE and discarded handshake keys. +3246 self.spaces[SpaceId::Handshake] +3247 .path_space(PathId::ZERO) +3248 .and_then(|pns| pns.largest_acked_packet) +3249 .is_some() +3250 || self.spaces[SpaceId::Data] +3251 .path_space(path) +3252 .and_then(|pns| pns.largest_acked_packet) +3253 .is_some() +3254 || (self.spaces[SpaceId::Data].crypto.is_some() +3255 && self.spaces[SpaceId::Handshake].crypto.is_none()) +3256 } +3257 +3258 /// Resets the the [`PathTimer::LossDetection`] timer to the next instant it may be needed +3259 /// +3260 /// The timer must fire if either: +3261 /// - An ack-eliciting packet we sent needs to be declared lost. +3262 /// - A tail-loss probe needs to be sent. +3263 /// +3264 /// See [`Connection::on_loss_detection_timeout`] for details. +3265 fn set_loss_detection_timer(&mut self, now: Instant, path_id: PathId) { +3266 if self.state.is_closed() { +3267 // No loss detection takes place on closed connections, and `close_common` already +3268 // stopped time timer. Ensure we don't restart it inadvertently, e.g. in response to a +3269 // reordered packet being handled by state-insensitive code. +3270 return; +3271 } +3272 +3273 if let Some((loss_time, _)) = self.loss_time_and_space(path_id) { +3274 // Time threshold loss detection. +3275 self.timers.set( +3276 Timer::PerPath(path_id, PathTimer::LossDetection), +3277 loss_time, +3278 self.qlog.with_time(now), +3279 ); +3280 return; +3281 } +3282 +3283 // Determine which PN space to arm PTO for. +3284 // Calculate PTO duration +3285 if let Some((timeout, _)) = self.pto_time_and_space(now, path_id) { +3286 self.timers.set( +3287 Timer::PerPath(path_id, PathTimer::LossDetection), +3288 timeout, +3289 self.qlog.with_time(now), +3290 ); +3291 } else { +3292 self.timers.stop( +3293 Timer::PerPath(path_id, PathTimer::LossDetection), +3294 self.qlog.with_time(now), +3295 ); +3296 } +3297 } +3298 +3299 /// The maximum probe timeout across all paths +3300 /// +3301 /// If `is_closing` is set to `true` it will filter out paths that have not yet been used. +3302 /// +3303 /// See [`Connection::pto`] +3304 fn pto_max_path(&self, space: SpaceId, is_closing: bool) -> Duration { +3305 match space { +3306 SpaceId::Initial | SpaceId::Handshake => self.pto(space, PathId::ZERO), +3307 SpaceId::Data => self +3308 .paths +3309 .iter() +3310 .filter_map(|(path_id, state)| { +3311 if is_closing && state.data.total_sent == 0 && state.data.total_recvd == 0 { +3312 // If we are closing and haven't sent anything yet, do not include +3313 None +3314 } else { +3315 let pto = self.pto(space, *path_id); +3316 Some(pto) +3317 } +3318 }) +3319 .max() +3320 .expect("there should be at least one path"), 3321 } -3322 -3323 self.reset_keep_alive(path_id, now); -3324 self.reset_idle_timeout(now, space_id, path_id); -3325 self.permit_idle_reset = true; -3326 self.receiving_ecn |= ecn.is_some(); -3327 if let Some(x) = ecn { -3328 let space = &mut self.spaces[space_id]; -3329 space.for_path(path_id).ecn_counters += x; -3330 -3331 if x.is_ce() { -3332 space -3333 .for_path(path_id) -3334 .pending_acks -3335 .set_immediate_ack_required(); -3336 } -3337 } -3338 -3339 let packet = match packet { -3340 Some(x) => x, -3341 None => return, -3342 }; -3343 match &self.side { -3344 ConnectionSide::Client { .. } => { -3345 // If we received a handshake packet that authenticated, then we're talking to -3346 // the real server. From now on we should no longer allow the server to migrate -3347 // its address. -3348 if space_id == SpaceId::Handshake -3349 && let Some(hs) = self.state.as_handshake_mut() -3350 { -3351 hs.allow_server_migration = false; -3352 } -3353 } -3354 ConnectionSide::Server { .. } => { -3355 if self.spaces[SpaceId::Initial].crypto.is_some() && space_id == SpaceId::Handshake -3356 { -3357 // A server stops sending and processing Initial packets when it receives its first Handshake packet. -3358 self.discard_space(now, SpaceId::Initial); -3359 } -3360 if self.zero_rtt_crypto.is_some() && is_1rtt { -3361 // Discard 0-RTT keys soon after receiving a 1-RTT packet -3362 self.set_key_discard_timer(now, space_id) -3363 } -3364 } +3322 } +3323 +3324 /// Probe Timeout +3325 /// +3326 /// The PTO is logically the time in which you'd expect to receive an acknowledgement +3327 /// for a packet. So approximately RTT + max_ack_delay. +3328 fn pto(&self, space: SpaceId, path_id: PathId) -> Duration { +3329 let max_ack_delay = match space { +3330 SpaceId::Initial | SpaceId::Handshake => Duration::ZERO, +3331 SpaceId::Data => self.ack_frequency.max_ack_delay_for_pto(), +3332 }; +3333 self.path_data(path_id).rtt.pto_base() + max_ack_delay +3334 } +3335 +3336 fn on_packet_authenticated( +3337 &mut self, +3338 now: Instant, +3339 space_id: SpaceId, +3340 path_id: PathId, +3341 ecn: Option<EcnCodepoint>, +3342 packet: Option<u64>, +3343 spin: bool, +3344 is_1rtt: bool, +3345 ) { +3346 self.total_authed_packets += 1; +3347 if let Some(AbandonState::ExpectingPathAbandon { deadline }) = self +3348 .paths +3349 .get(&path_id) +3350 .map(|path| &path.data.abandon_state) +3351 && now > *deadline +3352 { +3353 warn!("received data on path which we abandoned more than 3 * PTO ago"); +3354 // The peer failed to respond with a PATH_ABANDON in time. +3355 if !self.state.is_closed() { +3356 self.state +3357 .move_to_closed(TransportError::PROTOCOL_VIOLATION( +3358 "peer failed to respond with PATH_ABANDON in time", +3359 )); +3360 self.close_common(); +3361 self.set_close_timer(now); +3362 self.connection_close_pending = true; +3363 } +3364 return; 3365 } -3366 let space = self.spaces[space_id].for_path(path_id); -3367 space.pending_acks.insert_one(packet, now); -3368 if packet >= space.rx_packet.unwrap_or_default() { -3369 space.rx_packet = Some(packet); -3370 // Update outgoing spin bit, inverting iff we're the client -3371 self.spin = self.side.is_client() ^ spin; -3372 } -3373 } +3366 +3367 self.reset_keep_alive(path_id, now); +3368 self.reset_idle_timeout(now, space_id, path_id); +3369 self.permit_idle_reset = true; +3370 self.receiving_ecn |= ecn.is_some(); +3371 if let Some(x) = ecn { +3372 let space = &mut self.spaces[space_id]; +3373 space.for_path(path_id).ecn_counters += x; 3374 -3375 /// Resets the idle timeout timers -3376 /// -3377 /// Without multipath there is only the connection-wide idle timeout. When multipath is -3378 /// enabled there is an additional per-path idle timeout. -3379 fn reset_idle_timeout(&mut self, now: Instant, space: SpaceId, path_id: PathId) { -3380 // First reset the global idle timeout. -3381 if let Some(timeout) = self.idle_timeout { -3382 if self.state.is_closed() { -3383 self.timers -3384 .stop(Timer::Conn(ConnTimer::Idle), self.qlog.with_time(now)); -3385 } else { -3386 let dt = cmp::max(timeout, 3 * self.pto_max_path(space, false)); -3387 self.timers.set( -3388 Timer::Conn(ConnTimer::Idle), -3389 now + dt, -3390 self.qlog.with_time(now), -3391 ); -3392 } -3393 } -3394 -3395 // Now handle the per-path state -3396 if let Some(timeout) = self.path_data(path_id).idle_timeout { -3397 if self.state.is_closed() { -3398 self.timers.stop( -3399 Timer::PerPath(path_id, PathTimer::PathIdle), -3400 self.qlog.with_time(now), -3401 ); -3402 } else { -3403 let dt = cmp::max(timeout, 3 * self.pto(space, path_id)); -3404 self.timers.set( -3405 Timer::PerPath(path_id, PathTimer::PathIdle), -3406 now + dt, -3407 self.qlog.with_time(now), -3408 ); -3409 } -3410 } -3411 } -3412 -3413 /// Resets both the [`ConnTimer::KeepAlive`] and [`PathTimer::PathKeepAlive`] timers -3414 fn reset_keep_alive(&mut self, path_id: PathId, now: Instant) { -3415 if !self.state.is_established() { -3416 return; -3417 } +3375 if x.is_ce() { +3376 space +3377 .for_path(path_id) +3378 .pending_acks +3379 .set_immediate_ack_required(); +3380 } +3381 } +3382 +3383 let packet = match packet { +3384 Some(x) => x, +3385 None => return, +3386 }; +3387 match &self.side { +3388 ConnectionSide::Client { .. } => { +3389 // If we received a handshake packet that authenticated, then we're talking to +3390 // the real server. From now on we should no longer allow the server to migrate +3391 // its address. +3392 if space_id == SpaceId::Handshake +3393 && let Some(hs) = self.state.as_handshake_mut() +3394 { +3395 hs.allow_server_migration = false; +3396 } +3397 } +3398 ConnectionSide::Server { .. } => { +3399 if self.spaces[SpaceId::Initial].crypto.is_some() && space_id == SpaceId::Handshake +3400 { +3401 // A server stops sending and processing Initial packets when it receives its first Handshake packet. +3402 self.discard_space(now, SpaceId::Initial); +3403 } +3404 if self.zero_rtt_crypto.is_some() && is_1rtt { +3405 // Discard 0-RTT keys soon after receiving a 1-RTT packet +3406 self.set_key_discard_timer(now, space_id) +3407 } +3408 } +3409 } +3410 let space = self.spaces[space_id].for_path(path_id); +3411 space.pending_acks.insert_one(packet, now); +3412 if packet >= space.rx_packet.unwrap_or_default() { +3413 space.rx_packet = Some(packet); +3414 // Update outgoing spin bit, inverting iff we're the client +3415 self.spin = self.side.is_client() ^ spin; +3416 } +3417 } 3418 -3419 if let Some(interval) = self.config.keep_alive_interval { -3420 self.timers.set( -3421 Timer::Conn(ConnTimer::KeepAlive), -3422 now + interval, -3423 self.qlog.with_time(now), -3424 ); -3425 } -3426 -3427 if let Some(interval) = self.path_data(path_id).keep_alive { -3428 self.timers.set( -3429 Timer::PerPath(path_id, PathTimer::PathKeepAlive), -3430 now + interval, -3431 self.qlog.with_time(now), -3432 ); -3433 } -3434 } -3435 -3436 /// Sets the timer for when a previously issued CID should be retired next -3437 fn reset_cid_retirement(&mut self, now: Instant) { -3438 if let Some((_path, t)) = self.next_cid_retirement() { -3439 self.timers.set( -3440 Timer::Conn(ConnTimer::PushNewCid), -3441 t, -3442 self.qlog.with_time(now), -3443 ); -3444 } -3445 } -3446 -3447 /// The next time when a previously issued CID should be retired -3448 fn next_cid_retirement(&self) -> Option<(PathId, Instant)> { -3449 self.local_cid_state -3450 .iter() -3451 .filter_map(|(path_id, cid_state)| cid_state.next_timeout().map(|t| (*path_id, t))) -3452 .min_by_key(|(_path_id, timeout)| *timeout) -3453 } -3454 -3455 /// Handle the already-decrypted first packet from the client -3456 /// -3457 /// Decrypting the first packet in the `Endpoint` allows stateless packet handling to be more -3458 /// efficient. -3459 pub(crate) fn handle_first_packet( -3460 &mut self, -3461 now: Instant, -3462 network_path: FourTuple, -3463 ecn: Option<EcnCodepoint>, -3464 packet_number: u64, -3465 packet: InitialPacket, -3466 remaining: Option<BytesMut>, -3467 ) -> Result<(), ConnectionError> { -3468 let span = trace_span!("first recv"); -3469 let _guard = span.enter(); -3470 debug_assert!(self.side.is_server()); -3471 let len = packet.header_data.len() + packet.payload.len(); -3472 let path_id = PathId::ZERO; -3473 self.path_data_mut(path_id).total_recvd = len as u64; -3474 -3475 if let Some(hs) = self.state.as_handshake_mut() { -3476 hs.expected_token = packet.header.token.clone(); -3477 } else { -3478 unreachable!("first packet must be delivered in Handshake state"); -3479 } -3480 -3481 // The first packet is always on PathId::ZERO -3482 self.on_packet_authenticated( -3483 now, -3484 SpaceId::Initial, -3485 path_id, -3486 ecn, -3487 Some(packet_number), -3488 false, -3489 false, -3490 ); -3491 -3492 let packet: Packet = packet.into(); -3493 -3494 let mut qlog = QlogRecvPacket::new(len); -3495 qlog.header(&packet.header, Some(packet_number), path_id); -3496 -3497 self.process_decrypted_packet( -3498 now, -3499 network_path, -3500 path_id, -3501 Some(packet_number), -3502 packet, -3503 &mut qlog, -3504 )?; -3505 self.qlog.emit_packet_received(qlog, now); -3506 if let Some(data) = remaining { -3507 self.handle_coalesced(now, network_path, path_id, ecn, data); -3508 } -3509 -3510 self.qlog.emit_recovery_metrics( -3511 path_id, -3512 &mut self.paths.get_mut(&path_id).unwrap().data, -3513 now, -3514 ); -3515 -3516 Ok(()) -3517 } +3419 /// Resets the idle timeout timers +3420 /// +3421 /// Without multipath there is only the connection-wide idle timeout. When multipath is +3422 /// enabled there is an additional per-path idle timeout. +3423 fn reset_idle_timeout(&mut self, now: Instant, space: SpaceId, path_id: PathId) { +3424 // First reset the global idle timeout. +3425 if let Some(timeout) = self.idle_timeout { +3426 if self.state.is_closed() { +3427 self.timers +3428 .stop(Timer::Conn(ConnTimer::Idle), self.qlog.with_time(now)); +3429 } else { +3430 let dt = cmp::max(timeout, 3 * self.pto_max_path(space, false)); +3431 self.timers.set( +3432 Timer::Conn(ConnTimer::Idle), +3433 now + dt, +3434 self.qlog.with_time(now), +3435 ); +3436 } +3437 } +3438 +3439 // Now handle the per-path state +3440 if let Some(timeout) = self.path_data(path_id).idle_timeout { +3441 if self.state.is_closed() { +3442 self.timers.stop( +3443 Timer::PerPath(path_id, PathTimer::PathIdle), +3444 self.qlog.with_time(now), +3445 ); +3446 } else { +3447 let dt = cmp::max(timeout, 3 * self.pto(space, path_id)); +3448 self.timers.set( +3449 Timer::PerPath(path_id, PathTimer::PathIdle), +3450 now + dt, +3451 self.qlog.with_time(now), +3452 ); +3453 } +3454 } +3455 } +3456 +3457 /// Resets both the [`ConnTimer::KeepAlive`] and [`PathTimer::PathKeepAlive`] timers +3458 fn reset_keep_alive(&mut self, path_id: PathId, now: Instant) { +3459 if !self.state.is_established() { +3460 return; +3461 } +3462 +3463 if let Some(interval) = self.config.keep_alive_interval { +3464 self.timers.set( +3465 Timer::Conn(ConnTimer::KeepAlive), +3466 now + interval, +3467 self.qlog.with_time(now), +3468 ); +3469 } +3470 +3471 if let Some(interval) = self.path_data(path_id).keep_alive { +3472 self.timers.set( +3473 Timer::PerPath(path_id, PathTimer::PathKeepAlive), +3474 now + interval, +3475 self.qlog.with_time(now), +3476 ); +3477 } +3478 } +3479 +3480 /// Sets the timer for when a previously issued CID should be retired next +3481 fn reset_cid_retirement(&mut self, now: Instant) { +3482 if let Some((_path, t)) = self.next_cid_retirement() { +3483 self.timers.set( +3484 Timer::Conn(ConnTimer::PushNewCid), +3485 t, +3486 self.qlog.with_time(now), +3487 ); +3488 } +3489 } +3490 +3491 /// The next time when a previously issued CID should be retired +3492 fn next_cid_retirement(&self) -> Option<(PathId, Instant)> { +3493 self.local_cid_state +3494 .iter() +3495 .filter_map(|(path_id, cid_state)| cid_state.next_timeout().map(|t| (*path_id, t))) +3496 .min_by_key(|(_path_id, timeout)| *timeout) +3497 } +3498 +3499 /// Handle the already-decrypted first packet from the client +3500 /// +3501 /// Decrypting the first packet in the `Endpoint` allows stateless packet handling to be more +3502 /// efficient. +3503 pub(crate) fn handle_first_packet( +3504 &mut self, +3505 now: Instant, +3506 network_path: FourTuple, +3507 ecn: Option<EcnCodepoint>, +3508 packet_number: u64, +3509 packet: InitialPacket, +3510 remaining: Option<BytesMut>, +3511 ) -> Result<(), ConnectionError> { +3512 let span = trace_span!("first recv"); +3513 let _guard = span.enter(); +3514 debug_assert!(self.side.is_server()); +3515 let len = packet.header_data.len() + packet.payload.len(); +3516 let path_id = PathId::ZERO; +3517 self.path_data_mut(path_id).total_recvd = len as u64; 3518 -3519 fn init_0rtt(&mut self, now: Instant) { -3520 let (header, packet) = match self.crypto.early_crypto() { -3521 Some(x) => x, -3522 None => return, -3523 }; -3524 if self.side.is_client() { -3525 match self.crypto.transport_parameters() { -3526 Ok(params) => { -3527 let params = params -3528 .expect("crypto layer didn't supply transport parameters with ticket"); -3529 // Certain values must not be cached -3530 let params = TransportParameters { -3531 initial_src_cid: None, -3532 original_dst_cid: None, -3533 preferred_address: None, -3534 retry_src_cid: None, -3535 stateless_reset_token: None, -3536 min_ack_delay: None, -3537 ack_delay_exponent: TransportParameters::default().ack_delay_exponent, -3538 max_ack_delay: TransportParameters::default().max_ack_delay, -3539 initial_max_path_id: None, -3540 ..params -3541 }; -3542 self.set_peer_params(params); -3543 self.qlog.emit_peer_transport_params_restored(self, now); -3544 } -3545 Err(e) => { -3546 error!("session ticket has malformed transport parameters: {}", e); -3547 return; -3548 } -3549 } -3550 } -3551 trace!("0-RTT enabled"); -3552 self.zero_rtt_enabled = true; -3553 self.zero_rtt_crypto = Some(ZeroRttCrypto { header, packet }); -3554 } -3555 -3556 fn read_crypto( -3557 &mut self, -3558 space: SpaceId, -3559 crypto: &frame::Crypto, -3560 payload_len: usize, -3561 ) -> Result<(), TransportError> { -3562 let expected = if !self.state.is_handshake() { -3563 SpaceId::Data -3564 } else if self.highest_space == SpaceId::Initial { -3565 SpaceId::Initial -3566 } else { -3567 // On the server, self.highest_space can be Data after receiving the client's first -3568 // flight, but we expect Handshake CRYPTO until the handshake is complete. -3569 SpaceId::Handshake -3570 }; -3571 // We can't decrypt Handshake packets when highest_space is Initial, CRYPTO frames in 0-RTT -3572 // packets are illegal, and we don't process 1-RTT packets until the handshake is -3573 // complete. Therefore, we will never see CRYPTO data from a later-than-expected space. -3574 debug_assert!(space <= expected, "received out-of-order CRYPTO data"); -3575 -3576 let end = crypto.offset + crypto.data.len() as u64; -3577 if space < expected && end > self.spaces[space].crypto_stream.bytes_read() { -3578 warn!( -3579 "received new {:?} CRYPTO data when expecting {:?}", -3580 space, expected -3581 ); -3582 return Err(TransportError::PROTOCOL_VIOLATION( -3583 "new data at unexpected encryption level", -3584 )); -3585 } -3586 -3587 let space = &mut self.spaces[space]; -3588 let max = end.saturating_sub(space.crypto_stream.bytes_read()); -3589 if max > self.config.crypto_buffer_size as u64 { -3590 return Err(TransportError::CRYPTO_BUFFER_EXCEEDED("")); -3591 } -3592 -3593 space -3594 .crypto_stream -3595 .insert(crypto.offset, crypto.data.clone(), payload_len); -3596 while let Some(chunk) = space.crypto_stream.read(usize::MAX, true) { -3597 trace!("consumed {} CRYPTO bytes", chunk.bytes.len()); -3598 if self.crypto.read_handshake(&chunk.bytes)? { -3599 self.events.push_back(Event::HandshakeDataReady); -3600 } -3601 } -3602 -3603 Ok(()) -3604 } -3605 -3606 fn write_crypto(&mut self) { -3607 loop { -3608 let space = self.highest_space; -3609 let mut outgoing = Vec::new(); -3610 if let Some(crypto) = self.crypto.write_handshake(&mut outgoing) { -3611 match space { -3612 SpaceId::Initial => { -3613 self.upgrade_crypto(SpaceId::Handshake, crypto); -3614 } -3615 SpaceId::Handshake => { -3616 self.upgrade_crypto(SpaceId::Data, crypto); -3617 } -3618 _ => unreachable!("got updated secrets during 1-RTT"), -3619 } -3620 } -3621 if outgoing.is_empty() { -3622 if space == self.highest_space { -3623 break; -3624 } else { -3625 // Keys updated, check for more data to send -3626 continue; -3627 } -3628 } -3629 let offset = self.spaces[space].crypto_offset; -3630 let outgoing = Bytes::from(outgoing); -3631 if let Some(hs) = self.state.as_handshake_mut() -3632 && space == SpaceId::Initial -3633 && offset == 0 -3634 && self.side.is_client() -3635 { -3636 hs.client_hello = Some(outgoing.clone()); -3637 } -3638 self.spaces[space].crypto_offset += outgoing.len() as u64; -3639 trace!("wrote {} {:?} CRYPTO bytes", outgoing.len(), space); -3640 self.spaces[space].pending.crypto.push_back(frame::Crypto { -3641 offset, -3642 data: outgoing, -3643 }); -3644 } -3645 } +3519 if let Some(hs) = self.state.as_handshake_mut() { +3520 hs.expected_token = packet.header.token.clone(); +3521 } else { +3522 unreachable!("first packet must be delivered in Handshake state"); +3523 } +3524 +3525 // The first packet is always on PathId::ZERO +3526 self.on_packet_authenticated( +3527 now, +3528 SpaceId::Initial, +3529 path_id, +3530 ecn, +3531 Some(packet_number), +3532 false, +3533 false, +3534 ); +3535 +3536 let packet: Packet = packet.into(); +3537 +3538 let mut qlog = QlogRecvPacket::new(len); +3539 qlog.header(&packet.header, Some(packet_number), path_id); +3540 +3541 self.process_decrypted_packet( +3542 now, +3543 network_path, +3544 path_id, +3545 Some(packet_number), +3546 packet, +3547 &mut qlog, +3548 )?; +3549 self.qlog.emit_packet_received(qlog, now); +3550 if let Some(data) = remaining { +3551 self.handle_coalesced(now, network_path, path_id, ecn, data); +3552 } +3553 +3554 self.qlog.emit_recovery_metrics( +3555 path_id, +3556 &mut self.paths.get_mut(&path_id).unwrap().data, +3557 now, +3558 ); +3559 +3560 Ok(()) +3561 } +3562 +3563 fn init_0rtt(&mut self, now: Instant) { +3564 let (header, packet) = match self.crypto.early_crypto() { +3565 Some(x) => x, +3566 None => return, +3567 }; +3568 if self.side.is_client() { +3569 match self.crypto.transport_parameters() { +3570 Ok(params) => { +3571 let params = params +3572 .expect("crypto layer didn't supply transport parameters with ticket"); +3573 // Certain values must not be cached +3574 let params = TransportParameters { +3575 initial_src_cid: None, +3576 original_dst_cid: None, +3577 preferred_address: None, +3578 retry_src_cid: None, +3579 stateless_reset_token: None, +3580 min_ack_delay: None, +3581 ack_delay_exponent: TransportParameters::default().ack_delay_exponent, +3582 max_ack_delay: TransportParameters::default().max_ack_delay, +3583 initial_max_path_id: None, +3584 ..params +3585 }; +3586 self.set_peer_params(params); +3587 self.qlog.emit_peer_transport_params_restored(self, now); +3588 } +3589 Err(e) => { +3590 error!("session ticket has malformed transport parameters: {}", e); +3591 return; +3592 } +3593 } +3594 } +3595 trace!("0-RTT enabled"); +3596 self.zero_rtt_enabled = true; +3597 self.zero_rtt_crypto = Some(ZeroRttCrypto { header, packet }); +3598 } +3599 +3600 fn read_crypto( +3601 &mut self, +3602 space: SpaceId, +3603 crypto: &frame::Crypto, +3604 payload_len: usize, +3605 ) -> Result<(), TransportError> { +3606 let expected = if !self.state.is_handshake() { +3607 SpaceId::Data +3608 } else if self.highest_space == SpaceId::Initial { +3609 SpaceId::Initial +3610 } else { +3611 // On the server, self.highest_space can be Data after receiving the client's first +3612 // flight, but we expect Handshake CRYPTO until the handshake is complete. +3613 SpaceId::Handshake +3614 }; +3615 // We can't decrypt Handshake packets when highest_space is Initial, CRYPTO frames in 0-RTT +3616 // packets are illegal, and we don't process 1-RTT packets until the handshake is +3617 // complete. Therefore, we will never see CRYPTO data from a later-than-expected space. +3618 debug_assert!(space <= expected, "received out-of-order CRYPTO data"); +3619 +3620 let end = crypto.offset + crypto.data.len() as u64; +3621 if space < expected && end > self.spaces[space].crypto_stream.bytes_read() { +3622 warn!( +3623 "received new {:?} CRYPTO data when expecting {:?}", +3624 space, expected +3625 ); +3626 return Err(TransportError::PROTOCOL_VIOLATION( +3627 "new data at unexpected encryption level", +3628 )); +3629 } +3630 +3631 let space = &mut self.spaces[space]; +3632 let max = end.saturating_sub(space.crypto_stream.bytes_read()); +3633 if max > self.config.crypto_buffer_size as u64 { +3634 return Err(TransportError::CRYPTO_BUFFER_EXCEEDED("")); +3635 } +3636 +3637 space +3638 .crypto_stream +3639 .insert(crypto.offset, crypto.data.clone(), payload_len); +3640 while let Some(chunk) = space.crypto_stream.read(usize::MAX, true) { +3641 trace!("consumed {} CRYPTO bytes", chunk.bytes.len()); +3642 if self.crypto.read_handshake(&chunk.bytes)? { +3643 self.events.push_back(Event::HandshakeDataReady); +3644 } +3645 } 3646 -3647 /// Switch to stronger cryptography during handshake -3648 fn upgrade_crypto(&mut self, space: SpaceId, crypto: Keys) { -3649 debug_assert!( -3650 self.spaces[space].crypto.is_none(), -3651 "already reached packet space {space:?}" -3652 ); -3653 trace!("{:?} keys ready", space); -3654 if space == SpaceId::Data { -3655 // Precompute the first key update -3656 self.next_crypto = Some( -3657 self.crypto -3658 .next_1rtt_keys() -3659 .expect("handshake should be complete"), -3660 ); -3661 } -3662 -3663 self.spaces[space].crypto = Some(crypto); -3664 debug_assert!(space as usize > self.highest_space as usize); -3665 self.highest_space = space; -3666 if space == SpaceId::Data && self.side.is_client() { -3667 // Discard 0-RTT keys because 1-RTT keys are available. -3668 self.zero_rtt_crypto = None; -3669 } -3670 } -3671 -3672 fn discard_space(&mut self, now: Instant, space_id: SpaceId) { -3673 debug_assert!(space_id != SpaceId::Data); -3674 trace!("discarding {:?} keys", space_id); -3675 if space_id == SpaceId::Initial { -3676 // No longer needed -3677 if let ConnectionSide::Client { token, .. } = &mut self.side { -3678 *token = Bytes::new(); -3679 } -3680 } -3681 let space = &mut self.spaces[space_id]; -3682 space.crypto = None; -3683 let pns = space.for_path(PathId::ZERO); -3684 pns.time_of_last_ack_eliciting_packet = None; -3685 pns.loss_time = None; -3686 pns.loss_probes = 0; -3687 let sent_packets = mem::take(&mut pns.sent_packets); -3688 let path = self.paths.get_mut(&PathId::ZERO).unwrap(); -3689 for (_, packet) in sent_packets.into_iter() { -3690 path.data.remove_in_flight(&packet); -3691 } -3692 -3693 self.set_loss_detection_timer(now, PathId::ZERO) -3694 } -3695 -3696 fn handle_coalesced( -3697 &mut self, -3698 now: Instant, -3699 network_path: FourTuple, -3700 path_id: PathId, -3701 ecn: Option<EcnCodepoint>, -3702 data: BytesMut, -3703 ) { -3704 self.path_data_mut(path_id) -3705 .inc_total_recvd(data.len() as u64); -3706 let mut remaining = Some(data); -3707 let cid_len = self -3708 .local_cid_state -3709 .values() -3710 .map(|cid_state| cid_state.cid_len()) -3711 .next() -3712 .expect("one cid_state must exist"); -3713 while let Some(data) = remaining { -3714 match PartialDecode::new( -3715 data, -3716 &FixedLengthConnectionIdParser::new(cid_len), -3717 &[self.version], -3718 self.endpoint_config.grease_quic_bit, -3719 ) { -3720 Ok((partial_decode, rest)) => { -3721 remaining = rest; -3722 self.handle_decode(now, network_path, path_id, ecn, partial_decode); -3723 } -3724 Err(e) => { -3725 trace!("malformed header: {}", e); -3726 return; -3727 } -3728 } -3729 } -3730 } -3731 -3732 fn handle_decode( -3733 &mut self, -3734 now: Instant, -3735 network_path: FourTuple, -3736 path_id: PathId, -3737 ecn: Option<EcnCodepoint>, -3738 partial_decode: PartialDecode, -3739 ) { -3740 let qlog = QlogRecvPacket::new(partial_decode.len()); -3741 if let Some(decoded) = packet_crypto::unprotect_header( -3742 partial_decode, -3743 &self.spaces, -3744 self.zero_rtt_crypto.as_ref(), -3745 self.peer_params.stateless_reset_token, -3746 ) { -3747 self.handle_packet( -3748 now, -3749 network_path, -3750 path_id, -3751 ecn, -3752 decoded.packet, -3753 decoded.stateless_reset, -3754 qlog, -3755 ); -3756 } -3757 } -3758 -3759 fn handle_packet( -3760 &mut self, -3761 now: Instant, -3762 network_path: FourTuple, -3763 path_id: PathId, -3764 ecn: Option<EcnCodepoint>, -3765 packet: Option<Packet>, -3766 stateless_reset: bool, -3767 mut qlog: QlogRecvPacket, -3768 ) { -3769 self.stats.udp_rx.ios += 1; -3770 self.path_stats.entry(path_id).or_default().udp_rx.ios += 1; -3771 -3772 if let Some(ref packet) = packet { -3773 trace!( -3774 "got {:?} packet ({} bytes) from {} using id {}", -3775 packet.header.space(), -3776 packet.payload.len() + packet.header_data.len(), -3777 network_path, -3778 packet.header.dst_cid(), -3779 ); -3780 } -3781 -3782 if self.is_handshaking() { -3783 if path_id != PathId::ZERO { -3784 debug!(%network_path, %path_id, "discarding multipath packet during handshake"); -3785 return; -3786 } -3787 if network_path != self.path_data_mut(path_id).network_path { -3788 if let Some(hs) = self.state.as_handshake() { -3789 if hs.allow_server_migration { -3790 trace!(%network_path, prev = %self.path_data(path_id).network_path, "server migrated to new remote"); -3791 self.path_data_mut(path_id).network_path = network_path; -3792 self.qlog.emit_tuple_assigned(path_id, network_path, now); -3793 } else { -3794 debug!("discarding packet with unexpected remote during handshake"); -3795 return; -3796 } -3797 } else { -3798 debug!("discarding packet with unexpected remote during handshake"); -3799 return; -3800 } -3801 } -3802 } -3803 -3804 let was_closed = self.state.is_closed(); -3805 let was_drained = self.state.is_drained(); -3806 -3807 let decrypted = match packet { -3808 None => Err(None), -3809 Some(mut packet) => self -3810 .decrypt_packet(now, path_id, &mut packet) -3811 .map(move |number| (packet, number)), -3812 }; -3813 let result = match decrypted { -3814 _ if stateless_reset => { -3815 debug!("got stateless reset"); -3816 Err(ConnectionError::Reset) -3817 } -3818 Err(Some(e)) => { -3819 warn!("illegal packet: {}", e); -3820 Err(e.into()) -3821 } -3822 Err(None) => { -3823 debug!("failed to authenticate packet"); -3824 self.authentication_failures += 1; -3825 let integrity_limit = self.spaces[self.highest_space] -3826 .crypto -3827 .as_ref() -3828 .unwrap() -3829 .packet -3830 .local -3831 .integrity_limit(); -3832 if self.authentication_failures > integrity_limit { -3833 Err(TransportError::AEAD_LIMIT_REACHED("integrity limit violated").into()) -3834 } else { -3835 return; -3836 } -3837 } -3838 Ok((packet, number)) => { -3839 qlog.header(&packet.header, number, path_id); -3840 let span = match number { -3841 Some(pn) => trace_span!("recv", space = ?packet.header.space(), pn), -3842 None => trace_span!("recv", space = ?packet.header.space()), -3843 }; -3844 let _guard = span.enter(); -3845 -3846 let dedup = self.spaces[packet.header.space()] -3847 .path_space_mut(path_id) -3848 .map(|pns| &mut pns.dedup); -3849 if number.zip(dedup).is_some_and(|(n, d)| d.insert(n)) { -3850 debug!("discarding possible duplicate packet"); -3851 self.qlog.emit_packet_received(qlog, now); -3852 return; -3853 } else if self.state.is_handshake() && packet.header.is_short() { -3854 // TODO: SHOULD buffer these to improve reordering tolerance. -3855 trace!("dropping short packet during handshake"); -3856 self.qlog.emit_packet_received(qlog, now); -3857 return; -3858 } else { -3859 if let Header::Initial(InitialHeader { ref token, .. }) = packet.header -3860 && let Some(hs) = self.state.as_handshake() -3861 && self.side.is_server() -3862 && token != &hs.expected_token -3863 { -3864 // Clients must send the same retry token in every Initial. Initial -3865 // packets can be spoofed, so we discard rather than killing the -3866 // connection. -3867 warn!("discarding Initial with invalid retry token"); -3868 self.qlog.emit_packet_received(qlog, now); -3869 return; -3870 } -3871 -3872 if !self.state.is_closed() { -3873 let spin = match packet.header { -3874 Header::Short { spin, .. } => spin, -3875 _ => false, -3876 }; -3877 -3878 if self.side().is_server() && !self.abandoned_paths.contains(&path_id) { -3879 // Only the client is allowed to open paths -3880 self.ensure_path(path_id, network_path, now, number); -3881 } -3882 if self.paths.contains_key(&path_id) { -3883 self.on_packet_authenticated( -3884 now, -3885 packet.header.space(), -3886 path_id, -3887 ecn, -3888 number, -3889 spin, -3890 packet.header.is_1rtt(), -3891 ); -3892 } -3893 } -3894 -3895 let res = self.process_decrypted_packet( -3896 now, -3897 network_path, -3898 path_id, -3899 number, -3900 packet, -3901 &mut qlog, -3902 ); -3903 -3904 self.qlog.emit_packet_received(qlog, now); -3905 res -3906 } -3907 } -3908 }; -3909 -3910 // State transitions for error cases -3911 if let Err(conn_err) = result { -3912 match conn_err { -3913 ConnectionError::ApplicationClosed(reason) => self.state.move_to_closed(reason), -3914 ConnectionError::ConnectionClosed(reason) => self.state.move_to_closed(reason), -3915 ConnectionError::Reset -3916 | ConnectionError::TransportError(TransportError { -3917 code: TransportErrorCode::AEAD_LIMIT_REACHED, -3918 .. -3919 }) => { -3920 self.state.move_to_drained(Some(conn_err)); -3921 } -3922 ConnectionError::TimedOut => { -3923 unreachable!("timeouts aren't generated by packet processing"); -3924 } -3925 ConnectionError::TransportError(err) => { -3926 debug!("closing connection due to transport error: {}", err); -3927 self.state.move_to_closed(err); -3928 } -3929 ConnectionError::VersionMismatch => { -3930 self.state.move_to_draining(Some(conn_err)); -3931 } -3932 ConnectionError::LocallyClosed => { -3933 unreachable!("LocallyClosed isn't generated by packet processing"); -3934 } -3935 ConnectionError::CidsExhausted => { -3936 unreachable!("CidsExhausted isn't generated by packet processing"); -3937 } -3938 }; -3939 } -3940 -3941 if !was_closed && self.state.is_closed() { -3942 self.close_common(); -3943 if !self.state.is_drained() { -3944 self.set_close_timer(now); -3945 } -3946 } -3947 if !was_drained && self.state.is_drained() { -3948 self.endpoint_events.push_back(EndpointEventInner::Drained); -3949 // Close timer may have been started previously, e.g. if we sent a close and got a -3950 // stateless reset in response -3951 self.timers -3952 .stop(Timer::Conn(ConnTimer::Close), self.qlog.with_time(now)); -3953 } -3954 -3955 // Transmit CONNECTION_CLOSE if necessary -3956 if matches!(self.state.as_type(), StateType::Closed) { -3957 // If there is no PathData for this PathId the packet was for a brand new -3958 // path. It was a valid packet however, so the remote is valid and we want to -3959 // send CONNECTION_CLOSE. -3960 let path_remote = self -3961 .paths -3962 .get(&path_id) -3963 .map(|p| p.data.network_path) -3964 .unwrap_or(network_path); -3965 self.close = network_path == path_remote; -3966 } -3967 } -3968 -3969 fn process_decrypted_packet( -3970 &mut self, -3971 now: Instant, -3972 network_path: FourTuple, -3973 path_id: PathId, -3974 number: Option<u64>, -3975 packet: Packet, -3976 qlog: &mut QlogRecvPacket, -3977 ) -> Result<(), ConnectionError> { -3978 if !self.paths.contains_key(&path_id) { -3979 // There is a chance this is a server side, first (for this path) packet, which would -3980 // be a protocol violation. It's more likely, however, that this is a packet of a -3981 // pruned path -3982 trace!(%path_id, ?number, "discarding packet for unknown path"); -3983 return Ok(()); -3984 } -3985 let state = match self.state.as_type() { -3986 StateType::Established => { -3987 match packet.header.space() { -3988 SpaceId::Data => self.process_payload( -3989 now, -3990 network_path, -3991 path_id, -3992 number.unwrap(), -3993 packet, -3994 qlog, -3995 )?, -3996 _ if packet.header.has_frames() => { -3997 self.process_early_payload(now, path_id, packet, qlog)? -3998 } -3999 _ => { -4000 trace!("discarding unexpected pre-handshake packet"); -4001 } -4002 } -4003 return Ok(()); -4004 } -4005 StateType::Closed => { -4006 for result in frame::Iter::new(packet.payload.freeze())? { -4007 let frame = match result { -4008 Ok(frame) => frame, -4009 Err(err) => { -4010 debug!("frame decoding error: {err:?}"); -4011 continue; -4012 } -4013 }; -4014 qlog.frame(&frame); -4015 -4016 if let Frame::Padding = frame { -4017 continue; -4018 }; -4019 -4020 self.stats.frame_rx.record(frame.ty()); -4021 -4022 if let Frame::Close(_error) = frame { -4023 self.state.move_to_draining(None); -4024 break; -4025 } -4026 } -4027 return Ok(()); -4028 } -4029 StateType::Draining | StateType::Drained => return Ok(()), -4030 StateType::Handshake => self.state.as_handshake_mut().expect("checked"), -4031 }; -4032 -4033 match packet.header { -4034 Header::Retry { -4035 src_cid: rem_cid, .. -4036 } => { -4037 debug_assert_eq!(path_id, PathId::ZERO); -4038 if self.side.is_server() { -4039 return Err(TransportError::PROTOCOL_VIOLATION("client sent Retry").into()); -4040 } -4041 -4042 let is_valid_retry = self -4043 .rem_cids -4044 .get(&path_id) -4045 .map(|cids| cids.active()) -4046 .map(|orig_dst_cid| { -4047 self.crypto.is_valid_retry( -4048 orig_dst_cid, -4049 &packet.header_data, -4050 &packet.payload, -4051 ) -4052 }) -4053 .unwrap_or_default(); -4054 if self.total_authed_packets > 1 -4055 || packet.payload.len() <= 16 // token + 16 byte tag -4056 || !is_valid_retry -4057 { -4058 trace!("discarding invalid Retry"); -4059 // - After the client has received and processed an Initial or Retry -4060 // packet from the server, it MUST discard any subsequent Retry -4061 // packets that it receives. -4062 // - A client MUST discard a Retry packet with a zero-length Retry Token -4063 // field. -4064 // - Clients MUST discard Retry packets that have a Retry Integrity Tag -4065 // that cannot be validated -4066 return Ok(()); -4067 } -4068 -4069 trace!("retrying with CID {}", rem_cid); -4070 let client_hello = state.client_hello.take().unwrap(); -4071 self.retry_src_cid = Some(rem_cid); -4072 self.rem_cids -4073 .get_mut(&path_id) -4074 .expect("PathId::ZERO not yet abandoned, is_valid_retry would have been false") -4075 .update_initial_cid(rem_cid); -4076 self.rem_handshake_cid = rem_cid; -4077 -4078 let space = &mut self.spaces[SpaceId::Initial]; -4079 if let Some(info) = space.for_path(PathId::ZERO).take(0) { -4080 self.on_packet_acked(now, PathId::ZERO, info); -4081 }; -4082 -4083 self.discard_space(now, SpaceId::Initial); // Make sure we clean up after -4084 // any retransmitted Initials -4085 self.spaces[SpaceId::Initial] = { -4086 let mut space = PacketSpace::new(now, SpaceId::Initial, &mut self.rng); -4087 space.crypto = Some(self.crypto.initial_keys(rem_cid, self.side.side())); -4088 space.crypto_offset = client_hello.len() as u64; -4089 space.for_path(path_id).next_packet_number = self.spaces[SpaceId::Initial] -4090 .for_path(path_id) -4091 .next_packet_number; -4092 space.pending.crypto.push_back(frame::Crypto { -4093 offset: 0, -4094 data: client_hello, -4095 }); -4096 space -4097 }; -4098 -4099 // Retransmit all 0-RTT data -4100 let zero_rtt = mem::take( -4101 &mut self.spaces[SpaceId::Data] -4102 .for_path(PathId::ZERO) -4103 .sent_packets, -4104 ); -4105 for (_, info) in zero_rtt.into_iter() { -4106 self.paths -4107 .get_mut(&PathId::ZERO) -4108 .unwrap() -4109 .remove_in_flight(&info); -4110 self.spaces[SpaceId::Data].pending |= info.retransmits; +3647 Ok(()) +3648 } +3649 +3650 fn write_crypto(&mut self) { +3651 loop { +3652 let space = self.highest_space; +3653 let mut outgoing = Vec::new(); +3654 if let Some(crypto) = self.crypto.write_handshake(&mut outgoing) { +3655 match space { +3656 SpaceId::Initial => { +3657 self.upgrade_crypto(SpaceId::Handshake, crypto); +3658 } +3659 SpaceId::Handshake => { +3660 self.upgrade_crypto(SpaceId::Data, crypto); +3661 } +3662 _ => unreachable!("got updated secrets during 1-RTT"), +3663 } +3664 } +3665 if outgoing.is_empty() { +3666 if space == self.highest_space { +3667 break; +3668 } else { +3669 // Keys updated, check for more data to send +3670 continue; +3671 } +3672 } +3673 let offset = self.spaces[space].crypto_offset; +3674 let outgoing = Bytes::from(outgoing); +3675 if let Some(hs) = self.state.as_handshake_mut() +3676 && space == SpaceId::Initial +3677 && offset == 0 +3678 && self.side.is_client() +3679 { +3680 hs.client_hello = Some(outgoing.clone()); +3681 } +3682 self.spaces[space].crypto_offset += outgoing.len() as u64; +3683 trace!("wrote {} {:?} CRYPTO bytes", outgoing.len(), space); +3684 self.spaces[space].pending.crypto.push_back(frame::Crypto { +3685 offset, +3686 data: outgoing, +3687 }); +3688 } +3689 } +3690 +3691 /// Switch to stronger cryptography during handshake +3692 fn upgrade_crypto(&mut self, space: SpaceId, crypto: Keys) { +3693 debug_assert!( +3694 self.spaces[space].crypto.is_none(), +3695 "already reached packet space {space:?}" +3696 ); +3697 trace!("{:?} keys ready", space); +3698 if space == SpaceId::Data { +3699 // Precompute the first key update +3700 self.next_crypto = Some( +3701 self.crypto +3702 .next_1rtt_keys() +3703 .expect("handshake should be complete"), +3704 ); +3705 } +3706 +3707 self.spaces[space].crypto = Some(crypto); +3708 debug_assert!(space as usize > self.highest_space as usize); +3709 self.highest_space = space; +3710 if space == SpaceId::Data && self.side.is_client() { +3711 // Discard 0-RTT keys because 1-RTT keys are available. +3712 self.zero_rtt_crypto = None; +3713 } +3714 } +3715 +3716 fn discard_space(&mut self, now: Instant, space_id: SpaceId) { +3717 debug_assert!(space_id != SpaceId::Data); +3718 trace!("discarding {:?} keys", space_id); +3719 if space_id == SpaceId::Initial { +3720 // No longer needed +3721 if let ConnectionSide::Client { token, .. } = &mut self.side { +3722 *token = Bytes::new(); +3723 } +3724 } +3725 let space = &mut self.spaces[space_id]; +3726 space.crypto = None; +3727 let pns = space.for_path(PathId::ZERO); +3728 pns.time_of_last_ack_eliciting_packet = None; +3729 pns.loss_time = None; +3730 pns.loss_probes = 0; +3731 let sent_packets = mem::take(&mut pns.sent_packets); +3732 let path = self.paths.get_mut(&PathId::ZERO).unwrap(); +3733 for (_, packet) in sent_packets.into_iter() { +3734 path.data.remove_in_flight(&packet); +3735 } +3736 +3737 self.set_loss_detection_timer(now, PathId::ZERO) +3738 } +3739 +3740 fn handle_coalesced( +3741 &mut self, +3742 now: Instant, +3743 network_path: FourTuple, +3744 path_id: PathId, +3745 ecn: Option<EcnCodepoint>, +3746 data: BytesMut, +3747 ) { +3748 self.path_data_mut(path_id) +3749 .inc_total_recvd(data.len() as u64); +3750 let mut remaining = Some(data); +3751 let cid_len = self +3752 .local_cid_state +3753 .values() +3754 .map(|cid_state| cid_state.cid_len()) +3755 .next() +3756 .expect("one cid_state must exist"); +3757 while let Some(data) = remaining { +3758 match PartialDecode::new( +3759 data, +3760 &FixedLengthConnectionIdParser::new(cid_len), +3761 &[self.version], +3762 self.endpoint_config.grease_quic_bit, +3763 ) { +3764 Ok((partial_decode, rest)) => { +3765 remaining = rest; +3766 self.handle_decode(now, network_path, path_id, ecn, partial_decode); +3767 } +3768 Err(e) => { +3769 trace!("malformed header: {}", e); +3770 return; +3771 } +3772 } +3773 } +3774 } +3775 +3776 fn handle_decode( +3777 &mut self, +3778 now: Instant, +3779 network_path: FourTuple, +3780 path_id: PathId, +3781 ecn: Option<EcnCodepoint>, +3782 partial_decode: PartialDecode, +3783 ) { +3784 let qlog = QlogRecvPacket::new(partial_decode.len()); +3785 if let Some(decoded) = packet_crypto::unprotect_header( +3786 partial_decode, +3787 &self.spaces, +3788 self.zero_rtt_crypto.as_ref(), +3789 self.peer_params.stateless_reset_token, +3790 ) { +3791 self.handle_packet( +3792 now, +3793 network_path, +3794 path_id, +3795 ecn, +3796 decoded.packet, +3797 decoded.stateless_reset, +3798 qlog, +3799 ); +3800 } +3801 } +3802 +3803 fn handle_packet( +3804 &mut self, +3805 now: Instant, +3806 network_path: FourTuple, +3807 path_id: PathId, +3808 ecn: Option<EcnCodepoint>, +3809 packet: Option<Packet>, +3810 stateless_reset: bool, +3811 mut qlog: QlogRecvPacket, +3812 ) { +3813 self.stats.udp_rx.ios += 1; +3814 self.path_stats.entry(path_id).or_default().udp_rx.ios += 1; +3815 +3816 if let Some(ref packet) = packet { +3817 trace!( +3818 "got {:?} packet ({} bytes) from {} using id {}", +3819 packet.header.space(), +3820 packet.payload.len() + packet.header_data.len(), +3821 network_path, +3822 packet.header.dst_cid(), +3823 ); +3824 } +3825 +3826 if self.is_handshaking() { +3827 if path_id != PathId::ZERO { +3828 debug!(%network_path, %path_id, "discarding multipath packet during handshake"); +3829 return; +3830 } +3831 if network_path != self.path_data_mut(path_id).network_path { +3832 if let Some(hs) = self.state.as_handshake() { +3833 if hs.allow_server_migration { +3834 trace!(%network_path, prev = %self.path_data(path_id).network_path, "server migrated to new remote"); +3835 self.path_data_mut(path_id).network_path = network_path; +3836 self.qlog.emit_tuple_assigned(path_id, network_path, now); +3837 } else { +3838 debug!("discarding packet with unexpected remote during handshake"); +3839 return; +3840 } +3841 } else { +3842 debug!("discarding packet with unexpected remote during handshake"); +3843 return; +3844 } +3845 } +3846 } +3847 +3848 let was_closed = self.state.is_closed(); +3849 let was_drained = self.state.is_drained(); +3850 +3851 let decrypted = match packet { +3852 None => Err(None), +3853 Some(mut packet) => self +3854 .decrypt_packet(now, path_id, &mut packet) +3855 .map(move |number| (packet, number)), +3856 }; +3857 let result = match decrypted { +3858 _ if stateless_reset => { +3859 debug!("got stateless reset"); +3860 Err(ConnectionError::Reset) +3861 } +3862 Err(Some(e)) => { +3863 warn!("illegal packet: {}", e); +3864 Err(e.into()) +3865 } +3866 Err(None) => { +3867 debug!("failed to authenticate packet"); +3868 self.authentication_failures += 1; +3869 let integrity_limit = self.spaces[self.highest_space] +3870 .crypto +3871 .as_ref() +3872 .unwrap() +3873 .packet +3874 .local +3875 .integrity_limit(); +3876 if self.authentication_failures > integrity_limit { +3877 Err(TransportError::AEAD_LIMIT_REACHED("integrity limit violated").into()) +3878 } else { +3879 return; +3880 } +3881 } +3882 Ok((packet, number)) => { +3883 qlog.header(&packet.header, number, path_id); +3884 let span = match number { +3885 Some(pn) => trace_span!("recv", space = ?packet.header.space(), pn), +3886 None => trace_span!("recv", space = ?packet.header.space()), +3887 }; +3888 let _guard = span.enter(); +3889 +3890 let dedup = self.spaces[packet.header.space()] +3891 .path_space_mut(path_id) +3892 .map(|pns| &mut pns.dedup); +3893 if number.zip(dedup).is_some_and(|(n, d)| d.insert(n)) { +3894 debug!("discarding possible duplicate packet"); +3895 self.qlog.emit_packet_received(qlog, now); +3896 return; +3897 } else if self.state.is_handshake() && packet.header.is_short() { +3898 // TODO: SHOULD buffer these to improve reordering tolerance. +3899 trace!("dropping short packet during handshake"); +3900 self.qlog.emit_packet_received(qlog, now); +3901 return; +3902 } else { +3903 if let Header::Initial(InitialHeader { ref token, .. }) = packet.header +3904 && let Some(hs) = self.state.as_handshake() +3905 && self.side.is_server() +3906 && token != &hs.expected_token +3907 { +3908 // Clients must send the same retry token in every Initial. Initial +3909 // packets can be spoofed, so we discard rather than killing the +3910 // connection. +3911 warn!("discarding Initial with invalid retry token"); +3912 self.qlog.emit_packet_received(qlog, now); +3913 return; +3914 } +3915 +3916 if !self.state.is_closed() { +3917 let spin = match packet.header { +3918 Header::Short { spin, .. } => spin, +3919 _ => false, +3920 }; +3921 +3922 if self.side().is_server() && !self.abandoned_paths.contains(&path_id) { +3923 // Only the client is allowed to open paths +3924 self.ensure_path(path_id, network_path, now, number); +3925 } +3926 if self.paths.contains_key(&path_id) { +3927 self.on_packet_authenticated( +3928 now, +3929 packet.header.space(), +3930 path_id, +3931 ecn, +3932 number, +3933 spin, +3934 packet.header.is_1rtt(), +3935 ); +3936 } +3937 } +3938 +3939 let res = self.process_decrypted_packet( +3940 now, +3941 network_path, +3942 path_id, +3943 number, +3944 packet, +3945 &mut qlog, +3946 ); +3947 +3948 self.qlog.emit_packet_received(qlog, now); +3949 res +3950 } +3951 } +3952 }; +3953 +3954 // State transitions for error cases +3955 if let Err(conn_err) = result { +3956 match conn_err { +3957 ConnectionError::ApplicationClosed(reason) => self.state.move_to_closed(reason), +3958 ConnectionError::ConnectionClosed(reason) => self.state.move_to_closed(reason), +3959 ConnectionError::Reset +3960 | ConnectionError::TransportError(TransportError { +3961 code: TransportErrorCode::AEAD_LIMIT_REACHED, +3962 .. +3963 }) => { +3964 self.state.move_to_drained(Some(conn_err)); +3965 } +3966 ConnectionError::TimedOut => { +3967 unreachable!("timeouts aren't generated by packet processing"); +3968 } +3969 ConnectionError::TransportError(err) => { +3970 debug!("closing connection due to transport error: {}", err); +3971 self.state.move_to_closed(err); +3972 } +3973 ConnectionError::VersionMismatch => { +3974 self.state.move_to_draining(Some(conn_err)); +3975 } +3976 ConnectionError::LocallyClosed => { +3977 unreachable!("LocallyClosed isn't generated by packet processing"); +3978 } +3979 ConnectionError::CidsExhausted => { +3980 unreachable!("CidsExhausted isn't generated by packet processing"); +3981 } +3982 }; +3983 } +3984 +3985 if !was_closed && self.state.is_closed() { +3986 self.close_common(); +3987 if !self.state.is_drained() { +3988 self.set_close_timer(now); +3989 } +3990 } +3991 if !was_drained && self.state.is_drained() { +3992 self.endpoint_events.push_back(EndpointEventInner::Drained); +3993 // Close timer may have been started previously, e.g. if we sent a close and got a +3994 // stateless reset in response +3995 self.timers +3996 .stop(Timer::Conn(ConnTimer::Close), self.qlog.with_time(now)); +3997 } +3998 +3999 // Transmit CONNECTION_CLOSE if necessary +4000 if matches!(self.state.as_type(), StateType::Closed) { +4001 // If there is no PathData for this PathId the packet was for a brand new +4002 // path. It was a valid packet however, so the remote is valid and we want to +4003 // send CONNECTION_CLOSE. +4004 let path_remote = self +4005 .paths +4006 .get(&path_id) +4007 .map(|p| p.data.network_path) +4008 .unwrap_or(network_path); +4009 self.connection_close_pending = network_path == path_remote; +4010 } +4011 } +4012 +4013 fn process_decrypted_packet( +4014 &mut self, +4015 now: Instant, +4016 network_path: FourTuple, +4017 path_id: PathId, +4018 number: Option<u64>, +4019 packet: Packet, +4020 qlog: &mut QlogRecvPacket, +4021 ) -> Result<(), ConnectionError> { +4022 if !self.paths.contains_key(&path_id) { +4023 // There is a chance this is a server side, first (for this path) packet, which would +4024 // be a protocol violation. It's more likely, however, that this is a packet of a +4025 // pruned path +4026 trace!(%path_id, ?number, "discarding packet for unknown path"); +4027 return Ok(()); +4028 } +4029 let state = match self.state.as_type() { +4030 StateType::Established => { +4031 match packet.header.space() { +4032 SpaceId::Data => self.process_payload( +4033 now, +4034 network_path, +4035 path_id, +4036 number.unwrap(), +4037 packet, +4038 qlog, +4039 )?, +4040 _ if packet.header.has_frames() => { +4041 self.process_early_payload(now, path_id, packet, qlog)? +4042 } +4043 _ => { +4044 trace!("discarding unexpected pre-handshake packet"); +4045 } +4046 } +4047 return Ok(()); +4048 } +4049 StateType::Closed => { +4050 for result in frame::Iter::new(packet.payload.freeze())? { +4051 let frame = match result { +4052 Ok(frame) => frame, +4053 Err(err) => { +4054 debug!("frame decoding error: {err:?}"); +4055 continue; +4056 } +4057 }; +4058 qlog.frame(&frame); +4059 +4060 if let Frame::Padding = frame { +4061 continue; +4062 }; +4063 +4064 self.stats.frame_rx.record(frame.ty()); +4065 +4066 if let Frame::Close(_error) = frame { +4067 self.state.move_to_draining(None); +4068 break; +4069 } +4070 } +4071 return Ok(()); +4072 } +4073 StateType::Draining | StateType::Drained => return Ok(()), +4074 StateType::Handshake => self.state.as_handshake_mut().expect("checked"), +4075 }; +4076 +4077 match packet.header { +4078 Header::Retry { +4079 src_cid: rem_cid, .. +4080 } => { +4081 debug_assert_eq!(path_id, PathId::ZERO); +4082 if self.side.is_server() { +4083 return Err(TransportError::PROTOCOL_VIOLATION("client sent Retry").into()); +4084 } +4085 +4086 let is_valid_retry = self +4087 .rem_cids +4088 .get(&path_id) +4089 .map(|cids| cids.active()) +4090 .map(|orig_dst_cid| { +4091 self.crypto.is_valid_retry( +4092 orig_dst_cid, +4093 &packet.header_data, +4094 &packet.payload, +4095 ) +4096 }) +4097 .unwrap_or_default(); +4098 if self.total_authed_packets > 1 +4099 || packet.payload.len() <= 16 // token + 16 byte tag +4100 || !is_valid_retry +4101 { +4102 trace!("discarding invalid Retry"); +4103 // - After the client has received and processed an Initial or Retry +4104 // packet from the server, it MUST discard any subsequent Retry +4105 // packets that it receives. +4106 // - A client MUST discard a Retry packet with a zero-length Retry Token +4107 // field. +4108 // - Clients MUST discard Retry packets that have a Retry Integrity Tag +4109 // that cannot be validated +4110 return Ok(()); 4111 } -4112 self.streams.retransmit_all_for_0rtt(); -4113 -4114 let token_len = packet.payload.len() - 16; -4115 let ConnectionSide::Client { ref mut token, .. } = self.side else { -4116 unreachable!("we already short-circuited if we're server"); -4117 }; -4118 *token = packet.payload.freeze().split_to(token_len); -4119 -4120 self.state = State::handshake(state::Handshake { -4121 expected_token: Bytes::new(), -4122 rem_cid_set: false, -4123 client_hello: None, -4124 allow_server_migration: true, -4125 }); -4126 Ok(()) -4127 } -4128 Header::Long { -4129 ty: LongType::Handshake, -4130 src_cid: rem_cid, -4131 dst_cid: loc_cid, -4132 .. -4133 } => { -4134 debug_assert_eq!(path_id, PathId::ZERO); -4135 if rem_cid != self.rem_handshake_cid { -4136 debug!( -4137 "discarding packet with mismatched remote CID: {} != {}", -4138 self.rem_handshake_cid, rem_cid -4139 ); -4140 return Ok(()); -4141 } -4142 self.on_path_validated(path_id); -4143 -4144 self.process_early_payload(now, path_id, packet, qlog)?; -4145 if self.state.is_closed() { -4146 return Ok(()); -4147 } -4148 -4149 if self.crypto.is_handshaking() { -4150 trace!("handshake ongoing"); -4151 return Ok(()); -4152 } -4153 -4154 if self.side.is_client() { -4155 // Client-only because server params were set from the client's Initial -4156 let params = self.crypto.transport_parameters()?.ok_or_else(|| { -4157 TransportError::new( -4158 TransportErrorCode::crypto(0x6d), -4159 "transport parameters missing".to_owned(), -4160 ) -4161 })?; -4162 -4163 if self.has_0rtt() { -4164 if !self.crypto.early_data_accepted().unwrap() { -4165 debug_assert!(self.side.is_client()); -4166 debug!("0-RTT rejected"); -4167 self.accepted_0rtt = false; -4168 self.streams.zero_rtt_rejected(); -4169 -4170 // Discard already-queued frames -4171 self.spaces[SpaceId::Data].pending = Retransmits::default(); -4172 -4173 // Discard 0-RTT packets -4174 let sent_packets = mem::take( -4175 &mut self.spaces[SpaceId::Data].for_path(path_id).sent_packets, -4176 ); -4177 for (_, packet) in sent_packets.into_iter() { -4178 self.paths -4179 .get_mut(&path_id) -4180 .unwrap() -4181 .remove_in_flight(&packet); -4182 } -4183 } else { -4184 self.accepted_0rtt = true; -4185 params.validate_resumption_from(&self.peer_params)?; -4186 } -4187 } -4188 if let Some(token) = params.stateless_reset_token { -4189 // TODO(matheus23): Reset token for a remote, or for a 4-tuple? -4190 let remote = self.path_data(path_id).network_path.remote; -4191 self.endpoint_events -4192 .push_back(EndpointEventInner::ResetToken(path_id, remote, token)); -4193 } -4194 self.handle_peer_params(params, loc_cid, rem_cid, now)?; -4195 self.issue_first_cids(now); -4196 } else { -4197 // Server-only -4198 self.spaces[SpaceId::Data].pending.handshake_done = true; -4199 self.discard_space(now, SpaceId::Handshake); -4200 self.events.push_back(Event::HandshakeConfirmed); -4201 trace!("handshake confirmed"); -4202 } -4203 -4204 self.events.push_back(Event::Connected); -4205 self.state.move_to_established(); -4206 trace!("established"); -4207 -4208 // Multipath can only be enabled after the state has reached Established. -4209 // So this can not happen any earlier. -4210 self.issue_first_path_cids(now); -4211 Ok(()) -4212 } -4213 Header::Initial(InitialHeader { -4214 src_cid: rem_cid, -4215 dst_cid: loc_cid, -4216 .. -4217 }) => { -4218 debug_assert_eq!(path_id, PathId::ZERO); -4219 if !state.rem_cid_set { -4220 trace!("switching remote CID to {}", rem_cid); -4221 let mut state = state.clone(); -4222 self.rem_cids -4223 .get_mut(&path_id) -4224 .expect("PathId::ZERO not yet abandoned") -4225 .update_initial_cid(rem_cid); -4226 self.rem_handshake_cid = rem_cid; -4227 self.orig_rem_cid = rem_cid; -4228 state.rem_cid_set = true; -4229 self.state.move_to_handshake(state); -4230 } else if rem_cid != self.rem_handshake_cid { -4231 debug!( -4232 "discarding packet with mismatched remote CID: {} != {}", -4233 self.rem_handshake_cid, rem_cid -4234 ); -4235 return Ok(()); -4236 } -4237 -4238 let starting_space = self.highest_space; -4239 self.process_early_payload(now, path_id, packet, qlog)?; -4240 -4241 if self.side.is_server() -4242 && starting_space == SpaceId::Initial -4243 && self.highest_space != SpaceId::Initial -4244 { -4245 let params = self.crypto.transport_parameters()?.ok_or_else(|| { -4246 TransportError::new( -4247 TransportErrorCode::crypto(0x6d), -4248 "transport parameters missing".to_owned(), -4249 ) -4250 })?; -4251 self.handle_peer_params(params, loc_cid, rem_cid, now)?; -4252 self.issue_first_cids(now); -4253 self.init_0rtt(now); -4254 } +4112 +4113 trace!("retrying with CID {}", rem_cid); +4114 let client_hello = state.client_hello.take().unwrap(); +4115 self.retry_src_cid = Some(rem_cid); +4116 self.rem_cids +4117 .get_mut(&path_id) +4118 .expect("PathId::ZERO not yet abandoned, is_valid_retry would have been false") +4119 .update_initial_cid(rem_cid); +4120 self.rem_handshake_cid = rem_cid; +4121 +4122 let space = &mut self.spaces[SpaceId::Initial]; +4123 if let Some(info) = space.for_path(PathId::ZERO).take(0) { +4124 self.on_packet_acked(now, PathId::ZERO, info); +4125 }; +4126 +4127 self.discard_space(now, SpaceId::Initial); // Make sure we clean up after +4128 // any retransmitted Initials +4129 self.spaces[SpaceId::Initial] = { +4130 let mut space = PacketSpace::new(now, SpaceId::Initial, &mut self.rng); +4131 space.crypto = Some(self.crypto.initial_keys(rem_cid, self.side.side())); +4132 space.crypto_offset = client_hello.len() as u64; +4133 space.for_path(path_id).next_packet_number = self.spaces[SpaceId::Initial] +4134 .for_path(path_id) +4135 .next_packet_number; +4136 space.pending.crypto.push_back(frame::Crypto { +4137 offset: 0, +4138 data: client_hello, +4139 }); +4140 space +4141 }; +4142 +4143 // Retransmit all 0-RTT data +4144 let zero_rtt = mem::take( +4145 &mut self.spaces[SpaceId::Data] +4146 .for_path(PathId::ZERO) +4147 .sent_packets, +4148 ); +4149 for (_, info) in zero_rtt.into_iter() { +4150 self.paths +4151 .get_mut(&PathId::ZERO) +4152 .unwrap() +4153 .remove_in_flight(&info); +4154 self.spaces[SpaceId::Data].pending |= info.retransmits; +4155 } +4156 self.streams.retransmit_all_for_0rtt(); +4157 +4158 let token_len = packet.payload.len() - 16; +4159 let ConnectionSide::Client { ref mut token, .. } = self.side else { +4160 unreachable!("we already short-circuited if we're server"); +4161 }; +4162 *token = packet.payload.freeze().split_to(token_len); +4163 +4164 self.state = State::handshake(state::Handshake { +4165 expected_token: Bytes::new(), +4166 rem_cid_set: false, +4167 client_hello: None, +4168 allow_server_migration: true, +4169 }); +4170 Ok(()) +4171 } +4172 Header::Long { +4173 ty: LongType::Handshake, +4174 src_cid: rem_cid, +4175 dst_cid: loc_cid, +4176 .. +4177 } => { +4178 debug_assert_eq!(path_id, PathId::ZERO); +4179 if rem_cid != self.rem_handshake_cid { +4180 debug!( +4181 "discarding packet with mismatched remote CID: {} != {}", +4182 self.rem_handshake_cid, rem_cid +4183 ); +4184 return Ok(()); +4185 } +4186 self.on_path_validated(path_id); +4187 +4188 self.process_early_payload(now, path_id, packet, qlog)?; +4189 if self.state.is_closed() { +4190 return Ok(()); +4191 } +4192 +4193 if self.crypto.is_handshaking() { +4194 trace!("handshake ongoing"); +4195 return Ok(()); +4196 } +4197 +4198 if self.side.is_client() { +4199 // Client-only because server params were set from the client's Initial +4200 let params = self.crypto.transport_parameters()?.ok_or_else(|| { +4201 TransportError::new( +4202 TransportErrorCode::crypto(0x6d), +4203 "transport parameters missing".to_owned(), +4204 ) +4205 })?; +4206 +4207 if self.has_0rtt() { +4208 if !self.crypto.early_data_accepted().unwrap() { +4209 debug_assert!(self.side.is_client()); +4210 debug!("0-RTT rejected"); +4211 self.accepted_0rtt = false; +4212 self.streams.zero_rtt_rejected(); +4213 +4214 // Discard already-queued frames +4215 self.spaces[SpaceId::Data].pending = Retransmits::default(); +4216 +4217 // Discard 0-RTT packets +4218 let sent_packets = mem::take( +4219 &mut self.spaces[SpaceId::Data].for_path(path_id).sent_packets, +4220 ); +4221 for (_, packet) in sent_packets.into_iter() { +4222 self.paths +4223 .get_mut(&path_id) +4224 .unwrap() +4225 .remove_in_flight(&packet); +4226 } +4227 } else { +4228 self.accepted_0rtt = true; +4229 params.validate_resumption_from(&self.peer_params)?; +4230 } +4231 } +4232 if let Some(token) = params.stateless_reset_token { +4233 // TODO(matheus23): Reset token for a remote, or for a 4-tuple? +4234 let remote = self.path_data(path_id).network_path.remote; +4235 self.endpoint_events +4236 .push_back(EndpointEventInner::ResetToken(path_id, remote, token)); +4237 } +4238 self.handle_peer_params(params, loc_cid, rem_cid, now)?; +4239 self.issue_first_cids(now); +4240 } else { +4241 // Server-only +4242 self.spaces[SpaceId::Data].pending.handshake_done = true; +4243 self.discard_space(now, SpaceId::Handshake); +4244 self.events.push_back(Event::HandshakeConfirmed); +4245 trace!("handshake confirmed"); +4246 } +4247 +4248 self.events.push_back(Event::Connected); +4249 self.state.move_to_established(); +4250 trace!("established"); +4251 +4252 // Multipath can only be enabled after the state has reached Established. +4253 // So this can not happen any earlier. +4254 self.issue_first_path_cids(now); 4255 Ok(()) 4256 } -4257 Header::Long { -4258 ty: LongType::ZeroRtt, -4259 .. -4260 } => { -4261 self.process_payload(now, network_path, path_id, number.unwrap(), packet, qlog)?; -4262 Ok(()) -4263 } -4264 Header::VersionNegotiate { .. } => { -4265 if self.total_authed_packets > 1 { -4266 return Ok(()); -4267 } -4268 let supported = packet -4269 .payload -4270 .chunks(4) -4271 .any(|x| match <[u8; 4]>::try_from(x) { -4272 Ok(version) => self.version == u32::from_be_bytes(version), -4273 Err(_) => false, -4274 }); -4275 if supported { -4276 return Ok(()); -4277 } -4278 debug!("remote doesn't support our version"); -4279 Err(ConnectionError::VersionMismatch) -4280 } -4281 Header::Short { .. } => unreachable!( -4282 "short packets received during handshake are discarded in handle_packet" -4283 ), -4284 } -4285 } -4286 -4287 /// Process an Initial or Handshake packet payload -4288 fn process_early_payload( -4289 &mut self, -4290 now: Instant, -4291 path_id: PathId, -4292 packet: Packet, -4293 #[allow(unused)] qlog: &mut QlogRecvPacket, -4294 ) -> Result<(), TransportError> { -4295 debug_assert_ne!(packet.header.space(), SpaceId::Data); -4296 debug_assert_eq!(path_id, PathId::ZERO); -4297 let payload_len = packet.payload.len(); -4298 let mut ack_eliciting = false; -4299 for result in frame::Iter::new(packet.payload.freeze())? { -4300 let frame = result?; -4301 qlog.frame(&frame); -4302 let span = match frame { -4303 Frame::Padding => continue, -4304 _ => Some(trace_span!("frame", ty = %frame.ty(), path = tracing::field::Empty)), -4305 }; -4306 -4307 self.stats.frame_rx.record(frame.ty()); -4308 -4309 let _guard = span.as_ref().map(|x| x.enter()); -4310 ack_eliciting |= frame.is_ack_eliciting(); -4311 -4312 // Process frames -4313 if frame.is_1rtt() && packet.header.space() != SpaceId::Data { -4314 return Err(TransportError::PROTOCOL_VIOLATION( -4315 "illegal frame type in handshake", -4316 )); -4317 } -4318 -4319 match frame { -4320 Frame::Padding | Frame::Ping => {} -4321 Frame::Crypto(frame) => { -4322 self.read_crypto(packet.header.space(), &frame, payload_len)?; -4323 } -4324 Frame::Ack(ack) => { -4325 self.on_ack_received(now, packet.header.space(), ack)?; -4326 } -4327 Frame::PathAck(ack) => { -4328 span.as_ref() -4329 .map(|span| span.record("path", tracing::field::debug(&ack.path_id))); -4330 self.on_path_ack_received(now, packet.header.space(), ack)?; -4331 } -4332 Frame::Close(reason) => { -4333 self.state.move_to_draining(Some(reason.into())); -4334 return Ok(()); -4335 } -4336 _ => { -4337 let mut err = -4338 TransportError::PROTOCOL_VIOLATION("illegal frame type in handshake"); -4339 err.frame = frame::MaybeFrame::Known(frame.ty()); -4340 return Err(err); -4341 } -4342 } -4343 } -4344 -4345 if ack_eliciting { -4346 // In the initial and handshake spaces, ACKs must be sent immediately -4347 self.spaces[packet.header.space()] -4348 .for_path(path_id) -4349 .pending_acks -4350 .set_immediate_ack_required(); -4351 } +4257 Header::Initial(InitialHeader { +4258 src_cid: rem_cid, +4259 dst_cid: loc_cid, +4260 .. +4261 }) => { +4262 debug_assert_eq!(path_id, PathId::ZERO); +4263 if !state.rem_cid_set { +4264 trace!("switching remote CID to {}", rem_cid); +4265 let mut state = state.clone(); +4266 self.rem_cids +4267 .get_mut(&path_id) +4268 .expect("PathId::ZERO not yet abandoned") +4269 .update_initial_cid(rem_cid); +4270 self.rem_handshake_cid = rem_cid; +4271 self.orig_rem_cid = rem_cid; +4272 state.rem_cid_set = true; +4273 self.state.move_to_handshake(state); +4274 } else if rem_cid != self.rem_handshake_cid { +4275 debug!( +4276 "discarding packet with mismatched remote CID: {} != {}", +4277 self.rem_handshake_cid, rem_cid +4278 ); +4279 return Ok(()); +4280 } +4281 +4282 let starting_space = self.highest_space; +4283 self.process_early_payload(now, path_id, packet, qlog)?; +4284 +4285 if self.side.is_server() +4286 && starting_space == SpaceId::Initial +4287 && self.highest_space != SpaceId::Initial +4288 { +4289 let params = self.crypto.transport_parameters()?.ok_or_else(|| { +4290 TransportError::new( +4291 TransportErrorCode::crypto(0x6d), +4292 "transport parameters missing".to_owned(), +4293 ) +4294 })?; +4295 self.handle_peer_params(params, loc_cid, rem_cid, now)?; +4296 self.issue_first_cids(now); +4297 self.init_0rtt(now); +4298 } +4299 Ok(()) +4300 } +4301 Header::Long { +4302 ty: LongType::ZeroRtt, +4303 .. +4304 } => { +4305 self.process_payload(now, network_path, path_id, number.unwrap(), packet, qlog)?; +4306 Ok(()) +4307 } +4308 Header::VersionNegotiate { .. } => { +4309 if self.total_authed_packets > 1 { +4310 return Ok(()); +4311 } +4312 let supported = packet +4313 .payload +4314 .chunks(4) +4315 .any(|x| match <[u8; 4]>::try_from(x) { +4316 Ok(version) => self.version == u32::from_be_bytes(version), +4317 Err(_) => false, +4318 }); +4319 if supported { +4320 return Ok(()); +4321 } +4322 debug!("remote doesn't support our version"); +4323 Err(ConnectionError::VersionMismatch) +4324 } +4325 Header::Short { .. } => unreachable!( +4326 "short packets received during handshake are discarded in handle_packet" +4327 ), +4328 } +4329 } +4330 +4331 /// Process an Initial or Handshake packet payload +4332 fn process_early_payload( +4333 &mut self, +4334 now: Instant, +4335 path_id: PathId, +4336 packet: Packet, +4337 #[allow(unused)] qlog: &mut QlogRecvPacket, +4338 ) -> Result<(), TransportError> { +4339 debug_assert_ne!(packet.header.space(), SpaceId::Data); +4340 debug_assert_eq!(path_id, PathId::ZERO); +4341 let payload_len = packet.payload.len(); +4342 let mut ack_eliciting = false; +4343 for result in frame::Iter::new(packet.payload.freeze())? { +4344 let frame = result?; +4345 qlog.frame(&frame); +4346 let span = match frame { +4347 Frame::Padding => continue, +4348 _ => Some(trace_span!("frame", ty = %frame.ty(), path = tracing::field::Empty)), +4349 }; +4350 +4351 self.stats.frame_rx.record(frame.ty()); 4352 -4353 self.write_crypto(); -4354 Ok(()) -4355 } -4356 -4357 /// Processes the packet payload, always in the data space. -4358 fn process_payload( -4359 &mut self, -4360 now: Instant, -4361 network_path: FourTuple, -4362 path_id: PathId, -4363 number: u64, -4364 packet: Packet, -4365 #[allow(unused)] qlog: &mut QlogRecvPacket, -4366 ) -> Result<(), TransportError> { -4367 let payload = packet.payload.freeze(); -4368 let mut is_probing_packet = true; -4369 let mut close = None; -4370 let payload_len = payload.len(); -4371 let mut ack_eliciting = false; -4372 // if this packet triggers a path migration and includes a observed address frame, it's -4373 // stored here -4374 let mut migration_observed_addr = None; -4375 for result in frame::Iter::new(payload)? { -4376 let frame = result?; -4377 qlog.frame(&frame); -4378 let span = match frame { -4379 Frame::Padding => continue, -4380 _ => trace_span!("frame", ty = %frame.ty(), path = tracing::field::Empty), -4381 }; -4382 -4383 self.stats.frame_rx.record(frame.ty()); -4384 // Crypto, Stream and Datagram frames are special cased in order no pollute -4385 // the log with payload data -4386 match &frame { -4387 Frame::Crypto(f) => { -4388 trace!(offset = f.offset, len = f.data.len(), "got frame CRYPTO"); -4389 } -4390 Frame::Stream(f) => { -4391 trace!(id = %f.id, offset = f.offset, len = f.data.len(), fin = f.fin, "got frame STREAM"); -4392 } -4393 Frame::Datagram(f) => { -4394 trace!(len = f.data.len(), "got frame DATAGRAM"); -4395 } -4396 f => { -4397 trace!("got frame {f}"); -4398 } -4399 } +4353 let _guard = span.as_ref().map(|x| x.enter()); +4354 ack_eliciting |= frame.is_ack_eliciting(); +4355 +4356 // Process frames +4357 if frame.is_1rtt() && packet.header.space() != SpaceId::Data { +4358 return Err(TransportError::PROTOCOL_VIOLATION( +4359 "illegal frame type in handshake", +4360 )); +4361 } +4362 +4363 match frame { +4364 Frame::Padding | Frame::Ping => {} +4365 Frame::Crypto(frame) => { +4366 self.read_crypto(packet.header.space(), &frame, payload_len)?; +4367 } +4368 Frame::Ack(ack) => { +4369 self.on_ack_received(now, packet.header.space(), ack)?; +4370 } +4371 Frame::PathAck(ack) => { +4372 span.as_ref() +4373 .map(|span| span.record("path", tracing::field::debug(&ack.path_id))); +4374 self.on_path_ack_received(now, packet.header.space(), ack)?; +4375 } +4376 Frame::Close(reason) => { +4377 self.state.move_to_draining(Some(reason.into())); +4378 return Ok(()); +4379 } +4380 _ => { +4381 let mut err = +4382 TransportError::PROTOCOL_VIOLATION("illegal frame type in handshake"); +4383 err.frame = frame::MaybeFrame::Known(frame.ty()); +4384 return Err(err); +4385 } +4386 } +4387 } +4388 +4389 if ack_eliciting { +4390 // In the initial and handshake spaces, ACKs must be sent immediately +4391 self.spaces[packet.header.space()] +4392 .for_path(path_id) +4393 .pending_acks +4394 .set_immediate_ack_required(); +4395 } +4396 +4397 self.write_crypto(); +4398 Ok(()) +4399 } 4400 -4401 let _guard = span.enter(); -4402 if packet.header.is_0rtt() { -4403 match frame { -4404 Frame::Crypto(_) | Frame::Close(Close::Application(_)) => { -4405 return Err(TransportError::PROTOCOL_VIOLATION( -4406 "illegal frame type in 0-RTT", -4407 )); -4408 } -4409 _ => { -4410 if frame.is_1rtt() { -4411 return Err(TransportError::PROTOCOL_VIOLATION( -4412 "illegal frame type in 0-RTT", -4413 )); -4414 } -4415 } -4416 } -4417 } -4418 ack_eliciting |= frame.is_ack_eliciting(); -4419 -4420 // Check whether this could be a probing packet -4421 match frame { -4422 Frame::Padding -4423 | Frame::PathChallenge(_) -4424 | Frame::PathResponse(_) -4425 | Frame::NewConnectionId(_) -4426 | Frame::ObservedAddr(_) => {} -4427 _ => { -4428 is_probing_packet = false; -4429 } -4430 } -4431 -4432 match frame { -4433 Frame::Crypto(frame) => { -4434 self.read_crypto(SpaceId::Data, &frame, payload_len)?; -4435 } -4436 Frame::Stream(frame) => { -4437 if self.streams.received(frame, payload_len)?.should_transmit() { -4438 self.spaces[SpaceId::Data].pending.max_data = true; -4439 } -4440 } -4441 Frame::Ack(ack) => { -4442 self.on_ack_received(now, SpaceId::Data, ack)?; -4443 } -4444 Frame::PathAck(ack) => { -4445 span.record("path", tracing::field::debug(&ack.path_id)); -4446 self.on_path_ack_received(now, SpaceId::Data, ack)?; -4447 } -4448 Frame::Padding | Frame::Ping => {} -4449 Frame::Close(reason) => { -4450 close = Some(reason); -4451 } -4452 Frame::PathChallenge(challenge) => { -4453 let path = &mut self -4454 .path_mut(path_id) -4455 .expect("payload is processed only after the path becomes known"); -4456 path.path_responses.push(number, challenge.0, network_path); -4457 // At this point, update_network_path_or_discard was already called, so -4458 // we don't need to be lenient about `local_ip` possibly mis-matching. -4459 if network_path == path.network_path { -4460 // PATH_CHALLENGE on active path, possible off-path packet forwarding -4461 // attack. Send a non-probing packet to recover the active path. -4462 // TODO(flub): No longer true! We now path_challege also to validate -4463 // the path if the path is new, without an RFC9000-style -4464 // migration involved. This means we add in an extra -4465 // IMMEDIATE_ACK on some challenges. It isn't really wrong to do -4466 // so, but it still is something untidy. We should instead -4467 // suppress this when we know the remote is still validating the -4468 // path. -4469 match self.peer_supports_ack_frequency() { -4470 true => self.immediate_ack(path_id), -4471 false => { -4472 self.ping_path(path_id).ok(); -4473 } -4474 } -4475 } -4476 } -4477 Frame::PathResponse(response) => { -4478 let path = self -4479 .paths -4480 .get_mut(&path_id) -4481 .expect("payload is processed only after the path becomes known"); -4482 -4483 use PathTimer::*; -4484 use paths::OnPathResponseReceived::*; -4485 match path -4486 .data -4487 .on_path_response_received(now, response.0, network_path) -4488 { -4489 OnPath { was_open } => { -4490 let qlog = self.qlog.with_time(now); -4491 -4492 self.timers -4493 .stop(Timer::PerPath(path_id, PathValidation), qlog.clone()); -4494 self.timers -4495 .stop(Timer::PerPath(path_id, PathOpen), qlog.clone()); -4496 -4497 let next_challenge = path -4498 .data -4499 .earliest_expiring_challenge() -4500 .map(|time| time + self.ack_frequency.max_ack_delay_for_pto()); -4501 self.timers.set_or_stop( -4502 Timer::PerPath(path_id, PathChallengeLost), -4503 next_challenge, -4504 qlog, -4505 ); -4506 -4507 if !was_open { -4508 self.events -4509 .push_back(Event::Path(PathEvent::Opened { id: path_id })); -4510 if let Some(observed) = path.data.last_observed_addr_report.as_ref() -4511 { -4512 self.events.push_back(Event::Path(PathEvent::ObservedAddr { -4513 id: path_id, -4514 addr: observed.socket_addr(), -4515 })); -4516 } +4401 /// Processes the packet payload, always in the data space. +4402 fn process_payload( +4403 &mut self, +4404 now: Instant, +4405 network_path: FourTuple, +4406 path_id: PathId, +4407 number: u64, +4408 packet: Packet, +4409 #[allow(unused)] qlog: &mut QlogRecvPacket, +4410 ) -> Result<(), TransportError> { +4411 let payload = packet.payload.freeze(); +4412 let mut is_probing_packet = true; +4413 let mut close = None; +4414 let payload_len = payload.len(); +4415 let mut ack_eliciting = false; +4416 // if this packet triggers a path migration and includes a observed address frame, it's +4417 // stored here +4418 let mut migration_observed_addr = None; +4419 for result in frame::Iter::new(payload)? { +4420 let frame = result?; +4421 qlog.frame(&frame); +4422 let span = match frame { +4423 Frame::Padding => continue, +4424 _ => trace_span!("frame", ty = %frame.ty(), path = tracing::field::Empty), +4425 }; +4426 +4427 self.stats.frame_rx.record(frame.ty()); +4428 // Crypto, Stream and Datagram frames are special cased in order no pollute +4429 // the log with payload data +4430 match &frame { +4431 Frame::Crypto(f) => { +4432 trace!(offset = f.offset, len = f.data.len(), "got frame CRYPTO"); +4433 } +4434 Frame::Stream(f) => { +4435 trace!(id = %f.id, offset = f.offset, len = f.data.len(), fin = f.fin, "got frame STREAM"); +4436 } +4437 Frame::Datagram(f) => { +4438 trace!(len = f.data.len(), "got frame DATAGRAM"); +4439 } +4440 f => { +4441 trace!("got frame {f}"); +4442 } +4443 } +4444 +4445 let _guard = span.enter(); +4446 if packet.header.is_0rtt() { +4447 match frame { +4448 Frame::Crypto(_) | Frame::Close(Close::Application(_)) => { +4449 return Err(TransportError::PROTOCOL_VIOLATION( +4450 "illegal frame type in 0-RTT", +4451 )); +4452 } +4453 _ => { +4454 if frame.is_1rtt() { +4455 return Err(TransportError::PROTOCOL_VIOLATION( +4456 "illegal frame type in 0-RTT", +4457 )); +4458 } +4459 } +4460 } +4461 } +4462 ack_eliciting |= frame.is_ack_eliciting(); +4463 +4464 // Check whether this could be a probing packet +4465 match frame { +4466 Frame::Padding +4467 | Frame::PathChallenge(_) +4468 | Frame::PathResponse(_) +4469 | Frame::NewConnectionId(_) +4470 | Frame::ObservedAddr(_) => {} +4471 _ => { +4472 is_probing_packet = false; +4473 } +4474 } +4475 +4476 match frame { +4477 Frame::Crypto(frame) => { +4478 self.read_crypto(SpaceId::Data, &frame, payload_len)?; +4479 } +4480 Frame::Stream(frame) => { +4481 if self.streams.received(frame, payload_len)?.should_transmit() { +4482 self.spaces[SpaceId::Data].pending.max_data = true; +4483 } +4484 } +4485 Frame::Ack(ack) => { +4486 self.on_ack_received(now, SpaceId::Data, ack)?; +4487 } +4488 Frame::PathAck(ack) => { +4489 span.record("path", tracing::field::debug(&ack.path_id)); +4490 self.on_path_ack_received(now, SpaceId::Data, ack)?; +4491 } +4492 Frame::Padding | Frame::Ping => {} +4493 Frame::Close(reason) => { +4494 close = Some(reason); +4495 } +4496 Frame::PathChallenge(challenge) => { +4497 let path = &mut self +4498 .path_mut(path_id) +4499 .expect("payload is processed only after the path becomes known"); +4500 path.path_responses.push(number, challenge.0, network_path); +4501 // At this point, update_network_path_or_discard was already called, so +4502 // we don't need to be lenient about `local_ip` possibly mis-matching. +4503 if network_path == path.network_path { +4504 // PATH_CHALLENGE on active path, possible off-path packet forwarding +4505 // attack. Send a non-probing packet to recover the active path. +4506 // TODO(flub): No longer true! We now path_challege also to validate +4507 // the path if the path is new, without an RFC9000-style +4508 // migration involved. This means we add in an extra +4509 // IMMEDIATE_ACK on some challenges. It isn't really wrong to do +4510 // so, but it still is something untidy. We should instead +4511 // suppress this when we know the remote is still validating the +4512 // path. +4513 match self.peer_supports_ack_frequency() { +4514 true => self.immediate_ack(path_id), +4515 false => { +4516 self.ping_path(path_id).ok(); 4517 } -4518 if let Some((_, ref mut prev)) = path.prev { -4519 prev.challenges_sent.clear(); -4520 prev.send_new_challenge = false; -4521 } -4522 } -4523 OffPath => { -4524 debug!("Response to off-path PathChallenge!"); -4525 let next_challenge = path -4526 .data -4527 .earliest_expiring_challenge() -4528 .map(|time| time + self.ack_frequency.max_ack_delay_for_pto()); -4529 self.timers.set_or_stop( -4530 Timer::PerPath(path_id, PathChallengeLost), -4531 next_challenge, -4532 self.qlog.with_time(now), -4533 ); -4534 } -4535 Invalid { expected } => { -4536 debug!(%response, %network_path, %expected, "ignoring invalid PATH_RESPONSE") -4537 } -4538 Unknown => debug!(%response, "ignoring invalid PATH_RESPONSE"), -4539 } -4540 } -4541 Frame::MaxData(frame::MaxData(bytes)) => { -4542 self.streams.received_max_data(bytes); -4543 } -4544 Frame::MaxStreamData(frame::MaxStreamData { id, offset }) => { -4545 self.streams.received_max_stream_data(id, offset)?; -4546 } -4547 Frame::MaxStreams(frame::MaxStreams { dir, count }) => { -4548 self.streams.received_max_streams(dir, count)?; -4549 } -4550 Frame::ResetStream(frame) => { -4551 if self.streams.received_reset(frame)?.should_transmit() { -4552 self.spaces[SpaceId::Data].pending.max_data = true; -4553 } -4554 } -4555 Frame::DataBlocked { offset } => { -4556 debug!(offset, "peer claims to be blocked at connection level"); -4557 } -4558 Frame::StreamDataBlocked { id, offset } => { -4559 if id.initiator() == self.side.side() && id.dir() == Dir::Uni { -4560 debug!("got STREAM_DATA_BLOCKED on send-only {}", id); -4561 return Err(TransportError::STREAM_STATE_ERROR( -4562 "STREAM_DATA_BLOCKED on send-only stream", -4563 )); -4564 } -4565 debug!( -4566 stream = %id, -4567 offset, "peer claims to be blocked at stream level" -4568 ); -4569 } -4570 Frame::StreamsBlocked { dir, limit } => { -4571 if limit > MAX_STREAM_COUNT { -4572 return Err(TransportError::FRAME_ENCODING_ERROR( -4573 "unrepresentable stream limit", -4574 )); -4575 } -4576 debug!( -4577 "peer claims to be blocked opening more than {} {} streams", -4578 limit, dir -4579 ); -4580 } -4581 Frame::StopSending(frame::StopSending { id, error_code }) => { -4582 if id.initiator() != self.side.side() { -4583 if id.dir() == Dir::Uni { -4584 debug!("got STOP_SENDING on recv-only {}", id); -4585 return Err(TransportError::STREAM_STATE_ERROR( -4586 "STOP_SENDING on recv-only stream", -4587 )); -4588 } -4589 } else if self.streams.is_local_unopened(id) { -4590 return Err(TransportError::STREAM_STATE_ERROR( -4591 "STOP_SENDING on unopened stream", -4592 )); -4593 } -4594 self.streams.received_stop_sending(id, error_code); -4595 } -4596 Frame::RetireConnectionId(frame::RetireConnectionId { path_id, sequence }) => { -4597 if let Some(ref path_id) = path_id { -4598 span.record("path", tracing::field::debug(&path_id)); -4599 } -4600 let path_id = path_id.unwrap_or_default(); -4601 match self.local_cid_state.get_mut(&path_id) { -4602 None => error!(?path_id, "RETIRE_CONNECTION_ID for unknown path"), -4603 Some(cid_state) => { -4604 let allow_more_cids = cid_state -4605 .on_cid_retirement(sequence, self.peer_params.issue_cids_limit())?; -4606 -4607 // If the path has closed, we do not issue more CIDs for this path -4608 // For details see https://www.ietf.org/archive/id/draft-ietf-quic-multipath-17.html#section-3.2.2 -4609 // > an endpoint SHOULD provide new connection IDs for that path, if still open, using PATH_NEW_CONNECTION_ID frames. -4610 let has_path = !self.abandoned_paths.contains(&path_id); -4611 let allow_more_cids = allow_more_cids && has_path; -4612 -4613 self.endpoint_events -4614 .push_back(EndpointEventInner::RetireConnectionId( -4615 now, -4616 path_id, -4617 sequence, -4618 allow_more_cids, -4619 )); -4620 } -4621 } -4622 } -4623 Frame::NewConnectionId(frame) => { -4624 let path_id = if let Some(path_id) = frame.path_id { -4625 if !self.is_multipath_negotiated() { -4626 return Err(TransportError::PROTOCOL_VIOLATION( -4627 "received PATH_NEW_CONNECTION_ID frame when multipath was not negotiated", -4628 )); -4629 } -4630 if path_id > self.local_max_path_id { -4631 return Err(TransportError::PROTOCOL_VIOLATION( -4632 "PATH_NEW_CONNECTION_ID contains path_id exceeding current max", -4633 )); -4634 } -4635 path_id -4636 } else { -4637 PathId::ZERO -4638 }; -4639 -4640 if self.abandoned_paths.contains(&path_id) { -4641 trace!("ignoring issued CID for abandoned path"); -4642 continue; +4518 } +4519 } +4520 } +4521 Frame::PathResponse(response) => { +4522 let path = self +4523 .paths +4524 .get_mut(&path_id) +4525 .expect("payload is processed only after the path becomes known"); +4526 +4527 use PathTimer::*; +4528 use paths::OnPathResponseReceived::*; +4529 match path +4530 .data +4531 .on_path_response_received(now, response.0, network_path) +4532 { +4533 OnPath { was_open } => { +4534 let qlog = self.qlog.with_time(now); +4535 +4536 self.timers +4537 .stop(Timer::PerPath(path_id, PathValidation), qlog.clone()); +4538 self.timers +4539 .stop(Timer::PerPath(path_id, PathOpen), qlog.clone()); +4540 +4541 let next_challenge = path +4542 .data +4543 .earliest_expiring_challenge() +4544 .map(|time| time + self.ack_frequency.max_ack_delay_for_pto()); +4545 self.timers.set_or_stop( +4546 Timer::PerPath(path_id, PathChallengeLost), +4547 next_challenge, +4548 qlog, +4549 ); +4550 +4551 if !was_open { +4552 self.events +4553 .push_back(Event::Path(PathEvent::Opened { id: path_id })); +4554 if let Some(observed) = path.data.last_observed_addr_report.as_ref() +4555 { +4556 self.events.push_back(Event::Path(PathEvent::ObservedAddr { +4557 id: path_id, +4558 addr: observed.socket_addr(), +4559 })); +4560 } +4561 } +4562 if let Some((_, ref mut prev)) = path.prev { +4563 prev.challenges_sent.clear(); +4564 prev.send_new_challenge = false; +4565 } +4566 } +4567 OffPath => { +4568 debug!("Response to off-path PathChallenge!"); +4569 let next_challenge = path +4570 .data +4571 .earliest_expiring_challenge() +4572 .map(|time| time + self.ack_frequency.max_ack_delay_for_pto()); +4573 self.timers.set_or_stop( +4574 Timer::PerPath(path_id, PathChallengeLost), +4575 next_challenge, +4576 self.qlog.with_time(now), +4577 ); +4578 } +4579 Invalid { expected } => { +4580 debug!(%response, %network_path, %expected, "ignoring invalid PATH_RESPONSE") +4581 } +4582 Unknown => debug!(%response, "ignoring invalid PATH_RESPONSE"), +4583 } +4584 } +4585 Frame::MaxData(frame::MaxData(bytes)) => { +4586 self.streams.received_max_data(bytes); +4587 } +4588 Frame::MaxStreamData(frame::MaxStreamData { id, offset }) => { +4589 self.streams.received_max_stream_data(id, offset)?; +4590 } +4591 Frame::MaxStreams(frame::MaxStreams { dir, count }) => { +4592 self.streams.received_max_streams(dir, count)?; +4593 } +4594 Frame::ResetStream(frame) => { +4595 if self.streams.received_reset(frame)?.should_transmit() { +4596 self.spaces[SpaceId::Data].pending.max_data = true; +4597 } +4598 } +4599 Frame::DataBlocked { offset } => { +4600 debug!(offset, "peer claims to be blocked at connection level"); +4601 } +4602 Frame::StreamDataBlocked { id, offset } => { +4603 if id.initiator() == self.side.side() && id.dir() == Dir::Uni { +4604 debug!("got STREAM_DATA_BLOCKED on send-only {}", id); +4605 return Err(TransportError::STREAM_STATE_ERROR( +4606 "STREAM_DATA_BLOCKED on send-only stream", +4607 )); +4608 } +4609 debug!( +4610 stream = %id, +4611 offset, "peer claims to be blocked at stream level" +4612 ); +4613 } +4614 Frame::StreamsBlocked { dir, limit } => { +4615 if limit > MAX_STREAM_COUNT { +4616 return Err(TransportError::FRAME_ENCODING_ERROR( +4617 "unrepresentable stream limit", +4618 )); +4619 } +4620 debug!( +4621 "peer claims to be blocked opening more than {} {} streams", +4622 limit, dir +4623 ); +4624 } +4625 Frame::StopSending(frame::StopSending { id, error_code }) => { +4626 if id.initiator() != self.side.side() { +4627 if id.dir() == Dir::Uni { +4628 debug!("got STOP_SENDING on recv-only {}", id); +4629 return Err(TransportError::STREAM_STATE_ERROR( +4630 "STOP_SENDING on recv-only stream", +4631 )); +4632 } +4633 } else if self.streams.is_local_unopened(id) { +4634 return Err(TransportError::STREAM_STATE_ERROR( +4635 "STOP_SENDING on unopened stream", +4636 )); +4637 } +4638 self.streams.received_stop_sending(id, error_code); +4639 } +4640 Frame::RetireConnectionId(frame::RetireConnectionId { path_id, sequence }) => { +4641 if let Some(ref path_id) = path_id { +4642 span.record("path", tracing::field::debug(&path_id)); 4643 } -4644 if let Some(ref path_id) = frame.path_id { -4645 span.record("path", tracing::field::debug(&path_id)); -4646 } -4647 let rem_cids = self -4648 .rem_cids -4649 .entry(path_id) -4650 .or_insert_with(|| CidQueue::new(frame.id)); -4651 if rem_cids.active().is_empty() { -4652 return Err(TransportError::PROTOCOL_VIOLATION( -4653 "NEW_CONNECTION_ID when CIDs aren't in use", -4654 )); -4655 } -4656 if frame.retire_prior_to > frame.sequence { -4657 return Err(TransportError::PROTOCOL_VIOLATION( -4658 "NEW_CONNECTION_ID retiring unissued CIDs", -4659 )); -4660 } -4661 -4662 use crate::cid_queue::InsertError; -4663 match rem_cids.insert(frame) { -4664 Ok(None) if self.path(path_id).is_none() => { -4665 // if this gives us CIDs to open a new path and a nat traversal attempt -4666 // is underway we could try to probe a pending remote -4667 self.continue_nat_traversal_round(now); -4668 } -4669 Ok(None) => {} -4670 Ok(Some((retired, reset_token))) => { -4671 let pending_retired = -4672 &mut self.spaces[SpaceId::Data].pending.retire_cids; -4673 /// Ensure `pending_retired` cannot grow without bound. Limit is -4674 /// somewhat arbitrary but very permissive. -4675 const MAX_PENDING_RETIRED_CIDS: u64 = CidQueue::LEN as u64 * 10; -4676 // We don't bother counting in-flight frames because those are bounded -4677 // by congestion control. -4678 if (pending_retired.len() as u64) -4679 .saturating_add(retired.end.saturating_sub(retired.start)) -4680 > MAX_PENDING_RETIRED_CIDS -4681 { -4682 return Err(TransportError::CONNECTION_ID_LIMIT_ERROR( -4683 "queued too many retired CIDs", -4684 )); -4685 } -4686 pending_retired.extend(retired.map(|seq| (path_id, seq))); -4687 // TODO(matheus23): Reset token for a remote or a full 4-tuple? -4688 self.set_reset_token(path_id, network_path.remote, reset_token); -4689 } -4690 Err(InsertError::ExceedsLimit) => { -4691 return Err(TransportError::CONNECTION_ID_LIMIT_ERROR("")); -4692 } -4693 Err(InsertError::Retired) => { -4694 trace!("discarding already-retired"); -4695 // RETIRE_CONNECTION_ID might not have been previously sent if e.g. a -4696 // range of connection IDs larger than the active connection ID limit -4697 // was retired all at once via retire_prior_to. -4698 self.spaces[SpaceId::Data] -4699 .pending -4700 .retire_cids -4701 .push((path_id, frame.sequence)); -4702 continue; -4703 } -4704 }; +4644 let path_id = path_id.unwrap_or_default(); +4645 match self.local_cid_state.get_mut(&path_id) { +4646 None => error!(?path_id, "RETIRE_CONNECTION_ID for unknown path"), +4647 Some(cid_state) => { +4648 let allow_more_cids = cid_state +4649 .on_cid_retirement(sequence, self.peer_params.issue_cids_limit())?; +4650 +4651 // If the path has closed, we do not issue more CIDs for this path +4652 // For details see https://www.ietf.org/archive/id/draft-ietf-quic-multipath-17.html#section-3.2.2 +4653 // > an endpoint SHOULD provide new connection IDs for that path, if still open, using PATH_NEW_CONNECTION_ID frames. +4654 let has_path = !self.abandoned_paths.contains(&path_id); +4655 let allow_more_cids = allow_more_cids && has_path; +4656 +4657 self.endpoint_events +4658 .push_back(EndpointEventInner::RetireConnectionId( +4659 now, +4660 path_id, +4661 sequence, +4662 allow_more_cids, +4663 )); +4664 } +4665 } +4666 } +4667 Frame::NewConnectionId(frame) => { +4668 let path_id = if let Some(path_id) = frame.path_id { +4669 if !self.is_multipath_negotiated() { +4670 return Err(TransportError::PROTOCOL_VIOLATION( +4671 "received PATH_NEW_CONNECTION_ID frame when multipath was not negotiated", +4672 )); +4673 } +4674 if path_id > self.local_max_path_id { +4675 return Err(TransportError::PROTOCOL_VIOLATION( +4676 "PATH_NEW_CONNECTION_ID contains path_id exceeding current max", +4677 )); +4678 } +4679 path_id +4680 } else { +4681 PathId::ZERO +4682 }; +4683 +4684 if self.abandoned_paths.contains(&path_id) { +4685 trace!("ignoring issued CID for abandoned path"); +4686 continue; +4687 } +4688 if let Some(ref path_id) = frame.path_id { +4689 span.record("path", tracing::field::debug(&path_id)); +4690 } +4691 let rem_cids = self +4692 .rem_cids +4693 .entry(path_id) +4694 .or_insert_with(|| CidQueue::new(frame.id)); +4695 if rem_cids.active().is_empty() { +4696 return Err(TransportError::PROTOCOL_VIOLATION( +4697 "NEW_CONNECTION_ID when CIDs aren't in use", +4698 )); +4699 } +4700 if frame.retire_prior_to > frame.sequence { +4701 return Err(TransportError::PROTOCOL_VIOLATION( +4702 "NEW_CONNECTION_ID retiring unissued CIDs", +4703 )); +4704 } 4705 -4706 if self.side.is_server() -4707 && path_id == PathId::ZERO -4708 && self -4709 .rem_cids -4710 .get(&PathId::ZERO) -4711 .map(|cids| cids.active_seq() == 0) -4712 .unwrap_or_default() -4713 { -4714 // We're a server still using the initial remote CID for the client, so -4715 // let's switch immediately to enable clientside stateless resets. -4716 self.update_rem_cid(PathId::ZERO); -4717 } -4718 } -4719 Frame::NewToken(NewToken { token }) => { -4720 let ConnectionSide::Client { -4721 token_store, -4722 server_name, -4723 .. -4724 } = &self.side -4725 else { -4726 return Err(TransportError::PROTOCOL_VIOLATION("client sent NEW_TOKEN")); -4727 }; -4728 if token.is_empty() { -4729 return Err(TransportError::FRAME_ENCODING_ERROR("empty token")); -4730 } -4731 trace!("got new token"); -4732 token_store.insert(server_name, token); -4733 } -4734 Frame::Datagram(datagram) => { -4735 if self -4736 .datagrams -4737 .received(datagram, &self.config.datagram_receive_buffer_size)? -4738 { -4739 self.events.push_back(Event::DatagramReceived); -4740 } -4741 } -4742 Frame::AckFrequency(ack_frequency) => { -4743 // This frame can only be sent in the Data space -4744 -4745 if !self.ack_frequency.ack_frequency_received(&ack_frequency)? { -4746 // The AckFrequency frame is stale (we have already received a more -4747 // recent one) -4748 continue; -4749 } -4750 -4751 // Update the params for all of our paths -4752 for (path_id, space) in self.spaces[SpaceId::Data].number_spaces.iter_mut() { -4753 space.pending_acks.set_ack_frequency_params(&ack_frequency); -4754 -4755 // Our `max_ack_delay` has been updated, so we may need to adjust -4756 // its associated timeout -4757 if let Some(timeout) = space -4758 .pending_acks -4759 .max_ack_delay_timeout(self.ack_frequency.max_ack_delay) -4760 { -4761 self.timers.set( -4762 Timer::PerPath(*path_id, PathTimer::MaxAckDelay), -4763 timeout, -4764 self.qlog.with_time(now), -4765 ); -4766 } -4767 } -4768 } -4769 Frame::ImmediateAck => { -4770 // This frame can only be sent in the Data space -4771 for pns in self.spaces[SpaceId::Data].iter_paths_mut() { -4772 pns.pending_acks.set_immediate_ack_required(); -4773 } -4774 } -4775 Frame::HandshakeDone => { -4776 if self.side.is_server() { -4777 return Err(TransportError::PROTOCOL_VIOLATION( -4778 "client sent HANDSHAKE_DONE", -4779 )); -4780 } -4781 if self.spaces[SpaceId::Handshake].crypto.is_some() { -4782 self.discard_space(now, SpaceId::Handshake); -4783 } -4784 self.events.push_back(Event::HandshakeConfirmed); -4785 trace!("handshake confirmed"); -4786 } -4787 Frame::ObservedAddr(observed) => { -4788 // check if params allows the peer to send report and this node to receive it -4789 trace!(seq_no = %observed.seq_no, ip = %observed.ip, port = observed.port); -4790 if !self -4791 .peer_params -4792 .address_discovery_role -4793 .should_report(&self.config.address_discovery_role) -4794 { -4795 return Err(TransportError::PROTOCOL_VIOLATION( -4796 "received OBSERVED_ADDRESS frame when not negotiated", -4797 )); -4798 } -4799 // must only be sent in data space -4800 if packet.header.space() != SpaceId::Data { -4801 return Err(TransportError::PROTOCOL_VIOLATION( -4802 "OBSERVED_ADDRESS frame outside data space", -4803 )); -4804 } -4805 -4806 let path = self.path_data_mut(path_id); -4807 if network_path == path.network_path { -4808 if let Some(updated) = path.update_observed_addr_report(observed) -4809 && path.open -4810 { -4811 self.events.push_back(Event::Path(PathEvent::ObservedAddr { -4812 id: path_id, -4813 addr: updated, -4814 })); -4815 // otherwise the event is reported when the path is deemed open -4816 } -4817 } else { -4818 // include in migration -4819 migration_observed_addr = Some(observed) -4820 } -4821 } -4822 Frame::PathAbandon(frame::PathAbandon { -4823 path_id, -4824 error_code, -4825 }) => { -4826 span.record("path", tracing::field::debug(&path_id)); -4827 // TODO(flub): don't really know which error code to use here. -4828 match self.close_path(now, path_id, error_code.into()) { -4829 Ok(()) => { -4830 trace!("peer abandoned path"); -4831 } -4832 Err(ClosePathError::LastOpenPath) => { -4833 trace!("peer abandoned last path, closing connection"); -4834 return Err(TransportError::NO_VIABLE_PATH( -4835 "last path abandoned by peer", -4836 )); -4837 } -4838 Err(ClosePathError::ClosedPath) => { -4839 trace!("peer abandoned already closed path"); -4840 } -4841 }; -4842 // If we receive a retransmit of PATH_ABANDON then we may already have -4843 // abandoned this path locally. In that case the DiscardPath timer -4844 // may already have fired and we no longer have any state for this path. -4845 // Only set this timer if we still have path state. -4846 if let Some(path) = self.paths.get_mut(&path_id) -4847 && !matches!(path.data.abandon_state, AbandonState::ReceivedPathAbandon) -4848 { -4849 let ack_delay = self.ack_frequency.max_ack_delay_for_pto(); -4850 let pto = path.data.rtt.pto_base() + ack_delay; -4851 self.timers.set( -4852 Timer::PerPath(path_id, PathTimer::DiscardPath), -4853 now + 3 * pto, -4854 self.qlog.with_time(now), -4855 ); -4856 // We received a PATH_ABANDON, we don't expect another one by a certain time. -4857 path.data.abandon_state = AbandonState::ReceivedPathAbandon; -4858 } -4859 } -4860 Frame::PathStatusAvailable(info) => { -4861 span.record("path", tracing::field::debug(&info.path_id)); -4862 if self.is_multipath_negotiated() { -4863 self.on_path_status( -4864 info.path_id, -4865 PathStatus::Available, -4866 info.status_seq_no, -4867 ); -4868 } else { -4869 return Err(TransportError::PROTOCOL_VIOLATION( -4870 "received PATH_STATUS_AVAILABLE frame when multipath was not negotiated", -4871 )); -4872 } -4873 } -4874 Frame::PathStatusBackup(info) => { -4875 span.record("path", tracing::field::debug(&info.path_id)); -4876 if self.is_multipath_negotiated() { -4877 self.on_path_status(info.path_id, PathStatus::Backup, info.status_seq_no); -4878 } else { -4879 return Err(TransportError::PROTOCOL_VIOLATION( -4880 "received PATH_STATUS_BACKUP frame when multipath was not negotiated", -4881 )); -4882 } -4883 } -4884 Frame::MaxPathId(frame::MaxPathId(path_id)) => { -4885 span.record("path", tracing::field::debug(&path_id)); -4886 if !self.is_multipath_negotiated() { -4887 return Err(TransportError::PROTOCOL_VIOLATION( -4888 "received MAX_PATH_ID frame when multipath was not negotiated", -4889 )); -4890 } -4891 // frames that do not increase the path id are ignored -4892 if path_id > self.remote_max_path_id { -4893 self.remote_max_path_id = path_id; -4894 self.issue_first_path_cids(now); -4895 while let Some(true) = self.continue_nat_traversal_round(now) {} -4896 } -4897 } -4898 Frame::PathsBlocked(frame::PathsBlocked(max_path_id)) => { -4899 // Receipt of a value of Maximum Path Identifier or Path Identifier that is higher than the local maximum value MUST -4900 // be treated as a connection error of type PROTOCOL_VIOLATION. -4901 // Ref <https://www.ietf.org/archive/id/draft-ietf-quic-multipath-14.html#name-paths_blocked-and-path_cids> -4902 if self.is_multipath_negotiated() { -4903 if max_path_id > self.local_max_path_id { -4904 return Err(TransportError::PROTOCOL_VIOLATION( -4905 "PATHS_BLOCKED maximum path identifier was larger than local maximum", -4906 )); -4907 } -4908 debug!("received PATHS_BLOCKED({:?})", max_path_id); -4909 // TODO(@divma): ensure max concurrent paths -4910 } else { -4911 return Err(TransportError::PROTOCOL_VIOLATION( -4912 "received PATHS_BLOCKED frame when not multipath was not negotiated", -4913 )); -4914 } -4915 } -4916 Frame::PathCidsBlocked(frame::PathCidsBlocked { path_id, next_seq }) => { -4917 // Nothing to do. This is recorded in the frame stats, but otherwise we -4918 // always issue all CIDs we're allowed to issue, so either this is an -4919 // impatient peer or a bug on our side. -4920 -4921 // Receipt of a value of Maximum Path Identifier or Path Identifier that is higher than the local maximum value MUST -4922 // be treated as a connection error of type PROTOCOL_VIOLATION. -4923 // Ref <https://www.ietf.org/archive/id/draft-ietf-quic-multipath-14.html#name-paths_blocked-and-path_cids> -4924 if self.is_multipath_negotiated() { -4925 if path_id > self.local_max_path_id { -4926 return Err(TransportError::PROTOCOL_VIOLATION( -4927 "PATH_CIDS_BLOCKED path identifier was larger than local maximum", -4928 )); -4929 } -4930 if next_seq.0 -4931 > self -4932 .local_cid_state -4933 .get(&path_id) -4934 .map(|cid_state| cid_state.active_seq().1 + 1) -4935 .unwrap_or_default() -4936 { -4937 return Err(TransportError::PROTOCOL_VIOLATION( -4938 "PATH_CIDS_BLOCKED next sequence number larger than in local state", -4939 )); -4940 } -4941 debug!(%path_id, %next_seq, "received PATH_CIDS_BLOCKED"); -4942 } else { -4943 return Err(TransportError::PROTOCOL_VIOLATION( -4944 "received PATH_CIDS_BLOCKED frame when not multipath was not negotiated", -4945 )); -4946 } -4947 } -4948 Frame::AddAddress(addr) => { -4949 let client_state = match self.iroh_hp.client_side_mut() { -4950 Ok(state) => state, -4951 Err(err) => { -4952 return Err(TransportError::PROTOCOL_VIOLATION(format!( -4953 "Nat traversal(ADD_ADDRESS): {err}" -4954 ))); -4955 } -4956 }; -4957 -4958 if !client_state.check_remote_address(&addr) { -4959 // if the address is not valid we flag it, but update anyway -4960 warn!(?addr, "server sent illegal ADD_ADDRESS frame"); -4961 } -4962 -4963 match client_state.add_remote_address(addr) { -4964 Ok(maybe_added) => { -4965 if let Some(added) = maybe_added { -4966 self.events.push_back(Event::NatTraversal( -4967 iroh_hp::Event::AddressAdded(added), -4968 )); -4969 } -4970 } -4971 Err(e) => { -4972 warn!(%e, "failed to add remote address") +4706 use crate::cid_queue::InsertError; +4707 match rem_cids.insert(frame) { +4708 Ok(None) if self.path(path_id).is_none() => { +4709 // if this gives us CIDs to open a new path and a nat traversal attempt +4710 // is underway we could try to probe a pending remote +4711 self.continue_nat_traversal_round(now); +4712 } +4713 Ok(None) => {} +4714 Ok(Some((retired, reset_token))) => { +4715 let pending_retired = +4716 &mut self.spaces[SpaceId::Data].pending.retire_cids; +4717 /// Ensure `pending_retired` cannot grow without bound. Limit is +4718 /// somewhat arbitrary but very permissive. +4719 const MAX_PENDING_RETIRED_CIDS: u64 = CidQueue::LEN as u64 * 10; +4720 // We don't bother counting in-flight frames because those are bounded +4721 // by congestion control. +4722 if (pending_retired.len() as u64) +4723 .saturating_add(retired.end.saturating_sub(retired.start)) +4724 > MAX_PENDING_RETIRED_CIDS +4725 { +4726 return Err(TransportError::CONNECTION_ID_LIMIT_ERROR( +4727 "queued too many retired CIDs", +4728 )); +4729 } +4730 pending_retired.extend(retired.map(|seq| (path_id, seq))); +4731 // TODO(matheus23): Reset token for a remote or a full 4-tuple? +4732 self.set_reset_token(path_id, network_path.remote, reset_token); +4733 } +4734 Err(InsertError::ExceedsLimit) => { +4735 return Err(TransportError::CONNECTION_ID_LIMIT_ERROR("")); +4736 } +4737 Err(InsertError::Retired) => { +4738 trace!("discarding already-retired"); +4739 // RETIRE_CONNECTION_ID might not have been previously sent if e.g. a +4740 // range of connection IDs larger than the active connection ID limit +4741 // was retired all at once via retire_prior_to. +4742 self.spaces[SpaceId::Data] +4743 .pending +4744 .retire_cids +4745 .push((path_id, frame.sequence)); +4746 continue; +4747 } +4748 }; +4749 +4750 if self.side.is_server() +4751 && path_id == PathId::ZERO +4752 && self +4753 .rem_cids +4754 .get(&PathId::ZERO) +4755 .map(|cids| cids.active_seq() == 0) +4756 .unwrap_or_default() +4757 { +4758 // We're a server still using the initial remote CID for the client, so +4759 // let's switch immediately to enable clientside stateless resets. +4760 self.update_rem_cid(PathId::ZERO); +4761 } +4762 } +4763 Frame::NewToken(NewToken { token }) => { +4764 let ConnectionSide::Client { +4765 token_store, +4766 server_name, +4767 .. +4768 } = &self.side +4769 else { +4770 return Err(TransportError::PROTOCOL_VIOLATION("client sent NEW_TOKEN")); +4771 }; +4772 if token.is_empty() { +4773 return Err(TransportError::FRAME_ENCODING_ERROR("empty token")); +4774 } +4775 trace!("got new token"); +4776 token_store.insert(server_name, token); +4777 } +4778 Frame::Datagram(datagram) => { +4779 if self +4780 .datagrams +4781 .received(datagram, &self.config.datagram_receive_buffer_size)? +4782 { +4783 self.events.push_back(Event::DatagramReceived); +4784 } +4785 } +4786 Frame::AckFrequency(ack_frequency) => { +4787 // This frame can only be sent in the Data space +4788 +4789 if !self.ack_frequency.ack_frequency_received(&ack_frequency)? { +4790 // The AckFrequency frame is stale (we have already received a more +4791 // recent one) +4792 continue; +4793 } +4794 +4795 // Update the params for all of our paths +4796 for (path_id, space) in self.spaces[SpaceId::Data].number_spaces.iter_mut() { +4797 space.pending_acks.set_ack_frequency_params(&ack_frequency); +4798 +4799 // Our `max_ack_delay` has been updated, so we may need to adjust +4800 // its associated timeout +4801 if let Some(timeout) = space +4802 .pending_acks +4803 .max_ack_delay_timeout(self.ack_frequency.max_ack_delay) +4804 { +4805 self.timers.set( +4806 Timer::PerPath(*path_id, PathTimer::MaxAckDelay), +4807 timeout, +4808 self.qlog.with_time(now), +4809 ); +4810 } +4811 } +4812 } +4813 Frame::ImmediateAck => { +4814 // This frame can only be sent in the Data space +4815 for pns in self.spaces[SpaceId::Data].iter_paths_mut() { +4816 pns.pending_acks.set_immediate_ack_required(); +4817 } +4818 } +4819 Frame::HandshakeDone => { +4820 if self.side.is_server() { +4821 return Err(TransportError::PROTOCOL_VIOLATION( +4822 "client sent HANDSHAKE_DONE", +4823 )); +4824 } +4825 if self.spaces[SpaceId::Handshake].crypto.is_some() { +4826 self.discard_space(now, SpaceId::Handshake); +4827 } +4828 self.events.push_back(Event::HandshakeConfirmed); +4829 trace!("handshake confirmed"); +4830 } +4831 Frame::ObservedAddr(observed) => { +4832 // check if params allows the peer to send report and this node to receive it +4833 trace!(seq_no = %observed.seq_no, ip = %observed.ip, port = observed.port); +4834 if !self +4835 .peer_params +4836 .address_discovery_role +4837 .should_report(&self.config.address_discovery_role) +4838 { +4839 return Err(TransportError::PROTOCOL_VIOLATION( +4840 "received OBSERVED_ADDRESS frame when not negotiated", +4841 )); +4842 } +4843 // must only be sent in data space +4844 if packet.header.space() != SpaceId::Data { +4845 return Err(TransportError::PROTOCOL_VIOLATION( +4846 "OBSERVED_ADDRESS frame outside data space", +4847 )); +4848 } +4849 +4850 let path = self.path_data_mut(path_id); +4851 if network_path == path.network_path { +4852 if let Some(updated) = path.update_observed_addr_report(observed) +4853 && path.open +4854 { +4855 self.events.push_back(Event::Path(PathEvent::ObservedAddr { +4856 id: path_id, +4857 addr: updated, +4858 })); +4859 // otherwise the event is reported when the path is deemed open +4860 } +4861 } else { +4862 // include in migration +4863 migration_observed_addr = Some(observed) +4864 } +4865 } +4866 Frame::PathAbandon(frame::PathAbandon { +4867 path_id, +4868 error_code, +4869 }) => { +4870 span.record("path", tracing::field::debug(&path_id)); +4871 // TODO(flub): don't really know which error code to use here. +4872 match self.close_path(now, path_id, error_code.into()) { +4873 Ok(()) => { +4874 trace!("peer abandoned path"); +4875 } +4876 Err(ClosePathError::LastOpenPath) => { +4877 trace!("peer abandoned last path, closing connection"); +4878 return Err(TransportError::NO_VIABLE_PATH( +4879 "last path abandoned by peer", +4880 )); +4881 } +4882 Err(ClosePathError::ClosedPath) => { +4883 trace!("peer abandoned already closed path"); +4884 } +4885 }; +4886 // If we receive a retransmit of PATH_ABANDON then we may already have +4887 // abandoned this path locally. In that case the DiscardPath timer +4888 // may already have fired and we no longer have any state for this path. +4889 // Only set this timer if we still have path state. +4890 if let Some(path) = self.paths.get_mut(&path_id) +4891 && !matches!(path.data.abandon_state, AbandonState::ReceivedPathAbandon) +4892 { +4893 let ack_delay = self.ack_frequency.max_ack_delay_for_pto(); +4894 let pto = path.data.rtt.pto_base() + ack_delay; +4895 self.timers.set( +4896 Timer::PerPath(path_id, PathTimer::DiscardPath), +4897 now + 3 * pto, +4898 self.qlog.with_time(now), +4899 ); +4900 // We received a PATH_ABANDON, we don't expect another one by a certain time. +4901 path.data.abandon_state = AbandonState::ReceivedPathAbandon; +4902 } +4903 } +4904 Frame::PathStatusAvailable(info) => { +4905 span.record("path", tracing::field::debug(&info.path_id)); +4906 if self.is_multipath_negotiated() { +4907 self.on_path_status( +4908 info.path_id, +4909 PathStatus::Available, +4910 info.status_seq_no, +4911 ); +4912 } else { +4913 return Err(TransportError::PROTOCOL_VIOLATION( +4914 "received PATH_STATUS_AVAILABLE frame when multipath was not negotiated", +4915 )); +4916 } +4917 } +4918 Frame::PathStatusBackup(info) => { +4919 span.record("path", tracing::field::debug(&info.path_id)); +4920 if self.is_multipath_negotiated() { +4921 self.on_path_status(info.path_id, PathStatus::Backup, info.status_seq_no); +4922 } else { +4923 return Err(TransportError::PROTOCOL_VIOLATION( +4924 "received PATH_STATUS_BACKUP frame when multipath was not negotiated", +4925 )); +4926 } +4927 } +4928 Frame::MaxPathId(frame::MaxPathId(path_id)) => { +4929 span.record("path", tracing::field::debug(&path_id)); +4930 if !self.is_multipath_negotiated() { +4931 return Err(TransportError::PROTOCOL_VIOLATION( +4932 "received MAX_PATH_ID frame when multipath was not negotiated", +4933 )); +4934 } +4935 // frames that do not increase the path id are ignored +4936 if path_id > self.remote_max_path_id { +4937 self.remote_max_path_id = path_id; +4938 self.issue_first_path_cids(now); +4939 while let Some(true) = self.continue_nat_traversal_round(now) {} +4940 } +4941 } +4942 Frame::PathsBlocked(frame::PathsBlocked(max_path_id)) => { +4943 // Receipt of a value of Maximum Path Identifier or Path Identifier that is higher than the local maximum value MUST +4944 // be treated as a connection error of type PROTOCOL_VIOLATION. +4945 // Ref <https://www.ietf.org/archive/id/draft-ietf-quic-multipath-14.html#name-paths_blocked-and-path_cids> +4946 if self.is_multipath_negotiated() { +4947 if max_path_id > self.local_max_path_id { +4948 return Err(TransportError::PROTOCOL_VIOLATION( +4949 "PATHS_BLOCKED maximum path identifier was larger than local maximum", +4950 )); +4951 } +4952 debug!("received PATHS_BLOCKED({:?})", max_path_id); +4953 // TODO(@divma): ensure max concurrent paths +4954 } else { +4955 return Err(TransportError::PROTOCOL_VIOLATION( +4956 "received PATHS_BLOCKED frame when not multipath was not negotiated", +4957 )); +4958 } +4959 } +4960 Frame::PathCidsBlocked(frame::PathCidsBlocked { path_id, next_seq }) => { +4961 // Nothing to do. This is recorded in the frame stats, but otherwise we +4962 // always issue all CIDs we're allowed to issue, so either this is an +4963 // impatient peer or a bug on our side. +4964 +4965 // Receipt of a value of Maximum Path Identifier or Path Identifier that is higher than the local maximum value MUST +4966 // be treated as a connection error of type PROTOCOL_VIOLATION. +4967 // Ref <https://www.ietf.org/archive/id/draft-ietf-quic-multipath-14.html#name-paths_blocked-and-path_cids> +4968 if self.is_multipath_negotiated() { +4969 if path_id > self.local_max_path_id { +4970 return Err(TransportError::PROTOCOL_VIOLATION( +4971 "PATH_CIDS_BLOCKED path identifier was larger than local maximum", +4972 )); 4973 } -4974 } -4975 } -4976 Frame::RemoveAddress(addr) => { -4977 let client_state = match self.iroh_hp.client_side_mut() { -4978 Ok(state) => state, -4979 Err(err) => { -4980 return Err(TransportError::PROTOCOL_VIOLATION(format!( -4981 "Nat traversal(REMOVE_ADDRESS): {err}" -4982 ))); -4983 } -4984 }; -4985 if let Some(removed_addr) = client_state.remove_remote_address(addr) { -4986 self.events -4987 .push_back(Event::NatTraversal(iroh_hp::Event::AddressRemoved( -4988 removed_addr, -4989 ))); +4974 if next_seq.0 +4975 > self +4976 .local_cid_state +4977 .get(&path_id) +4978 .map(|cid_state| cid_state.active_seq().1 + 1) +4979 .unwrap_or_default() +4980 { +4981 return Err(TransportError::PROTOCOL_VIOLATION( +4982 "PATH_CIDS_BLOCKED next sequence number larger than in local state", +4983 )); +4984 } +4985 debug!(%path_id, %next_seq, "received PATH_CIDS_BLOCKED"); +4986 } else { +4987 return Err(TransportError::PROTOCOL_VIOLATION( +4988 "received PATH_CIDS_BLOCKED frame when not multipath was not negotiated", +4989 )); 4990 } 4991 } -4992 Frame::ReachOut(reach_out) => { -4993 let server_state = match self.iroh_hp.server_side_mut() { +4992 Frame::AddAddress(addr) => { +4993 let client_state = match self.iroh_hp.client_side_mut() { 4994 Ok(state) => state, 4995 Err(err) => { 4996 return Err(TransportError::PROTOCOL_VIOLATION(format!( -4997 "Nat traversal(REACH_OUT): {err}" +4997 "Nat traversal(ADD_ADDRESS): {err}" 4998 ))); 4999 } 5000 }; 5001 -5002 if let Err(err) = server_state.handle_reach_out(reach_out) { -5003 return Err(TransportError::PROTOCOL_VIOLATION(format!( -5004 "Nat traversal(REACH_OUT): {err}" -5005 ))); -5006 } -5007 } -5008 } -5009 } -5010 -5011 let space = self.spaces[SpaceId::Data].for_path(path_id); -5012 if space -5013 .pending_acks -5014 .packet_received(now, number, ack_eliciting, &space.dedup) -5015 { -5016 if self.abandoned_paths.contains(&path_id) { -5017 // § 3.4.3 QUIC-MULTIPATH: promptly send ACKs for packets received from -5018 // abandoned paths. -5019 space.pending_acks.set_immediate_ack_required(); -5020 } else { -5021 self.timers.set( -5022 Timer::PerPath(path_id, PathTimer::MaxAckDelay), -5023 now + self.ack_frequency.max_ack_delay, -5024 self.qlog.with_time(now), -5025 ); -5026 } -5027 } -5028 -5029 // Issue stream ID credit due to ACKs of outgoing finish/resets and incoming finish/resets -5030 // on stopped streams. Incoming finishes/resets on open streams are not handled here as they -5031 // are only freed, and hence only issue credit, once the application has been notified -5032 // during a read on the stream. -5033 let pending = &mut self.spaces[SpaceId::Data].pending; -5034 self.streams.queue_max_stream_id(pending); -5035 -5036 if let Some(reason) = close { -5037 self.state.move_to_draining(Some(reason.into())); -5038 self.close = true; -5039 } -5040 -5041 if Some(number) == self.spaces[SpaceId::Data].for_path(path_id).rx_packet -5042 && !is_probing_packet -5043 && network_path != self.path_data(path_id).network_path -5044 { -5045 let ConnectionSide::Server { ref server_config } = self.side else { -5046 panic!("packets from unknown remote should be dropped by clients"); -5047 }; -5048 debug_assert!( -5049 server_config.migration, -5050 "migration-initiating packets should have been dropped immediately" -5051 ); -5052 self.migrate(path_id, now, network_path, migration_observed_addr); -5053 // Break linkability, if possible -5054 self.update_rem_cid(path_id); -5055 self.spin = false; -5056 } -5057 -5058 Ok(()) -5059 } -5060 -5061 fn migrate( -5062 &mut self, -5063 path_id: PathId, -5064 now: Instant, -5065 network_path: FourTuple, -5066 observed_addr: Option<ObservedAddr>, -5067 ) { -5068 trace!(%network_path, %path_id, "migration initiated"); -5069 self.path_generation_counter = self.path_generation_counter.wrapping_add(1); -5070 // TODO(@divma): conditions for path migration in multipath are very specific, check them -5071 // again to prevent path migrations that should actually create a new path +5002 if !client_state.check_remote_address(&addr) { +5003 // if the address is not valid we flag it, but update anyway +5004 warn!(?addr, "server sent illegal ADD_ADDRESS frame"); +5005 } +5006 +5007 match client_state.add_remote_address(addr) { +5008 Ok(maybe_added) => { +5009 if let Some(added) = maybe_added { +5010 self.events.push_back(Event::NatTraversal( +5011 iroh_hp::Event::AddressAdded(added), +5012 )); +5013 } +5014 } +5015 Err(e) => { +5016 warn!(%e, "failed to add remote address") +5017 } +5018 } +5019 } +5020 Frame::RemoveAddress(addr) => { +5021 let client_state = match self.iroh_hp.client_side_mut() { +5022 Ok(state) => state, +5023 Err(err) => { +5024 return Err(TransportError::PROTOCOL_VIOLATION(format!( +5025 "Nat traversal(REMOVE_ADDRESS): {err}" +5026 ))); +5027 } +5028 }; +5029 if let Some(removed_addr) = client_state.remove_remote_address(addr) { +5030 self.events +5031 .push_back(Event::NatTraversal(iroh_hp::Event::AddressRemoved( +5032 removed_addr, +5033 ))); +5034 } +5035 } +5036 Frame::ReachOut(reach_out) => { +5037 let server_state = match self.iroh_hp.server_side_mut() { +5038 Ok(state) => state, +5039 Err(err) => { +5040 return Err(TransportError::PROTOCOL_VIOLATION(format!( +5041 "Nat traversal(REACH_OUT): {err}" +5042 ))); +5043 } +5044 }; +5045 +5046 if let Err(err) = server_state.handle_reach_out(reach_out) { +5047 return Err(TransportError::PROTOCOL_VIOLATION(format!( +5048 "Nat traversal(REACH_OUT): {err}" +5049 ))); +5050 } +5051 } +5052 } +5053 } +5054 +5055 let space = self.spaces[SpaceId::Data].for_path(path_id); +5056 if space +5057 .pending_acks +5058 .packet_received(now, number, ack_eliciting, &space.dedup) +5059 { +5060 if self.abandoned_paths.contains(&path_id) { +5061 // § 3.4.3 QUIC-MULTIPATH: promptly send ACKs for packets received from +5062 // abandoned paths. +5063 space.pending_acks.set_immediate_ack_required(); +5064 } else { +5065 self.timers.set( +5066 Timer::PerPath(path_id, PathTimer::MaxAckDelay), +5067 now + self.ack_frequency.max_ack_delay, +5068 self.qlog.with_time(now), +5069 ); +5070 } +5071 } 5072 -5073 // Reset rtt/congestion state for new path unless it looks like a NAT rebinding. -5074 // Note that the congestion window will not grow until validation terminates. Helps mitigate -5075 // amplification attacks performed by spoofing source addresses. -5076 let prev_pto = self.pto(SpaceId::Data, path_id); -5077 let known_path = self.paths.get_mut(&path_id).expect("known path"); -5078 let path = &mut known_path.data; -5079 let mut new_path = if network_path.remote.is_ipv4() -5080 && network_path.remote.ip() == path.network_path.remote.ip() -5081 { -5082 PathData::from_previous(network_path, path, self.path_generation_counter, now) -5083 } else { -5084 let peer_max_udp_payload_size = -5085 u16::try_from(self.peer_params.max_udp_payload_size.into_inner()) -5086 .unwrap_or(u16::MAX); -5087 PathData::new( -5088 network_path, -5089 self.allow_mtud, -5090 Some(peer_max_udp_payload_size), -5091 self.path_generation_counter, -5092 now, -5093 &self.config, -5094 ) -5095 }; -5096 new_path.last_observed_addr_report = path.last_observed_addr_report.clone(); -5097 if let Some(report) = observed_addr -5098 && let Some(updated) = new_path.update_observed_addr_report(report) -5099 { -5100 tracing::info!("adding observed addr event from migration"); -5101 self.events.push_back(Event::Path(PathEvent::ObservedAddr { -5102 id: path_id, -5103 addr: updated, -5104 })); -5105 } -5106 new_path.send_new_challenge = true; -5107 -5108 let mut prev = mem::replace(path, new_path); -5109 // Don't clobber the original path if the previous one hasn't been validated yet -5110 if !prev.is_validating_path() { -5111 prev.send_new_challenge = true; -5112 // We haven't updated the remote CID yet, this captures the remote CID we were using on -5113 // the previous path. -5114 -5115 known_path.prev = Some((self.rem_cids.get(&path_id).unwrap().active(), prev)); -5116 } -5117 -5118 // We need to re-assign the correct remote to this path in qlog -5119 self.qlog.emit_tuple_assigned(path_id, network_path, now); -5120 -5121 self.timers.set( -5122 Timer::PerPath(path_id, PathTimer::PathValidation), -5123 now + 3 * cmp::max(self.pto(SpaceId::Data, path_id), prev_pto), -5124 self.qlog.with_time(now), -5125 ); -5126 } -5127 -5128 /// Handle a change in the local address, i.e. an active migration -5129 pub fn local_address_changed(&mut self) { -5130 // TODO(flub): if multipath is enabled this needs to create a new path entirely. -5131 self.update_rem_cid(PathId::ZERO); -5132 self.ping(); -5133 } -5134 -5135 /// Switch to a previously unused remote connection ID, if possible -5136 fn update_rem_cid(&mut self, path_id: PathId) { -5137 let Some((reset_token, retired)) = -5138 self.rem_cids.get_mut(&path_id).and_then(|cids| cids.next()) -5139 else { -5140 return; -5141 }; -5142 -5143 // Retire the current remote CID and any CIDs we had to skip. -5144 self.spaces[SpaceId::Data] -5145 .pending -5146 .retire_cids -5147 .extend(retired.map(|seq| (path_id, seq))); -5148 let remote = self.path_data(path_id).network_path.remote; -5149 self.set_reset_token(path_id, remote, reset_token); -5150 } +5073 // Issue stream ID credit due to ACKs of outgoing finish/resets and incoming finish/resets +5074 // on stopped streams. Incoming finishes/resets on open streams are not handled here as they +5075 // are only freed, and hence only issue credit, once the application has been notified +5076 // during a read on the stream. +5077 let pending = &mut self.spaces[SpaceId::Data].pending; +5078 self.streams.queue_max_stream_id(pending); +5079 +5080 if let Some(reason) = close { +5081 self.state.move_to_draining(Some(reason.into())); +5082 self.connection_close_pending = true; +5083 } +5084 +5085 if Some(number) == self.spaces[SpaceId::Data].for_path(path_id).rx_packet +5086 && !is_probing_packet +5087 && network_path != self.path_data(path_id).network_path +5088 { +5089 let ConnectionSide::Server { ref server_config } = self.side else { +5090 panic!("packets from unknown remote should be dropped by clients"); +5091 }; +5092 debug_assert!( +5093 server_config.migration, +5094 "migration-initiating packets should have been dropped immediately" +5095 ); +5096 self.migrate(path_id, now, network_path, migration_observed_addr); +5097 // Break linkability, if possible +5098 self.update_rem_cid(path_id); +5099 self.spin = false; +5100 } +5101 +5102 Ok(()) +5103 } +5104 +5105 fn migrate( +5106 &mut self, +5107 path_id: PathId, +5108 now: Instant, +5109 network_path: FourTuple, +5110 observed_addr: Option<ObservedAddr>, +5111 ) { +5112 trace!(%network_path, %path_id, "migration initiated"); +5113 self.path_generation_counter = self.path_generation_counter.wrapping_add(1); +5114 // TODO(@divma): conditions for path migration in multipath are very specific, check them +5115 // again to prevent path migrations that should actually create a new path +5116 +5117 // Reset rtt/congestion state for new path unless it looks like a NAT rebinding. +5118 // Note that the congestion window will not grow until validation terminates. Helps mitigate +5119 // amplification attacks performed by spoofing source addresses. +5120 let prev_pto = self.pto(SpaceId::Data, path_id); +5121 let known_path = self.paths.get_mut(&path_id).expect("known path"); +5122 let path = &mut known_path.data; +5123 let mut new_path = if network_path.remote.is_ipv4() +5124 && network_path.remote.ip() == path.network_path.remote.ip() +5125 { +5126 PathData::from_previous(network_path, path, self.path_generation_counter, now) +5127 } else { +5128 let peer_max_udp_payload_size = +5129 u16::try_from(self.peer_params.max_udp_payload_size.into_inner()) +5130 .unwrap_or(u16::MAX); +5131 PathData::new( +5132 network_path, +5133 self.allow_mtud, +5134 Some(peer_max_udp_payload_size), +5135 self.path_generation_counter, +5136 now, +5137 &self.config, +5138 ) +5139 }; +5140 new_path.last_observed_addr_report = path.last_observed_addr_report.clone(); +5141 if let Some(report) = observed_addr +5142 && let Some(updated) = new_path.update_observed_addr_report(report) +5143 { +5144 tracing::info!("adding observed addr event from migration"); +5145 self.events.push_back(Event::Path(PathEvent::ObservedAddr { +5146 id: path_id, +5147 addr: updated, +5148 })); +5149 } +5150 new_path.send_new_challenge = true; 5151 -5152 /// Sends this reset token to the endpoint -5153 /// -5154 /// The endpoint needs to know the reset tokens issued by the peer, so that if the peer -5155 /// sends a reset token it knows to route it to this connection. See RFC 9000 section -5156 /// 10.3. Stateless Reset. -5157 /// -5158 /// Reset tokens are different for each path, the endpoint identifies paths by peer -5159 /// socket address however, not by path ID. -5160 fn set_reset_token(&mut self, path_id: PathId, remote: SocketAddr, reset_token: ResetToken) { -5161 self.endpoint_events -5162 .push_back(EndpointEventInner::ResetToken(path_id, remote, reset_token)); -5163 -5164 // During the handshake the server sends a reset token in the transport -5165 // parameters. When we are the client and we receive the reset token during the -5166 // handshake we want this to affect our peer transport parameters. -5167 // TODO(flub): Pretty sure this is pointless, the entire params is overwritten -5168 // shortly after this was called. And then the params don't have this anymore. -5169 if path_id == PathId::ZERO { -5170 self.peer_params.stateless_reset_token = Some(reset_token); -5171 } -5172 } -5173 -5174 /// Issue an initial set of connection IDs to the peer upon connection -5175 fn issue_first_cids(&mut self, now: Instant) { -5176 if self -5177 .local_cid_state -5178 .get(&PathId::ZERO) -5179 .expect("PathId::ZERO exists when the connection is created") -5180 .cid_len() -5181 == 0 -5182 { -5183 return; -5184 } -5185 -5186 // Subtract 1 to account for the CID we supplied while handshaking -5187 let mut n = self.peer_params.issue_cids_limit() - 1; -5188 if let ConnectionSide::Server { server_config } = &self.side -5189 && server_config.has_preferred_address() -5190 { -5191 // We also sent a CID in the transport parameters -5192 n -= 1; -5193 } -5194 self.endpoint_events -5195 .push_back(EndpointEventInner::NeedIdentifiers(PathId::ZERO, now, n)); -5196 } -5197 -5198 /// Issues an initial set of CIDs for paths that have not yet had any CIDs issued -5199 /// -5200 /// Later CIDs are issued when CIDs expire or are retired by the peer. -5201 fn issue_first_path_cids(&mut self, now: Instant) { -5202 if let Some(max_path_id) = self.max_path_id() { -5203 let mut path_id = self.max_path_id_with_cids.next(); -5204 while path_id <= max_path_id { -5205 self.endpoint_events -5206 .push_back(EndpointEventInner::NeedIdentifiers( -5207 path_id, -5208 now, -5209 self.peer_params.issue_cids_limit(), -5210 )); -5211 path_id = path_id.next(); -5212 } -5213 self.max_path_id_with_cids = max_path_id; -5214 } -5215 } -5216 -5217 /// Populates a packet with frames -5218 /// -5219 /// This tries to fit as many frames as possible into the packet. -5220 /// -5221 /// *path_exclusive_only* means to only build frames which can only be sent on this -5222 /// *path. This is used in multipath for backup paths while there is still an active -5223 /// *path. -5224 fn populate_packet<'a, 'b>( -5225 &mut self, -5226 now: Instant, -5227 space_id: SpaceId, -5228 path_id: PathId, -5229 path_exclusive_only: bool, -5230 builder: &mut PacketBuilder<'a, 'b>, -5231 ) { -5232 let pn = builder.exact_number; -5233 let is_multipath_negotiated = self.is_multipath_negotiated(); -5234 let stats = &mut self.stats.frame_tx; -5235 let space = &mut self.spaces[space_id]; -5236 let path = &mut self.paths.get_mut(&path_id).expect("known path").data; -5237 let is_0rtt = space_id == SpaceId::Data && space.crypto.is_none(); -5238 space -5239 .for_path(path_id) -5240 .pending_acks -5241 .maybe_ack_non_eliciting(); -5242 -5243 // HANDSHAKE_DONE -5244 if !is_0rtt -5245 && !path_exclusive_only -5246 && mem::replace(&mut space.pending.handshake_done, false) -5247 { -5248 builder.write_frame(frame::HandshakeDone, stats); -5249 } -5250 -5251 // REACH_OUT -5252 if let Some((round, addresses)) = space.pending.reach_out.as_mut() -5253 && !path_exclusive_only -5254 { -5255 while let Some(local_addr) = addresses.pop() { -5256 let reach_out = frame::ReachOut::new(*round, local_addr); -5257 if builder.frame_space_remaining() > reach_out.size() { -5258 builder.write_frame(reach_out, stats); -5259 } else { -5260 addresses.push(local_addr); -5261 break; -5262 } -5263 } -5264 if addresses.is_empty() { -5265 space.pending.reach_out = None; -5266 } -5267 } -5268 -5269 // OBSERVED_ADDR -5270 if !path_exclusive_only -5271 && space_id == SpaceId::Data -5272 && self -5273 .config -5274 .address_discovery_role -5275 .should_report(&self.peer_params.address_discovery_role) -5276 && (!path.observed_addr_sent || space.pending.observed_addr) -5277 { -5278 let frame = -5279 frame::ObservedAddr::new(path.network_path.remote, self.next_observed_addr_seq_no); -5280 if builder.frame_space_remaining() > frame.size() { -5281 builder.write_frame(frame, stats); -5282 -5283 self.next_observed_addr_seq_no = self.next_observed_addr_seq_no.saturating_add(1u8); -5284 path.observed_addr_sent = true; -5285 -5286 space.pending.observed_addr = false; -5287 } -5288 } -5289 -5290 // PING -5291 if mem::replace(&mut space.for_path(path_id).ping_pending, false) { -5292 builder.write_frame(frame::Ping, stats); +5152 let mut prev = mem::replace(path, new_path); +5153 // Don't clobber the original path if the previous one hasn't been validated yet +5154 if !prev.is_validating_path() { +5155 prev.send_new_challenge = true; +5156 // We haven't updated the remote CID yet, this captures the remote CID we were using on +5157 // the previous path. +5158 +5159 known_path.prev = Some((self.rem_cids.get(&path_id).unwrap().active(), prev)); +5160 } +5161 +5162 // We need to re-assign the correct remote to this path in qlog +5163 self.qlog.emit_tuple_assigned(path_id, network_path, now); +5164 +5165 self.timers.set( +5166 Timer::PerPath(path_id, PathTimer::PathValidation), +5167 now + 3 * cmp::max(self.pto(SpaceId::Data, path_id), prev_pto), +5168 self.qlog.with_time(now), +5169 ); +5170 } +5171 +5172 /// Handle a change in the local address, i.e. an active migration +5173 pub fn local_address_changed(&mut self) { +5174 // TODO(flub): if multipath is enabled this needs to create a new path entirely. +5175 self.update_rem_cid(PathId::ZERO); +5176 self.ping(); +5177 } +5178 +5179 /// Switch to a previously unused remote connection ID, if possible +5180 fn update_rem_cid(&mut self, path_id: PathId) { +5181 let Some((reset_token, retired)) = +5182 self.rem_cids.get_mut(&path_id).and_then(|cids| cids.next()) +5183 else { +5184 return; +5185 }; +5186 +5187 // Retire the current remote CID and any CIDs we had to skip. +5188 self.spaces[SpaceId::Data] +5189 .pending +5190 .retire_cids +5191 .extend(retired.map(|seq| (path_id, seq))); +5192 let remote = self.path_data(path_id).network_path.remote; +5193 self.set_reset_token(path_id, remote, reset_token); +5194 } +5195 +5196 /// Sends this reset token to the endpoint +5197 /// +5198 /// The endpoint needs to know the reset tokens issued by the peer, so that if the peer +5199 /// sends a reset token it knows to route it to this connection. See RFC 9000 section +5200 /// 10.3. Stateless Reset. +5201 /// +5202 /// Reset tokens are different for each path, the endpoint identifies paths by peer +5203 /// socket address however, not by path ID. +5204 fn set_reset_token(&mut self, path_id: PathId, remote: SocketAddr, reset_token: ResetToken) { +5205 self.endpoint_events +5206 .push_back(EndpointEventInner::ResetToken(path_id, remote, reset_token)); +5207 +5208 // During the handshake the server sends a reset token in the transport +5209 // parameters. When we are the client and we receive the reset token during the +5210 // handshake we want this to affect our peer transport parameters. +5211 // TODO(flub): Pretty sure this is pointless, the entire params is overwritten +5212 // shortly after this was called. And then the params don't have this anymore. +5213 if path_id == PathId::ZERO { +5214 self.peer_params.stateless_reset_token = Some(reset_token); +5215 } +5216 } +5217 +5218 /// Issue an initial set of connection IDs to the peer upon connection +5219 fn issue_first_cids(&mut self, now: Instant) { +5220 if self +5221 .local_cid_state +5222 .get(&PathId::ZERO) +5223 .expect("PathId::ZERO exists when the connection is created") +5224 .cid_len() +5225 == 0 +5226 { +5227 return; +5228 } +5229 +5230 // Subtract 1 to account for the CID we supplied while handshaking +5231 let mut n = self.peer_params.issue_cids_limit() - 1; +5232 if let ConnectionSide::Server { server_config } = &self.side +5233 && server_config.has_preferred_address() +5234 { +5235 // We also sent a CID in the transport parameters +5236 n -= 1; +5237 } +5238 self.endpoint_events +5239 .push_back(EndpointEventInner::NeedIdentifiers(PathId::ZERO, now, n)); +5240 } +5241 +5242 /// Issues an initial set of CIDs for paths that have not yet had any CIDs issued +5243 /// +5244 /// Later CIDs are issued when CIDs expire or are retired by the peer. +5245 fn issue_first_path_cids(&mut self, now: Instant) { +5246 if let Some(max_path_id) = self.max_path_id() { +5247 let mut path_id = self.max_path_id_with_cids.next(); +5248 while path_id <= max_path_id { +5249 self.endpoint_events +5250 .push_back(EndpointEventInner::NeedIdentifiers( +5251 path_id, +5252 now, +5253 self.peer_params.issue_cids_limit(), +5254 )); +5255 path_id = path_id.next(); +5256 } +5257 self.max_path_id_with_cids = max_path_id; +5258 } +5259 } +5260 +5261 /// Populates a packet with frames +5262 /// +5263 /// This tries to fit as many frames as possible into the packet. +5264 /// +5265 /// *path_exclusive_only* means to only build frames which can only be sent on this +5266 /// *path. This is used in multipath for backup paths while there is still an active +5267 /// *path. +5268 fn populate_packet<'a, 'b>( +5269 &mut self, +5270 now: Instant, +5271 space_id: SpaceId, +5272 path_id: PathId, +5273 path_exclusive_only: bool, +5274 builder: &mut PacketBuilder<'a, 'b>, +5275 ) { +5276 let pn = builder.packet_number; +5277 let is_multipath_negotiated = self.is_multipath_negotiated(); +5278 let stats = &mut self.stats.frame_tx; +5279 let space = &mut self.spaces[space_id]; +5280 let path = &mut self.paths.get_mut(&path_id).expect("known path").data; +5281 let is_0rtt = space_id == SpaceId::Data && space.crypto.is_none(); +5282 space +5283 .for_path(path_id) +5284 .pending_acks +5285 .maybe_ack_non_eliciting(); +5286 +5287 // HANDSHAKE_DONE +5288 if !is_0rtt +5289 && !path_exclusive_only +5290 && mem::replace(&mut space.pending.handshake_done, false) +5291 { +5292 builder.write_frame(frame::HandshakeDone, stats); 5293 } 5294 -5295 // IMMEDIATE_ACK -5296 if mem::replace(&mut space.for_path(path_id).immediate_ack_pending, false) { -5297 debug_assert_eq!( -5298 space_id, -5299 SpaceId::Data, -5300 "immediate acks must be sent in the data space" -5301 ); -5302 builder.write_frame(frame::ImmediateAck, stats); -5303 } -5304 -5305 // ACK -5306 // TODO(flub): Should this send acks for this path anyway? -5307 -5308 if !path_exclusive_only { -5309 for path_id in space -5310 .number_spaces -5311 .iter_mut() -5312 .filter(|(_, pns)| pns.pending_acks.can_send()) -5313 .map(|(&path_id, _)| path_id) -5314 .collect::<Vec<_>>() -5315 { -5316 Self::populate_acks( -5317 now, -5318 self.receiving_ecn, -5319 path_id, -5320 space_id, -5321 space, -5322 is_multipath_negotiated, -5323 builder, -5324 stats, -5325 ); -5326 } -5327 } -5328 -5329 // ACK_FREQUENCY -5330 if !path_exclusive_only && mem::replace(&mut space.pending.ack_frequency, false) { -5331 let sequence_number = self.ack_frequency.next_sequence_number(); -5332 -5333 // Safe to unwrap because this is always provided when ACK frequency is enabled -5334 let config = self.config.ack_frequency_config.as_ref().unwrap(); -5335 -5336 // Ensure the delay is within bounds to avoid a PROTOCOL_VIOLATION error -5337 let max_ack_delay = self.ack_frequency.candidate_max_ack_delay( -5338 path.rtt.get(), -5339 config, -5340 &self.peer_params, -5341 ); -5342 -5343 let frame = frame::AckFrequency { -5344 sequence: sequence_number, -5345 ack_eliciting_threshold: config.ack_eliciting_threshold, -5346 request_max_ack_delay: max_ack_delay.as_micros().try_into().unwrap_or(VarInt::MAX), -5347 reordering_threshold: config.reordering_threshold, -5348 }; -5349 builder.write_frame(frame, stats); -5350 -5351 self.ack_frequency -5352 .ack_frequency_sent(path_id, pn, max_ack_delay); -5353 } -5354 -5355 // PATH_CHALLENGE -5356 if builder.frame_space_remaining() > frame::PathChallenge::SIZE_BOUND -5357 && space_id == SpaceId::Data -5358 && path.send_new_challenge -5359 && !self.state.is_closed() -5360 // we don't want to send new challenges if we are already closing -5361 { -5362 path.send_new_challenge = false; -5363 -5364 // Generate a new challenge every time we send a new PATH_CHALLENGE -5365 let token = self.rng.random(); -5366 let info = paths::SentChallengeInfo { -5367 sent_instant: now, -5368 network_path: path.network_path, -5369 }; -5370 path.challenges_sent.insert(token, info); -5371 let challenge = frame::PathChallenge(token); -5372 trace!(frame = %challenge); -5373 builder.write_frame(challenge, stats); -5374 builder.require_padding(); -5375 let pto = self.ack_frequency.max_ack_delay_for_pto() + path.rtt.pto_base(); -5376 self.timers.set( -5377 Timer::PerPath(path_id, PathTimer::PathChallengeLost), -5378 now + pto, -5379 self.qlog.with_time(now), -5380 ); -5381 -5382 if is_multipath_negotiated && !path.validated && path.send_new_challenge { -5383 // queue informing the path status along with the challenge -5384 space.pending.path_status.insert(path_id); -5385 } +5295 // REACH_OUT +5296 if let Some((round, addresses)) = space.pending.reach_out.as_mut() +5297 && !path_exclusive_only +5298 { +5299 while let Some(local_addr) = addresses.pop() { +5300 let reach_out = frame::ReachOut::new(*round, local_addr); +5301 if builder.frame_space_remaining() > reach_out.size() { +5302 builder.write_frame(reach_out, stats); +5303 } else { +5304 addresses.push(local_addr); +5305 break; +5306 } +5307 } +5308 if addresses.is_empty() { +5309 space.pending.reach_out = None; +5310 } +5311 } +5312 +5313 // OBSERVED_ADDR +5314 if !path_exclusive_only +5315 && space_id == SpaceId::Data +5316 && self +5317 .config +5318 .address_discovery_role +5319 .should_report(&self.peer_params.address_discovery_role) +5320 && (!path.observed_addr_sent || space.pending.observed_addr) +5321 { +5322 let frame = +5323 frame::ObservedAddr::new(path.network_path.remote, self.next_observed_addr_seq_no); +5324 if builder.frame_space_remaining() > frame.size() { +5325 builder.write_frame(frame, stats); +5326 +5327 self.next_observed_addr_seq_no = self.next_observed_addr_seq_no.saturating_add(1u8); +5328 path.observed_addr_sent = true; +5329 +5330 space.pending.observed_addr = false; +5331 } +5332 } +5333 +5334 // PING +5335 if mem::replace(&mut space.for_path(path_id).ping_pending, false) { +5336 builder.write_frame(frame::Ping, stats); +5337 } +5338 +5339 // IMMEDIATE_ACK +5340 if mem::replace(&mut space.for_path(path_id).immediate_ack_pending, false) { +5341 debug_assert_eq!( +5342 space_id, +5343 SpaceId::Data, +5344 "immediate acks must be sent in the data space" +5345 ); +5346 builder.write_frame(frame::ImmediateAck, stats); +5347 } +5348 +5349 // ACK +5350 // TODO(flub): Should this send acks for this path anyway? +5351 +5352 if !path_exclusive_only { +5353 for path_id in space +5354 .number_spaces +5355 .iter_mut() +5356 .filter(|(_, pns)| pns.pending_acks.can_send()) +5357 .map(|(&path_id, _)| path_id) +5358 .collect::<Vec<_>>() +5359 { +5360 Self::populate_acks( +5361 now, +5362 self.receiving_ecn, +5363 path_id, +5364 space_id, +5365 space, +5366 is_multipath_negotiated, +5367 builder, +5368 stats, +5369 ); +5370 } +5371 } +5372 +5373 // ACK_FREQUENCY +5374 if !path_exclusive_only && mem::replace(&mut space.pending.ack_frequency, false) { +5375 let sequence_number = self.ack_frequency.next_sequence_number(); +5376 +5377 // Safe to unwrap because this is always provided when ACK frequency is enabled +5378 let config = self.config.ack_frequency_config.as_ref().unwrap(); +5379 +5380 // Ensure the delay is within bounds to avoid a PROTOCOL_VIOLATION error +5381 let max_ack_delay = self.ack_frequency.candidate_max_ack_delay( +5382 path.rtt.get(), +5383 config, +5384 &self.peer_params, +5385 ); 5386 -5387 // Always include an OBSERVED_ADDR frame with a PATH_CHALLENGE, regardless -5388 // of whether one has already been sent on this path. -5389 if space_id == SpaceId::Data -5390 && self -5391 .config -5392 .address_discovery_role -5393 .should_report(&self.peer_params.address_discovery_role) -5394 { -5395 let frame = frame::ObservedAddr::new( -5396 path.network_path.remote, -5397 self.next_observed_addr_seq_no, -5398 ); -5399 if builder.frame_space_remaining() > frame.size() { -5400 builder.write_frame(frame, stats); -5401 -5402 self.next_observed_addr_seq_no = -5403 self.next_observed_addr_seq_no.saturating_add(1u8); -5404 path.observed_addr_sent = true; -5405 -5406 space.pending.observed_addr = false; -5407 } -5408 } -5409 } -5410 -5411 // PATH_RESPONSE -5412 if builder.frame_space_remaining() > frame::PathResponse::SIZE_BOUND -5413 && space_id == SpaceId::Data -5414 && let Some(token) = path.path_responses.pop_on_path(path.network_path) -5415 { -5416 let response = frame::PathResponse(token); -5417 trace!(frame = %response); -5418 builder.write_frame(response, stats); -5419 builder.require_padding(); -5420 -5421 // NOTE: this is technically not required but might be useful to ride the -5422 // request/response nature of path challenges to refresh an observation -5423 // Since PATH_RESPONSE is a probing frame, this is allowed by the spec. -5424 if space_id == SpaceId::Data -5425 && self -5426 .config -5427 .address_discovery_role -5428 .should_report(&self.peer_params.address_discovery_role) -5429 { -5430 let frame = frame::ObservedAddr::new( -5431 path.network_path.remote, -5432 self.next_observed_addr_seq_no, -5433 ); -5434 if builder.frame_space_remaining() > frame.size() { -5435 builder.write_frame(frame, stats); -5436 -5437 self.next_observed_addr_seq_no = -5438 self.next_observed_addr_seq_no.saturating_add(1u8); -5439 path.observed_addr_sent = true; -5440 -5441 space.pending.observed_addr = false; -5442 } -5443 } -5444 } +5387 let frame = frame::AckFrequency { +5388 sequence: sequence_number, +5389 ack_eliciting_threshold: config.ack_eliciting_threshold, +5390 request_max_ack_delay: max_ack_delay.as_micros().try_into().unwrap_or(VarInt::MAX), +5391 reordering_threshold: config.reordering_threshold, +5392 }; +5393 builder.write_frame(frame, stats); +5394 +5395 self.ack_frequency +5396 .ack_frequency_sent(path_id, pn, max_ack_delay); +5397 } +5398 +5399 // PATH_CHALLENGE +5400 if builder.frame_space_remaining() > frame::PathChallenge::SIZE_BOUND +5401 && space_id == SpaceId::Data +5402 && path.send_new_challenge +5403 && !self.state.is_closed() +5404 // we don't want to send new challenges if we are already closing +5405 { +5406 path.send_new_challenge = false; +5407 +5408 // Generate a new challenge every time we send a new PATH_CHALLENGE +5409 let token = self.rng.random(); +5410 let info = paths::SentChallengeInfo { +5411 sent_instant: now, +5412 network_path: path.network_path, +5413 }; +5414 path.challenges_sent.insert(token, info); +5415 let challenge = frame::PathChallenge(token); +5416 trace!(frame = %challenge); +5417 builder.write_frame(challenge, stats); +5418 builder.require_padding(); +5419 let pto = self.ack_frequency.max_ack_delay_for_pto() + path.rtt.pto_base(); +5420 self.timers.set( +5421 Timer::PerPath(path_id, PathTimer::PathChallengeLost), +5422 now + pto, +5423 self.qlog.with_time(now), +5424 ); +5425 +5426 if is_multipath_negotiated && !path.validated && path.send_new_challenge { +5427 // queue informing the path status along with the challenge +5428 space.pending.path_status.insert(path_id); +5429 } +5430 +5431 // Always include an OBSERVED_ADDR frame with a PATH_CHALLENGE, regardless +5432 // of whether one has already been sent on this path. +5433 if space_id == SpaceId::Data +5434 && self +5435 .config +5436 .address_discovery_role +5437 .should_report(&self.peer_params.address_discovery_role) +5438 { +5439 let frame = frame::ObservedAddr::new( +5440 path.network_path.remote, +5441 self.next_observed_addr_seq_no, +5442 ); +5443 if builder.frame_space_remaining() > frame.size() { +5444 builder.write_frame(frame, stats); 5445 -5446 // CRYPTO -5447 while !path_exclusive_only -5448 && builder.frame_space_remaining() > frame::Crypto::SIZE_BOUND -5449 && !is_0rtt -5450 { -5451 let mut frame = match space.pending.crypto.pop_front() { -5452 Some(x) => x, -5453 None => break, -5454 }; -5455 -5456 // Calculate the maximum amount of crypto data we can store in the buffer. -5457 // Since the offset is known, we can reserve the exact size required to encode it. -5458 // For length we reserve 2bytes which allows to encode up to 2^14, -5459 // which is more than what fits into normally sized QUIC frames. -5460 let max_crypto_data_size = builder.frame_space_remaining() -5461 - 1 // Frame Type -5462 - VarInt::size(unsafe { VarInt::from_u64_unchecked(frame.offset) }) -5463 - 2; // Maximum encoded length for frame size, given we send less than 2^14 bytes +5446 self.next_observed_addr_seq_no = +5447 self.next_observed_addr_seq_no.saturating_add(1u8); +5448 path.observed_addr_sent = true; +5449 +5450 space.pending.observed_addr = false; +5451 } +5452 } +5453 } +5454 +5455 // PATH_RESPONSE +5456 if builder.frame_space_remaining() > frame::PathResponse::SIZE_BOUND +5457 && space_id == SpaceId::Data +5458 && let Some(token) = path.path_responses.pop_on_path(path.network_path) +5459 { +5460 let response = frame::PathResponse(token); +5461 trace!(frame = %response); +5462 builder.write_frame(response, stats); +5463 builder.require_padding(); 5464 -5465 let len = frame -5466 .data -5467 .len() -5468 .min(2usize.pow(14) - 1) -5469 .min(max_crypto_data_size); -5470 -5471 let data = frame.data.split_to(len); -5472 let offset = frame.offset; -5473 let truncated = frame::Crypto { offset, data }; -5474 builder.write_frame(truncated, stats); -5475 -5476 if !frame.data.is_empty() { -5477 frame.offset += len as u64; -5478 space.pending.crypto.push_front(frame); -5479 } -5480 } -5481 -5482 // TODO(flub): maybe this is much higher priority? -5483 // PATH_ABANDON -5484 while !path_exclusive_only -5485 && space_id == SpaceId::Data -5486 && frame::PathAbandon::SIZE_BOUND <= builder.frame_space_remaining() -5487 { -5488 let Some((abandoned_path_id, error_code)) = space.pending.path_abandon.pop_first() -5489 else { -5490 break; -5491 }; -5492 let frame = frame::PathAbandon { -5493 path_id: abandoned_path_id, -5494 error_code, -5495 }; -5496 builder.write_frame(frame, stats); -5497 -5498 let ack_delay = self.ack_frequency.max_ack_delay_for_pto(); -5499 // We can't access path here anymore due to borrowing issues. -5500 let send_pto = self.paths.get(&path_id).unwrap().data.rtt.pto_base() + ack_delay; -5501 if let Some(abandoned_path) = self.paths.get_mut(&abandoned_path_id) { -5502 // We only want to set the deadline on the *first* PATH_ABANDON we send. -5503 // Retransmits shouldn't run this code again -5504 if matches!( -5505 abandoned_path.data.abandon_state, -5506 AbandonState::NotAbandoned -5507 ) { -5508 // The peer MUST respond with a corresponding PATH_ABANDON frame. -5509 // The other peer has 3 * PTO to do that. -5510 // This uses the PTO of the path we send on! -5511 // If the PATH_ABANDON comes in within the deadline we're giving here, then this -5512 // state will be set to `AbandonState::ReceivedPathAbandon`, essentially clearing -5513 // the deadline. If we receive a frame after the deadline, we error out with a -5514 // protocol violation. -5515 // Receiving other frames before the deadline is fine, as those might be packets -5516 // that were still in-flight. -5517 abandoned_path.data.abandon_state = AbandonState::ExpectingPathAbandon { -5518 deadline: now + 3 * send_pto, -5519 }; -5520 -5521 // At some point, we need to forget about the path. -5522 // If we do so too early, then we'll have discarded the CIDs of that path and won't -5523 // handle incoming packets on that path correctly. -5524 // To give this path enough time, we assume that the peer will have received our -5525 // PATH_ABANDON within 3 * PTO of the path we sent the abandon on, -5526 // and then we give the path 3 * PTO time to make it very unlikely that there will -5527 // still be packets incoming on the path at that point. -5528 // This timer will actually get reset to a value that's likely to be even earlier -5529 // once we actually receive the PATH_ABANDON frame itself. -5530 let abandoned_pto = -5531 self.paths.get(&path_id).unwrap().data.rtt.pto_base() + ack_delay; -5532 self.timers.set( -5533 Timer::PerPath(abandoned_path_id, PathTimer::DiscardPath), -5534 now + 3 * send_pto + 3 * abandoned_pto, -5535 self.qlog.with_time(now), -5536 ); -5537 } -5538 } else { -5539 warn!("sent PATH_ABANDON after path was already discarded"); -5540 } -5541 } -5542 -5543 // PATH_STATUS_AVAILABLE & PATH_STATUS_BACKUP -5544 while !path_exclusive_only -5545 && space_id == SpaceId::Data -5546 && frame::PathStatusAvailable::SIZE_BOUND <= builder.frame_space_remaining() -5547 { -5548 let Some(path_id) = space.pending.path_status.pop_first() else { -5549 break; -5550 }; -5551 let Some(path) = self.paths.get(&path_id).map(|path_state| &path_state.data) else { -5552 trace!(%path_id, "discarding queued path status for unknown path"); -5553 continue; -5554 }; -5555 -5556 let seq = path.status.seq(); -5557 match path.local_status() { -5558 PathStatus::Available => { -5559 let frame = frame::PathStatusAvailable { -5560 path_id, -5561 status_seq_no: seq, -5562 }; -5563 builder.write_frame(frame, stats); -5564 } -5565 PathStatus::Backup => { -5566 let frame = frame::PathStatusBackup { -5567 path_id, -5568 status_seq_no: seq, -5569 }; -5570 builder.write_frame(frame, stats); -5571 } -5572 } -5573 } -5574 -5575 // MAX_PATH_ID -5576 if space_id == SpaceId::Data -5577 && !path_exclusive_only -5578 && space.pending.max_path_id -5579 && frame::MaxPathId::SIZE_BOUND <= builder.frame_space_remaining() -5580 { -5581 let frame = frame::MaxPathId(self.local_max_path_id); -5582 builder.write_frame(frame, stats); -5583 space.pending.max_path_id = false; -5584 } -5585 -5586 // PATHS_BLOCKED -5587 if space_id == SpaceId::Data -5588 && !path_exclusive_only -5589 && space.pending.paths_blocked -5590 && frame::PathsBlocked::SIZE_BOUND <= builder.frame_space_remaining() +5465 // NOTE: this is technically not required but might be useful to ride the +5466 // request/response nature of path challenges to refresh an observation +5467 // Since PATH_RESPONSE is a probing frame, this is allowed by the spec. +5468 if space_id == SpaceId::Data +5469 && self +5470 .config +5471 .address_discovery_role +5472 .should_report(&self.peer_params.address_discovery_role) +5473 { +5474 let frame = frame::ObservedAddr::new( +5475 path.network_path.remote, +5476 self.next_observed_addr_seq_no, +5477 ); +5478 if builder.frame_space_remaining() > frame.size() { +5479 builder.write_frame(frame, stats); +5480 +5481 self.next_observed_addr_seq_no = +5482 self.next_observed_addr_seq_no.saturating_add(1u8); +5483 path.observed_addr_sent = true; +5484 +5485 space.pending.observed_addr = false; +5486 } +5487 } +5488 } +5489 +5490 // CRYPTO +5491 while !path_exclusive_only +5492 && builder.frame_space_remaining() > frame::Crypto::SIZE_BOUND +5493 && !is_0rtt +5494 { +5495 let mut frame = match space.pending.crypto.pop_front() { +5496 Some(x) => x, +5497 None => break, +5498 }; +5499 +5500 // Calculate the maximum amount of crypto data we can store in the buffer. +5501 // Since the offset is known, we can reserve the exact size required to encode it. +5502 // For length we reserve 2bytes which allows to encode up to 2^14, +5503 // which is more than what fits into normally sized QUIC frames. +5504 let max_crypto_data_size = builder.frame_space_remaining() +5505 - 1 // Frame Type +5506 - VarInt::size(unsafe { VarInt::from_u64_unchecked(frame.offset) }) +5507 - 2; // Maximum encoded length for frame size, given we send less than 2^14 bytes +5508 +5509 let len = frame +5510 .data +5511 .len() +5512 .min(2usize.pow(14) - 1) +5513 .min(max_crypto_data_size); +5514 +5515 let data = frame.data.split_to(len); +5516 let offset = frame.offset; +5517 let truncated = frame::Crypto { offset, data }; +5518 builder.write_frame(truncated, stats); +5519 +5520 if !frame.data.is_empty() { +5521 frame.offset += len as u64; +5522 space.pending.crypto.push_front(frame); +5523 } +5524 } +5525 +5526 // TODO(flub): maybe this is much higher priority? +5527 // PATH_ABANDON +5528 while !path_exclusive_only +5529 && space_id == SpaceId::Data +5530 && frame::PathAbandon::SIZE_BOUND <= builder.frame_space_remaining() +5531 { +5532 let Some((abandoned_path_id, error_code)) = space.pending.path_abandon.pop_first() +5533 else { +5534 break; +5535 }; +5536 let frame = frame::PathAbandon { +5537 path_id: abandoned_path_id, +5538 error_code, +5539 }; +5540 builder.write_frame(frame, stats); +5541 +5542 let ack_delay = self.ack_frequency.max_ack_delay_for_pto(); +5543 // We can't access path here anymore due to borrowing issues. +5544 let send_pto = self.paths.get(&path_id).unwrap().data.rtt.pto_base() + ack_delay; +5545 if let Some(abandoned_path) = self.paths.get_mut(&abandoned_path_id) { +5546 // We only want to set the deadline on the *first* PATH_ABANDON we send. +5547 // Retransmits shouldn't run this code again +5548 if matches!( +5549 abandoned_path.data.abandon_state, +5550 AbandonState::NotAbandoned +5551 ) { +5552 // The peer MUST respond with a corresponding PATH_ABANDON frame. +5553 // The other peer has 3 * PTO to do that. +5554 // This uses the PTO of the path we send on! +5555 // If the PATH_ABANDON comes in within the deadline we're giving here, then this +5556 // state will be set to `AbandonState::ReceivedPathAbandon`, essentially clearing +5557 // the deadline. If we receive a frame after the deadline, we error out with a +5558 // protocol violation. +5559 // Receiving other frames before the deadline is fine, as those might be packets +5560 // that were still in-flight. +5561 abandoned_path.data.abandon_state = AbandonState::ExpectingPathAbandon { +5562 deadline: now + 3 * send_pto, +5563 }; +5564 +5565 // At some point, we need to forget about the path. +5566 // If we do so too early, then we'll have discarded the CIDs of that path and won't +5567 // handle incoming packets on that path correctly. +5568 // To give this path enough time, we assume that the peer will have received our +5569 // PATH_ABANDON within 3 * PTO of the path we sent the abandon on, +5570 // and then we give the path 3 * PTO time to make it very unlikely that there will +5571 // still be packets incoming on the path at that point. +5572 // This timer will actually get reset to a value that's likely to be even earlier +5573 // once we actually receive the PATH_ABANDON frame itself. +5574 let abandoned_pto = +5575 self.paths.get(&path_id).unwrap().data.rtt.pto_base() + ack_delay; +5576 self.timers.set( +5577 Timer::PerPath(abandoned_path_id, PathTimer::DiscardPath), +5578 now + 3 * send_pto + 3 * abandoned_pto, +5579 self.qlog.with_time(now), +5580 ); +5581 } +5582 } else { +5583 warn!("sent PATH_ABANDON after path was already discarded"); +5584 } +5585 } +5586 +5587 // PATH_STATUS_AVAILABLE & PATH_STATUS_BACKUP +5588 while !path_exclusive_only +5589 && space_id == SpaceId::Data +5590 && frame::PathStatusAvailable::SIZE_BOUND <= builder.frame_space_remaining() 5591 { -5592 let frame = frame::PathsBlocked(self.remote_max_path_id); -5593 builder.write_frame(frame, stats); -5594 space.pending.paths_blocked = false; -5595 } -5596 -5597 // PATH_CIDS_BLOCKED -5598 while space_id == SpaceId::Data -5599 && !path_exclusive_only -5600 && frame::PathCidsBlocked::SIZE_BOUND <= builder.frame_space_remaining() -5601 { -5602 let Some(path_id) = space.pending.path_cids_blocked.pop_first() else { -5603 break; -5604 }; -5605 let next_seq = match self.rem_cids.get(&path_id) { -5606 Some(cid_queue) => VarInt(cid_queue.active_seq() + 1), -5607 None => VarInt(0), -5608 }; -5609 let frame = frame::PathCidsBlocked { path_id, next_seq }; -5610 builder.write_frame(frame, stats); -5611 } -5612 -5613 // RESET_STREAM, STOP_SENDING, MAX_DATA, MAX_STREAM_DATA, MAX_STREAMS -5614 if space_id == SpaceId::Data && !path_exclusive_only { -5615 self.streams -5616 .write_control_frames(builder, &mut space.pending, stats); +5592 let Some(path_id) = space.pending.path_status.pop_first() else { +5593 break; +5594 }; +5595 let Some(path) = self.paths.get(&path_id).map(|path_state| &path_state.data) else { +5596 trace!(%path_id, "discarding queued path status for unknown path"); +5597 continue; +5598 }; +5599 +5600 let seq = path.status.seq(); +5601 match path.local_status() { +5602 PathStatus::Available => { +5603 let frame = frame::PathStatusAvailable { +5604 path_id, +5605 status_seq_no: seq, +5606 }; +5607 builder.write_frame(frame, stats); +5608 } +5609 PathStatus::Backup => { +5610 let frame = frame::PathStatusBackup { +5611 path_id, +5612 status_seq_no: seq, +5613 }; +5614 builder.write_frame(frame, stats); +5615 } +5616 } 5617 } 5618 -5619 // NEW_CONNECTION_ID -5620 let cid_len = self -5621 .local_cid_state -5622 .values() -5623 .map(|cid_state| cid_state.cid_len()) -5624 .max() -5625 .expect("some local CID state must exist"); -5626 let new_cid_size_bound = -5627 frame::NewConnectionId::size_bound(is_multipath_negotiated, cid_len); -5628 while !path_exclusive_only && builder.frame_space_remaining() > new_cid_size_bound { -5629 let issued = match space.pending.new_cids.pop() { -5630 Some(x) => x, -5631 None => break, -5632 }; -5633 let retire_prior_to = self -5634 .local_cid_state -5635 .get(&issued.path_id) -5636 .map(|cid_state| cid_state.retire_prior_to()) -5637 .unwrap_or_else(|| panic!("missing local CID state for path={}", issued.path_id)); -5638 -5639 let cid_path_id = match is_multipath_negotiated { -5640 true => Some(issued.path_id), -5641 false => { -5642 debug_assert_eq!(issued.path_id, PathId::ZERO); -5643 None -5644 } -5645 }; -5646 let frame = frame::NewConnectionId { -5647 path_id: cid_path_id, -5648 sequence: issued.sequence, -5649 retire_prior_to, -5650 id: issued.id, -5651 reset_token: issued.reset_token, +5619 // MAX_PATH_ID +5620 if space_id == SpaceId::Data +5621 && !path_exclusive_only +5622 && space.pending.max_path_id +5623 && frame::MaxPathId::SIZE_BOUND <= builder.frame_space_remaining() +5624 { +5625 let frame = frame::MaxPathId(self.local_max_path_id); +5626 builder.write_frame(frame, stats); +5627 space.pending.max_path_id = false; +5628 } +5629 +5630 // PATHS_BLOCKED +5631 if space_id == SpaceId::Data +5632 && !path_exclusive_only +5633 && space.pending.paths_blocked +5634 && frame::PathsBlocked::SIZE_BOUND <= builder.frame_space_remaining() +5635 { +5636 let frame = frame::PathsBlocked(self.remote_max_path_id); +5637 builder.write_frame(frame, stats); +5638 space.pending.paths_blocked = false; +5639 } +5640 +5641 // PATH_CIDS_BLOCKED +5642 while space_id == SpaceId::Data +5643 && !path_exclusive_only +5644 && frame::PathCidsBlocked::SIZE_BOUND <= builder.frame_space_remaining() +5645 { +5646 let Some(path_id) = space.pending.path_cids_blocked.pop_first() else { +5647 break; +5648 }; +5649 let next_seq = match self.rem_cids.get(&path_id) { +5650 Some(cid_queue) => VarInt(cid_queue.active_seq() + 1), +5651 None => VarInt(0), 5652 }; -5653 builder.write_frame(frame, stats); -5654 } -5655 -5656 // RETIRE_CONNECTION_ID -5657 let retire_cid_bound = frame::RetireConnectionId::size_bound(is_multipath_negotiated); -5658 while !path_exclusive_only && builder.frame_space_remaining() > retire_cid_bound { -5659 let (path_id, sequence) = match space.pending.retire_cids.pop() { -5660 Some((PathId::ZERO, seq)) if !is_multipath_negotiated => (None, seq), -5661 Some((path_id, seq)) => (Some(path_id), seq), -5662 None => break, -5663 }; -5664 let frame = frame::RetireConnectionId { path_id, sequence }; -5665 builder.write_frame(frame, stats); -5666 } -5667 -5668 // DATAGRAM -5669 let mut sent_datagrams = false; -5670 while !path_exclusive_only -5671 && builder.frame_space_remaining() > Datagram::SIZE_BOUND -5672 && space_id == SpaceId::Data -5673 { -5674 match self.datagrams.write(builder, stats) { -5675 true => { -5676 sent_datagrams = true; -5677 } -5678 false => break, -5679 } -5680 } -5681 if self.datagrams.send_blocked && sent_datagrams { -5682 self.events.push_back(Event::DatagramsUnblocked); -5683 self.datagrams.send_blocked = false; -5684 } -5685 -5686 let path = &mut self.paths.get_mut(&path_id).expect("known path").data; -5687 -5688 // NEW_TOKEN -5689 if !path_exclusive_only { -5690 while let Some(network_path) = space.pending.new_tokens.pop() { -5691 debug_assert_eq!(space_id, SpaceId::Data); -5692 let ConnectionSide::Server { server_config } = &self.side else { -5693 panic!("NEW_TOKEN frames should not be enqueued by clients"); -5694 }; -5695 -5696 if !network_path.is_probably_same_path(&path.network_path) { -5697 // NEW_TOKEN frames contain tokens bound to a client's IP address, and are only -5698 // useful if used from the same IP address. Thus, we abandon enqueued NEW_TOKEN -5699 // frames upon an path change. Instead, when the new path becomes validated, -5700 // NEW_TOKEN frames may be enqueued for the new path instead. -5701 continue; -5702 } -5703 -5704 let token = Token::new( -5705 TokenPayload::Validation { -5706 ip: network_path.remote.ip(), -5707 issued: server_config.time_source.now(), -5708 }, -5709 &mut self.rng, -5710 ); -5711 let new_token = NewToken { -5712 token: token.encode(&*server_config.token_key).into(), -5713 }; -5714 -5715 if builder.frame_space_remaining() < new_token.size() { -5716 space.pending.new_tokens.push(network_path); -5717 break; -5718 } -5719 -5720 builder.write_frame(new_token, stats); -5721 builder.retransmits_mut().new_tokens.push(network_path); -5722 } -5723 } -5724 -5725 // STREAM -5726 if !path_exclusive_only && space_id == SpaceId::Data { -5727 self.streams -5728 .write_stream_frames(builder, self.config.send_fairness, stats); -5729 } -5730 -5731 // ADD_ADDRESS -5732 while space_id == SpaceId::Data -5733 && !path_exclusive_only -5734 && frame::AddAddress::SIZE_BOUND <= builder.frame_space_remaining() -5735 { -5736 if let Some(added_address) = space.pending.add_address.pop_last() { -5737 builder.write_frame(added_address, stats); -5738 } else { -5739 break; -5740 } -5741 } -5742 -5743 // REMOVE_ADDRESS -5744 while space_id == SpaceId::Data -5745 && !path_exclusive_only -5746 && frame::RemoveAddress::SIZE_BOUND <= builder.frame_space_remaining() -5747 { -5748 if let Some(removed_address) = space.pending.remove_address.pop_last() { -5749 builder.write_frame(removed_address, stats); -5750 } else { -5751 break; -5752 } -5753 } -5754 } -5755 -5756 /// Write pending ACKs into a buffer -5757 fn populate_acks<'a, 'b>( -5758 now: Instant, -5759 receiving_ecn: bool, -5760 path_id: PathId, -5761 space_id: SpaceId, -5762 space: &mut PacketSpace, -5763 is_multipath_negotiated: bool, -5764 builder: &mut PacketBuilder<'a, 'b>, -5765 stats: &mut FrameStats, -5766 ) { -5767 // 0-RTT packets must never carry acks (which would have to be of handshake packets) -5768 debug_assert!(space.crypto.is_some(), "tried to send ACK in 0-RTT"); -5769 -5770 debug_assert!( -5771 is_multipath_negotiated || path_id == PathId::ZERO, -5772 "Only PathId::ZERO allowed without multipath (have {path_id:?})" -5773 ); -5774 if is_multipath_negotiated { -5775 debug_assert!( -5776 space_id == SpaceId::Data || path_id == PathId::ZERO, -5777 "path acks must be sent in 1RTT space (have {space_id:?})" -5778 ); -5779 } -5780 -5781 let pns = space.for_path(path_id); -5782 let ranges = pns.pending_acks.ranges(); -5783 debug_assert!(!ranges.is_empty(), "can not send empty ACK range"); -5784 let ecn = if receiving_ecn { -5785 Some(&pns.ecn_counters) -5786 } else { -5787 None -5788 }; -5789 -5790 let delay_micros = pns.pending_acks.ack_delay(now).as_micros() as u64; -5791 // TODO: This should come from `TransportConfig` if that gets configurable. -5792 let ack_delay_exp = TransportParameters::default().ack_delay_exponent; -5793 let delay = delay_micros >> ack_delay_exp.into_inner(); -5794 -5795 if is_multipath_negotiated && space_id == SpaceId::Data { -5796 if !ranges.is_empty() { -5797 let frame = frame::PathAck::encoder(path_id, delay, ranges, ecn); -5798 builder.write_frame(frame, stats); -5799 } -5800 } else { -5801 builder.write_frame(frame::Ack::encoder(delay, ranges, ecn), stats); -5802 } -5803 } -5804 -5805 fn close_common(&mut self) { -5806 trace!("connection closed"); -5807 self.timers.reset(); -5808 } -5809 -5810 fn set_close_timer(&mut self, now: Instant) { -5811 // QUIC-MULTIPATH § 2.6 Connection Closure: draining for 3*PTO with PTO the max of -5812 // the PTO for all paths. -5813 let pto_max = self.pto_max_path(self.highest_space, true); -5814 self.timers.set( -5815 Timer::Conn(ConnTimer::Close), -5816 now + 3 * pto_max, -5817 self.qlog.with_time(now), -5818 ); -5819 } -5820 -5821 /// Handle transport parameters received from the peer -5822 /// -5823 /// *rem_cid* and *loc_cid* are the source and destination CIDs respectively of the -5824 /// *packet into which the transport parameters arrived. -5825 fn handle_peer_params( -5826 &mut self, -5827 params: TransportParameters, -5828 loc_cid: ConnectionId, -5829 rem_cid: ConnectionId, -5830 now: Instant, -5831 ) -> Result<(), TransportError> { -5832 if Some(self.orig_rem_cid) != params.initial_src_cid -5833 || (self.side.is_client() -5834 && (Some(self.initial_dst_cid) != params.original_dst_cid -5835 || self.retry_src_cid != params.retry_src_cid)) -5836 { -5837 return Err(TransportError::TRANSPORT_PARAMETER_ERROR( -5838 "CID authentication failure", -5839 )); -5840 } -5841 if params.initial_max_path_id.is_some() && (loc_cid.is_empty() || rem_cid.is_empty()) { -5842 return Err(TransportError::PROTOCOL_VIOLATION( -5843 "multipath must not use zero-length CIDs", -5844 )); -5845 } -5846 -5847 self.set_peer_params(params); -5848 self.qlog.emit_peer_transport_params_received(self, now); -5849 -5850 Ok(()) -5851 } -5852 -5853 fn set_peer_params(&mut self, params: TransportParameters) { -5854 self.streams.set_params(&params); -5855 self.idle_timeout = -5856 negotiate_max_idle_timeout(self.config.max_idle_timeout, Some(params.max_idle_timeout)); -5857 trace!("negotiated max idle timeout {:?}", self.idle_timeout); -5858 -5859 if let Some(ref info) = params.preferred_address { -5860 // During the handshake PathId::ZERO exists. -5861 self.rem_cids.get_mut(&PathId::ZERO).expect("not yet abandoned").insert(frame::NewConnectionId { -5862 path_id: None, -5863 sequence: 1, -5864 id: info.connection_id, -5865 reset_token: info.stateless_reset_token, -5866 retire_prior_to: 0, -5867 }) -5868 .expect( -5869 "preferred address CID is the first received, and hence is guaranteed to be legal", -5870 ); -5871 let remote = self.path_data(PathId::ZERO).network_path.remote; -5872 self.set_reset_token(PathId::ZERO, remote, info.stateless_reset_token); -5873 } -5874 self.ack_frequency.peer_max_ack_delay = get_max_ack_delay(&params); -5875 -5876 let mut multipath_enabled = None; -5877 if let (Some(local_max_path_id), Some(remote_max_path_id)) = ( -5878 self.config.get_initial_max_path_id(), -5879 params.initial_max_path_id, -5880 ) { -5881 // multipath is enabled, register the local and remote maximums -5882 self.local_max_path_id = local_max_path_id; -5883 self.remote_max_path_id = remote_max_path_id; -5884 let initial_max_path_id = local_max_path_id.min(remote_max_path_id); -5885 debug!(%initial_max_path_id, "multipath negotiated"); -5886 multipath_enabled = Some(initial_max_path_id); -5887 } -5888 -5889 if let Some((max_locally_allowed_remote_addresses, max_remotely_allowed_remote_addresses)) = -5890 self.config -5891 .max_remote_nat_traversal_addresses -5892 .zip(params.max_remote_nat_traversal_addresses) -5893 { -5894 if let Some(max_initial_paths) = -5895 multipath_enabled.map(|path_id| path_id.saturating_add(1u8)) -5896 { -5897 let max_local_addresses = max_remotely_allowed_remote_addresses.get(); -5898 let max_remote_addresses = max_locally_allowed_remote_addresses.get(); -5899 self.iroh_hp = -5900 iroh_hp::State::new(max_remote_addresses, max_local_addresses, self.side()); -5901 debug!( -5902 %max_remote_addresses, %max_local_addresses, -5903 "iroh hole punching negotiated" -5904 ); -5905 -5906 match self.side() { -5907 Side::Client => { -5908 if max_initial_paths.as_u32() < max_remote_addresses as u32 + 1 { -5909 // in this case the client might try to open `max_remote_addresses` new -5910 // paths, but the current multipath configuration will not allow it -5911 warn!(%max_initial_paths, %max_remote_addresses, "local client configuration might cause nat traversal issues") -5912 } else if max_local_addresses as u64 -5913 > params.active_connection_id_limit.into_inner() -5914 { -5915 // the server allows us to send at most `params.active_connection_id_limit` -5916 // but they might need at least `max_local_addresses` to effectively send -5917 // `PATH_CHALLENGE` frames to each advertised local address -5918 warn!(%max_local_addresses, remote_cid_limit=%params.active_connection_id_limit.into_inner(), "remote server configuration might cause nat traversal issues") -5919 } -5920 } -5921 Side::Server => { -5922 if (max_initial_paths.as_u32() as u64) < crate::LOC_CID_COUNT { -5923 warn!(%max_initial_paths, local_cid_limit=%crate::LOC_CID_COUNT, "local server configuration might cause nat traversal issues") -5924 } -5925 } -5926 } -5927 } else { -5928 debug!("iroh nat traversal enabled for both endpoints, but multipath is missing") -5929 } -5930 } -5931 -5932 self.peer_params = params; -5933 let peer_max_udp_payload_size = -5934 u16::try_from(self.peer_params.max_udp_payload_size.into_inner()).unwrap_or(u16::MAX); -5935 self.path_data_mut(PathId::ZERO) -5936 .mtud -5937 .on_peer_max_udp_payload_size_received(peer_max_udp_payload_size); -5938 } -5939 -5940 /// Decrypts a packet, returning the packet number on success -5941 fn decrypt_packet( -5942 &mut self, -5943 now: Instant, -5944 path_id: PathId, -5945 packet: &mut Packet, -5946 ) -> Result<Option<u64>, Option<TransportError>> { -5947 let result = packet_crypto::decrypt_packet_body( -5948 packet, -5949 path_id, -5950 &self.spaces, -5951 self.zero_rtt_crypto.as_ref(), -5952 self.key_phase, -5953 self.prev_crypto.as_ref(), -5954 self.next_crypto.as_ref(), -5955 )?; -5956 -5957 let result = match result { -5958 Some(r) => r, -5959 None => return Ok(None), -5960 }; -5961 -5962 if result.outgoing_key_update_acked -5963 && let Some(prev) = self.prev_crypto.as_mut() -5964 { -5965 prev.end_packet = Some((result.number, now)); -5966 self.set_key_discard_timer(now, packet.header.space()); -5967 } -5968 -5969 if result.incoming_key_update { -5970 trace!("key update authenticated"); -5971 self.update_keys(Some((result.number, now)), true); -5972 self.set_key_discard_timer(now, packet.header.space()); -5973 } -5974 -5975 Ok(Some(result.number)) -5976 } -5977 -5978 fn update_keys(&mut self, end_packet: Option<(u64, Instant)>, remote: bool) { -5979 trace!("executing key update"); -5980 // Generate keys for the key phase after the one we're switching to, store them in -5981 // `next_crypto`, make the contents of `next_crypto` current, and move the current keys into -5982 // `prev_crypto`. -5983 let new = self -5984 .crypto -5985 .next_1rtt_keys() -5986 .expect("only called for `Data` packets"); -5987 self.key_phase_size = new -5988 .local -5989 .confidentiality_limit() -5990 .saturating_sub(KEY_UPDATE_MARGIN); -5991 let old = mem::replace( -5992 &mut self.spaces[SpaceId::Data] -5993 .crypto -5994 .as_mut() -5995 .unwrap() // safe because update_keys() can only be triggered by short packets -5996 .packet, -5997 mem::replace(self.next_crypto.as_mut().unwrap(), new), -5998 ); -5999 self.spaces[SpaceId::Data] -6000 .iter_paths_mut() -6001 .for_each(|s| s.sent_with_keys = 0); -6002 self.prev_crypto = Some(PrevCrypto { -6003 crypto: old, -6004 end_packet, -6005 update_unacked: remote, -6006 }); -6007 self.key_phase = !self.key_phase; -6008 } -6009 -6010 fn peer_supports_ack_frequency(&self) -> bool { -6011 self.peer_params.min_ack_delay.is_some() -6012 } -6013 -6014 /// Send an IMMEDIATE_ACK frame to the remote endpoint -6015 /// -6016 /// According to the spec, this will result in an error if the remote endpoint does not support -6017 /// the Acknowledgement Frequency extension -6018 pub(crate) fn immediate_ack(&mut self, path_id: PathId) { -6019 debug_assert_eq!( -6020 self.highest_space, -6021 SpaceId::Data, -6022 "immediate ack must be written in the data space" -6023 ); -6024 self.spaces[self.highest_space] -6025 .for_path(path_id) -6026 .immediate_ack_pending = true; -6027 } -6028 -6029 /// Decodes a packet, returning its decrypted payload, so it can be inspected in tests -6030 #[cfg(test)] -6031 pub(crate) fn decode_packet(&self, event: &ConnectionEvent) -> Option<Vec<u8>> { -6032 let (path_id, first_decode, remaining) = match &event.0 { -6033 ConnectionEventInner::Datagram(DatagramConnectionEvent { -6034 path_id, -6035 first_decode, -6036 remaining, -6037 .. -6038 }) => (path_id, first_decode, remaining), -6039 _ => return None, -6040 }; -6041 -6042 if remaining.is_some() { -6043 panic!("Packets should never be coalesced in tests"); -6044 } -6045 -6046 let decrypted_header = packet_crypto::unprotect_header( -6047 first_decode.clone(), -6048 &self.spaces, -6049 self.zero_rtt_crypto.as_ref(), -6050 self.peer_params.stateless_reset_token, -6051 )?; -6052 -6053 let mut packet = decrypted_header.packet?; -6054 packet_crypto::decrypt_packet_body( -6055 &mut packet, -6056 *path_id, -6057 &self.spaces, -6058 self.zero_rtt_crypto.as_ref(), -6059 self.key_phase, -6060 self.prev_crypto.as_ref(), -6061 self.next_crypto.as_ref(), -6062 ) -6063 .ok()?; -6064 -6065 Some(packet.payload.to_vec()) -6066 } -6067 -6068 /// The number of bytes of packets containing retransmittable frames that have not been -6069 /// acknowledged or declared lost. -6070 #[cfg(test)] -6071 pub(crate) fn bytes_in_flight(&self) -> u64 { -6072 // TODO(@divma): consider including for multipath? -6073 self.path_data(PathId::ZERO).in_flight.bytes -6074 } -6075 -6076 /// Number of bytes worth of non-ack-only packets that may be sent -6077 #[cfg(test)] -6078 pub(crate) fn congestion_window(&self) -> u64 { -6079 let path = self.path_data(PathId::ZERO); -6080 path.congestion -6081 .window() -6082 .saturating_sub(path.in_flight.bytes) -6083 } -6084 -6085 /// Whether no timers but keepalive, idle, rtt, pushnewcid, and key discard are running -6086 #[cfg(test)] -6087 pub(crate) fn is_idle(&self) -> bool { -6088 let current_timers = self.timers.values(); -6089 current_timers -6090 .into_iter() -6091 .filter(|(timer, _)| { -6092 !matches!( -6093 timer, -6094 Timer::Conn(ConnTimer::KeepAlive) -6095 | Timer::PerPath(_, PathTimer::PathKeepAlive) -6096 | Timer::Conn(ConnTimer::PushNewCid) -6097 | Timer::Conn(ConnTimer::KeyDiscard) -6098 ) -6099 }) -6100 .min_by_key(|(_, time)| *time) -6101 .is_none_or(|(timer, _)| timer == Timer::Conn(ConnTimer::Idle)) -6102 } -6103 -6104 /// Whether explicit congestion notification is in use on outgoing packets. -6105 #[cfg(test)] -6106 pub(crate) fn using_ecn(&self) -> bool { -6107 self.path_data(PathId::ZERO).sending_ecn -6108 } -6109 -6110 /// The number of received bytes in the current path -6111 #[cfg(test)] -6112 pub(crate) fn total_recvd(&self) -> u64 { -6113 self.path_data(PathId::ZERO).total_recvd -6114 } -6115 -6116 #[cfg(test)] -6117 pub(crate) fn active_local_cid_seq(&self) -> (u64, u64) { -6118 self.local_cid_state -6119 .get(&PathId::ZERO) -6120 .unwrap() -6121 .active_seq() -6122 } -6123 -6124 #[cfg(test)] -6125 #[track_caller] -6126 pub(crate) fn active_local_path_cid_seq(&self, path_id: u32) -> (u64, u64) { -6127 self.local_cid_state -6128 .get(&PathId(path_id)) -6129 .unwrap() -6130 .active_seq() -6131 } -6132 -6133 /// Instruct the peer to replace previously issued CIDs by sending a NEW_CONNECTION_ID frame -6134 /// with updated `retire_prior_to` field set to `v` -6135 #[cfg(test)] -6136 pub(crate) fn rotate_local_cid(&mut self, v: u64, now: Instant) { -6137 let n = self -6138 .local_cid_state -6139 .get_mut(&PathId::ZERO) -6140 .unwrap() -6141 .assign_retire_seq(v); -6142 self.endpoint_events -6143 .push_back(EndpointEventInner::NeedIdentifiers(PathId::ZERO, now, n)); -6144 } -6145 -6146 /// Check the current active remote CID sequence for `PathId::ZERO` -6147 #[cfg(test)] -6148 pub(crate) fn active_rem_cid_seq(&self) -> u64 { -6149 self.rem_cids.get(&PathId::ZERO).unwrap().active_seq() -6150 } -6151 -6152 /// Returns the detected maximum udp payload size for the current path -6153 #[cfg(test)] -6154 pub(crate) fn path_mtu(&self, path_id: PathId) -> u16 { -6155 self.path_data(path_id).current_mtu() -6156 } -6157 -6158 /// Triggers path validation on all paths -6159 #[cfg(test)] -6160 pub(crate) fn trigger_path_validation(&mut self) { -6161 for path in self.paths.values_mut() { -6162 path.data.send_new_challenge = true; -6163 } -6164 } -6165 -6166 /// Whether we have 1-RTT data to send -6167 /// -6168 /// This checks for frames that can only be sent in the data space (1-RTT): -6169 /// - Pending PATH_CHALLENGE frames on the active and previous path if just migrated. -6170 /// - Pending PATH_RESPONSE frames. -6171 /// - Pending data to send in STREAM frames. -6172 /// - Pending DATAGRAM frames to send. -6173 /// -6174 /// See also [`PacketSpace::can_send`] which keeps track of all other frame types that -6175 /// may need to be sent. -6176 fn can_send_1rtt(&self, path_id: PathId, max_size: usize) -> SendableFrames { -6177 let path_exclusive = self.paths.get(&path_id).is_some_and(|path| { -6178 path.data.send_new_challenge -6179 || path -6180 .prev -6181 .as_ref() -6182 .is_some_and(|(_, path)| path.send_new_challenge) -6183 || !path.data.path_responses.is_empty() -6184 }); -6185 let other = self.streams.can_send_stream_data() -6186 || self -6187 .datagrams -6188 .outgoing -6189 .front() -6190 .is_some_and(|x| x.size(true) <= max_size); -6191 SendableFrames { -6192 acks: false, -6193 other, -6194 close: false, -6195 path_exclusive, -6196 } -6197 } -6198 -6199 /// Terminate the connection instantly, without sending a close packet -6200 fn kill(&mut self, reason: ConnectionError) { -6201 self.close_common(); -6202 self.state.move_to_drained(Some(reason)); -6203 self.endpoint_events.push_back(EndpointEventInner::Drained); -6204 } -6205 -6206 /// Storage size required for the largest packet that can be transmitted on all currently -6207 /// available paths -6208 /// -6209 /// Buffers passed to [`Connection::poll_transmit`] should be at least this large. -6210 /// -6211 /// When multipath is enabled, this value is the minimum MTU across all available paths. -6212 pub fn current_mtu(&self) -> u16 { -6213 self.paths -6214 .iter() -6215 .filter(|&(path_id, _path_state)| !self.abandoned_paths.contains(path_id)) -6216 .map(|(_path_id, path_state)| path_state.data.current_mtu()) -6217 .min() -6218 .expect("There is always at least one available path") -6219 } -6220 -6221 /// Size of non-frame data for a 1-RTT packet -6222 /// -6223 /// Quantifies space consumed by the QUIC header and AEAD tag. All other bytes in a packet are -6224 /// frames. Changes if the length of the remote connection ID changes, which is expected to be -6225 /// rare. If `pn` is specified, may additionally change unpredictably due to variations in -6226 /// latency and packet loss. -6227 fn predict_1rtt_overhead(&mut self, pn: u64, path: PathId) -> usize { -6228 let pn_len = PacketNumber::new( -6229 pn, -6230 self.spaces[SpaceId::Data] -6231 .for_path(path) -6232 .largest_acked_packet -6233 .unwrap_or(0), -6234 ) -6235 .len(); -6236 -6237 // 1 byte for flags -6238 1 + self -6239 .rem_cids -6240 .get(&path) -6241 .map(|cids| cids.active().len()) -6242 .unwrap_or(20) // Max CID len in QUIC v1 -6243 + pn_len -6244 + self.tag_len_1rtt() -6245 } -6246 -6247 fn predict_1rtt_overhead_no_pn(&self) -> usize { -6248 let pn_len = 4; +5653 let frame = frame::PathCidsBlocked { path_id, next_seq }; +5654 builder.write_frame(frame, stats); +5655 } +5656 +5657 // RESET_STREAM, STOP_SENDING, MAX_DATA, MAX_STREAM_DATA, MAX_STREAMS +5658 if space_id == SpaceId::Data && !path_exclusive_only { +5659 self.streams +5660 .write_control_frames(builder, &mut space.pending, stats); +5661 } +5662 +5663 // NEW_CONNECTION_ID +5664 let cid_len = self +5665 .local_cid_state +5666 .values() +5667 .map(|cid_state| cid_state.cid_len()) +5668 .max() +5669 .expect("some local CID state must exist"); +5670 let new_cid_size_bound = +5671 frame::NewConnectionId::size_bound(is_multipath_negotiated, cid_len); +5672 while !path_exclusive_only && builder.frame_space_remaining() > new_cid_size_bound { +5673 let issued = match space.pending.new_cids.pop() { +5674 Some(x) => x, +5675 None => break, +5676 }; +5677 let retire_prior_to = self +5678 .local_cid_state +5679 .get(&issued.path_id) +5680 .map(|cid_state| cid_state.retire_prior_to()) +5681 .unwrap_or_else(|| panic!("missing local CID state for path={}", issued.path_id)); +5682 +5683 let cid_path_id = match is_multipath_negotiated { +5684 true => Some(issued.path_id), +5685 false => { +5686 debug_assert_eq!(issued.path_id, PathId::ZERO); +5687 None +5688 } +5689 }; +5690 let frame = frame::NewConnectionId { +5691 path_id: cid_path_id, +5692 sequence: issued.sequence, +5693 retire_prior_to, +5694 id: issued.id, +5695 reset_token: issued.reset_token, +5696 }; +5697 builder.write_frame(frame, stats); +5698 } +5699 +5700 // RETIRE_CONNECTION_ID +5701 let retire_cid_bound = frame::RetireConnectionId::size_bound(is_multipath_negotiated); +5702 while !path_exclusive_only && builder.frame_space_remaining() > retire_cid_bound { +5703 let (path_id, sequence) = match space.pending.retire_cids.pop() { +5704 Some((PathId::ZERO, seq)) if !is_multipath_negotiated => (None, seq), +5705 Some((path_id, seq)) => (Some(path_id), seq), +5706 None => break, +5707 }; +5708 let frame = frame::RetireConnectionId { path_id, sequence }; +5709 builder.write_frame(frame, stats); +5710 } +5711 +5712 // DATAGRAM +5713 let mut sent_datagrams = false; +5714 while !path_exclusive_only +5715 && builder.frame_space_remaining() > Datagram::SIZE_BOUND +5716 && space_id == SpaceId::Data +5717 { +5718 match self.datagrams.write(builder, stats) { +5719 true => { +5720 sent_datagrams = true; +5721 } +5722 false => break, +5723 } +5724 } +5725 if self.datagrams.send_blocked && sent_datagrams { +5726 self.events.push_back(Event::DatagramsUnblocked); +5727 self.datagrams.send_blocked = false; +5728 } +5729 +5730 let path = &mut self.paths.get_mut(&path_id).expect("known path").data; +5731 +5732 // NEW_TOKEN +5733 if !path_exclusive_only { +5734 while let Some(network_path) = space.pending.new_tokens.pop() { +5735 debug_assert_eq!(space_id, SpaceId::Data); +5736 let ConnectionSide::Server { server_config } = &self.side else { +5737 panic!("NEW_TOKEN frames should not be enqueued by clients"); +5738 }; +5739 +5740 if !network_path.is_probably_same_path(&path.network_path) { +5741 // NEW_TOKEN frames contain tokens bound to a client's IP address, and are only +5742 // useful if used from the same IP address. Thus, we abandon enqueued NEW_TOKEN +5743 // frames upon an path change. Instead, when the new path becomes validated, +5744 // NEW_TOKEN frames may be enqueued for the new path instead. +5745 continue; +5746 } +5747 +5748 let token = Token::new( +5749 TokenPayload::Validation { +5750 ip: network_path.remote.ip(), +5751 issued: server_config.time_source.now(), +5752 }, +5753 &mut self.rng, +5754 ); +5755 let new_token = NewToken { +5756 token: token.encode(&*server_config.token_key).into(), +5757 }; +5758 +5759 if builder.frame_space_remaining() < new_token.size() { +5760 space.pending.new_tokens.push(network_path); +5761 break; +5762 } +5763 +5764 builder.write_frame(new_token, stats); +5765 builder.retransmits_mut().new_tokens.push(network_path); +5766 } +5767 } +5768 +5769 // STREAM +5770 if !path_exclusive_only && space_id == SpaceId::Data { +5771 self.streams +5772 .write_stream_frames(builder, self.config.send_fairness, stats); +5773 } +5774 +5775 // ADD_ADDRESS +5776 while space_id == SpaceId::Data +5777 && !path_exclusive_only +5778 && frame::AddAddress::SIZE_BOUND <= builder.frame_space_remaining() +5779 { +5780 if let Some(added_address) = space.pending.add_address.pop_last() { +5781 builder.write_frame(added_address, stats); +5782 } else { +5783 break; +5784 } +5785 } +5786 +5787 // REMOVE_ADDRESS +5788 while space_id == SpaceId::Data +5789 && !path_exclusive_only +5790 && frame::RemoveAddress::SIZE_BOUND <= builder.frame_space_remaining() +5791 { +5792 if let Some(removed_address) = space.pending.remove_address.pop_last() { +5793 builder.write_frame(removed_address, stats); +5794 } else { +5795 break; +5796 } +5797 } +5798 } +5799 +5800 /// Write pending ACKs into a buffer +5801 fn populate_acks<'a, 'b>( +5802 now: Instant, +5803 receiving_ecn: bool, +5804 path_id: PathId, +5805 space_id: SpaceId, +5806 space: &mut PacketSpace, +5807 is_multipath_negotiated: bool, +5808 builder: &mut PacketBuilder<'a, 'b>, +5809 stats: &mut FrameStats, +5810 ) { +5811 // 0-RTT packets must never carry acks (which would have to be of handshake packets) +5812 debug_assert!(space.crypto.is_some(), "tried to send ACK in 0-RTT"); +5813 +5814 debug_assert!( +5815 is_multipath_negotiated || path_id == PathId::ZERO, +5816 "Only PathId::ZERO allowed without multipath (have {path_id:?})" +5817 ); +5818 if is_multipath_negotiated { +5819 debug_assert!( +5820 space_id == SpaceId::Data || path_id == PathId::ZERO, +5821 "path acks must be sent in 1RTT space (have {space_id:?})" +5822 ); +5823 } +5824 +5825 let pns = space.for_path(path_id); +5826 let ranges = pns.pending_acks.ranges(); +5827 debug_assert!(!ranges.is_empty(), "can not send empty ACK range"); +5828 let ecn = if receiving_ecn { +5829 Some(&pns.ecn_counters) +5830 } else { +5831 None +5832 }; +5833 +5834 let delay_micros = pns.pending_acks.ack_delay(now).as_micros() as u64; +5835 // TODO: This should come from `TransportConfig` if that gets configurable. +5836 let ack_delay_exp = TransportParameters::default().ack_delay_exponent; +5837 let delay = delay_micros >> ack_delay_exp.into_inner(); +5838 +5839 if is_multipath_negotiated && space_id == SpaceId::Data { +5840 if !ranges.is_empty() { +5841 let frame = frame::PathAck::encoder(path_id, delay, ranges, ecn); +5842 builder.write_frame(frame, stats); +5843 } +5844 } else { +5845 builder.write_frame(frame::Ack::encoder(delay, ranges, ecn), stats); +5846 } +5847 } +5848 +5849 fn close_common(&mut self) { +5850 trace!("connection closed"); +5851 self.timers.reset(); +5852 } +5853 +5854 fn set_close_timer(&mut self, now: Instant) { +5855 // QUIC-MULTIPATH § 2.6 Connection Closure: draining for 3*PTO with PTO the max of +5856 // the PTO for all paths. +5857 let pto_max = self.pto_max_path(self.highest_space, true); +5858 self.timers.set( +5859 Timer::Conn(ConnTimer::Close), +5860 now + 3 * pto_max, +5861 self.qlog.with_time(now), +5862 ); +5863 } +5864 +5865 /// Handle transport parameters received from the peer +5866 /// +5867 /// *rem_cid* and *loc_cid* are the source and destination CIDs respectively of the +5868 /// *packet into which the transport parameters arrived. +5869 fn handle_peer_params( +5870 &mut self, +5871 params: TransportParameters, +5872 loc_cid: ConnectionId, +5873 rem_cid: ConnectionId, +5874 now: Instant, +5875 ) -> Result<(), TransportError> { +5876 if Some(self.orig_rem_cid) != params.initial_src_cid +5877 || (self.side.is_client() +5878 && (Some(self.initial_dst_cid) != params.original_dst_cid +5879 || self.retry_src_cid != params.retry_src_cid)) +5880 { +5881 return Err(TransportError::TRANSPORT_PARAMETER_ERROR( +5882 "CID authentication failure", +5883 )); +5884 } +5885 if params.initial_max_path_id.is_some() && (loc_cid.is_empty() || rem_cid.is_empty()) { +5886 return Err(TransportError::PROTOCOL_VIOLATION( +5887 "multipath must not use zero-length CIDs", +5888 )); +5889 } +5890 +5891 self.set_peer_params(params); +5892 self.qlog.emit_peer_transport_params_received(self, now); +5893 +5894 Ok(()) +5895 } +5896 +5897 fn set_peer_params(&mut self, params: TransportParameters) { +5898 self.streams.set_params(&params); +5899 self.idle_timeout = +5900 negotiate_max_idle_timeout(self.config.max_idle_timeout, Some(params.max_idle_timeout)); +5901 trace!("negotiated max idle timeout {:?}", self.idle_timeout); +5902 +5903 if let Some(ref info) = params.preferred_address { +5904 // During the handshake PathId::ZERO exists. +5905 self.rem_cids.get_mut(&PathId::ZERO).expect("not yet abandoned").insert(frame::NewConnectionId { +5906 path_id: None, +5907 sequence: 1, +5908 id: info.connection_id, +5909 reset_token: info.stateless_reset_token, +5910 retire_prior_to: 0, +5911 }) +5912 .expect( +5913 "preferred address CID is the first received, and hence is guaranteed to be legal", +5914 ); +5915 let remote = self.path_data(PathId::ZERO).network_path.remote; +5916 self.set_reset_token(PathId::ZERO, remote, info.stateless_reset_token); +5917 } +5918 self.ack_frequency.peer_max_ack_delay = get_max_ack_delay(&params); +5919 +5920 let mut multipath_enabled = None; +5921 if let (Some(local_max_path_id), Some(remote_max_path_id)) = ( +5922 self.config.get_initial_max_path_id(), +5923 params.initial_max_path_id, +5924 ) { +5925 // multipath is enabled, register the local and remote maximums +5926 self.local_max_path_id = local_max_path_id; +5927 self.remote_max_path_id = remote_max_path_id; +5928 let initial_max_path_id = local_max_path_id.min(remote_max_path_id); +5929 debug!(%initial_max_path_id, "multipath negotiated"); +5930 multipath_enabled = Some(initial_max_path_id); +5931 } +5932 +5933 if let Some((max_locally_allowed_remote_addresses, max_remotely_allowed_remote_addresses)) = +5934 self.config +5935 .max_remote_nat_traversal_addresses +5936 .zip(params.max_remote_nat_traversal_addresses) +5937 { +5938 if let Some(max_initial_paths) = +5939 multipath_enabled.map(|path_id| path_id.saturating_add(1u8)) +5940 { +5941 let max_local_addresses = max_remotely_allowed_remote_addresses.get(); +5942 let max_remote_addresses = max_locally_allowed_remote_addresses.get(); +5943 self.iroh_hp = +5944 iroh_hp::State::new(max_remote_addresses, max_local_addresses, self.side()); +5945 debug!( +5946 %max_remote_addresses, %max_local_addresses, +5947 "iroh hole punching negotiated" +5948 ); +5949 +5950 match self.side() { +5951 Side::Client => { +5952 if max_initial_paths.as_u32() < max_remote_addresses as u32 + 1 { +5953 // in this case the client might try to open `max_remote_addresses` new +5954 // paths, but the current multipath configuration will not allow it +5955 warn!(%max_initial_paths, %max_remote_addresses, "local client configuration might cause nat traversal issues") +5956 } else if max_local_addresses as u64 +5957 > params.active_connection_id_limit.into_inner() +5958 { +5959 // the server allows us to send at most `params.active_connection_id_limit` +5960 // but they might need at least `max_local_addresses` to effectively send +5961 // `PATH_CHALLENGE` frames to each advertised local address +5962 warn!(%max_local_addresses, remote_cid_limit=%params.active_connection_id_limit.into_inner(), "remote server configuration might cause nat traversal issues") +5963 } +5964 } +5965 Side::Server => { +5966 if (max_initial_paths.as_u32() as u64) < crate::LOC_CID_COUNT { +5967 warn!(%max_initial_paths, local_cid_limit=%crate::LOC_CID_COUNT, "local server configuration might cause nat traversal issues") +5968 } +5969 } +5970 } +5971 } else { +5972 debug!("iroh nat traversal enabled for both endpoints, but multipath is missing") +5973 } +5974 } +5975 +5976 self.peer_params = params; +5977 let peer_max_udp_payload_size = +5978 u16::try_from(self.peer_params.max_udp_payload_size.into_inner()).unwrap_or(u16::MAX); +5979 self.path_data_mut(PathId::ZERO) +5980 .mtud +5981 .on_peer_max_udp_payload_size_received(peer_max_udp_payload_size); +5982 } +5983 +5984 /// Decrypts a packet, returning the packet number on success +5985 fn decrypt_packet( +5986 &mut self, +5987 now: Instant, +5988 path_id: PathId, +5989 packet: &mut Packet, +5990 ) -> Result<Option<u64>, Option<TransportError>> { +5991 let result = packet_crypto::decrypt_packet_body( +5992 packet, +5993 path_id, +5994 &self.spaces, +5995 self.zero_rtt_crypto.as_ref(), +5996 self.key_phase, +5997 self.prev_crypto.as_ref(), +5998 self.next_crypto.as_ref(), +5999 )?; +6000 +6001 let result = match result { +6002 Some(r) => r, +6003 None => return Ok(None), +6004 }; +6005 +6006 if result.outgoing_key_update_acked +6007 && let Some(prev) = self.prev_crypto.as_mut() +6008 { +6009 prev.end_packet = Some((result.number, now)); +6010 self.set_key_discard_timer(now, packet.header.space()); +6011 } +6012 +6013 if result.incoming_key_update { +6014 trace!("key update authenticated"); +6015 self.update_keys(Some((result.number, now)), true); +6016 self.set_key_discard_timer(now, packet.header.space()); +6017 } +6018 +6019 Ok(Some(result.number)) +6020 } +6021 +6022 fn update_keys(&mut self, end_packet: Option<(u64, Instant)>, remote: bool) { +6023 trace!("executing key update"); +6024 // Generate keys for the key phase after the one we're switching to, store them in +6025 // `next_crypto`, make the contents of `next_crypto` current, and move the current keys into +6026 // `prev_crypto`. +6027 let new = self +6028 .crypto +6029 .next_1rtt_keys() +6030 .expect("only called for `Data` packets"); +6031 self.key_phase_size = new +6032 .local +6033 .confidentiality_limit() +6034 .saturating_sub(KEY_UPDATE_MARGIN); +6035 let old = mem::replace( +6036 &mut self.spaces[SpaceId::Data] +6037 .crypto +6038 .as_mut() +6039 .unwrap() // safe because update_keys() can only be triggered by short packets +6040 .packet, +6041 mem::replace(self.next_crypto.as_mut().unwrap(), new), +6042 ); +6043 self.spaces[SpaceId::Data] +6044 .iter_paths_mut() +6045 .for_each(|s| s.sent_with_keys = 0); +6046 self.prev_crypto = Some(PrevCrypto { +6047 crypto: old, +6048 end_packet, +6049 update_unacked: remote, +6050 }); +6051 self.key_phase = !self.key_phase; +6052 } +6053 +6054 fn peer_supports_ack_frequency(&self) -> bool { +6055 self.peer_params.min_ack_delay.is_some() +6056 } +6057 +6058 /// Send an IMMEDIATE_ACK frame to the remote endpoint +6059 /// +6060 /// According to the spec, this will result in an error if the remote endpoint does not support +6061 /// the Acknowledgement Frequency extension +6062 pub(crate) fn immediate_ack(&mut self, path_id: PathId) { +6063 debug_assert_eq!( +6064 self.highest_space, +6065 SpaceId::Data, +6066 "immediate ack must be written in the data space" +6067 ); +6068 self.spaces[self.highest_space] +6069 .for_path(path_id) +6070 .immediate_ack_pending = true; +6071 } +6072 +6073 /// Decodes a packet, returning its decrypted payload, so it can be inspected in tests +6074 #[cfg(test)] +6075 pub(crate) fn decode_packet(&self, event: &ConnectionEvent) -> Option<Vec<u8>> { +6076 let (path_id, first_decode, remaining) = match &event.0 { +6077 ConnectionEventInner::Datagram(DatagramConnectionEvent { +6078 path_id, +6079 first_decode, +6080 remaining, +6081 .. +6082 }) => (path_id, first_decode, remaining), +6083 _ => return None, +6084 }; +6085 +6086 if remaining.is_some() { +6087 panic!("Packets should never be coalesced in tests"); +6088 } +6089 +6090 let decrypted_header = packet_crypto::unprotect_header( +6091 first_decode.clone(), +6092 &self.spaces, +6093 self.zero_rtt_crypto.as_ref(), +6094 self.peer_params.stateless_reset_token, +6095 )?; +6096 +6097 let mut packet = decrypted_header.packet?; +6098 packet_crypto::decrypt_packet_body( +6099 &mut packet, +6100 *path_id, +6101 &self.spaces, +6102 self.zero_rtt_crypto.as_ref(), +6103 self.key_phase, +6104 self.prev_crypto.as_ref(), +6105 self.next_crypto.as_ref(), +6106 ) +6107 .ok()?; +6108 +6109 Some(packet.payload.to_vec()) +6110 } +6111 +6112 /// The number of bytes of packets containing retransmittable frames that have not been +6113 /// acknowledged or declared lost. +6114 #[cfg(test)] +6115 pub(crate) fn bytes_in_flight(&self) -> u64 { +6116 // TODO(@divma): consider including for multipath? +6117 self.path_data(PathId::ZERO).in_flight.bytes +6118 } +6119 +6120 /// Number of bytes worth of non-ack-only packets that may be sent +6121 #[cfg(test)] +6122 pub(crate) fn congestion_window(&self) -> u64 { +6123 let path = self.path_data(PathId::ZERO); +6124 path.congestion +6125 .window() +6126 .saturating_sub(path.in_flight.bytes) +6127 } +6128 +6129 /// Whether no timers but keepalive, idle, rtt, pushnewcid, and key discard are running +6130 #[cfg(test)] +6131 pub(crate) fn is_idle(&self) -> bool { +6132 let current_timers = self.timers.values(); +6133 current_timers +6134 .into_iter() +6135 .filter(|(timer, _)| { +6136 !matches!( +6137 timer, +6138 Timer::Conn(ConnTimer::KeepAlive) +6139 | Timer::PerPath(_, PathTimer::PathKeepAlive) +6140 | Timer::Conn(ConnTimer::PushNewCid) +6141 | Timer::Conn(ConnTimer::KeyDiscard) +6142 ) +6143 }) +6144 .min_by_key(|(_, time)| *time) +6145 .is_none_or(|(timer, _)| timer == Timer::Conn(ConnTimer::Idle)) +6146 } +6147 +6148 /// Whether explicit congestion notification is in use on outgoing packets. +6149 #[cfg(test)] +6150 pub(crate) fn using_ecn(&self) -> bool { +6151 self.path_data(PathId::ZERO).sending_ecn +6152 } +6153 +6154 /// The number of received bytes in the current path +6155 #[cfg(test)] +6156 pub(crate) fn total_recvd(&self) -> u64 { +6157 self.path_data(PathId::ZERO).total_recvd +6158 } +6159 +6160 #[cfg(test)] +6161 pub(crate) fn active_local_cid_seq(&self) -> (u64, u64) { +6162 self.local_cid_state +6163 .get(&PathId::ZERO) +6164 .unwrap() +6165 .active_seq() +6166 } +6167 +6168 #[cfg(test)] +6169 #[track_caller] +6170 pub(crate) fn active_local_path_cid_seq(&self, path_id: u32) -> (u64, u64) { +6171 self.local_cid_state +6172 .get(&PathId(path_id)) +6173 .unwrap() +6174 .active_seq() +6175 } +6176 +6177 /// Instruct the peer to replace previously issued CIDs by sending a NEW_CONNECTION_ID frame +6178 /// with updated `retire_prior_to` field set to `v` +6179 #[cfg(test)] +6180 pub(crate) fn rotate_local_cid(&mut self, v: u64, now: Instant) { +6181 let n = self +6182 .local_cid_state +6183 .get_mut(&PathId::ZERO) +6184 .unwrap() +6185 .assign_retire_seq(v); +6186 self.endpoint_events +6187 .push_back(EndpointEventInner::NeedIdentifiers(PathId::ZERO, now, n)); +6188 } +6189 +6190 /// Check the current active remote CID sequence for `PathId::ZERO` +6191 #[cfg(test)] +6192 pub(crate) fn active_rem_cid_seq(&self) -> u64 { +6193 self.rem_cids.get(&PathId::ZERO).unwrap().active_seq() +6194 } +6195 +6196 /// Returns the detected maximum udp payload size for the current path +6197 #[cfg(test)] +6198 pub(crate) fn path_mtu(&self, path_id: PathId) -> u16 { +6199 self.path_data(path_id).current_mtu() +6200 } +6201 +6202 /// Triggers path validation on all paths +6203 #[cfg(test)] +6204 pub(crate) fn trigger_path_validation(&mut self) { +6205 for path in self.paths.values_mut() { +6206 path.data.send_new_challenge = true; +6207 } +6208 } +6209 +6210 /// Whether we have 1-RTT data to send +6211 /// +6212 /// This checks for frames that can only be sent in the data space (1-RTT): +6213 /// - Pending PATH_CHALLENGE frames on the active and previous path if just migrated. +6214 /// - Pending PATH_RESPONSE frames. +6215 /// - Pending data to send in STREAM frames. +6216 /// - Pending DATAGRAM frames to send. +6217 /// +6218 /// See also [`PacketSpace::can_send`] which keeps track of all other frame types that +6219 /// may need to be sent. +6220 fn can_send_1rtt(&self, path_id: PathId, max_size: usize) -> SendableFrames { +6221 let path_exclusive = self.paths.get(&path_id).is_some_and(|path| { +6222 path.data.send_new_challenge +6223 || path +6224 .prev +6225 .as_ref() +6226 .is_some_and(|(_, path)| path.send_new_challenge) +6227 || !path.data.path_responses.is_empty() +6228 }); +6229 let other = self.streams.can_send_stream_data() +6230 || self +6231 .datagrams +6232 .outgoing +6233 .front() +6234 .is_some_and(|x| x.size(true) <= max_size); +6235 SendableFrames { +6236 acks: false, +6237 other, +6238 close: false, +6239 path_exclusive, +6240 } +6241 } +6242 +6243 /// Terminate the connection instantly, without sending a close packet +6244 fn kill(&mut self, reason: ConnectionError) { +6245 self.close_common(); +6246 self.state.move_to_drained(Some(reason)); +6247 self.endpoint_events.push_back(EndpointEventInner::Drained); +6248 } 6249 -6250 let cid_len = self -6251 .rem_cids -6252 .values() -6253 .map(|cids| cids.active().len()) -6254 .max() -6255 .unwrap_or(20); // Max CID len in QUIC v1 -6256 -6257 // 1 byte for flags -6258 1 + cid_len + pn_len + self.tag_len_1rtt() -6259 } -6260 -6261 fn tag_len_1rtt(&self) -> usize { -6262 let key = match self.spaces[SpaceId::Data].crypto.as_ref() { -6263 Some(crypto) => Some(&*crypto.packet.local), -6264 None => self.zero_rtt_crypto.as_ref().map(|x| &*x.packet), -6265 }; -6266 // If neither Data nor 0-RTT keys are available, make a reasonable tag length guess. As of -6267 // this writing, all QUIC cipher suites use 16-byte tags. We could return `None` instead, -6268 // but that would needlessly prevent sending datagrams during 0-RTT. -6269 key.map_or(16, |x| x.tag_len()) -6270 } -6271 -6272 /// Mark the path as validated, and enqueue NEW_TOKEN frames to be sent as appropriate -6273 fn on_path_validated(&mut self, path_id: PathId) { -6274 self.path_data_mut(path_id).validated = true; -6275 let ConnectionSide::Server { server_config } = &self.side else { -6276 return; -6277 }; -6278 let network_path = self.path_data(path_id).network_path; -6279 let new_tokens = &mut self.spaces[SpaceId::Data as usize].pending.new_tokens; -6280 new_tokens.clear(); -6281 for _ in 0..server_config.validation_token.sent { -6282 new_tokens.push(network_path); -6283 } -6284 } -6285 -6286 /// Handle new path status information: PATH_STATUS_AVAILABLE, PATH_STATUS_BACKUP -6287 fn on_path_status(&mut self, path_id: PathId, status: PathStatus, status_seq_no: VarInt) { -6288 if let Some(path) = self.paths.get_mut(&path_id) { -6289 path.data.status.remote_update(status, status_seq_no); -6290 } else { -6291 debug!("PATH_STATUS_AVAILABLE received unknown path {:?}", path_id); -6292 } -6293 self.events.push_back( -6294 PathEvent::RemoteStatus { -6295 id: path_id, -6296 status, -6297 } -6298 .into(), -6299 ); -6300 } -6301 -6302 /// Returns the maximum [`PathId`] to be used for sending in this connection. -6303 /// -6304 /// This is calculated as minimum between the local and remote's maximums when multipath is -6305 /// enabled, or `None` when disabled. -6306 /// -6307 /// For data that's received, we should use [`Self::local_max_path_id`] instead. -6308 /// The reasoning is that the remote might already have updated to its own newer -6309 /// [`Self::max_path_id`] after sending out a `MAX_PATH_ID` frame, but it got re-ordered. -6310 fn max_path_id(&self) -> Option<PathId> { -6311 if self.is_multipath_negotiated() { -6312 Some(self.remote_max_path_id.min(self.local_max_path_id)) -6313 } else { -6314 None -6315 } -6316 } -6317 -6318 /// Add addresses the local endpoint considers are reachable for nat traversal -6319 pub fn add_nat_traversal_address(&mut self, address: SocketAddr) -> Result<(), iroh_hp::Error> { -6320 if let Some(added) = self.iroh_hp.add_local_address(address)? { -6321 self.spaces[SpaceId::Data].pending.add_address.insert(added); -6322 }; -6323 Ok(()) -6324 } -6325 -6326 /// Removes an address the endpoing no longer considers reachable for nat traversal -6327 /// -6328 /// Addresses not present in the set will be silently ignored. -6329 pub fn remove_nat_traversal_address( -6330 &mut self, -6331 address: SocketAddr, -6332 ) -> Result<(), iroh_hp::Error> { -6333 if let Some(removed) = self.iroh_hp.remove_local_address(address)? { -6334 self.spaces[SpaceId::Data] -6335 .pending -6336 .remove_address -6337 .insert(removed); -6338 } -6339 Ok(()) -6340 } -6341 -6342 /// Get the current local nat traversal addresses -6343 pub fn get_local_nat_traversal_addresses(&self) -> Result<Vec<SocketAddr>, iroh_hp::Error> { -6344 self.iroh_hp.get_local_nat_traversal_addresses() -6345 } -6346 -6347 /// Get the currently advertised nat traversal addresses by the server -6348 pub fn get_remote_nat_traversal_addresses(&self) -> Result<Vec<SocketAddr>, iroh_hp::Error> { -6349 Ok(self -6350 .iroh_hp -6351 .client_side()? -6352 .get_remote_nat_traversal_addresses()) -6353 } -6354 -6355 /// Attempts to open a path for nat traversal. -6356 /// -6357 /// `ipv6` indicates if the path should be opened using an IPV6 remote. If the address is -6358 /// ignored, it will return `None`. -6359 /// -6360 /// On success returns the [`PathId`] and remote address of the path, as well as whether the path -6361 /// existed for the adjusted remote. -6362 fn open_nat_traversal_path( -6363 &mut self, -6364 now: Instant, -6365 (ip, port): (IpAddr, u16), -6366 ipv6: bool, -6367 ) -> Result<Option<(PathId, SocketAddr, bool)>, PathError> { -6368 // If this endpoint is an IPv6 endpoint we use IPv6 addresses for all remotes. -6369 let remote = match ip { -6370 IpAddr::V4(addr) if ipv6 => SocketAddr::new(addr.to_ipv6_mapped().into(), port), -6371 IpAddr::V4(addr) => SocketAddr::new(addr.into(), port), -6372 IpAddr::V6(_) if ipv6 => SocketAddr::new(ip, port), -6373 IpAddr::V6(_) => { -6374 trace!("not using IPv6 nat candidate for IPv4 socket"); -6375 return Ok(None); -6376 } -6377 }; -6378 // TODO(matheus23): Probe the correct 4-tuple, instead of only a remote address? -6379 // By specifying None, we do two things: 1. open_path_ensure won't generate two -6380 // paths to the same remote and 2. we let the OS choose which interface to use for -6381 // sending on that path. -6382 let network_path = FourTuple { -6383 remote, -6384 local_ip: None, -6385 }; -6386 match self.open_path_ensure(network_path, PathStatus::Backup, now) { -6387 Ok((path_id, path_was_known)) => { -6388 if path_was_known { -6389 trace!(%path_id, %remote, "nat traversal: path existed for remote"); -6390 } -6391 Ok(Some((path_id, remote, path_was_known))) -6392 } -6393 Err(e) => { -6394 debug!(%remote, %e, "nat traversal: failed to probe remote"); -6395 Err(e) -6396 } -6397 } -6398 } -6399 -6400 /// Initiates a new nat traversal round -6401 /// -6402 /// A nat traversal round involves advertising the client's local addresses in `REACH_OUT` -6403 /// frames, and initiating probing of the known remote addresses. When a new round is -6404 /// initiated, the previous one is cancelled, and paths that have not been opened are closed. -6405 /// -6406 /// Returns the server addresses that are now being probed. -6407 /// If addresses fail due to spurious errors, these might succeed later and not be returned in -6408 /// this set. -6409 pub fn initiate_nat_traversal_round( -6410 &mut self, -6411 now: Instant, -6412 ) -> Result<Vec<SocketAddr>, iroh_hp::Error> { -6413 if self.state.is_closed() { -6414 return Err(iroh_hp::Error::Closed); -6415 } -6416 -6417 let client_state = self.iroh_hp.client_side_mut()?; -6418 let iroh_hp::NatTraversalRound { -6419 new_round, -6420 reach_out_at, -6421 addresses_to_probe, -6422 prev_round_path_ids, -6423 } = client_state.initiate_nat_traversal_round()?; -6424 -6425 self.spaces[SpaceId::Data].pending.reach_out = Some((new_round, reach_out_at)); -6426 -6427 for path_id in prev_round_path_ids { -6428 // TODO(@divma): this sounds reasonable but we need if this actually works for the -6429 // purposes of the protocol -6430 let validated = self -6431 .path(path_id) -6432 .map(|path| path.validated) -6433 .unwrap_or(false); -6434 -6435 if !validated { -6436 let _ = self.close_path( -6437 now, -6438 path_id, -6439 TransportErrorCode::APPLICATION_ABANDON_PATH.into(), -6440 ); -6441 } -6442 } +6250 /// Storage size required for the largest packet that can be transmitted on all currently +6251 /// available paths +6252 /// +6253 /// Buffers passed to [`Connection::poll_transmit`] should be at least this large. +6254 /// +6255 /// When multipath is enabled, this value is the minimum MTU across all available paths. +6256 pub fn current_mtu(&self) -> u16 { +6257 self.paths +6258 .iter() +6259 .filter(|&(path_id, _path_state)| !self.abandoned_paths.contains(path_id)) +6260 .map(|(_path_id, path_state)| path_state.data.current_mtu()) +6261 .min() +6262 .expect("There is always at least one available path") +6263 } +6264 +6265 /// Size of non-frame data for a 1-RTT packet +6266 /// +6267 /// Quantifies space consumed by the QUIC header and AEAD tag. All other bytes in a packet are +6268 /// frames. Changes if the length of the remote connection ID changes, which is expected to be +6269 /// rare. If `pn` is specified, may additionally change unpredictably due to variations in +6270 /// latency and packet loss. +6271 fn predict_1rtt_overhead(&mut self, pn: u64, path: PathId) -> usize { +6272 let pn_len = PacketNumber::new( +6273 pn, +6274 self.spaces[SpaceId::Data] +6275 .for_path(path) +6276 .largest_acked_packet +6277 .unwrap_or(0), +6278 ) +6279 .len(); +6280 +6281 // 1 byte for flags +6282 1 + self +6283 .rem_cids +6284 .get(&path) +6285 .map(|cids| cids.active().len()) +6286 .unwrap_or(20) // Max CID len in QUIC v1 +6287 + pn_len +6288 + self.tag_len_1rtt() +6289 } +6290 +6291 fn predict_1rtt_overhead_no_pn(&self) -> usize { +6292 let pn_len = 4; +6293 +6294 let cid_len = self +6295 .rem_cids +6296 .values() +6297 .map(|cids| cids.active().len()) +6298 .max() +6299 .unwrap_or(20); // Max CID len in QUIC v1 +6300 +6301 // 1 byte for flags +6302 1 + cid_len + pn_len + self.tag_len_1rtt() +6303 } +6304 +6305 fn tag_len_1rtt(&self) -> usize { +6306 let key = match self.spaces[SpaceId::Data].crypto.as_ref() { +6307 Some(crypto) => Some(&*crypto.packet.local), +6308 None => self.zero_rtt_crypto.as_ref().map(|x| &*x.packet), +6309 }; +6310 // If neither Data nor 0-RTT keys are available, make a reasonable tag length guess. As of +6311 // this writing, all QUIC cipher suites use 16-byte tags. We could return `None` instead, +6312 // but that would needlessly prevent sending datagrams during 0-RTT. +6313 key.map_or(16, |x| x.tag_len()) +6314 } +6315 +6316 /// Mark the path as validated, and enqueue NEW_TOKEN frames to be sent as appropriate +6317 fn on_path_validated(&mut self, path_id: PathId) { +6318 self.path_data_mut(path_id).validated = true; +6319 let ConnectionSide::Server { server_config } = &self.side else { +6320 return; +6321 }; +6322 let network_path = self.path_data(path_id).network_path; +6323 let new_tokens = &mut self.spaces[SpaceId::Data as usize].pending.new_tokens; +6324 new_tokens.clear(); +6325 for _ in 0..server_config.validation_token.sent { +6326 new_tokens.push(network_path); +6327 } +6328 } +6329 +6330 /// Handle new path status information: PATH_STATUS_AVAILABLE, PATH_STATUS_BACKUP +6331 fn on_path_status(&mut self, path_id: PathId, status: PathStatus, status_seq_no: VarInt) { +6332 if let Some(path) = self.paths.get_mut(&path_id) { +6333 path.data.status.remote_update(status, status_seq_no); +6334 } else { +6335 debug!("PATH_STATUS_AVAILABLE received unknown path {:?}", path_id); +6336 } +6337 self.events.push_back( +6338 PathEvent::RemoteStatus { +6339 id: path_id, +6340 status, +6341 } +6342 .into(), +6343 ); +6344 } +6345 +6346 /// Returns the maximum [`PathId`] to be used for sending in this connection. +6347 /// +6348 /// This is calculated as minimum between the local and remote's maximums when multipath is +6349 /// enabled, or `None` when disabled. +6350 /// +6351 /// For data that's received, we should use [`Self::local_max_path_id`] instead. +6352 /// The reasoning is that the remote might already have updated to its own newer +6353 /// [`Self::max_path_id`] after sending out a `MAX_PATH_ID` frame, but it got re-ordered. +6354 fn max_path_id(&self) -> Option<PathId> { +6355 if self.is_multipath_negotiated() { +6356 Some(self.remote_max_path_id.min(self.local_max_path_id)) +6357 } else { +6358 None +6359 } +6360 } +6361 +6362 /// Add addresses the local endpoint considers are reachable for nat traversal +6363 pub fn add_nat_traversal_address(&mut self, address: SocketAddr) -> Result<(), iroh_hp::Error> { +6364 if let Some(added) = self.iroh_hp.add_local_address(address)? { +6365 self.spaces[SpaceId::Data].pending.add_address.insert(added); +6366 }; +6367 Ok(()) +6368 } +6369 +6370 /// Removes an address the endpoing no longer considers reachable for nat traversal +6371 /// +6372 /// Addresses not present in the set will be silently ignored. +6373 pub fn remove_nat_traversal_address( +6374 &mut self, +6375 address: SocketAddr, +6376 ) -> Result<(), iroh_hp::Error> { +6377 if let Some(removed) = self.iroh_hp.remove_local_address(address)? { +6378 self.spaces[SpaceId::Data] +6379 .pending +6380 .remove_address +6381 .insert(removed); +6382 } +6383 Ok(()) +6384 } +6385 +6386 /// Get the current local nat traversal addresses +6387 pub fn get_local_nat_traversal_addresses(&self) -> Result<Vec<SocketAddr>, iroh_hp::Error> { +6388 self.iroh_hp.get_local_nat_traversal_addresses() +6389 } +6390 +6391 /// Get the currently advertised nat traversal addresses by the server +6392 pub fn get_remote_nat_traversal_addresses(&self) -> Result<Vec<SocketAddr>, iroh_hp::Error> { +6393 Ok(self +6394 .iroh_hp +6395 .client_side()? +6396 .get_remote_nat_traversal_addresses()) +6397 } +6398 +6399 /// Attempts to open a path for nat traversal. +6400 /// +6401 /// `ipv6` indicates if the path should be opened using an IPV6 remote. If the address is +6402 /// ignored, it will return `None`. +6403 /// +6404 /// On success returns the [`PathId`] and remote address of the path, as well as whether the path +6405 /// existed for the adjusted remote. +6406 fn open_nat_traversal_path( +6407 &mut self, +6408 now: Instant, +6409 (ip, port): (IpAddr, u16), +6410 ipv6: bool, +6411 ) -> Result<Option<(PathId, SocketAddr, bool)>, PathError> { +6412 // If this endpoint is an IPv6 endpoint we use IPv6 addresses for all remotes. +6413 let remote = match ip { +6414 IpAddr::V4(addr) if ipv6 => SocketAddr::new(addr.to_ipv6_mapped().into(), port), +6415 IpAddr::V4(addr) => SocketAddr::new(addr.into(), port), +6416 IpAddr::V6(_) if ipv6 => SocketAddr::new(ip, port), +6417 IpAddr::V6(_) => { +6418 trace!("not using IPv6 nat candidate for IPv4 socket"); +6419 return Ok(None); +6420 } +6421 }; +6422 // TODO(matheus23): Probe the correct 4-tuple, instead of only a remote address? +6423 // By specifying None, we do two things: 1. open_path_ensure won't generate two +6424 // paths to the same remote and 2. we let the OS choose which interface to use for +6425 // sending on that path. +6426 let network_path = FourTuple { +6427 remote, +6428 local_ip: None, +6429 }; +6430 match self.open_path_ensure(network_path, PathStatus::Backup, now) { +6431 Ok((path_id, path_was_known)) => { +6432 if path_was_known { +6433 trace!(%path_id, %remote, "nat traversal: path existed for remote"); +6434 } +6435 Ok(Some((path_id, remote, path_was_known))) +6436 } +6437 Err(e) => { +6438 debug!(%remote, %e, "nat traversal: failed to probe remote"); +6439 Err(e) +6440 } +6441 } +6442 } 6443 -6444 let mut err = None; -6445 -6446 let mut path_ids = Vec::with_capacity(addresses_to_probe.len()); -6447 let mut probed_addresses = Vec::with_capacity(addresses_to_probe.len()); -6448 let ipv6 = self -6449 .paths -6450 .values() -6451 .any(|p| p.data.network_path.remote.is_ipv6()); -6452 -6453 for (id, address) in addresses_to_probe { -6454 match self.open_nat_traversal_path(now, address, ipv6) { -6455 Ok(None) => {} -6456 Ok(Some((path_id, remote, path_was_known))) => { -6457 if !path_was_known { -6458 path_ids.push(path_id); -6459 probed_addresses.push(remote); -6460 } -6461 } -6462 Err(e) => { -6463 self.iroh_hp -6464 .client_side_mut() -6465 .expect("validated") -6466 .report_in_continuation(id, e); -6467 err.get_or_insert(e); -6468 } -6469 } -6470 } -6471 -6472 if let Some(err) = err { -6473 // We failed to probe any addresses, bail out -6474 if probed_addresses.is_empty() { -6475 return Err(iroh_hp::Error::Multipath(err)); -6476 } -6477 } +6444 /// Initiates a new nat traversal round +6445 /// +6446 /// A nat traversal round involves advertising the client's local addresses in `REACH_OUT` +6447 /// frames, and initiating probing of the known remote addresses. When a new round is +6448 /// initiated, the previous one is cancelled, and paths that have not been opened are closed. +6449 /// +6450 /// Returns the server addresses that are now being probed. +6451 /// If addresses fail due to spurious errors, these might succeed later and not be returned in +6452 /// this set. +6453 pub fn initiate_nat_traversal_round( +6454 &mut self, +6455 now: Instant, +6456 ) -> Result<Vec<SocketAddr>, iroh_hp::Error> { +6457 if self.state.is_closed() { +6458 return Err(iroh_hp::Error::Closed); +6459 } +6460 +6461 let client_state = self.iroh_hp.client_side_mut()?; +6462 let iroh_hp::NatTraversalRound { +6463 new_round, +6464 reach_out_at, +6465 addresses_to_probe, +6466 prev_round_path_ids, +6467 } = client_state.initiate_nat_traversal_round()?; +6468 +6469 self.spaces[SpaceId::Data].pending.reach_out = Some((new_round, reach_out_at)); +6470 +6471 for path_id in prev_round_path_ids { +6472 // TODO(@divma): this sounds reasonable but we need if this actually works for the +6473 // purposes of the protocol +6474 let validated = self +6475 .path(path_id) +6476 .map(|path| path.validated) +6477 .unwrap_or(false); 6478 -6479 self.iroh_hp -6480 .client_side_mut() -6481 .expect("connection side validated") -6482 .set_round_path_ids(path_ids); -6483 -6484 Ok(probed_addresses) -6485 } -6486 -6487 /// Attempts to continue a nat traversal round by trying to open paths for pending client probes. -6488 /// -6489 /// If there was nothing to do, it returns `None`. Otherwise it returns whether the path was -6490 /// successfully open. -6491 fn continue_nat_traversal_round(&mut self, now: Instant) -> Option<bool> { -6492 let client_state = self.iroh_hp.client_side_mut().ok()?; -6493 let (id, address) = client_state.continue_nat_traversal_round()?; -6494 let ipv6 = self -6495 .paths -6496 .values() -6497 .any(|p| p.data.network_path.remote.is_ipv6()); -6498 let open_result = self.open_nat_traversal_path(now, address, ipv6); -6499 let client_state = self.iroh_hp.client_side_mut().expect("validated"); -6500 match open_result { -6501 Ok(None) => Some(true), -6502 Ok(Some((path_id, _remote, path_was_known))) => { -6503 if !path_was_known { -6504 client_state.add_round_path_id(path_id); +6479 if !validated { +6480 let _ = self.close_path( +6481 now, +6482 path_id, +6483 TransportErrorCode::APPLICATION_ABANDON_PATH.into(), +6484 ); +6485 } +6486 } +6487 +6488 let mut err = None; +6489 +6490 let mut path_ids = Vec::with_capacity(addresses_to_probe.len()); +6491 let mut probed_addresses = Vec::with_capacity(addresses_to_probe.len()); +6492 let ipv6 = self +6493 .paths +6494 .values() +6495 .any(|p| p.data.network_path.remote.is_ipv6()); +6496 +6497 for (id, address) in addresses_to_probe { +6498 match self.open_nat_traversal_path(now, address, ipv6) { +6499 Ok(None) => {} +6500 Ok(Some((path_id, remote, path_was_known))) => { +6501 if !path_was_known { +6502 path_ids.push(path_id); +6503 probed_addresses.push(remote); +6504 } 6505 } -6506 Some(true) -6507 } -6508 Err(e) => { -6509 client_state.report_in_continuation(id, e); -6510 Some(false) -6511 } -6512 } -6513 } -6514} +6506 Err(e) => { +6507 self.iroh_hp +6508 .client_side_mut() +6509 .expect("validated") +6510 .report_in_continuation(id, e); +6511 err.get_or_insert(e); +6512 } +6513 } +6514 } 6515 -6516impl fmt::Debug for Connection { -6517 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { -6518 f.debug_struct("Connection") -6519 .field("handshake_cid", &self.handshake_cid) -6520 .finish() -6521 } -6522} -6523 -6524#[derive(Debug, Copy, Clone, PartialEq, Eq)] -6525enum PathBlocked { -6526 No, -6527 AntiAmplification, -6528 Congestion, -6529 Pacing, -6530} -6531 -6532/// Fields of `Connection` specific to it being client-side or server-side -6533enum ConnectionSide { -6534 Client { -6535 /// Sent in every outgoing Initial packet. Always empty after Initial keys are discarded -6536 token: Bytes, -6537 token_store: Arc<dyn TokenStore>, -6538 server_name: String, -6539 }, -6540 Server { -6541 server_config: Arc<ServerConfig>, -6542 }, -6543} -6544 -6545impl ConnectionSide { -6546 fn remote_may_migrate(&self, state: &State) -> bool { -6547 match self { -6548 Self::Server { server_config } => server_config.migration, -6549 Self::Client { .. } => { -6550 if let Some(hs) = state.as_handshake() { -6551 hs.allow_server_migration -6552 } else { -6553 false -6554 } +6516 if let Some(err) = err { +6517 // We failed to probe any addresses, bail out +6518 if probed_addresses.is_empty() { +6519 return Err(iroh_hp::Error::Multipath(err)); +6520 } +6521 } +6522 +6523 self.iroh_hp +6524 .client_side_mut() +6525 .expect("connection side validated") +6526 .set_round_path_ids(path_ids); +6527 +6528 Ok(probed_addresses) +6529 } +6530 +6531 /// Attempts to continue a nat traversal round by trying to open paths for pending client probes. +6532 /// +6533 /// If there was nothing to do, it returns `None`. Otherwise it returns whether the path was +6534 /// successfully open. +6535 fn continue_nat_traversal_round(&mut self, now: Instant) -> Option<bool> { +6536 let client_state = self.iroh_hp.client_side_mut().ok()?; +6537 let (id, address) = client_state.continue_nat_traversal_round()?; +6538 let ipv6 = self +6539 .paths +6540 .values() +6541 .any(|p| p.data.network_path.remote.is_ipv6()); +6542 let open_result = self.open_nat_traversal_path(now, address, ipv6); +6543 let client_state = self.iroh_hp.client_side_mut().expect("validated"); +6544 match open_result { +6545 Ok(None) => Some(true), +6546 Ok(Some((path_id, _remote, path_was_known))) => { +6547 if !path_was_known { +6548 client_state.add_round_path_id(path_id); +6549 } +6550 Some(true) +6551 } +6552 Err(e) => { +6553 client_state.report_in_continuation(id, e); +6554 Some(false) 6555 } 6556 } 6557 } -6558 -6559 fn is_client(&self) -> bool { -6560 self.side().is_client() -6561 } -6562 -6563 fn is_server(&self) -> bool { -6564 self.side().is_server() +6558} +6559 +6560impl fmt::Debug for Connection { +6561 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { +6562 f.debug_struct("Connection") +6563 .field("handshake_cid", &self.handshake_cid) +6564 .finish() 6565 } -6566 -6567 fn side(&self) -> Side { -6568 match *self { -6569 Self::Client { .. } => Side::Client, -6570 Self::Server { .. } => Side::Server, -6571 } -6572 } -6573} -6574 -6575impl From<SideArgs> for ConnectionSide { -6576 fn from(side: SideArgs) -> Self { -6577 match side { -6578 SideArgs::Client { -6579 token_store, -6580 server_name, -6581 } => Self::Client { -6582 token: token_store.take(&server_name).unwrap_or_default(), -6583 token_store, -6584 server_name, -6585 }, -6586 SideArgs::Server { -6587 server_config, -6588 pref_addr_cid: _, -6589 path_validated: _, -6590 } => Self::Server { server_config }, -6591 } -6592 } -6593} -6594 -6595/// Parameters to `Connection::new` specific to it being client-side or server-side -6596pub(crate) enum SideArgs { -6597 Client { -6598 token_store: Arc<dyn TokenStore>, -6599 server_name: String, -6600 }, -6601 Server { -6602 server_config: Arc<ServerConfig>, -6603 pref_addr_cid: Option<ConnectionId>, -6604 path_validated: bool, -6605 }, -6606} -6607 -6608impl SideArgs { -6609 pub(crate) fn pref_addr_cid(&self) -> Option<ConnectionId> { -6610 match *self { -6611 Self::Client { .. } => None, -6612 Self::Server { pref_addr_cid, .. } => pref_addr_cid, -6613 } -6614 } -6615 -6616 pub(crate) fn path_validated(&self) -> bool { -6617 match *self { -6618 Self::Client { .. } => true, -6619 Self::Server { path_validated, .. } => path_validated, -6620 } -6621 } -6622 -6623 pub(crate) fn side(&self) -> Side { -6624 match *self { -6625 Self::Client { .. } => Side::Client, -6626 Self::Server { .. } => Side::Server, -6627 } -6628 } -6629} -6630 -6631/// Reasons why a connection might be lost -6632#[derive(Debug, Error, Clone, PartialEq, Eq)] -6633pub enum ConnectionError { -6634 /// The peer doesn't implement any supported version -6635 #[error("peer doesn't implement any supported version")] -6636 VersionMismatch, -6637 /// The peer violated the QUIC specification as understood by this implementation -6638 #[error(transparent)] -6639 TransportError(#[from] TransportError), -6640 /// The peer's QUIC stack aborted the connection automatically -6641 #[error("aborted by peer: {0}")] -6642 ConnectionClosed(frame::ConnectionClose), -6643 /// The peer closed the connection -6644 #[error("closed by peer: {0}")] -6645 ApplicationClosed(frame::ApplicationClose), -6646 /// The peer is unable to continue processing this connection, usually due to having restarted -6647 #[error("reset by peer")] -6648 Reset, -6649 /// Communication with the peer has lapsed for longer than the negotiated idle timeout -6650 /// -6651 /// If neither side is sending keep-alives, a connection will time out after a long enough idle -6652 /// period even if the peer is still reachable. See also [`TransportConfig::max_idle_timeout()`] -6653 /// and [`TransportConfig::keep_alive_interval()`]. -6654 #[error("timed out")] -6655 TimedOut, -6656 /// The local application closed the connection -6657 #[error("closed")] -6658 LocallyClosed, -6659 /// The connection could not be created because not enough of the CID space is available -6660 /// -6661 /// Try using longer connection IDs. -6662 #[error("CIDs exhausted")] -6663 CidsExhausted, -6664} -6665 -6666impl From<Close> for ConnectionError { -6667 fn from(x: Close) -> Self { -6668 match x { -6669 Close::Connection(reason) => Self::ConnectionClosed(reason), -6670 Close::Application(reason) => Self::ApplicationClosed(reason), +6566} +6567 +6568#[derive(Debug, Copy, Clone, PartialEq, Eq)] +6569enum PathBlocked { +6570 No, +6571 AntiAmplification, +6572 Congestion, +6573 Pacing, +6574} +6575 +6576/// Fields of `Connection` specific to it being client-side or server-side +6577enum ConnectionSide { +6578 Client { +6579 /// Sent in every outgoing Initial packet. Always empty after Initial keys are discarded +6580 token: Bytes, +6581 token_store: Arc<dyn TokenStore>, +6582 server_name: String, +6583 }, +6584 Server { +6585 server_config: Arc<ServerConfig>, +6586 }, +6587} +6588 +6589impl ConnectionSide { +6590 fn remote_may_migrate(&self, state: &State) -> bool { +6591 match self { +6592 Self::Server { server_config } => server_config.migration, +6593 Self::Client { .. } => { +6594 if let Some(hs) = state.as_handshake() { +6595 hs.allow_server_migration +6596 } else { +6597 false +6598 } +6599 } +6600 } +6601 } +6602 +6603 fn is_client(&self) -> bool { +6604 self.side().is_client() +6605 } +6606 +6607 fn is_server(&self) -> bool { +6608 self.side().is_server() +6609 } +6610 +6611 fn side(&self) -> Side { +6612 match *self { +6613 Self::Client { .. } => Side::Client, +6614 Self::Server { .. } => Side::Server, +6615 } +6616 } +6617} +6618 +6619impl From<SideArgs> for ConnectionSide { +6620 fn from(side: SideArgs) -> Self { +6621 match side { +6622 SideArgs::Client { +6623 token_store, +6624 server_name, +6625 } => Self::Client { +6626 token: token_store.take(&server_name).unwrap_or_default(), +6627 token_store, +6628 server_name, +6629 }, +6630 SideArgs::Server { +6631 server_config, +6632 pref_addr_cid: _, +6633 path_validated: _, +6634 } => Self::Server { server_config }, +6635 } +6636 } +6637} +6638 +6639/// Parameters to `Connection::new` specific to it being client-side or server-side +6640pub(crate) enum SideArgs { +6641 Client { +6642 token_store: Arc<dyn TokenStore>, +6643 server_name: String, +6644 }, +6645 Server { +6646 server_config: Arc<ServerConfig>, +6647 pref_addr_cid: Option<ConnectionId>, +6648 path_validated: bool, +6649 }, +6650} +6651 +6652impl SideArgs { +6653 pub(crate) fn pref_addr_cid(&self) -> Option<ConnectionId> { +6654 match *self { +6655 Self::Client { .. } => None, +6656 Self::Server { pref_addr_cid, .. } => pref_addr_cid, +6657 } +6658 } +6659 +6660 pub(crate) fn path_validated(&self) -> bool { +6661 match *self { +6662 Self::Client { .. } => true, +6663 Self::Server { path_validated, .. } => path_validated, +6664 } +6665 } +6666 +6667 pub(crate) fn side(&self) -> Side { +6668 match *self { +6669 Self::Client { .. } => Side::Client, +6670 Self::Server { .. } => Side::Server, 6671 } 6672 } 6673} 6674 -6675// For compatibility with API consumers -6676impl From<ConnectionError> for io::Error { -6677 fn from(x: ConnectionError) -> Self { -6678 use ConnectionError::*; -6679 let kind = match x { -6680 TimedOut => io::ErrorKind::TimedOut, -6681 Reset => io::ErrorKind::ConnectionReset, -6682 ApplicationClosed(_) | ConnectionClosed(_) => io::ErrorKind::ConnectionAborted, -6683 TransportError(_) | VersionMismatch | LocallyClosed | CidsExhausted => { -6684 io::ErrorKind::Other -6685 } -6686 }; -6687 Self::new(kind, x) -6688 } -6689} -6690 -6691/// Errors that might trigger a path being closed -6692// TODO(@divma): maybe needs to be reworked based on what we want to do with the public API -6693#[derive(Debug, Error, PartialEq, Eq, Clone, Copy)] -6694pub enum PathError { -6695 /// The extension was not negotiated with the peer -6696 #[error("multipath extension not negotiated")] -6697 MultipathNotNegotiated, -6698 /// Paths can only be opened client-side -6699 #[error("the server side may not open a path")] -6700 ServerSideNotAllowed, -6701 /// Current limits do not allow us to open more paths -6702 #[error("maximum number of concurrent paths reached")] -6703 MaxPathIdReached, -6704 /// No remote CIDs available to open a new path -6705 #[error("remoted CIDs exhausted")] -6706 RemoteCidsExhausted, -6707 /// Path could not be validated and will be abandoned -6708 #[error("path validation failed")] -6709 ValidationFailed, -6710 /// The remote address for the path is not supported by the endpoint -6711 #[error("invalid remote address")] -6712 InvalidRemoteAddress(SocketAddr), -6713} -6714 -6715/// Errors triggered when abandoning a path -6716#[derive(Debug, Error, Clone, Eq, PartialEq)] -6717pub enum ClosePathError { -6718 /// The path is already closed or was never opened -6719 #[error("closed path")] -6720 ClosedPath, -6721 /// This is the last path, which can not be abandoned -6722 #[error("last open path")] -6723 LastOpenPath, -6724} -6725 -6726/// Error when the multipath extension was not negotiated, but attempted to be used. -6727#[derive(Debug, Error, Clone, Copy)] -6728#[error("Multipath extension not negotiated")] -6729pub struct MultipathNotNegotiated { -6730 _private: (), -6731} -6732 -6733/// Events of interest to the application -6734#[derive(Debug)] -6735pub enum Event { -6736 /// The connection's handshake data is ready -6737 HandshakeDataReady, -6738 /// The connection was successfully established -6739 Connected, -6740 /// The TLS handshake was confirmed -6741 HandshakeConfirmed, -6742 /// The connection was lost -6743 /// -6744 /// Emitted if the peer closes the connection or an error is encountered. -6745 ConnectionLost { -6746 /// Reason that the connection was closed -6747 reason: ConnectionError, -6748 }, -6749 /// Stream events -6750 Stream(StreamEvent), -6751 /// One or more application datagrams have been received -6752 DatagramReceived, -6753 /// One or more application datagrams have been sent after blocking -6754 DatagramsUnblocked, -6755 /// (Multi)Path events -6756 Path(PathEvent), -6757 /// Iroh's nat traversal events -6758 NatTraversal(iroh_hp::Event), -6759} -6760 -6761impl From<PathEvent> for Event { -6762 fn from(source: PathEvent) -> Self { -6763 Self::Path(source) -6764 } -6765} -6766 -6767fn get_max_ack_delay(params: &TransportParameters) -> Duration { -6768 Duration::from_micros(params.max_ack_delay.0 * 1000) -6769} -6770 -6771// Prevents overflow and improves behavior in extreme circumstances -6772const MAX_BACKOFF_EXPONENT: u32 = 16; -6773 -6774/// Minimal remaining size to allow packet coalescing, excluding cryptographic tag -6775/// -6776/// This must be at least as large as the header for a well-formed empty packet to be coalesced, -6777/// plus some space for frames. We only care about handshake headers because short header packets -6778/// necessarily have smaller headers, and initial packets are only ever the first packet in a -6779/// datagram (because we coalesce in ascending packet space order and the only reason to split a -6780/// packet is when packet space changes). -6781const MIN_PACKET_SPACE: usize = MAX_HANDSHAKE_OR_0RTT_HEADER_SIZE + 32; -6782 -6783/// Largest amount of space that could be occupied by a Handshake or 0-RTT packet's header -6784/// -6785/// Excludes packet-type-specific fields such as packet number or Initial token -6786// https://www.rfc-editor.org/rfc/rfc9000.html#name-0-rtt: flags + version + dcid len + dcid + -6787// scid len + scid + length + pn -6788const MAX_HANDSHAKE_OR_0RTT_HEADER_SIZE: usize = -6789 1 + 4 + 1 + MAX_CID_SIZE + 1 + MAX_CID_SIZE + VarInt::from_u32(u16::MAX as u32).size() + 4; -6790 -6791/// Perform key updates this many packets before the AEAD confidentiality limit. -6792/// -6793/// Chosen arbitrarily, intended to be large enough to prevent spurious connection loss. -6794const KEY_UPDATE_MARGIN: u64 = 10_000; -6795 -6796#[derive(Default)] -6797struct SentFrames { -6798 retransmits: ThinRetransmits, -6799 /// The packet number of the largest acknowledged packet for each path -6800 largest_acked: FxHashMap<PathId, u64>, -6801 stream_frames: StreamMetaVec, -6802 /// Whether the packet contains non-retransmittable frames (like datagrams) -6803 non_retransmits: bool, -6804 /// If the datagram containing these frames should be padded to the min MTU -6805 requires_padding: bool, -6806} -6807 -6808impl SentFrames { -6809 /// Returns whether the packet contains only ACKs -6810 fn is_ack_only(&self, streams: &StreamsState) -> bool { -6811 !self.largest_acked.is_empty() -6812 && !self.non_retransmits -6813 && self.stream_frames.is_empty() -6814 && self.retransmits.is_empty(streams) -6815 } -6816 -6817 fn retransmits_mut(&mut self) -> &mut Retransmits { -6818 self.retransmits.get_or_create() -6819 } -6820 -6821 fn record_sent_frame(&mut self, frame: frame::EncodableFrame<'_>) { -6822 use frame::EncodableFrame::*; -6823 match frame { -6824 PathAck(path_ack_encoder) => { -6825 if let Some(max) = path_ack_encoder.ranges.max() { -6826 self.largest_acked.insert(path_ack_encoder.path_id, max); -6827 } -6828 } -6829 Ack(ack_encoder) => { -6830 if let Some(max) = ack_encoder.ranges.max() { -6831 self.largest_acked.insert(PathId::ZERO, max); -6832 } -6833 } -6834 Close(_) => { /* non retransmittable, but after this we don't really care */ } -6835 PathResponse(_) => self.non_retransmits = true, -6836 HandshakeDone(_) => self.retransmits_mut().handshake_done = true, -6837 ReachOut(frame::ReachOut { round, ip, port }) => self -6838 .retransmits_mut() -6839 .reach_out -6840 .get_or_insert_with(|| (round, Vec::new())) -6841 .1 -6842 .push((ip, port)), -6843 ObservedAddr(_) => self.retransmits_mut().observed_addr = true, -6844 Ping(_) => self.non_retransmits = true, -6845 ImmediateAck(_) => self.non_retransmits = true, -6846 AckFrequency(_) => self.retransmits_mut().ack_frequency = true, -6847 PathChallenge(_) => self.non_retransmits = true, -6848 Crypto(crypto) => self.retransmits_mut().crypto.push_back(crypto), -6849 PathAbandon(path_abandon) => { -6850 self.retransmits_mut() -6851 .path_abandon -6852 .entry(path_abandon.path_id) -6853 .or_insert(path_abandon.error_code); -6854 } -6855 PathStatusAvailable(frame::PathStatusAvailable { path_id, .. }) -6856 | PathStatusBackup(frame::PathStatusBackup { path_id, .. }) => { -6857 self.retransmits_mut().path_status.insert(path_id); -6858 } -6859 MaxPathId(_) => self.retransmits_mut().max_path_id = true, -6860 PathsBlocked(_) => self.retransmits_mut().paths_blocked = true, -6861 PathCidsBlocked(path_cids_blocked) => { -6862 self.retransmits_mut() -6863 .path_cids_blocked -6864 .insert(path_cids_blocked.path_id); -6865 } -6866 ResetStream(reset) => self -6867 .retransmits_mut() -6868 .reset_stream -6869 .push((reset.id, reset.error_code)), -6870 StopSending(stop_sending) => self.retransmits_mut().stop_sending.push(stop_sending), -6871 NewConnectionId(new_cid) => self.retransmits_mut().new_cids.push(new_cid.issued()), -6872 RetireConnectionId(retire_cid) => self -6873 .retransmits_mut() -6874 .retire_cids -6875 .push((retire_cid.path_id.unwrap_or_default(), retire_cid.sequence)), -6876 Datagram(_) => self.non_retransmits = true, -6877 NewToken(_) => {} -6878 AddAddress(add_address) => { -6879 self.retransmits_mut().add_address.insert(add_address); -6880 } -6881 RemoveAddress(remove_address) => { -6882 self.retransmits_mut().remove_address.insert(remove_address); -6883 } -6884 StreamMeta(stream_meta_encoder) => self.stream_frames.push(stream_meta_encoder.meta), -6885 MaxData(_) => self.retransmits_mut().max_data = true, -6886 MaxStreamData(max) => { -6887 self.retransmits_mut().max_stream_data.insert(max.id); -6888 } -6889 MaxStreams(max_streams) => { -6890 self.retransmits_mut().max_stream_id[max_streams.dir as usize] = true -6891 } -6892 } -6893 } -6894} -6895 -6896/// Compute the negotiated idle timeout based on local and remote max_idle_timeout transport parameters. -6897/// -6898/// According to the definition of max_idle_timeout, a value of `0` means the timeout is disabled; see <https://www.rfc-editor.org/rfc/rfc9000#section-18.2-4.4.1.> -6899/// -6900/// According to the negotiation procedure, either the minimum of the timeouts or one specified is used as the negotiated value; see <https://www.rfc-editor.org/rfc/rfc9000#section-10.1-2.> -6901/// -6902/// Returns the negotiated idle timeout as a `Duration`, or `None` when both endpoints have opted out of idle timeout. -6903fn negotiate_max_idle_timeout(x: Option<VarInt>, y: Option<VarInt>) -> Option<Duration> { -6904 match (x, y) { -6905 (Some(VarInt(0)) | None, Some(VarInt(0)) | None) => None, -6906 (Some(VarInt(0)) | None, Some(y)) => Some(Duration::from_millis(y.0)), -6907 (Some(x), Some(VarInt(0)) | None) => Some(Duration::from_millis(x.0)), -6908 (Some(x), Some(y)) => Some(Duration::from_millis(cmp::min(x, y).0)), -6909 } -6910} -6911 -6912#[cfg(test)] -6913mod tests { -6914 use super::*; -6915 -6916 #[test] -6917 fn negotiate_max_idle_timeout_commutative() { -6918 let test_params = [ -6919 (None, None, None), -6920 (None, Some(VarInt(0)), None), -6921 (None, Some(VarInt(2)), Some(Duration::from_millis(2))), -6922 (Some(VarInt(0)), Some(VarInt(0)), None), -6923 ( -6924 Some(VarInt(2)), -6925 Some(VarInt(0)), -6926 Some(Duration::from_millis(2)), -6927 ), -6928 ( -6929 Some(VarInt(1)), -6930 Some(VarInt(4)), -6931 Some(Duration::from_millis(1)), -6932 ), -6933 ]; -6934 -6935 for (left, right, result) in test_params { -6936 assert_eq!(negotiate_max_idle_timeout(left, right), result); -6937 assert_eq!(negotiate_max_idle_timeout(right, left), result); -6938 } -6939 } -6940}

\ No newline at end of file +6675/// Reasons why a connection might be lost +6676#[derive(Debug, Error, Clone, PartialEq, Eq)] +6677pub enum ConnectionError { +6678 /// The peer doesn't implement any supported version +6679 #[error("peer doesn't implement any supported version")] +6680 VersionMismatch, +6681 /// The peer violated the QUIC specification as understood by this implementation +6682 #[error(transparent)] +6683 TransportError(#[from] TransportError), +6684 /// The peer's QUIC stack aborted the connection automatically +6685 #[error("aborted by peer: {0}")] +6686 ConnectionClosed(frame::ConnectionClose), +6687 /// The peer closed the connection +6688 #[error("closed by peer: {0}")] +6689 ApplicationClosed(frame::ApplicationClose), +6690 /// The peer is unable to continue processing this connection, usually due to having restarted +6691 #[error("reset by peer")] +6692 Reset, +6693 /// Communication with the peer has lapsed for longer than the negotiated idle timeout +6694 /// +6695 /// If neither side is sending keep-alives, a connection will time out after a long enough idle +6696 /// period even if the peer is still reachable. See also [`TransportConfig::max_idle_timeout()`] +6697 /// and [`TransportConfig::keep_alive_interval()`]. +6698 #[error("timed out")] +6699 TimedOut, +6700 /// The local application closed the connection +6701 #[error("closed")] +6702 LocallyClosed, +6703 /// The connection could not be created because not enough of the CID space is available +6704 /// +6705 /// Try using longer connection IDs. +6706 #[error("CIDs exhausted")] +6707 CidsExhausted, +6708} +6709 +6710impl From<Close> for ConnectionError { +6711 fn from(x: Close) -> Self { +6712 match x { +6713 Close::Connection(reason) => Self::ConnectionClosed(reason), +6714 Close::Application(reason) => Self::ApplicationClosed(reason), +6715 } +6716 } +6717} +6718 +6719// For compatibility with API consumers +6720impl From<ConnectionError> for io::Error { +6721 fn from(x: ConnectionError) -> Self { +6722 use ConnectionError::*; +6723 let kind = match x { +6724 TimedOut => io::ErrorKind::TimedOut, +6725 Reset => io::ErrorKind::ConnectionReset, +6726 ApplicationClosed(_) | ConnectionClosed(_) => io::ErrorKind::ConnectionAborted, +6727 TransportError(_) | VersionMismatch | LocallyClosed | CidsExhausted => { +6728 io::ErrorKind::Other +6729 } +6730 }; +6731 Self::new(kind, x) +6732 } +6733} +6734 +6735/// Errors that might trigger a path being closed +6736// TODO(@divma): maybe needs to be reworked based on what we want to do with the public API +6737#[derive(Debug, Error, PartialEq, Eq, Clone, Copy)] +6738pub enum PathError { +6739 /// The extension was not negotiated with the peer +6740 #[error("multipath extension not negotiated")] +6741 MultipathNotNegotiated, +6742 /// Paths can only be opened client-side +6743 #[error("the server side may not open a path")] +6744 ServerSideNotAllowed, +6745 /// Current limits do not allow us to open more paths +6746 #[error("maximum number of concurrent paths reached")] +6747 MaxPathIdReached, +6748 /// No remote CIDs available to open a new path +6749 #[error("remoted CIDs exhausted")] +6750 RemoteCidsExhausted, +6751 /// Path could not be validated and will be abandoned +6752 #[error("path validation failed")] +6753 ValidationFailed, +6754 /// The remote address for the path is not supported by the endpoint +6755 #[error("invalid remote address")] +6756 InvalidRemoteAddress(SocketAddr), +6757} +6758 +6759/// Errors triggered when abandoning a path +6760#[derive(Debug, Error, Clone, Eq, PartialEq)] +6761pub enum ClosePathError { +6762 /// The path is already closed or was never opened +6763 #[error("closed path")] +6764 ClosedPath, +6765 /// This is the last path, which can not be abandoned +6766 #[error("last open path")] +6767 LastOpenPath, +6768} +6769 +6770/// Error when the multipath extension was not negotiated, but attempted to be used. +6771#[derive(Debug, Error, Clone, Copy)] +6772#[error("Multipath extension not negotiated")] +6773pub struct MultipathNotNegotiated { +6774 _private: (), +6775} +6776 +6777/// Events of interest to the application +6778#[derive(Debug)] +6779pub enum Event { +6780 /// The connection's handshake data is ready +6781 HandshakeDataReady, +6782 /// The connection was successfully established +6783 Connected, +6784 /// The TLS handshake was confirmed +6785 HandshakeConfirmed, +6786 /// The connection was lost +6787 /// +6788 /// Emitted if the peer closes the connection or an error is encountered. +6789 ConnectionLost { +6790 /// Reason that the connection was closed +6791 reason: ConnectionError, +6792 }, +6793 /// Stream events +6794 Stream(StreamEvent), +6795 /// One or more application datagrams have been received +6796 DatagramReceived, +6797 /// One or more application datagrams have been sent after blocking +6798 DatagramsUnblocked, +6799 /// (Multi)Path events +6800 Path(PathEvent), +6801 /// Iroh's nat traversal events +6802 NatTraversal(iroh_hp::Event), +6803} +6804 +6805impl From<PathEvent> for Event { +6806 fn from(source: PathEvent) -> Self { +6807 Self::Path(source) +6808 } +6809} +6810 +6811fn get_max_ack_delay(params: &TransportParameters) -> Duration { +6812 Duration::from_micros(params.max_ack_delay.0 * 1000) +6813} +6814 +6815// Prevents overflow and improves behavior in extreme circumstances +6816const MAX_BACKOFF_EXPONENT: u32 = 16; +6817 +6818/// Minimal remaining size to allow packet coalescing, excluding cryptographic tag +6819/// +6820/// This must be at least as large as the header for a well-formed empty packet to be coalesced, +6821/// plus some space for frames. We only care about handshake headers because short header packets +6822/// necessarily have smaller headers, and initial packets are only ever the first packet in a +6823/// datagram (because we coalesce in ascending packet space order and the only reason to split a +6824/// packet is when packet space changes). +6825const MIN_PACKET_SPACE: usize = MAX_HANDSHAKE_OR_0RTT_HEADER_SIZE + 32; +6826 +6827/// Largest amount of space that could be occupied by a Handshake or 0-RTT packet's header +6828/// +6829/// Excludes packet-type-specific fields such as packet number or Initial token +6830// https://www.rfc-editor.org/rfc/rfc9000.html#name-0-rtt: flags + version + dcid len + dcid + +6831// scid len + scid + length + pn +6832const MAX_HANDSHAKE_OR_0RTT_HEADER_SIZE: usize = +6833 1 + 4 + 1 + MAX_CID_SIZE + 1 + MAX_CID_SIZE + VarInt::from_u32(u16::MAX as u32).size() + 4; +6834 +6835/// Perform key updates this many packets before the AEAD confidentiality limit. +6836/// +6837/// Chosen arbitrarily, intended to be large enough to prevent spurious connection loss. +6838const KEY_UPDATE_MARGIN: u64 = 10_000; +6839 +6840#[derive(Default)] +6841struct SentFrames { +6842 retransmits: ThinRetransmits, +6843 /// The packet number of the largest acknowledged packet for each path +6844 largest_acked: FxHashMap<PathId, u64>, +6845 stream_frames: StreamMetaVec, +6846 /// Whether the packet contains non-retransmittable frames (like datagrams) +6847 non_retransmits: bool, +6848 /// If the datagram containing these frames should be padded to the min MTU +6849 requires_padding: bool, +6850} +6851 +6852impl SentFrames { +6853 /// Returns whether the packet contains only ACKs +6854 fn is_ack_only(&self, streams: &StreamsState) -> bool { +6855 !self.largest_acked.is_empty() +6856 && !self.non_retransmits +6857 && self.stream_frames.is_empty() +6858 && self.retransmits.is_empty(streams) +6859 } +6860 +6861 fn retransmits_mut(&mut self) -> &mut Retransmits { +6862 self.retransmits.get_or_create() +6863 } +6864 +6865 fn record_sent_frame(&mut self, frame: frame::EncodableFrame<'_>) { +6866 use frame::EncodableFrame::*; +6867 match frame { +6868 PathAck(path_ack_encoder) => { +6869 if let Some(max) = path_ack_encoder.ranges.max() { +6870 self.largest_acked.insert(path_ack_encoder.path_id, max); +6871 } +6872 } +6873 Ack(ack_encoder) => { +6874 if let Some(max) = ack_encoder.ranges.max() { +6875 self.largest_acked.insert(PathId::ZERO, max); +6876 } +6877 } +6878 Close(_) => { /* non retransmittable, but after this we don't really care */ } +6879 PathResponse(_) => self.non_retransmits = true, +6880 HandshakeDone(_) => self.retransmits_mut().handshake_done = true, +6881 ReachOut(frame::ReachOut { round, ip, port }) => self +6882 .retransmits_mut() +6883 .reach_out +6884 .get_or_insert_with(|| (round, Vec::new())) +6885 .1 +6886 .push((ip, port)), +6887 ObservedAddr(_) => self.retransmits_mut().observed_addr = true, +6888 Ping(_) => self.non_retransmits = true, +6889 ImmediateAck(_) => self.non_retransmits = true, +6890 AckFrequency(_) => self.retransmits_mut().ack_frequency = true, +6891 PathChallenge(_) => self.non_retransmits = true, +6892 Crypto(crypto) => self.retransmits_mut().crypto.push_back(crypto), +6893 PathAbandon(path_abandon) => { +6894 self.retransmits_mut() +6895 .path_abandon +6896 .entry(path_abandon.path_id) +6897 .or_insert(path_abandon.error_code); +6898 } +6899 PathStatusAvailable(frame::PathStatusAvailable { path_id, .. }) +6900 | PathStatusBackup(frame::PathStatusBackup { path_id, .. }) => { +6901 self.retransmits_mut().path_status.insert(path_id); +6902 } +6903 MaxPathId(_) => self.retransmits_mut().max_path_id = true, +6904 PathsBlocked(_) => self.retransmits_mut().paths_blocked = true, +6905 PathCidsBlocked(path_cids_blocked) => { +6906 self.retransmits_mut() +6907 .path_cids_blocked +6908 .insert(path_cids_blocked.path_id); +6909 } +6910 ResetStream(reset) => self +6911 .retransmits_mut() +6912 .reset_stream +6913 .push((reset.id, reset.error_code)), +6914 StopSending(stop_sending) => self.retransmits_mut().stop_sending.push(stop_sending), +6915 NewConnectionId(new_cid) => self.retransmits_mut().new_cids.push(new_cid.issued()), +6916 RetireConnectionId(retire_cid) => self +6917 .retransmits_mut() +6918 .retire_cids +6919 .push((retire_cid.path_id.unwrap_or_default(), retire_cid.sequence)), +6920 Datagram(_) => self.non_retransmits = true, +6921 NewToken(_) => {} +6922 AddAddress(add_address) => { +6923 self.retransmits_mut().add_address.insert(add_address); +6924 } +6925 RemoveAddress(remove_address) => { +6926 self.retransmits_mut().remove_address.insert(remove_address); +6927 } +6928 StreamMeta(stream_meta_encoder) => self.stream_frames.push(stream_meta_encoder.meta), +6929 MaxData(_) => self.retransmits_mut().max_data = true, +6930 MaxStreamData(max) => { +6931 self.retransmits_mut().max_stream_data.insert(max.id); +6932 } +6933 MaxStreams(max_streams) => { +6934 self.retransmits_mut().max_stream_id[max_streams.dir as usize] = true +6935 } +6936 } +6937 } +6938} +6939 +6940/// Compute the negotiated idle timeout based on local and remote max_idle_timeout transport parameters. +6941/// +6942/// According to the definition of max_idle_timeout, a value of `0` means the timeout is disabled; see <https://www.rfc-editor.org/rfc/rfc9000#section-18.2-4.4.1.> +6943/// +6944/// According to the negotiation procedure, either the minimum of the timeouts or one specified is used as the negotiated value; see <https://www.rfc-editor.org/rfc/rfc9000#section-10.1-2.> +6945/// +6946/// Returns the negotiated idle timeout as a `Duration`, or `None` when both endpoints have opted out of idle timeout. +6947fn negotiate_max_idle_timeout(x: Option<VarInt>, y: Option<VarInt>) -> Option<Duration> { +6948 match (x, y) { +6949 (Some(VarInt(0)) | None, Some(VarInt(0)) | None) => None, +6950 (Some(VarInt(0)) | None, Some(y)) => Some(Duration::from_millis(y.0)), +6951 (Some(x), Some(VarInt(0)) | None) => Some(Duration::from_millis(x.0)), +6952 (Some(x), Some(y)) => Some(Duration::from_millis(cmp::min(x, y).0)), +6953 } +6954} +6955 +6956#[cfg(test)] +6957mod tests { +6958 use super::*; +6959 +6960 #[test] +6961 fn negotiate_max_idle_timeout_commutative() { +6962 let test_params = [ +6963 (None, None, None), +6964 (None, Some(VarInt(0)), None), +6965 (None, Some(VarInt(2)), Some(Duration::from_millis(2))), +6966 (Some(VarInt(0)), Some(VarInt(0)), None), +6967 ( +6968 Some(VarInt(2)), +6969 Some(VarInt(0)), +6970 Some(Duration::from_millis(2)), +6971 ), +6972 ( +6973 Some(VarInt(1)), +6974 Some(VarInt(4)), +6975 Some(Duration::from_millis(1)), +6976 ), +6977 ]; +6978 +6979 for (left, right, result) in test_params { +6980 assert_eq!(negotiate_max_idle_timeout(left, right), result); +6981 assert_eq!(negotiate_max_idle_timeout(right, left), result); +6982 } +6983 } +6984}

\ No newline at end of file diff --git a/pr/338/docs/src/iroh_quinn_proto/connection/packet_builder.rs.html b/pr/338/docs/src/iroh_quinn_proto/connection/packet_builder.rs.html index 35ac0c0d5..20cacdead 100644 --- a/pr/338/docs/src/iroh_quinn_proto/connection/packet_builder.rs.html +++ b/pr/338/docs/src/iroh_quinn_proto/connection/packet_builder.rs.html @@ -25,7 +25,7 @@ 25 path: PathId, 26 pub(super) partial_encode: PartialEncode, 27 pub(super) ack_eliciting: bool, -28 pub(super) exact_number: u64, +28 pub(super) packet_number: u64, 29 /// Is this packet allowed to be coalesced? 30 pub(super) can_coalesce: bool, 31 /// Smallest absolute position in the associated buffer that must be occupied by this packet's @@ -93,11 +93,11 @@ 93 } 94 95 let space = &mut conn.spaces[space_id]; -96 let exact_number = space.for_path(path_id).get_tx_number(&mut conn.rng); -97 let span = trace_span!("send", space = ?space_id, pn = exact_number, %path_id).entered(); +96 let packet_number = space.for_path(path_id).get_tx_number(&mut conn.rng); +97 let span = trace_span!("send", space = ?space_id, pn = packet_number, %path_id).entered(); 98 99 let number = PacketNumber::new( -100 exact_number, +100 packet_number, 101 space.for_path(path_id).largest_acked_packet.unwrap_or(0), 102 ); 103 let header = match space_id { @@ -171,7 +171,7 @@ 171 172 qlog.header( 173 &header, -174 Some(exact_number), +174 Some(packet_number), 175 space_id, 176 space_id == SpaceId::Data && conn.spaces[SpaceId::Data].crypto.is_none(), 177 path_id, @@ -182,7 +182,7 @@ 182 space: space_id, 183 path: path_id, 184 partial_encode, -185 exact_number, +185 packet_number, 186 can_coalesce: header.can_coalesce(), 187 min_size, 188 tag_len, @@ -201,7 +201,7 @@ 201 path: PathId::ZERO, 202 partial_encode: PartialEncode::no_header(), 203 ack_eliciting: true, -204 exact_number: 0, +204 packet_number: 0, 205 can_coalesce: true, 206 min_size: 0, 207 tag_len: 0, @@ -291,7 +291,7 @@ 291 PadDatagram::ToMinMtu => self.pad_to(MIN_INITIAL_SIZE), 292 } 293 let ack_eliciting = self.ack_eliciting; -294 let exact_number = self.exact_number; +294 let exact_number = self.packet_number; 295 let space_id = self.space; 296 let (size, padded, sent) = self.finish(conn, now); 297 @@ -372,7 +372,7 @@ 372 self.partial_encode.finish( 373 packet_buf, 374 header_crypto, -375 Some((self.exact_number, self.path, packet_crypto)), +375 Some((self.packet_number, self.path, packet_crypto)), 376 ); 377 378 let packet_len = self.buf.len() - encode_start;