From 7615a23616d1b444bda782d5a28eb8f4732476d8 Mon Sep 17 00:00:00 2001 From: Martin Kysel Date: Fri, 13 Sep 2024 14:16:47 -0600 Subject: [PATCH 01/14] Introduce gRPC replication client api --- xmtp_api_grpc/src/grpc_api_helper.rs | 69 +++++++++++++++++++++++++++- xmtp_proto/src/api_client.rs | 25 ++++++++++ 2 files changed, 92 insertions(+), 2 deletions(-) diff --git a/xmtp_api_grpc/src/grpc_api_helper.rs b/xmtp_api_grpc/src/grpc_api_helper.rs index 6e61a81ac..6502e584f 100644 --- a/xmtp_api_grpc/src/grpc_api_helper.rs +++ b/xmtp_api_grpc/src/grpc_api_helper.rs @@ -9,7 +9,7 @@ use tokio::sync::oneshot; use tonic::transport::ClientTlsConfig; use tonic::{metadata::MetadataValue, transport::Channel, Request, Streaming}; -use xmtp_proto::api_client::{ClientWithMetadata, XmtpMlsStreams}; +use xmtp_proto::api_client::{ClientWithMetadata, XmtpMlsStreams, XmtpReplicationClient}; use xmtp_proto::xmtp::mls::api::v1::{GroupMessage, WelcomeMessage}; use xmtp_proto::{ api_client::{ @@ -28,6 +28,8 @@ use xmtp_proto::{ UploadKeyPackageRequest, }, }; +use xmtp_proto::xmtp::xmtpv4::{BatchSubscribeEnvelopesRequest, BatchSubscribeEnvelopesResponse, PublishEnvelopeRequest, PublishEnvelopeResponse, QueryEnvelopesRequest, QueryEnvelopesResponse}; +use xmtp_proto::xmtp::xmtpv4::replication_api_client::ReplicationApiClient; async fn create_tls_channel(address: String) -> Result { let channel = Channel::from_shared(address) @@ -72,6 +74,7 @@ pub struct Client { pub(crate) identity_client: ProtoIdentityApiClient, pub(crate) app_version: MetadataValue, pub(crate) libxmtp_version: MetadataValue, + pub(crate) replication_client: ReplicationApiClient, } impl Client { @@ -93,7 +96,8 @@ impl Client { let client = MessageApiClient::new(channel.clone()); let mls_client = ProtoMlsApiClient::new(channel.clone()); - let identity_client = ProtoIdentityApiClient::new(channel); + let identity_client = ProtoIdentityApiClient::new(channel.clone()); + let replication_client = ReplicationApiClient::new(channel); Ok(Self { client, @@ -101,6 +105,7 @@ impl Client { app_version, libxmtp_version, identity_client, + replication_client }) } @@ -482,3 +487,63 @@ impl XmtpMlsStreams for Client { Ok(stream.into()) } } + + +pub struct BatchSubscribeStream { + inner: tonic::codec::Streaming, +} + +impl From> for BatchSubscribeStream { + fn from(inner: tonic::codec::Streaming) -> Self { + BatchSubscribeStream { inner } + } +} + +impl Stream for BatchSubscribeStream { + type Item = Result; + + fn poll_next( + mut self: Pin<&mut Self>, + cx: &mut std::task::Context<'_>, + ) -> std::task::Poll> { + self.inner + .poll_next_unpin(cx) + .map(|data| data.map(|v| v.map_err(|e| Error::new(ErrorKind::SubscribeError).with(e)))) + } +} + +impl XmtpReplicationClient for Client { + type BatchSubscribeStream<'a> = BatchSubscribeStream; + + async fn publish_envelope(&self, request: PublishEnvelopeRequest) -> Result { + let client = &mut self.replication_client.clone(); + + client + .publish_envelope(request) + .await + .map(|r| r.into_inner()) + .map_err(|e| Error::new(ErrorKind::PublishError).with(e)) + } + + async fn query_envelopes(&self, request: QueryEnvelopesRequest) -> Result { + let client = &mut self.replication_client.clone(); + + client + .query_envelopes(request) + .await + .map(|r| r.into_inner()) + .map_err(|e| Error::new(ErrorKind::QueryError).with(e)) + } + + async fn batch_subscribe_envelopes(&self, request: BatchSubscribeEnvelopesRequest) -> Result, Error> { + let client = &mut self.replication_client.clone(); + let res = client + .batch_subscribe_envelopes(request) + .await + .map_err(|e| Error::new(ErrorKind::SubscribeError).with(e))?; + + let stream = res.into_inner(); + + Ok(stream.into()) + } +} diff --git a/xmtp_proto/src/api_client.rs b/xmtp_proto/src/api_client.rs index 60db8e4e9..4068cceb5 100644 --- a/xmtp_proto/src/api_client.rs +++ b/xmtp_proto/src/api_client.rs @@ -17,6 +17,7 @@ use crate::xmtp::mls::api::v1::{ SendGroupMessagesRequest, SendWelcomeMessagesRequest, SubscribeGroupMessagesRequest, SubscribeWelcomeMessagesRequest, UploadKeyPackageRequest, WelcomeMessage, }; +use crate::xmtp::xmtpv4::{BatchSubscribeEnvelopesRequest, BatchSubscribeEnvelopesResponse, PublishEnvelopeRequest, PublishEnvelopeResponse, QueryEnvelopesRequest, QueryEnvelopesResponse}; #[derive(Debug)] pub enum ErrorKind { @@ -232,3 +233,27 @@ pub trait LocalXmtpIdentityClient { request: GetInboxIdsRequest, ) -> Result; } + +#[allow(async_fn_in_trait)] +#[cfg_attr(not(target_arch = "wasm32"), trait_variant::make(XmtpReplicationClient: Send))] +#[cfg_attr(target_arch = "wasm32", trait_variant::make(XmtpReplicationClient: Wasm))] +pub trait LocalXmtpReplicationClient { + type BatchSubscribeStream<'a>: Stream> + Send + 'a + where + Self: 'a; + + async fn publish_envelope( + &self, + request: PublishEnvelopeRequest, + ) -> Result; + + async fn query_envelopes( + &self, + request: QueryEnvelopesRequest, + ) -> Result; + + fn batch_subscribe_envelopes( + &self, + request: BatchSubscribeEnvelopesRequest, + ) -> impl futures::Future, Error>> + Send; +} \ No newline at end of file From cc70ecdfa134136c2f000f70eb4839c37a6595aa Mon Sep 17 00:00:00 2001 From: Martin Kysel Date: Fri, 13 Sep 2024 16:27:37 -0600 Subject: [PATCH 02/14] advancement --- bindings_ffi/src/mls.rs | 4 +- bindings_ffi/src/v2.rs | 2 +- examples/cli/cli-client.rs | 4 +- xmtp_api_grpc/src/grpc_api_helper.rs | 116 ++++++++++++++++++++++----- xmtp_api_grpc/src/lib.rs | 18 ++--- xmtp_mls/src/utils/test.rs | 4 +- 6 files changed, 112 insertions(+), 36 deletions(-) diff --git a/bindings_ffi/src/mls.rs b/bindings_ffi/src/mls.rs index 27fec6166..6300679df 100644 --- a/bindings_ffi/src/mls.rs +++ b/bindings_ffi/src/mls.rs @@ -91,7 +91,7 @@ pub async fn create_client( host, is_secure ); - let api_client = TonicApiClient::create(host.clone(), is_secure).await?; + let api_client = TonicApiClient::create(host.clone(), is_secure, false).await?; log::info!( "Creating message store with path: {:?} and encryption key: {} of length {:?}", @@ -159,7 +159,7 @@ pub async fn get_inbox_id_for_address( account_address: String, ) -> Result, GenericError> { let api_client = ApiClientWrapper::new( - TonicApiClient::create(host.clone(), is_secure).await?, + TonicApiClient::create(host.clone(), is_secure, false).await?, Retry::default(), ); diff --git a/bindings_ffi/src/v2.rs b/bindings_ffi/src/v2.rs index f98a9a803..e604cf91f 100644 --- a/bindings_ffi/src/v2.rs +++ b/bindings_ffi/src/v2.rs @@ -23,7 +23,7 @@ pub async fn create_v2_client( host: String, is_secure: bool, ) -> Result, GenericError> { - let client = GrpcClient::create(host, is_secure).await?; + let client = GrpcClient::create(host, is_secure, false).await?; let client = FfiV2ApiClient { inner_client: Arc::new(client), diff --git a/examples/cli/cli-client.rs b/examples/cli/cli-client.rs index 063cc450e..e0a322560 100755 --- a/examples/cli/cli-client.rs +++ b/examples/cli/cli-client.rs @@ -416,7 +416,7 @@ async fn create_client(cli: &Cli, account: IdentityStrategy) -> Result Result Result { @@ -75,10 +77,11 @@ pub struct Client { pub(crate) app_version: MetadataValue, pub(crate) libxmtp_version: MetadataValue, pub(crate) replication_client: ReplicationApiClient, + use_replication_v4: bool, } impl Client { - pub async fn create(host: String, is_secure: bool) -> Result { + pub async fn create(host: String, is_secure: bool, use_replication_v4: bool) -> Result { let host = host.to_string(); let app_version = MetadataValue::try_from(&String::from("0.0.0")) .map_err(|e| Error::new(ErrorKind::MetadataError).with(e))?; @@ -105,7 +108,8 @@ impl Client { app_version, libxmtp_version, identity_client, - replication_client + replication_client, + use_replication_v4 }) } @@ -340,12 +344,22 @@ impl MutableApiSubscription for GrpcMutableSubscription { impl XmtpMlsClient for Client { #[tracing::instrument(level = "trace", skip_all)] async fn upload_key_package(&self, req: UploadKeyPackageRequest) -> Result<(), Error> { - let client = &mut self.mls_client.clone(); + if self.use_replication_v4 { + let client = &mut self.replication_client.clone(); + let payload = wrap_client_envelope(req.to_client_envelope()); + let res = client.publish_envelope(payload).await; + match res { + Ok(_) => Ok(()), + Err(e) => Err(Error::new(ErrorKind::MlsError).with(e)), + } + } else { + let client = &mut self.mls_client.clone(); - let res = client.upload_key_package(self.build_request(req)).await; - match res { - Ok(_) => Ok(()), - Err(e) => Err(Error::new(ErrorKind::MlsError).with(e)), + let res = client.upload_key_package(self.build_request(req)).await; + match res { + Ok(_) => Ok(()), + Err(e) => Err(Error::new(ErrorKind::MlsError).with(e)), + } } } @@ -363,23 +377,41 @@ impl XmtpMlsClient for Client { #[tracing::instrument(level = "trace", skip_all)] async fn send_group_messages(&self, req: SendGroupMessagesRequest) -> Result<(), Error> { - let client = &mut self.mls_client.clone(); - let res = client.send_group_messages(self.build_request(req)).await; - - match res { - Ok(_) => Ok(()), - Err(e) => Err(Error::new(ErrorKind::MlsError).with(e)), + if self.use_replication_v4 { + let client = &mut self.replication_client.clone(); + let payload = wrap_client_envelope(req.to_client_envelope()); + let res = client.publish_envelope(payload).await; + match res { + Ok(_) => Ok(()), + Err(e) => Err(Error::new(ErrorKind::MlsError).with(e)), + } + } else { + let client = &mut self.mls_client.clone(); + let res = client.send_group_messages(self.build_request(req)).await; + match res { + Ok(_) => Ok(()), + Err(e) => Err(Error::new(ErrorKind::MlsError).with(e)), + } } } #[tracing::instrument(level = "trace", skip_all)] async fn send_welcome_messages(&self, req: SendWelcomeMessagesRequest) -> Result<(), Error> { - let client = &mut self.mls_client.clone(); - let res = client.send_welcome_messages(self.build_request(req)).await; - - match res { - Ok(_) => Ok(()), - Err(e) => Err(Error::new(ErrorKind::MlsError).with(e)), + if self.use_replication_v4 { + let client = &mut self.replication_client.clone(); + let payload = wrap_client_envelope(req.to_client_envelope()); + let res = client.publish_envelope(payload).await; + match res { + Ok(_) => Ok(()), + Err(e) => Err(Error::new(ErrorKind::MlsError).with(e)), + } + } else { + let client = &mut self.mls_client.clone(); + let res = client.send_welcome_messages(self.build_request(req)).await; + match res { + Ok(_) => Ok(()), + Err(e) => Err(Error::new(ErrorKind::MlsError).with(e)), + } } } @@ -547,3 +579,47 @@ impl XmtpReplicationClient for Client { Ok(stream.into()) } } + + +trait ClientEnvelopeConversion { + fn to_client_envelope(self) -> ClientEnvelope; +} + +impl ClientEnvelopeConversion for SendGroupMessagesRequest { + fn to_client_envelope(self) -> ClientEnvelope { + ClientEnvelope { + aad: None, + payload: Some(Payload::GroupMessage(self.messages.first().unwrap().clone())) + } + } +} + +impl ClientEnvelopeConversion for SendWelcomeMessagesRequest { + fn to_client_envelope(self) -> ClientEnvelope { + ClientEnvelope { + aad: None, + payload: Some(Payload::WelcomeMessage(self.messages.first().unwrap().clone())) + } + } +} + +impl ClientEnvelopeConversion for UploadKeyPackageRequest { + fn to_client_envelope(self) -> ClientEnvelope { + ClientEnvelope { + aad: None, + payload: Some(Payload::UploadKeyPackage(self)) + } + } +} + +fn wrap_client_envelope(req: ClientEnvelope) -> PublishEnvelopeRequest { + let mut buf = vec![]; + req.encode(&mut buf).unwrap(); + + PublishEnvelopeRequest { + payer_envelope: Some(PayerEnvelope { + unsigned_client_envelope: buf, + payer_signature: None, + }), + } +} \ No newline at end of file diff --git a/xmtp_api_grpc/src/lib.rs b/xmtp_api_grpc/src/lib.rs index a774b86bc..8be1719b1 100644 --- a/xmtp_api_grpc/src/lib.rs +++ b/xmtp_api_grpc/src/lib.rs @@ -49,7 +49,7 @@ mod tests { #[tokio::test] async fn grpc_query_test() { - let mut client = Client::create(LOCALHOST_ADDRESS.to_string(), false) + let mut client = Client::create(LOCALHOST_ADDRESS.to_string(), false, false) .await .unwrap(); @@ -70,7 +70,7 @@ mod tests { #[tokio::test] async fn grpc_batch_query_test() { - let client = Client::create(LOCALHOST_ADDRESS.to_string(), false) + let client = Client::create(LOCALHOST_ADDRESS.to_string(), false, false) .await .unwrap(); let req = BatchQueryRequest { @@ -85,7 +85,7 @@ mod tests { #[tokio::test] async fn publish_test() { - let client = Client::create(LOCALHOST_ADDRESS.to_string(), false) + let client = Client::create(LOCALHOST_ADDRESS.to_string(), false, false) .await .unwrap(); @@ -115,7 +115,7 @@ mod tests { #[tokio::test] async fn subscribe_test() { tokio::time::timeout(std::time::Duration::from_secs(5), async move { - let client = Client::create(LOCALHOST_ADDRESS.to_string(), false) + let client = Client::create(LOCALHOST_ADDRESS.to_string(), false, false) .await .unwrap(); @@ -162,7 +162,7 @@ mod tests { #[tokio::test] async fn tls_test() { - let client = Client::create(DEV_ADDRESS.to_string(), true).await.unwrap(); + let client = Client::create(DEV_ADDRESS.to_string(), true, false).await.unwrap(); let result = client .query(QueryRequest { @@ -177,7 +177,7 @@ mod tests { #[tokio::test] async fn bidrectional_streaming_test() { - let client = Client::create(LOCALHOST_ADDRESS.to_string(), false) + let client = Client::create(LOCALHOST_ADDRESS.to_string(), false, false) .await .unwrap(); @@ -234,7 +234,7 @@ mod tests { #[tokio::test] async fn test_dev_publish() { let auth_token = get_auth_token(); - let dev_client = Client::create(DEV_ADDRESS.to_string(), true).await.unwrap(); + let dev_client = Client::create(DEV_ADDRESS.to_string(), true, false).await.unwrap(); dev_client .publish( auth_token, @@ -254,7 +254,7 @@ mod tests { async fn long_lived_subscribe_test() { let auth_token = get_auth_token(); tokio::time::timeout(std::time::Duration::from_secs(100), async move { - let client = Client::create(DEV_ADDRESS.to_string(), true).await.unwrap(); + let client = Client::create(DEV_ADDRESS.to_string(), true, false).await.unwrap(); let topic = uuid::Uuid::new_v4(); let mut subscription = client @@ -307,7 +307,7 @@ mod tests { #[tokio::test] async fn metadata_test() { - let mut client = Client::create(DEV_ADDRESS.to_string(), true).await.unwrap(); + let mut client = Client::create(DEV_ADDRESS.to_string(), true, false).await.unwrap(); let app_version = "test/1.0.0".to_string(); let libxmtp_version = "0.0.1".to_string(); diff --git a/xmtp_mls/src/utils/test.rs b/xmtp_mls/src/utils/test.rs index 529191155..078e3b622 100755 --- a/xmtp_mls/src/utils/test.rs +++ b/xmtp_mls/src/utils/test.rs @@ -66,13 +66,13 @@ impl XmtpTestClient for XmtpHttpApiClient { impl XmtpTestClient for GrpcClient { async fn create_local() -> Self { - GrpcClient::create("http://localhost:5556".into(), false) + GrpcClient::create("http://localhost:5556".into(), false, false) .await .unwrap() } async fn create_dev() -> Self { - GrpcClient::create("https://grpc.dev.xmtp.network:443".into(), false) + GrpcClient::create("https://grpc.dev.xmtp.network:443".into(), false, false) .await .unwrap() } From 9a92b24cf54745d5d40a813adce48c8ee895e38c Mon Sep 17 00:00:00 2001 From: Martin Kysel Date: Mon, 16 Sep 2024 13:09:41 -0600 Subject: [PATCH 03/14] teach client to use v4 --- examples/cli/cli-client.rs | 59 +++++++++++++++++++--------- xmtp_api_grpc/src/conversions.rs | 14 +++++++ xmtp_api_grpc/src/grpc_api_helper.rs | 53 +++---------------------- xmtp_api_grpc/src/identity.rs | 25 ++++++++---- xmtp_api_grpc/src/lib.rs | 2 + xmtp_proto/src/convert.rs | 41 +++++++++++++++++++ 6 files changed, 121 insertions(+), 73 deletions(-) create mode 100644 xmtp_api_grpc/src/conversions.rs diff --git a/examples/cli/cli-client.rs b/examples/cli/cli-client.rs index e0a322560..23d8bb3a3 100755 --- a/examples/cli/cli-client.rs +++ b/examples/cli/cli-client.rs @@ -63,6 +63,8 @@ struct Cli { local: bool, #[clap(long, default_value_t = false)] json: bool, + #[clap(long, default_value_t = false)] + testnet: bool, } #[derive(ValueEnum, Debug, Copy, Clone)] @@ -412,24 +414,45 @@ async fn create_client(cli: &Cli, account: IdentityStrategy) -> Result PublishEnvelopeRequest { + let mut buf = vec![]; + req.encode(&mut buf).unwrap(); + + PublishEnvelopeRequest { + payer_envelope: Some(PayerEnvelope { + unsigned_client_envelope: buf, + payer_signature: None, + }), + } +} diff --git a/xmtp_api_grpc/src/grpc_api_helper.rs b/xmtp_api_grpc/src/grpc_api_helper.rs index 4d5737a2b..5202b5e0c 100644 --- a/xmtp_api_grpc/src/grpc_api_helper.rs +++ b/xmtp_api_grpc/src/grpc_api_helper.rs @@ -32,6 +32,7 @@ use xmtp_proto::{ use xmtp_proto::xmtp::xmtpv4::{BatchSubscribeEnvelopesRequest, BatchSubscribeEnvelopesResponse, ClientEnvelope, PayerEnvelope, PublishEnvelopeRequest, PublishEnvelopeResponse, QueryEnvelopesRequest, QueryEnvelopesResponse}; use xmtp_proto::xmtp::xmtpv4::client_envelope::Payload; use xmtp_proto::xmtp::xmtpv4::replication_api_client::ReplicationApiClient; +use crate::conversions::wrap_client_envelope; async fn create_tls_channel(address: String) -> Result { let channel = Channel::from_shared(address) @@ -77,7 +78,7 @@ pub struct Client { pub(crate) app_version: MetadataValue, pub(crate) libxmtp_version: MetadataValue, pub(crate) replication_client: ReplicationApiClient, - use_replication_v4: bool, + pub(crate) use_replication_v4: bool, } impl Client { @@ -346,7 +347,7 @@ impl XmtpMlsClient for Client { async fn upload_key_package(&self, req: UploadKeyPackageRequest) -> Result<(), Error> { if self.use_replication_v4 { let client = &mut self.replication_client.clone(); - let payload = wrap_client_envelope(req.to_client_envelope()); + let payload = wrap_client_envelope(ClientEnvelope::from(req)); let res = client.publish_envelope(payload).await; match res { Ok(_) => Ok(()), @@ -379,7 +380,7 @@ impl XmtpMlsClient for Client { async fn send_group_messages(&self, req: SendGroupMessagesRequest) -> Result<(), Error> { if self.use_replication_v4 { let client = &mut self.replication_client.clone(); - let payload = wrap_client_envelope(req.to_client_envelope()); + let payload = wrap_client_envelope(ClientEnvelope::from(req)); let res = client.publish_envelope(payload).await; match res { Ok(_) => Ok(()), @@ -399,7 +400,7 @@ impl XmtpMlsClient for Client { async fn send_welcome_messages(&self, req: SendWelcomeMessagesRequest) -> Result<(), Error> { if self.use_replication_v4 { let client = &mut self.replication_client.clone(); - let payload = wrap_client_envelope(req.to_client_envelope()); + let payload = wrap_client_envelope(ClientEnvelope::from(req)); let res = client.publish_envelope(payload).await; match res { Ok(_) => Ok(()), @@ -578,48 +579,4 @@ impl XmtpReplicationClient for Client { Ok(stream.into()) } -} - - -trait ClientEnvelopeConversion { - fn to_client_envelope(self) -> ClientEnvelope; -} - -impl ClientEnvelopeConversion for SendGroupMessagesRequest { - fn to_client_envelope(self) -> ClientEnvelope { - ClientEnvelope { - aad: None, - payload: Some(Payload::GroupMessage(self.messages.first().unwrap().clone())) - } - } -} - -impl ClientEnvelopeConversion for SendWelcomeMessagesRequest { - fn to_client_envelope(self) -> ClientEnvelope { - ClientEnvelope { - aad: None, - payload: Some(Payload::WelcomeMessage(self.messages.first().unwrap().clone())) - } - } -} - -impl ClientEnvelopeConversion for UploadKeyPackageRequest { - fn to_client_envelope(self) -> ClientEnvelope { - ClientEnvelope { - aad: None, - payload: Some(Payload::UploadKeyPackage(self)) - } - } -} - -fn wrap_client_envelope(req: ClientEnvelope) -> PublishEnvelopeRequest { - let mut buf = vec![]; - req.encode(&mut buf).unwrap(); - - PublishEnvelopeRequest { - payer_envelope: Some(PayerEnvelope { - unsigned_client_envelope: buf, - payer_signature: None, - }), - } } \ No newline at end of file diff --git a/xmtp_api_grpc/src/identity.rs b/xmtp_api_grpc/src/identity.rs index 92531e0a6..f8630cb99 100644 --- a/xmtp_api_grpc/src/identity.rs +++ b/xmtp_api_grpc/src/identity.rs @@ -6,8 +6,9 @@ use xmtp_proto::{ GetInboxIdsResponse, PublishIdentityUpdateRequest, PublishIdentityUpdateResponse, }, }; - +use xmtp_proto::xmtp::xmtpv4::ClientEnvelope; use crate::Client; +use crate::conversions::wrap_client_envelope; impl XmtpIdentityClient for Client { #[tracing::instrument(level = "trace", skip_all)] @@ -15,14 +16,24 @@ impl XmtpIdentityClient for Client { &self, request: PublishIdentityUpdateRequest, ) -> Result { - let client = &mut self.identity_client.clone(); + if self.use_replication_v4 { + let client = &mut self.replication_client.clone(); + let payload = wrap_client_envelope(ClientEnvelope::from(request)); + let res = client.publish_envelope(payload).await; + match res { + Ok(_) => Ok(PublishIdentityUpdateResponse{}), + Err(e) => Err(Error::new(ErrorKind::MlsError).with(e)), + } + } else { + let client = &mut self.identity_client.clone(); - let res = client - .publish_identity_update(self.build_request(request)) - .await; + let res = client + .publish_identity_update(self.build_request(request)) + .await; - res.map(|response| response.into_inner()) - .map_err(|err| Error::new(ErrorKind::IdentityError).with(err)) + res.map(|response| response.into_inner()) + .map_err(|err| Error::new(ErrorKind::IdentityError).with(err)) + } } #[tracing::instrument(level = "trace", skip_all)] diff --git a/xmtp_api_grpc/src/lib.rs b/xmtp_api_grpc/src/lib.rs index 8be1719b1..618630733 100644 --- a/xmtp_api_grpc/src/lib.rs +++ b/xmtp_api_grpc/src/lib.rs @@ -1,10 +1,12 @@ pub mod auth_token; pub mod grpc_api_helper; mod identity; +mod conversions; pub const LOCALHOST_ADDRESS: &str = "http://localhost:5556"; pub const DEV_ADDRESS: &str = "https://grpc.dev.xmtp.network:443"; +use prost::Message; pub use grpc_api_helper::{Client, GroupMessageStream, WelcomeMessageStream}; #[cfg(test)] diff --git a/xmtp_proto/src/convert.rs b/xmtp_proto/src/convert.rs index f85e8c8a0..d19a92841 100644 --- a/xmtp_proto/src/convert.rs +++ b/xmtp_proto/src/convert.rs @@ -1,3 +1,8 @@ +use crate::xmtp::identity::api::v1::PublishIdentityUpdateRequest; +use crate::xmtp::mls::api::v1::{SendGroupMessagesRequest, SendWelcomeMessagesRequest, UploadKeyPackageRequest}; +use crate::xmtp::xmtpv4::client_envelope::Payload; +use crate::xmtp::xmtpv4::ClientEnvelope; + mod inbox_id { use crate::xmtp::identity::MlsCredential; @@ -16,3 +21,39 @@ mod inbox_id { } } } + +impl From for ClientEnvelope { + fn from(req: SendWelcomeMessagesRequest) -> Self { + ClientEnvelope { + aad: None, + payload: Some(Payload::WelcomeMessage(req.messages.first().unwrap().clone())) + } + } +} + +impl From for ClientEnvelope { + fn from(req: SendGroupMessagesRequest) -> Self { + ClientEnvelope { + aad: None, + payload: Some(Payload::GroupMessage(req.messages.first().unwrap().clone())) + } + } +} + +impl From for ClientEnvelope { + fn from(req: UploadKeyPackageRequest) -> Self { + ClientEnvelope { + aad: None, + payload: Some(Payload::UploadKeyPackage(req)) + } + } +} + +impl From for ClientEnvelope { + fn from(req: PublishIdentityUpdateRequest) -> Self { + ClientEnvelope { + aad: None, + payload: Some(Payload::IdentityUpdate(req.identity_update.unwrap())) + } + } +} \ No newline at end of file From 9d486cab037277c31b2b5099d740a5655ad29b2e Mon Sep 17 00:00:00 2001 From: Martin Kysel Date: Mon, 16 Sep 2024 13:25:28 -0600 Subject: [PATCH 04/14] cleanup --- bindings_node/src/mls_client.rs | 2 +- examples/cli/cli-client.rs | 1 + xmtp_api_grpc/src/grpc_api_helper.rs | 11 +++++------ xmtp_api_grpc/src/lib.rs | 1 - xmtp_proto/src/convert.rs | 18 ++++++++++++++---- 5 files changed, 21 insertions(+), 12 deletions(-) diff --git a/bindings_node/src/mls_client.rs b/bindings_node/src/mls_client.rs index e5000cc61..348d9ce42 100644 --- a/bindings_node/src/mls_client.rs +++ b/bindings_node/src/mls_client.rs @@ -126,7 +126,7 @@ pub async fn get_inbox_id_for_address( ) -> Result> { let account_address = account_address.to_lowercase(); let api_client = ApiClientWrapper::new( - TonicApiClient::create(host.clone(), is_secure) + TonicApiClient::create(host.clone(), is_secure, false) .await .map_err(|e| Error::from_reason(format!("{}", e)))?, Retry::default(), diff --git a/examples/cli/cli-client.rs b/examples/cli/cli-client.rs index 23d8bb3a3..e01133d53 100755 --- a/examples/cli/cli-client.rs +++ b/examples/cli/cli-client.rs @@ -434,6 +434,7 @@ async fn create_client(cli: &Cli, account: IdentityStrategy) -> Result Result { let channel = Channel::from_shared(address) diff --git a/xmtp_api_grpc/src/lib.rs b/xmtp_api_grpc/src/lib.rs index 618630733..cd1b99149 100644 --- a/xmtp_api_grpc/src/lib.rs +++ b/xmtp_api_grpc/src/lib.rs @@ -6,7 +6,6 @@ mod conversions; pub const LOCALHOST_ADDRESS: &str = "http://localhost:5556"; pub const DEV_ADDRESS: &str = "https://grpc.dev.xmtp.network:443"; -use prost::Message; pub use grpc_api_helper::{Client, GroupMessageStream, WelcomeMessageStream}; #[cfg(test)] diff --git a/xmtp_proto/src/convert.rs b/xmtp_proto/src/convert.rs index d19a92841..d17c110b6 100644 --- a/xmtp_proto/src/convert.rs +++ b/xmtp_proto/src/convert.rs @@ -1,7 +1,7 @@ use crate::xmtp::identity::api::v1::PublishIdentityUpdateRequest; use crate::xmtp::mls::api::v1::{SendGroupMessagesRequest, SendWelcomeMessagesRequest, UploadKeyPackageRequest}; use crate::xmtp::xmtpv4::client_envelope::Payload; -use crate::xmtp::xmtpv4::ClientEnvelope; +use crate::xmtp::xmtpv4::{AuthenticatedData, ClientEnvelope}; mod inbox_id { @@ -34,7 +34,7 @@ impl From for ClientEnvelope { impl From for ClientEnvelope { fn from(req: SendGroupMessagesRequest) -> Self { ClientEnvelope { - aad: None, + aad: Some(AuthenticatedData::dummy()), payload: Some(Payload::GroupMessage(req.messages.first().unwrap().clone())) } } @@ -43,7 +43,7 @@ impl From for ClientEnvelope { impl From for ClientEnvelope { fn from(req: UploadKeyPackageRequest) -> Self { ClientEnvelope { - aad: None, + aad: Some(AuthenticatedData::dummy()), payload: Some(Payload::UploadKeyPackage(req)) } } @@ -52,8 +52,18 @@ impl From for ClientEnvelope { impl From for ClientEnvelope { fn from(req: PublishIdentityUpdateRequest) -> Self { ClientEnvelope { - aad: None, + aad: Some(AuthenticatedData::dummy()), payload: Some(Payload::IdentityUpdate(req.identity_update.unwrap())) } } +} + +impl AuthenticatedData { + pub fn dummy() -> AuthenticatedData { + AuthenticatedData { + target_originator: 1, + target_topic: vec![0x5], + last_seen: None, + } + } } \ No newline at end of file From 45c63dd93440711005ba437628374ed1048a7f5c Mon Sep 17 00:00:00 2001 From: Martin Kysel Date: Mon, 16 Sep 2024 13:28:35 -0600 Subject: [PATCH 05/14] Fix fmt --- examples/cli/cli-client.rs | 25 ++++++++++------------ xmtp_api_grpc/src/grpc_api_helper.rs | 31 +++++++++++++++++++++------- xmtp_api_grpc/src/identity.rs | 8 +++---- xmtp_api_grpc/src/lib.rs | 18 +++++++++++----- xmtp_proto/src/api_client.rs | 15 +++++++++----- xmtp_proto/src/convert.rs | 16 ++++++++------ 6 files changed, 71 insertions(+), 42 deletions(-) diff --git a/examples/cli/cli-client.rs b/examples/cli/cli-client.rs index e01133d53..e1c692114 100755 --- a/examples/cli/cli-client.rs +++ b/examples/cli/cli-client.rs @@ -417,23 +417,20 @@ async fn create_client(cli: &Cli, account: IdentityStrategy) -> Result Result { + pub async fn create( + host: String, + is_secure: bool, + use_replication_v4: bool, + ) -> Result { let host = host.to_string(); let app_version = MetadataValue::try_from(&String::from("0.0.0")) .map_err(|e| Error::new(ErrorKind::MetadataError).with(e))?; @@ -109,7 +116,7 @@ impl Client { libxmtp_version, identity_client, replication_client, - use_replication_v4 + use_replication_v4, }) } @@ -520,7 +527,6 @@ impl XmtpMlsStreams for Client { } } - pub struct BatchSubscribeStream { inner: tonic::codec::Streaming, } @@ -547,7 +553,10 @@ impl Stream for BatchSubscribeStream { impl XmtpReplicationClient for Client { type BatchSubscribeStream<'a> = BatchSubscribeStream; - async fn publish_envelope(&self, request: PublishEnvelopeRequest) -> Result { + async fn publish_envelope( + &self, + request: PublishEnvelopeRequest, + ) -> Result { let client = &mut self.replication_client.clone(); client @@ -557,7 +566,10 @@ impl XmtpReplicationClient for Client { .map_err(|e| Error::new(ErrorKind::PublishError).with(e)) } - async fn query_envelopes(&self, request: QueryEnvelopesRequest) -> Result { + async fn query_envelopes( + &self, + request: QueryEnvelopesRequest, + ) -> Result { let client = &mut self.replication_client.clone(); client @@ -567,7 +579,10 @@ impl XmtpReplicationClient for Client { .map_err(|e| Error::new(ErrorKind::QueryError).with(e)) } - async fn batch_subscribe_envelopes(&self, request: BatchSubscribeEnvelopesRequest) -> Result, Error> { + async fn batch_subscribe_envelopes( + &self, + request: BatchSubscribeEnvelopesRequest, + ) -> Result, Error> { let client = &mut self.replication_client.clone(); let res = client .batch_subscribe_envelopes(request) @@ -578,4 +593,4 @@ impl XmtpReplicationClient for Client { Ok(stream.into()) } -} \ No newline at end of file +} diff --git a/xmtp_api_grpc/src/identity.rs b/xmtp_api_grpc/src/identity.rs index f8630cb99..605852669 100644 --- a/xmtp_api_grpc/src/identity.rs +++ b/xmtp_api_grpc/src/identity.rs @@ -1,3 +1,6 @@ +use crate::conversions::wrap_client_envelope; +use crate::Client; +use xmtp_proto::xmtp::xmtpv4::ClientEnvelope; use xmtp_proto::{ api_client::{Error, ErrorKind, XmtpIdentityClient}, xmtp::identity::api::v1::{ @@ -6,9 +9,6 @@ use xmtp_proto::{ GetInboxIdsResponse, PublishIdentityUpdateRequest, PublishIdentityUpdateResponse, }, }; -use xmtp_proto::xmtp::xmtpv4::ClientEnvelope; -use crate::Client; -use crate::conversions::wrap_client_envelope; impl XmtpIdentityClient for Client { #[tracing::instrument(level = "trace", skip_all)] @@ -21,7 +21,7 @@ impl XmtpIdentityClient for Client { let payload = wrap_client_envelope(ClientEnvelope::from(request)); let res = client.publish_envelope(payload).await; match res { - Ok(_) => Ok(PublishIdentityUpdateResponse{}), + Ok(_) => Ok(PublishIdentityUpdateResponse {}), Err(e) => Err(Error::new(ErrorKind::MlsError).with(e)), } } else { diff --git a/xmtp_api_grpc/src/lib.rs b/xmtp_api_grpc/src/lib.rs index cd1b99149..c9eb1fb9f 100644 --- a/xmtp_api_grpc/src/lib.rs +++ b/xmtp_api_grpc/src/lib.rs @@ -1,7 +1,7 @@ pub mod auth_token; +mod conversions; pub mod grpc_api_helper; mod identity; -mod conversions; pub const LOCALHOST_ADDRESS: &str = "http://localhost:5556"; pub const DEV_ADDRESS: &str = "https://grpc.dev.xmtp.network:443"; @@ -163,7 +163,9 @@ mod tests { #[tokio::test] async fn tls_test() { - let client = Client::create(DEV_ADDRESS.to_string(), true, false).await.unwrap(); + let client = Client::create(DEV_ADDRESS.to_string(), true, false) + .await + .unwrap(); let result = client .query(QueryRequest { @@ -235,7 +237,9 @@ mod tests { #[tokio::test] async fn test_dev_publish() { let auth_token = get_auth_token(); - let dev_client = Client::create(DEV_ADDRESS.to_string(), true, false).await.unwrap(); + let dev_client = Client::create(DEV_ADDRESS.to_string(), true, false) + .await + .unwrap(); dev_client .publish( auth_token, @@ -255,7 +259,9 @@ mod tests { async fn long_lived_subscribe_test() { let auth_token = get_auth_token(); tokio::time::timeout(std::time::Duration::from_secs(100), async move { - let client = Client::create(DEV_ADDRESS.to_string(), true, false).await.unwrap(); + let client = Client::create(DEV_ADDRESS.to_string(), true, false) + .await + .unwrap(); let topic = uuid::Uuid::new_v4(); let mut subscription = client @@ -308,7 +314,9 @@ mod tests { #[tokio::test] async fn metadata_test() { - let mut client = Client::create(DEV_ADDRESS.to_string(), true, false).await.unwrap(); + let mut client = Client::create(DEV_ADDRESS.to_string(), true, false) + .await + .unwrap(); let app_version = "test/1.0.0".to_string(); let libxmtp_version = "0.0.1".to_string(); diff --git a/xmtp_proto/src/api_client.rs b/xmtp_proto/src/api_client.rs index 4068cceb5..4b76a8738 100644 --- a/xmtp_proto/src/api_client.rs +++ b/xmtp_proto/src/api_client.rs @@ -17,7 +17,10 @@ use crate::xmtp::mls::api::v1::{ SendGroupMessagesRequest, SendWelcomeMessagesRequest, SubscribeGroupMessagesRequest, SubscribeWelcomeMessagesRequest, UploadKeyPackageRequest, WelcomeMessage, }; -use crate::xmtp::xmtpv4::{BatchSubscribeEnvelopesRequest, BatchSubscribeEnvelopesResponse, PublishEnvelopeRequest, PublishEnvelopeResponse, QueryEnvelopesRequest, QueryEnvelopesResponse}; +use crate::xmtp::xmtpv4::{ + BatchSubscribeEnvelopesRequest, BatchSubscribeEnvelopesResponse, PublishEnvelopeRequest, + PublishEnvelopeResponse, QueryEnvelopesRequest, QueryEnvelopesResponse, +}; #[derive(Debug)] pub enum ErrorKind { @@ -238,7 +241,9 @@ pub trait LocalXmtpIdentityClient { #[cfg_attr(not(target_arch = "wasm32"), trait_variant::make(XmtpReplicationClient: Send))] #[cfg_attr(target_arch = "wasm32", trait_variant::make(XmtpReplicationClient: Wasm))] pub trait LocalXmtpReplicationClient { - type BatchSubscribeStream<'a>: Stream> + Send + 'a + type BatchSubscribeStream<'a>: Stream> + + Send + + 'a where Self: 'a; @@ -250,10 +255,10 @@ pub trait LocalXmtpReplicationClient { async fn query_envelopes( &self, request: QueryEnvelopesRequest, - ) -> Result; + ) -> Result; fn batch_subscribe_envelopes( &self, request: BatchSubscribeEnvelopesRequest, - ) -> impl futures::Future, Error>> + Send; -} \ No newline at end of file + ) -> impl futures::Future, Error>> + Send; +} diff --git a/xmtp_proto/src/convert.rs b/xmtp_proto/src/convert.rs index d17c110b6..a6b5fb339 100644 --- a/xmtp_proto/src/convert.rs +++ b/xmtp_proto/src/convert.rs @@ -1,5 +1,7 @@ use crate::xmtp::identity::api::v1::PublishIdentityUpdateRequest; -use crate::xmtp::mls::api::v1::{SendGroupMessagesRequest, SendWelcomeMessagesRequest, UploadKeyPackageRequest}; +use crate::xmtp::mls::api::v1::{ + SendGroupMessagesRequest, SendWelcomeMessagesRequest, UploadKeyPackageRequest, +}; use crate::xmtp::xmtpv4::client_envelope::Payload; use crate::xmtp::xmtpv4::{AuthenticatedData, ClientEnvelope}; @@ -26,7 +28,9 @@ impl From for ClientEnvelope { fn from(req: SendWelcomeMessagesRequest) -> Self { ClientEnvelope { aad: None, - payload: Some(Payload::WelcomeMessage(req.messages.first().unwrap().clone())) + payload: Some(Payload::WelcomeMessage( + req.messages.first().unwrap().clone(), + )), } } } @@ -35,7 +39,7 @@ impl From for ClientEnvelope { fn from(req: SendGroupMessagesRequest) -> Self { ClientEnvelope { aad: Some(AuthenticatedData::dummy()), - payload: Some(Payload::GroupMessage(req.messages.first().unwrap().clone())) + payload: Some(Payload::GroupMessage(req.messages.first().unwrap().clone())), } } } @@ -44,7 +48,7 @@ impl From for ClientEnvelope { fn from(req: UploadKeyPackageRequest) -> Self { ClientEnvelope { aad: Some(AuthenticatedData::dummy()), - payload: Some(Payload::UploadKeyPackage(req)) + payload: Some(Payload::UploadKeyPackage(req)), } } } @@ -53,7 +57,7 @@ impl From for ClientEnvelope { fn from(req: PublishIdentityUpdateRequest) -> Self { ClientEnvelope { aad: Some(AuthenticatedData::dummy()), - payload: Some(Payload::IdentityUpdate(req.identity_update.unwrap())) + payload: Some(Payload::IdentityUpdate(req.identity_update.unwrap())), } } } @@ -66,4 +70,4 @@ impl AuthenticatedData { last_seen: None, } } -} \ No newline at end of file +} From 7d5437d9093f6b296ae9d6ca3f954ebe6b127845 Mon Sep 17 00:00:00 2001 From: Martin Kysel Date: Mon, 16 Sep 2024 13:34:22 -0600 Subject: [PATCH 06/14] another one --- bindings_node/src/mls_client.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bindings_node/src/mls_client.rs b/bindings_node/src/mls_client.rs index 348d9ce42..357e3c130 100644 --- a/bindings_node/src/mls_client.rs +++ b/bindings_node/src/mls_client.rs @@ -68,7 +68,7 @@ pub async fn create_client( encryption_key: Option, history_sync_url: Option, ) -> Result { - let api_client = TonicApiClient::create(host.clone(), is_secure) + let api_client = TonicApiClient::create(host.clone(), is_secure, false) .await .map_err(|_| Error::from_reason("Error creating Tonic API client"))?; From 9cc822ed368e29b3e17b73db3be75c05f0ba7c02 Mon Sep 17 00:00:00 2001 From: Nicholas Molnar <65710+neekolas@users.noreply.github.com> Date: Tue, 24 Sep 2024 15:23:12 -0500 Subject: [PATCH 07/14] Write to identity updates --- xmtp_api_grpc/src/identity.rs | 84 ++++++++++++++++++++++++++++++++--- 1 file changed, 77 insertions(+), 7 deletions(-) diff --git a/xmtp_api_grpc/src/identity.rs b/xmtp_api_grpc/src/identity.rs index 605852669..486d5e215 100644 --- a/xmtp_api_grpc/src/identity.rs +++ b/xmtp_api_grpc/src/identity.rs @@ -1,6 +1,13 @@ use crate::conversions::wrap_client_envelope; use crate::Client; -use xmtp_proto::xmtp::xmtpv4::ClientEnvelope; +use prost::Message; +use xmtp_proto::xmtp::identity::api::v1::get_identity_updates_response::{self, IdentityUpdateLog}; +use xmtp_proto::xmtp::xmtpv4::client_envelope::Payload; +use xmtp_proto::xmtp::xmtpv4::envelopes_query::Filter; +use xmtp_proto::xmtp::xmtpv4::{ + ClientEnvelope, EnvelopesQuery, OriginatorEnvelope, QueryEnvelopesRequest, + UnsignedOriginatorEnvelope, +}; use xmtp_proto::{ api_client::{Error, ErrorKind, XmtpIdentityClient}, xmtp::identity::api::v1::{ @@ -54,13 +61,76 @@ impl XmtpIdentityClient for Client { &self, request: GetIdentityUpdatesV2Request, ) -> Result { - let client = &mut self.identity_client.clone(); + let client = &mut self.replication_client.clone(); + let mut responses = vec![]; - let res = client - .get_identity_updates(self.build_request(request)) - .await; + for inner_req in request.requests.iter() { + let v4_envelopes = client + .query_envelopes(QueryEnvelopesRequest { + query: Some(EnvelopesQuery { + last_seen: None, + filter: Some(Filter::Topic(build_identity_update_topic( + inner_req.inbox_id.clone(), + ))), + }), + limit: 100, + }) + .await + .map_err(|err| Error::new(ErrorKind::IdentityError).with(err))?; - res.map(|response| response.into_inner()) - .map_err(|err| Error::new(ErrorKind::IdentityError).with(err)) + let identity_update_responses = v4_envelopes + .into_inner() + .envelopes + .iter() + .map(convert_v4_envelope_to_identity_update) + .collect::, Error>>()?; + + responses.push(get_identity_updates_response::Response { + inbox_id: inner_req.inbox_id.clone(), + updates: identity_update_responses, + }); + } + + Ok(GetIdentityUpdatesV2Response { responses }) } } + +fn convert_v4_envelope_to_identity_update( + envelope: &OriginatorEnvelope, +) -> Result { + let mut unsigned_originator_envelope = envelope.unsigned_originator_envelope.as_slice(); + let originator_envelope = UnsignedOriginatorEnvelope::decode(&mut unsigned_originator_envelope) + .map_err(|e| Error::new(ErrorKind::IdentityError).with(e))?; + + let payer_envelope = originator_envelope + .payer_envelope + .ok_or(Error::new(ErrorKind::IdentityError).with("Payer envelope is None"))?; + + // TODO: validate payer signatures + let mut unsigned_client_envelope = payer_envelope.unsigned_client_envelope.as_slice(); + + let client_envelope = ClientEnvelope::decode(&mut unsigned_client_envelope) + .map_err(|e| Error::new(ErrorKind::IdentityError).with(e))?; + let payload = client_envelope + .payload + .ok_or(Error::new(ErrorKind::IdentityError).with("Payload is None"))?; + + let identity_update = match payload { + Payload::IdentityUpdate(update) => update, + _ => { + return Err( + Error::new(ErrorKind::IdentityError).with("Payload is not an identity update") + ) + } + }; + + Ok(IdentityUpdateLog { + sequence_id: originator_envelope.originator_sequence_id, + server_timestamp_ns: originator_envelope.originator_ns as u64, + update: Some(identity_update), + }) +} + +fn build_identity_update_topic(inbox_id: String) -> Vec { + format!("i/{}", inbox_id).into_bytes() +} From aa20dbfde22ec26b1acad362cd315585f8f73c10 Mon Sep 17 00:00:00 2001 From: Nicholas Molnar <65710+neekolas@users.noreply.github.com> Date: Wed, 25 Sep 2024 15:22:47 -0500 Subject: [PATCH 08/14] Add get inbox ids endpoint to the server --- Cargo.lock | 1 + bindings_ffi/Cargo.lock | 1 + bindings_node/Cargo.lock | 1 + dev/gen_protos.sh | 2 +- xmtp_api_grpc/src/identity.rs | 30 +- xmtp_proto/Cargo.toml | 1 + xmtp_proto/src/convert.rs | 33 +- xmtp_proto/src/gen/xmtp.xmtpv4.rs | 742 ++++++++++++++---------- xmtp_proto/src/gen/xmtp.xmtpv4.serde.rs | 382 ++++++++++++ xmtp_proto/src/gen/xmtp.xmtpv4.tonic.rs | 79 +++ 10 files changed, 953 insertions(+), 319 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2127a8feb..20c8013b2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6347,6 +6347,7 @@ name = "xmtp_proto" version = "0.0.1" dependencies = [ "futures", + "hex", "openmls", "pbjson", "pbjson-types", diff --git a/bindings_ffi/Cargo.lock b/bindings_ffi/Cargo.lock index 4ca4562cf..87969f025 100644 --- a/bindings_ffi/Cargo.lock +++ b/bindings_ffi/Cargo.lock @@ -5793,6 +5793,7 @@ name = "xmtp_proto" version = "0.0.1" dependencies = [ "futures", + "hex", "openmls", "pbjson", "pbjson-types", diff --git a/bindings_node/Cargo.lock b/bindings_node/Cargo.lock index 03a2852a2..a2fc5dd3c 100644 --- a/bindings_node/Cargo.lock +++ b/bindings_node/Cargo.lock @@ -5298,6 +5298,7 @@ name = "xmtp_proto" version = "0.0.1" dependencies = [ "futures", + "hex", "openmls", "pbjson", "pbjson-types", diff --git a/dev/gen_protos.sh b/dev/gen_protos.sh index fabae5e81..df6143e04 100755 --- a/dev/gen_protos.sh +++ b/dev/gen_protos.sh @@ -6,7 +6,7 @@ if ! cargo install --list | grep "protoc-gen-prost-crate" > /dev/null; then fi fi -if ! buf generate https://github.com/xmtp/proto.git#branch=main,subdir=proto; then +if ! buf generate https://github.com/xmtp/proto.git#branch=nm/add-get-inbox-ids,subdir=proto; then echo "Failed to generate protobuf definitions" exit 1 fi diff --git a/xmtp_api_grpc/src/identity.rs b/xmtp_api_grpc/src/identity.rs index 486d5e215..52d53cfc8 100644 --- a/xmtp_api_grpc/src/identity.rs +++ b/xmtp_api_grpc/src/identity.rs @@ -15,6 +15,7 @@ use xmtp_proto::{ GetIdentityUpdatesResponse as GetIdentityUpdatesV2Response, GetInboxIdsRequest, GetInboxIdsResponse, PublishIdentityUpdateRequest, PublishIdentityUpdateResponse, }, + xmtp::xmtpv4::GetInboxIdsRequest as GetInboxIdsV4Request, }; impl XmtpIdentityClient for Client { @@ -48,11 +49,34 @@ impl XmtpIdentityClient for Client { &self, request: GetInboxIdsRequest, ) -> Result { - let client = &mut self.identity_client.clone(); - - let res = client.get_inbox_ids(self.build_request(request)).await; + let client = &mut self.replication_client.clone(); + let req = GetInboxIdsV4Request { + requests: request + .requests + .into_iter() + .map( + |r| xmtp_proto::xmtp::xmtpv4::get_inbox_ids_request::Request { + address: r.address, + }, + ) + .collect(), + }; + + let res = client.get_inbox_ids(self.build_request(req)).await; res.map(|response| response.into_inner()) + .map(|response| GetInboxIdsResponse { + responses: response + .responses + .into_iter() + .map(|r| { + xmtp_proto::xmtp::identity::api::v1::get_inbox_ids_response::Response { + address: r.address, + inbox_id: r.inbox_id, + } + }) + .collect(), + }) .map_err(|err| Error::new(ErrorKind::IdentityError).with(err)) } diff --git a/xmtp_proto/Cargo.toml b/xmtp_proto/Cargo.toml index 9bfffc877..327520529 100644 --- a/xmtp_proto/Cargo.toml +++ b/xmtp_proto/Cargo.toml @@ -13,6 +13,7 @@ prost-types = { workspace = true } serde = { workspace = true } openmls = { workspace = true, optional = true } trait-variant = "0.1.2" +hex.workspace = true [target.'cfg(not(target_arch = "wasm32"))'.dependencies] tonic = { workspace = true } diff --git a/xmtp_proto/src/convert.rs b/xmtp_proto/src/convert.rs index a6b5fb339..bc02e4d09 100644 --- a/xmtp_proto/src/convert.rs +++ b/xmtp_proto/src/convert.rs @@ -1,4 +1,8 @@ +use openmls::prelude::tls_codec::Deserialize; +use openmls::prelude::{MlsMessageIn, ProtocolMessage}; + use crate::xmtp::identity::api::v1::PublishIdentityUpdateRequest; +use crate::xmtp::mls::api::v1::group_message_input::Version as GroupMessageInputVersion; use crate::xmtp::mls::api::v1::{ SendGroupMessagesRequest, SendWelcomeMessagesRequest, UploadKeyPackageRequest, }; @@ -37,8 +41,13 @@ impl From for ClientEnvelope { impl From for ClientEnvelope { fn from(req: SendGroupMessagesRequest) -> Self { + let first_message = req.messages.first().unwrap(); + let version = match first_message.version.as_ref().unwrap() { + GroupMessageInputVersion::V1(v1) => v1, + }; + let topic = extract_topic_from_group_message(version.data.clone()).unwrap(); ClientEnvelope { - aad: Some(AuthenticatedData::dummy()), + aad: Some(AuthenticatedData::with_topic(topic)), payload: Some(Payload::GroupMessage(req.messages.first().unwrap().clone())), } } @@ -70,4 +79,26 @@ impl AuthenticatedData { last_seen: None, } } + + pub fn with_topic(topic: String) -> AuthenticatedData { + AuthenticatedData { + target_originator: 1, + target_topic: topic.as_bytes().to_vec(), + last_seen: None, + } + } +} + +fn extract_topic_from_group_message(message: Vec) -> Result { + let msg_result = + MlsMessageIn::tls_deserialize(&mut message.as_slice()).map_err(|e| e.to_string())?; + + let protocol_message: ProtocolMessage = msg_result + .try_into_protocol_message() + .map_err(|e| e.to_string())?; + + Ok(format!( + "g/{}", + hex::encode(protocol_message.group_id().as_slice()) + )) } diff --git a/xmtp_proto/src/gen/xmtp.xmtpv4.rs b/xmtp_proto/src/gen/xmtp.xmtpv4.rs index d93be56fe..33b54cc0b 100644 --- a/xmtp_proto/src/gen/xmtp.xmtpv4.rs +++ b/xmtp_proto/src/gen/xmtp.xmtpv4.rs @@ -179,6 +179,42 @@ pub struct PublishEnvelopeResponse { #[prost(message, optional, tag="1")] pub originator_envelope: ::core::option::Option, } +/// Request to retrieve the XIDs for the given addresses +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct GetInboxIdsRequest { + #[prost(message, repeated, tag="1")] + pub requests: ::prost::alloc::vec::Vec, +} +/// Nested message and enum types in `GetInboxIdsRequest`. +pub mod get_inbox_ids_request { + /// A single request for a given address + #[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] + pub struct Request { + #[prost(string, tag="1")] + pub address: ::prost::alloc::string::String, + } +} +/// Response with the XIDs for the requested addresses +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct GetInboxIdsResponse { + #[prost(message, repeated, tag="1")] + pub responses: ::prost::alloc::vec::Vec, +} +/// Nested message and enum types in `GetInboxIdsResponse`. +pub mod get_inbox_ids_response { + /// A single response for a given address + #[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] + pub struct Response { + #[prost(string, tag="1")] + pub address: ::prost::alloc::string::String, + #[prost(string, optional, tag="2")] + pub inbox_id: ::core::option::Option<::prost::alloc::string::String>, + } +} /// Misbehavior types #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] #[repr(i32)] @@ -217,7 +253,7 @@ impl Misbehavior { } /// Encoded file descriptor set for the `xmtp.xmtpv4` package pub const FILE_DESCRIPTOR_SET: &[u8] = &[ - 0x0a, 0xad, 0x3c, 0x0a, 0x24, 0x78, 0x6d, 0x74, 0x70, 0x76, 0x34, 0x2f, 0x6d, 0x65, 0x73, 0x73, + 0x0a, 0x84, 0x46, 0x0a, 0x24, 0x78, 0x6d, 0x74, 0x70, 0x76, 0x34, 0x2f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x61, 0x70, 0x69, 0x2f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x61, 0x70, 0x69, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0b, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x76, 0x34, 0x1a, 0x1c, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x61, @@ -386,320 +422,398 @@ pub const FILE_DESCRIPTOR_SET: &[u8] = &[ 0x6c, 0x6f, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x76, 0x34, 0x2e, 0x4f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x45, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x52, 0x12, 0x6f, 0x72, 0x69, - 0x67, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x45, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x2a, - 0xce, 0x01, 0x0a, 0x0b, 0x4d, 0x69, 0x73, 0x62, 0x65, 0x68, 0x61, 0x76, 0x69, 0x6f, 0x72, 0x12, - 0x1b, 0x0a, 0x17, 0x4d, 0x49, 0x53, 0x42, 0x45, 0x48, 0x41, 0x56, 0x49, 0x4f, 0x52, 0x5f, 0x55, - 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x20, 0x0a, 0x1c, - 0x4d, 0x49, 0x53, 0x42, 0x45, 0x48, 0x41, 0x56, 0x49, 0x4f, 0x52, 0x5f, 0x55, 0x4e, 0x41, 0x56, - 0x41, 0x49, 0x4c, 0x41, 0x42, 0x4c, 0x45, 0x5f, 0x4e, 0x4f, 0x44, 0x45, 0x10, 0x01, 0x12, 0x2b, - 0x0a, 0x27, 0x4d, 0x49, 0x53, 0x42, 0x45, 0x48, 0x41, 0x56, 0x49, 0x4f, 0x52, 0x5f, 0x4f, 0x55, - 0x54, 0x5f, 0x4f, 0x46, 0x5f, 0x4f, 0x52, 0x44, 0x45, 0x52, 0x5f, 0x4f, 0x52, 0x49, 0x47, 0x49, - 0x4e, 0x41, 0x54, 0x4f, 0x52, 0x5f, 0x53, 0x49, 0x44, 0x10, 0x02, 0x12, 0x28, 0x0a, 0x24, 0x4d, - 0x49, 0x53, 0x42, 0x45, 0x48, 0x41, 0x56, 0x49, 0x4f, 0x52, 0x5f, 0x44, 0x55, 0x50, 0x4c, 0x49, - 0x43, 0x41, 0x54, 0x45, 0x5f, 0x4f, 0x52, 0x49, 0x47, 0x49, 0x4e, 0x41, 0x54, 0x4f, 0x52, 0x5f, - 0x53, 0x49, 0x44, 0x10, 0x03, 0x12, 0x29, 0x0a, 0x25, 0x4d, 0x49, 0x53, 0x42, 0x45, 0x48, 0x41, - 0x56, 0x49, 0x4f, 0x52, 0x5f, 0x43, 0x59, 0x43, 0x4c, 0x49, 0x43, 0x41, 0x4c, 0x5f, 0x4d, 0x45, - 0x53, 0x53, 0x41, 0x47, 0x45, 0x5f, 0x4f, 0x52, 0x44, 0x45, 0x52, 0x49, 0x4e, 0x47, 0x10, 0x04, - 0x32, 0xb4, 0x03, 0x0a, 0x0e, 0x52, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x41, 0x70, 0x69, 0x12, 0x9e, 0x01, 0x0a, 0x17, 0x42, 0x61, 0x74, 0x63, 0x68, 0x53, 0x75, 0x62, - 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x45, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x73, 0x12, - 0x2b, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x76, 0x34, 0x2e, 0x42, 0x61, - 0x74, 0x63, 0x68, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x45, 0x6e, 0x76, 0x65, - 0x6c, 0x6f, 0x70, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2c, 0x2e, 0x78, - 0x6d, 0x74, 0x70, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x76, 0x34, 0x2e, 0x42, 0x61, 0x74, 0x63, 0x68, - 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x45, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, - 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x26, 0x82, 0xd3, 0xe4, 0x93, - 0x02, 0x20, 0x3a, 0x01, 0x2a, 0x22, 0x1b, 0x2f, 0x6d, 0x6c, 0x73, 0x2f, 0x76, 0x32, 0x2f, 0x73, - 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x2d, 0x65, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, - 0x65, 0x73, 0x30, 0x01, 0x12, 0x7d, 0x0a, 0x0e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x45, 0x6e, 0x76, - 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x73, 0x12, 0x22, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x78, 0x6d, - 0x74, 0x70, 0x76, 0x34, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x45, 0x6e, 0x76, 0x65, 0x6c, 0x6f, - 0x70, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x78, 0x6d, 0x74, + 0x67, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x45, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x22, + 0x7e, 0x0a, 0x12, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x62, 0x6f, 0x78, 0x49, 0x64, 0x73, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x43, 0x0a, 0x08, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x78, + 0x6d, 0x74, 0x70, 0x76, 0x34, 0x2e, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x62, 0x6f, 0x78, 0x49, 0x64, + 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x52, 0x08, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x1a, 0x23, 0x0a, 0x07, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x22, + 0xb1, 0x01, 0x0a, 0x13, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x62, 0x6f, 0x78, 0x49, 0x64, 0x73, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x47, 0x0a, 0x09, 0x72, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x78, 0x6d, 0x74, + 0x70, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x76, 0x34, 0x2e, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x62, 0x6f, + 0x78, 0x49, 0x64, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x52, 0x09, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x73, + 0x1a, 0x51, 0x0a, 0x08, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, + 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, + 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x1e, 0x0a, 0x08, 0x69, 0x6e, 0x62, 0x6f, 0x78, 0x5f, + 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x07, 0x69, 0x6e, 0x62, 0x6f, + 0x78, 0x49, 0x64, 0x88, 0x01, 0x01, 0x42, 0x0b, 0x0a, 0x09, 0x5f, 0x69, 0x6e, 0x62, 0x6f, 0x78, + 0x5f, 0x69, 0x64, 0x2a, 0xce, 0x01, 0x0a, 0x0b, 0x4d, 0x69, 0x73, 0x62, 0x65, 0x68, 0x61, 0x76, + 0x69, 0x6f, 0x72, 0x12, 0x1b, 0x0a, 0x17, 0x4d, 0x49, 0x53, 0x42, 0x45, 0x48, 0x41, 0x56, 0x49, + 0x4f, 0x52, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, + 0x12, 0x20, 0x0a, 0x1c, 0x4d, 0x49, 0x53, 0x42, 0x45, 0x48, 0x41, 0x56, 0x49, 0x4f, 0x52, 0x5f, + 0x55, 0x4e, 0x41, 0x56, 0x41, 0x49, 0x4c, 0x41, 0x42, 0x4c, 0x45, 0x5f, 0x4e, 0x4f, 0x44, 0x45, + 0x10, 0x01, 0x12, 0x2b, 0x0a, 0x27, 0x4d, 0x49, 0x53, 0x42, 0x45, 0x48, 0x41, 0x56, 0x49, 0x4f, + 0x52, 0x5f, 0x4f, 0x55, 0x54, 0x5f, 0x4f, 0x46, 0x5f, 0x4f, 0x52, 0x44, 0x45, 0x52, 0x5f, 0x4f, + 0x52, 0x49, 0x47, 0x49, 0x4e, 0x41, 0x54, 0x4f, 0x52, 0x5f, 0x53, 0x49, 0x44, 0x10, 0x02, 0x12, + 0x28, 0x0a, 0x24, 0x4d, 0x49, 0x53, 0x42, 0x45, 0x48, 0x41, 0x56, 0x49, 0x4f, 0x52, 0x5f, 0x44, + 0x55, 0x50, 0x4c, 0x49, 0x43, 0x41, 0x54, 0x45, 0x5f, 0x4f, 0x52, 0x49, 0x47, 0x49, 0x4e, 0x41, + 0x54, 0x4f, 0x52, 0x5f, 0x53, 0x49, 0x44, 0x10, 0x03, 0x12, 0x29, 0x0a, 0x25, 0x4d, 0x49, 0x53, + 0x42, 0x45, 0x48, 0x41, 0x56, 0x49, 0x4f, 0x52, 0x5f, 0x43, 0x59, 0x43, 0x4c, 0x49, 0x43, 0x41, + 0x4c, 0x5f, 0x4d, 0x45, 0x53, 0x53, 0x41, 0x47, 0x45, 0x5f, 0x4f, 0x52, 0x44, 0x45, 0x52, 0x49, + 0x4e, 0x47, 0x10, 0x04, 0x32, 0xa8, 0x04, 0x0a, 0x0e, 0x52, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x41, 0x70, 0x69, 0x12, 0x9e, 0x01, 0x0a, 0x17, 0x42, 0x61, 0x74, 0x63, + 0x68, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x45, 0x6e, 0x76, 0x65, 0x6c, 0x6f, + 0x70, 0x65, 0x73, 0x12, 0x2b, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x76, + 0x34, 0x2e, 0x42, 0x61, 0x74, 0x63, 0x68, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, + 0x45, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x2c, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x76, 0x34, 0x2e, 0x42, + 0x61, 0x74, 0x63, 0x68, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x45, 0x6e, 0x76, + 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x26, + 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x20, 0x3a, 0x01, 0x2a, 0x22, 0x1b, 0x2f, 0x6d, 0x6c, 0x73, 0x2f, + 0x76, 0x32, 0x2f, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x2d, 0x65, 0x6e, 0x76, + 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x73, 0x30, 0x01, 0x12, 0x7d, 0x0a, 0x0e, 0x51, 0x75, 0x65, 0x72, + 0x79, 0x45, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x73, 0x12, 0x22, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x76, 0x34, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x45, 0x6e, - 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, - 0x22, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1c, 0x3a, 0x01, 0x2a, 0x22, 0x17, 0x2f, 0x6d, 0x6c, 0x73, - 0x2f, 0x76, 0x32, 0x2f, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2d, 0x65, 0x6e, 0x76, 0x65, 0x6c, 0x6f, - 0x70, 0x65, 0x73, 0x12, 0x81, 0x01, 0x0a, 0x0f, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x45, - 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x12, 0x23, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x78, - 0x6d, 0x74, 0x70, 0x76, 0x34, 0x2e, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x45, 0x6e, 0x76, - 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x78, - 0x6d, 0x74, 0x70, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x76, 0x34, 0x2e, 0x50, 0x75, 0x62, 0x6c, 0x69, - 0x73, 0x68, 0x45, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x22, 0x23, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1d, 0x3a, 0x01, 0x2a, 0x22, 0x18, 0x2f, - 0x6d, 0x6c, 0x73, 0x2f, 0x76, 0x32, 0x2f, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x2d, 0x65, - 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x42, 0x9f, 0x01, 0x0a, 0x0f, 0x63, 0x6f, 0x6d, 0x2e, - 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x76, 0x34, 0x42, 0x0f, 0x4d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x41, 0x70, 0x69, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x2e, - 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x6d, 0x74, 0x70, 0x2f, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x76, 0x33, 0x2f, 0x67, 0x6f, 0x2f, 0x78, 0x6d, 0x74, 0x70, - 0x76, 0x34, 0x2f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x61, 0x70, 0x69, 0xa2, 0x02, - 0x03, 0x58, 0x58, 0x58, 0xaa, 0x02, 0x0b, 0x58, 0x6d, 0x74, 0x70, 0x2e, 0x58, 0x6d, 0x74, 0x70, - 0x76, 0x34, 0xca, 0x02, 0x0b, 0x58, 0x6d, 0x74, 0x70, 0x5c, 0x58, 0x6d, 0x74, 0x70, 0x76, 0x34, - 0xe2, 0x02, 0x17, 0x58, 0x6d, 0x74, 0x70, 0x5c, 0x58, 0x6d, 0x74, 0x70, 0x76, 0x34, 0x5c, 0x47, - 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x0c, 0x58, 0x6d, 0x74, - 0x70, 0x3a, 0x3a, 0x58, 0x6d, 0x74, 0x70, 0x76, 0x34, 0x4a, 0xdc, 0x20, 0x0a, 0x07, 0x12, 0x05, - 0x01, 0x00, 0x95, 0x01, 0x01, 0x0a, 0x23, 0x0a, 0x01, 0x0c, 0x12, 0x03, 0x01, 0x00, 0x12, 0x1a, - 0x19, 0x20, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x20, 0x41, 0x50, 0x49, 0x20, 0x66, 0x6f, - 0x72, 0x20, 0x58, 0x4d, 0x54, 0x50, 0x20, 0x56, 0x34, 0x0a, 0x0a, 0x08, 0x0a, 0x01, 0x02, 0x12, - 0x03, 0x03, 0x00, 0x14, 0x0a, 0x09, 0x0a, 0x02, 0x03, 0x00, 0x12, 0x03, 0x05, 0x00, 0x26, 0x0a, - 0x09, 0x0a, 0x02, 0x03, 0x01, 0x12, 0x03, 0x06, 0x00, 0x31, 0x0a, 0x09, 0x0a, 0x02, 0x03, 0x02, - 0x12, 0x03, 0x07, 0x00, 0x2f, 0x0a, 0x09, 0x0a, 0x02, 0x03, 0x03, 0x12, 0x03, 0x08, 0x00, 0x1e, - 0x0a, 0x08, 0x0a, 0x01, 0x08, 0x12, 0x03, 0x0a, 0x00, 0x45, 0x0a, 0x09, 0x0a, 0x02, 0x08, 0x0b, - 0x12, 0x03, 0x0a, 0x00, 0x45, 0x0a, 0xb7, 0x01, 0x0a, 0x02, 0x04, 0x00, 0x12, 0x04, 0x0e, 0x00, - 0x10, 0x01, 0x1a, 0xaa, 0x01, 0x20, 0x54, 0x68, 0x65, 0x20, 0x6c, 0x61, 0x73, 0x74, 0x20, 0x73, - 0x65, 0x65, 0x6e, 0x20, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x20, 0x70, 0x65, 0x72, 0x20, 0x6f, 0x72, - 0x69, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x2e, 0x20, 0x4f, 0x72, 0x69, 0x67, 0x69, 0x6e, - 0x61, 0x74, 0x6f, 0x72, 0x73, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x68, 0x61, 0x76, 0x65, 0x20, - 0x6e, 0x6f, 0x74, 0x20, 0x62, 0x65, 0x65, 0x6e, 0x20, 0x73, 0x65, 0x65, 0x6e, 0x20, 0x61, 0x72, - 0x65, 0x20, 0x6f, 0x6d, 0x69, 0x74, 0x74, 0x65, 0x64, 0x2e, 0x0a, 0x20, 0x45, 0x6e, 0x74, 0x72, - 0x69, 0x65, 0x73, 0x20, 0x4d, 0x55, 0x53, 0x54, 0x20, 0x62, 0x65, 0x20, 0x73, 0x6f, 0x72, 0x74, - 0x65, 0x64, 0x20, 0x69, 0x6e, 0x20, 0x61, 0x73, 0x63, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x20, - 0x6f, 0x72, 0x64, 0x65, 0x72, 0x2c, 0x20, 0x73, 0x6f, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x73, - 0x6d, 0x61, 0x6c, 0x6c, 0x65, 0x72, 0x20, 0x6e, 0x6f, 0x64, 0x65, 0x20, 0x49, 0x44, 0x27, 0x73, - 0x20, 0x61, 0x70, 0x70, 0x65, 0x61, 0x72, 0x20, 0x66, 0x69, 0x72, 0x73, 0x74, 0x2e, 0x0a, 0x0a, - 0x0a, 0x0a, 0x03, 0x04, 0x00, 0x01, 0x12, 0x03, 0x0e, 0x08, 0x13, 0x0a, 0x0b, 0x0a, 0x04, 0x04, - 0x00, 0x02, 0x00, 0x12, 0x03, 0x0f, 0x02, 0x31, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x00, - 0x06, 0x12, 0x03, 0x0f, 0x02, 0x15, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x00, 0x01, 0x12, - 0x03, 0x0f, 0x16, 0x2c, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x00, 0x03, 0x12, 0x03, 0x0f, - 0x2f, 0x30, 0x0a, 0x53, 0x0a, 0x02, 0x04, 0x01, 0x12, 0x04, 0x13, 0x00, 0x17, 0x01, 0x1a, 0x47, - 0x20, 0x44, 0x61, 0x74, 0x61, 0x20, 0x76, 0x69, 0x73, 0x69, 0x62, 0x6c, 0x65, 0x20, 0x74, 0x6f, - 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x74, 0x68, 0x61, 0x74, - 0x20, 0x68, 0x61, 0x73, 0x20, 0x62, 0x65, 0x65, 0x6e, 0x20, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, - 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x20, 0x62, 0x79, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, - 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x2e, 0x0a, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x01, 0x01, 0x12, 0x03, - 0x13, 0x08, 0x19, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x01, 0x02, 0x00, 0x12, 0x03, 0x14, 0x02, 0x1f, - 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x00, 0x05, 0x12, 0x03, 0x14, 0x02, 0x08, 0x0a, 0x0c, - 0x0a, 0x05, 0x04, 0x01, 0x02, 0x00, 0x01, 0x12, 0x03, 0x14, 0x09, 0x1a, 0x0a, 0x0c, 0x0a, 0x05, - 0x04, 0x01, 0x02, 0x00, 0x03, 0x12, 0x03, 0x14, 0x1d, 0x1e, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x01, - 0x02, 0x01, 0x12, 0x03, 0x15, 0x02, 0x19, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x01, 0x05, - 0x12, 0x03, 0x15, 0x02, 0x07, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x01, 0x01, 0x12, 0x03, - 0x15, 0x08, 0x14, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x01, 0x03, 0x12, 0x03, 0x15, 0x17, - 0x18, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x01, 0x02, 0x02, 0x12, 0x03, 0x16, 0x02, 0x1c, 0x0a, 0x0c, - 0x0a, 0x05, 0x04, 0x01, 0x02, 0x02, 0x06, 0x12, 0x03, 0x16, 0x02, 0x0d, 0x0a, 0x0c, 0x0a, 0x05, - 0x04, 0x01, 0x02, 0x02, 0x01, 0x12, 0x03, 0x16, 0x0e, 0x17, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, - 0x02, 0x02, 0x03, 0x12, 0x03, 0x16, 0x1a, 0x1b, 0x0a, 0x0a, 0x0a, 0x02, 0x04, 0x02, 0x12, 0x04, - 0x19, 0x00, 0x21, 0x01, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x02, 0x01, 0x12, 0x03, 0x19, 0x08, 0x16, - 0x0a, 0x0c, 0x0a, 0x04, 0x04, 0x02, 0x08, 0x00, 0x12, 0x04, 0x1a, 0x02, 0x1f, 0x03, 0x0a, 0x0c, - 0x0a, 0x05, 0x04, 0x02, 0x08, 0x00, 0x01, 0x12, 0x03, 0x1a, 0x08, 0x0f, 0x0a, 0x0b, 0x0a, 0x04, - 0x04, 0x02, 0x02, 0x00, 0x12, 0x03, 0x1b, 0x04, 0x38, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, - 0x00, 0x06, 0x12, 0x03, 0x1b, 0x04, 0x25, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x00, 0x01, - 0x12, 0x03, 0x1b, 0x26, 0x33, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x00, 0x03, 0x12, 0x03, - 0x1b, 0x36, 0x37, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x02, 0x02, 0x01, 0x12, 0x03, 0x1c, 0x04, 0x3c, - 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x01, 0x06, 0x12, 0x03, 0x1c, 0x04, 0x27, 0x0a, 0x0c, - 0x0a, 0x05, 0x04, 0x02, 0x02, 0x01, 0x01, 0x12, 0x03, 0x1c, 0x28, 0x37, 0x0a, 0x0c, 0x0a, 0x05, - 0x04, 0x02, 0x02, 0x01, 0x03, 0x12, 0x03, 0x1c, 0x3a, 0x3b, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x02, - 0x02, 0x02, 0x12, 0x03, 0x1d, 0x04, 0x42, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x02, 0x06, - 0x12, 0x03, 0x1d, 0x04, 0x2d, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x02, 0x01, 0x12, 0x03, - 0x1d, 0x2e, 0x3d, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x02, 0x03, 0x12, 0x03, 0x1d, 0x40, - 0x41, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x02, 0x02, 0x03, 0x12, 0x03, 0x1e, 0x04, 0x43, 0x0a, 0x0c, - 0x0a, 0x05, 0x04, 0x02, 0x02, 0x03, 0x06, 0x12, 0x03, 0x1e, 0x04, 0x2b, 0x0a, 0x0c, 0x0a, 0x05, - 0x04, 0x02, 0x02, 0x03, 0x01, 0x12, 0x03, 0x1e, 0x2c, 0x3e, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, - 0x02, 0x03, 0x03, 0x12, 0x03, 0x1e, 0x41, 0x42, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x02, 0x02, 0x04, - 0x12, 0x03, 0x20, 0x02, 0x1c, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x04, 0x06, 0x12, 0x03, - 0x20, 0x02, 0x13, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x04, 0x01, 0x12, 0x03, 0x20, 0x14, - 0x17, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x04, 0x03, 0x12, 0x03, 0x20, 0x1a, 0x1b, 0x0a, - 0x38, 0x0a, 0x02, 0x04, 0x03, 0x12, 0x04, 0x24, 0x00, 0x27, 0x01, 0x1a, 0x2c, 0x20, 0x57, 0x72, - 0x61, 0x70, 0x73, 0x20, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x20, 0x65, 0x6e, 0x76, 0x65, 0x6c, - 0x6f, 0x70, 0x65, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x70, 0x61, 0x79, 0x65, 0x72, 0x20, 0x73, - 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x0a, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x03, 0x01, - 0x12, 0x03, 0x24, 0x08, 0x15, 0x0a, 0x22, 0x0a, 0x04, 0x04, 0x03, 0x02, 0x00, 0x12, 0x03, 0x25, - 0x02, 0x25, 0x22, 0x15, 0x20, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x20, 0x73, 0x65, - 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, - 0x00, 0x05, 0x12, 0x03, 0x25, 0x02, 0x07, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, 0x00, 0x01, - 0x12, 0x03, 0x25, 0x08, 0x20, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, 0x00, 0x03, 0x12, 0x03, - 0x25, 0x23, 0x24, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x03, 0x02, 0x01, 0x12, 0x03, 0x26, 0x02, 0x4b, - 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, 0x01, 0x06, 0x12, 0x03, 0x26, 0x02, 0x36, 0x0a, 0x0c, - 0x0a, 0x05, 0x04, 0x03, 0x02, 0x01, 0x01, 0x12, 0x03, 0x26, 0x37, 0x46, 0x0a, 0x0c, 0x0a, 0x05, - 0x04, 0x03, 0x02, 0x01, 0x03, 0x12, 0x03, 0x26, 0x49, 0x4a, 0x0a, 0x8e, 0x01, 0x0a, 0x02, 0x04, - 0x04, 0x12, 0x04, 0x2b, 0x00, 0x30, 0x01, 0x1a, 0x81, 0x01, 0x20, 0x46, 0x6f, 0x72, 0x20, 0x62, - 0x6c, 0x6f, 0x63, 0x6b, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x20, 0x65, 0x6e, 0x76, 0x65, 0x6c, 0x6f, - 0x70, 0x65, 0x73, 0x2c, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, - 0x74, 0x6f, 0x72, 0x5f, 0x73, 0x69, 0x64, 0x20, 0x69, 0x73, 0x20, 0x73, 0x65, 0x74, 0x20, 0x62, - 0x79, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x6d, 0x61, 0x72, 0x74, 0x20, 0x63, 0x6f, 0x6e, 0x74, - 0x72, 0x61, 0x63, 0x74, 0x2c, 0x0a, 0x20, 0x62, 0x75, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6f, - 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x5f, 0x6e, 0x73, 0x20, 0x69, 0x73, 0x20, - 0x73, 0x65, 0x74, 0x20, 0x62, 0x79, 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x75, 0x62, 0x6c, 0x69, - 0x73, 0x68, 0x69, 0x6e, 0x67, 0x20, 0x6e, 0x6f, 0x64, 0x65, 0x0a, 0x0a, 0x0a, 0x0a, 0x03, 0x04, - 0x04, 0x01, 0x12, 0x03, 0x2b, 0x08, 0x22, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x04, 0x02, 0x00, 0x12, - 0x03, 0x2c, 0x02, 0x20, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x02, 0x00, 0x05, 0x12, 0x03, 0x2c, - 0x02, 0x08, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x02, 0x00, 0x01, 0x12, 0x03, 0x2c, 0x09, 0x1b, - 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x02, 0x00, 0x03, 0x12, 0x03, 0x2c, 0x1e, 0x1f, 0x0a, 0x0b, - 0x0a, 0x04, 0x04, 0x04, 0x02, 0x01, 0x12, 0x03, 0x2d, 0x02, 0x24, 0x0a, 0x0c, 0x0a, 0x05, 0x04, - 0x04, 0x02, 0x01, 0x05, 0x12, 0x03, 0x2d, 0x02, 0x08, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x02, - 0x01, 0x01, 0x12, 0x03, 0x2d, 0x09, 0x1f, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x02, 0x01, 0x03, - 0x12, 0x03, 0x2d, 0x22, 0x23, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x04, 0x02, 0x02, 0x12, 0x03, 0x2e, - 0x02, 0x1a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x02, 0x02, 0x05, 0x12, 0x03, 0x2e, 0x02, 0x07, - 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x02, 0x02, 0x01, 0x12, 0x03, 0x2e, 0x08, 0x15, 0x0a, 0x0c, - 0x0a, 0x05, 0x04, 0x04, 0x02, 0x02, 0x03, 0x12, 0x03, 0x2e, 0x18, 0x19, 0x0a, 0x0b, 0x0a, 0x04, - 0x04, 0x04, 0x02, 0x03, 0x12, 0x03, 0x2f, 0x02, 0x23, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x02, - 0x03, 0x06, 0x12, 0x03, 0x2f, 0x02, 0x0f, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x02, 0x03, 0x01, - 0x12, 0x03, 0x2f, 0x10, 0x1e, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x02, 0x03, 0x03, 0x12, 0x03, - 0x2f, 0x21, 0x22, 0x0a, 0x43, 0x0a, 0x02, 0x04, 0x05, 0x12, 0x04, 0x33, 0x00, 0x36, 0x01, 0x1a, - 0x37, 0x20, 0x41, 0x6e, 0x20, 0x61, 0x6c, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x74, 0x69, 0x76, 0x65, - 0x20, 0x74, 0x6f, 0x20, 0x61, 0x20, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x20, - 0x66, 0x6f, 0x72, 0x20, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x20, 0x70, - 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x73, 0x0a, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x05, 0x01, 0x12, - 0x03, 0x33, 0x08, 0x17, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x05, 0x02, 0x00, 0x12, 0x03, 0x34, 0x02, - 0x1a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x05, 0x02, 0x00, 0x05, 0x12, 0x03, 0x34, 0x02, 0x08, 0x0a, - 0x0c, 0x0a, 0x05, 0x04, 0x05, 0x02, 0x00, 0x01, 0x12, 0x03, 0x34, 0x09, 0x15, 0x0a, 0x0c, 0x0a, - 0x05, 0x04, 0x05, 0x02, 0x00, 0x03, 0x12, 0x03, 0x34, 0x18, 0x19, 0x0a, 0x0b, 0x0a, 0x04, 0x04, - 0x05, 0x02, 0x01, 0x12, 0x03, 0x35, 0x02, 0x1f, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x05, 0x02, 0x01, - 0x05, 0x12, 0x03, 0x35, 0x02, 0x08, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x05, 0x02, 0x01, 0x01, 0x12, - 0x03, 0x35, 0x09, 0x1a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x05, 0x02, 0x01, 0x03, 0x12, 0x03, 0x35, - 0x1d, 0x1e, 0x0a, 0x28, 0x0a, 0x02, 0x04, 0x06, 0x12, 0x04, 0x39, 0x00, 0x3f, 0x01, 0x1a, 0x1c, - 0x20, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x20, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x74, - 0x6f, 0x72, 0x20, 0x65, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x0a, 0x0a, 0x0a, 0x0a, 0x03, - 0x04, 0x06, 0x01, 0x12, 0x03, 0x39, 0x08, 0x1a, 0x0a, 0x22, 0x0a, 0x04, 0x04, 0x06, 0x02, 0x00, - 0x12, 0x03, 0x3a, 0x02, 0x29, 0x22, 0x15, 0x20, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, - 0x20, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, - 0x04, 0x06, 0x02, 0x00, 0x05, 0x12, 0x03, 0x3a, 0x02, 0x07, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x06, - 0x02, 0x00, 0x01, 0x12, 0x03, 0x3a, 0x08, 0x24, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x06, 0x02, 0x00, - 0x03, 0x12, 0x03, 0x3a, 0x27, 0x28, 0x0a, 0x0c, 0x0a, 0x04, 0x04, 0x06, 0x08, 0x00, 0x12, 0x04, - 0x3b, 0x02, 0x3e, 0x03, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x06, 0x08, 0x00, 0x01, 0x12, 0x03, 0x3b, - 0x08, 0x0d, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x06, 0x02, 0x01, 0x12, 0x03, 0x3c, 0x04, 0x52, 0x0a, - 0x0c, 0x0a, 0x05, 0x04, 0x06, 0x02, 0x01, 0x06, 0x12, 0x03, 0x3c, 0x04, 0x38, 0x0a, 0x0c, 0x0a, - 0x05, 0x04, 0x06, 0x02, 0x01, 0x01, 0x12, 0x03, 0x3c, 0x39, 0x4d, 0x0a, 0x0c, 0x0a, 0x05, 0x04, - 0x06, 0x02, 0x01, 0x03, 0x12, 0x03, 0x3c, 0x50, 0x51, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x06, 0x02, - 0x02, 0x12, 0x03, 0x3d, 0x04, 0x29, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x06, 0x02, 0x02, 0x06, 0x12, - 0x03, 0x3d, 0x04, 0x13, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x06, 0x02, 0x02, 0x01, 0x12, 0x03, 0x3d, - 0x14, 0x24, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x06, 0x02, 0x02, 0x03, 0x12, 0x03, 0x3d, 0x27, 0x28, - 0x0a, 0x1f, 0x0a, 0x02, 0x05, 0x00, 0x12, 0x04, 0x42, 0x00, 0x48, 0x01, 0x1a, 0x13, 0x20, 0x4d, - 0x69, 0x73, 0x62, 0x65, 0x68, 0x61, 0x76, 0x69, 0x6f, 0x72, 0x20, 0x74, 0x79, 0x70, 0x65, 0x73, - 0x0a, 0x0a, 0x0a, 0x0a, 0x03, 0x05, 0x00, 0x01, 0x12, 0x03, 0x42, 0x05, 0x10, 0x0a, 0x0b, 0x0a, - 0x04, 0x05, 0x00, 0x02, 0x00, 0x12, 0x03, 0x43, 0x02, 0x1e, 0x0a, 0x0c, 0x0a, 0x05, 0x05, 0x00, - 0x02, 0x00, 0x01, 0x12, 0x03, 0x43, 0x02, 0x19, 0x0a, 0x0c, 0x0a, 0x05, 0x05, 0x00, 0x02, 0x00, - 0x02, 0x12, 0x03, 0x43, 0x1c, 0x1d, 0x0a, 0x0b, 0x0a, 0x04, 0x05, 0x00, 0x02, 0x01, 0x12, 0x03, - 0x44, 0x02, 0x23, 0x0a, 0x0c, 0x0a, 0x05, 0x05, 0x00, 0x02, 0x01, 0x01, 0x12, 0x03, 0x44, 0x02, - 0x1e, 0x0a, 0x0c, 0x0a, 0x05, 0x05, 0x00, 0x02, 0x01, 0x02, 0x12, 0x03, 0x44, 0x21, 0x22, 0x0a, - 0x0b, 0x0a, 0x04, 0x05, 0x00, 0x02, 0x02, 0x12, 0x03, 0x45, 0x02, 0x2e, 0x0a, 0x0c, 0x0a, 0x05, - 0x05, 0x00, 0x02, 0x02, 0x01, 0x12, 0x03, 0x45, 0x02, 0x29, 0x0a, 0x0c, 0x0a, 0x05, 0x05, 0x00, - 0x02, 0x02, 0x02, 0x12, 0x03, 0x45, 0x2c, 0x2d, 0x0a, 0x0b, 0x0a, 0x04, 0x05, 0x00, 0x02, 0x03, - 0x12, 0x03, 0x46, 0x02, 0x2b, 0x0a, 0x0c, 0x0a, 0x05, 0x05, 0x00, 0x02, 0x03, 0x01, 0x12, 0x03, - 0x46, 0x02, 0x26, 0x0a, 0x0c, 0x0a, 0x05, 0x05, 0x00, 0x02, 0x03, 0x02, 0x12, 0x03, 0x46, 0x29, - 0x2a, 0x0a, 0x0b, 0x0a, 0x04, 0x05, 0x00, 0x02, 0x04, 0x12, 0x03, 0x47, 0x02, 0x2c, 0x0a, 0x0c, - 0x0a, 0x05, 0x05, 0x00, 0x02, 0x04, 0x01, 0x12, 0x03, 0x47, 0x02, 0x27, 0x0a, 0x0c, 0x0a, 0x05, - 0x05, 0x00, 0x02, 0x04, 0x02, 0x12, 0x03, 0x47, 0x2a, 0x2b, 0x0a, 0x4a, 0x0a, 0x02, 0x04, 0x07, - 0x12, 0x04, 0x4b, 0x00, 0x4e, 0x01, 0x1a, 0x3e, 0x20, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x73, - 0x20, 0x6e, 0x6f, 0x64, 0x65, 0x20, 0x6d, 0x69, 0x73, 0x62, 0x65, 0x68, 0x61, 0x76, 0x69, 0x6f, - 0x72, 0x2c, 0x20, 0x73, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x62, - 0x79, 0x20, 0x6e, 0x6f, 0x64, 0x65, 0x73, 0x20, 0x6f, 0x72, 0x20, 0x62, 0x79, 0x20, 0x63, 0x6c, - 0x69, 0x65, 0x6e, 0x74, 0x73, 0x0a, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x07, 0x01, 0x12, 0x03, 0x4b, - 0x08, 0x19, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x07, 0x02, 0x00, 0x12, 0x03, 0x4c, 0x02, 0x17, 0x0a, - 0x0c, 0x0a, 0x05, 0x04, 0x07, 0x02, 0x00, 0x06, 0x12, 0x03, 0x4c, 0x02, 0x0d, 0x0a, 0x0c, 0x0a, - 0x05, 0x04, 0x07, 0x02, 0x00, 0x01, 0x12, 0x03, 0x4c, 0x0e, 0x12, 0x0a, 0x0c, 0x0a, 0x05, 0x04, - 0x07, 0x02, 0x00, 0x03, 0x12, 0x03, 0x4c, 0x15, 0x16, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x07, 0x02, - 0x01, 0x12, 0x03, 0x4d, 0x02, 0x2c, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x07, 0x02, 0x01, 0x04, 0x12, - 0x03, 0x4d, 0x02, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x07, 0x02, 0x01, 0x06, 0x12, 0x03, 0x4d, - 0x0b, 0x1d, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x07, 0x02, 0x01, 0x01, 0x12, 0x03, 0x4d, 0x1e, 0x27, - 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x07, 0x02, 0x01, 0x03, 0x12, 0x03, 0x4d, 0x2a, 0x2b, 0x0a, 0x4a, - 0x0a, 0x02, 0x04, 0x08, 0x12, 0x04, 0x51, 0x00, 0x59, 0x01, 0x1a, 0x3e, 0x20, 0x51, 0x75, 0x65, - 0x72, 0x79, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x65, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x73, - 0x2c, 0x20, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x20, 0x62, 0x79, 0x20, 0x71, 0x75, 0x65, 0x72, - 0x79, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x20, - 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x73, 0x0a, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x08, - 0x01, 0x12, 0x03, 0x51, 0x08, 0x16, 0x0a, 0x0c, 0x0a, 0x04, 0x04, 0x08, 0x08, 0x00, 0x12, 0x04, - 0x52, 0x02, 0x57, 0x03, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x08, 0x08, 0x00, 0x01, 0x12, 0x03, 0x52, - 0x08, 0x0e, 0x0a, 0x1d, 0x0a, 0x04, 0x04, 0x08, 0x02, 0x00, 0x12, 0x03, 0x54, 0x04, 0x14, 0x1a, - 0x10, 0x20, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x20, 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, - 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x08, 0x02, 0x00, 0x05, 0x12, 0x03, 0x54, 0x04, 0x09, 0x0a, - 0x0c, 0x0a, 0x05, 0x04, 0x08, 0x02, 0x00, 0x01, 0x12, 0x03, 0x54, 0x0a, 0x0f, 0x0a, 0x0c, 0x0a, - 0x05, 0x04, 0x08, 0x02, 0x00, 0x03, 0x12, 0x03, 0x54, 0x12, 0x13, 0x0a, 0x1b, 0x0a, 0x04, 0x04, - 0x08, 0x02, 0x01, 0x12, 0x03, 0x56, 0x04, 0x22, 0x1a, 0x0e, 0x20, 0x4e, 0x6f, 0x64, 0x65, 0x20, - 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x08, 0x02, 0x01, - 0x05, 0x12, 0x03, 0x56, 0x04, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x08, 0x02, 0x01, 0x01, 0x12, - 0x03, 0x56, 0x0b, 0x1d, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x08, 0x02, 0x01, 0x03, 0x12, 0x03, 0x56, - 0x20, 0x21, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x08, 0x02, 0x02, 0x12, 0x03, 0x58, 0x02, 0x1c, 0x0a, - 0x0c, 0x0a, 0x05, 0x04, 0x08, 0x02, 0x02, 0x06, 0x12, 0x03, 0x58, 0x02, 0x0d, 0x0a, 0x0c, 0x0a, - 0x05, 0x04, 0x08, 0x02, 0x02, 0x01, 0x12, 0x03, 0x58, 0x0e, 0x17, 0x0a, 0x0c, 0x0a, 0x05, 0x04, - 0x08, 0x02, 0x02, 0x03, 0x12, 0x03, 0x58, 0x1a, 0x1b, 0x0a, 0x2a, 0x0a, 0x02, 0x04, 0x09, 0x12, - 0x04, 0x5c, 0x00, 0x62, 0x01, 0x1a, 0x1e, 0x20, 0x42, 0x61, 0x74, 0x63, 0x68, 0x20, 0x73, 0x75, - 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x20, 0x74, 0x6f, 0x20, 0x65, 0x6e, 0x76, 0x65, 0x6c, - 0x6f, 0x70, 0x65, 0x73, 0x0a, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x09, 0x01, 0x12, 0x03, 0x5c, 0x08, - 0x26, 0x0a, 0x39, 0x0a, 0x04, 0x04, 0x09, 0x03, 0x00, 0x12, 0x04, 0x5e, 0x02, 0x60, 0x03, 0x1a, - 0x2b, 0x20, 0x53, 0x69, 0x6e, 0x67, 0x6c, 0x65, 0x20, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, - 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x20, 0x66, 0x6f, - 0x72, 0x20, 0x65, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x73, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, - 0x04, 0x09, 0x03, 0x00, 0x01, 0x12, 0x03, 0x5e, 0x0a, 0x23, 0x0a, 0x0d, 0x0a, 0x06, 0x04, 0x09, - 0x03, 0x00, 0x02, 0x00, 0x12, 0x03, 0x5f, 0x04, 0x1d, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x09, 0x03, - 0x00, 0x02, 0x00, 0x06, 0x12, 0x03, 0x5f, 0x04, 0x12, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x09, 0x03, - 0x00, 0x02, 0x00, 0x01, 0x12, 0x03, 0x5f, 0x13, 0x18, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x09, 0x03, - 0x00, 0x02, 0x00, 0x03, 0x12, 0x03, 0x5f, 0x1b, 0x1c, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x09, 0x02, - 0x00, 0x12, 0x03, 0x61, 0x02, 0x32, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x09, 0x02, 0x00, 0x04, 0x12, - 0x03, 0x61, 0x02, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x09, 0x02, 0x00, 0x06, 0x12, 0x03, 0x61, - 0x0b, 0x24, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x09, 0x02, 0x00, 0x01, 0x12, 0x03, 0x61, 0x25, 0x2d, - 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x09, 0x02, 0x00, 0x03, 0x12, 0x03, 0x61, 0x30, 0x31, 0x0a, 0x57, - 0x0a, 0x02, 0x04, 0x0a, 0x12, 0x04, 0x65, 0x00, 0x67, 0x01, 0x1a, 0x4b, 0x20, 0x53, 0x74, 0x72, - 0x65, 0x61, 0x6d, 0x65, 0x64, 0x20, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x20, 0x66, - 0x6f, 0x72, 0x20, 0x62, 0x61, 0x74, 0x63, 0x68, 0x20, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, - 0x62, 0x65, 0x20, 0x2d, 0x20, 0x63, 0x61, 0x6e, 0x20, 0x62, 0x65, 0x20, 0x6d, 0x75, 0x6c, 0x74, - 0x69, 0x70, 0x6c, 0x65, 0x20, 0x65, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x73, 0x20, 0x61, - 0x74, 0x20, 0x6f, 0x6e, 0x63, 0x65, 0x0a, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x0a, 0x01, 0x12, 0x03, - 0x65, 0x08, 0x27, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x0a, 0x02, 0x00, 0x12, 0x03, 0x66, 0x02, 0x2c, - 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x0a, 0x02, 0x00, 0x04, 0x12, 0x03, 0x66, 0x02, 0x0a, 0x0a, 0x0c, - 0x0a, 0x05, 0x04, 0x0a, 0x02, 0x00, 0x06, 0x12, 0x03, 0x66, 0x0b, 0x1d, 0x0a, 0x0c, 0x0a, 0x05, - 0x04, 0x0a, 0x02, 0x00, 0x01, 0x12, 0x03, 0x66, 0x1e, 0x27, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x0a, - 0x02, 0x00, 0x03, 0x12, 0x03, 0x66, 0x2a, 0x2b, 0x0a, 0x25, 0x0a, 0x02, 0x04, 0x0b, 0x12, 0x04, - 0x6a, 0x00, 0x6d, 0x01, 0x1a, 0x19, 0x20, 0x51, 0x75, 0x65, 0x72, 0x79, 0x20, 0x65, 0x6e, 0x76, - 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x73, 0x20, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x0a, 0x0a, - 0x0a, 0x0a, 0x03, 0x04, 0x0b, 0x01, 0x12, 0x03, 0x6a, 0x08, 0x1d, 0x0a, 0x0b, 0x0a, 0x04, 0x04, - 0x0b, 0x02, 0x00, 0x12, 0x03, 0x6b, 0x02, 0x1b, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x0b, 0x02, 0x00, - 0x06, 0x12, 0x03, 0x6b, 0x02, 0x10, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x0b, 0x02, 0x00, 0x01, 0x12, - 0x03, 0x6b, 0x11, 0x16, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x0b, 0x02, 0x00, 0x03, 0x12, 0x03, 0x6b, - 0x19, 0x1a, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x0b, 0x02, 0x01, 0x12, 0x03, 0x6c, 0x02, 0x13, 0x0a, - 0x0c, 0x0a, 0x05, 0x04, 0x0b, 0x02, 0x01, 0x05, 0x12, 0x03, 0x6c, 0x02, 0x08, 0x0a, 0x0c, 0x0a, - 0x05, 0x04, 0x0b, 0x02, 0x01, 0x01, 0x12, 0x03, 0x6c, 0x09, 0x0e, 0x0a, 0x0c, 0x0a, 0x05, 0x04, - 0x0b, 0x02, 0x01, 0x03, 0x12, 0x03, 0x6c, 0x11, 0x12, 0x0a, 0x26, 0x0a, 0x02, 0x04, 0x0c, 0x12, - 0x04, 0x70, 0x00, 0x72, 0x01, 0x1a, 0x1a, 0x20, 0x51, 0x75, 0x65, 0x72, 0x79, 0x20, 0x65, 0x6e, - 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x73, 0x20, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x0a, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x0c, 0x01, 0x12, 0x03, 0x70, 0x08, 0x1e, 0x0a, 0x0b, 0x0a, - 0x04, 0x04, 0x0c, 0x02, 0x00, 0x12, 0x03, 0x71, 0x02, 0x2c, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x0c, - 0x02, 0x00, 0x04, 0x12, 0x03, 0x71, 0x02, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x0c, 0x02, 0x00, - 0x06, 0x12, 0x03, 0x71, 0x0b, 0x1d, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x0c, 0x02, 0x00, 0x01, 0x12, - 0x03, 0x71, 0x1e, 0x27, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x0c, 0x02, 0x00, 0x03, 0x12, 0x03, 0x71, - 0x2a, 0x2b, 0x0a, 0x0a, 0x0a, 0x02, 0x04, 0x0d, 0x12, 0x04, 0x74, 0x00, 0x76, 0x01, 0x0a, 0x0a, - 0x0a, 0x03, 0x04, 0x0d, 0x01, 0x12, 0x03, 0x74, 0x08, 0x1e, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x0d, - 0x02, 0x00, 0x12, 0x03, 0x75, 0x02, 0x23, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x0d, 0x02, 0x00, 0x06, - 0x12, 0x03, 0x75, 0x02, 0x0f, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x0d, 0x02, 0x00, 0x01, 0x12, 0x03, - 0x75, 0x10, 0x1e, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x0d, 0x02, 0x00, 0x03, 0x12, 0x03, 0x75, 0x21, - 0x22, 0x0a, 0x0a, 0x0a, 0x02, 0x04, 0x0e, 0x12, 0x04, 0x78, 0x00, 0x7a, 0x01, 0x0a, 0x0a, 0x0a, - 0x03, 0x04, 0x0e, 0x01, 0x12, 0x03, 0x78, 0x08, 0x1f, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x0e, 0x02, - 0x00, 0x12, 0x03, 0x79, 0x02, 0x2d, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x0e, 0x02, 0x00, 0x06, 0x12, - 0x03, 0x79, 0x02, 0x14, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x0e, 0x02, 0x00, 0x01, 0x12, 0x03, 0x79, - 0x15, 0x28, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x0e, 0x02, 0x00, 0x03, 0x12, 0x03, 0x79, 0x2b, 0x2c, - 0x0a, 0x1e, 0x0a, 0x02, 0x06, 0x00, 0x12, 0x05, 0x7d, 0x00, 0x95, 0x01, 0x01, 0x1a, 0x11, 0x20, - 0x52, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x50, 0x49, 0x0a, - 0x0a, 0x0a, 0x0a, 0x03, 0x06, 0x00, 0x01, 0x12, 0x03, 0x7d, 0x08, 0x16, 0x0a, 0x27, 0x0a, 0x04, - 0x06, 0x00, 0x02, 0x00, 0x12, 0x05, 0x7f, 0x02, 0x84, 0x01, 0x03, 0x1a, 0x18, 0x20, 0x53, 0x75, - 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x20, 0x74, 0x6f, 0x20, 0x65, 0x6e, 0x76, 0x65, 0x6c, - 0x6f, 0x70, 0x65, 0x73, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x06, 0x00, 0x02, 0x00, 0x01, 0x12, 0x03, - 0x7f, 0x06, 0x1d, 0x0a, 0x0c, 0x0a, 0x05, 0x06, 0x00, 0x02, 0x00, 0x02, 0x12, 0x03, 0x7f, 0x1e, - 0x3c, 0x0a, 0x0c, 0x0a, 0x05, 0x06, 0x00, 0x02, 0x00, 0x06, 0x12, 0x03, 0x7f, 0x47, 0x4d, 0x0a, - 0x0c, 0x0a, 0x05, 0x06, 0x00, 0x02, 0x00, 0x03, 0x12, 0x03, 0x7f, 0x4e, 0x6d, 0x0a, 0x0f, 0x0a, - 0x05, 0x06, 0x00, 0x02, 0x00, 0x04, 0x12, 0x06, 0x80, 0x01, 0x04, 0x83, 0x01, 0x06, 0x0a, 0x13, - 0x0a, 0x09, 0x06, 0x00, 0x02, 0x00, 0x04, 0xb0, 0xca, 0xbc, 0x22, 0x12, 0x06, 0x80, 0x01, 0x04, - 0x83, 0x01, 0x06, 0x0a, 0x12, 0x0a, 0x0a, 0x06, 0x00, 0x02, 0x00, 0x04, 0xb0, 0xca, 0xbc, 0x22, - 0x04, 0x12, 0x04, 0x81, 0x01, 0x06, 0x29, 0x0a, 0x12, 0x0a, 0x0a, 0x06, 0x00, 0x02, 0x00, 0x04, - 0xb0, 0xca, 0xbc, 0x22, 0x07, 0x12, 0x04, 0x82, 0x01, 0x06, 0x0f, 0x0a, 0x21, 0x0a, 0x04, 0x06, - 0x00, 0x02, 0x01, 0x12, 0x06, 0x87, 0x01, 0x02, 0x8c, 0x01, 0x03, 0x1a, 0x11, 0x20, 0x51, 0x75, - 0x65, 0x72, 0x79, 0x20, 0x65, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x73, 0x0a, 0x0a, 0x0d, - 0x0a, 0x05, 0x06, 0x00, 0x02, 0x01, 0x01, 0x12, 0x04, 0x87, 0x01, 0x06, 0x14, 0x0a, 0x0d, 0x0a, - 0x05, 0x06, 0x00, 0x02, 0x01, 0x02, 0x12, 0x04, 0x87, 0x01, 0x15, 0x2a, 0x0a, 0x0d, 0x0a, 0x05, - 0x06, 0x00, 0x02, 0x01, 0x03, 0x12, 0x04, 0x87, 0x01, 0x35, 0x4b, 0x0a, 0x0f, 0x0a, 0x05, 0x06, - 0x00, 0x02, 0x01, 0x04, 0x12, 0x06, 0x88, 0x01, 0x04, 0x8b, 0x01, 0x06, 0x0a, 0x13, 0x0a, 0x09, - 0x06, 0x00, 0x02, 0x01, 0x04, 0xb0, 0xca, 0xbc, 0x22, 0x12, 0x06, 0x88, 0x01, 0x04, 0x8b, 0x01, - 0x06, 0x0a, 0x12, 0x0a, 0x0a, 0x06, 0x00, 0x02, 0x01, 0x04, 0xb0, 0xca, 0xbc, 0x22, 0x04, 0x12, - 0x04, 0x89, 0x01, 0x06, 0x25, 0x0a, 0x12, 0x0a, 0x0a, 0x06, 0x00, 0x02, 0x01, 0x04, 0xb0, 0xca, - 0xbc, 0x22, 0x07, 0x12, 0x04, 0x8a, 0x01, 0x06, 0x0f, 0x0a, 0x22, 0x0a, 0x04, 0x06, 0x00, 0x02, - 0x02, 0x12, 0x06, 0x8f, 0x01, 0x02, 0x94, 0x01, 0x03, 0x1a, 0x12, 0x20, 0x50, 0x75, 0x62, 0x6c, - 0x69, 0x73, 0x68, 0x20, 0x65, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x0a, 0x0a, 0x0d, 0x0a, - 0x05, 0x06, 0x00, 0x02, 0x02, 0x01, 0x12, 0x04, 0x8f, 0x01, 0x06, 0x15, 0x0a, 0x0d, 0x0a, 0x05, - 0x06, 0x00, 0x02, 0x02, 0x02, 0x12, 0x04, 0x8f, 0x01, 0x16, 0x2c, 0x0a, 0x0d, 0x0a, 0x05, 0x06, - 0x00, 0x02, 0x02, 0x03, 0x12, 0x04, 0x8f, 0x01, 0x37, 0x4e, 0x0a, 0x0f, 0x0a, 0x05, 0x06, 0x00, - 0x02, 0x02, 0x04, 0x12, 0x06, 0x90, 0x01, 0x04, 0x93, 0x01, 0x06, 0x0a, 0x13, 0x0a, 0x09, 0x06, - 0x00, 0x02, 0x02, 0x04, 0xb0, 0xca, 0xbc, 0x22, 0x12, 0x06, 0x90, 0x01, 0x04, 0x93, 0x01, 0x06, - 0x0a, 0x12, 0x0a, 0x0a, 0x06, 0x00, 0x02, 0x02, 0x04, 0xb0, 0xca, 0xbc, 0x22, 0x04, 0x12, 0x04, - 0x91, 0x01, 0x06, 0x26, 0x0a, 0x12, 0x0a, 0x0a, 0x06, 0x00, 0x02, 0x02, 0x04, 0xb0, 0xca, 0xbc, - 0x22, 0x07, 0x12, 0x04, 0x92, 0x01, 0x06, 0x0f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, + 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x76, 0x34, 0x2e, 0x51, 0x75, 0x65, + 0x72, 0x79, 0x45, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x22, 0x22, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1c, 0x3a, 0x01, 0x2a, 0x22, 0x17, + 0x2f, 0x6d, 0x6c, 0x73, 0x2f, 0x76, 0x32, 0x2f, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2d, 0x65, 0x6e, + 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x73, 0x12, 0x81, 0x01, 0x0a, 0x0f, 0x50, 0x75, 0x62, 0x6c, + 0x69, 0x73, 0x68, 0x45, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x12, 0x23, 0x2e, 0x78, 0x6d, + 0x74, 0x70, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x76, 0x34, 0x2e, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, + 0x68, 0x45, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x24, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x76, 0x34, 0x2e, 0x50, + 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x45, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x23, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1d, 0x3a, 0x01, + 0x2a, 0x22, 0x18, 0x2f, 0x6d, 0x6c, 0x73, 0x2f, 0x76, 0x32, 0x2f, 0x70, 0x75, 0x62, 0x6c, 0x69, + 0x73, 0x68, 0x2d, 0x65, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x12, 0x72, 0x0a, 0x0b, 0x47, + 0x65, 0x74, 0x49, 0x6e, 0x62, 0x6f, 0x78, 0x49, 0x64, 0x73, 0x12, 0x1f, 0x2e, 0x78, 0x6d, 0x74, + 0x70, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x76, 0x34, 0x2e, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x62, 0x6f, + 0x78, 0x49, 0x64, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x78, 0x6d, + 0x74, 0x70, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x76, 0x34, 0x2e, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x62, + 0x6f, 0x78, 0x49, 0x64, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x20, 0x82, + 0xd3, 0xe4, 0x93, 0x02, 0x1a, 0x3a, 0x01, 0x2a, 0x22, 0x15, 0x2f, 0x6d, 0x6c, 0x73, 0x2f, 0x76, + 0x32, 0x2f, 0x67, 0x65, 0x74, 0x2d, 0x69, 0x6e, 0x62, 0x6f, 0x78, 0x2d, 0x69, 0x64, 0x73, 0x42, + 0x9f, 0x01, 0x0a, 0x0f, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x78, 0x6d, 0x74, + 0x70, 0x76, 0x34, 0x42, 0x0f, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x41, 0x70, 0x69, 0x50, + 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x2e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, + 0x6f, 0x6d, 0x2f, 0x78, 0x6d, 0x74, 0x70, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x76, 0x33, + 0x2f, 0x67, 0x6f, 0x2f, 0x78, 0x6d, 0x74, 0x70, 0x76, 0x34, 0x2f, 0x6d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x5f, 0x61, 0x70, 0x69, 0xa2, 0x02, 0x03, 0x58, 0x58, 0x58, 0xaa, 0x02, 0x0b, 0x58, + 0x6d, 0x74, 0x70, 0x2e, 0x58, 0x6d, 0x74, 0x70, 0x76, 0x34, 0xca, 0x02, 0x0b, 0x58, 0x6d, 0x74, + 0x70, 0x5c, 0x58, 0x6d, 0x74, 0x70, 0x76, 0x34, 0xe2, 0x02, 0x17, 0x58, 0x6d, 0x74, 0x70, 0x5c, + 0x58, 0x6d, 0x74, 0x70, 0x76, 0x34, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, + 0x74, 0x61, 0xea, 0x02, 0x0c, 0x58, 0x6d, 0x74, 0x70, 0x3a, 0x3a, 0x58, 0x6d, 0x74, 0x70, 0x76, + 0x34, 0x4a, 0x8b, 0x27, 0x0a, 0x07, 0x12, 0x05, 0x01, 0x00, 0xb1, 0x01, 0x01, 0x0a, 0x23, 0x0a, + 0x01, 0x0c, 0x12, 0x03, 0x01, 0x00, 0x12, 0x1a, 0x19, 0x20, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x20, 0x41, 0x50, 0x49, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x58, 0x4d, 0x54, 0x50, 0x20, 0x56, + 0x34, 0x0a, 0x0a, 0x08, 0x0a, 0x01, 0x02, 0x12, 0x03, 0x03, 0x00, 0x14, 0x0a, 0x09, 0x0a, 0x02, + 0x03, 0x00, 0x12, 0x03, 0x05, 0x00, 0x26, 0x0a, 0x09, 0x0a, 0x02, 0x03, 0x01, 0x12, 0x03, 0x06, + 0x00, 0x31, 0x0a, 0x09, 0x0a, 0x02, 0x03, 0x02, 0x12, 0x03, 0x07, 0x00, 0x2f, 0x0a, 0x09, 0x0a, + 0x02, 0x03, 0x03, 0x12, 0x03, 0x08, 0x00, 0x1e, 0x0a, 0x08, 0x0a, 0x01, 0x08, 0x12, 0x03, 0x0a, + 0x00, 0x45, 0x0a, 0x09, 0x0a, 0x02, 0x08, 0x0b, 0x12, 0x03, 0x0a, 0x00, 0x45, 0x0a, 0xb7, 0x01, + 0x0a, 0x02, 0x04, 0x00, 0x12, 0x04, 0x0e, 0x00, 0x10, 0x01, 0x1a, 0xaa, 0x01, 0x20, 0x54, 0x68, + 0x65, 0x20, 0x6c, 0x61, 0x73, 0x74, 0x20, 0x73, 0x65, 0x65, 0x6e, 0x20, 0x65, 0x6e, 0x74, 0x72, + 0x79, 0x20, 0x70, 0x65, 0x72, 0x20, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, + 0x2e, 0x20, 0x4f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x73, 0x20, 0x74, 0x68, + 0x61, 0x74, 0x20, 0x68, 0x61, 0x76, 0x65, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x62, 0x65, 0x65, 0x6e, + 0x20, 0x73, 0x65, 0x65, 0x6e, 0x20, 0x61, 0x72, 0x65, 0x20, 0x6f, 0x6d, 0x69, 0x74, 0x74, 0x65, + 0x64, 0x2e, 0x0a, 0x20, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x20, 0x4d, 0x55, 0x53, 0x54, + 0x20, 0x62, 0x65, 0x20, 0x73, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x20, 0x61, 0x73, + 0x63, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x2c, 0x20, 0x73, + 0x6f, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x73, 0x6d, 0x61, 0x6c, 0x6c, 0x65, 0x72, 0x20, 0x6e, + 0x6f, 0x64, 0x65, 0x20, 0x49, 0x44, 0x27, 0x73, 0x20, 0x61, 0x70, 0x70, 0x65, 0x61, 0x72, 0x20, + 0x66, 0x69, 0x72, 0x73, 0x74, 0x2e, 0x0a, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x00, 0x01, 0x12, 0x03, + 0x0e, 0x08, 0x13, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x00, 0x02, 0x00, 0x12, 0x03, 0x0f, 0x02, 0x31, + 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x00, 0x06, 0x12, 0x03, 0x0f, 0x02, 0x15, 0x0a, 0x0c, + 0x0a, 0x05, 0x04, 0x00, 0x02, 0x00, 0x01, 0x12, 0x03, 0x0f, 0x16, 0x2c, 0x0a, 0x0c, 0x0a, 0x05, + 0x04, 0x00, 0x02, 0x00, 0x03, 0x12, 0x03, 0x0f, 0x2f, 0x30, 0x0a, 0x53, 0x0a, 0x02, 0x04, 0x01, + 0x12, 0x04, 0x13, 0x00, 0x17, 0x01, 0x1a, 0x47, 0x20, 0x44, 0x61, 0x74, 0x61, 0x20, 0x76, 0x69, + 0x73, 0x69, 0x62, 0x6c, 0x65, 0x20, 0x74, 0x6f, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x72, + 0x76, 0x65, 0x72, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x68, 0x61, 0x73, 0x20, 0x62, 0x65, 0x65, + 0x6e, 0x20, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x20, + 0x62, 0x79, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x2e, 0x0a, 0x0a, + 0x0a, 0x0a, 0x03, 0x04, 0x01, 0x01, 0x12, 0x03, 0x13, 0x08, 0x19, 0x0a, 0x0b, 0x0a, 0x04, 0x04, + 0x01, 0x02, 0x00, 0x12, 0x03, 0x14, 0x02, 0x1f, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x00, + 0x05, 0x12, 0x03, 0x14, 0x02, 0x08, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x00, 0x01, 0x12, + 0x03, 0x14, 0x09, 0x1a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x00, 0x03, 0x12, 0x03, 0x14, + 0x1d, 0x1e, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x01, 0x02, 0x01, 0x12, 0x03, 0x15, 0x02, 0x19, 0x0a, + 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x01, 0x05, 0x12, 0x03, 0x15, 0x02, 0x07, 0x0a, 0x0c, 0x0a, + 0x05, 0x04, 0x01, 0x02, 0x01, 0x01, 0x12, 0x03, 0x15, 0x08, 0x14, 0x0a, 0x0c, 0x0a, 0x05, 0x04, + 0x01, 0x02, 0x01, 0x03, 0x12, 0x03, 0x15, 0x17, 0x18, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x01, 0x02, + 0x02, 0x12, 0x03, 0x16, 0x02, 0x1c, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x02, 0x06, 0x12, + 0x03, 0x16, 0x02, 0x0d, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x02, 0x01, 0x12, 0x03, 0x16, + 0x0e, 0x17, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x02, 0x03, 0x12, 0x03, 0x16, 0x1a, 0x1b, + 0x0a, 0x0a, 0x0a, 0x02, 0x04, 0x02, 0x12, 0x04, 0x19, 0x00, 0x21, 0x01, 0x0a, 0x0a, 0x0a, 0x03, + 0x04, 0x02, 0x01, 0x12, 0x03, 0x19, 0x08, 0x16, 0x0a, 0x0c, 0x0a, 0x04, 0x04, 0x02, 0x08, 0x00, + 0x12, 0x04, 0x1a, 0x02, 0x1f, 0x03, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x08, 0x00, 0x01, 0x12, + 0x03, 0x1a, 0x08, 0x0f, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x02, 0x02, 0x00, 0x12, 0x03, 0x1b, 0x04, + 0x38, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x00, 0x06, 0x12, 0x03, 0x1b, 0x04, 0x25, 0x0a, + 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x00, 0x01, 0x12, 0x03, 0x1b, 0x26, 0x33, 0x0a, 0x0c, 0x0a, + 0x05, 0x04, 0x02, 0x02, 0x00, 0x03, 0x12, 0x03, 0x1b, 0x36, 0x37, 0x0a, 0x0b, 0x0a, 0x04, 0x04, + 0x02, 0x02, 0x01, 0x12, 0x03, 0x1c, 0x04, 0x3c, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x01, + 0x06, 0x12, 0x03, 0x1c, 0x04, 0x27, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x01, 0x01, 0x12, + 0x03, 0x1c, 0x28, 0x37, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x01, 0x03, 0x12, 0x03, 0x1c, + 0x3a, 0x3b, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x02, 0x02, 0x02, 0x12, 0x03, 0x1d, 0x04, 0x42, 0x0a, + 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x02, 0x06, 0x12, 0x03, 0x1d, 0x04, 0x2d, 0x0a, 0x0c, 0x0a, + 0x05, 0x04, 0x02, 0x02, 0x02, 0x01, 0x12, 0x03, 0x1d, 0x2e, 0x3d, 0x0a, 0x0c, 0x0a, 0x05, 0x04, + 0x02, 0x02, 0x02, 0x03, 0x12, 0x03, 0x1d, 0x40, 0x41, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x02, 0x02, + 0x03, 0x12, 0x03, 0x1e, 0x04, 0x43, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x03, 0x06, 0x12, + 0x03, 0x1e, 0x04, 0x2b, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x03, 0x01, 0x12, 0x03, 0x1e, + 0x2c, 0x3e, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x03, 0x03, 0x12, 0x03, 0x1e, 0x41, 0x42, + 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x02, 0x02, 0x04, 0x12, 0x03, 0x20, 0x02, 0x1c, 0x0a, 0x0c, 0x0a, + 0x05, 0x04, 0x02, 0x02, 0x04, 0x06, 0x12, 0x03, 0x20, 0x02, 0x13, 0x0a, 0x0c, 0x0a, 0x05, 0x04, + 0x02, 0x02, 0x04, 0x01, 0x12, 0x03, 0x20, 0x14, 0x17, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, + 0x04, 0x03, 0x12, 0x03, 0x20, 0x1a, 0x1b, 0x0a, 0x38, 0x0a, 0x02, 0x04, 0x03, 0x12, 0x04, 0x24, + 0x00, 0x27, 0x01, 0x1a, 0x2c, 0x20, 0x57, 0x72, 0x61, 0x70, 0x73, 0x20, 0x63, 0x6c, 0x69, 0x65, + 0x6e, 0x74, 0x20, 0x65, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x20, 0x77, 0x69, 0x74, 0x68, + 0x20, 0x70, 0x61, 0x79, 0x65, 0x72, 0x20, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, + 0x0a, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x03, 0x01, 0x12, 0x03, 0x24, 0x08, 0x15, 0x0a, 0x22, 0x0a, + 0x04, 0x04, 0x03, 0x02, 0x00, 0x12, 0x03, 0x25, 0x02, 0x25, 0x22, 0x15, 0x20, 0x50, 0x72, 0x6f, + 0x74, 0x6f, 0x62, 0x75, 0x66, 0x20, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x64, + 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, 0x00, 0x05, 0x12, 0x03, 0x25, 0x02, 0x07, 0x0a, + 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, 0x00, 0x01, 0x12, 0x03, 0x25, 0x08, 0x20, 0x0a, 0x0c, 0x0a, + 0x05, 0x04, 0x03, 0x02, 0x00, 0x03, 0x12, 0x03, 0x25, 0x23, 0x24, 0x0a, 0x0b, 0x0a, 0x04, 0x04, + 0x03, 0x02, 0x01, 0x12, 0x03, 0x26, 0x02, 0x4b, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, 0x01, + 0x06, 0x12, 0x03, 0x26, 0x02, 0x36, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, 0x01, 0x01, 0x12, + 0x03, 0x26, 0x37, 0x46, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, 0x01, 0x03, 0x12, 0x03, 0x26, + 0x49, 0x4a, 0x0a, 0x8e, 0x01, 0x0a, 0x02, 0x04, 0x04, 0x12, 0x04, 0x2b, 0x00, 0x30, 0x01, 0x1a, + 0x81, 0x01, 0x20, 0x46, 0x6f, 0x72, 0x20, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x63, 0x68, 0x61, 0x69, + 0x6e, 0x20, 0x65, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x73, 0x2c, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x5f, 0x73, 0x69, 0x64, 0x20, + 0x69, 0x73, 0x20, 0x73, 0x65, 0x74, 0x20, 0x62, 0x79, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x6d, + 0x61, 0x72, 0x74, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x2c, 0x0a, 0x20, 0x62, + 0x75, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x6f, + 0x72, 0x5f, 0x6e, 0x73, 0x20, 0x69, 0x73, 0x20, 0x73, 0x65, 0x74, 0x20, 0x62, 0x79, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x69, 0x6e, 0x67, 0x20, 0x6e, 0x6f, + 0x64, 0x65, 0x0a, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x04, 0x01, 0x12, 0x03, 0x2b, 0x08, 0x22, 0x0a, + 0x0b, 0x0a, 0x04, 0x04, 0x04, 0x02, 0x00, 0x12, 0x03, 0x2c, 0x02, 0x20, 0x0a, 0x0c, 0x0a, 0x05, + 0x04, 0x04, 0x02, 0x00, 0x05, 0x12, 0x03, 0x2c, 0x02, 0x08, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, + 0x02, 0x00, 0x01, 0x12, 0x03, 0x2c, 0x09, 0x1b, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x02, 0x00, + 0x03, 0x12, 0x03, 0x2c, 0x1e, 0x1f, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x04, 0x02, 0x01, 0x12, 0x03, + 0x2d, 0x02, 0x24, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x02, 0x01, 0x05, 0x12, 0x03, 0x2d, 0x02, + 0x08, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x02, 0x01, 0x01, 0x12, 0x03, 0x2d, 0x09, 0x1f, 0x0a, + 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x02, 0x01, 0x03, 0x12, 0x03, 0x2d, 0x22, 0x23, 0x0a, 0x0b, 0x0a, + 0x04, 0x04, 0x04, 0x02, 0x02, 0x12, 0x03, 0x2e, 0x02, 0x1a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, + 0x02, 0x02, 0x05, 0x12, 0x03, 0x2e, 0x02, 0x07, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x02, 0x02, + 0x01, 0x12, 0x03, 0x2e, 0x08, 0x15, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x02, 0x02, 0x03, 0x12, + 0x03, 0x2e, 0x18, 0x19, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x04, 0x02, 0x03, 0x12, 0x03, 0x2f, 0x02, + 0x23, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x02, 0x03, 0x06, 0x12, 0x03, 0x2f, 0x02, 0x0f, 0x0a, + 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x02, 0x03, 0x01, 0x12, 0x03, 0x2f, 0x10, 0x1e, 0x0a, 0x0c, 0x0a, + 0x05, 0x04, 0x04, 0x02, 0x03, 0x03, 0x12, 0x03, 0x2f, 0x21, 0x22, 0x0a, 0x43, 0x0a, 0x02, 0x04, + 0x05, 0x12, 0x04, 0x33, 0x00, 0x36, 0x01, 0x1a, 0x37, 0x20, 0x41, 0x6e, 0x20, 0x61, 0x6c, 0x74, + 0x65, 0x72, 0x6e, 0x61, 0x74, 0x69, 0x76, 0x65, 0x20, 0x74, 0x6f, 0x20, 0x61, 0x20, 0x73, 0x69, + 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x62, 0x6c, 0x6f, 0x63, + 0x6b, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x20, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x73, 0x0a, + 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x05, 0x01, 0x12, 0x03, 0x33, 0x08, 0x17, 0x0a, 0x0b, 0x0a, 0x04, + 0x04, 0x05, 0x02, 0x00, 0x12, 0x03, 0x34, 0x02, 0x1a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x05, 0x02, + 0x00, 0x05, 0x12, 0x03, 0x34, 0x02, 0x08, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x05, 0x02, 0x00, 0x01, + 0x12, 0x03, 0x34, 0x09, 0x15, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x05, 0x02, 0x00, 0x03, 0x12, 0x03, + 0x34, 0x18, 0x19, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x05, 0x02, 0x01, 0x12, 0x03, 0x35, 0x02, 0x1f, + 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x05, 0x02, 0x01, 0x05, 0x12, 0x03, 0x35, 0x02, 0x08, 0x0a, 0x0c, + 0x0a, 0x05, 0x04, 0x05, 0x02, 0x01, 0x01, 0x12, 0x03, 0x35, 0x09, 0x1a, 0x0a, 0x0c, 0x0a, 0x05, + 0x04, 0x05, 0x02, 0x01, 0x03, 0x12, 0x03, 0x35, 0x1d, 0x1e, 0x0a, 0x28, 0x0a, 0x02, 0x04, 0x06, + 0x12, 0x04, 0x39, 0x00, 0x3f, 0x01, 0x1a, 0x1c, 0x20, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x20, + 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x20, 0x65, 0x6e, 0x76, 0x65, 0x6c, + 0x6f, 0x70, 0x65, 0x0a, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x06, 0x01, 0x12, 0x03, 0x39, 0x08, 0x1a, + 0x0a, 0x22, 0x0a, 0x04, 0x04, 0x06, 0x02, 0x00, 0x12, 0x03, 0x3a, 0x02, 0x29, 0x22, 0x15, 0x20, + 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x20, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, + 0x7a, 0x65, 0x64, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x06, 0x02, 0x00, 0x05, 0x12, 0x03, 0x3a, + 0x02, 0x07, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x06, 0x02, 0x00, 0x01, 0x12, 0x03, 0x3a, 0x08, 0x24, + 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x06, 0x02, 0x00, 0x03, 0x12, 0x03, 0x3a, 0x27, 0x28, 0x0a, 0x0c, + 0x0a, 0x04, 0x04, 0x06, 0x08, 0x00, 0x12, 0x04, 0x3b, 0x02, 0x3e, 0x03, 0x0a, 0x0c, 0x0a, 0x05, + 0x04, 0x06, 0x08, 0x00, 0x01, 0x12, 0x03, 0x3b, 0x08, 0x0d, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x06, + 0x02, 0x01, 0x12, 0x03, 0x3c, 0x04, 0x52, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x06, 0x02, 0x01, 0x06, + 0x12, 0x03, 0x3c, 0x04, 0x38, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x06, 0x02, 0x01, 0x01, 0x12, 0x03, + 0x3c, 0x39, 0x4d, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x06, 0x02, 0x01, 0x03, 0x12, 0x03, 0x3c, 0x50, + 0x51, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x06, 0x02, 0x02, 0x12, 0x03, 0x3d, 0x04, 0x29, 0x0a, 0x0c, + 0x0a, 0x05, 0x04, 0x06, 0x02, 0x02, 0x06, 0x12, 0x03, 0x3d, 0x04, 0x13, 0x0a, 0x0c, 0x0a, 0x05, + 0x04, 0x06, 0x02, 0x02, 0x01, 0x12, 0x03, 0x3d, 0x14, 0x24, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x06, + 0x02, 0x02, 0x03, 0x12, 0x03, 0x3d, 0x27, 0x28, 0x0a, 0x1f, 0x0a, 0x02, 0x05, 0x00, 0x12, 0x04, + 0x42, 0x00, 0x48, 0x01, 0x1a, 0x13, 0x20, 0x4d, 0x69, 0x73, 0x62, 0x65, 0x68, 0x61, 0x76, 0x69, + 0x6f, 0x72, 0x20, 0x74, 0x79, 0x70, 0x65, 0x73, 0x0a, 0x0a, 0x0a, 0x0a, 0x03, 0x05, 0x00, 0x01, + 0x12, 0x03, 0x42, 0x05, 0x10, 0x0a, 0x0b, 0x0a, 0x04, 0x05, 0x00, 0x02, 0x00, 0x12, 0x03, 0x43, + 0x02, 0x1e, 0x0a, 0x0c, 0x0a, 0x05, 0x05, 0x00, 0x02, 0x00, 0x01, 0x12, 0x03, 0x43, 0x02, 0x19, + 0x0a, 0x0c, 0x0a, 0x05, 0x05, 0x00, 0x02, 0x00, 0x02, 0x12, 0x03, 0x43, 0x1c, 0x1d, 0x0a, 0x0b, + 0x0a, 0x04, 0x05, 0x00, 0x02, 0x01, 0x12, 0x03, 0x44, 0x02, 0x23, 0x0a, 0x0c, 0x0a, 0x05, 0x05, + 0x00, 0x02, 0x01, 0x01, 0x12, 0x03, 0x44, 0x02, 0x1e, 0x0a, 0x0c, 0x0a, 0x05, 0x05, 0x00, 0x02, + 0x01, 0x02, 0x12, 0x03, 0x44, 0x21, 0x22, 0x0a, 0x0b, 0x0a, 0x04, 0x05, 0x00, 0x02, 0x02, 0x12, + 0x03, 0x45, 0x02, 0x2e, 0x0a, 0x0c, 0x0a, 0x05, 0x05, 0x00, 0x02, 0x02, 0x01, 0x12, 0x03, 0x45, + 0x02, 0x29, 0x0a, 0x0c, 0x0a, 0x05, 0x05, 0x00, 0x02, 0x02, 0x02, 0x12, 0x03, 0x45, 0x2c, 0x2d, + 0x0a, 0x0b, 0x0a, 0x04, 0x05, 0x00, 0x02, 0x03, 0x12, 0x03, 0x46, 0x02, 0x2b, 0x0a, 0x0c, 0x0a, + 0x05, 0x05, 0x00, 0x02, 0x03, 0x01, 0x12, 0x03, 0x46, 0x02, 0x26, 0x0a, 0x0c, 0x0a, 0x05, 0x05, + 0x00, 0x02, 0x03, 0x02, 0x12, 0x03, 0x46, 0x29, 0x2a, 0x0a, 0x0b, 0x0a, 0x04, 0x05, 0x00, 0x02, + 0x04, 0x12, 0x03, 0x47, 0x02, 0x2c, 0x0a, 0x0c, 0x0a, 0x05, 0x05, 0x00, 0x02, 0x04, 0x01, 0x12, + 0x03, 0x47, 0x02, 0x27, 0x0a, 0x0c, 0x0a, 0x05, 0x05, 0x00, 0x02, 0x04, 0x02, 0x12, 0x03, 0x47, + 0x2a, 0x2b, 0x0a, 0x4a, 0x0a, 0x02, 0x04, 0x07, 0x12, 0x04, 0x4b, 0x00, 0x4e, 0x01, 0x1a, 0x3e, + 0x20, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x20, 0x6e, 0x6f, 0x64, 0x65, 0x20, 0x6d, 0x69, + 0x73, 0x62, 0x65, 0x68, 0x61, 0x76, 0x69, 0x6f, 0x72, 0x2c, 0x20, 0x73, 0x75, 0x62, 0x6d, 0x69, + 0x74, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x62, 0x79, 0x20, 0x6e, 0x6f, 0x64, 0x65, 0x73, 0x20, + 0x6f, 0x72, 0x20, 0x62, 0x79, 0x20, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x73, 0x0a, 0x0a, 0x0a, + 0x0a, 0x03, 0x04, 0x07, 0x01, 0x12, 0x03, 0x4b, 0x08, 0x19, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x07, + 0x02, 0x00, 0x12, 0x03, 0x4c, 0x02, 0x17, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x07, 0x02, 0x00, 0x06, + 0x12, 0x03, 0x4c, 0x02, 0x0d, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x07, 0x02, 0x00, 0x01, 0x12, 0x03, + 0x4c, 0x0e, 0x12, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x07, 0x02, 0x00, 0x03, 0x12, 0x03, 0x4c, 0x15, + 0x16, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x07, 0x02, 0x01, 0x12, 0x03, 0x4d, 0x02, 0x2c, 0x0a, 0x0c, + 0x0a, 0x05, 0x04, 0x07, 0x02, 0x01, 0x04, 0x12, 0x03, 0x4d, 0x02, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, + 0x04, 0x07, 0x02, 0x01, 0x06, 0x12, 0x03, 0x4d, 0x0b, 0x1d, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x07, + 0x02, 0x01, 0x01, 0x12, 0x03, 0x4d, 0x1e, 0x27, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x07, 0x02, 0x01, + 0x03, 0x12, 0x03, 0x4d, 0x2a, 0x2b, 0x0a, 0x4a, 0x0a, 0x02, 0x04, 0x08, 0x12, 0x04, 0x51, 0x00, + 0x59, 0x01, 0x1a, 0x3e, 0x20, 0x51, 0x75, 0x65, 0x72, 0x79, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x65, + 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x73, 0x2c, 0x20, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, + 0x20, 0x62, 0x79, 0x20, 0x71, 0x75, 0x65, 0x72, 0x79, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x73, 0x75, + 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x20, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, + 0x73, 0x0a, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x08, 0x01, 0x12, 0x03, 0x51, 0x08, 0x16, 0x0a, 0x0c, + 0x0a, 0x04, 0x04, 0x08, 0x08, 0x00, 0x12, 0x04, 0x52, 0x02, 0x57, 0x03, 0x0a, 0x0c, 0x0a, 0x05, + 0x04, 0x08, 0x08, 0x00, 0x01, 0x12, 0x03, 0x52, 0x08, 0x0e, 0x0a, 0x1d, 0x0a, 0x04, 0x04, 0x08, + 0x02, 0x00, 0x12, 0x03, 0x54, 0x04, 0x14, 0x1a, 0x10, 0x20, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, + 0x20, 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x08, 0x02, + 0x00, 0x05, 0x12, 0x03, 0x54, 0x04, 0x09, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x08, 0x02, 0x00, 0x01, + 0x12, 0x03, 0x54, 0x0a, 0x0f, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x08, 0x02, 0x00, 0x03, 0x12, 0x03, + 0x54, 0x12, 0x13, 0x0a, 0x1b, 0x0a, 0x04, 0x04, 0x08, 0x02, 0x01, 0x12, 0x03, 0x56, 0x04, 0x22, + 0x1a, 0x0e, 0x20, 0x4e, 0x6f, 0x64, 0x65, 0x20, 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, 0x0a, + 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x08, 0x02, 0x01, 0x05, 0x12, 0x03, 0x56, 0x04, 0x0a, 0x0a, 0x0c, + 0x0a, 0x05, 0x04, 0x08, 0x02, 0x01, 0x01, 0x12, 0x03, 0x56, 0x0b, 0x1d, 0x0a, 0x0c, 0x0a, 0x05, + 0x04, 0x08, 0x02, 0x01, 0x03, 0x12, 0x03, 0x56, 0x20, 0x21, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x08, + 0x02, 0x02, 0x12, 0x03, 0x58, 0x02, 0x1c, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x08, 0x02, 0x02, 0x06, + 0x12, 0x03, 0x58, 0x02, 0x0d, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x08, 0x02, 0x02, 0x01, 0x12, 0x03, + 0x58, 0x0e, 0x17, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x08, 0x02, 0x02, 0x03, 0x12, 0x03, 0x58, 0x1a, + 0x1b, 0x0a, 0x2a, 0x0a, 0x02, 0x04, 0x09, 0x12, 0x04, 0x5c, 0x00, 0x62, 0x01, 0x1a, 0x1e, 0x20, + 0x42, 0x61, 0x74, 0x63, 0x68, 0x20, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x20, + 0x74, 0x6f, 0x20, 0x65, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x73, 0x0a, 0x0a, 0x0a, 0x0a, + 0x03, 0x04, 0x09, 0x01, 0x12, 0x03, 0x5c, 0x08, 0x26, 0x0a, 0x39, 0x0a, 0x04, 0x04, 0x09, 0x03, + 0x00, 0x12, 0x04, 0x5e, 0x02, 0x60, 0x03, 0x1a, 0x2b, 0x20, 0x53, 0x69, 0x6e, 0x67, 0x6c, 0x65, + 0x20, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x72, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x65, 0x6e, 0x76, 0x65, 0x6c, 0x6f, + 0x70, 0x65, 0x73, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x09, 0x03, 0x00, 0x01, 0x12, 0x03, 0x5e, + 0x0a, 0x23, 0x0a, 0x0d, 0x0a, 0x06, 0x04, 0x09, 0x03, 0x00, 0x02, 0x00, 0x12, 0x03, 0x5f, 0x04, + 0x1d, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x09, 0x03, 0x00, 0x02, 0x00, 0x06, 0x12, 0x03, 0x5f, 0x04, + 0x12, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x09, 0x03, 0x00, 0x02, 0x00, 0x01, 0x12, 0x03, 0x5f, 0x13, + 0x18, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x09, 0x03, 0x00, 0x02, 0x00, 0x03, 0x12, 0x03, 0x5f, 0x1b, + 0x1c, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x09, 0x02, 0x00, 0x12, 0x03, 0x61, 0x02, 0x32, 0x0a, 0x0c, + 0x0a, 0x05, 0x04, 0x09, 0x02, 0x00, 0x04, 0x12, 0x03, 0x61, 0x02, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, + 0x04, 0x09, 0x02, 0x00, 0x06, 0x12, 0x03, 0x61, 0x0b, 0x24, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x09, + 0x02, 0x00, 0x01, 0x12, 0x03, 0x61, 0x25, 0x2d, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x09, 0x02, 0x00, + 0x03, 0x12, 0x03, 0x61, 0x30, 0x31, 0x0a, 0x57, 0x0a, 0x02, 0x04, 0x0a, 0x12, 0x04, 0x65, 0x00, + 0x67, 0x01, 0x1a, 0x4b, 0x20, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x65, 0x64, 0x20, 0x72, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x62, 0x61, 0x74, 0x63, 0x68, + 0x20, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x20, 0x2d, 0x20, 0x63, 0x61, 0x6e, + 0x20, 0x62, 0x65, 0x20, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x20, 0x65, 0x6e, 0x76, + 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x73, 0x20, 0x61, 0x74, 0x20, 0x6f, 0x6e, 0x63, 0x65, 0x0a, 0x0a, + 0x0a, 0x0a, 0x03, 0x04, 0x0a, 0x01, 0x12, 0x03, 0x65, 0x08, 0x27, 0x0a, 0x0b, 0x0a, 0x04, 0x04, + 0x0a, 0x02, 0x00, 0x12, 0x03, 0x66, 0x02, 0x2c, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x0a, 0x02, 0x00, + 0x04, 0x12, 0x03, 0x66, 0x02, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x0a, 0x02, 0x00, 0x06, 0x12, + 0x03, 0x66, 0x0b, 0x1d, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x0a, 0x02, 0x00, 0x01, 0x12, 0x03, 0x66, + 0x1e, 0x27, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x0a, 0x02, 0x00, 0x03, 0x12, 0x03, 0x66, 0x2a, 0x2b, + 0x0a, 0x25, 0x0a, 0x02, 0x04, 0x0b, 0x12, 0x04, 0x6a, 0x00, 0x6d, 0x01, 0x1a, 0x19, 0x20, 0x51, + 0x75, 0x65, 0x72, 0x79, 0x20, 0x65, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x73, 0x20, 0x72, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x0a, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x0b, 0x01, 0x12, 0x03, + 0x6a, 0x08, 0x1d, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x0b, 0x02, 0x00, 0x12, 0x03, 0x6b, 0x02, 0x1b, + 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x0b, 0x02, 0x00, 0x06, 0x12, 0x03, 0x6b, 0x02, 0x10, 0x0a, 0x0c, + 0x0a, 0x05, 0x04, 0x0b, 0x02, 0x00, 0x01, 0x12, 0x03, 0x6b, 0x11, 0x16, 0x0a, 0x0c, 0x0a, 0x05, + 0x04, 0x0b, 0x02, 0x00, 0x03, 0x12, 0x03, 0x6b, 0x19, 0x1a, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x0b, + 0x02, 0x01, 0x12, 0x03, 0x6c, 0x02, 0x13, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x0b, 0x02, 0x01, 0x05, + 0x12, 0x03, 0x6c, 0x02, 0x08, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x0b, 0x02, 0x01, 0x01, 0x12, 0x03, + 0x6c, 0x09, 0x0e, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x0b, 0x02, 0x01, 0x03, 0x12, 0x03, 0x6c, 0x11, + 0x12, 0x0a, 0x26, 0x0a, 0x02, 0x04, 0x0c, 0x12, 0x04, 0x70, 0x00, 0x72, 0x01, 0x1a, 0x1a, 0x20, + 0x51, 0x75, 0x65, 0x72, 0x79, 0x20, 0x65, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x73, 0x20, + 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x0a, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x0c, 0x01, + 0x12, 0x03, 0x70, 0x08, 0x1e, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x0c, 0x02, 0x00, 0x12, 0x03, 0x71, + 0x02, 0x2c, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x0c, 0x02, 0x00, 0x04, 0x12, 0x03, 0x71, 0x02, 0x0a, + 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x0c, 0x02, 0x00, 0x06, 0x12, 0x03, 0x71, 0x0b, 0x1d, 0x0a, 0x0c, + 0x0a, 0x05, 0x04, 0x0c, 0x02, 0x00, 0x01, 0x12, 0x03, 0x71, 0x1e, 0x27, 0x0a, 0x0c, 0x0a, 0x05, + 0x04, 0x0c, 0x02, 0x00, 0x03, 0x12, 0x03, 0x71, 0x2a, 0x2b, 0x0a, 0x0a, 0x0a, 0x02, 0x04, 0x0d, + 0x12, 0x04, 0x74, 0x00, 0x76, 0x01, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x0d, 0x01, 0x12, 0x03, 0x74, + 0x08, 0x1e, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x0d, 0x02, 0x00, 0x12, 0x03, 0x75, 0x02, 0x23, 0x0a, + 0x0c, 0x0a, 0x05, 0x04, 0x0d, 0x02, 0x00, 0x06, 0x12, 0x03, 0x75, 0x02, 0x0f, 0x0a, 0x0c, 0x0a, + 0x05, 0x04, 0x0d, 0x02, 0x00, 0x01, 0x12, 0x03, 0x75, 0x10, 0x1e, 0x0a, 0x0c, 0x0a, 0x05, 0x04, + 0x0d, 0x02, 0x00, 0x03, 0x12, 0x03, 0x75, 0x21, 0x22, 0x0a, 0x0a, 0x0a, 0x02, 0x04, 0x0e, 0x12, + 0x04, 0x78, 0x00, 0x7a, 0x01, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x0e, 0x01, 0x12, 0x03, 0x78, 0x08, + 0x1f, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x0e, 0x02, 0x00, 0x12, 0x03, 0x79, 0x02, 0x2d, 0x0a, 0x0c, + 0x0a, 0x05, 0x04, 0x0e, 0x02, 0x00, 0x06, 0x12, 0x03, 0x79, 0x02, 0x14, 0x0a, 0x0c, 0x0a, 0x05, + 0x04, 0x0e, 0x02, 0x00, 0x01, 0x12, 0x03, 0x79, 0x15, 0x28, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x0e, + 0x02, 0x00, 0x03, 0x12, 0x03, 0x79, 0x2b, 0x2c, 0x0a, 0x43, 0x0a, 0x02, 0x04, 0x0f, 0x12, 0x05, + 0x7d, 0x00, 0x84, 0x01, 0x01, 0x1a, 0x36, 0x20, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x20, + 0x74, 0x6f, 0x20, 0x72, 0x65, 0x74, 0x72, 0x69, 0x65, 0x76, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x58, 0x49, 0x44, 0x73, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x74, 0x68, 0x65, 0x20, 0x67, 0x69, 0x76, + 0x65, 0x6e, 0x20, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x0a, 0x0a, 0x0a, 0x0a, + 0x03, 0x04, 0x0f, 0x01, 0x12, 0x03, 0x7d, 0x08, 0x1a, 0x0a, 0x35, 0x0a, 0x04, 0x04, 0x0f, 0x03, + 0x00, 0x12, 0x05, 0x7f, 0x02, 0x81, 0x01, 0x03, 0x1a, 0x26, 0x20, 0x41, 0x20, 0x73, 0x69, 0x6e, + 0x67, 0x6c, 0x65, 0x20, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x20, 0x66, 0x6f, 0x72, 0x20, + 0x61, 0x20, 0x67, 0x69, 0x76, 0x65, 0x6e, 0x20, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x0a, + 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x0f, 0x03, 0x00, 0x01, 0x12, 0x03, 0x7f, 0x0a, 0x11, 0x0a, 0x0e, + 0x0a, 0x06, 0x04, 0x0f, 0x03, 0x00, 0x02, 0x00, 0x12, 0x04, 0x80, 0x01, 0x04, 0x17, 0x0a, 0x0f, + 0x0a, 0x07, 0x04, 0x0f, 0x03, 0x00, 0x02, 0x00, 0x05, 0x12, 0x04, 0x80, 0x01, 0x04, 0x0a, 0x0a, + 0x0f, 0x0a, 0x07, 0x04, 0x0f, 0x03, 0x00, 0x02, 0x00, 0x01, 0x12, 0x04, 0x80, 0x01, 0x0b, 0x12, + 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x0f, 0x03, 0x00, 0x02, 0x00, 0x03, 0x12, 0x04, 0x80, 0x01, 0x15, + 0x16, 0x0a, 0x0c, 0x0a, 0x04, 0x04, 0x0f, 0x02, 0x00, 0x12, 0x04, 0x83, 0x01, 0x02, 0x20, 0x0a, + 0x0d, 0x0a, 0x05, 0x04, 0x0f, 0x02, 0x00, 0x04, 0x12, 0x04, 0x83, 0x01, 0x02, 0x0a, 0x0a, 0x0d, + 0x0a, 0x05, 0x04, 0x0f, 0x02, 0x00, 0x06, 0x12, 0x04, 0x83, 0x01, 0x0b, 0x12, 0x0a, 0x0d, 0x0a, + 0x05, 0x04, 0x0f, 0x02, 0x00, 0x01, 0x12, 0x04, 0x83, 0x01, 0x13, 0x1b, 0x0a, 0x0d, 0x0a, 0x05, + 0x04, 0x0f, 0x02, 0x00, 0x03, 0x12, 0x04, 0x83, 0x01, 0x1e, 0x1f, 0x0a, 0x42, 0x0a, 0x02, 0x04, + 0x10, 0x12, 0x06, 0x87, 0x01, 0x00, 0x8f, 0x01, 0x01, 0x1a, 0x34, 0x20, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x74, 0x68, 0x65, 0x20, 0x58, 0x49, + 0x44, 0x73, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x74, 0x68, 0x65, 0x20, 0x72, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x65, 0x64, 0x20, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x0a, 0x0a, + 0x0b, 0x0a, 0x03, 0x04, 0x10, 0x01, 0x12, 0x04, 0x87, 0x01, 0x08, 0x1b, 0x0a, 0x37, 0x0a, 0x04, + 0x04, 0x10, 0x03, 0x00, 0x12, 0x06, 0x89, 0x01, 0x02, 0x8c, 0x01, 0x03, 0x1a, 0x27, 0x20, 0x41, + 0x20, 0x73, 0x69, 0x6e, 0x67, 0x6c, 0x65, 0x20, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x20, 0x66, 0x6f, 0x72, 0x20, 0x61, 0x20, 0x67, 0x69, 0x76, 0x65, 0x6e, 0x20, 0x61, 0x64, 0x64, + 0x72, 0x65, 0x73, 0x73, 0x0a, 0x0a, 0x0d, 0x0a, 0x05, 0x04, 0x10, 0x03, 0x00, 0x01, 0x12, 0x04, + 0x89, 0x01, 0x0a, 0x12, 0x0a, 0x0e, 0x0a, 0x06, 0x04, 0x10, 0x03, 0x00, 0x02, 0x00, 0x12, 0x04, + 0x8a, 0x01, 0x04, 0x17, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x10, 0x03, 0x00, 0x02, 0x00, 0x05, 0x12, + 0x04, 0x8a, 0x01, 0x04, 0x0a, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x10, 0x03, 0x00, 0x02, 0x00, 0x01, + 0x12, 0x04, 0x8a, 0x01, 0x0b, 0x12, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x10, 0x03, 0x00, 0x02, 0x00, + 0x03, 0x12, 0x04, 0x8a, 0x01, 0x15, 0x16, 0x0a, 0x0e, 0x0a, 0x06, 0x04, 0x10, 0x03, 0x00, 0x02, + 0x01, 0x12, 0x04, 0x8b, 0x01, 0x04, 0x21, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x10, 0x03, 0x00, 0x02, + 0x01, 0x04, 0x12, 0x04, 0x8b, 0x01, 0x04, 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x10, 0x03, 0x00, + 0x02, 0x01, 0x05, 0x12, 0x04, 0x8b, 0x01, 0x0d, 0x13, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x10, 0x03, + 0x00, 0x02, 0x01, 0x01, 0x12, 0x04, 0x8b, 0x01, 0x14, 0x1c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x10, + 0x03, 0x00, 0x02, 0x01, 0x03, 0x12, 0x04, 0x8b, 0x01, 0x1f, 0x20, 0x0a, 0x0c, 0x0a, 0x04, 0x04, + 0x10, 0x02, 0x00, 0x12, 0x04, 0x8e, 0x01, 0x02, 0x22, 0x0a, 0x0d, 0x0a, 0x05, 0x04, 0x10, 0x02, + 0x00, 0x04, 0x12, 0x04, 0x8e, 0x01, 0x02, 0x0a, 0x0a, 0x0d, 0x0a, 0x05, 0x04, 0x10, 0x02, 0x00, + 0x06, 0x12, 0x04, 0x8e, 0x01, 0x0b, 0x13, 0x0a, 0x0d, 0x0a, 0x05, 0x04, 0x10, 0x02, 0x00, 0x01, + 0x12, 0x04, 0x8e, 0x01, 0x14, 0x1d, 0x0a, 0x0d, 0x0a, 0x05, 0x04, 0x10, 0x02, 0x00, 0x03, 0x12, + 0x04, 0x8e, 0x01, 0x20, 0x21, 0x0a, 0x1f, 0x0a, 0x02, 0x06, 0x00, 0x12, 0x06, 0x92, 0x01, 0x00, + 0xb1, 0x01, 0x01, 0x1a, 0x11, 0x20, 0x52, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x20, 0x41, 0x50, 0x49, 0x0a, 0x0a, 0x0b, 0x0a, 0x03, 0x06, 0x00, 0x01, 0x12, 0x04, 0x92, + 0x01, 0x08, 0x16, 0x0a, 0x28, 0x0a, 0x04, 0x06, 0x00, 0x02, 0x00, 0x12, 0x06, 0x94, 0x01, 0x02, + 0x99, 0x01, 0x03, 0x1a, 0x18, 0x20, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x20, + 0x74, 0x6f, 0x20, 0x65, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x73, 0x0a, 0x0a, 0x0d, 0x0a, + 0x05, 0x06, 0x00, 0x02, 0x00, 0x01, 0x12, 0x04, 0x94, 0x01, 0x06, 0x1d, 0x0a, 0x0d, 0x0a, 0x05, + 0x06, 0x00, 0x02, 0x00, 0x02, 0x12, 0x04, 0x94, 0x01, 0x1e, 0x3c, 0x0a, 0x0d, 0x0a, 0x05, 0x06, + 0x00, 0x02, 0x00, 0x06, 0x12, 0x04, 0x94, 0x01, 0x47, 0x4d, 0x0a, 0x0d, 0x0a, 0x05, 0x06, 0x00, + 0x02, 0x00, 0x03, 0x12, 0x04, 0x94, 0x01, 0x4e, 0x6d, 0x0a, 0x0f, 0x0a, 0x05, 0x06, 0x00, 0x02, + 0x00, 0x04, 0x12, 0x06, 0x95, 0x01, 0x04, 0x98, 0x01, 0x06, 0x0a, 0x13, 0x0a, 0x09, 0x06, 0x00, + 0x02, 0x00, 0x04, 0xb0, 0xca, 0xbc, 0x22, 0x12, 0x06, 0x95, 0x01, 0x04, 0x98, 0x01, 0x06, 0x0a, + 0x12, 0x0a, 0x0a, 0x06, 0x00, 0x02, 0x00, 0x04, 0xb0, 0xca, 0xbc, 0x22, 0x04, 0x12, 0x04, 0x96, + 0x01, 0x06, 0x29, 0x0a, 0x12, 0x0a, 0x0a, 0x06, 0x00, 0x02, 0x00, 0x04, 0xb0, 0xca, 0xbc, 0x22, + 0x07, 0x12, 0x04, 0x97, 0x01, 0x06, 0x0f, 0x0a, 0x21, 0x0a, 0x04, 0x06, 0x00, 0x02, 0x01, 0x12, + 0x06, 0x9c, 0x01, 0x02, 0xa1, 0x01, 0x03, 0x1a, 0x11, 0x20, 0x51, 0x75, 0x65, 0x72, 0x79, 0x20, + 0x65, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x73, 0x0a, 0x0a, 0x0d, 0x0a, 0x05, 0x06, 0x00, + 0x02, 0x01, 0x01, 0x12, 0x04, 0x9c, 0x01, 0x06, 0x14, 0x0a, 0x0d, 0x0a, 0x05, 0x06, 0x00, 0x02, + 0x01, 0x02, 0x12, 0x04, 0x9c, 0x01, 0x15, 0x2a, 0x0a, 0x0d, 0x0a, 0x05, 0x06, 0x00, 0x02, 0x01, + 0x03, 0x12, 0x04, 0x9c, 0x01, 0x35, 0x4b, 0x0a, 0x0f, 0x0a, 0x05, 0x06, 0x00, 0x02, 0x01, 0x04, + 0x12, 0x06, 0x9d, 0x01, 0x04, 0xa0, 0x01, 0x06, 0x0a, 0x13, 0x0a, 0x09, 0x06, 0x00, 0x02, 0x01, + 0x04, 0xb0, 0xca, 0xbc, 0x22, 0x12, 0x06, 0x9d, 0x01, 0x04, 0xa0, 0x01, 0x06, 0x0a, 0x12, 0x0a, + 0x0a, 0x06, 0x00, 0x02, 0x01, 0x04, 0xb0, 0xca, 0xbc, 0x22, 0x04, 0x12, 0x04, 0x9e, 0x01, 0x06, + 0x25, 0x0a, 0x12, 0x0a, 0x0a, 0x06, 0x00, 0x02, 0x01, 0x04, 0xb0, 0xca, 0xbc, 0x22, 0x07, 0x12, + 0x04, 0x9f, 0x01, 0x06, 0x0f, 0x0a, 0x22, 0x0a, 0x04, 0x06, 0x00, 0x02, 0x02, 0x12, 0x06, 0xa4, + 0x01, 0x02, 0xa9, 0x01, 0x03, 0x1a, 0x12, 0x20, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x20, + 0x65, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x0a, 0x0a, 0x0d, 0x0a, 0x05, 0x06, 0x00, 0x02, + 0x02, 0x01, 0x12, 0x04, 0xa4, 0x01, 0x06, 0x15, 0x0a, 0x0d, 0x0a, 0x05, 0x06, 0x00, 0x02, 0x02, + 0x02, 0x12, 0x04, 0xa4, 0x01, 0x16, 0x2c, 0x0a, 0x0d, 0x0a, 0x05, 0x06, 0x00, 0x02, 0x02, 0x03, + 0x12, 0x04, 0xa4, 0x01, 0x37, 0x4e, 0x0a, 0x0f, 0x0a, 0x05, 0x06, 0x00, 0x02, 0x02, 0x04, 0x12, + 0x06, 0xa5, 0x01, 0x04, 0xa8, 0x01, 0x06, 0x0a, 0x13, 0x0a, 0x09, 0x06, 0x00, 0x02, 0x02, 0x04, + 0xb0, 0xca, 0xbc, 0x22, 0x12, 0x06, 0xa5, 0x01, 0x04, 0xa8, 0x01, 0x06, 0x0a, 0x12, 0x0a, 0x0a, + 0x06, 0x00, 0x02, 0x02, 0x04, 0xb0, 0xca, 0xbc, 0x22, 0x04, 0x12, 0x04, 0xa6, 0x01, 0x06, 0x26, + 0x0a, 0x12, 0x0a, 0x0a, 0x06, 0x00, 0x02, 0x02, 0x04, 0xb0, 0xca, 0xbc, 0x22, 0x07, 0x12, 0x04, + 0xa7, 0x01, 0x06, 0x0f, 0x0a, 0x0e, 0x0a, 0x04, 0x06, 0x00, 0x02, 0x03, 0x12, 0x06, 0xab, 0x01, + 0x02, 0xb0, 0x01, 0x03, 0x0a, 0x0d, 0x0a, 0x05, 0x06, 0x00, 0x02, 0x03, 0x01, 0x12, 0x04, 0xab, + 0x01, 0x06, 0x11, 0x0a, 0x0d, 0x0a, 0x05, 0x06, 0x00, 0x02, 0x03, 0x02, 0x12, 0x04, 0xab, 0x01, + 0x12, 0x24, 0x0a, 0x0d, 0x0a, 0x05, 0x06, 0x00, 0x02, 0x03, 0x03, 0x12, 0x04, 0xab, 0x01, 0x2f, + 0x42, 0x0a, 0x0f, 0x0a, 0x05, 0x06, 0x00, 0x02, 0x03, 0x04, 0x12, 0x06, 0xac, 0x01, 0x04, 0xaf, + 0x01, 0x06, 0x0a, 0x13, 0x0a, 0x09, 0x06, 0x00, 0x02, 0x03, 0x04, 0xb0, 0xca, 0xbc, 0x22, 0x12, + 0x06, 0xac, 0x01, 0x04, 0xaf, 0x01, 0x06, 0x0a, 0x12, 0x0a, 0x0a, 0x06, 0x00, 0x02, 0x03, 0x04, + 0xb0, 0xca, 0xbc, 0x22, 0x04, 0x12, 0x04, 0xad, 0x01, 0x06, 0x23, 0x0a, 0x12, 0x0a, 0x0a, 0x06, + 0x00, 0x02, 0x03, 0x04, 0xb0, 0xca, 0xbc, 0x22, 0x07, 0x12, 0x04, 0xae, 0x01, 0x06, 0x0f, 0x62, + 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, ]; include!("xmtp.xmtpv4.serde.rs"); include!("xmtp.xmtpv4.tonic.rs"); diff --git a/xmtp_proto/src/gen/xmtp.xmtpv4.serde.rs b/xmtp_proto/src/gen/xmtp.xmtpv4.serde.rs index 19f6d37bd..5d1b48432 100644 --- a/xmtp_proto/src/gen/xmtp.xmtpv4.serde.rs +++ b/xmtp_proto/src/gen/xmtp.xmtpv4.serde.rs @@ -806,6 +806,388 @@ impl<'de> serde::Deserialize<'de> for EnvelopesQuery { deserializer.deserialize_struct("xmtp.xmtpv4.EnvelopesQuery", FIELDS, GeneratedVisitor) } } +impl serde::Serialize for GetInboxIdsRequest { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + use serde::ser::SerializeStruct; + let mut len = 0; + if !self.requests.is_empty() { + len += 1; + } + let mut struct_ser = serializer.serialize_struct("xmtp.xmtpv4.GetInboxIdsRequest", len)?; + if !self.requests.is_empty() { + struct_ser.serialize_field("requests", &self.requests)?; + } + struct_ser.end() + } +} +impl<'de> serde::Deserialize<'de> for GetInboxIdsRequest { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &[ + "requests", + ]; + + #[allow(clippy::enum_variant_names)] + enum GeneratedField { + Requests, + } + impl<'de> serde::Deserialize<'de> for GeneratedField { + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + struct GeneratedVisitor; + + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = GeneratedField; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(formatter, "expected one of: {:?}", &FIELDS) + } + + #[allow(unused_variables)] + fn visit_str(self, value: &str) -> std::result::Result + where + E: serde::de::Error, + { + match value { + "requests" => Ok(GeneratedField::Requests), + _ => Err(serde::de::Error::unknown_field(value, FIELDS)), + } + } + } + deserializer.deserialize_identifier(GeneratedVisitor) + } + } + struct GeneratedVisitor; + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = GetInboxIdsRequest; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("struct xmtp.xmtpv4.GetInboxIdsRequest") + } + + fn visit_map(self, mut map_: V) -> std::result::Result + where + V: serde::de::MapAccess<'de>, + { + let mut requests__ = None; + while let Some(k) = map_.next_key()? { + match k { + GeneratedField::Requests => { + if requests__.is_some() { + return Err(serde::de::Error::duplicate_field("requests")); + } + requests__ = Some(map_.next_value()?); + } + } + } + Ok(GetInboxIdsRequest { + requests: requests__.unwrap_or_default(), + }) + } + } + deserializer.deserialize_struct("xmtp.xmtpv4.GetInboxIdsRequest", FIELDS, GeneratedVisitor) + } +} +impl serde::Serialize for get_inbox_ids_request::Request { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + use serde::ser::SerializeStruct; + let mut len = 0; + if !self.address.is_empty() { + len += 1; + } + let mut struct_ser = serializer.serialize_struct("xmtp.xmtpv4.GetInboxIdsRequest.Request", len)?; + if !self.address.is_empty() { + struct_ser.serialize_field("address", &self.address)?; + } + struct_ser.end() + } +} +impl<'de> serde::Deserialize<'de> for get_inbox_ids_request::Request { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &[ + "address", + ]; + + #[allow(clippy::enum_variant_names)] + enum GeneratedField { + Address, + } + impl<'de> serde::Deserialize<'de> for GeneratedField { + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + struct GeneratedVisitor; + + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = GeneratedField; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(formatter, "expected one of: {:?}", &FIELDS) + } + + #[allow(unused_variables)] + fn visit_str(self, value: &str) -> std::result::Result + where + E: serde::de::Error, + { + match value { + "address" => Ok(GeneratedField::Address), + _ => Err(serde::de::Error::unknown_field(value, FIELDS)), + } + } + } + deserializer.deserialize_identifier(GeneratedVisitor) + } + } + struct GeneratedVisitor; + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = get_inbox_ids_request::Request; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("struct xmtp.xmtpv4.GetInboxIdsRequest.Request") + } + + fn visit_map(self, mut map_: V) -> std::result::Result + where + V: serde::de::MapAccess<'de>, + { + let mut address__ = None; + while let Some(k) = map_.next_key()? { + match k { + GeneratedField::Address => { + if address__.is_some() { + return Err(serde::de::Error::duplicate_field("address")); + } + address__ = Some(map_.next_value()?); + } + } + } + Ok(get_inbox_ids_request::Request { + address: address__.unwrap_or_default(), + }) + } + } + deserializer.deserialize_struct("xmtp.xmtpv4.GetInboxIdsRequest.Request", FIELDS, GeneratedVisitor) + } +} +impl serde::Serialize for GetInboxIdsResponse { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + use serde::ser::SerializeStruct; + let mut len = 0; + if !self.responses.is_empty() { + len += 1; + } + let mut struct_ser = serializer.serialize_struct("xmtp.xmtpv4.GetInboxIdsResponse", len)?; + if !self.responses.is_empty() { + struct_ser.serialize_field("responses", &self.responses)?; + } + struct_ser.end() + } +} +impl<'de> serde::Deserialize<'de> for GetInboxIdsResponse { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &[ + "responses", + ]; + + #[allow(clippy::enum_variant_names)] + enum GeneratedField { + Responses, + } + impl<'de> serde::Deserialize<'de> for GeneratedField { + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + struct GeneratedVisitor; + + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = GeneratedField; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(formatter, "expected one of: {:?}", &FIELDS) + } + + #[allow(unused_variables)] + fn visit_str(self, value: &str) -> std::result::Result + where + E: serde::de::Error, + { + match value { + "responses" => Ok(GeneratedField::Responses), + _ => Err(serde::de::Error::unknown_field(value, FIELDS)), + } + } + } + deserializer.deserialize_identifier(GeneratedVisitor) + } + } + struct GeneratedVisitor; + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = GetInboxIdsResponse; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("struct xmtp.xmtpv4.GetInboxIdsResponse") + } + + fn visit_map(self, mut map_: V) -> std::result::Result + where + V: serde::de::MapAccess<'de>, + { + let mut responses__ = None; + while let Some(k) = map_.next_key()? { + match k { + GeneratedField::Responses => { + if responses__.is_some() { + return Err(serde::de::Error::duplicate_field("responses")); + } + responses__ = Some(map_.next_value()?); + } + } + } + Ok(GetInboxIdsResponse { + responses: responses__.unwrap_or_default(), + }) + } + } + deserializer.deserialize_struct("xmtp.xmtpv4.GetInboxIdsResponse", FIELDS, GeneratedVisitor) + } +} +impl serde::Serialize for get_inbox_ids_response::Response { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + use serde::ser::SerializeStruct; + let mut len = 0; + if !self.address.is_empty() { + len += 1; + } + if self.inbox_id.is_some() { + len += 1; + } + let mut struct_ser = serializer.serialize_struct("xmtp.xmtpv4.GetInboxIdsResponse.Response", len)?; + if !self.address.is_empty() { + struct_ser.serialize_field("address", &self.address)?; + } + if let Some(v) = self.inbox_id.as_ref() { + struct_ser.serialize_field("inboxId", v)?; + } + struct_ser.end() + } +} +impl<'de> serde::Deserialize<'de> for get_inbox_ids_response::Response { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &[ + "address", + "inbox_id", + "inboxId", + ]; + + #[allow(clippy::enum_variant_names)] + enum GeneratedField { + Address, + InboxId, + } + impl<'de> serde::Deserialize<'de> for GeneratedField { + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + struct GeneratedVisitor; + + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = GeneratedField; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(formatter, "expected one of: {:?}", &FIELDS) + } + + #[allow(unused_variables)] + fn visit_str(self, value: &str) -> std::result::Result + where + E: serde::de::Error, + { + match value { + "address" => Ok(GeneratedField::Address), + "inboxId" | "inbox_id" => Ok(GeneratedField::InboxId), + _ => Err(serde::de::Error::unknown_field(value, FIELDS)), + } + } + } + deserializer.deserialize_identifier(GeneratedVisitor) + } + } + struct GeneratedVisitor; + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = get_inbox_ids_response::Response; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("struct xmtp.xmtpv4.GetInboxIdsResponse.Response") + } + + fn visit_map(self, mut map_: V) -> std::result::Result + where + V: serde::de::MapAccess<'de>, + { + let mut address__ = None; + let mut inbox_id__ = None; + while let Some(k) = map_.next_key()? { + match k { + GeneratedField::Address => { + if address__.is_some() { + return Err(serde::de::Error::duplicate_field("address")); + } + address__ = Some(map_.next_value()?); + } + GeneratedField::InboxId => { + if inbox_id__.is_some() { + return Err(serde::de::Error::duplicate_field("inboxId")); + } + inbox_id__ = map_.next_value()?; + } + } + } + Ok(get_inbox_ids_response::Response { + address: address__.unwrap_or_default(), + inbox_id: inbox_id__, + }) + } + } + deserializer.deserialize_struct("xmtp.xmtpv4.GetInboxIdsResponse.Response", FIELDS, GeneratedVisitor) + } +} impl serde::Serialize for Misbehavior { #[allow(deprecated)] fn serialize(&self, serializer: S) -> std::result::Result diff --git a/xmtp_proto/src/gen/xmtp.xmtpv4.tonic.rs b/xmtp_proto/src/gen/xmtp.xmtpv4.tonic.rs index 3f775e2e1..0686cd6a9 100644 --- a/xmtp_proto/src/gen/xmtp.xmtpv4.tonic.rs +++ b/xmtp_proto/src/gen/xmtp.xmtpv4.tonic.rs @@ -177,6 +177,32 @@ pub mod replication_api_client { ); self.inner.unary(req, path, codec).await } + /// + pub async fn get_inbox_ids( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/xmtp.xmtpv4.ReplicationApi/GetInboxIds", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert(GrpcMethod::new("xmtp.xmtpv4.ReplicationApi", "GetInboxIds")); + self.inner.unary(req, path, codec).await + } } } /// Generated server implementations. @@ -223,6 +249,14 @@ pub mod replication_api_server { tonic::Response, tonic::Status, >; + /// + async fn get_inbox_ids( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; } /** Replication API */ @@ -447,6 +481,51 @@ pub mod replication_api_server { }; Box::pin(fut) } + "/xmtp.xmtpv4.ReplicationApi/GetInboxIds" => { + #[allow(non_camel_case_types)] + struct GetInboxIdsSvc(pub Arc); + impl< + T: ReplicationApi, + > tonic::server::UnaryService + for GetInboxIdsSvc { + type Response = super::GetInboxIdsResponse; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::get_inbox_ids(&inner, request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = GetInboxIdsSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } _ => { Box::pin(async move { Ok( From 4124db0a6fa10c694428e2d320c31f8951ddf8b9 Mon Sep 17 00:00:00 2001 From: Nicholas Molnar <65710+neekolas@users.noreply.github.com> Date: Thu, 26 Sep 2024 11:44:46 -0500 Subject: [PATCH 09/14] Add more methods to send to v4 --- Cargo.lock | 1 + bindings_ffi/Cargo.lock | 1 + bindings_node/Cargo.lock | 1 + xmtp_api_grpc/src/conversions.rs | 15 +++- xmtp_api_grpc/src/grpc_api_helper.rs | 122 ++++++++++++++++++++++----- xmtp_api_grpc/src/identity.rs | 55 ++++++------ xmtp_proto/Cargo.toml | 29 +++++-- xmtp_proto/src/convert.rs | 96 +++++++++++++++------ 8 files changed, 234 insertions(+), 86 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 20c8013b2..54a24aabc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6349,6 +6349,7 @@ dependencies = [ "futures", "hex", "openmls", + "openmls_rust_crypto", "pbjson", "pbjson-types", "prost", diff --git a/bindings_ffi/Cargo.lock b/bindings_ffi/Cargo.lock index 87969f025..ca88132e3 100644 --- a/bindings_ffi/Cargo.lock +++ b/bindings_ffi/Cargo.lock @@ -5795,6 +5795,7 @@ dependencies = [ "futures", "hex", "openmls", + "openmls_rust_crypto", "pbjson", "pbjson-types", "prost", diff --git a/bindings_node/Cargo.lock b/bindings_node/Cargo.lock index a2fc5dd3c..fc33e2af9 100644 --- a/bindings_node/Cargo.lock +++ b/bindings_node/Cargo.lock @@ -5300,6 +5300,7 @@ dependencies = [ "futures", "hex", "openmls", + "openmls_rust_crypto", "pbjson", "pbjson-types", "prost", diff --git a/xmtp_api_grpc/src/conversions.rs b/xmtp_api_grpc/src/conversions.rs index 203675f9f..b1c45115e 100644 --- a/xmtp_api_grpc/src/conversions.rs +++ b/xmtp_api_grpc/src/conversions.rs @@ -1,5 +1,8 @@ use prost::Message; -use xmtp_proto::xmtp::xmtpv4::{ClientEnvelope, PayerEnvelope, PublishEnvelopeRequest}; +use xmtp_proto::xmtp::xmtpv4::{ + ClientEnvelope, OriginatorEnvelope, PayerEnvelope, PublishEnvelopeRequest, + UnsignedOriginatorEnvelope, +}; pub fn wrap_client_envelope(req: ClientEnvelope) -> PublishEnvelopeRequest { let mut buf = vec![]; @@ -12,3 +15,13 @@ pub fn wrap_client_envelope(req: ClientEnvelope) -> PublishEnvelopeRequest { }), } } + +pub fn extract_client_envelope(req: &OriginatorEnvelope) -> ClientEnvelope { + let mut unsigned_bytes = req.unsigned_originator_envelope.as_slice(); + let unsigned_originator = UnsignedOriginatorEnvelope::decode(&mut unsigned_bytes) + .expect("Failed to decode unsigned originator envelope"); + + let payer_envelope = unsigned_originator.payer_envelope.unwrap(); + let mut payer_bytes = payer_envelope.unsigned_client_envelope.as_slice(); + ClientEnvelope::decode(&mut payer_bytes).expect("Failed to decode client envelope") +} diff --git a/xmtp_api_grpc/src/grpc_api_helper.rs b/xmtp_api_grpc/src/grpc_api_helper.rs index 5be7556c7..ed5d47e1e 100644 --- a/xmtp_api_grpc/src/grpc_api_helper.rs +++ b/xmtp_api_grpc/src/grpc_api_helper.rs @@ -9,14 +9,18 @@ use futures::{SinkExt, Stream, StreamExt, TryStreamExt}; use tokio::sync::oneshot; use tonic::transport::ClientTlsConfig; use tonic::{metadata::MetadataValue, transport::Channel, Request, Streaming}; +use xmtp_proto::convert::{build_group_message_topic, build_key_package_topic}; +use xmtp_proto::xmtp::xmtpv4::client_envelope::Payload; +use xmtp_proto::xmtp::xmtpv4::envelopes_query::Filter; -use crate::conversions::wrap_client_envelope; +use crate::conversions::{extract_client_envelope, wrap_client_envelope}; use xmtp_proto::api_client::{ClientWithMetadata, XmtpMlsStreams, XmtpReplicationClient}; -use xmtp_proto::xmtp::mls::api::v1::{GroupMessage, WelcomeMessage}; +use xmtp_proto::xmtp::mls::api::v1::{fetch_key_packages_response, GroupMessage, WelcomeMessage}; use xmtp_proto::xmtp::xmtpv4::replication_api_client::ReplicationApiClient; use xmtp_proto::xmtp::xmtpv4::{ BatchSubscribeEnvelopesRequest, BatchSubscribeEnvelopesResponse, ClientEnvelope, - PublishEnvelopeRequest, PublishEnvelopeResponse, QueryEnvelopesRequest, QueryEnvelopesResponse, + EnvelopesQuery, OriginatorEnvelope, PublishEnvelopeRequest, PublishEnvelopeResponse, + QueryEnvelopesRequest, QueryEnvelopesResponse, }; use xmtp_proto::{ api_client::{ @@ -129,6 +133,29 @@ impl Client { req } + + pub async fn query_v4_envelopes( + &self, + topics: Vec>, + ) -> Result>, Error> { + let requests = topics.iter().map(|topic| async { + let client = &mut self.replication_client.clone(); + let v4_envelopes = client + .query_envelopes(QueryEnvelopesRequest { + query: Some(EnvelopesQuery { + last_seen: None, + filter: Some(Filter::Topic(topic.to_vec())), + }), + limit: 100, + }) + .await + .map_err(|err| Error::new(ErrorKind::IdentityError).with(err))?; + + Ok(v4_envelopes.into_inner().envelopes) + }); + + Ok(futures::future::try_join_all(requests).await?) + } } impl ClientWithMetadata for Client { @@ -375,23 +402,56 @@ impl XmtpMlsClient for Client { &self, req: FetchKeyPackagesRequest, ) -> Result { - let client = &mut self.mls_client.clone(); - let res = client.fetch_key_packages(self.build_request(req)).await; + if self.use_replication_v4 { + let topics = req + .installation_keys + .iter() + .map(|key| build_key_package_topic(key.as_slice())) + .collect(); + + let envelopes = self.query_v4_envelopes(topics).await?; + let key_packages = envelopes + .iter() + .map(|envelopes| { + // The last envelope should be the newest key package upload + let unsigned = envelopes.last().unwrap(); + let client_env = extract_client_envelope(unsigned); + if let Some(Payload::UploadKeyPackage(upload_key_package)) = client_env.payload + { + fetch_key_packages_response::KeyPackage { + key_package_tls_serialized: upload_key_package + .key_package + .unwrap() + .key_package_tls_serialized, + } + } else { + panic!("Payload is not a key package"); + } + }) + .collect(); - res.map(|r| r.into_inner()) - .map_err(|e| Error::new(ErrorKind::MlsError).with(e)) + Ok(FetchKeyPackagesResponse { key_packages }) + } else { + let client = &mut self.mls_client.clone(); + let res = client.fetch_key_packages(self.build_request(req)).await; + + res.map(|r| r.into_inner()) + .map_err(|e| Error::new(ErrorKind::MlsError).with(e)) + } } #[tracing::instrument(level = "trace", skip_all)] async fn send_group_messages(&self, req: SendGroupMessagesRequest) -> Result<(), Error> { if self.use_replication_v4 { let client = &mut self.replication_client.clone(); - let payload = wrap_client_envelope(ClientEnvelope::from(req)); - let res = client.publish_envelope(payload).await; - match res { - Ok(_) => Ok(()), - Err(e) => Err(Error::new(ErrorKind::MlsError).with(e)), + for message in req.messages { + let payload = wrap_client_envelope(ClientEnvelope::from(message)); + let res = client.publish_envelope(payload).await; + if let Err(e) = res { + return Err(Error::new(ErrorKind::MlsError).with(e)); + } } + Ok(()) } else { let client = &mut self.mls_client.clone(); let res = client.send_group_messages(self.build_request(req)).await; @@ -406,12 +466,14 @@ impl XmtpMlsClient for Client { async fn send_welcome_messages(&self, req: SendWelcomeMessagesRequest) -> Result<(), Error> { if self.use_replication_v4 { let client = &mut self.replication_client.clone(); - let payload = wrap_client_envelope(ClientEnvelope::from(req)); - let res = client.publish_envelope(payload).await; - match res { - Ok(_) => Ok(()), - Err(e) => Err(Error::new(ErrorKind::MlsError).with(e)), + for message in req.messages { + let payload = wrap_client_envelope(ClientEnvelope::from(message)); + let res = client.publish_envelope(payload).await; + if let Err(e) = res { + return Err(Error::new(ErrorKind::MlsError).with(e)); + } } + Ok(()) } else { let client = &mut self.mls_client.clone(); let res = client.send_welcome_messages(self.build_request(req)).await; @@ -427,11 +489,29 @@ impl XmtpMlsClient for Client { &self, req: QueryGroupMessagesRequest, ) -> Result { - let client = &mut self.mls_client.clone(); - let res = client.query_group_messages(self.build_request(req)).await; + if self.use_replication_v4 { + let client = &mut self.replication_client.clone(); + let res = client + .query_envelopes(QueryEnvelopesRequest { + query: Some(EnvelopesQuery { + last_seen: None, + filter: Some(Filter::Topic(build_group_message_topic( + req.group_id.as_slice(), + ))), + }), + limit: 100, + }) + .await + .map_err(|e| Error::new(ErrorKind::MlsError).with(e))?; - res.map(|r| r.into_inner()) - .map_err(|e| Error::new(ErrorKind::MlsError).with(e)) + Err(Error::new(ErrorKind::MlsError).with("not implemented")) + } else { + let client = &mut self.mls_client.clone(); + let res = client.query_group_messages(self.build_request(req)).await; + + res.map(|r| r.into_inner()) + .map_err(|e| Error::new(ErrorKind::MlsError).with(e)) + } } #[tracing::instrument(level = "trace", skip_all)] diff --git a/xmtp_api_grpc/src/identity.rs b/xmtp_api_grpc/src/identity.rs index 52d53cfc8..4573797fd 100644 --- a/xmtp_api_grpc/src/identity.rs +++ b/xmtp_api_grpc/src/identity.rs @@ -85,35 +85,30 @@ impl XmtpIdentityClient for Client { &self, request: GetIdentityUpdatesV2Request, ) -> Result { - let client = &mut self.replication_client.clone(); - let mut responses = vec![]; - - for inner_req in request.requests.iter() { - let v4_envelopes = client - .query_envelopes(QueryEnvelopesRequest { - query: Some(EnvelopesQuery { - last_seen: None, - filter: Some(Filter::Topic(build_identity_update_topic( - inner_req.inbox_id.clone(), - ))), - }), - limit: 100, + let topics = request + .requests + .iter() + .map(|r| build_identity_update_topic(r.inbox_id.clone())) + .collect(); + let v4_envelopes = self.query_v4_envelopes(topics).await?; + let joined_data = v4_envelopes + .into_iter() + .zip(request.requests.into_iter()) + .collect::>(); + let responses = joined_data + .iter() + .map(|(envelopes, inner_req)| { + let identity_updates = envelopes + .iter() + .map(convert_v4_envelope_to_identity_update) + .collect::, Error>>()?; + + Ok(get_identity_updates_response::Response { + inbox_id: inner_req.inbox_id.clone(), + updates: identity_updates, }) - .await - .map_err(|err| Error::new(ErrorKind::IdentityError).with(err))?; - - let identity_update_responses = v4_envelopes - .into_inner() - .envelopes - .iter() - .map(convert_v4_envelope_to_identity_update) - .collect::, Error>>()?; - - responses.push(get_identity_updates_response::Response { - inbox_id: inner_req.inbox_id.clone(), - updates: identity_update_responses, - }); - } + }) + .collect::, Error>>()?; Ok(GetIdentityUpdatesV2Response { responses }) } @@ -158,3 +153,7 @@ fn convert_v4_envelope_to_identity_update( fn build_identity_update_topic(inbox_id: String) -> Vec { format!("i/{}", inbox_id).into_bytes() } + +fn build_key_package_topic(installation_id: Vec) -> Vec { + format!("kp/{}", hex::encode(installation_id)).into_bytes() +} diff --git a/xmtp_proto/Cargo.toml b/xmtp_proto/Cargo.toml index 327520529..72d783884 100644 --- a/xmtp_proto/Cargo.toml +++ b/xmtp_proto/Cargo.toml @@ -9,27 +9,40 @@ pbjson-types.workspace = true pbjson.workspace = true prost = { workspace = true, features = ["prost-derive"] } # Only necessary if using Protobuf well-known types: +hex.workspace = true +openmls = { workspace = true, optional = true } +openmls_rust_crypto = { workspace = true, optional = true } prost-types = { workspace = true } serde = { workspace = true } -openmls = { workspace = true, optional = true } trait-variant = "0.1.2" -hex.workspace = true [target.'cfg(not(target_arch = "wasm32"))'.dependencies] tonic = { workspace = true } [features] -convert = ["openmls", "proto_full"] +convert = ["openmls", "openmls_rust_crypto", "proto_full"] default = [] # @@protoc_deletion_point(features) # This section is automatically generated by protoc-gen-prost-crate. # Changes in this area may be lost on regeneration. -proto_full = ["xmtp-identity","xmtp-identity-api-v1","xmtp-identity-associations","xmtp-keystore_api-v1","xmtp-message_api-v1","xmtp-message_contents","xmtp-mls-api-v1","xmtp-mls-database","xmtp-mls-message_contents","xmtp-mls_validation-v1","xmtp-xmtpv4"] +proto_full = [ + "xmtp-identity", + "xmtp-identity-api-v1", + "xmtp-identity-associations", + "xmtp-keystore_api-v1", + "xmtp-message_api-v1", + "xmtp-message_contents", + "xmtp-mls-api-v1", + "xmtp-mls-database", + "xmtp-mls-message_contents", + "xmtp-mls_validation-v1", + "xmtp-xmtpv4", +] "xmtp-identity" = [] -"xmtp-identity-api-v1" = ["xmtp-identity","xmtp-identity-associations"] -"xmtp-identity-associations" = ["xmtp-identity","xmtp-message_contents"] +"xmtp-identity-api-v1" = ["xmtp-identity", "xmtp-identity-associations"] +"xmtp-identity-associations" = ["xmtp-identity", "xmtp-message_contents"] "xmtp-keystore_api-v1" = ["xmtp-message_contents"] "xmtp-message_api-v1" = ["xmtp-message_contents"] "xmtp-message_contents" = [] @@ -37,5 +50,5 @@ proto_full = ["xmtp-identity","xmtp-identity-api-v1","xmtp-identity-associations "xmtp-mls-database" = [] "xmtp-mls-message_contents" = [] "xmtp-mls_validation-v1" = ["xmtp-identity-associations"] -"xmtp-xmtpv4" = ["xmtp-identity-associations","xmtp-mls-api-v1"] -## @@protoc_insertion_point(features) \ No newline at end of file +"xmtp-xmtpv4" = ["xmtp-identity-associations", "xmtp-mls-api-v1"] +## @@protoc_insertion_point(features) diff --git a/xmtp_proto/src/convert.rs b/xmtp_proto/src/convert.rs index bc02e4d09..71a353926 100644 --- a/xmtp_proto/src/convert.rs +++ b/xmtp_proto/src/convert.rs @@ -1,13 +1,19 @@ use openmls::prelude::tls_codec::Deserialize; -use openmls::prelude::{MlsMessageIn, ProtocolMessage}; +use openmls::prelude::{KeyPackageIn, MlsMessageIn, ProtocolMessage, ProtocolVersion}; use crate::xmtp::identity::api::v1::PublishIdentityUpdateRequest; -use crate::xmtp::mls::api::v1::group_message_input::Version as GroupMessageInputVersion; use crate::xmtp::mls::api::v1::{ - SendGroupMessagesRequest, SendWelcomeMessagesRequest, UploadKeyPackageRequest, + group_message_input::Version as GroupMessageInputVersion, + welcome_message_input::Version as WelcomeMessageVersion, +}; +use crate::xmtp::mls::api::v1::{ + GroupMessageInput, KeyPackageUpload, UploadKeyPackageRequest, WelcomeMessageInput, }; use crate::xmtp::xmtpv4::client_envelope::Payload; use crate::xmtp::xmtpv4::{AuthenticatedData, ClientEnvelope}; +use openmls_rust_crypto::RustCrypto; + +pub const MLS_PROTOCOL_VERSION: ProtocolVersion = ProtocolVersion::Mls10; mod inbox_id { @@ -28,27 +34,26 @@ mod inbox_id { } } -impl From for ClientEnvelope { - fn from(req: SendWelcomeMessagesRequest) -> Self { +impl From for ClientEnvelope { + fn from(req: WelcomeMessageInput) -> Self { ClientEnvelope { - aad: None, - payload: Some(Payload::WelcomeMessage( - req.messages.first().unwrap().clone(), - )), + aad: Some(AuthenticatedData::with_topic(get_welcome_message_topic( + &req, + ))), + payload: Some(Payload::WelcomeMessage(req)), } } } -impl From for ClientEnvelope { - fn from(req: SendGroupMessagesRequest) -> Self { - let first_message = req.messages.first().unwrap(); - let version = match first_message.version.as_ref().unwrap() { +impl From for ClientEnvelope { + fn from(req: GroupMessageInput) -> Self { + let version = match req.version.as_ref().unwrap() { GroupMessageInputVersion::V1(v1) => v1, }; - let topic = extract_topic_from_group_message(version.data.clone()).unwrap(); + let topic = get_group_message_topic(version.data.clone()); ClientEnvelope { aad: Some(AuthenticatedData::with_topic(topic)), - payload: Some(Payload::GroupMessage(req.messages.first().unwrap().clone())), + payload: Some(Payload::GroupMessage(req)), } } } @@ -56,7 +61,9 @@ impl From for ClientEnvelope { impl From for ClientEnvelope { fn from(req: UploadKeyPackageRequest) -> Self { ClientEnvelope { - aad: Some(AuthenticatedData::dummy()), + aad: Some(AuthenticatedData::with_topic(get_key_package_topic( + &req.key_package.as_ref().unwrap(), + ))), payload: Some(Payload::UploadKeyPackage(req)), } } @@ -64,9 +71,12 @@ impl From for ClientEnvelope { impl From for ClientEnvelope { fn from(req: PublishIdentityUpdateRequest) -> Self { + let identity_update = req.identity_update.unwrap(); ClientEnvelope { - aad: Some(AuthenticatedData::dummy()), - payload: Some(Payload::IdentityUpdate(req.identity_update.unwrap())), + aad: Some(AuthenticatedData::with_topic(build_identity_update_topic( + identity_update.inbox_id.clone(), + ))), + payload: Some(Payload::IdentityUpdate(identity_update)), } } } @@ -80,25 +90,55 @@ impl AuthenticatedData { } } - pub fn with_topic(topic: String) -> AuthenticatedData { + pub fn with_topic(topic: Vec) -> AuthenticatedData { AuthenticatedData { target_originator: 1, - target_topic: topic.as_bytes().to_vec(), + target_topic: topic, last_seen: None, } } } -fn extract_topic_from_group_message(message: Vec) -> Result { - let msg_result = - MlsMessageIn::tls_deserialize(&mut message.as_slice()).map_err(|e| e.to_string())?; +fn get_group_message_topic(message: Vec) -> Vec { + let msg_result = MlsMessageIn::tls_deserialize(&mut message.as_slice()) + .expect("Failed to deserialize message"); let protocol_message: ProtocolMessage = msg_result .try_into_protocol_message() - .map_err(|e| e.to_string())?; + .expect("Failed to convert to protocol message"); + + build_group_message_topic(protocol_message.group_id().as_slice()) +} + +fn get_welcome_message_topic(req: &WelcomeMessageInput) -> Vec { + let WelcomeMessageVersion::V1(v1) = req.version.as_ref().unwrap(); + build_welcome_message_topic(v1.installation_key.as_slice()) +} + +fn get_key_package_topic(key_package: &KeyPackageUpload) -> Vec { + let kp_in: KeyPackageIn = + KeyPackageIn::tls_deserialize_exact(key_package.key_package_tls_serialized.as_slice()) + .expect("key package serialization"); + let rust_crypto = RustCrypto::default(); + let kp = kp_in + .validate(&rust_crypto, MLS_PROTOCOL_VERSION) + .expect("key package validation"); + let installation_key = kp.leaf_node().signature_key().as_slice(); + build_key_package_topic(installation_key) +} + +pub fn build_identity_update_topic(inbox_id: String) -> Vec { + format!("i/{}", inbox_id).into_bytes() +} + +pub fn build_key_package_topic(installation_id: &[u8]) -> Vec { + format!("kp/{}", hex::encode(installation_id)).into_bytes() +} + +fn build_welcome_message_topic(installation_id: &[u8]) -> Vec { + format!("w/{}", hex::encode(installation_id)).into_bytes() +} - Ok(format!( - "g/{}", - hex::encode(protocol_message.group_id().as_slice()) - )) +pub fn build_group_message_topic(group_id: &[u8]) -> Vec { + format!("g/{}", hex::encode(group_id)).into_bytes() } From 03190453eed90f8a8d22612f18d5b931a9929332 Mon Sep 17 00:00:00 2001 From: Nicholas Molnar <65710+neekolas@users.noreply.github.com> Date: Thu, 26 Sep 2024 12:58:37 -0500 Subject: [PATCH 10/14] Convert group message results --- xmtp_api_grpc/src/conversions.rs | 21 ++++++++++++-- xmtp_api_grpc/src/grpc_api_helper.rs | 41 ++++++++++++++++++++++++++-- xmtp_api_grpc/src/identity.rs | 15 ++-------- 3 files changed, 58 insertions(+), 19 deletions(-) diff --git a/xmtp_api_grpc/src/conversions.rs b/xmtp_api_grpc/src/conversions.rs index b1c45115e..507ba0791 100644 --- a/xmtp_api_grpc/src/conversions.rs +++ b/xmtp_api_grpc/src/conversions.rs @@ -16,12 +16,27 @@ pub fn wrap_client_envelope(req: ClientEnvelope) -> PublishEnvelopeRequest { } } -pub fn extract_client_envelope(req: &OriginatorEnvelope) -> ClientEnvelope { +pub fn extract_unsigned_originator_envelope( + req: &OriginatorEnvelope, +) -> UnsignedOriginatorEnvelope { let mut unsigned_bytes = req.unsigned_originator_envelope.as_slice(); - let unsigned_originator = UnsignedOriginatorEnvelope::decode(&mut unsigned_bytes) - .expect("Failed to decode unsigned originator envelope"); + UnsignedOriginatorEnvelope::decode(&mut unsigned_bytes) + .expect("Failed to decode unsigned originator envelope") +} + +pub fn extract_client_envelope(req: &OriginatorEnvelope) -> ClientEnvelope { + let unsigned_originator = extract_unsigned_originator_envelope(req); let payer_envelope = unsigned_originator.payer_envelope.unwrap(); let mut payer_bytes = payer_envelope.unsigned_client_envelope.as_slice(); ClientEnvelope::decode(&mut payer_bytes).expect("Failed to decode client envelope") } + +pub fn extract_group_id_from_topic(topic: Vec) -> Vec { + let topic_str = String::from_utf8(topic).expect("Failed to convert topic to string"); + let group_id = topic_str + .split(":") + .nth(1) + .expect("Failed to extract group id from topic"); + group_id.as_bytes().to_vec() +} diff --git a/xmtp_api_grpc/src/grpc_api_helper.rs b/xmtp_api_grpc/src/grpc_api_helper.rs index ed5d47e1e..abafbc2f8 100644 --- a/xmtp_api_grpc/src/grpc_api_helper.rs +++ b/xmtp_api_grpc/src/grpc_api_helper.rs @@ -13,9 +13,14 @@ use xmtp_proto::convert::{build_group_message_topic, build_key_package_topic}; use xmtp_proto::xmtp::xmtpv4::client_envelope::Payload; use xmtp_proto::xmtp::xmtpv4::envelopes_query::Filter; -use crate::conversions::{extract_client_envelope, wrap_client_envelope}; +use crate::conversions::{ + extract_client_envelope, extract_group_id_from_topic, extract_unsigned_originator_envelope, + wrap_client_envelope, +}; use xmtp_proto::api_client::{ClientWithMetadata, XmtpMlsStreams, XmtpReplicationClient}; -use xmtp_proto::xmtp::mls::api::v1::{fetch_key_packages_response, GroupMessage, WelcomeMessage}; +use xmtp_proto::xmtp::mls::api::v1::{ + fetch_key_packages_response, group_message, group_message_input, GroupMessage, WelcomeMessage, +}; use xmtp_proto::xmtp::xmtpv4::replication_api_client::ReplicationApiClient; use xmtp_proto::xmtp::xmtpv4::{ BatchSubscribeEnvelopesRequest, BatchSubscribeEnvelopesResponse, ClientEnvelope, @@ -504,7 +509,37 @@ impl XmtpMlsClient for Client { .await .map_err(|e| Error::new(ErrorKind::MlsError).with(e))?; - Err(Error::new(ErrorKind::MlsError).with("not implemented")) + let envelopes = res.into_inner().envelopes; + let response = QueryGroupMessagesResponse { + messages: envelopes + .iter() + .map(|envelope| { + let unsigned_originator_envelope = + extract_unsigned_originator_envelope(envelope); + let client_envelope = extract_client_envelope(envelope); + let Payload::GroupMessage(group_message) = client_envelope.payload.unwrap() + else { + panic!("Payload is not a group message"); + }; + let group_id = + extract_group_id_from_topic(client_envelope.aad.unwrap().target_topic); + let group_message_input::Version::V1(v1_group_message) = + group_message.version.unwrap(); + + GroupMessage { + version: Some(group_message::Version::V1(group_message::V1 { + id: unsigned_originator_envelope.originator_sequence_id, + created_ns: unsigned_originator_envelope.originator_ns as u64, + group_id, + data: v1_group_message.data, + sender_hmac: v1_group_message.sender_hmac, + })), + } + }) + .collect(), + paging_info: None, + }; + Ok(response) } else { let client = &mut self.mls_client.clone(); let res = client.query_group_messages(self.build_request(req)).await; diff --git a/xmtp_api_grpc/src/identity.rs b/xmtp_api_grpc/src/identity.rs index 4573797fd..2e20ccb90 100644 --- a/xmtp_api_grpc/src/identity.rs +++ b/xmtp_api_grpc/src/identity.rs @@ -1,13 +1,10 @@ use crate::conversions::wrap_client_envelope; use crate::Client; use prost::Message; +use xmtp_proto::convert::build_identity_update_topic; use xmtp_proto::xmtp::identity::api::v1::get_identity_updates_response::{self, IdentityUpdateLog}; use xmtp_proto::xmtp::xmtpv4::client_envelope::Payload; -use xmtp_proto::xmtp::xmtpv4::envelopes_query::Filter; -use xmtp_proto::xmtp::xmtpv4::{ - ClientEnvelope, EnvelopesQuery, OriginatorEnvelope, QueryEnvelopesRequest, - UnsignedOriginatorEnvelope, -}; +use xmtp_proto::xmtp::xmtpv4::{ClientEnvelope, OriginatorEnvelope, UnsignedOriginatorEnvelope}; use xmtp_proto::{ api_client::{Error, ErrorKind, XmtpIdentityClient}, xmtp::identity::api::v1::{ @@ -149,11 +146,3 @@ fn convert_v4_envelope_to_identity_update( update: Some(identity_update), }) } - -fn build_identity_update_topic(inbox_id: String) -> Vec { - format!("i/{}", inbox_id).into_bytes() -} - -fn build_key_package_topic(installation_id: Vec) -> Vec { - format!("kp/{}", hex::encode(installation_id)).into_bytes() -} From d77f22f1a5a8ee434dbc04785cccd6c0293033b0 Mon Sep 17 00:00:00 2001 From: Nicholas Molnar <65710+neekolas@users.noreply.github.com> Date: Thu, 26 Sep 2024 13:06:05 -0500 Subject: [PATCH 11/14] Convert welcome message results --- xmtp_api_grpc/src/grpc_api_helper.rs | 62 +++++++++++++++++++++++++--- xmtp_proto/src/convert.rs | 2 +- 2 files changed, 57 insertions(+), 7 deletions(-) diff --git a/xmtp_api_grpc/src/grpc_api_helper.rs b/xmtp_api_grpc/src/grpc_api_helper.rs index abafbc2f8..08af0c29e 100644 --- a/xmtp_api_grpc/src/grpc_api_helper.rs +++ b/xmtp_api_grpc/src/grpc_api_helper.rs @@ -9,7 +9,9 @@ use futures::{SinkExt, Stream, StreamExt, TryStreamExt}; use tokio::sync::oneshot; use tonic::transport::ClientTlsConfig; use tonic::{metadata::MetadataValue, transport::Channel, Request, Streaming}; -use xmtp_proto::convert::{build_group_message_topic, build_key_package_topic}; +use xmtp_proto::convert::{ + build_group_message_topic, build_key_package_topic, build_welcome_message_topic, +}; use xmtp_proto::xmtp::xmtpv4::client_envelope::Payload; use xmtp_proto::xmtp::xmtpv4::envelopes_query::Filter; @@ -19,7 +21,8 @@ use crate::conversions::{ }; use xmtp_proto::api_client::{ClientWithMetadata, XmtpMlsStreams, XmtpReplicationClient}; use xmtp_proto::xmtp::mls::api::v1::{ - fetch_key_packages_response, group_message, group_message_input, GroupMessage, WelcomeMessage, + fetch_key_packages_response, group_message, group_message_input, welcome_message, + welcome_message_input, GroupMessage, WelcomeMessage, }; use xmtp_proto::xmtp::xmtpv4::replication_api_client::ReplicationApiClient; use xmtp_proto::xmtp::xmtpv4::{ @@ -554,11 +557,58 @@ impl XmtpMlsClient for Client { &self, req: QueryWelcomeMessagesRequest, ) -> Result { - let client = &mut self.mls_client.clone(); - let res = client.query_welcome_messages(self.build_request(req)).await; + if self.use_replication_v4 { + let client = &mut self.replication_client.clone(); + let res = client + .query_envelopes(QueryEnvelopesRequest { + query: Some(EnvelopesQuery { + last_seen: None, + filter: Some(Filter::Topic(build_welcome_message_topic( + req.installation_key.as_slice(), + ))), + }), + limit: 100, + }) + .await + .map_err(|e| Error::new(ErrorKind::MlsError).with(e))?; + + let envelopes = res.into_inner().envelopes; + let response = QueryWelcomeMessagesResponse { + messages: envelopes + .iter() + .map(|envelope| { + let unsigned_originator_envelope = + extract_unsigned_originator_envelope(envelope); + let client_envelope = extract_client_envelope(envelope); + let Payload::WelcomeMessage(welcome_message) = + client_envelope.payload.unwrap() + else { + panic!("Payload is not a group message"); + }; + let welcome_message_input::Version::V1(v1_welcome_message) = + welcome_message.version.unwrap(); + + WelcomeMessage { + version: Some(welcome_message::Version::V1(welcome_message::V1 { + id: unsigned_originator_envelope.originator_sequence_id, + created_ns: unsigned_originator_envelope.originator_ns as u64, + installation_key: req.installation_key.clone(), + data: v1_welcome_message.data, + hpke_public_key: v1_welcome_message.hpke_public_key, + })), + } + }) + .collect(), + paging_info: None, + }; + Ok(response) + } else { + let client = &mut self.mls_client.clone(); + let res = client.query_welcome_messages(self.build_request(req)).await; - res.map(|r| r.into_inner()) - .map_err(|e| Error::new(ErrorKind::MlsError).with(e)) + res.map(|r| r.into_inner()) + .map_err(|e| Error::new(ErrorKind::MlsError).with(e)) + } } } diff --git a/xmtp_proto/src/convert.rs b/xmtp_proto/src/convert.rs index 71a353926..3b741d228 100644 --- a/xmtp_proto/src/convert.rs +++ b/xmtp_proto/src/convert.rs @@ -135,7 +135,7 @@ pub fn build_key_package_topic(installation_id: &[u8]) -> Vec { format!("kp/{}", hex::encode(installation_id)).into_bytes() } -fn build_welcome_message_topic(installation_id: &[u8]) -> Vec { +pub fn build_welcome_message_topic(installation_id: &[u8]) -> Vec { format!("w/{}", hex::encode(installation_id)).into_bytes() } From ba8b08a0ee14bfecd1677bb16db6f42dabce0077 Mon Sep 17 00:00:00 2001 From: Nicholas Molnar <65710+neekolas@users.noreply.github.com> Date: Thu, 26 Sep 2024 13:08:06 -0500 Subject: [PATCH 12/14] Fix delimiter --- xmtp_api_grpc/src/conversions.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xmtp_api_grpc/src/conversions.rs b/xmtp_api_grpc/src/conversions.rs index 507ba0791..f7807e4e6 100644 --- a/xmtp_api_grpc/src/conversions.rs +++ b/xmtp_api_grpc/src/conversions.rs @@ -35,7 +35,7 @@ pub fn extract_client_envelope(req: &OriginatorEnvelope) -> ClientEnvelope { pub fn extract_group_id_from_topic(topic: Vec) -> Vec { let topic_str = String::from_utf8(topic).expect("Failed to convert topic to string"); let group_id = topic_str - .split(":") + .split("/") .nth(1) .expect("Failed to extract group id from topic"); group_id.as_bytes().to_vec() From 200d46a909218cdcf0d807fc3d9414262def14ac Mon Sep 17 00:00:00 2001 From: Nicholas Molnar <65710+neekolas@users.noreply.github.com> Date: Thu, 26 Sep 2024 13:13:52 -0500 Subject: [PATCH 13/14] Take group id from request --- xmtp_api_grpc/src/grpc_api_helper.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/xmtp_api_grpc/src/grpc_api_helper.rs b/xmtp_api_grpc/src/grpc_api_helper.rs index 08af0c29e..ced5c7bdf 100644 --- a/xmtp_api_grpc/src/grpc_api_helper.rs +++ b/xmtp_api_grpc/src/grpc_api_helper.rs @@ -524,8 +524,7 @@ impl XmtpMlsClient for Client { else { panic!("Payload is not a group message"); }; - let group_id = - extract_group_id_from_topic(client_envelope.aad.unwrap().target_topic); + let group_message_input::Version::V1(v1_group_message) = group_message.version.unwrap(); @@ -533,7 +532,7 @@ impl XmtpMlsClient for Client { version: Some(group_message::Version::V1(group_message::V1 { id: unsigned_originator_envelope.originator_sequence_id, created_ns: unsigned_originator_envelope.originator_ns as u64, - group_id, + group_id: req.group_id.clone(), data: v1_group_message.data, sender_hmac: v1_group_message.sender_hmac, })), From 95ce41143cf4c9241f29c2d0c7727b53fbad8435 Mon Sep 17 00:00:00 2001 From: Richard Hua Date: Thu, 26 Sep 2024 15:36:21 -0500 Subject: [PATCH 14/14] Add check command --- examples/cli/cli-client.rs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/examples/cli/cli-client.rs b/examples/cli/cli-client.rs index 76c7838c2..74d6f7e5a 100755 --- a/examples/cli/cli-client.rs +++ b/examples/cli/cli-client.rs @@ -81,6 +81,10 @@ enum Commands { #[clap(long)] seed_phrase: Option, }, + Check { + #[arg(value_name = "address")] + address: String, + }, CreateGroup { #[clap(value_enum, default_value_t = Permissions::EveryoneIsAdmin)] permissions: Permissions, @@ -190,6 +194,14 @@ async fn main() { Commands::Register { seed_phrase } => { unreachable!() } + Commands::Check { address } => { + info!("Check {:?}", address); + let client = create_client(&cli, IdentityStrategy::CachedOnly) + .await + .unwrap(); + let dict = client.can_message(vec![address.clone()]).await.unwrap(); + info!("Can message: {:?}", dict.get(address).unwrap()); + } Commands::Info {} => { info!("Info"); let client = create_client(&cli, IdentityStrategy::CachedOnly) @@ -428,7 +440,7 @@ async fn create_client(cli: &Cli, account: IdentityStrategy) -> Result