diff --git a/Cargo.lock b/Cargo.lock index d79b9eb..aa315d8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -596,6 +596,18 @@ version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" +[[package]] +name = "epee-encoding" +version = "0.5.0" +dependencies = [ + "bytes", + "fixed-bytes", + "hex", + "paste", + "sealed", + "thiserror", +] + [[package]] name = "equivalent" version = "1.0.1" @@ -656,6 +668,14 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "27573eac26f4dd11e2b1916c3fe1baa56407c83c71a773a8ba17ec0bca03b6b7" +[[package]] +name = "fixed-bytes" +version = "0.1.0" +dependencies = [ + "bytes", + "thiserror", +] + [[package]] name = "flexible-transcript" version = "0.3.2" @@ -1313,6 +1333,12 @@ dependencies = [ "subtle", ] +[[package]] +name = "paste" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" + [[package]] name = "pbkdf2" version = "0.12.2" @@ -1694,6 +1720,18 @@ dependencies = [ "untrusted", ] +[[package]] +name = "sealed" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4a8caec23b7800fb97971a1c6ae365b6239aaeddfb934d6265f8505e795699d" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 2.0.48", +] + [[package]] name = "security-framework" version = "2.9.2" diff --git a/Cargo.toml b/Cargo.toml index b56473a..3989579 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,6 +6,8 @@ members = [ "consensus/rules", "cryptonight", "helper", + "net/epee-encoding", + "net/fixed-bytes", "net/levin", "net/monero-wire", "p2p/monero-p2p", diff --git a/misc/DESIGN.md b/misc/DESIGN.md index 9a56ae8..bfadffb 100644 --- a/misc/DESIGN.md +++ b/misc/DESIGN.md @@ -20,16 +20,16 @@ ### Introduction -This document outlines the initial plan for Cuprate, a Rust Monero node. Currently, Monero only +This document outlines the initial plan for Cuprate, a Rust Monero node. Currently, Monero only has one node implementation, which many would class as an issue. -This document isn't supposed to outline everything, but it is meant to give a good overview of the +This document isn't supposed to outline everything, but it is meant to give a good overview of the plan. Cuprate won't build everything from scratch and aims to use crates already in existence -when they're a good fit, an example is monero-serai for our transactions and blocks. +when they're a good fit, an example is monero-serai for our transactions and blocks. -Cuprate makes heavy use of [tower](https://docs.rs/tower/latest/tower/index.html) to modularize its +Cuprate makes heavy use of [tower](https://docs.rs/tower/latest/tower/index.html) to modularize its parts. Using tower across the node will provide us with a consistent API and will allow us to use towers extensive middleware, for tasks such as routing requests and timeouts. @@ -38,49 +38,57 @@ extensive middleware, for tasks such as routing requests and timeouts. ### P2P Cuprates P2P takes heavy inspiration from Zebra. The P2P crate will abstract the network into one endpoint, -meaning other parts of the node will have no P2P code except from sending requests to this one endpoint. -This endpoint will be made of a few different tower::Services for the different routing methods, the most +meaning other parts of the node will have no P2P code except from sending requests to this one endpoint. +This endpoint will be made of a few different tower::Services for the different routing methods, the most simple method is to use a load balancing algorithm to send a request to one peer. -The peer to peer part of Cuprate will be split into 3 crates: +The peer to peer part of Cuprate will be split into multiple crates: -| Name | Short Description | -|---------------|-----------------------------------------------------------------------------------------------| -| levin-cuprate | A library containing the levin header format. | -| monero-wire | A library containing all Monero P2P messages built on-top of `levin-cuprate`. | -| cuprate-p2p | A library abstracting the P2P network away, with logic for handshakes, the address book, etc. | +| Name | Short Description | +|---------------------|----------------------------------------------------------------------------------------------------------------| +| levin-cuprate | A library containing the levin header format. | +| monero-wire | A library containing all Monero P2P messages built on-top of `levin-cuprate`. | +| monero-p2p | A library defining the network zone abstraction and individual peer logic (handshakes etc). | +| monero-address-book | Contains the P2P address book, handles storing peers, getting peers etc. | +| cuprate-p2p | Defines the PeerSet and the different routing methods (excluding d++), has the logic for starting the network. | +| dandelion-pp | Defines the D++ routing method. | #### levin-cuprate This library will have the [levin header format](https://github.com/monero-project/monero/blob/master/docs/LEVIN_PROTOCOL.md#header), -with a [tokio-codec](https://docs.rs/tokio-util/0.7.8/tokio_util/codec/index.html) for encoding and -decoding p2p messages. To do this a trait `LevinMessage` will be used so users can define their own +with a [tokio-codec](https://docs.rs/tokio-util/0.7.8/tokio_util/codec/index.html) for encoding and +decoding p2p messages. To do this a trait `LevinMessage` will be used so users can define their own P2P messages. This will allow other Rust projects to use the levin header format with different messages. #### monero-wire -This will be a library built on top of [levin-cuprate](#levin-cuprate), It will contain every P2P +This will be a library built on top of [levin-cuprate](#levin-cuprate), It will contain every P2P message with decoding/ encoding capability. This library will implement the `LevinMessage` trait. -The serialization format used for P2P messages has already been implemented in Rust, multiple times :). I have decided to -implement it yet again in the crate: `epee-encoding`. This crate was created specifically for use in Cuprate. +The serialization format used for P2P messages has already been implemented in Rust, multiple times :). I have decided to +use monero-epee-bin-serde. -The monero-wire crate will be able to be used in other Rust projects who want to interact with Monero's P2P network. +The monero-wire crate can be used in other Rust projects which need Monero's p2p network messages. -#### cuprate-p2p +#### monero-p2p -This library will abstract the P2P network away into one endpoint. Sadly, this endpoint will have to be made -up of different tower::Services for the different routing methods. For example, new blocks need to be sent to every -peer but a request may only need to go to a single peer. +This library will contain the network zone abstraction, which abstracts over clear-net, Tor, I2P and any future network. -The library will be split into many modules: +This will also contain a `Client` and `Connection`. The `Connection` will be an async task that gives requests from +the peer to the inbound request handler and sends requests from Cuprate to the peer. The `Client` will implement +tower::Service and will simply pass requests from our node to the `Connection` task. -##### protocol +This will also contain a `Handshaker` which is responsible for taking a peer connection doing a handshake with it +and creating a `Client` and `Connection`. + +This library is intended to be a more flexible monero p2p library than what cuprate-p2p is, allowing wider use in applications that need to +interact with Monero's p2p network but don't want/ or need Cuprates whole p2p stack. To be compatible with tower::Service the Monero P2P protocol needs to be split into requests and responses. -Levin admin messages are already in the request/ response format, but notifications are not. For some +Levin admin messages are already in the request/ response format, but notifications are not. For some notifications it's easy: `GetObjectsRequest` but for others it's harder. Here is a table of the Monero P2P messages put in either requests or responses: + ``` /// Admin (These are already in request/ response format): /// Handshake, @@ -100,41 +108,32 @@ Here is a table of the Monero P2P messages put in either requests or responses: To split messages that can be requests or responses we will need to keep track of sent requests. -##### peer +#### monero-address-book -This will contain a `Client` and `Connection`. The `Connection` will be an async task that gives requests from -the peer to the inbound request handler and sends requests from Cuprate to the peer. The `Client` will implement -tower::Service and will simply pass requests from our node to the `Connection` task. +This implements Monero's p2p address book, this is a separate crate to monero-p2p to allow developers to create their own address book implementation +if `monero-address-book` is not suitable for them. `monero-address-book` will implement an `AddressBook` trait defined in `monero-p2p`. -This module will also contain a `Handshaker` which is responsible for taking a peer connection doing a handshake with it -and creating a `Client` and `Connection`. +#### cuprate-p2p -##### address book +This library will abstract the P2P network away into one endpoint. Sadly, this endpoint will have to be made +up of different tower::Services for the different routing methods. For example, new blocks need to be sent to every +peer but a request for a block may only need to go to a single peer. -The address book will use the same overall idea as monerod's address book. It will contain a White, Grey and Anchor -list. Under the hood we will have 3 separate address books for each network (clear, i2p, Tor) and will route requests -using a tower::Steer. +To allow splitting the endpoint into multiple tower::Services a `PeerSet` will be defined that will be shared between the services and is the structure +that holds on the currently connected peer on a certain network. The tower::Services will use this `PeerSet` to get peers to route requests to. -White: Peers we have connected to at some point. +`cuprate-p2p` will also have a block downloader which will be a `futures::Stream`, it will use the `PeerSet` to find the chain with the highest cumulative +difficulty and download that chain, when it gets a block it will pass it back through the `Stream`. -Gray: Peers we have heard about but haven't attempted to connect to. +#### dandelion-pp -Anchor: A list of currently connected peers so, if we were to re-start, we can choose a couple peers from this list to -reduce our chance of being isolated. +This crate is separate from the other routing methods to allow wider usage, to do this it will be generic over the requests/ responses allowing users +to define them. -The address book will be an async task which we will be able to interact with through a tower::Service. +This crate won't be able to handle all of dandelion++ as that requires knowledge of the tx-pool but it will handle all of the routing side, deciding the current +state, getting the peers to route to etc. -##### peer set - -This is the part of the P2P crate that holds all currently connected peers. The rest of Cuprate will interact with this -structure to send requests to the network. There will be multiple tower::Service interfaces to interact with the network -for the different routing methods: - -- broadcast: send a message to all ready `Clients` -- single: use a load balancing algorithm to route a message to a single `Client` -- multiple: sends a request to an amount of peers chosen by the requester, this might be joined with broadcast. - -*There may be more routing methods in the future* +Each request will have to include an origin, e.g self, fluff, so the d++ can route it correctly. --- @@ -142,7 +141,7 @@ for the different routing methods: The verifier will be split into 2 different tower::Services: block and transaction. All checks will be explicit and won't be scattered around the codebase, if for some reason we do have to scatter checks -(some are preformed at de-serialisation for example) they will be referred to in to in the non-scattered +(some are preformed at de-serialisation for example) they will be referred to in to in the non-scattered location. The verifiers tower::Services will be optional and behind a feature flags so projects that need Monero's consensus @@ -158,50 +157,22 @@ old CryptoNight POW(s). #### Transaction -Responsible for validating transactions. This is able to handle one or more transactions at a time to -benefit from batching verification where we can, currently only bulletproofs(+) is able to be batched. -monero-serai already has the API to allow batch verification of bulletproofs(+). Also accepting multiple -transactions will also allow us to use a thread-pool like `rayon` to parallelize verification that can't +Responsible for validating transactions. This is able to handle one or more transactions at a time to +benefit from batching verification where we can, currently only bulletproofs(+) is able to be batched. +monero-serai already has the API to allow batch verification of bulletproofs(+). Also accepting multiple +transactions will also allow us to use a thread-pool like `rayon` to parallelize verification that can't be batched. -Transaction verification will be split into 2 sections: hard and soft. - -##### Hard: -If a transaction fails this, the node will reject the transaction completely including in blocks. - -##### Soft: -If a transaction fails this, the node won't broadcast the transaction but will allow it in blocks. - -This is to make it easy to do things like stopping transaction with too large extra fields and making transactions -follow a standard decoy selection algorithm (this isn't planned) without the need for a hard fork. - ---- - -### Syncer - -The syncer will be responsible for syncing the blockchain after falling behind. It will utilize many of the components -we have discussed, a new tower::Service is needed though `The block downloader`. - -#### The block downloader - -This will be responsible for finding the chain tip and getting blocks from peers, it does no verification* and simply gets -the next block. - -(*) some verification may be done here just to see if the block we got is the one we asked for but TBD. - -The syncer will call the block downloader to get the chain-tip then it will call for the next batch of blocks, when it has this batch -it will send it to the block verifier, which will return if the blocks are valid, if they are we add them to our blockchain. - --- ### Database The database interface will abstract away the underlying database to allow us to easily swap out the database for a different one, -this makes it possible to performance test different databases for our workload, which we plan to do. Initially we plan to go with +this makes it possible to performance test different databases for our workload, which we plan to do. Initially we plan to go with MDBX, a database similar to LMDB which is used in monerod. -We plan to investigate the database schema for optimisations as well, so our schema will more than likely be different than monerods. +We plan to investigate the database schema for optimisations as well, so our schema will more than likely be different than monerods. -Cuprate will interact with the database though a tower::Service providing another layer of abstraction, the service will make use of -the database interface abstraction. This allows us to make use of towers middleware for the database and makes the database conform to +Cuprate will interact with the database though a tower::Service providing another layer of abstraction, the service will make use of +the database interface abstraction. This allows us to make use of towers middleware for the database and makes the database conform to the API of the rest of the node. diff --git a/net/epee-encoding/Cargo.toml b/net/epee-encoding/Cargo.toml new file mode 100644 index 0000000..8132c2f --- /dev/null +++ b/net/epee-encoding/Cargo.toml @@ -0,0 +1,26 @@ +[package] +name = "epee-encoding" +version = "0.5.0" +edition = "2021" +license = "MIT" +authors = ["Boog900"] +readme = "README.md" +keywords = ["monero", "epee", "no-std"] +description = "Epee binary format library." +repository = "https://github.com/Boog900/epee-encoding" +rust-version = "1.60" + +[features] +default = ["std"] +std = ["dep:thiserror", "bytes/std", "fixed-bytes/std"] + +[dependencies] +fixed-bytes = { path = "../fixed-bytes", default-features = false } + +sealed = "0.5.0" +paste = "1.0.14" +bytes = { workspace = true } +thiserror = { workspace = true, optional = true} + +[dev-dependencies] +hex = { workspace = true, features = ["default"] } diff --git a/net/epee-encoding/LICENSE b/net/epee-encoding/LICENSE new file mode 100644 index 0000000..0e5fe08 --- /dev/null +++ b/net/epee-encoding/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023 Boog900 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/net/epee-encoding/README.md b/net/epee-encoding/README.md new file mode 100644 index 0000000..d182524 --- /dev/null +++ b/net/epee-encoding/README.md @@ -0,0 +1,202 @@ +# Epee Encoding + +- [What](#what) +- [Features](#features) +- [Usage](#usage) +- [Derive Attributes](#derive-attributes) +- [No std](#no-std) +- [Options](#options) + +## What +This crate implements the epee binary format found in Monero; unlike other crates, +this one does not use serde, this is not because serde is bad but its to reduce the +load on maintainers as all the traits in this lib are specific to epee instead of +general purpose. + +## Features + +### Default + +The default feature enables the [derive](#derive) feature. + +### Derive + +This feature enables the derive macro for creating epee objects for example: + +```rust +use epee_encoding::EpeeObject; +#[derive(EpeeObject)] +struct Test { + val: u8 +} +``` + +## Usage + +### example without derive: +```rust +use epee_encoding::{EpeeObject, EpeeObjectBuilder, read_epee_value, write_field, to_bytes, from_bytes}; +use epee_encoding::io::{Read, Write}; + +pub struct Test { + val: u64 +} + +#[derive(Default)] +pub struct __TestEpeeBuilder { + val: Option, +} + +impl EpeeObjectBuilder for __TestEpeeBuilder { + fn add_field(&mut self, name: &str, r: &mut R) -> epee_encoding::error::Result { + match name { + "val" => {self.val = Some(read_epee_value(r)?);} + _ => return Ok(false), + } + Ok(true) + } + + fn finish(self) -> epee_encoding::error::Result { + Ok( + Test { + val: self.val.ok_or_else(|| epee_encoding::error::Error::Format("Required field was not found!"))? + } + ) + } +} + +impl EpeeObject for Test { + type Builder = __TestEpeeBuilder; + + fn number_of_fields(&self) -> u64 { + 1 + } + + fn write_fields(&self, w: &mut W) -> epee_encoding::error::Result<()> { + // write the fields + write_field(&self.val, "val", w) + } +} + + +let data = [1, 17, 1, 1, 1, 1, 2, 1, 1, 4, 3, 118, 97, 108, 5, 4, 0, 0, 0, 0, 0, 0, 0]; // the data to decode; +let val: Test = from_bytes(&data).unwrap(); +let data = to_bytes(&val).unwrap(); + + +``` + +### example with derive: +```rust +use epee_encoding::{EpeeObject, from_bytes, to_bytes}; + +#[derive(EpeeObject)] +struct Test { + val: u64 +} + + +let data = [1, 17, 1, 1, 1, 1, 2, 1, 1, 4, 3, 118, 97, 108, 5, 4, 0, 0, 0, 0, 0, 0, 0]; // the data to decode; +let val: Test = from_bytes(&data).unwrap(); +let data = to_bytes(&val).unwrap(); + +``` + +## Derive Attributes + +The `EpeeObject` derive macro has a few attributes which correspond to specific C/C++ macro fields. + +- [epee_flatten](#epeeflatten) +- [epee_alt_name](#epeealtname) +- [epee_default](#epeedefault) + +### epee_flatten + +This is equivalent to `KV_SERIALIZE_PARENT`, it flattens all the fields in the object into the parent object. + +so this in C/C++: +```cpp +struct request_t: public rpc_request_base + { + uint8_t major_version; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE_PARENT(rpc_request_base) + KV_SERIALIZE(major_version) + END_KV_SERIALIZE_MAP() + }; +``` +Would look like this in Rust: +```rust +#[derive(EpeeObject)] +struct RequestT { + #[epee_flatten] + rpc_request_base: RequestBase, + major_version: u8, +} +``` + +### epee_alt_name + +This allows you to re-name a field for when its encoded, although this isn't related to a specific macro in +C/C++ this was included because Monero has [some odd names](https://github.com/monero-project/monero/blob/0a1eaf26f9dd6b762c2582ee12603b2a4671c735/src/cryptonote_protocol/cryptonote_protocol_defs.h#L199). + +example: +```rust +#[derive(EpeeObject)] +pub struct HandshakeR { + #[epee_alt_name("node_data")] + pub node_daa: BasicNodeData, +} +``` + +### epee_default + +This is equivalent to `KV_SERIALIZE_OPT` and allows you to specify a default value for a field, when a default value +is specified the value will be used if it is not contained in the data and the field will not be encoded if the value is +the default value. + +so this in C/C++: +```cpp +struct request_t +{ + std::vector txs; + std::string _; // padding + bool dandelionpp_fluff; //zero initialization defaults to stem mode + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(txs) + KV_SERIALIZE(_) + KV_SERIALIZE_OPT(dandelionpp_fluff, true) // backwards compatible mode is fluff + END_KV_SERIALIZE_MAP() +}; +``` + +would look like this in Rust: +```rust +#[derive(EpeeObject)] +struct RequestT { + txs: Vec>, + #[epee_alt_name("_")] + padding: Vec, + #[epee_default(true)] + dandelionpp_fluff: bool, +} +``` + +## No std + +This crate is no-std. + +## Options + +To have an optional field, you should wrap the type in `Option` and use the `epee_default` attribute. +So it would look like this: + +```rust +#[derive(EpeeObject)] +struct T { + #[epee_default(None)] + val: Option, +} +``` \ No newline at end of file diff --git a/net/epee-encoding/src/error.rs b/net/epee-encoding/src/error.rs new file mode 100644 index 0000000..efe517f --- /dev/null +++ b/net/epee-encoding/src/error.rs @@ -0,0 +1,52 @@ +use core::fmt::{Debug, Formatter}; +use core::{num::TryFromIntError, str::Utf8Error}; + +pub type Result = core::result::Result; + +#[cfg_attr(feature = "std", derive(thiserror::Error))] +pub enum Error { + #[cfg_attr(feature = "std", error("IO error: {0}"))] + IO(&'static str), + #[cfg_attr(feature = "std", error("Format error: {0}"))] + Format(&'static str), + #[cfg_attr(feature = "std", error("Value error: {0}"))] + Value(&'static str), +} + +impl Error { + fn field_name(&self) -> &'static str { + match self { + Error::IO(_) => "io", + Error::Format(_) => "format", + Error::Value(_) => "value", + } + } + + fn field_data(&self) -> &'static str { + match self { + Error::IO(data) => data, + Error::Format(data) => data, + Error::Value(data) => data, + } + } +} + +impl Debug for Error { + fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { + f.debug_struct("Error") + .field(self.field_name(), &self.field_data()) + .finish() + } +} + +impl From for Error { + fn from(_: TryFromIntError) -> Self { + Error::Value("Int is too large") + } +} + +impl From for Error { + fn from(_: Utf8Error) -> Self { + Error::Value("Invalid utf8 str") + } +} diff --git a/net/epee-encoding/src/io.rs b/net/epee-encoding/src/io.rs new file mode 100644 index 0000000..4f4240d --- /dev/null +++ b/net/epee-encoding/src/io.rs @@ -0,0 +1,44 @@ +use bytes::{Buf, BufMut}; + +use crate::error::*; + +#[inline] +pub fn checked_read_primitive( + b: &mut B, + read: impl Fn(&mut B) -> R, +) -> Result { + checked_read(b, read, core::mem::size_of::()) +} + +#[inline] +pub fn checked_read(b: &mut B, read: impl Fn(&mut B) -> R, size: usize) -> Result { + if b.remaining() < size { + Err(Error::IO("Not enough bytes in buffer to build object."))?; + } + + Ok(read(b)) +} + +#[inline] +pub fn checked_write_primitive( + b: &mut B, + write: impl Fn(&mut B, T), + t: T, +) -> Result<()> { + checked_write(b, write, t, core::mem::size_of::()) +} + +#[inline] +pub fn checked_write( + b: &mut B, + write: impl Fn(&mut B, T), + t: T, + size: usize, +) -> Result<()> { + if b.remaining_mut() < size { + Err(Error::IO("Not enough capacity to write object."))?; + } + + write(b, t); + Ok(()) +} diff --git a/net/epee-encoding/src/lib.rs b/net/epee-encoding/src/lib.rs new file mode 100644 index 0000000..611f54d --- /dev/null +++ b/net/epee-encoding/src/lib.rs @@ -0,0 +1,317 @@ +#![cfg_attr(not(feature = "std"), no_std)] +//! Epee Encoding +//! +//! This library contains the Epee binary format found in Monero, unlike other +//! crates this crate does not use serde. +//! +//! example without macro: +//! ```rust +//! # use epee_encoding::{EpeeObject, EpeeObjectBuilder, read_epee_value, write_field, to_bytes, from_bytes}; +//! # use bytes::{Buf, BufMut}; +//! +//! pub struct Test { +//! val: u64 +//! } +//! +//! #[derive(Default)] +//! pub struct __TestEpeeBuilder { +//! val: Option, +//! } +//! +//! impl EpeeObjectBuilder for __TestEpeeBuilder { +//! fn add_field(&mut self, name: &str, r: &mut B) -> epee_encoding::error::Result { +//! match name { +//! "val" => {self.val = Some(read_epee_value(r)?);} +//! _ => return Ok(false), +//! } +//! Ok(true) +//! } +//! +//! fn finish(self) -> epee_encoding::error::Result { +//! Ok( +//! Test { +//! val: self.val.ok_or_else(|| epee_encoding::error::Error::Format("Required field was not found!"))? +//! } +//! ) +//! } +//! } +//! +//! impl EpeeObject for Test { +//! type Builder = __TestEpeeBuilder; +//! +//! fn number_of_fields(&self) -> u64 { +//! 1 +//! } +//! +//! fn write_fields(self, w: &mut B) -> epee_encoding::error::Result<()> { +//! // write the fields +//! write_field(self.val, "val", w) +//! } +//! } +//! +//! +//! let data = [1, 17, 1, 1, 1, 1, 2, 1, 1, 4, 3, 118, 97, 108, 5, 4, 0, 0, 0, 0, 0, 0, 0]; // the data to decode; +//! let val: Test = from_bytes(&data).unwrap(); +//! let data = to_bytes(val).unwrap(); +//! +//! +//! ``` +//! +//! example with macro: +//! ```rust +//! use epee_encoding::{from_bytes, to_bytes}; +//! +//! // TODO: open an issue documenting why you need to do this here +//! // like this: https://github.com/Boog900/epee-encoding/issues/1 +//! mod i_64079 { +//! use epee_encoding::epee_object; +//! +//! pub struct Test2 { +//! val: u64 +//! } +//! +//! epee_object!( +//! Test2, +//! val: u64, +//! ); +//! } +//! use i_64079::*; +//! +//! +//! let data = [1, 17, 1, 1, 1, 1, 2, 1, 1, 4, 3, 118, 97, 108, 5, 4, 0, 0, 0, 0, 0, 0, 0]; // the data to decode; +//! let val: Test2 = from_bytes(&data).unwrap(); +//! let data = to_bytes(val).unwrap(); +//! +//! ``` + +extern crate alloc; + +use alloc::vec::Vec; +use core::{ops::Deref, str::from_utf8 as str_from_utf8}; + +use bytes::{Buf, BufMut, Bytes}; + +pub mod error; +mod io; +pub mod macros; +pub mod marker; +mod value; +mod varint; + +pub use error::*; +use io::*; +pub use marker::{InnerMarker, Marker}; +pub use value::EpeeValue; +use varint::*; + +/// Header that needs to be at the beginning of every binary blob that follows +/// this binary serialization format. +const HEADER: &[u8] = b"\x01\x11\x01\x01\x01\x01\x02\x01\x01"; +/// The maximum length a byte array (marked as a string) can be. +const MAX_STRING_LEN_POSSIBLE: u64 = 2000000000; +/// The maximum depth of skipped objects. +const MAX_DEPTH_OF_SKIPPED_OBJECTS: u8 = 20; +/// The maximum number of fields in an object. +const MAX_NUM_FIELDS: u64 = 1000; + +/// A trait for an object that can build a type `T` from the epee format. +pub trait EpeeObjectBuilder: Default + Sized { + /// Called when a field names has been read no other bytes following the field + /// name will have been read. + /// + /// Returns a bool if true then the field has been read otherwise the field is not + /// needed and has not been read. + fn add_field(&mut self, name: &str, b: &mut B) -> Result; + + /// Called when the number of fields has been read. + fn finish(self) -> Result; +} + +/// A trait for an object that can be turned into epee bytes. +pub trait EpeeObject: Sized { + type Builder: EpeeObjectBuilder; + + /// Returns the number of fields to be encoded. + fn number_of_fields(&self) -> u64; + + /// write the objects fields into the writer. + fn write_fields(self, w: &mut B) -> Result<()>; +} + +/// Read the object `T` from a byte array. +pub fn from_bytes(mut buf: &[u8]) -> Result { + read_head_object(&mut buf) +} + +/// Turn the object into epee bytes. +pub fn to_bytes(val: T) -> Result> { + let mut buf = Vec::::new(); + write_head_object(val, &mut buf)?; + Ok(buf) +} + +fn read_header(r: &mut B) -> Result<()> { + let buf = checked_read(r, |b: &mut B| b.copy_to_bytes(HEADER.len()), HEADER.len())?; + + if buf.deref() != HEADER { + return Err(Error::Format("Data does not contain header")); + } + Ok(()) +} + +fn write_header(w: &mut B) -> Result<()> { + checked_write(w, BufMut::put_slice, HEADER, HEADER.len()) +} + +fn write_head_object(val: T, w: &mut B) -> Result<()> { + write_header(w)?; + val.write(w) +} + +fn read_head_object(r: &mut B) -> Result { + read_header(r)?; + let mut skipped_objects = 0; + read_object(r, &mut skipped_objects) +} + +fn read_field_name_bytes(r: &mut B) -> Result { + let len: usize = r.get_u8().into(); + + checked_read(r, |b: &mut B| b.copy_to_bytes(len), len) +} + +fn write_field_name(val: &str, w: &mut B) -> Result<()> { + checked_write_primitive(w, BufMut::put_u8, val.len().try_into()?)?; + let slice = val.as_bytes(); + checked_write(w, BufMut::put_slice, slice, slice.len()) +} + +/// Write an epee field. +pub fn write_field(val: T, field_name: &str, w: &mut B) -> Result<()> { + if val.should_write() { + write_field_name(field_name, w)?; + write_epee_value(val, w)?; + } + Ok(()) +} + +fn read_object(r: &mut B, skipped_objects: &mut u8) -> Result { + let mut object_builder = T::Builder::default(); + + let number_o_field = read_varint(r)?; + + if number_o_field > MAX_NUM_FIELDS { + return Err(Error::Format( + "Data has object with more fields than the maximum allowed", + )); + } + + for _ in 0..number_o_field { + let field_name_bytes = read_field_name_bytes(r)?; + let field_name = str_from_utf8(field_name_bytes.deref())?; + + if !object_builder.add_field(field_name, r)? { + skip_epee_value(r, skipped_objects)?; + } + } + object_builder.finish() +} + +/// Read a marker from the [`Read`], this function should only be used for +/// custom serialisation based on the marker otherwise just use [`read_epee_value`]. +pub fn read_marker(r: &mut B) -> Result { + Marker::try_from(checked_read_primitive(r, Buf::get_u8)?) +} + +/// Read an epee value from the stream, an epee value is the part after the key +/// including the marker. +pub fn read_epee_value(r: &mut B) -> Result { + let marker = read_marker(r)?; + T::read(r, &marker) +} + +/// Write an epee value to the stream, an epee value is the part after the key +/// including the marker. +fn write_epee_value(val: T, w: &mut B) -> Result<()> { + checked_write_primitive(w, BufMut::put_u8, T::MARKER.as_u8())?; + val.write(w) +} + +/// A helper object builder that just skips every field. +#[derive(Default)] +struct SkipObjectBuilder; + +impl EpeeObjectBuilder for SkipObjectBuilder { + fn add_field(&mut self, _name: &str, _r: &mut B) -> Result { + Ok(false) + } + + fn finish(self) -> Result { + Ok(SkipObject) + } +} + +/// A helper object that just skips every field. +struct SkipObject; + +impl EpeeObject for SkipObject { + type Builder = SkipObjectBuilder; + + fn number_of_fields(&self) -> u64 { + panic!("This is a helper function to use when de-serialising") + } + + fn write_fields(self, _w: &mut B) -> Result<()> { + panic!("This is a helper function to use when de-serialising") + } +} + +/// Skip an epee value, should be used when you do not need the value +/// stored at a key. +fn skip_epee_value(r: &mut B, skipped_objects: &mut u8) -> Result<()> { + let marker = read_marker(r)?; + + let mut len = 1; + if marker.is_seq { + len = read_varint(r)?; + } + + if let Some(size) = marker.inner_marker.size() { + let bytes_to_skip = size + .checked_mul(len.try_into()?) + .ok_or(Error::Value("List is too big"))?; + return advance(bytes_to_skip, r); + }; + + for _ in 0..len { + match marker.inner_marker { + InnerMarker::I64 + | InnerMarker::U64 + | InnerMarker::F64 + | InnerMarker::I32 + | InnerMarker::U32 + | InnerMarker::I16 + | InnerMarker::U16 + | InnerMarker::I8 + | InnerMarker::U8 + | InnerMarker::Bool => unreachable!("These types are constant size."), + InnerMarker::String => { + let len = read_varint(r)?; + advance(len.try_into()?, r)?; + } + InnerMarker::Object => { + *skipped_objects += 1; + if *skipped_objects > MAX_DEPTH_OF_SKIPPED_OBJECTS { + return Err(Error::Format("Depth of skipped objects exceeded maximum")); + } + read_object::(r, skipped_objects)?; + *skipped_objects -= 1; + } + }; + } + Ok(()) +} + +fn advance(n: usize, b: &mut B) -> Result<()> { + checked_read(b, |b: &mut B| b.advance(n), n) +} diff --git a/net/epee-encoding/src/macros.rs b/net/epee-encoding/src/macros.rs new file mode 100644 index 0000000..578a414 --- /dev/null +++ b/net/epee-encoding/src/macros.rs @@ -0,0 +1,125 @@ +pub use bytes; +pub use paste::paste; + +#[macro_export] +macro_rules! field_name { + ($field: ident, $alt_name: literal) => { + $alt_name + }; + ($field: ident,) => { + stringify!($field) + }; +} + +#[macro_export] +macro_rules! field_ty { + ($ty:ty, $ty_as:ty) => { + $ty_as + }; + ($ty:ty,) => { + $ty + }; +} + +#[macro_export] +macro_rules! epee_object { + ( + $obj:ident, + $($field: ident $(($alt_name: literal))?: $ty:ty $(= $default:literal)? $(as $ty_as:ty)?, )+ + $(!flatten: $($flat_field: ident: $flat_ty:ty ,)+)? + + ) => { + epee_encoding::macros::paste!( + #[allow(non_snake_case)] + mod [<__epee_builder_ $obj>] { + use super::*; + + #[derive(Default)] + pub struct [<__Builder $obj>] { + $($field: Option,)+ + $($($flat_field: <$flat_ty as epee_encoding::EpeeObject>::Builder,)+)? + } + + impl epee_encoding::EpeeObjectBuilder<$obj> for [<__Builder $obj>] { + fn add_field(&mut self, name: &str, b: &mut B) -> epee_encoding::error::Result { + match name { + $(epee_encoding::field_name!($field, $($alt_name)?) => { + if core::mem::replace(&mut self.$field, Some(epee_encoding::read_epee_value(b)?)).is_some() { + Err(epee_encoding::error::Error::Value("Duplicate field in data"))?; + } + Ok(true) + },)+ + _ => { + $( + $( if self.$flat_field.add_field(name, b)? { + return Ok(true); + })+ + )? + + Ok(false) + } + } + } + + fn finish(self) -> epee_encoding::error::Result<$obj> { + Ok( + $obj { + $( + $field: self.$field + $(.or(Some($default)))? + .or(epee_encoding::EpeeValue::epee_default_value()) + $(.map(<$ty_as>::into))? + .ok_or(epee_encoding::error::Error::Value("Missing field in data"))?, + )+ + + $( + $( + $flat_field: self.$flat_field.finish()?, + )+ + )? + } + ) + } + } + } + + impl epee_encoding::EpeeObject for $obj { + type Builder = [<__epee_builder_ $obj>]::[<__Builder $obj>]; + + fn number_of_fields(&self) -> u64 { + let mut fields = 0; + + $( + if $(&self.$field != &$default &&)? epee_encoding::EpeeValue::should_write($(<&$ty_as>::from)?( &self.$field) ) { + fields += 1; + } + )+ + + $( + $( + fields += self.$flat_field.number_of_fields(); + )+ + )? + + fields + } + + fn write_fields(self, w: &mut B) -> epee_encoding::error::Result<()> { + $( + if $(&self.$field != &$default &&)? epee_encoding::EpeeValue::should_write($(<&$ty_as>::from)?( &self.$field) ) { + epee_encoding::write_field($(<$ty_as>::from)?(self.$field), epee_encoding::field_name!($field, $($alt_name)?), w)?; + } + )+ + + $( + $( + self.$flat_field.write_fields(w)?; + )+ + )? + + Ok(()) + } + } + ); + }; +} diff --git a/net/epee-encoding/src/marker.rs b/net/epee-encoding/src/marker.rs new file mode 100644 index 0000000..d8ffc4b --- /dev/null +++ b/net/epee-encoding/src/marker.rs @@ -0,0 +1,120 @@ +/// This module contains a [`Marker`] which is appended before each value to tell you the type. +use crate::Error; + +/// The inner marker just telling you the type. +#[derive(Debug, Clone, Copy, Eq, PartialEq)] +pub enum InnerMarker { + I64, + I32, + I16, + I8, + U64, + U32, + U16, + U8, + F64, + String, + Bool, + Object, +} + +impl InnerMarker { + pub fn size(&self) -> Option { + Some(match self { + InnerMarker::I64 | InnerMarker::U64 | InnerMarker::F64 => 8, + InnerMarker::I32 | InnerMarker::U32 => 4, + InnerMarker::I16 | InnerMarker::U16 => 2, + InnerMarker::I8 | InnerMarker::U8 | InnerMarker::Bool => 1, + InnerMarker::String | InnerMarker::Object => return None, + }) + } +} + +/// A marker appended before Epee values which tell you the type of the field and if +/// its a sequence. +#[derive(Debug, Clone, Eq, PartialEq)] +pub struct Marker { + pub inner_marker: InnerMarker, + pub is_seq: bool, +} + +impl Marker { + pub(crate) const fn new(inner_marker: InnerMarker) -> Self { + Marker { + inner_marker, + is_seq: false, + } + } + pub const fn into_seq(self) -> Self { + if self.is_seq { + panic!("Sequence of sequence not allowed!"); + } + if matches!(self.inner_marker, InnerMarker::U8) { + return Marker { + inner_marker: InnerMarker::String, + is_seq: false, + }; + } + + Marker { + inner_marker: self.inner_marker, + is_seq: true, + } + } + + pub const fn as_u8(&self) -> u8 { + let marker_val = match self.inner_marker { + InnerMarker::I64 => 1, + InnerMarker::I32 => 2, + InnerMarker::I16 => 3, + InnerMarker::I8 => 4, + InnerMarker::U64 => 5, + InnerMarker::U32 => 6, + InnerMarker::U16 => 7, + InnerMarker::U8 => 8, + InnerMarker::F64 => 9, + InnerMarker::String => 10, + InnerMarker::Bool => 11, + InnerMarker::Object => 12, + }; + + if self.is_seq { + marker_val | 0x80 + } else { + marker_val + } + } +} + +impl TryFrom for Marker { + type Error = Error; + + fn try_from(mut value: u8) -> Result { + let is_seq = value & 0x80 > 0; + + if is_seq { + value ^= 0x80; + } + + let inner_marker = match value { + 1 => InnerMarker::I64, + 2 => InnerMarker::I32, + 3 => InnerMarker::I16, + 4 => InnerMarker::I8, + 5 => InnerMarker::U64, + 6 => InnerMarker::U32, + 7 => InnerMarker::U16, + 8 => InnerMarker::U8, + 9 => InnerMarker::F64, + 10 => InnerMarker::String, + 11 => InnerMarker::Bool, + 12 => InnerMarker::Object, + _ => return Err(Error::Format("Unknown value Marker")), + }; + + Ok(Marker { + inner_marker, + is_seq, + }) + } +} diff --git a/net/epee-encoding/src/value.rs b/net/epee-encoding/src/value.rs new file mode 100644 index 0000000..4490726 --- /dev/null +++ b/net/epee-encoding/src/value.rs @@ -0,0 +1,511 @@ +use alloc::{string::String, vec::Vec}; +/// This module contains a `sealed` [`EpeeValue`] trait and different impls for +/// the different possible base epee values. +use core::fmt::Debug; + +use bytes::{Buf, BufMut, Bytes}; +use sealed::sealed; + +use fixed_bytes::{ByteArray, ByteArrayVec}; + +use crate::{ + io::*, varint::*, EpeeObject, Error, InnerMarker, Marker, Result, MAX_STRING_LEN_POSSIBLE, +}; + +/// A trait for epee values, this trait is sealed as all possible epee values are +/// defined in the lib, to make an [`EpeeValue`] outside the lib you will need to +/// use the trait [`EpeeObject`]. +#[sealed] +pub trait EpeeValue: Sized { + const MARKER: Marker; + + fn read(r: &mut B, marker: &Marker) -> Result; + + fn should_write(&self) -> bool { + true + } + + /// This is different than default field values and instead is the default + /// value of a whole type. + /// + /// For example a `Vec` has a default value of a zero length vec as when a + /// sequence has no entries it is not encoded. + fn epee_default_value() -> Option { + None + } + + fn write(self, w: &mut B) -> Result<()>; +} + +#[sealed] +impl EpeeValue for T { + const MARKER: Marker = Marker::new(InnerMarker::Object); + + fn read(r: &mut B, marker: &Marker) -> Result { + if marker != &Self::MARKER { + return Err(Error::Format("Marker does not match expected Marker")); + } + + let mut skipped_objects = 0; + crate::read_object(r, &mut skipped_objects) + } + + fn write(self, w: &mut B) -> Result<()> { + write_varint(self.number_of_fields(), w)?; + self.write_fields(w) + } +} + +#[sealed] +impl EpeeValue for Vec { + const MARKER: Marker = T::MARKER.into_seq(); + + fn read(r: &mut B, marker: &Marker) -> Result { + if !marker.is_seq { + return Err(Error::Format( + "Marker is not sequence when a sequence was expected", + )); + } + let len = read_varint(r)?; + + let individual_marker = Marker::new(marker.inner_marker); + + let mut res = Vec::with_capacity(len.try_into()?); + for _ in 0..len { + res.push(T::read(r, &individual_marker)?); + } + Ok(res) + } + + fn should_write(&self) -> bool { + !self.is_empty() + } + + fn epee_default_value() -> Option { + Some(Vec::new()) + } + + fn write(self, w: &mut B) -> Result<()> { + write_varint(self.len().try_into()?, w)?; + for item in self.into_iter() { + item.write(w)?; + } + Ok(()) + } +} + +#[sealed] +impl EpeeValue for [T; N] { + const MARKER: Marker = ::MARKER.into_seq(); + + fn read(r: &mut B, marker: &Marker) -> Result { + let vec = Vec::::read(r, marker)?; + + if vec.len() != N { + return Err(Error::Format("Array has incorrect length")); + } + + Ok(vec.try_into().unwrap()) + } + + fn write(self, w: &mut B) -> Result<()> { + write_varint(self.len().try_into()?, w)?; + for item in self.into_iter() { + item.write(w)?; + } + Ok(()) + } +} + +macro_rules! epee_numb { + ($numb:ty, $marker:ident, $read_fn:ident, $write_fn:ident) => { + #[sealed] + impl EpeeValue for $numb { + const MARKER: Marker = Marker::new(InnerMarker::$marker); + + fn read(r: &mut B, marker: &Marker) -> Result { + if marker != &Self::MARKER { + return Err(Error::Format("Marker does not match expected Marker")); + } + + checked_read_primitive(r, Buf::$read_fn) + } + + fn write(self, w: &mut B) -> Result<()> { + checked_write_primitive(w, BufMut::$write_fn, self) + } + } + }; +} + +epee_numb!(i64, I64, get_i64_le, put_i64_le); +epee_numb!(i32, I32, get_i32_le, put_i32_le); +epee_numb!(i16, I16, get_i16_le, put_i16_le); +epee_numb!(i8, I8, get_i8, put_i8); +epee_numb!(u8, U8, get_u8, put_u8); +epee_numb!(u16, U16, get_u16_le, put_u16_le); +epee_numb!(u32, U32, get_u32_le, put_u32_le); +epee_numb!(u64, U64, get_u64_le, put_u64_le); +epee_numb!(f64, F64, get_f64_le, put_f64_le); + +#[sealed] +impl EpeeValue for bool { + const MARKER: Marker = Marker::new(InnerMarker::Bool); + + fn read(r: &mut B, marker: &Marker) -> Result { + if marker != &Self::MARKER { + return Err(Error::Format("Marker does not match expected Marker")); + } + + Ok(checked_read_primitive(r, Buf::get_u8)? != 0) + } + + fn write(self, w: &mut B) -> Result<()> { + checked_write_primitive(w, BufMut::put_u8, if self { 1 } else { 0 }) + } +} + +#[sealed] +impl EpeeValue for Vec { + const MARKER: Marker = Marker::new(InnerMarker::String); + + fn read(r: &mut B, marker: &Marker) -> Result { + if marker != &Self::MARKER { + return Err(Error::Format("Marker does not match expected Marker")); + } + + let len = read_varint(r)?; + if len > MAX_STRING_LEN_POSSIBLE { + return Err(Error::Format("Byte array exceeded max length")); + } + + if r.remaining() < len.try_into()? { + return Err(Error::IO("Not enough bytes to fill object")); + } + + let mut res = vec![0; len.try_into()?]; + r.copy_to_slice(&mut res); + + Ok(res) + } + + fn write(self, w: &mut B) -> Result<()> { + write_varint(self.len().try_into()?, w)?; + + if w.remaining_mut() < self.len() { + return Err(Error::IO("Not enough capacity to write bytes")); + } + + w.put_slice(&self); + Ok(()) + } +} + +#[sealed::sealed] +impl EpeeValue for Bytes { + const MARKER: Marker = Marker::new(InnerMarker::String); + + fn read(r: &mut B, marker: &Marker) -> Result { + if marker != &Self::MARKER { + return Err(Error::Format("Marker does not match expected Marker")); + } + + let len = read_varint(r)?; + if len > MAX_STRING_LEN_POSSIBLE { + return Err(Error::Format("Byte array exceeded max length")); + } + + if r.remaining() < len.try_into()? { + return Err(Error::IO("Not enough bytes to fill object")); + } + + Ok(r.copy_to_bytes(len.try_into()?)) + } + + fn write(self, w: &mut B) -> Result<()> { + write_varint(self.len().try_into()?, w)?; + + if w.remaining_mut() < self.len() { + return Err(Error::IO("Not enough capacity to write bytes")); + } + + w.put(self); + Ok(()) + } +} + +#[sealed::sealed] +impl EpeeValue for ByteArrayVec { + const MARKER: Marker = Marker::new(InnerMarker::String); + + fn read(r: &mut B, marker: &Marker) -> Result { + if marker != &Self::MARKER { + return Err(Error::Format("Marker does not match expected Marker")); + } + + let len = read_varint(r)?; + if len > MAX_STRING_LEN_POSSIBLE { + return Err(Error::Format("Byte array exceeded max length")); + } + + if r.remaining() + < usize::try_from(len)? + .checked_mul(N) + .ok_or(Error::Value("Length of field is too long"))? + { + return Err(Error::IO("Not enough bytes to fill object")); + } + + ByteArrayVec::try_from(r.copy_to_bytes(usize::try_from(len)?)) + .map_err(|_| Error::Format("Field has invalid length")) + } + + fn write(self, w: &mut B) -> Result<()> { + let bytes = self.take_bytes(); + + write_varint(bytes.len().try_into()?, w)?; + + if w.remaining_mut() < bytes.len() { + return Err(Error::IO("Not enough capacity to write bytes")); + } + + w.put(bytes); + Ok(()) + } +} + +#[sealed::sealed] +impl EpeeValue for ByteArray { + const MARKER: Marker = Marker::new(InnerMarker::String); + + fn read(r: &mut B, marker: &Marker) -> Result { + if marker != &Self::MARKER { + return Err(Error::Format("Marker does not match expected Marker")); + } + + let len: usize = read_varint(r)?.try_into()?; + if len != N { + return Err(Error::Format("Byte array has incorrect length")); + } + + if r.remaining() < N { + return Err(Error::IO("Not enough bytes to fill object")); + } + + ByteArray::try_from(r.copy_to_bytes(N)) + .map_err(|_| Error::Format("Field has invalid length")) + } + + fn write(self, w: &mut B) -> Result<()> { + let bytes = self.take_bytes(); + + write_varint(N.try_into().unwrap(), w)?; + + if w.remaining_mut() < N { + return Err(Error::IO("Not enough capacity to write bytes")); + } + + w.put(bytes); + Ok(()) + } +} + +#[sealed] +impl EpeeValue for String { + const MARKER: Marker = Marker::new(InnerMarker::String); + + fn read(r: &mut B, marker: &Marker) -> Result { + let bytes = Vec::::read(r, marker)?; + String::from_utf8(bytes).map_err(|_| Error::Format("Invalid string")) + } + + fn should_write(&self) -> bool { + !self.is_empty() + } + + fn epee_default_value() -> Option { + Some(String::new()) + } + + fn write(self, w: &mut B) -> Result<()> { + write_varint(self.len().try_into()?, w)?; + + if w.remaining_mut() < self.len() { + return Err(Error::IO("Not enough capacity to write bytes")); + } + + w.put_slice(self.as_bytes()); + Ok(()) + } +} + +#[sealed] +impl EpeeValue for [u8; N] { + const MARKER: Marker = Marker::new(InnerMarker::String); + + fn read(r: &mut B, marker: &Marker) -> Result { + let bytes = Vec::::read(r, marker)?; + + if bytes.len() != N { + return Err(Error::Format("Byte array has incorrect length")); + } + + Ok(bytes.try_into().unwrap()) + } + + fn write(self, w: &mut B) -> Result<()> { + write_varint(self.len().try_into()?, w)?; + + if w.remaining_mut() < self.len() { + return Err(Error::IO("Not enough capacity to write bytes")); + } + + w.put_slice(&self); + Ok(()) + } +} + +#[sealed] +impl EpeeValue for Vec<[u8; N]> { + const MARKER: Marker = <[u8; N]>::MARKER.into_seq(); + + fn read(r: &mut B, marker: &Marker) -> Result { + if !marker.is_seq { + return Err(Error::Format( + "Marker is not sequence when a sequence was expected", + )); + } + + let len = read_varint(r)?; + + let individual_marker = Marker::new(marker.inner_marker); + + let mut res = Vec::with_capacity(len.try_into()?); + for _ in 0..len { + res.push(<[u8; N]>::read(r, &individual_marker)?); + } + Ok(res) + } + + fn should_write(&self) -> bool { + !self.is_empty() + } + + fn epee_default_value() -> Option { + Some(Vec::new()) + } + + fn write(self, w: &mut B) -> Result<()> { + write_varint(self.len().try_into()?, w)?; + for item in self.into_iter() { + item.write(w)?; + } + Ok(()) + } +} + +macro_rules! epee_seq { + ($val:ty) => { + #[sealed] + impl EpeeValue for Vec<$val> { + const MARKER: Marker = <$val>::MARKER.into_seq(); + + fn read(r: &mut B, marker: &Marker) -> Result { + if !marker.is_seq { + return Err(Error::Format( + "Marker is not sequence when a sequence was expected", + )); + } + + let len = read_varint(r)?; + + let individual_marker = Marker::new(marker.inner_marker.clone()); + + let mut res = Vec::with_capacity(len.try_into()?); + for _ in 0..len { + res.push(<$val>::read(r, &individual_marker)?); + } + Ok(res) + } + + fn should_write(&self) -> bool { + !self.is_empty() + } + + fn epee_default_value() -> Option { + Some(Vec::new()) + } + + fn write(self, w: &mut B) -> Result<()> { + write_varint(self.len().try_into()?, w)?; + for item in self.into_iter() { + item.write(w)?; + } + Ok(()) + } + } + + #[sealed] + impl EpeeValue for [$val; N] { + const MARKER: Marker = <$val>::MARKER.into_seq(); + + fn read(r: &mut B, marker: &Marker) -> Result { + let vec = Vec::<$val>::read(r, marker)?; + + if vec.len() != N { + return Err(Error::Format("Array has incorrect length")); + } + + Ok(vec.try_into().unwrap()) + } + + fn write(self, w: &mut B) -> Result<()> { + write_varint(self.len().try_into()?, w)?; + for item in self.into_iter() { + item.write(w)?; + } + Ok(()) + } + } + }; +} + +epee_seq!(i64); +epee_seq!(i32); +epee_seq!(i16); +epee_seq!(i8); +epee_seq!(u64); +epee_seq!(u32); +epee_seq!(u16); +epee_seq!(f64); +epee_seq!(bool); +epee_seq!(Vec); +epee_seq!(String); + +#[sealed] +impl EpeeValue for Option { + const MARKER: Marker = T::MARKER; + + fn read(r: &mut B, marker: &Marker) -> Result { + Ok(Some(T::read(r, marker)?)) + } + + fn should_write(&self) -> bool { + match self { + Some(t) => t.should_write(), + None => false, + } + } + + fn epee_default_value() -> Option { + Some(None) + } + + fn write(self, w: &mut B) -> Result<()> { + match self { + Some(t) => t.write(w)?, + None => panic!("Can't write an Option::None value, this should be handled elsewhere"), + } + Ok(()) + } +} diff --git a/net/epee-encoding/src/varint.rs b/net/epee-encoding/src/varint.rs new file mode 100644 index 0000000..5de4eed --- /dev/null +++ b/net/epee-encoding/src/varint.rs @@ -0,0 +1,91 @@ +use bytes::{Buf, BufMut}; + +use crate::error::*; + +const SIZE_OF_SIZE_MARKER: u32 = 2; +const FITS_IN_ONE_BYTE: u64 = 2_u64.pow(8 - SIZE_OF_SIZE_MARKER) - 1; +const FITS_IN_TWO_BYTES: u64 = 2_u64.pow(16 - SIZE_OF_SIZE_MARKER) - 1; +const FITS_IN_FOUR_BYTES: u64 = 2_u64.pow(32 - SIZE_OF_SIZE_MARKER) - 1; + +pub fn read_varint(r: &mut B) -> Result { + if !r.has_remaining() { + Err(Error::IO("Not enough bytes to build VarInt"))? + } + + let vi_start = r.get_u8(); + let len = 1 << (vi_start & 0b11); + + if r.remaining() < len - 1 { + Err(Error::IO("Not enough bytes to build VarInt"))? + } + + let mut vi = u64::from(vi_start >> 2); + for i in 1..len { + vi |= u64::from(r.get_u8()) << (((i - 1) * 8) + 6); + } + Ok(vi) +} + +pub fn write_varint(number: u64, w: &mut B) -> Result<()> { + let size_marker = match number { + 0..=FITS_IN_ONE_BYTE => 0, + 64..=FITS_IN_TWO_BYTES => 1, + 16384..=FITS_IN_FOUR_BYTES => 2, + _ => 3, + }; + + if w.remaining_mut() < 1 << size_marker { + Err(Error::IO("Not enough capacity to write VarInt"))?; + } + + let number = (number << 2) | size_marker; + + // Although `as` is unsafe we just checked the length. + match size_marker { + 0 => w.put_u8(number as u8), + 1 => w.put_u16_le(number as u16), + 2 => w.put_u32_le(number as u32), + 3 => w.put_u64_le(number), + _ => unreachable!(), + } + + Ok(()) +} + +#[cfg(test)] +mod tests { + + use alloc::vec::Vec; + + use crate::varint::*; + + fn assert_varint_length(number: u64, len: usize) { + let mut w = Vec::new(); + write_varint(number, &mut w).unwrap(); + assert_eq!(w.len(), len); + } + + fn assert_varint_val(mut varint: &[u8], val: u64) { + assert_eq!(read_varint(&mut varint).unwrap(), val); + } + + #[test] + fn varint_write_length() { + assert_varint_length(FITS_IN_ONE_BYTE, 1); + assert_varint_length(FITS_IN_ONE_BYTE + 1, 2); + assert_varint_length(FITS_IN_TWO_BYTES, 2); + assert_varint_length(FITS_IN_TWO_BYTES + 1, 4); + assert_varint_length(FITS_IN_FOUR_BYTES, 4); + assert_varint_length(FITS_IN_FOUR_BYTES + 1, 8); + } + + #[test] + fn varint_read() { + assert_varint_val(&[252], FITS_IN_ONE_BYTE); + assert_varint_val(&[1, 1], FITS_IN_ONE_BYTE + 1); + assert_varint_val(&[253, 255], FITS_IN_TWO_BYTES); + assert_varint_val(&[2, 0, 1, 0], FITS_IN_TWO_BYTES + 1); + assert_varint_val(&[254, 255, 255, 255], FITS_IN_FOUR_BYTES); + assert_varint_val(&[3, 0, 0, 0, 1, 0, 0, 0], FITS_IN_FOUR_BYTES + 1); + } +} diff --git a/net/epee-encoding/tests/alt_name.rs b/net/epee-encoding/tests/alt_name.rs new file mode 100644 index 0000000..cce9084 --- /dev/null +++ b/net/epee-encoding/tests/alt_name.rs @@ -0,0 +1,35 @@ +use epee_encoding::{epee_object, from_bytes, to_bytes}; + +struct AltName { + val: u8, + d: u64, +} + +epee_object!( + AltName, + val("val2"): u8, + d: u64, +); + +struct AltName2 { + val2: u8, + d: u64, +} + +epee_object!( + AltName2, + val2: u8, + d: u64, +); + +#[test] +fn epee_alt_name() { + let val2 = AltName2 { val2: 40, d: 30 }; + let bytes = to_bytes(val2).unwrap(); + + let val: AltName = from_bytes(&bytes).unwrap(); + + let bytes2 = to_bytes(val).unwrap(); + + assert_eq!(bytes, bytes2); +} diff --git a/net/epee-encoding/tests/duplicate_key.rs b/net/epee-encoding/tests/duplicate_key.rs new file mode 100644 index 0000000..d2b54b8 --- /dev/null +++ b/net/epee-encoding/tests/duplicate_key.rs @@ -0,0 +1,39 @@ +use epee_encoding::{epee_object, from_bytes}; + +struct T { + a: u8, +} + +epee_object!( + T, + a: u8, +); + +struct TT { + a: u8, +} + +epee_object!( + TT, + a: u8 = 0, +); + +#[test] +fn duplicate_key() { + let data = [ + 0x01, 0x11, 0x01, 0x1, 0x01, 0x01, 0x02, 0x1, 0x1, 0x08, 0x01, b'a', 0x0B, 0x00, 0x01, + b'a', 0x0B, 0x00, + ]; + + assert!(from_bytes::(&data).is_err()); +} + +#[test] +fn duplicate_key_with_default() { + let data = [ + 0x01, 0x11, 0x01, 0x1, 0x01, 0x01, 0x02, 0x1, 0x1, 0x08, 0x01, b'a', 0x0B, 0x00, 0x01, + b'a', 0x0B, 0x00, + ]; + + assert!(from_bytes::(&data).is_err()); +} diff --git a/net/epee-encoding/tests/epee_default.rs b/net/epee-encoding/tests/epee_default.rs new file mode 100644 index 0000000..e4a480e --- /dev/null +++ b/net/epee-encoding/tests/epee_default.rs @@ -0,0 +1,74 @@ +use epee_encoding::{epee_object, from_bytes, to_bytes}; + +pub struct Optional { + val: u8, + optional_val: i32, +} + +epee_object!( + Optional, + val: u8, + optional_val: i32 = -4, +); +pub struct NotOptional { + val: u8, + optional_val: i32, +} + +epee_object!( + NotOptional, + val: u8, + optional_val: i32, +); + +#[derive(Default)] +pub struct NotPresent { + val: u8, +} + +epee_object!( + NotPresent, + val: u8, +); + +#[test] +fn epee_default_does_not_encode() { + let val = Optional { + val: 1, + optional_val: -4, + }; + let bytes = to_bytes(val).unwrap(); + + assert!(from_bytes::(&bytes).is_err()); + + let val: Optional = from_bytes(&bytes).unwrap(); + assert_eq!(val.optional_val, -4); + assert_eq!(val.val, 1); +} + +#[test] +fn epee_non_default_does_encode() { + let val = Optional { + val: 8, + optional_val: -3, + }; + let bytes = to_bytes(val).unwrap(); + + assert!(from_bytes::(&bytes).is_ok()); + + let val: Optional = from_bytes(&bytes).unwrap(); + assert_eq!(val.optional_val, -3); + assert_eq!(val.val, 8) +} + +#[test] +fn epee_value_not_present_with_default() { + let val = NotPresent { val: 76 }; + let bytes = to_bytes(val).unwrap(); + + assert!(from_bytes::(&bytes).is_err()); + + let val: Optional = from_bytes(&bytes).unwrap(); + assert_eq!(val.optional_val, -4); + assert_eq!(val.val, 76) +} diff --git a/net/epee-encoding/tests/flattend.rs b/net/epee-encoding/tests/flattend.rs new file mode 100644 index 0000000..b84b389 --- /dev/null +++ b/net/epee-encoding/tests/flattend.rs @@ -0,0 +1,102 @@ +use epee_encoding::{epee_object, from_bytes, to_bytes}; + +struct Child { + val: u64, + val2: Vec, +} + +epee_object!( + Child, + val: u64, + val2: Vec, +); +struct Parent { + child: Child, + h: f64, +} + +epee_object!( + Parent, + h: f64, + !flatten: + child: Child, +); + +#[derive(Clone)] +struct ParentChild { + h: f64, + val: u64, + val2: Vec, +} + +epee_object!( + ParentChild, + h: f64, + val: u64, + val2: Vec, +); + +#[test] +fn epee_flatten() { + let val2 = ParentChild { + h: 38.9, + val: 94, + val2: vec![4, 5], + }; + let bytes = to_bytes(val2.clone()).unwrap(); + + let val: Parent = from_bytes(&bytes).unwrap(); + + assert_eq!(val.child.val2, val2.val2); + assert_eq!(val.child.val, val2.val); + assert_eq!(val.h, val2.h); +} + +#[derive(Debug, Default, Clone, PartialEq)] +struct Child1 { + val: u64, + val2: Vec, +} + +epee_object!( + Child1, + val: u64, + val2: Vec, +); + +#[derive(Debug, Default, Clone, PartialEq)] +struct Child2 { + buz: u16, + fiz: String, +} + +epee_object!( + Child2, + buz: u16, + fiz: String, +); + +#[derive(Debug, Default, Clone, PartialEq)] +struct Parent12 { + child1: Child1, + child2: Child2, + h: f64, +} + +epee_object!( + Parent12, + h: f64, + !flatten: + child1: Child1, + child2: Child2, +); + +#[test] +fn epee_double_flatten() { + let val = Parent12::default(); + + let bytes = to_bytes(val.clone()).unwrap(); + let val1: Parent12 = from_bytes(&bytes).unwrap(); + + assert_eq!(val, val1); +} diff --git a/net/epee-encoding/tests/options.rs b/net/epee-encoding/tests/options.rs new file mode 100644 index 0000000..4a76aac --- /dev/null +++ b/net/epee-encoding/tests/options.rs @@ -0,0 +1,31 @@ +use epee_encoding::{epee_object, from_bytes, to_bytes}; + +#[derive(Clone)] +struct T { + val: Option, +} + +epee_object!( + T, + val: Option, +); + +#[test] +fn optional_val_not_in_data() { + let bytes: &[u8] = b"\x01\x11\x01\x01\x01\x01\x02\x01\x01\x00"; + let t: T = from_bytes(bytes).unwrap(); + let bytes2 = to_bytes(t.clone()).unwrap(); + assert_eq!(bytes, bytes2); + assert!(t.val.is_none()); +} + +#[test] +fn optional_val_in_data() { + let bytes = [ + 0x01, 0x11, 0x01, 0x1, 0x01, 0x01, 0x02, 0x1, 0x1, 0x04, 0x03, b'v', b'a', b'l', 0x08, 21, + ]; + let t: T = from_bytes(&bytes).unwrap(); + let bytes2 = to_bytes(t.clone()).unwrap(); + assert_eq!(bytes.as_slice(), bytes2.as_slice()); + assert_eq!(t.val.unwrap(), 21); +} diff --git a/net/epee-encoding/tests/p2p.rs b/net/epee-encoding/tests/p2p.rs new file mode 100644 index 0000000..ace7478 --- /dev/null +++ b/net/epee-encoding/tests/p2p.rs @@ -0,0 +1,59 @@ +use epee_encoding::{epee_object, from_bytes, to_bytes}; + +#[derive(Eq, PartialEq, Debug, Clone)] +pub struct SupportFlags(u32); + +impl From for SupportFlags { + fn from(value: u32) -> Self { + SupportFlags(value) + } +} + +impl From for u32 { + fn from(value: SupportFlags) -> Self { + value.0 + } +} + +impl<'a> From<&'a SupportFlags> for &'a u32 { + fn from(value: &'a SupportFlags) -> Self { + &value.0 + } +} + +#[derive(Eq, PartialEq, Debug, Clone)] +pub struct BasicNodeData { + pub my_port: u32, + pub network_id: [u8; 16], + pub peer_id: u64, + pub support_flags: SupportFlags, +} + +epee_object!( + BasicNodeData, + my_port: u32, + network_id: [u8; 16], + peer_id: u64, + support_flags: SupportFlags as u32, +); + +#[derive(Eq, PartialEq, Debug, Clone)] +pub struct HandshakeR { + pub node_data: BasicNodeData, +} + +epee_object!( + HandshakeR, + node_data: BasicNodeData, +); + +#[test] +fn p2p_handshake() { + let bytes = hex::decode("01110101010102010108096e6f64655f646174610c10076d795f706f727406a04600000a6e6574776f726b5f69640a401230f171610441611731008216a1a11007706565725f6964053eb3c096c4471c340d737570706f72745f666c61677306010000000c7061796c6f61645f646174610c181563756d756c61746976655f646966666963756c7479053951f7a79aab4a031b63756d756c61746976655f646966666963756c74795f746f7036340500000000000000000e63757272656e745f68656967687405fa092a00000000000c7072756e696e675f73656564068001000006746f705f69640a806cc497b230ba57a95edb370be8d6870c94e0992937c89b1def3a4cb7726d37ad0b746f705f76657273696f6e0810").unwrap(); + + let val: HandshakeR = from_bytes(&bytes).unwrap(); + + let bytes = to_bytes(val.clone()).unwrap(); + + assert_eq!(val, from_bytes(&bytes).unwrap()); +} diff --git a/net/epee-encoding/tests/rpc.rs b/net/epee-encoding/tests/rpc.rs new file mode 100644 index 0000000..caa1914 --- /dev/null +++ b/net/epee-encoding/tests/rpc.rs @@ -0,0 +1,83 @@ +use epee_encoding::{epee_object, from_bytes, to_bytes}; + +#[derive(Clone, Debug, PartialEq)] +struct BaseResponse { + credits: u64, + status: String, + top_hash: String, + untrusted: bool, +} + +epee_object!( + BaseResponse, + credits: u64, + status: String, + top_hash: String, + untrusted: bool, +); + +#[derive(Clone, Debug, PartialEq)] +struct GetOIndexesResponse { + base: BaseResponse, + o_indexes: Vec, +} + +epee_object!( + GetOIndexesResponse, + o_indexes: Vec, + !flatten: + base: BaseResponse, +); + +#[derive(Clone, Debug, PartialEq)] +struct GetOutsResponse { + base: BaseResponse, + outs: Vec, +} + +epee_object!( + GetOutsResponse, + outs: Vec, + !flatten: + base: BaseResponse, +); + +#[derive(Clone, Copy, Debug, PartialEq)] +struct OutKey { + height: u64, + key: [u8; 32], + mask: [u8; 32], + txid: [u8; 32], + unlocked: bool, +} + +epee_object!( + OutKey, + height: u64, + key: [u8; 32], + mask: [u8; 32], + txid: [u8; 32], + unlocked: bool, +); + +#[test] +fn rpc_get_outs_response() { + let bytes = hex::decode("011101010101020101140763726564697473050000000000000000046f7574738c04140668656967687405a100000000000000036b65790a802d392d0be38eb4699c17767e62a063b8d2f989ec15c80e5d2665ab06f8397439046d61736b0a805e8b863c5b267deda13f4bc5d5ec8e59043028380f2431bc8691c15c83e1fea404747869640a80c0646e065a33b849f0d9563673ca48eb0c603fe721dd982720dba463172c246f08756e6c6f636b65640b00067374617475730a084f4b08746f705f686173680a0009756e747275737465640b00").unwrap(); + let val: GetOutsResponse = from_bytes(&bytes).unwrap(); + let bytes = to_bytes(val.clone()).unwrap(); + + assert_eq!(val, from_bytes(&bytes).unwrap()); +} + +#[test] +fn get_out_indexes_response() { + let bytes = [ + 1, 17, 1, 1, 1, 1, 2, 1, 1, 16, 7, 99, 114, 101, 100, 105, 116, 115, 5, 0, 0, 0, 0, 0, 0, + 0, 0, 6, 115, 116, 97, 116, 117, 115, 10, 8, 79, 75, 8, 116, 111, 112, 95, 104, 97, 115, + 104, 10, 0, 9, 117, 110, 116, 114, 117, 115, 116, 101, 100, 11, 0, + ]; + let val: GetOIndexesResponse = from_bytes(&bytes).unwrap(); + let bytes = to_bytes(val.clone()).unwrap(); + + assert_eq!(val, from_bytes(&bytes).unwrap()); +} diff --git a/net/epee-encoding/tests/seq.rs b/net/epee-encoding/tests/seq.rs new file mode 100644 index 0000000..0989f9a --- /dev/null +++ b/net/epee-encoding/tests/seq.rs @@ -0,0 +1,60 @@ +use epee_encoding::{epee_object, from_bytes}; + +struct ObjSeq { + seq: Vec, +} + +epee_object!( + ObjSeq, + seq: Vec, +); + +struct ValSeq { + seq: Vec, +} + +epee_object!( + ValSeq, + seq: Vec, +); + +#[test] +fn seq_with_zero_len_can_have_any_marker() { + let mut data = [ + 0x01, 0x11, 0x01, 0x1, 0x01, 0x01, 0x02, 0x1, 0x1, 0x04, 0x03, b's', b'e', b'q', + ] + .to_vec(); + for marker in 1..13 { + data.push(0x80 | marker); + data.push(0); + + assert!(from_bytes::(&data).is_ok()); + + assert!(from_bytes::(&data).is_ok()); + + data.drain(14..); + } +} + +#[test] +fn seq_with_non_zero_len_must_have_correct_marker() { + let mut data = [ + 0x01, 0x11, 0x01, 0x1, 0x01, 0x01, 0x02, 0x1, 0x1, 0x04, 0x03, b's', b'e', b'q', + ] + .to_vec(); + for marker in 2..13 { + // 1 is the marker for i64 + data.push(0x80 | marker); + data.push(0x04); // varint length of 1 + data.extend_from_slice(&1_i64.to_le_bytes()); + + assert!(from_bytes::(&data).is_err()); + + data.drain(14..); + } + + data.push(0x80 + 1); + data.push(0x04); // varint length + data.extend_from_slice(&1_i64.to_le_bytes()); + (from_bytes::(&data).unwrap()); +} diff --git a/net/epee-encoding/tests/stack_overflow.rs b/net/epee-encoding/tests/stack_overflow.rs new file mode 100644 index 0000000..c939684 --- /dev/null +++ b/net/epee-encoding/tests/stack_overflow.rs @@ -0,0 +1,741 @@ +use epee_encoding::{epee_object, from_bytes}; + +struct D { + val: u8, +} + +epee_object!( + D, + val: u8, +); +struct Q { + req: u8, + d: D, +} + +epee_object!( + Q, + req: u8, + d: D, +); + +#[test] +fn stack_overlfow() { + let bytes = vec![ + 1, 17, 1, 1, 1, 1, 2, 1, 1, 8, 3, 114, 101, 113, 8, 3, 1, 100, 12, 8, 3, 118, 97, 108, 8, + 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, + 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, + 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, + 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, + 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, + 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, + 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, + 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, + 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, + 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, + 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, + 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, + 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, + 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, + 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, + 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, + 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, + 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, + 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, + 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, + 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, + 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, + 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, + 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, + 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, + 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, + 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, + 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, + 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, + 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, + 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, + 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, + 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, + 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, + 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, + 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, + 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, + 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, + 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, + 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, + 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, + 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, + 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, + 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, + 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, + 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, + 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, + 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, + 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, + 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, + 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, + 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, + 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, + 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, + 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, + 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, + 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, + 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, + 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, + 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, + 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, + 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, + 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, + 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, + 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, + 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, + 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, + 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, + 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, + 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, + 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, + 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, + 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, + 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, + 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, + 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, + 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, + 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, + 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, + 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, + 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, + 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, + 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, + 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, + 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, + 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, + 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, + 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, + 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, + 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, + 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, + 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, + 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, + 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, + 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, + 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, + 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, + 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, + 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, + 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, + 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, + 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, + 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, + 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, + 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, + 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, + 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, + 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, + 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, + 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, + 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, + 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, + 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, + 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, + 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, + 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, + 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, + 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, + 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, + 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, + 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, + 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, + 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, + 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, + 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, + 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, + 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, + 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, + 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, + 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, + 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, + 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, + 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, + 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, + 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, + 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, + 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, + 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, + 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, + 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, + 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, + 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, + 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, + 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, + 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, + 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, + 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, + 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, + 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, + 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, + 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, + 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, + 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, + 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, + 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, + 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, + 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, + 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, + 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, + 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, + 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, + 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, + 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, + 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, + 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, + 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, + 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, + 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, + 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, + 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, + 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, + 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, + 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, + 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, + 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, + 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, + 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, + 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, + 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, + 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, + 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, + 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, + 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, + 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, + 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, + 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, + 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, + 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, + 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, + 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, + 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, + 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, + 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, + 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, + 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, + 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, + 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, + 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, + 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, + 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, + 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, + 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, + 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, + 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, + 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, + 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, + 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, + 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, + 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, + 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, + 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, + 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, + 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, + 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, + 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, + 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, + 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, + 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, + 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, + 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, + 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, + 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, + 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, + 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, + 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, + 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, + 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, + 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, + 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, + 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, + 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, + 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, + 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, + 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, + 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, + 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, + 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, + 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, + 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, + 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, + 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, + 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, + 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, + 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, + 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, + 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, + 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, + 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, + 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, + 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, + 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, + 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, + 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, + 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, + 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, + 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, + 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, + 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, + 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, + 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, + 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, + 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, + 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, + 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, + 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, + 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, + 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, + 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, + 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, + 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, + 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, + 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, + 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, + 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, + 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, + 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, + 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, + 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, + 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, + 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, + 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, + 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, + 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, + 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, + 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, + 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, + 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, + 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, + 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, + 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, + 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, + 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, + 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, + 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, + 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, + 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, + 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, + 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, + 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, + 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, + 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, + 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, + 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, + 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, + 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, + 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, + 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, + 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, + 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, + 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, + 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, + 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, + 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, + 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, + 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, + 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, + 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, + 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, + 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, + 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, + 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, + 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, + 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, + 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, + 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, + 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, + 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, + 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, + 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, + 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, + 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, + 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, + 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, + 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, + 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, + 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, + 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, + 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, + 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, + 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, + 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, + 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, + 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, + 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, + 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, + 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, + 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, + 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, + 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, + 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, + 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, + 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, + 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, + 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, + 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, + 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, + 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, + 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, + 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, + 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, + 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, + 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, + 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, + 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, + 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, + 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, + 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, + 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, + 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, + 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, + 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, + 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, + 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, + 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, + 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, + 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, + 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, + 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, + 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, + 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, + 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, + 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, + 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, + 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, + 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, + 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, + 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, + 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, + 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, + 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, + 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, + 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, + 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, + 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, + 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, + 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, + 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, + 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, + 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, + 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, + 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, + 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, + 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, + 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, + 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, + 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, + 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, + 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, + 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, + 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, + 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, + 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, + 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, + 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, + 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, + 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, + 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, + 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, + 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, + 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, + 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, + 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, + 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, + 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, + 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, + 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, + 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, + 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, + 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, + 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, + 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, + 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, + 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, + 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, + 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, + 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, + 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, + 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, + 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, + 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, + 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, + 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, + 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, + 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, + 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, + 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, + 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, + 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, + 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, + 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, + 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, + 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, + 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, + 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, + 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, + 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, + 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, + 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, + 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, + 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, + 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, + 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, + 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, + 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, + 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, + 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, + 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, + 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, + 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, + 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, + 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, + 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, + 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, + 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, + 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, + 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, + 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, + 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, + 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, + 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, + 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, + 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, + 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, + 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, + 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, + 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, + 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, + 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, + 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, + 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, + 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, + 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, + 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, + 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, + 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, + 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, + 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, + 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, + 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, + 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, + 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, + 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, + 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, + 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, + 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, + 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, + 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, + 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, + 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, + 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, + 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, + 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, + 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, + 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, + 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, + 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, + 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, + 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, + 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, + 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, + 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, + 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, + 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, + 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, + 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, + 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, + 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, + 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, + 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, + 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, + 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, + 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, + 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, + 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, + 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, + 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, + 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, + 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, + 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, + 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, + 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, + 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, + 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, + 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, + 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, + 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, + 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, + 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, + 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, + 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, + 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, + 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, + 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, + 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, + 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, + 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, + 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, + 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, + 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, + 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, + 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, + 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, + 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, + 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, + 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, + 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, + 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, + 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, + 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, + 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, + 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, + 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, + 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, + 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, + 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, + 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, + 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, + 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, + 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, + 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, + 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, + 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, + 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, + 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, + 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, + 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, + 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, + 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, + 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, + 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, + 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, + 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, + 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, + 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, + 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, + 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, + 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, + 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, + 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, + 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, + 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, + 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, + 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, + 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, + 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, + 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, + 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, + 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, + 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, + 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, + 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, + 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, + 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, + 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, + 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, + 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, + 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, + 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, + 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, + 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, + 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, + 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, + 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, + 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, + 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, + 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, + 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, + 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, + 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, + 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, + 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, + 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, + 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, + 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, + 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, + 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, + 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, + 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, + 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, + 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, + 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, + 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, + 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, + 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, + 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, + 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, + 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, + 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, + 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, + 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, + 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, + 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, + 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, + 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, + 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, + 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, + 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, + 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, + 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, + 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, + 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, + 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, + 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, + 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, + 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, + 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, + 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, + 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, + 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, + 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, + 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, + 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, + 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, + 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, + 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, + 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, + 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, + 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, + 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, + 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, + 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, + 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, + 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, + 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, + 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, + 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, + 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, + 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, + 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, + 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, + 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, + 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, + 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, + 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, + 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, + 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, + 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, + 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, + 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, + 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, + 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, + 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, + 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, + 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, + 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, + 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, + 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, + 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, + 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, + 8, 7, 1, 100, 12, 8, 3, 118, 97, 108, 8, 7, + ]; + + let obj: Result = from_bytes(&bytes); + + assert!(obj.is_err()) +} diff --git a/net/fixed-bytes/Cargo.toml b/net/fixed-bytes/Cargo.toml new file mode 100644 index 0000000..3bda00b --- /dev/null +++ b/net/fixed-bytes/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "fixed-bytes" +version = "0.1.0" +edition = "2021" + +[features] +default = ["std"] +std = ["bytes/std", "dep:thiserror"] + +[dependencies] +thiserror = { workspace = true, optional = true } +bytes = { workspace = true } \ No newline at end of file diff --git a/net/fixed-bytes/src/lib.rs b/net/fixed-bytes/src/lib.rs new file mode 100644 index 0000000..c4272c1 --- /dev/null +++ b/net/fixed-bytes/src/lib.rs @@ -0,0 +1,126 @@ +use core::ops::Deref; +use std::fmt::{Debug, Formatter}; +use std::ops::Index; + +use bytes::Bytes; + +#[cfg_attr(feature = "std", derive(thiserror::Error))] +pub enum FixedByteError { + #[cfg_attr( + feature = "std", + error("Cannot create fix byte array, input has invalid length.") + )] + InvalidLength, +} + +impl FixedByteError { + fn field_name(&self) -> &'static str { + match self { + FixedByteError::InvalidLength => "input", + } + } + + fn field_data(&self) -> &'static str { + match self { + FixedByteError::InvalidLength => { + "Cannot create fix byte array, input has invalid length." + } + } + } +} + +impl Debug for FixedByteError { + fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { + f.debug_struct("FixedByteError") + .field(self.field_name(), &self.field_data()) + .finish() + } +} + +/// A fixed size byte slice. +/// +/// Internally this is just a wrapper around [`Bytes`], with the constructors checking that the length is equal to [`N`]. +/// This implements [`Deref`] with the target being `[u8; N]`. +pub struct ByteArray(Bytes); + +impl ByteArray { + pub fn take_bytes(self) -> Bytes { + self.0 + } +} + +impl Deref for ByteArray { + type Target = [u8; N]; + + fn deref(&self) -> &Self::Target { + self.0.deref().try_into().unwrap() + } +} + +impl TryFrom for ByteArray { + type Error = FixedByteError; + + fn try_from(value: Bytes) -> Result { + if value.len() != N { + return Err(FixedByteError::InvalidLength); + } + Ok(ByteArray(value)) + } +} + +pub struct ByteArrayVec(Bytes); + +impl ByteArrayVec { + pub fn len(&self) -> usize { + self.0.len() / N + } + + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + + pub fn take_bytes(self) -> Bytes { + self.0 + } +} + +impl TryFrom for ByteArrayVec { + type Error = FixedByteError; + + fn try_from(value: Bytes) -> Result { + if value.len() % N != 0 { + return Err(FixedByteError::InvalidLength); + } + + Ok(ByteArrayVec(value)) + } +} + +impl Index for ByteArrayVec { + type Output = [u8; 32]; + + fn index(&self, index: usize) -> &Self::Output { + if (index + 1) * N > self.0.len() { + panic!("Index out of range, idx: {}, length: {}", index, self.len()); + } + + self.0[index * N..(index + 1) * N] + .as_ref() + .try_into() + .unwrap() + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn byte_array_vec_len() { + let bytes = vec![0; 32 * 100]; + let bytes = ByteArrayVec::<32>::try_from(Bytes::from(bytes)).unwrap(); + + assert_eq!(bytes.len(), 100); + let _ = bytes[99]; + } +} diff --git a/net/levin/Cargo.toml b/net/levin/Cargo.toml index 0101e08..790d436 100644 --- a/net/levin/Cargo.toml +++ b/net/levin/Cargo.toml @@ -8,7 +8,7 @@ authors = ["Boog900"] repository = "https://github.com/Cuprate/cuprate/tree/main/net/levin" [dependencies] -thiserror = "1" -bytes = "1" -tokio-util = {version = "0.7", features = ["codec"]} +thiserror = { workspace = true } +bytes = { workspace = true } +tokio-util = { workspace = true, features = ["codec"]}