From ed350d2401249360768365462830ef7b74531804 Mon Sep 17 00:00:00 2001 From: Ry Racherbaumer Date: Thu, 21 Nov 2024 16:05:10 -0600 Subject: [PATCH 01/46] Update Node and WASM bindings (#1313) * Add installation_id_bytes to Node client * Prepare node bindings release * Add installation_id_bytes to WASM client * Add signature methods to WASM client * Prepare WASM bindings release * Clippy fix --- bindings_node/CHANGELOG.md | 4 +++ bindings_node/package.json | 2 +- bindings_node/src/client.rs | 5 ++++ bindings_wasm/CHANGELOG.md | 5 ++++ bindings_wasm/package.json | 2 +- bindings_wasm/src/client.rs | 52 +++++++++++++++++++++++++++++++++++++ 6 files changed, 68 insertions(+), 2 deletions(-) diff --git a/bindings_node/CHANGELOG.md b/bindings_node/CHANGELOG.md index 4c2dbe669..426caf777 100644 --- a/bindings_node/CHANGELOG.md +++ b/bindings_node/CHANGELOG.md @@ -1,5 +1,9 @@ # @xmtp/node-bindings +## 0.0.21 + +- Added `installation_id_bytes` to `Client` + ## 0.0.20 - Fixed argument types for new signing methods diff --git a/bindings_node/package.json b/bindings_node/package.json index 9939f3844..65db63a12 100644 --- a/bindings_node/package.json +++ b/bindings_node/package.json @@ -1,6 +1,6 @@ { "name": "@xmtp/node-bindings", - "version": "0.0.20", + "version": "0.0.21", "repository": { "type": "git", "url": "git+https://git@github.com/xmtp/libxmtp.git", diff --git a/bindings_node/src/client.rs b/bindings_node/src/client.rs index d2158b57c..3f042e501 100644 --- a/bindings_node/src/client.rs +++ b/bindings_node/src/client.rs @@ -201,6 +201,11 @@ impl Client { ed25519_public_key_to_address(self.inner_client.installation_public_key().as_slice()) } + #[napi] + pub fn installation_id_bytes(&self) -> Uint8Array { + self.inner_client.installation_public_key().into() + } + #[napi] pub async fn can_message(&self, account_addresses: Vec) -> Result> { let results: HashMap = self diff --git a/bindings_wasm/CHANGELOG.md b/bindings_wasm/CHANGELOG.md index ae7da1394..69994bd9e 100644 --- a/bindings_wasm/CHANGELOG.md +++ b/bindings_wasm/CHANGELOG.md @@ -1,5 +1,10 @@ # @xmtp/wasm-bindings +## 0.0.6 + +- Added `installation_id_bytes` to `Client` +- Added `sign_with_installation_key`, `verify_signed_with_installation_key`, and `verify_signed_with_public_key` to `Client` + ## 0.0.5 - Filtered out group membership messages from DM groups diff --git a/bindings_wasm/package.json b/bindings_wasm/package.json index e799e8cf2..d963f21e1 100644 --- a/bindings_wasm/package.json +++ b/bindings_wasm/package.json @@ -1,6 +1,6 @@ { "name": "@xmtp/wasm-bindings", - "version": "0.0.5", + "version": "0.0.6", "type": "module", "license": "MIT", "description": "WASM bindings for the libXMTP rust library", diff --git a/bindings_wasm/src/client.rs b/bindings_wasm/src/client.rs index 7b3711d79..13451ce22 100644 --- a/bindings_wasm/src/client.rs +++ b/bindings_wasm/src/client.rs @@ -11,6 +11,7 @@ use wasm_bindgen::JsValue; use xmtp_api_http::XmtpHttpApiClient; use xmtp_cryptography::signature::ed25519_public_key_to_address; use xmtp_id::associations::builder::SignatureRequest; +use xmtp_id::associations::verify_signed_with_public_context; use xmtp_mls::builder::ClientBuilder; use xmtp_mls::groups::scoped_client::ScopedGroupClient; use xmtp_mls::identity::IdentityStrategy; @@ -203,6 +204,11 @@ impl Client { ed25519_public_key_to_address(self.inner_client.installation_public_key().as_slice()) } + #[wasm_bindgen(getter, js_name = installationIdBytes)] + pub fn installation_id_bytes(&self) -> Uint8Array { + Uint8Array::from(self.inner_client.installation_public_key().as_slice()) + } + #[wasm_bindgen(js_name = canMessage)] pub async fn can_message(&self, account_addresses: Vec) -> Result { let results: HashMap = self @@ -278,4 +284,50 @@ impl Client { pub fn conversations(&self) -> Conversations { Conversations::new(self.inner_client.clone()) } + + #[wasm_bindgen(js_name = signWithInstallationKey)] + pub fn sign_with_installation_key(&self, signature_text: String) -> Result { + let result = self + .inner_client + .context() + .sign_with_public_context(signature_text) + .map_err(|e| JsError::new(format!("{}", e).as_str()))?; + + Ok(Uint8Array::from(result.as_slice())) + } + + #[wasm_bindgen(js_name = verifySignedWithInstallationKey)] + pub fn verify_signed_with_installation_key( + &self, + signature_text: String, + signature_bytes: Uint8Array, + ) -> Result<(), JsError> { + let public_key = self.inner_client().installation_public_key(); + self.verify_signed_with_public_key( + signature_text, + signature_bytes, + Uint8Array::from(public_key.as_slice()), + ) + } + + #[wasm_bindgen(js_name = verifySignedWithPublicKey)] + pub fn verify_signed_with_public_key( + &self, + signature_text: String, + signature_bytes: Uint8Array, + public_key: Uint8Array, + ) -> Result<(), JsError> { + let signature_bytes = signature_bytes.to_vec(); + let signature_bytes: [u8; 64] = signature_bytes + .try_into() + .map_err(|_| JsError::new("signature_bytes is not 64 bytes long."))?; + + let public_key = public_key.to_vec(); + let public_key: [u8; 32] = public_key + .try_into() + .map_err(|_| JsError::new("public_key is not 32 bytes long."))?; + + verify_signed_with_public_context(signature_text, &signature_bytes, &public_key) + .map_err(|e| JsError::new(format!("{}", e).as_str())) + } } From ab9d335ed25e1ef2fcf4f902571ca8f8b4151afb Mon Sep 17 00:00:00 2001 From: Dakota Brink <779390+codabrink@users.noreply.github.com> Date: Fri, 22 Nov 2024 13:19:13 -0500 Subject: [PATCH 02/46] Simplify Wallet Association By Using Installation Keys (#1314) * wip * wip * sign with installation * cleanup * naming * more cleanup * cleanup * cleanup * getting closer * test fix * remove a param * cleanup * fix js tests * unnecessary clone --- bindings_ffi/src/mls.rs | 70 +++++++++++++++-------------- bindings_node/src/signatures.rs | 12 ++--- bindings_node/test/Client.test.ts | 17 ------- bindings_wasm/src/signatures.rs | 7 +-- xmtp_id/src/associations/builder.rs | 29 ++++-------- xmtp_id/src/associations/member.rs | 7 +++ xmtp_mls/src/identity_updates.rs | 45 ++++++++++++------- 7 files changed, 88 insertions(+), 99 deletions(-) diff --git a/bindings_ffi/src/mls.rs b/bindings_ffi/src/mls.rs index 7ab18fe12..f8c9ab19a 100644 --- a/bindings_ffi/src/mls.rs +++ b/bindings_ffi/src/mls.rs @@ -472,15 +472,15 @@ impl FfiXmtpClient { Ok(()) } - /// Adds an identity - really a wallet address - to the existing client + /// Adds a wallet address to the existing client pub async fn add_wallet( &self, - existing_wallet_address: &str, new_wallet_address: &str, ) -> Result, GenericError> { let signature_request = self .inner_client - .associate_wallet(existing_wallet_address.into(), new_wallet_address.into())?; + .associate_wallet(new_wallet_address.into()) + .await?; let scw_verifier = self.inner_client.scw_verifier().clone(); let request = Arc::new(FfiSignatureRequest { inner: Arc::new(tokio::sync::Mutex::new(signature_request)), @@ -2172,27 +2172,28 @@ mod tests { assert!(result_errored, "did not error on wrong encryption key") } + trait SignWithWallet { + async fn add_wallet_signature(&self, wallet: &xmtp_cryptography::utils::LocalWallet); + } + use super::FfiSignatureRequest; - async fn sign_with_wallet( - wallet: &xmtp_cryptography::utils::LocalWallet, - signature_request: &FfiSignatureRequest, - ) { - let scw_verifier = signature_request.scw_verifier.clone(); - let signature_text = signature_request.inner.lock().await.signature_text(); - let wallet_signature: Vec = wallet.sign(&signature_text.clone()).unwrap().into(); + impl SignWithWallet for FfiSignatureRequest { + async fn add_wallet_signature(&self, wallet: &xmtp_cryptography::utils::LocalWallet) { + let signature_text = self.inner.lock().await.signature_text(); + let wallet_signature: Vec = wallet.sign(&signature_text.clone()).unwrap().into(); - signature_request - .inner - .lock() - .await - .add_signature( - UnverifiedSignature::RecoverableEcdsa(UnverifiedRecoverableEcdsaSignature::new( - wallet_signature, - )), - scw_verifier, - ) - .await - .unwrap(); + self.inner + .lock() + .await + .add_signature( + UnverifiedSignature::RecoverableEcdsa( + UnverifiedRecoverableEcdsaSignature::new(wallet_signature), + ), + &self.scw_verifier, + ) + .await + .unwrap(); + } } use xmtp_cryptography::utils::generate_local_wallet; @@ -2224,7 +2225,9 @@ mod tests { let signature_request = client.signature_request().unwrap().clone(); register_client(&ffi_inbox_owner, &client).await; - sign_with_wallet(&ffi_inbox_owner.wallet, &signature_request).await; + signature_request + .add_wallet_signature(&ffi_inbox_owner.wallet) + .await; let conn = client.inner_client.store().conn().unwrap(); let state = client @@ -2236,18 +2239,16 @@ mod tests { assert_eq!(state.members().len(), 2); // Now, add the second wallet to the client - let wallet_to_add = generate_local_wallet(); let new_account_address = wallet_to_add.get_address(); println!("second address: {}", new_account_address); let signature_request = client - .add_wallet(&ffi_inbox_owner.get_address(), &new_account_address) + .add_wallet(&new_account_address) .await .expect("could not add wallet"); - sign_with_wallet(&ffi_inbox_owner.wallet, &signature_request).await; - sign_with_wallet(&wallet_to_add, &signature_request).await; + signature_request.add_wallet_signature(&wallet_to_add).await; client .apply_signature_request(signature_request) @@ -2290,7 +2291,9 @@ mod tests { let signature_request = client.signature_request().unwrap().clone(); register_client(&ffi_inbox_owner, &client).await; - sign_with_wallet(&ffi_inbox_owner.wallet, &signature_request).await; + signature_request + .add_wallet_signature(&ffi_inbox_owner.wallet) + .await; let conn = client.inner_client.store().conn().unwrap(); let state = client @@ -2308,12 +2311,11 @@ mod tests { println!("second address: {}", new_account_address); let signature_request = client - .add_wallet(&ffi_inbox_owner.get_address(), &new_account_address) + .add_wallet(&new_account_address) .await .expect("could not add wallet"); - sign_with_wallet(&ffi_inbox_owner.wallet, &signature_request).await; - sign_with_wallet(&wallet_to_add, &signature_request).await; + signature_request.add_wallet_signature(&wallet_to_add).await; client .apply_signature_request(signature_request.clone()) @@ -2334,7 +2336,9 @@ mod tests { .await .expect("could not revoke wallet"); - sign_with_wallet(&ffi_inbox_owner.wallet, &signature_request).await; + signature_request + .add_wallet_signature(&ffi_inbox_owner.wallet) + .await; client .apply_signature_request(signature_request) @@ -3835,7 +3839,7 @@ mod tests { assert_eq!(client_2_state.installations.len(), 2); let signature_request = client_1.revoke_all_other_installations().await.unwrap(); - sign_with_wallet(&wallet, &signature_request).await; + signature_request.add_wallet_signature(&wallet).await; client_1 .apply_signature_request(signature_request) .await diff --git a/bindings_node/src/signatures.rs b/bindings_node/src/signatures.rs index cfc67a81f..709c374ec 100644 --- a/bindings_node/src/signatures.rs +++ b/bindings_node/src/signatures.rs @@ -35,17 +35,11 @@ impl Client { } #[napi] - pub async fn add_wallet_signature_text( - &self, - existing_wallet_address: String, - new_wallet_address: String, - ) -> Result { + pub async fn add_wallet_signature_text(&self, new_wallet_address: String) -> Result { let signature_request = self .inner_client() - .associate_wallet( - existing_wallet_address.to_lowercase(), - new_wallet_address.to_lowercase(), - ) + .associate_wallet(new_wallet_address.to_lowercase()) + .await .map_err(ErrorWrapper::from)?; let signature_text = signature_request.signature_text(); let mut signature_requests = self.signature_requests().lock().await; diff --git a/bindings_node/test/Client.test.ts b/bindings_node/test/Client.test.ts index 063b0f603..8942e7b25 100644 --- a/bindings_node/test/Client.test.ts +++ b/bindings_node/test/Client.test.ts @@ -64,23 +64,14 @@ describe('Client', () => { const user2 = createUser() const client = await createRegisteredClient(user) const signatureText = await client.addWalletSignatureText( - user.account.address, user2.account.address ) expect(signatureText).toBeDefined() - // sign message - const signature = await user.wallet.signMessage({ - message: signatureText, - }) const signature2 = await user2.wallet.signMessage({ message: signatureText, }) - await client.addSignature( - SignatureRequestType.AddWallet, - toBytes(signature) - ) await client.addSignature( SignatureRequestType.AddWallet, toBytes(signature2) @@ -101,23 +92,15 @@ describe('Client', () => { const user2 = createUser() const client = await createRegisteredClient(user) const signatureText = await client.addWalletSignatureText( - user.account.address, user2.account.address ) expect(signatureText).toBeDefined() // sign message - const signature = await user.wallet.signMessage({ - message: signatureText, - }) const signature2 = await user2.wallet.signMessage({ message: signatureText, }) - await client.addSignature( - SignatureRequestType.AddWallet, - toBytes(signature) - ) await client.addSignature( SignatureRequestType.AddWallet, toBytes(signature2) diff --git a/bindings_wasm/src/signatures.rs b/bindings_wasm/src/signatures.rs index 7c9f27ac7..9fde22378 100644 --- a/bindings_wasm/src/signatures.rs +++ b/bindings_wasm/src/signatures.rs @@ -36,15 +36,12 @@ impl Client { #[wasm_bindgen(js_name = addWalletSignatureText)] pub async fn add_wallet_signature_text( &self, - existing_wallet_address: String, new_wallet_address: String, ) -> Result { let signature_request = self .inner_client() - .associate_wallet( - existing_wallet_address.to_lowercase(), - new_wallet_address.to_lowercase(), - ) + .associate_wallet(new_wallet_address.to_lowercase()) + .await .map_err(|e| JsError::new(format!("{}", e).as_str()))?; let signature_text = signature_request.signature_text(); let mut signature_requests = self.signature_requests().lock().await; diff --git a/xmtp_id/src/associations/builder.rs b/xmtp_id/src/associations/builder.rs index b1e689411..43c0d166a 100644 --- a/xmtp_id/src/associations/builder.rs +++ b/xmtp_id/src/associations/builder.rs @@ -2,7 +2,7 @@ //! resolved into an [`IdentityUpdate`]. An [`IdentityUpdate`] may be used for updating the state //! of an XMTP ID according to [XIP-46](https://github.com/xmtp/XIPs/pull/53) -use std::collections::{HashMap, HashSet}; +use std::collections::HashMap; use crate::{scw_verifier::SmartContractSignatureVerifier, utils::now_ns}; use thiserror::Error; @@ -194,29 +194,18 @@ impl SignatureRequest { } } - pub fn missing_signatures(&self) -> Vec { - let signers: HashSet = self - .pending_actions + pub fn missing_signatures(&self) -> Vec<&MemberIdentifier> { + self.pending_actions .iter() - .flat_map(|pending_action| { - pending_action - .pending_signatures - .values() - .cloned() - .collect::>() - }) - .collect(); - - let signatures: HashSet = self.signatures.keys().cloned().collect(); - - signers.difference(&signatures).cloned().collect() + .flat_map(|pending_action| pending_action.pending_signatures.values()) + .filter(|ident| !self.signatures.contains_key(ident)) + .collect() } - pub fn missing_address_signatures(&self) -> Vec { + pub fn missing_address_signatures(&self) -> Vec<&MemberIdentifier> { self.missing_signatures() - .iter() + .into_iter() .filter(|member| member.kind() == MemberKind::Address) - .cloned() .collect() } @@ -277,7 +266,7 @@ impl SignatureRequest { "adding verified signature"); // Make sure the signer is someone actually in the request - if !missing_signatures.contains(signer_identity) { + if !missing_signatures.contains(&signer_identity) { return Err(SignatureRequestError::UnknownSigner); } diff --git a/xmtp_id/src/associations/member.rs b/xmtp_id/src/associations/member.rs index 8c7d5cab7..40b162e73 100644 --- a/xmtp_id/src/associations/member.rs +++ b/xmtp_id/src/associations/member.rs @@ -1,3 +1,4 @@ +use ed25519_dalek::VerifyingKey; use xmtp_cryptography::XmtpInstallationCredential; #[derive(Clone, Debug, PartialEq)] @@ -106,6 +107,12 @@ impl From> for MemberIdentifier { } } +impl From for MemberIdentifier { + fn from(installation: VerifyingKey) -> Self { + installation.as_bytes().to_vec().into() + } +} + impl<'a> From<&'a XmtpInstallationCredential> for MemberIdentifier { fn from(cred: &'a XmtpInstallationCredential) -> MemberIdentifier { MemberIdentifier::Installation(cred.public_slice().to_vec()) diff --git a/xmtp_mls/src/identity_updates.rs b/xmtp_mls/src/identity_updates.rs index 83c0b9c5f..23d08e69a 100644 --- a/xmtp_mls/src/identity_updates.rs +++ b/xmtp_mls/src/identity_updates.rs @@ -7,6 +7,7 @@ use crate::{ }; use futures::future::try_join_all; use thiserror::Error; +use xmtp_cryptography::CredentialSign; use xmtp_id::{ associations::{ apply_update, @@ -15,8 +16,8 @@ use xmtp_id::{ unverified::{ UnverifiedIdentityUpdate, UnverifiedInstallationKeySignature, UnverifiedSignature, }, - AssociationError, AssociationState, AssociationStateDiff, IdentityUpdate, MemberIdentifier, - SignatureError, + AssociationError, AssociationState, AssociationStateDiff, IdentityUpdate, + InstallationKeyContext, MemberIdentifier, SignatureError, }, scw_verifier::SmartContractSignatureVerifier, InboxIdRef, @@ -276,18 +277,32 @@ where } /// Generate a `AssociateWallet` signature request using an existing wallet and a new wallet address - pub fn associate_wallet( + pub async fn associate_wallet( &self, - existing_wallet_address: String, new_wallet_address: String, ) -> Result { tracing::info!("Associating new wallet with inbox_id {}", self.inbox_id()); let inbox_id = self.inbox_id(); let builder = SignatureRequestBuilder::new(inbox_id); + let installation_public_key = self.identity().installation_keys.verifying_key(); + let new_member_identifier: MemberIdentifier = new_wallet_address.into(); + + let mut signature_request = builder + .add_association(new_member_identifier, installation_public_key.into()) + .build(); + + let signature = self + .identity() + .installation_keys + .credential_sign::(signature_request.signature_text())?; + signature_request + .add_signature( + UnverifiedSignature::new_installation_key(signature, installation_public_key), + &self.scw_verifier, + ) + .await?; - Ok(builder - .add_association(new_wallet_address.into(), existing_wallet_address.into()) - .build()) + Ok(signature_request) } /// Revoke the given wallets from the association state for the client's inbox @@ -602,10 +617,10 @@ pub(crate) mod tests { let client = ClientBuilder::new_test_client(&wallet).await; let mut add_association_request = client - .associate_wallet(wallet_address.clone(), wallet_2_address.clone()) + .associate_wallet(wallet_2_address.clone()) + .await .unwrap(); - add_wallet_signature(&mut add_association_request, &wallet).await; add_wallet_signature(&mut add_association_request, &wallet_2).await; client @@ -656,10 +671,10 @@ pub(crate) mod tests { assert_logged!("Wrote association", 1); let mut add_association_request = client - .associate_wallet(wallet_address.clone(), wallet_2_address.clone()) + .associate_wallet(wallet_2_address.clone()) + .await .unwrap(); - add_wallet_signature(&mut add_association_request, &wallet).await; add_wallet_signature(&mut add_association_request, &wallet_2).await; client @@ -737,10 +752,10 @@ pub(crate) mod tests { .unwrap(); let new_wallet = generate_local_wallet(); let mut add_association_request = client - .associate_wallet(wallet.get_address(), new_wallet.get_address()) + .associate_wallet(new_wallet.get_address()) + .await .unwrap(); - add_wallet_signature(&mut add_association_request, &wallet).await; add_wallet_signature(&mut add_association_request, &new_wallet).await; client @@ -817,10 +832,10 @@ pub(crate) mod tests { let client = ClientBuilder::new_test_client(&recovery_wallet).await; let mut add_wallet_signature_request = client - .associate_wallet(recovery_wallet.get_address(), second_wallet.get_address()) + .associate_wallet(second_wallet.get_address()) + .await .unwrap(); - add_wallet_signature(&mut add_wallet_signature_request, &recovery_wallet).await; add_wallet_signature(&mut add_wallet_signature_request, &second_wallet).await; client From 363daec242727cc8d7eb07901ed77b60f83f7f8e Mon Sep 17 00:00:00 2001 From: Martin Kysel Date: Fri, 22 Nov 2024 13:48:33 -0500 Subject: [PATCH 03/46] Replication Client: Fix Batch message send (#1300) In the previous code we would break down a batch message containing N messages to N network calls with 1 message each. Fix that. --- xmtp_api_grpc/src/replication_client.rs | 44 ++++++++++--------- xmtp_proto/src/convert.rs | 57 +++++++++++-------------- 2 files changed, 48 insertions(+), 53 deletions(-) diff --git a/xmtp_api_grpc/src/replication_client.rs b/xmtp_api_grpc/src/replication_client.rs index d7ae88e2c..97f7fa5c5 100644 --- a/xmtp_api_grpc/src/replication_client.rs +++ b/xmtp_api_grpc/src/replication_client.rs @@ -362,14 +362,8 @@ impl XmtpIdentityClient for ClientV4 { &self, request: PublishIdentityUpdateRequest, ) -> Result { - let client = &mut self.payer_client.clone(); - let res = client - .publish_client_envelopes(PublishClientEnvelopesRequest::try_from(request)?) - .await; - match res { - Ok(_) => Ok(PublishIdentityUpdateResponse {}), - Err(e) => Err(Error::new(ErrorKind::MlsError).with(e)), - } + self.publish_envelopes_to_payer(vec![request]).await?; + Ok(PublishIdentityUpdateResponse {}) } #[tracing::instrument(level = "trace", skip_all)] @@ -482,20 +476,30 @@ impl ClientV4 { } #[tracing::instrument(level = "trace", skip_all)] - async fn publish_envelopes_to_payer< - T: TryInto, - >( + async fn publish_envelopes_to_payer( &self, - items: impl IntoIterator, - ) -> Result<(), Error> { + messages: impl IntoIterator, + ) -> Result<(), Error> + where + T: TryInto, + >::Error: std::error::Error + Send + Sync + 'static, + { let client = &mut self.payer_client.clone(); - for item in items { - let request = item.try_into()?; - let res = client.publish_client_envelopes(request).await; - if let Err(e) = res { - return Err(Error::new(ErrorKind::MlsError).with(e)); - } - } + + let envelopes: Vec = messages + .into_iter() + .map(|message| { + message + .try_into() + .map_err(|e| Error::new(ErrorKind::MlsError).with(e)) + }) + .collect::>()?; + + client + .publish_client_envelopes(PublishClientEnvelopesRequest { envelopes }) + .await + .map_err(|e| Error::new(ErrorKind::MlsError).with(e))?; + Ok(()) } } diff --git a/xmtp_proto/src/convert.rs b/xmtp_proto/src/convert.rs index fe6f2a1e8..7e265f27c 100644 --- a/xmtp_proto/src/convert.rs +++ b/xmtp_proto/src/convert.rs @@ -6,7 +6,6 @@ use crate::xmtp::mls::api::v1::{ }; use crate::xmtp::xmtpv4::envelopes::client_envelope::Payload; use crate::xmtp::xmtpv4::envelopes::{AuthenticatedData, ClientEnvelope}; -use crate::xmtp::xmtpv4::payer_api::PublishClientEnvelopesRequest; use crate::v4_utils::{ build_identity_topic_from_hex_encoded, build_welcome_message_topic, get_group_message_topic, @@ -34,18 +33,16 @@ mod inbox_id { } } -impl TryFrom for PublishClientEnvelopesRequest { +impl TryFrom for ClientEnvelope { type Error = Error; fn try_from(req: UploadKeyPackageRequest) -> Result { if let Some(key_package) = req.key_package.as_ref() { - Ok(PublishClientEnvelopesRequest { - envelopes: vec![ClientEnvelope { - aad: Some(AuthenticatedData::with_topic(get_key_package_topic( - key_package, - )?)), - payload: Some(Payload::UploadKeyPackage(req)), - }], + Ok(ClientEnvelope { + aad: Some(AuthenticatedData::with_topic(get_key_package_topic( + key_package, + )?)), + payload: Some(Payload::UploadKeyPackage(req)), }) } else { Err(Error::new(InternalError(MissingPayloadError))) @@ -53,18 +50,16 @@ impl TryFrom for PublishClientEnvelopesRequest { } } -impl TryFrom for PublishClientEnvelopesRequest { +impl TryFrom for ClientEnvelope { type Error = Error; fn try_from(req: PublishIdentityUpdateRequest) -> Result { if let Some(identity_update) = req.identity_update { - Ok(PublishClientEnvelopesRequest { - envelopes: vec![ClientEnvelope { - aad: Some(AuthenticatedData::with_topic( - build_identity_topic_from_hex_encoded(&identity_update.inbox_id)?, - )), - payload: Some(Payload::IdentityUpdate(identity_update)), - }], + Ok(ClientEnvelope { + aad: Some(AuthenticatedData::with_topic( + build_identity_topic_from_hex_encoded(&identity_update.inbox_id)?, + )), + payload: Some(Payload::IdentityUpdate(identity_update)), }) } else { Err(Error::new(InternalError(MissingPayloadError))) @@ -72,18 +67,16 @@ impl TryFrom for PublishClientEnvelopesRequest { } } -impl TryFrom for PublishClientEnvelopesRequest { +impl TryFrom for ClientEnvelope { type Error = crate::Error; fn try_from(req: GroupMessageInput) -> Result { if let Some(GroupMessageInputVersion::V1(ref version)) = req.version { - Ok(PublishClientEnvelopesRequest { - envelopes: vec![ClientEnvelope { - aad: Some(AuthenticatedData::with_topic(get_group_message_topic( - version.data.clone(), - )?)), - payload: Some(Payload::GroupMessage(req)), - }], + Ok(ClientEnvelope { + aad: Some(AuthenticatedData::with_topic(get_group_message_topic( + version.data.clone(), + )?)), + payload: Some(Payload::GroupMessage(req)), }) } else { Err(Error::new(InternalError(MissingPayloadError))) @@ -91,18 +84,16 @@ impl TryFrom for PublishClientEnvelopesRequest { } } -impl TryFrom for PublishClientEnvelopesRequest { +impl TryFrom for ClientEnvelope { type Error = crate::Error; fn try_from(req: WelcomeMessageInput) -> Result { if let Some(WelcomeMessageVersion::V1(ref version)) = req.version { - Ok(PublishClientEnvelopesRequest { - envelopes: vec![ClientEnvelope { - aad: Some(AuthenticatedData::with_topic(build_welcome_message_topic( - version.installation_key.as_slice(), - ))), - payload: Some(Payload::WelcomeMessage(req)), - }], + Ok(ClientEnvelope { + aad: Some(AuthenticatedData::with_topic(build_welcome_message_topic( + version.installation_key.as_slice(), + ))), + payload: Some(Payload::WelcomeMessage(req)), }) } else { Err(Error::new(InternalError(MissingPayloadError))) From ce01a7310fcb169bef2faa117012aead49e17fda Mon Sep 17 00:00:00 2001 From: Ry Racherbaumer Date: Fri, 22 Nov 2024 15:24:54 -0600 Subject: [PATCH 04/46] Update Node and WASM bindings (#1333) * Move signature fns to signatures mod * Make DB path optional * Add tests * Prepare releases --- bindings_node/CHANGELOG.md | 4 +++ bindings_node/package.json | 2 +- bindings_node/src/client.rs | 52 +++-------------------------- bindings_node/src/signatures.rs | 45 +++++++++++++++++++++++++- bindings_node/test/Client.test.ts | 28 ++++++++++++++-- bindings_wasm/CHANGELOG.md | 4 +++ bindings_wasm/package.json | 2 +- bindings_wasm/src/client.rs | 54 +++---------------------------- bindings_wasm/src/signatures.rs | 46 ++++++++++++++++++++++++++ bindings_wasm/tests/web.rs | 2 +- 10 files changed, 137 insertions(+), 102 deletions(-) diff --git a/bindings_node/CHANGELOG.md b/bindings_node/CHANGELOG.md index 426caf777..abbea749a 100644 --- a/bindings_node/CHANGELOG.md +++ b/bindings_node/CHANGELOG.md @@ -1,5 +1,9 @@ # @xmtp/node-bindings +## 0.0.22 + +- Moved `verify_signed_with_public_key` out of `Client` + ## 0.0.21 - Added `installation_id_bytes` to `Client` diff --git a/bindings_node/package.json b/bindings_node/package.json index 65db63a12..3aae68c7e 100644 --- a/bindings_node/package.json +++ b/bindings_node/package.json @@ -1,6 +1,6 @@ { "name": "@xmtp/node-bindings", - "version": "0.0.21", + "version": "0.0.22", "repository": { "type": "git", "url": "git+https://git@github.com/xmtp/libxmtp.git", diff --git a/bindings_node/src/client.rs b/bindings_node/src/client.rs index 3f042e501..2ca5f5c9f 100644 --- a/bindings_node/src/client.rs +++ b/bindings_node/src/client.rs @@ -13,7 +13,6 @@ use tracing_subscriber::{fmt, prelude::*}; pub use xmtp_api_grpc::grpc_api_helper::Client as TonicApiClient; use xmtp_cryptography::signature::ed25519_public_key_to_address; use xmtp_id::associations::builder::SignatureRequest; -use xmtp_id::associations::verify_signed_with_public_context; use xmtp_mls::builder::ClientBuilder; use xmtp_mls::groups::scoped_client::LocalScopedGroupClient; use xmtp_mls::identity::IdentityStrategy; @@ -123,7 +122,7 @@ fn init_logging(options: LogOptions) -> Result<()> { pub async fn create_client( host: String, is_secure: bool, - db_path: String, + db_path: Option, inbox_id: String, account_address: String, encryption_key: Option, @@ -135,7 +134,10 @@ pub async fn create_client( .await .map_err(|_| Error::from_reason("Error creating Tonic API client"))?; - let storage_option = StorageOption::Persistent(db_path); + let storage_option = match db_path { + Some(path) => StorageOption::Persistent(path), + None => StorageOption::Ephemeral, + }; let store = match encryption_key { Some(key) => { @@ -295,48 +297,4 @@ impl Client { .map_err(ErrorWrapper::from)?; Ok(state.into_iter().map(Into::into).collect()) } - - #[napi] - pub fn sign_with_installation_key(&self, signature_text: String) -> Result { - let result = self - .inner_client - .context() - .sign_with_public_context(signature_text) - .map_err(ErrorWrapper::from)?; - - Ok(result.into()) - } - - #[napi] - pub fn verify_signed_with_installation_key( - &self, - signature_text: String, - signature_bytes: Uint8Array, - ) -> Result<()> { - let public_key = self.inner_client().installation_public_key(); - self.verify_signed_with_public_key(signature_text, signature_bytes, public_key.into()) - } - - #[napi] - pub fn verify_signed_with_public_key( - &self, - signature_text: String, - signature_bytes: Uint8Array, - public_key: Uint8Array, - ) -> Result<()> { - let signature_bytes = signature_bytes.deref().to_vec(); - let signature_bytes: [u8; 64] = signature_bytes - .try_into() - .map_err(|_| Error::from_reason("signature_bytes is not 64 bytes long."))?; - - let public_key = public_key.deref().to_vec(); - let public_key: [u8; 32] = public_key - .try_into() - .map_err(|_| Error::from_reason("public_key is not 32 bytes long."))?; - - Ok( - verify_signed_with_public_context(signature_text, &signature_bytes, &public_key) - .map_err(ErrorWrapper::from)?, - ) - } } diff --git a/bindings_node/src/signatures.rs b/bindings_node/src/signatures.rs index 709c374ec..d32ae8e5f 100644 --- a/bindings_node/src/signatures.rs +++ b/bindings_node/src/signatures.rs @@ -5,9 +5,31 @@ use napi_derive::napi; use std::ops::Deref; use xmtp_id::associations::{ unverified::{NewUnverifiedSmartContractWalletSignature, UnverifiedSignature}, - AccountId, + verify_signed_with_public_context, AccountId, }; +#[napi] +pub fn verify_signed_with_public_key( + signature_text: String, + signature_bytes: Uint8Array, + public_key: Uint8Array, +) -> Result<()> { + let signature_bytes = signature_bytes.deref().to_vec(); + let signature_bytes: [u8; 64] = signature_bytes + .try_into() + .map_err(|_| Error::from_reason("signature_bytes is not 64 bytes long."))?; + + let public_key = public_key.deref().to_vec(); + let public_key: [u8; 32] = public_key + .try_into() + .map_err(|_| Error::from_reason("public_key is not 32 bytes long."))?; + + Ok( + verify_signed_with_public_context(signature_text, &signature_bytes, &public_key) + .map_err(ErrorWrapper::from)?, + ) +} + #[napi] #[derive(Eq, Hash, PartialEq)] pub enum SignatureRequestType { @@ -167,4 +189,25 @@ impl Client { Ok(()) } + + #[napi] + pub fn sign_with_installation_key(&self, signature_text: String) -> Result { + let result = self + .inner_client() + .context() + .sign_with_public_context(signature_text) + .map_err(ErrorWrapper::from)?; + + Ok(result.into()) + } + + #[napi] + pub fn verify_signed_with_installation_key( + &self, + signature_text: String, + signature_bytes: Uint8Array, + ) -> Result<()> { + let public_key = self.inner_client().installation_public_key(); + verify_signed_with_public_key(signature_text, signature_bytes, public_key.into()) + } } diff --git a/bindings_node/test/Client.test.ts b/bindings_node/test/Client.test.ts index 8942e7b25..ea84ea155 100644 --- a/bindings_node/test/Client.test.ts +++ b/bindings_node/test/Client.test.ts @@ -2,7 +2,12 @@ import { v4 } from 'uuid' import { toBytes } from 'viem' import { describe, expect, it } from 'vitest' import { createClient, createRegisteredClient, createUser } from '@test/helpers' -import { ConsentEntityType, ConsentState, SignatureRequestType } from '../dist' +import { + ConsentEntityType, + ConsentState, + SignatureRequestType, + verifySignedWithPublicKey, +} from '../dist' describe('Client', () => { it('should not be registered at first', async () => { @@ -224,5 +229,24 @@ describe('Client', () => { user2.account.address.toLowerCase(), ]) }) - it('should create client with structured logging', async () => {}) + + it('should sign and verify with installation key', async () => { + const user = createUser() + const client = await createRegisteredClient(user) + const text = 'gm!' + const signature = client.signWithInstallationKey(text) + expect(signature).toBeDefined() + expect(() => + client.verifySignedWithInstallationKey(text, signature) + ).not.toThrow() + expect(() => + client.verifySignedWithInstallationKey(text, new Uint8Array()) + ).toThrow() + expect(() => + verifySignedWithPublicKey(text, signature, client.installationIdBytes()) + ).not.toThrow() + expect(() => + verifySignedWithPublicKey(text, signature, new Uint8Array()) + ).toThrow() + }) }) diff --git a/bindings_wasm/CHANGELOG.md b/bindings_wasm/CHANGELOG.md index 69994bd9e..7755ac0c9 100644 --- a/bindings_wasm/CHANGELOG.md +++ b/bindings_wasm/CHANGELOG.md @@ -1,5 +1,9 @@ # @xmtp/wasm-bindings +## 0.0.7 + +- Moved `verify_signed_with_public_key` out of `Client` + ## 0.0.6 - Added `installation_id_bytes` to `Client` diff --git a/bindings_wasm/package.json b/bindings_wasm/package.json index d963f21e1..014358de6 100644 --- a/bindings_wasm/package.json +++ b/bindings_wasm/package.json @@ -1,6 +1,6 @@ { "name": "@xmtp/wasm-bindings", - "version": "0.0.6", + "version": "0.0.7", "type": "module", "license": "MIT", "description": "WASM bindings for the libXMTP rust library", diff --git a/bindings_wasm/src/client.rs b/bindings_wasm/src/client.rs index 13451ce22..be29aea38 100644 --- a/bindings_wasm/src/client.rs +++ b/bindings_wasm/src/client.rs @@ -11,7 +11,6 @@ use wasm_bindgen::JsValue; use xmtp_api_http::XmtpHttpApiClient; use xmtp_cryptography::signature::ed25519_public_key_to_address; use xmtp_id::associations::builder::SignatureRequest; -use xmtp_id::associations::verify_signed_with_public_context; use xmtp_mls::builder::ClientBuilder; use xmtp_mls::groups::scoped_client::ScopedGroupClient; use xmtp_mls::identity::IdentityStrategy; @@ -125,7 +124,7 @@ pub async fn create_client( host: String, inbox_id: String, account_address: String, - db_path: String, + db_path: Option, encryption_key: Option, history_sync_url: Option, log_options: Option, @@ -134,7 +133,10 @@ pub async fn create_client( xmtp_mls::storage::init_sqlite().await; let api_client = XmtpHttpApiClient::new(host.clone()).unwrap(); - let storage_option = StorageOption::Persistent(db_path); + let storage_option = match db_path { + Some(path) => StorageOption::Persistent(path), + None => StorageOption::Ephemeral, + }; let store = match encryption_key { Some(key) => { @@ -284,50 +286,4 @@ impl Client { pub fn conversations(&self) -> Conversations { Conversations::new(self.inner_client.clone()) } - - #[wasm_bindgen(js_name = signWithInstallationKey)] - pub fn sign_with_installation_key(&self, signature_text: String) -> Result { - let result = self - .inner_client - .context() - .sign_with_public_context(signature_text) - .map_err(|e| JsError::new(format!("{}", e).as_str()))?; - - Ok(Uint8Array::from(result.as_slice())) - } - - #[wasm_bindgen(js_name = verifySignedWithInstallationKey)] - pub fn verify_signed_with_installation_key( - &self, - signature_text: String, - signature_bytes: Uint8Array, - ) -> Result<(), JsError> { - let public_key = self.inner_client().installation_public_key(); - self.verify_signed_with_public_key( - signature_text, - signature_bytes, - Uint8Array::from(public_key.as_slice()), - ) - } - - #[wasm_bindgen(js_name = verifySignedWithPublicKey)] - pub fn verify_signed_with_public_key( - &self, - signature_text: String, - signature_bytes: Uint8Array, - public_key: Uint8Array, - ) -> Result<(), JsError> { - let signature_bytes = signature_bytes.to_vec(); - let signature_bytes: [u8; 64] = signature_bytes - .try_into() - .map_err(|_| JsError::new("signature_bytes is not 64 bytes long."))?; - - let public_key = public_key.to_vec(); - let public_key: [u8; 32] = public_key - .try_into() - .map_err(|_| JsError::new("public_key is not 32 bytes long."))?; - - verify_signed_with_public_context(signature_text, &signature_bytes, &public_key) - .map_err(|e| JsError::new(format!("{}", e).as_str())) - } } diff --git a/bindings_wasm/src/signatures.rs b/bindings_wasm/src/signatures.rs index 9fde22378..8265c88d0 100644 --- a/bindings_wasm/src/signatures.rs +++ b/bindings_wasm/src/signatures.rs @@ -1,5 +1,6 @@ use js_sys::Uint8Array; use wasm_bindgen::prelude::{wasm_bindgen, JsError}; +use xmtp_id::associations::verify_signed_with_public_context; use xmtp_id::associations::{ unverified::{NewUnverifiedSmartContractWalletSignature, UnverifiedSignature}, AccountId, @@ -7,6 +8,26 @@ use xmtp_id::associations::{ use crate::client::Client; +#[wasm_bindgen(js_name = verifySignedWithPublicKey)] +pub fn verify_signed_with_public_key( + signature_text: String, + signature_bytes: Uint8Array, + public_key: Uint8Array, +) -> Result<(), JsError> { + let signature_bytes = signature_bytes.to_vec(); + let signature_bytes: [u8; 64] = signature_bytes + .try_into() + .map_err(|_| JsError::new("signature_bytes is not 64 bytes long."))?; + + let public_key = public_key.to_vec(); + let public_key: [u8; 32] = public_key + .try_into() + .map_err(|_| JsError::new("public_key is not 32 bytes long."))?; + + verify_signed_with_public_context(signature_text, &signature_bytes, &public_key) + .map_err(|e| JsError::new(format!("{}", e).as_str())) +} + #[wasm_bindgen] #[derive(Clone, Eq, Hash, PartialEq)] pub enum SignatureRequestType { @@ -172,4 +193,29 @@ impl Client { Ok(()) } + + #[wasm_bindgen(js_name = signWithInstallationKey)] + pub fn sign_with_installation_key(&self, signature_text: String) -> Result { + let result = self + .inner_client() + .context() + .sign_with_public_context(signature_text) + .map_err(|e| JsError::new(format!("{}", e).as_str()))?; + + Ok(Uint8Array::from(result.as_slice())) + } + + #[wasm_bindgen(js_name = verifySignedWithInstallationKey)] + pub fn verify_signed_with_installation_key( + &self, + signature_text: String, + signature_bytes: Uint8Array, + ) -> Result<(), JsError> { + let public_key = self.inner_client().installation_public_key(); + verify_signed_with_public_key( + signature_text, + signature_bytes, + Uint8Array::from(public_key.as_slice()), + ) + } } diff --git a/bindings_wasm/tests/web.rs b/bindings_wasm/tests/web.rs index 32f6d02d6..afc323617 100644 --- a/bindings_wasm/tests/web.rs +++ b/bindings_wasm/tests/web.rs @@ -26,7 +26,7 @@ pub async fn test_create_client() { host.clone(), inbox_id.unwrap(), account_address.clone(), - "test".to_string(), + None, None, None, Some(LogOptions { From d27579d61f372a2996ac139d9726fd3cb1939c92 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 25 Nov 2024 16:02:22 +0000 Subject: [PATCH 05/46] Bump typescript in /bindings_node in the node-dev group (#1334) --- bindings_node/package.json | 2 +- bindings_node/yarn.lock | 18 +++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/bindings_node/package.json b/bindings_node/package.json index 3aae68c7e..83b153584 100644 --- a/bindings_node/package.json +++ b/bindings_node/package.json @@ -42,7 +42,7 @@ "@types/uuid": "^10.0.0", "prettier": "^3.3.3", "prettier-plugin-packagejson": "^2.5.3", - "typescript": "^5.6.3", + "typescript": "^5.7.2", "uuid": "^11.0.3", "viem": "^2.21.47", "vite": "^5.4.11", diff --git a/bindings_node/yarn.lock b/bindings_node/yarn.lock index 94a66d978..d81c31878 100644 --- a/bindings_node/yarn.lock +++ b/bindings_node/yarn.lock @@ -1839,7 +1839,7 @@ __metadata: "@types/uuid": "npm:^10.0.0" prettier: "npm:^3.3.3" prettier-plugin-packagejson: "npm:^2.5.3" - typescript: "npm:^5.6.3" + typescript: "npm:^5.7.2" uuid: "npm:^11.0.3" viem: "npm:^2.21.47" vite: "npm:^5.4.11" @@ -3641,23 +3641,23 @@ __metadata: languageName: node linkType: hard -"typescript@npm:^5.6.3": - version: 5.6.3 - resolution: "typescript@npm:5.6.3" +"typescript@npm:^5.7.2": + version: 5.7.2 + resolution: "typescript@npm:5.7.2" bin: tsc: bin/tsc tsserver: bin/tsserver - checksum: 10/c328e418e124b500908781d9f7b9b93cf08b66bf5936d94332b463822eea2f4e62973bfb3b8a745fdc038785cb66cf59d1092bac3ec2ac6a3e5854687f7833f1 + checksum: 10/4caa3904df69db9d4a8bedc31bafc1e19ffb7b24fbde2997a1633ae1398d0de5bdbf8daf602ccf3b23faddf1aeeb9b795223a2ed9c9a4fdcaf07bfde114a401a languageName: node linkType: hard -"typescript@patch:typescript@npm%3A^5.6.3#optional!builtin": - version: 5.6.3 - resolution: "typescript@patch:typescript@npm%3A5.6.3#optional!builtin::version=5.6.3&hash=8c6c40" +"typescript@patch:typescript@npm%3A^5.7.2#optional!builtin": + version: 5.7.2 + resolution: "typescript@patch:typescript@npm%3A5.7.2#optional!builtin::version=5.7.2&hash=cef18b" bin: tsc: bin/tsc tsserver: bin/tsserver - checksum: 10/00504c01ee42d470c23495426af07512e25e6546bce7e24572e72a9ca2e6b2e9bea63de4286c3cfea644874da1467dcfca23f4f98f7caf20f8b03c0213bb6837 + checksum: 10/ff27fc124bceb8969be722baa38af945b2505767cf794de3e2715e58f61b43780284060287d651fcbbdfb6f917f4653b20f4751991f17e0706db389b9bb3f75d languageName: node linkType: hard From 5aa0ddd5356e8b73132c1175b6858cdbd04bf2ff Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 25 Nov 2024 16:37:19 +0000 Subject: [PATCH 06/46] Nightly Protos (#1335) Co-authored-by: Martin Kysel --- xmtp_proto/src/gen/xmtp.message_contents.rs | 917 ++++----- .../src/gen/xmtp.message_contents.serde.rs | 62 + .../src/gen/xmtp.mls.message_contents.rs | 1741 +++++++++-------- 3 files changed, 1415 insertions(+), 1305 deletions(-) diff --git a/xmtp_proto/src/gen/xmtp.message_contents.rs b/xmtp_proto/src/gen/xmtp.message_contents.rs index b4ec8ba5f..9b79214ca 100644 --- a/xmtp_proto/src/gen/xmtp.message_contents.rs +++ b/xmtp_proto/src/gen/xmtp.message_contents.rs @@ -791,16 +791,27 @@ pub struct FrameActionBody { #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct FrameAction { + #[deprecated] #[prost(message, optional, tag="1")] pub signature: ::core::option::Option, /// The SignedPublicKeyBundle of the signer, used to link the XMTP signature /// with a blockchain account through a chain of signatures. + #[deprecated] #[prost(message, optional, tag="2")] pub signed_public_key_bundle: ::core::option::Option, /// Serialized FrameActionBody message, so that the signature verification can /// happen on a byte-perfect representation of the message #[prost(bytes="vec", tag="3")] pub action_body: ::prost::alloc::vec::Vec, + /// The installation signature + #[prost(bytes="vec", tag="4")] + pub installation_signature: ::prost::alloc::vec::Vec, + /// The public installation id used to sign. + #[prost(bytes="vec", tag="5")] + pub installation_id: ::prost::alloc::vec::Vec, + /// The inbox id of the installation used to sign. + #[prost(string, tag="6")] + pub inbox_id: ::prost::alloc::string::String, } // Message V1 @@ -2608,7 +2619,7 @@ pub const FILE_DESCRIPTOR_SET: &[u8] = &[ 0x0a, 0x05, 0x04, 0x00, 0x02, 0x00, 0x05, 0x12, 0x03, 0x0c, 0x04, 0x09, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x00, 0x01, 0x12, 0x03, 0x0c, 0x0a, 0x0c, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x00, 0x03, 0x12, 0x03, 0x0c, 0x0f, 0x10, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, - 0x0a, 0xd5, 0x15, 0x0a, 0x1d, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, + 0x0a, 0xb3, 0x19, 0x0a, 0x1d, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2f, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x15, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x1a, 0x21, 0x6d, 0x65, 0x73, 0x73, 0x61, @@ -2637,127 +2648,137 @@ pub const FILE_DESCRIPTOR_SET: &[u8] = &[ 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x25, 0x0a, 0x0e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, - 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x22, 0xd5, 0x01, 0x0a, 0x0b, 0x46, 0x72, 0x61, 0x6d, - 0x65, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x3e, 0x0a, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x22, 0xd8, 0x02, 0x0a, 0x0b, 0x46, 0x72, 0x61, 0x6d, + 0x65, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x42, 0x0a, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, - 0x74, 0x73, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x52, 0x09, 0x73, 0x69, - 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x12, 0x65, 0x0a, 0x18, 0x73, 0x69, 0x67, 0x6e, 0x65, - 0x64, 0x5f, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x62, 0x75, 0x6e, - 0x64, 0x6c, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x78, 0x6d, 0x74, 0x70, - 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, - 0x73, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, - 0x79, 0x42, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x52, 0x15, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x50, - 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x42, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x12, 0x1f, - 0x0a, 0x0b, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x62, 0x6f, 0x64, 0x79, 0x18, 0x03, 0x20, - 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x6f, 0x64, 0x79, 0x42, - 0xc7, 0x01, 0x0a, 0x19, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x42, 0x0b, 0x46, - 0x72, 0x61, 0x6d, 0x65, 0x73, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x2c, 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, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0xa2, 0x02, 0x03, 0x58, 0x4d, 0x58, - 0xaa, 0x02, 0x14, 0x58, 0x6d, 0x74, 0x70, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x43, - 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0xca, 0x02, 0x14, 0x58, 0x6d, 0x74, 0x70, 0x5c, 0x4d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0xe2, 0x02, - 0x20, 0x58, 0x6d, 0x74, 0x70, 0x5c, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, - 0x74, 0x65, 0x6e, 0x74, 0x73, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, - 0x61, 0xea, 0x02, 0x15, 0x58, 0x6d, 0x74, 0x70, 0x3a, 0x3a, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x4a, 0xd4, 0x0e, 0x0a, 0x06, 0x12, 0x04, - 0x01, 0x00, 0x2e, 0x01, 0x0a, 0x47, 0x0a, 0x01, 0x0c, 0x12, 0x03, 0x01, 0x00, 0x12, 0x1a, 0x3d, - 0x20, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x20, 0x69, 0x73, 0x20, 0x61, 0x20, - 0x67, 0x65, 0x6e, 0x65, 0x72, 0x69, 0x63, 0x20, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x75, 0x72, - 0x65, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x20, 0x6b, 0x65, 0x79, - 0x20, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x2e, 0x0a, 0x0a, 0x08, 0x0a, - 0x01, 0x02, 0x12, 0x03, 0x03, 0x00, 0x1e, 0x0a, 0x09, 0x0a, 0x02, 0x03, 0x00, 0x12, 0x03, 0x05, - 0x00, 0x2b, 0x0a, 0x09, 0x0a, 0x02, 0x03, 0x01, 0x12, 0x03, 0x06, 0x00, 0x2a, 0x0a, 0x08, 0x0a, - 0x01, 0x08, 0x12, 0x03, 0x08, 0x00, 0x43, 0x0a, 0x09, 0x0a, 0x02, 0x08, 0x0b, 0x12, 0x03, 0x08, - 0x00, 0x43, 0x0a, 0x83, 0x01, 0x0a, 0x02, 0x04, 0x00, 0x12, 0x04, 0x0d, 0x00, 0x22, 0x01, 0x1a, - 0x77, 0x20, 0x54, 0x68, 0x65, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x20, 0x74, 0x68, - 0x61, 0x74, 0x20, 0x77, 0x69, 0x6c, 0x6c, 0x20, 0x62, 0x65, 0x20, 0x73, 0x69, 0x67, 0x6e, 0x65, - 0x64, 0x20, 0x62, 0x79, 0x20, 0x74, 0x68, 0x65, 0x20, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x20, - 0x61, 0x6e, 0x64, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x73, - 0x69, 0x64, 0x65, 0x20, 0x74, 0x68, 0x65, 0x0a, 0x20, 0x60, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, - 0x5f, 0x62, 0x6f, 0x64, 0x79, 0x60, 0x20, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x6f, 0x66, 0x20, - 0x74, 0x68, 0x65, 0x20, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, - 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x0a, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x00, 0x01, 0x12, - 0x03, 0x0d, 0x08, 0x17, 0x0a, 0x56, 0x0a, 0x04, 0x04, 0x00, 0x02, 0x00, 0x12, 0x03, 0x10, 0x02, - 0x17, 0x1a, 0x49, 0x20, 0x54, 0x68, 0x65, 0x20, 0x55, 0x52, 0x4c, 0x20, 0x6f, 0x66, 0x20, 0x74, - 0x68, 0x65, 0x20, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x77, 0x61, - 0x73, 0x20, 0x63, 0x6c, 0x69, 0x63, 0x6b, 0x65, 0x64, 0x0a, 0x20, 0x4d, 0x61, 0x79, 0x20, 0x62, - 0x65, 0x20, 0x64, 0x69, 0x66, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x74, 0x20, 0x66, 0x72, 0x6f, 0x6d, - 0x20, 0x60, 0x70, 0x6f, 0x73, 0x74, 0x5f, 0x75, 0x72, 0x6c, 0x60, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, - 0x04, 0x00, 0x02, 0x00, 0x05, 0x12, 0x03, 0x10, 0x02, 0x08, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, - 0x02, 0x00, 0x01, 0x12, 0x03, 0x10, 0x09, 0x12, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x00, - 0x03, 0x12, 0x03, 0x10, 0x15, 0x16, 0x0a, 0x34, 0x0a, 0x04, 0x04, 0x00, 0x02, 0x01, 0x12, 0x03, - 0x12, 0x02, 0x19, 0x1a, 0x27, 0x20, 0x54, 0x68, 0x65, 0x20, 0x31, 0x2d, 0x69, 0x6e, 0x64, 0x65, - 0x78, 0x65, 0x64, 0x20, 0x62, 0x75, 0x74, 0x74, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, - 0x77, 0x61, 0x73, 0x20, 0x63, 0x6c, 0x69, 0x63, 0x6b, 0x65, 0x64, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, - 0x04, 0x00, 0x02, 0x01, 0x05, 0x12, 0x03, 0x12, 0x02, 0x07, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, - 0x02, 0x01, 0x01, 0x12, 0x03, 0x12, 0x08, 0x14, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x01, - 0x03, 0x12, 0x03, 0x12, 0x17, 0x18, 0x0a, 0x45, 0x0a, 0x04, 0x04, 0x00, 0x02, 0x02, 0x12, 0x03, - 0x14, 0x02, 0x2b, 0x1a, 0x38, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x20, - 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69, 0x63, 0x6b, 0x20, 0x69, 0x6e, 0x20, - 0x6d, 0x69, 0x6c, 0x6c, 0x69, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x20, 0x73, 0x69, 0x6e, - 0x63, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x65, 0x70, 0x6f, 0x63, 0x68, 0x0a, 0x0a, 0x0c, 0x0a, - 0x05, 0x04, 0x00, 0x02, 0x02, 0x05, 0x12, 0x03, 0x14, 0x02, 0x08, 0x0a, 0x0c, 0x0a, 0x05, 0x04, - 0x00, 0x02, 0x02, 0x01, 0x12, 0x03, 0x14, 0x09, 0x12, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, - 0x02, 0x03, 0x12, 0x03, 0x14, 0x15, 0x16, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x02, 0x08, - 0x12, 0x03, 0x14, 0x17, 0x2a, 0x0a, 0x0d, 0x0a, 0x06, 0x04, 0x00, 0x02, 0x02, 0x08, 0x03, 0x12, - 0x03, 0x14, 0x18, 0x29, 0x0a, 0x8a, 0x01, 0x0a, 0x04, 0x04, 0x00, 0x02, 0x03, 0x12, 0x03, 0x17, - 0x02, 0x2c, 0x1a, 0x7d, 0x20, 0x41, 0x20, 0x75, 0x6e, 0x69, 0x71, 0x75, 0x65, 0x20, 0x69, 0x64, - 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x74, 0x68, 0x65, - 0x20, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2c, 0x20, 0x6e, - 0x6f, 0x74, 0x20, 0x74, 0x69, 0x65, 0x64, 0x20, 0x74, 0x6f, 0x20, 0x61, 0x6e, 0x79, 0x74, 0x68, - 0x69, 0x6e, 0x67, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x0a, 0x20, 0x6e, 0x65, 0x74, 0x77, - 0x6f, 0x72, 0x6b, 0x2e, 0x20, 0x57, 0x69, 0x6c, 0x6c, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x6d, 0x61, - 0x74, 0x63, 0x68, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x20, 0x6f, 0x72, - 0x20, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, - 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x03, 0x05, 0x12, 0x03, 0x17, 0x02, 0x08, 0x0a, - 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x03, 0x01, 0x12, 0x03, 0x17, 0x09, 0x27, 0x0a, 0x0c, 0x0a, - 0x05, 0x04, 0x00, 0x02, 0x03, 0x03, 0x12, 0x03, 0x17, 0x2a, 0x2b, 0x0a, 0x1d, 0x0a, 0x04, 0x04, - 0x00, 0x02, 0x04, 0x12, 0x03, 0x19, 0x02, 0x1c, 0x1a, 0x10, 0x20, 0x55, 0x6e, 0x69, 0x78, 0x20, - 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, - 0x02, 0x04, 0x05, 0x12, 0x03, 0x19, 0x02, 0x08, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x04, - 0x01, 0x12, 0x03, 0x19, 0x09, 0x17, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x04, 0x03, 0x12, - 0x03, 0x19, 0x1a, 0x1b, 0x0a, 0x31, 0x0a, 0x04, 0x04, 0x00, 0x02, 0x05, 0x12, 0x03, 0x1b, 0x02, - 0x18, 0x1a, 0x24, 0x20, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x20, 0x74, 0x65, 0x78, 0x74, 0x20, 0x66, - 0x72, 0x6f, 0x6d, 0x20, 0x61, 0x20, 0x74, 0x65, 0x78, 0x74, 0x20, 0x69, 0x6e, 0x70, 0x75, 0x74, - 0x20, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x05, 0x05, - 0x12, 0x03, 0x1b, 0x02, 0x08, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x05, 0x01, 0x12, 0x03, - 0x1b, 0x09, 0x13, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x05, 0x03, 0x12, 0x03, 0x1b, 0x16, - 0x17, 0x0a, 0x65, 0x0a, 0x04, 0x04, 0x00, 0x02, 0x06, 0x12, 0x03, 0x1d, 0x02, 0x13, 0x1a, 0x58, - 0x20, 0x41, 0x20, 0x73, 0x74, 0x61, 0x74, 0x65, 0x20, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, - 0x7a, 0x65, 0x64, 0x20, 0x74, 0x6f, 0x20, 0x61, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x20, - 0x28, 0x66, 0x6f, 0x72, 0x20, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x20, 0x76, 0x69, 0x61, - 0x20, 0x4a, 0x53, 0x4f, 0x4e, 0x2e, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x69, 0x66, 0x79, 0x28, - 0x29, 0x29, 0x2e, 0x20, 0x4d, 0x61, 0x78, 0x69, 0x6d, 0x75, 0x6d, 0x20, 0x34, 0x30, 0x39, 0x36, - 0x20, 0x62, 0x79, 0x74, 0x65, 0x73, 0x2e, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x06, - 0x05, 0x12, 0x03, 0x1d, 0x02, 0x08, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x06, 0x01, 0x12, - 0x03, 0x1d, 0x09, 0x0e, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x06, 0x03, 0x12, 0x03, 0x1d, - 0x11, 0x12, 0x0a, 0x22, 0x0a, 0x04, 0x04, 0x00, 0x02, 0x07, 0x12, 0x03, 0x1f, 0x02, 0x15, 0x1a, - 0x15, 0x20, 0x41, 0x20, 0x30, 0x78, 0x20, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x20, 0x61, 0x64, - 0x64, 0x72, 0x65, 0x73, 0x73, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x07, 0x05, 0x12, - 0x03, 0x1f, 0x02, 0x08, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x07, 0x01, 0x12, 0x03, 0x1f, - 0x09, 0x10, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x07, 0x03, 0x12, 0x03, 0x1f, 0x13, 0x14, - 0x0a, 0x28, 0x0a, 0x04, 0x04, 0x00, 0x02, 0x08, 0x12, 0x03, 0x21, 0x02, 0x1c, 0x1a, 0x1b, 0x20, - 0x41, 0x20, 0x68, 0x61, 0x73, 0x68, 0x20, 0x66, 0x72, 0x6f, 0x6d, 0x20, 0x61, 0x20, 0x74, 0x72, - 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, - 0x02, 0x08, 0x05, 0x12, 0x03, 0x21, 0x02, 0x08, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x08, - 0x01, 0x12, 0x03, 0x21, 0x09, 0x17, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x08, 0x03, 0x12, - 0x03, 0x21, 0x1a, 0x1b, 0x0a, 0x79, 0x0a, 0x02, 0x04, 0x01, 0x12, 0x04, 0x26, 0x00, 0x2e, 0x01, - 0x1a, 0x6d, 0x20, 0x54, 0x68, 0x65, 0x20, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x20, 0x70, 0x61, 0x79, - 0x6c, 0x6f, 0x61, 0x64, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x77, 0x69, 0x6c, 0x6c, 0x20, 0x62, - 0x65, 0x20, 0x73, 0x65, 0x6e, 0x74, 0x20, 0x61, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x60, 0x6d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x42, 0x79, 0x74, 0x65, 0x73, 0x60, 0x20, 0x69, 0x6e, 0x20, - 0x74, 0x68, 0x65, 0x0a, 0x20, 0x60, 0x74, 0x72, 0x75, 0x73, 0x74, 0x65, 0x64, 0x5f, 0x64, 0x61, - 0x74, 0x61, 0x60, 0x20, 0x70, 0x61, 0x72, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, - 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x0a, 0x0a, - 0x0a, 0x0a, 0x03, 0x04, 0x01, 0x01, 0x12, 0x03, 0x26, 0x08, 0x13, 0x0a, 0x0b, 0x0a, 0x04, 0x04, - 0x01, 0x02, 0x00, 0x12, 0x03, 0x27, 0x02, 0x1a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x00, - 0x06, 0x12, 0x03, 0x27, 0x02, 0x0b, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x00, 0x01, 0x12, - 0x03, 0x27, 0x0c, 0x15, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x00, 0x03, 0x12, 0x03, 0x27, - 0x18, 0x19, 0x0a, 0x92, 0x01, 0x0a, 0x04, 0x04, 0x01, 0x02, 0x01, 0x12, 0x03, 0x2a, 0x02, 0x35, + 0x74, 0x73, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x42, 0x02, 0x18, 0x01, + 0x52, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x12, 0x69, 0x0a, 0x18, 0x73, + 0x69, 0x67, 0x6e, 0x65, 0x64, 0x5f, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x6b, 0x65, 0x79, + 0x5f, 0x62, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, + 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, + 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x50, 0x75, 0x62, 0x6c, + 0x69, 0x63, 0x4b, 0x65, 0x79, 0x42, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x42, 0x02, 0x18, 0x01, 0x52, + 0x15, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, + 0x42, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x5f, 0x62, 0x6f, 0x64, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x61, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x42, 0x6f, 0x64, 0x79, 0x12, 0x35, 0x0a, 0x16, 0x69, 0x6e, 0x73, 0x74, 0x61, + 0x6c, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, + 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x15, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x12, 0x27, + 0x0a, 0x0f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, + 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0e, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x69, 0x6e, 0x62, 0x6f, 0x78, + 0x5f, 0x69, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x69, 0x6e, 0x62, 0x6f, 0x78, + 0x49, 0x64, 0x42, 0xc7, 0x01, 0x0a, 0x19, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, + 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, + 0x42, 0x0b, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, + 0x2c, 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, 0x6d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0xa2, 0x02, 0x03, + 0x58, 0x4d, 0x58, 0xaa, 0x02, 0x14, 0x58, 0x6d, 0x74, 0x70, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0xca, 0x02, 0x14, 0x58, 0x6d, 0x74, + 0x70, 0x5c, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, + 0x73, 0xe2, 0x02, 0x20, 0x58, 0x6d, 0x74, 0x70, 0x5c, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, + 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x15, 0x58, 0x6d, 0x74, 0x70, 0x3a, 0x3a, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x4a, 0xaf, 0x11, 0x0a, + 0x06, 0x12, 0x04, 0x01, 0x00, 0x34, 0x01, 0x0a, 0x47, 0x0a, 0x01, 0x0c, 0x12, 0x03, 0x01, 0x00, + 0x12, 0x1a, 0x3d, 0x20, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x20, 0x69, 0x73, + 0x20, 0x61, 0x20, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x69, 0x63, 0x20, 0x73, 0x74, 0x72, 0x75, 0x63, + 0x74, 0x75, 0x72, 0x65, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x20, + 0x6b, 0x65, 0x79, 0x20, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x2e, 0x0a, + 0x0a, 0x08, 0x0a, 0x01, 0x02, 0x12, 0x03, 0x03, 0x00, 0x1e, 0x0a, 0x09, 0x0a, 0x02, 0x03, 0x00, + 0x12, 0x03, 0x05, 0x00, 0x2b, 0x0a, 0x09, 0x0a, 0x02, 0x03, 0x01, 0x12, 0x03, 0x06, 0x00, 0x2a, + 0x0a, 0x08, 0x0a, 0x01, 0x08, 0x12, 0x03, 0x08, 0x00, 0x43, 0x0a, 0x09, 0x0a, 0x02, 0x08, 0x0b, + 0x12, 0x03, 0x08, 0x00, 0x43, 0x0a, 0x83, 0x01, 0x0a, 0x02, 0x04, 0x00, 0x12, 0x04, 0x0d, 0x00, + 0x22, 0x01, 0x1a, 0x77, 0x20, 0x54, 0x68, 0x65, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x77, 0x69, 0x6c, 0x6c, 0x20, 0x62, 0x65, 0x20, 0x73, 0x69, + 0x67, 0x6e, 0x65, 0x64, 0x20, 0x62, 0x79, 0x20, 0x74, 0x68, 0x65, 0x20, 0x43, 0x6c, 0x69, 0x65, + 0x6e, 0x74, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x65, 0x64, 0x20, + 0x69, 0x6e, 0x73, 0x69, 0x64, 0x65, 0x20, 0x74, 0x68, 0x65, 0x0a, 0x20, 0x60, 0x61, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x5f, 0x62, 0x6f, 0x64, 0x79, 0x60, 0x20, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x20, + 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x41, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x0a, 0x0a, 0x0a, 0x0a, 0x03, 0x04, + 0x00, 0x01, 0x12, 0x03, 0x0d, 0x08, 0x17, 0x0a, 0x56, 0x0a, 0x04, 0x04, 0x00, 0x02, 0x00, 0x12, + 0x03, 0x10, 0x02, 0x17, 0x1a, 0x49, 0x20, 0x54, 0x68, 0x65, 0x20, 0x55, 0x52, 0x4c, 0x20, 0x6f, + 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x20, 0x74, 0x68, 0x61, 0x74, + 0x20, 0x77, 0x61, 0x73, 0x20, 0x63, 0x6c, 0x69, 0x63, 0x6b, 0x65, 0x64, 0x0a, 0x20, 0x4d, 0x61, + 0x79, 0x20, 0x62, 0x65, 0x20, 0x64, 0x69, 0x66, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x74, 0x20, 0x66, + 0x72, 0x6f, 0x6d, 0x20, 0x60, 0x70, 0x6f, 0x73, 0x74, 0x5f, 0x75, 0x72, 0x6c, 0x60, 0x0a, 0x0a, + 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x00, 0x05, 0x12, 0x03, 0x10, 0x02, 0x08, 0x0a, 0x0c, 0x0a, + 0x05, 0x04, 0x00, 0x02, 0x00, 0x01, 0x12, 0x03, 0x10, 0x09, 0x12, 0x0a, 0x0c, 0x0a, 0x05, 0x04, + 0x00, 0x02, 0x00, 0x03, 0x12, 0x03, 0x10, 0x15, 0x16, 0x0a, 0x34, 0x0a, 0x04, 0x04, 0x00, 0x02, + 0x01, 0x12, 0x03, 0x12, 0x02, 0x19, 0x1a, 0x27, 0x20, 0x54, 0x68, 0x65, 0x20, 0x31, 0x2d, 0x69, + 0x6e, 0x64, 0x65, 0x78, 0x65, 0x64, 0x20, 0x62, 0x75, 0x74, 0x74, 0x6f, 0x6e, 0x20, 0x74, 0x68, + 0x61, 0x74, 0x20, 0x77, 0x61, 0x73, 0x20, 0x63, 0x6c, 0x69, 0x63, 0x6b, 0x65, 0x64, 0x0a, 0x0a, + 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x01, 0x05, 0x12, 0x03, 0x12, 0x02, 0x07, 0x0a, 0x0c, 0x0a, + 0x05, 0x04, 0x00, 0x02, 0x01, 0x01, 0x12, 0x03, 0x12, 0x08, 0x14, 0x0a, 0x0c, 0x0a, 0x05, 0x04, + 0x00, 0x02, 0x01, 0x03, 0x12, 0x03, 0x12, 0x17, 0x18, 0x0a, 0x45, 0x0a, 0x04, 0x04, 0x00, 0x02, + 0x02, 0x12, 0x03, 0x14, 0x02, 0x2b, 0x1a, 0x38, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, + 0x6d, 0x70, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69, 0x63, 0x6b, 0x20, + 0x69, 0x6e, 0x20, 0x6d, 0x69, 0x6c, 0x6c, 0x69, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x20, + 0x73, 0x69, 0x6e, 0x63, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x65, 0x70, 0x6f, 0x63, 0x68, 0x0a, + 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x02, 0x05, 0x12, 0x03, 0x14, 0x02, 0x08, 0x0a, 0x0c, + 0x0a, 0x05, 0x04, 0x00, 0x02, 0x02, 0x01, 0x12, 0x03, 0x14, 0x09, 0x12, 0x0a, 0x0c, 0x0a, 0x05, + 0x04, 0x00, 0x02, 0x02, 0x03, 0x12, 0x03, 0x14, 0x15, 0x16, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, + 0x02, 0x02, 0x08, 0x12, 0x03, 0x14, 0x17, 0x2a, 0x0a, 0x0d, 0x0a, 0x06, 0x04, 0x00, 0x02, 0x02, + 0x08, 0x03, 0x12, 0x03, 0x14, 0x18, 0x29, 0x0a, 0x8a, 0x01, 0x0a, 0x04, 0x04, 0x00, 0x02, 0x03, + 0x12, 0x03, 0x17, 0x02, 0x2c, 0x1a, 0x7d, 0x20, 0x41, 0x20, 0x75, 0x6e, 0x69, 0x71, 0x75, 0x65, + 0x20, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x20, 0x66, 0x6f, 0x72, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x2c, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x74, 0x69, 0x65, 0x64, 0x20, 0x74, 0x6f, 0x20, 0x61, 0x6e, + 0x79, 0x74, 0x68, 0x69, 0x6e, 0x67, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x0a, 0x20, 0x6e, + 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x2e, 0x20, 0x57, 0x69, 0x6c, 0x6c, 0x20, 0x6e, 0x6f, 0x74, + 0x20, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x6f, 0x70, 0x69, 0x63, + 0x20, 0x6f, 0x72, 0x20, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x5f, 0x69, 0x64, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x03, 0x05, 0x12, 0x03, 0x17, + 0x02, 0x08, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x03, 0x01, 0x12, 0x03, 0x17, 0x09, 0x27, + 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x03, 0x03, 0x12, 0x03, 0x17, 0x2a, 0x2b, 0x0a, 0x1d, + 0x0a, 0x04, 0x04, 0x00, 0x02, 0x04, 0x12, 0x03, 0x19, 0x02, 0x1c, 0x1a, 0x10, 0x20, 0x55, 0x6e, + 0x69, 0x78, 0x20, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x0a, 0x0a, 0x0c, 0x0a, + 0x05, 0x04, 0x00, 0x02, 0x04, 0x05, 0x12, 0x03, 0x19, 0x02, 0x08, 0x0a, 0x0c, 0x0a, 0x05, 0x04, + 0x00, 0x02, 0x04, 0x01, 0x12, 0x03, 0x19, 0x09, 0x17, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, + 0x04, 0x03, 0x12, 0x03, 0x19, 0x1a, 0x1b, 0x0a, 0x31, 0x0a, 0x04, 0x04, 0x00, 0x02, 0x05, 0x12, + 0x03, 0x1b, 0x02, 0x18, 0x1a, 0x24, 0x20, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x20, 0x74, 0x65, 0x78, + 0x74, 0x20, 0x66, 0x72, 0x6f, 0x6d, 0x20, 0x61, 0x20, 0x74, 0x65, 0x78, 0x74, 0x20, 0x69, 0x6e, + 0x70, 0x75, 0x74, 0x20, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, + 0x02, 0x05, 0x05, 0x12, 0x03, 0x1b, 0x02, 0x08, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x05, + 0x01, 0x12, 0x03, 0x1b, 0x09, 0x13, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x05, 0x03, 0x12, + 0x03, 0x1b, 0x16, 0x17, 0x0a, 0x65, 0x0a, 0x04, 0x04, 0x00, 0x02, 0x06, 0x12, 0x03, 0x1d, 0x02, + 0x13, 0x1a, 0x58, 0x20, 0x41, 0x20, 0x73, 0x74, 0x61, 0x74, 0x65, 0x20, 0x73, 0x65, 0x72, 0x69, + 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x20, 0x74, 0x6f, 0x20, 0x61, 0x20, 0x73, 0x74, 0x72, 0x69, + 0x6e, 0x67, 0x20, 0x28, 0x66, 0x6f, 0x72, 0x20, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x20, + 0x76, 0x69, 0x61, 0x20, 0x4a, 0x53, 0x4f, 0x4e, 0x2e, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x69, + 0x66, 0x79, 0x28, 0x29, 0x29, 0x2e, 0x20, 0x4d, 0x61, 0x78, 0x69, 0x6d, 0x75, 0x6d, 0x20, 0x34, + 0x30, 0x39, 0x36, 0x20, 0x62, 0x79, 0x74, 0x65, 0x73, 0x2e, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, + 0x00, 0x02, 0x06, 0x05, 0x12, 0x03, 0x1d, 0x02, 0x08, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, + 0x06, 0x01, 0x12, 0x03, 0x1d, 0x09, 0x0e, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x06, 0x03, + 0x12, 0x03, 0x1d, 0x11, 0x12, 0x0a, 0x22, 0x0a, 0x04, 0x04, 0x00, 0x02, 0x07, 0x12, 0x03, 0x1f, + 0x02, 0x15, 0x1a, 0x15, 0x20, 0x41, 0x20, 0x30, 0x78, 0x20, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, + 0x20, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, + 0x07, 0x05, 0x12, 0x03, 0x1f, 0x02, 0x08, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x07, 0x01, + 0x12, 0x03, 0x1f, 0x09, 0x10, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x07, 0x03, 0x12, 0x03, + 0x1f, 0x13, 0x14, 0x0a, 0x28, 0x0a, 0x04, 0x04, 0x00, 0x02, 0x08, 0x12, 0x03, 0x21, 0x02, 0x1c, + 0x1a, 0x1b, 0x20, 0x41, 0x20, 0x68, 0x61, 0x73, 0x68, 0x20, 0x66, 0x72, 0x6f, 0x6d, 0x20, 0x61, + 0x20, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x0a, 0x0a, 0x0c, 0x0a, + 0x05, 0x04, 0x00, 0x02, 0x08, 0x05, 0x12, 0x03, 0x21, 0x02, 0x08, 0x0a, 0x0c, 0x0a, 0x05, 0x04, + 0x00, 0x02, 0x08, 0x01, 0x12, 0x03, 0x21, 0x09, 0x17, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, + 0x08, 0x03, 0x12, 0x03, 0x21, 0x1a, 0x1b, 0x0a, 0x79, 0x0a, 0x02, 0x04, 0x01, 0x12, 0x04, 0x26, + 0x00, 0x34, 0x01, 0x1a, 0x6d, 0x20, 0x54, 0x68, 0x65, 0x20, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x20, + 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x77, 0x69, 0x6c, + 0x6c, 0x20, 0x62, 0x65, 0x20, 0x73, 0x65, 0x6e, 0x74, 0x20, 0x61, 0x73, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x60, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x42, 0x79, 0x74, 0x65, 0x73, 0x60, 0x20, + 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x0a, 0x20, 0x60, 0x74, 0x72, 0x75, 0x73, 0x74, 0x65, 0x64, + 0x5f, 0x64, 0x61, 0x74, 0x61, 0x60, 0x20, 0x70, 0x61, 0x72, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x0a, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x01, 0x01, 0x12, 0x03, 0x26, 0x08, 0x13, 0x0a, 0x0b, + 0x0a, 0x04, 0x04, 0x01, 0x02, 0x00, 0x12, 0x03, 0x27, 0x02, 0x2e, 0x0a, 0x0c, 0x0a, 0x05, 0x04, + 0x01, 0x02, 0x00, 0x06, 0x12, 0x03, 0x27, 0x02, 0x0b, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, + 0x00, 0x01, 0x12, 0x03, 0x27, 0x0c, 0x15, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x00, 0x03, + 0x12, 0x03, 0x27, 0x18, 0x19, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x00, 0x08, 0x12, 0x03, + 0x27, 0x1a, 0x2d, 0x0a, 0x0d, 0x0a, 0x06, 0x04, 0x01, 0x02, 0x00, 0x08, 0x03, 0x12, 0x03, 0x27, + 0x1b, 0x2c, 0x0a, 0x92, 0x01, 0x0a, 0x04, 0x04, 0x01, 0x02, 0x01, 0x12, 0x03, 0x2a, 0x02, 0x49, 0x1a, 0x84, 0x01, 0x20, 0x54, 0x68, 0x65, 0x20, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x42, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x72, 0x2c, 0x20, 0x75, 0x73, 0x65, @@ -2769,325 +2790,345 @@ pub const FILE_DESCRIPTOR_SET: &[u8] = &[ 0x74, 0x75, 0x72, 0x65, 0x73, 0x2e, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x01, 0x06, 0x12, 0x03, 0x2a, 0x02, 0x17, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x01, 0x01, 0x12, 0x03, 0x2a, 0x18, 0x30, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x01, 0x03, 0x12, 0x03, 0x2a, 0x33, - 0x34, 0x0a, 0x92, 0x01, 0x0a, 0x04, 0x04, 0x01, 0x02, 0x02, 0x12, 0x03, 0x2d, 0x02, 0x18, 0x1a, - 0x84, 0x01, 0x20, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x20, 0x46, 0x72, - 0x61, 0x6d, 0x65, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x6f, 0x64, 0x79, 0x20, 0x6d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x2c, 0x20, 0x73, 0x6f, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x74, - 0x68, 0x65, 0x20, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x20, 0x76, 0x65, 0x72, - 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x63, 0x61, 0x6e, 0x0a, 0x20, 0x68, - 0x61, 0x70, 0x70, 0x65, 0x6e, 0x20, 0x6f, 0x6e, 0x20, 0x61, 0x20, 0x62, 0x79, 0x74, 0x65, 0x2d, - 0x70, 0x65, 0x72, 0x66, 0x65, 0x63, 0x74, 0x20, 0x72, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, - 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x02, 0x05, 0x12, - 0x03, 0x2d, 0x02, 0x07, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x02, 0x01, 0x12, 0x03, 0x2d, - 0x08, 0x13, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x02, 0x03, 0x12, 0x03, 0x2d, 0x16, 0x17, - 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, 0x0a, 0xb5, 0x20, 0x0a, 0x1e, 0x6d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2f, 0x6d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x15, 0x78, 0x6d, 0x74, - 0x70, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, - 0x74, 0x73, 0x1a, 0x21, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, - 0x65, 0x6e, 0x74, 0x73, 0x2f, 0x63, 0x69, 0x70, 0x68, 0x65, 0x72, 0x74, 0x65, 0x78, 0x74, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x2d, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, - 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2f, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x21, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, - 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2f, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x6b, 0x65, - 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xb5, 0x01, 0x0a, 0x0f, 0x4d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x56, 0x31, 0x12, 0x3e, 0x0a, 0x06, 0x73, - 0x65, 0x6e, 0x64, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x78, 0x6d, - 0x74, 0x70, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, - 0x6e, 0x74, 0x73, 0x2e, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x42, 0x75, 0x6e, - 0x64, 0x6c, 0x65, 0x52, 0x06, 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x12, 0x44, 0x0a, 0x09, 0x72, - 0x65, 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, - 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, - 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, - 0x42, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x52, 0x09, 0x72, 0x65, 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, - 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x22, - 0x71, 0x0a, 0x09, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x56, 0x31, 0x12, 0x21, 0x0a, 0x0c, - 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x0c, 0x52, 0x0b, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, - 0x41, 0x0a, 0x0a, 0x63, 0x69, 0x70, 0x68, 0x65, 0x72, 0x74, 0x65, 0x78, 0x74, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x43, 0x69, 0x70, 0x68, - 0x65, 0x72, 0x74, 0x65, 0x78, 0x74, 0x52, 0x0a, 0x63, 0x69, 0x70, 0x68, 0x65, 0x72, 0x74, 0x65, - 0x78, 0x74, 0x22, 0x46, 0x0a, 0x0f, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x65, 0x61, - 0x64, 0x65, 0x72, 0x56, 0x32, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, - 0x5f, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, - 0x65, 0x64, 0x4e, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x22, 0xdd, 0x01, 0x0a, 0x09, 0x4d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x56, 0x32, 0x12, 0x21, 0x0a, 0x0c, 0x68, 0x65, 0x61, 0x64, - 0x65, 0x72, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0b, - 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x41, 0x0a, 0x0a, 0x63, - 0x69, 0x70, 0x68, 0x65, 0x72, 0x74, 0x65, 0x78, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x21, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, - 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x43, 0x69, 0x70, 0x68, 0x65, 0x72, 0x74, 0x65, - 0x78, 0x74, 0x52, 0x0a, 0x63, 0x69, 0x70, 0x68, 0x65, 0x72, 0x74, 0x65, 0x78, 0x74, 0x12, 0x24, - 0x0a, 0x0b, 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x5f, 0x68, 0x6d, 0x61, 0x63, 0x18, 0x03, 0x20, - 0x01, 0x28, 0x0c, 0x48, 0x00, 0x52, 0x0a, 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x48, 0x6d, 0x61, - 0x63, 0x88, 0x01, 0x01, 0x12, 0x24, 0x0a, 0x0b, 0x73, 0x68, 0x6f, 0x75, 0x6c, 0x64, 0x5f, 0x70, - 0x75, 0x73, 0x68, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x48, 0x01, 0x52, 0x0a, 0x73, 0x68, 0x6f, - 0x75, 0x6c, 0x64, 0x50, 0x75, 0x73, 0x68, 0x88, 0x01, 0x01, 0x42, 0x0e, 0x0a, 0x0c, 0x5f, 0x73, - 0x65, 0x6e, 0x64, 0x65, 0x72, 0x5f, 0x68, 0x6d, 0x61, 0x63, 0x42, 0x0e, 0x0a, 0x0c, 0x5f, 0x73, - 0x68, 0x6f, 0x75, 0x6c, 0x64, 0x5f, 0x70, 0x75, 0x73, 0x68, 0x22, 0x7c, 0x0a, 0x07, 0x4d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x32, 0x0a, 0x02, 0x76, 0x31, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x20, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x56, 0x31, 0x48, 0x00, 0x52, 0x02, 0x76, 0x31, 0x12, 0x32, 0x0a, 0x02, 0x76, 0x32, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x4d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x56, 0x32, 0x48, 0x00, 0x52, 0x02, 0x76, 0x32, 0x42, 0x09, 0x0a, - 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0xed, 0x02, 0x0a, 0x0e, 0x44, 0x65, 0x63, - 0x6f, 0x64, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, - 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x27, 0x0a, 0x0f, 0x6d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x56, 0x65, 0x72, - 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x25, 0x0a, 0x0e, 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x5f, 0x61, - 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x73, 0x65, - 0x6e, 0x64, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x30, 0x0a, 0x11, 0x72, - 0x65, 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, - 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x10, 0x72, 0x65, 0x63, 0x69, 0x70, 0x69, - 0x65, 0x6e, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x88, 0x01, 0x01, 0x12, 0x17, 0x0a, - 0x07, 0x73, 0x65, 0x6e, 0x74, 0x5f, 0x6e, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, - 0x73, 0x65, 0x6e, 0x74, 0x4e, 0x73, 0x12, 0x23, 0x0a, 0x0d, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, - 0x74, 0x5f, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x63, - 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x54, 0x6f, 0x70, 0x69, 0x63, 0x12, 0x50, 0x0a, 0x0c, 0x63, - 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x07, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x2c, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x43, 0x6f, 0x6e, 0x76, 0x65, 0x72, - 0x73, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x52, - 0x0c, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x23, 0x0a, - 0x0d, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x08, - 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x42, 0x79, 0x74, - 0x65, 0x73, 0x42, 0x14, 0x0a, 0x12, 0x5f, 0x72, 0x65, 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, 0x74, - 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x42, 0xc8, 0x01, 0x0a, 0x19, 0x63, 0x6f, 0x6d, - 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, - 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x42, 0x0c, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x50, - 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x2c, 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, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, - 0x65, 0x6e, 0x74, 0x73, 0xa2, 0x02, 0x03, 0x58, 0x4d, 0x58, 0xaa, 0x02, 0x14, 0x58, 0x6d, 0x74, - 0x70, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, - 0x73, 0xca, 0x02, 0x14, 0x58, 0x6d, 0x74, 0x70, 0x5c, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0xe2, 0x02, 0x20, 0x58, 0x6d, 0x74, 0x70, 0x5c, - 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x5c, - 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x15, 0x58, 0x6d, - 0x74, 0x70, 0x3a, 0x3a, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, - 0x6e, 0x74, 0x73, 0x4a, 0xf2, 0x14, 0x0a, 0x06, 0x12, 0x04, 0x01, 0x00, 0x4d, 0x01, 0x0a, 0x4a, - 0x0a, 0x01, 0x0c, 0x12, 0x03, 0x01, 0x00, 0x12, 0x1a, 0x40, 0x20, 0x4d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x73, 0x20, 0x75, 0x73, 0x65, 0x64, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x74, 0x72, 0x61, - 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x73, 0x74, 0x6f, 0x72, 0x61, - 0x67, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x75, 0x73, 0x65, 0x72, 0x20, 0x63, 0x6f, 0x6e, 0x76, 0x65, - 0x72, 0x73, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x0a, 0x0a, 0x08, 0x0a, 0x01, 0x02, 0x12, - 0x03, 0x03, 0x00, 0x1e, 0x0a, 0x09, 0x0a, 0x02, 0x03, 0x00, 0x12, 0x03, 0x05, 0x00, 0x2b, 0x0a, - 0x09, 0x0a, 0x02, 0x03, 0x01, 0x12, 0x03, 0x06, 0x00, 0x37, 0x0a, 0x09, 0x0a, 0x02, 0x03, 0x02, - 0x12, 0x03, 0x07, 0x00, 0x2b, 0x0a, 0x08, 0x0a, 0x01, 0x08, 0x12, 0x03, 0x09, 0x00, 0x43, 0x0a, - 0x09, 0x0a, 0x02, 0x08, 0x0b, 0x12, 0x03, 0x09, 0x00, 0x43, 0x0a, 0x8c, 0x01, 0x0a, 0x02, 0x04, - 0x00, 0x12, 0x04, 0x10, 0x00, 0x14, 0x01, 0x1a, 0x72, 0x20, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x20, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x20, 0x69, 0x73, 0x20, 0x65, 0x6e, 0x63, 0x6f, - 0x64, 0x65, 0x64, 0x20, 0x73, 0x65, 0x70, 0x61, 0x72, 0x61, 0x74, 0x65, 0x6c, 0x79, 0x20, 0x61, - 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x79, 0x74, 0x65, 0x73, 0x20, 0x61, 0x72, 0x65, 0x20, - 0x61, 0x6c, 0x73, 0x6f, 0x20, 0x75, 0x73, 0x65, 0x64, 0x0a, 0x20, 0x61, 0x73, 0x20, 0x61, 0x73, - 0x73, 0x6f, 0x63, 0x69, 0x61, 0x74, 0x65, 0x64, 0x20, 0x64, 0x61, 0x74, 0x61, 0x20, 0x66, 0x6f, - 0x72, 0x20, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x20, - 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x0a, 0x32, 0x0c, 0x20, 0x4d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x20, 0x56, 0x31, 0x0a, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x00, 0x01, - 0x12, 0x03, 0x10, 0x08, 0x17, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x00, 0x02, 0x00, 0x12, 0x03, 0x11, - 0x02, 0x1d, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x00, 0x06, 0x12, 0x03, 0x11, 0x02, 0x11, - 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x00, 0x01, 0x12, 0x03, 0x11, 0x12, 0x18, 0x0a, 0x0c, - 0x0a, 0x05, 0x04, 0x00, 0x02, 0x00, 0x03, 0x12, 0x03, 0x11, 0x1b, 0x1c, 0x0a, 0x0b, 0x0a, 0x04, - 0x04, 0x00, 0x02, 0x01, 0x12, 0x03, 0x12, 0x02, 0x20, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, - 0x01, 0x06, 0x12, 0x03, 0x12, 0x02, 0x11, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x01, 0x01, - 0x12, 0x03, 0x12, 0x12, 0x1b, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x01, 0x03, 0x12, 0x03, - 0x12, 0x1e, 0x1f, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x00, 0x02, 0x02, 0x12, 0x03, 0x13, 0x02, 0x17, - 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x02, 0x05, 0x12, 0x03, 0x13, 0x02, 0x08, 0x0a, 0x0c, - 0x0a, 0x05, 0x04, 0x00, 0x02, 0x02, 0x01, 0x12, 0x03, 0x13, 0x09, 0x12, 0x0a, 0x0c, 0x0a, 0x05, - 0x04, 0x00, 0x02, 0x02, 0x03, 0x12, 0x03, 0x13, 0x15, 0x16, 0x0a, 0x37, 0x0a, 0x02, 0x04, 0x01, - 0x12, 0x04, 0x17, 0x00, 0x1c, 0x01, 0x1a, 0x2b, 0x20, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x6f, 0x70, 0x20, 0x6c, 0x65, 0x76, 0x65, - 0x6c, 0x20, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x20, 0x65, 0x6c, 0x65, 0x6d, 0x65, - 0x6e, 0x74, 0x0a, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x01, 0x01, 0x12, 0x03, 0x17, 0x08, 0x11, 0x0a, - 0x33, 0x0a, 0x04, 0x04, 0x01, 0x02, 0x00, 0x12, 0x03, 0x19, 0x02, 0x19, 0x1a, 0x26, 0x20, 0x65, - 0x6e, 0x63, 0x61, 0x70, 0x73, 0x75, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x20, 0x65, 0x6e, 0x63, 0x6f, - 0x64, 0x65, 0x64, 0x20, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x65, 0x61, 0x64, 0x65, - 0x72, 0x56, 0x31, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x00, 0x05, 0x12, 0x03, 0x19, - 0x02, 0x07, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x00, 0x01, 0x12, 0x03, 0x19, 0x08, 0x14, - 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x00, 0x03, 0x12, 0x03, 0x19, 0x17, 0x18, 0x0a, 0x47, - 0x0a, 0x04, 0x04, 0x01, 0x02, 0x01, 0x12, 0x03, 0x1b, 0x02, 0x1c, 0x1a, 0x3a, 0x20, 0x43, 0x69, - 0x70, 0x68, 0x65, 0x72, 0x74, 0x65, 0x78, 0x74, 0x2e, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, - 0x20, 0x4d, 0x55, 0x53, 0x54, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x20, 0x65, 0x6e, - 0x63, 0x72, 0x79, 0x70, 0x74, 0x65, 0x64, 0x20, 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x64, 0x43, - 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x01, 0x06, - 0x12, 0x03, 0x1b, 0x02, 0x0c, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x01, 0x01, 0x12, 0x03, - 0x1b, 0x0d, 0x17, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x01, 0x03, 0x12, 0x03, 0x1b, 0x1a, - 0x1b, 0x0a, 0x88, 0x02, 0x0a, 0x02, 0x04, 0x02, 0x12, 0x04, 0x24, 0x00, 0x29, 0x01, 0x1a, 0xed, - 0x01, 0x20, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x20, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, - 0x20, 0x63, 0x61, 0x72, 0x72, 0x69, 0x65, 0x73, 0x20, 0x69, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x69, 0x73, 0x20, 0x6e, 0x6f, 0x74, - 0x20, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x65, 0x64, 0x2c, 0x20, 0x61, 0x6e, 0x64, 0x20, - 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x72, 0x65, 0x66, 0x6f, 0x72, 0x65, 0x0a, 0x20, 0x6f, 0x62, - 0x73, 0x65, 0x72, 0x76, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x62, 0x79, 0x20, 0x74, 0x68, 0x65, 0x20, - 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x2e, 0x20, 0x49, 0x74, 0x20, 0x69, 0x73, 0x20, 0x68, - 0x6f, 0x77, 0x65, 0x76, 0x65, 0x72, 0x20, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, - 0x61, 0x74, 0x65, 0x64, 0x20, 0x61, 0x73, 0x20, 0x61, 0x73, 0x73, 0x6f, 0x63, 0x69, 0x61, 0x74, - 0x65, 0x64, 0x20, 0x64, 0x61, 0x74, 0x61, 0x0a, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, - 0x41, 0x45, 0x41, 0x44, 0x20, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x20, - 0x75, 0x73, 0x65, 0x64, 0x20, 0x74, 0x6f, 0x20, 0x70, 0x72, 0x6f, 0x74, 0x65, 0x63, 0x74, 0x20, - 0x74, 0x68, 0x65, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2c, 0x0a, 0x20, 0x74, 0x68, - 0x75, 0x73, 0x20, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x74, 0x61, 0x6d, - 0x70, 0x65, 0x72, 0x20, 0x65, 0x76, 0x69, 0x64, 0x65, 0x6e, 0x63, 0x65, 0x2e, 0x0a, 0x32, 0x0c, - 0x20, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x20, 0x56, 0x32, 0x0a, 0x0a, 0x0a, 0x0a, 0x03, - 0x04, 0x02, 0x01, 0x12, 0x03, 0x24, 0x08, 0x17, 0x0a, 0x35, 0x0a, 0x04, 0x04, 0x02, 0x02, 0x00, - 0x12, 0x03, 0x26, 0x02, 0x18, 0x1a, 0x28, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x20, 0x73, - 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x65, 0x64, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x20, 0x63, 0x72, 0x65, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x74, 0x69, 0x6d, 0x65, 0x0a, 0x0a, - 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x00, 0x05, 0x12, 0x03, 0x26, 0x02, 0x08, 0x0a, 0x0c, 0x0a, - 0x05, 0x04, 0x02, 0x02, 0x00, 0x01, 0x12, 0x03, 0x26, 0x09, 0x13, 0x0a, 0x0c, 0x0a, 0x05, 0x04, - 0x02, 0x02, 0x00, 0x03, 0x12, 0x03, 0x26, 0x16, 0x17, 0x0a, 0x2f, 0x0a, 0x04, 0x04, 0x02, 0x02, - 0x01, 0x12, 0x03, 0x28, 0x02, 0x13, 0x1a, 0x22, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x6f, 0x70, - 0x69, 0x63, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x20, 0x62, - 0x65, 0x6c, 0x6f, 0x6e, 0x67, 0x73, 0x20, 0x74, 0x6f, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, - 0x02, 0x01, 0x05, 0x12, 0x03, 0x28, 0x02, 0x08, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x01, - 0x01, 0x12, 0x03, 0x28, 0x09, 0x0e, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x01, 0x03, 0x12, - 0x03, 0x28, 0x11, 0x12, 0x0a, 0x4d, 0x0a, 0x02, 0x04, 0x03, 0x12, 0x04, 0x2c, 0x00, 0x37, 0x01, - 0x1a, 0x41, 0x20, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x20, 0x63, 0x6f, 0x6d, 0x62, 0x69, - 0x6e, 0x65, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x64, 0x20, - 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x74, 0x68, 0x65, 0x20, - 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x65, 0x64, 0x20, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, - 0x64, 0x2e, 0x0a, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x03, 0x01, 0x12, 0x03, 0x2c, 0x08, 0x11, 0x0a, - 0x33, 0x0a, 0x04, 0x04, 0x03, 0x02, 0x00, 0x12, 0x03, 0x2e, 0x02, 0x19, 0x1a, 0x26, 0x20, 0x65, - 0x6e, 0x63, 0x61, 0x70, 0x73, 0x75, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x20, 0x65, 0x6e, 0x63, 0x6f, - 0x64, 0x65, 0x64, 0x20, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x65, 0x61, 0x64, 0x65, - 0x72, 0x56, 0x32, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, 0x00, 0x05, 0x12, 0x03, 0x2e, - 0x02, 0x07, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, 0x00, 0x01, 0x12, 0x03, 0x2e, 0x08, 0x14, - 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, 0x00, 0x03, 0x12, 0x03, 0x2e, 0x17, 0x18, 0x0a, 0x46, - 0x0a, 0x04, 0x04, 0x03, 0x02, 0x01, 0x12, 0x03, 0x30, 0x02, 0x1c, 0x1a, 0x39, 0x20, 0x43, 0x69, - 0x70, 0x68, 0x65, 0x72, 0x74, 0x65, 0x78, 0x74, 0x2e, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, - 0x20, 0x4d, 0x55, 0x53, 0x54, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x20, 0x65, 0x6e, - 0x63, 0x72, 0x79, 0x70, 0x74, 0x65, 0x64, 0x20, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x43, 0x6f, - 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, 0x01, 0x06, 0x12, - 0x03, 0x30, 0x02, 0x0c, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, 0x01, 0x01, 0x12, 0x03, 0x30, - 0x0d, 0x17, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, 0x01, 0x03, 0x12, 0x03, 0x30, 0x1a, 0x1b, - 0x0a, 0x5c, 0x0a, 0x04, 0x04, 0x03, 0x02, 0x02, 0x12, 0x03, 0x33, 0x02, 0x21, 0x1a, 0x4f, 0x20, - 0x48, 0x4d, 0x41, 0x43, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x20, 0x63, 0x69, 0x70, 0x68, 0x65, 0x72, 0x74, 0x65, 0x78, 0x74, 0x2c, 0x20, - 0x77, 0x69, 0x74, 0x68, 0x20, 0x74, 0x68, 0x65, 0x20, 0x48, 0x4d, 0x41, 0x43, 0x20, 0x6b, 0x65, - 0x79, 0x20, 0x64, 0x65, 0x72, 0x69, 0x76, 0x65, 0x64, 0x20, 0x66, 0x72, 0x6f, 0x6d, 0x20, 0x74, - 0x68, 0x65, 0x20, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x0a, 0x20, 0x6b, 0x65, 0x79, 0x0a, 0x0a, 0x0c, - 0x0a, 0x05, 0x04, 0x03, 0x02, 0x02, 0x04, 0x12, 0x03, 0x33, 0x02, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, - 0x04, 0x03, 0x02, 0x02, 0x05, 0x12, 0x03, 0x33, 0x0b, 0x10, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, - 0x02, 0x02, 0x01, 0x12, 0x03, 0x33, 0x11, 0x1c, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, 0x02, - 0x03, 0x12, 0x03, 0x33, 0x1f, 0x20, 0x0a, 0x5f, 0x0a, 0x04, 0x04, 0x03, 0x02, 0x03, 0x12, 0x03, - 0x36, 0x02, 0x20, 0x1a, 0x52, 0x20, 0x46, 0x6c, 0x61, 0x67, 0x20, 0x69, 0x6e, 0x64, 0x69, 0x63, - 0x61, 0x74, 0x69, 0x6e, 0x67, 0x20, 0x77, 0x68, 0x65, 0x74, 0x68, 0x65, 0x72, 0x20, 0x74, 0x68, - 0x65, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x20, 0x73, 0x68, 0x6f, 0x75, 0x6c, 0x64, - 0x20, 0x62, 0x65, 0x20, 0x70, 0x75, 0x73, 0x68, 0x65, 0x64, 0x20, 0x66, 0x72, 0x6f, 0x6d, 0x20, - 0x61, 0x20, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x0a, 0x20, - 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, 0x03, 0x04, - 0x12, 0x03, 0x36, 0x02, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, 0x03, 0x05, 0x12, 0x03, - 0x36, 0x0b, 0x0f, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, 0x03, 0x01, 0x12, 0x03, 0x36, 0x10, - 0x1b, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, 0x03, 0x03, 0x12, 0x03, 0x36, 0x1e, 0x1f, 0x0a, - 0x1f, 0x0a, 0x02, 0x04, 0x04, 0x12, 0x04, 0x3a, 0x00, 0x3f, 0x01, 0x1a, 0x13, 0x20, 0x56, 0x65, - 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x64, 0x20, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x0a, - 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x04, 0x01, 0x12, 0x03, 0x3a, 0x08, 0x0f, 0x0a, 0x0c, 0x0a, 0x04, - 0x04, 0x04, 0x08, 0x00, 0x12, 0x04, 0x3b, 0x02, 0x3e, 0x03, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, - 0x08, 0x00, 0x01, 0x12, 0x03, 0x3b, 0x08, 0x0f, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x04, 0x02, 0x00, - 0x12, 0x03, 0x3c, 0x04, 0x15, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x02, 0x00, 0x06, 0x12, 0x03, - 0x3c, 0x04, 0x0d, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x02, 0x00, 0x01, 0x12, 0x03, 0x3c, 0x0e, - 0x10, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x02, 0x00, 0x03, 0x12, 0x03, 0x3c, 0x13, 0x14, 0x0a, - 0x0b, 0x0a, 0x04, 0x04, 0x04, 0x02, 0x01, 0x12, 0x03, 0x3d, 0x04, 0x15, 0x0a, 0x0c, 0x0a, 0x05, - 0x04, 0x04, 0x02, 0x01, 0x06, 0x12, 0x03, 0x3d, 0x04, 0x0d, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, - 0x02, 0x01, 0x01, 0x12, 0x03, 0x3d, 0x0e, 0x10, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x02, 0x01, - 0x03, 0x12, 0x03, 0x3d, 0x13, 0x14, 0x0a, 0xae, 0x01, 0x0a, 0x02, 0x04, 0x05, 0x12, 0x04, 0x44, - 0x00, 0x4d, 0x01, 0x1a, 0xa1, 0x01, 0x20, 0x44, 0x65, 0x63, 0x6f, 0x64, 0x65, 0x64, 0x4d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x20, 0x72, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x73, - 0x20, 0x74, 0x68, 0x65, 0x20, 0x64, 0x65, 0x63, 0x72, 0x79, 0x70, 0x74, 0x65, 0x64, 0x20, 0x6d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, - 0x0a, 0x20, 0x44, 0x65, 0x63, 0x6f, 0x64, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x20, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x20, 0x61, 0x72, 0x65, 0x20, 0x6e, - 0x6f, 0x74, 0x20, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x64, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, - 0x20, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x2c, 0x20, 0x62, 0x75, 0x74, 0x0a, 0x20, 0x6d, - 0x61, 0x79, 0x20, 0x62, 0x65, 0x20, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x64, - 0x20, 0x61, 0x6e, 0x64, 0x20, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x64, 0x20, 0x62, 0x79, 0x20, 0x63, - 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x73, 0x0a, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x05, 0x01, 0x12, 0x03, - 0x44, 0x08, 0x16, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x05, 0x02, 0x00, 0x12, 0x03, 0x45, 0x02, 0x10, - 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x05, 0x02, 0x00, 0x05, 0x12, 0x03, 0x45, 0x02, 0x08, 0x0a, 0x0c, - 0x0a, 0x05, 0x04, 0x05, 0x02, 0x00, 0x01, 0x12, 0x03, 0x45, 0x09, 0x0b, 0x0a, 0x0c, 0x0a, 0x05, - 0x04, 0x05, 0x02, 0x00, 0x03, 0x12, 0x03, 0x45, 0x0e, 0x0f, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x05, - 0x02, 0x01, 0x12, 0x03, 0x46, 0x02, 0x1d, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x05, 0x02, 0x01, 0x05, - 0x12, 0x03, 0x46, 0x02, 0x08, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x05, 0x02, 0x01, 0x01, 0x12, 0x03, - 0x46, 0x09, 0x18, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x05, 0x02, 0x01, 0x03, 0x12, 0x03, 0x46, 0x1b, - 0x1c, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x05, 0x02, 0x02, 0x12, 0x03, 0x47, 0x02, 0x1c, 0x0a, 0x0c, - 0x0a, 0x05, 0x04, 0x05, 0x02, 0x02, 0x05, 0x12, 0x03, 0x47, 0x02, 0x08, 0x0a, 0x0c, 0x0a, 0x05, - 0x04, 0x05, 0x02, 0x02, 0x01, 0x12, 0x03, 0x47, 0x09, 0x17, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x05, - 0x02, 0x02, 0x03, 0x12, 0x03, 0x47, 0x1a, 0x1b, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x05, 0x02, 0x03, - 0x12, 0x03, 0x48, 0x02, 0x28, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x05, 0x02, 0x03, 0x04, 0x12, 0x03, - 0x48, 0x02, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x05, 0x02, 0x03, 0x05, 0x12, 0x03, 0x48, 0x0b, - 0x11, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x05, 0x02, 0x03, 0x01, 0x12, 0x03, 0x48, 0x12, 0x23, 0x0a, - 0x0c, 0x0a, 0x05, 0x04, 0x05, 0x02, 0x03, 0x03, 0x12, 0x03, 0x48, 0x26, 0x27, 0x0a, 0x0b, 0x0a, - 0x04, 0x04, 0x05, 0x02, 0x04, 0x12, 0x03, 0x49, 0x02, 0x15, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x05, - 0x02, 0x04, 0x05, 0x12, 0x03, 0x49, 0x02, 0x08, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x05, 0x02, 0x04, - 0x01, 0x12, 0x03, 0x49, 0x09, 0x10, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x05, 0x02, 0x04, 0x03, 0x12, - 0x03, 0x49, 0x13, 0x14, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x05, 0x02, 0x05, 0x12, 0x03, 0x4a, 0x02, - 0x1b, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x05, 0x02, 0x05, 0x05, 0x12, 0x03, 0x4a, 0x02, 0x08, 0x0a, - 0x0c, 0x0a, 0x05, 0x04, 0x05, 0x02, 0x05, 0x01, 0x12, 0x03, 0x4a, 0x09, 0x16, 0x0a, 0x0c, 0x0a, - 0x05, 0x04, 0x05, 0x02, 0x05, 0x03, 0x12, 0x03, 0x4a, 0x19, 0x1a, 0x0a, 0x0b, 0x0a, 0x04, 0x04, - 0x05, 0x02, 0x06, 0x12, 0x03, 0x4b, 0x02, 0x29, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x05, 0x02, 0x06, - 0x06, 0x12, 0x03, 0x4b, 0x02, 0x17, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x05, 0x02, 0x06, 0x01, 0x12, - 0x03, 0x4b, 0x18, 0x24, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x05, 0x02, 0x06, 0x03, 0x12, 0x03, 0x4b, - 0x27, 0x28, 0x0a, 0x2a, 0x0a, 0x04, 0x04, 0x05, 0x02, 0x07, 0x12, 0x03, 0x4c, 0x02, 0x1a, 0x22, - 0x1d, 0x20, 0x65, 0x6e, 0x63, 0x61, 0x70, 0x73, 0x75, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x20, 0x45, - 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x64, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x0a, 0x0a, 0x0c, - 0x0a, 0x05, 0x04, 0x05, 0x02, 0x07, 0x05, 0x12, 0x03, 0x4c, 0x02, 0x07, 0x0a, 0x0c, 0x0a, 0x05, - 0x04, 0x05, 0x02, 0x07, 0x01, 0x12, 0x03, 0x4c, 0x08, 0x15, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x05, - 0x02, 0x07, 0x03, 0x12, 0x03, 0x4c, 0x18, 0x19, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, - 0x0a, 0xe0, 0x05, 0x0a, 0x25, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, - 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2f, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x5f, 0x70, 0x61, 0x79, - 0x6c, 0x6f, 0x61, 0x64, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x15, 0x78, 0x6d, 0x74, 0x70, - 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, - 0x73, 0x1a, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, - 0x6e, 0x74, 0x73, 0x2f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x22, 0x69, 0x0a, 0x0d, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x50, 0x61, 0x79, - 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x3e, - 0x0a, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x20, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, - 0x75, 0x72, 0x65, 0x52, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x42, 0xce, - 0x01, 0x0a, 0x19, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x42, 0x12, 0x53, 0x69, - 0x67, 0x6e, 0x65, 0x64, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x50, 0x72, 0x6f, 0x74, 0x6f, - 0x50, 0x01, 0x5a, 0x2c, 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, + 0x34, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x01, 0x08, 0x12, 0x03, 0x2a, 0x35, 0x48, 0x0a, + 0x0d, 0x0a, 0x06, 0x04, 0x01, 0x02, 0x01, 0x08, 0x03, 0x12, 0x03, 0x2a, 0x36, 0x47, 0x0a, 0x92, + 0x01, 0x0a, 0x04, 0x04, 0x01, 0x02, 0x02, 0x12, 0x03, 0x2d, 0x02, 0x18, 0x1a, 0x84, 0x01, 0x20, + 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x20, 0x46, 0x72, 0x61, 0x6d, 0x65, + 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x6f, 0x64, 0x79, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x2c, 0x20, 0x73, 0x6f, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x20, 0x76, 0x65, 0x72, 0x69, 0x66, 0x69, + 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x63, 0x61, 0x6e, 0x0a, 0x20, 0x68, 0x61, 0x70, 0x70, + 0x65, 0x6e, 0x20, 0x6f, 0x6e, 0x20, 0x61, 0x20, 0x62, 0x79, 0x74, 0x65, 0x2d, 0x70, 0x65, 0x72, + 0x66, 0x65, 0x63, 0x74, 0x20, 0x72, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x02, 0x05, 0x12, 0x03, 0x2d, 0x02, + 0x07, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x02, 0x01, 0x12, 0x03, 0x2d, 0x08, 0x13, 0x0a, + 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x02, 0x03, 0x12, 0x03, 0x2d, 0x16, 0x17, 0x0a, 0x29, 0x0a, + 0x04, 0x04, 0x01, 0x02, 0x03, 0x12, 0x03, 0x2f, 0x02, 0x23, 0x1a, 0x1c, 0x20, 0x54, 0x68, 0x65, + 0x20, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x73, 0x69, + 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x03, + 0x05, 0x12, 0x03, 0x2f, 0x02, 0x07, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x03, 0x01, 0x12, + 0x03, 0x2f, 0x08, 0x1e, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x03, 0x03, 0x12, 0x03, 0x2f, + 0x21, 0x22, 0x0a, 0x37, 0x0a, 0x04, 0x04, 0x01, 0x02, 0x04, 0x12, 0x03, 0x31, 0x02, 0x1c, 0x1a, + 0x2a, 0x20, 0x54, 0x68, 0x65, 0x20, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x20, 0x69, 0x6e, 0x73, + 0x74, 0x61, 0x6c, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x69, 0x64, 0x20, 0x75, 0x73, 0x65, + 0x64, 0x20, 0x74, 0x6f, 0x20, 0x73, 0x69, 0x67, 0x6e, 0x2e, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, + 0x01, 0x02, 0x04, 0x05, 0x12, 0x03, 0x31, 0x02, 0x07, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, + 0x04, 0x01, 0x12, 0x03, 0x31, 0x08, 0x17, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x04, 0x03, + 0x12, 0x03, 0x31, 0x1a, 0x1b, 0x0a, 0x3d, 0x0a, 0x04, 0x04, 0x01, 0x02, 0x05, 0x12, 0x03, 0x33, + 0x02, 0x16, 0x1a, 0x30, 0x20, 0x54, 0x68, 0x65, 0x20, 0x69, 0x6e, 0x62, 0x6f, 0x78, 0x20, 0x69, + 0x64, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x75, 0x73, 0x65, 0x64, 0x20, 0x74, 0x6f, 0x20, 0x73, 0x69, + 0x67, 0x6e, 0x2e, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x05, 0x05, 0x12, 0x03, 0x33, + 0x02, 0x08, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x05, 0x01, 0x12, 0x03, 0x33, 0x09, 0x11, + 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x05, 0x03, 0x12, 0x03, 0x33, 0x14, 0x15, 0x62, 0x06, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, 0x0a, 0xb5, 0x20, 0x0a, 0x1e, 0x6d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2f, 0x6d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x15, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, - 0xa2, 0x02, 0x03, 0x58, 0x4d, 0x58, 0xaa, 0x02, 0x14, 0x58, 0x6d, 0x74, 0x70, 0x2e, 0x4d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0xca, 0x02, 0x14, - 0x58, 0x6d, 0x74, 0x70, 0x5c, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x74, - 0x65, 0x6e, 0x74, 0x73, 0xe2, 0x02, 0x20, 0x58, 0x6d, 0x74, 0x70, 0x5c, 0x4d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x5c, 0x47, 0x50, 0x42, 0x4d, - 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x15, 0x58, 0x6d, 0x74, 0x70, 0x3a, 0x3a, - 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x4a, - 0xb9, 0x02, 0x0a, 0x06, 0x12, 0x04, 0x01, 0x00, 0x0e, 0x01, 0x0a, 0x43, 0x0a, 0x01, 0x0c, 0x12, - 0x03, 0x01, 0x00, 0x12, 0x1a, 0x39, 0x20, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, - 0x20, 0x69, 0x73, 0x20, 0x61, 0x20, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x69, 0x63, 0x20, 0x73, 0x74, - 0x72, 0x75, 0x63, 0x74, 0x75, 0x72, 0x65, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x73, 0x69, 0x67, 0x6e, - 0x65, 0x64, 0x20, 0x62, 0x79, 0x74, 0x65, 0x20, 0x61, 0x72, 0x72, 0x61, 0x79, 0x73, 0x0a, 0x0a, - 0x08, 0x0a, 0x01, 0x02, 0x12, 0x03, 0x03, 0x00, 0x1e, 0x0a, 0x09, 0x0a, 0x02, 0x03, 0x00, 0x12, - 0x03, 0x05, 0x00, 0x2a, 0x0a, 0x08, 0x0a, 0x01, 0x08, 0x12, 0x03, 0x07, 0x00, 0x43, 0x0a, 0x09, - 0x0a, 0x02, 0x08, 0x0b, 0x12, 0x03, 0x07, 0x00, 0x43, 0x0a, 0x46, 0x0a, 0x02, 0x04, 0x00, 0x12, - 0x04, 0x0b, 0x00, 0x0e, 0x01, 0x1a, 0x3a, 0x20, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x50, 0x61, - 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x20, 0x69, 0x73, 0x20, 0x61, 0x20, 0x77, 0x72, 0x61, 0x70, 0x70, - 0x65, 0x72, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x61, 0x20, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, - 0x72, 0x65, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x61, 0x20, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, - 0x0a, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x00, 0x01, 0x12, 0x03, 0x0b, 0x08, 0x15, 0x0a, 0x0b, 0x0a, - 0x04, 0x04, 0x00, 0x02, 0x00, 0x12, 0x03, 0x0c, 0x02, 0x14, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, - 0x02, 0x00, 0x05, 0x12, 0x03, 0x0c, 0x02, 0x07, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x00, - 0x01, 0x12, 0x03, 0x0c, 0x08, 0x0f, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x00, 0x03, 0x12, - 0x03, 0x0c, 0x12, 0x13, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x00, 0x02, 0x01, 0x12, 0x03, 0x0d, 0x02, - 0x1a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x01, 0x06, 0x12, 0x03, 0x0d, 0x02, 0x0b, 0x0a, - 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x01, 0x01, 0x12, 0x03, 0x0d, 0x0c, 0x15, 0x0a, 0x0c, 0x0a, - 0x05, 0x04, 0x00, 0x02, 0x01, 0x03, 0x12, 0x03, 0x0d, 0x18, 0x19, 0x62, 0x06, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x33, + 0x1a, 0x21, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, + 0x74, 0x73, 0x2f, 0x63, 0x69, 0x70, 0x68, 0x65, 0x72, 0x74, 0x65, 0x78, 0x74, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x1a, 0x2d, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, + 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2f, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x5f, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x1a, 0x21, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, + 0x65, 0x6e, 0x74, 0x73, 0x2f, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x6b, 0x65, 0x79, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xb5, 0x01, 0x0a, 0x0f, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x56, 0x31, 0x12, 0x3e, 0x0a, 0x06, 0x73, 0x65, 0x6e, + 0x64, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x78, 0x6d, 0x74, 0x70, + 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, + 0x73, 0x2e, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x42, 0x75, 0x6e, 0x64, 0x6c, + 0x65, 0x52, 0x06, 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x12, 0x44, 0x0a, 0x09, 0x72, 0x65, 0x63, + 0x69, 0x70, 0x69, 0x65, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x78, + 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, + 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x42, 0x75, + 0x6e, 0x64, 0x6c, 0x65, 0x52, 0x09, 0x72, 0x65, 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, 0x74, 0x12, + 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x04, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x22, 0x71, 0x0a, + 0x09, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x56, 0x31, 0x12, 0x21, 0x0a, 0x0c, 0x68, 0x65, + 0x61, 0x64, 0x65, 0x72, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, + 0x52, 0x0b, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x41, 0x0a, + 0x0a, 0x63, 0x69, 0x70, 0x68, 0x65, 0x72, 0x74, 0x65, 0x78, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x21, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x43, 0x69, 0x70, 0x68, 0x65, 0x72, + 0x74, 0x65, 0x78, 0x74, 0x52, 0x0a, 0x63, 0x69, 0x70, 0x68, 0x65, 0x72, 0x74, 0x65, 0x78, 0x74, + 0x22, 0x46, 0x0a, 0x0f, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x65, 0x61, 0x64, 0x65, + 0x72, 0x56, 0x32, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x6e, + 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, + 0x4e, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x05, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x22, 0xdd, 0x01, 0x0a, 0x09, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x56, 0x32, 0x12, 0x21, 0x0a, 0x0c, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, + 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0b, 0x68, 0x65, + 0x61, 0x64, 0x65, 0x72, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x41, 0x0a, 0x0a, 0x63, 0x69, 0x70, + 0x68, 0x65, 0x72, 0x74, 0x65, 0x78, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, + 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, + 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x43, 0x69, 0x70, 0x68, 0x65, 0x72, 0x74, 0x65, 0x78, 0x74, + 0x52, 0x0a, 0x63, 0x69, 0x70, 0x68, 0x65, 0x72, 0x74, 0x65, 0x78, 0x74, 0x12, 0x24, 0x0a, 0x0b, + 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x5f, 0x68, 0x6d, 0x61, 0x63, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x0c, 0x48, 0x00, 0x52, 0x0a, 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x48, 0x6d, 0x61, 0x63, 0x88, + 0x01, 0x01, 0x12, 0x24, 0x0a, 0x0b, 0x73, 0x68, 0x6f, 0x75, 0x6c, 0x64, 0x5f, 0x70, 0x75, 0x73, + 0x68, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x48, 0x01, 0x52, 0x0a, 0x73, 0x68, 0x6f, 0x75, 0x6c, + 0x64, 0x50, 0x75, 0x73, 0x68, 0x88, 0x01, 0x01, 0x42, 0x0e, 0x0a, 0x0c, 0x5f, 0x73, 0x65, 0x6e, + 0x64, 0x65, 0x72, 0x5f, 0x68, 0x6d, 0x61, 0x63, 0x42, 0x0e, 0x0a, 0x0c, 0x5f, 0x73, 0x68, 0x6f, + 0x75, 0x6c, 0x64, 0x5f, 0x70, 0x75, 0x73, 0x68, 0x22, 0x7c, 0x0a, 0x07, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x12, 0x32, 0x0a, 0x02, 0x76, 0x31, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x20, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, + 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x56, + 0x31, 0x48, 0x00, 0x52, 0x02, 0x76, 0x31, 0x12, 0x32, 0x0a, 0x02, 0x76, 0x32, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x56, 0x32, 0x48, 0x00, 0x52, 0x02, 0x76, 0x32, 0x42, 0x09, 0x0a, 0x07, 0x76, + 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0xed, 0x02, 0x0a, 0x0e, 0x44, 0x65, 0x63, 0x6f, 0x64, + 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x27, 0x0a, 0x0f, 0x6d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, + 0x6f, 0x6e, 0x12, 0x25, 0x0a, 0x0e, 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x5f, 0x61, 0x64, 0x64, + 0x72, 0x65, 0x73, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x73, 0x65, 0x6e, 0x64, + 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x30, 0x0a, 0x11, 0x72, 0x65, 0x63, + 0x69, 0x70, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x10, 0x72, 0x65, 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, + 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x88, 0x01, 0x01, 0x12, 0x17, 0x0a, 0x07, 0x73, + 0x65, 0x6e, 0x74, 0x5f, 0x6e, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x73, 0x65, + 0x6e, 0x74, 0x4e, 0x73, 0x12, 0x23, 0x0a, 0x0d, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x5f, + 0x74, 0x6f, 0x70, 0x69, 0x63, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x63, 0x6f, 0x6e, + 0x74, 0x65, 0x6e, 0x74, 0x54, 0x6f, 0x70, 0x69, 0x63, 0x12, 0x50, 0x0a, 0x0c, 0x63, 0x6f, 0x6e, + 0x76, 0x65, 0x72, 0x73, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x2c, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, + 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x43, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x52, 0x0c, 0x63, + 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x23, 0x0a, 0x0d, 0x63, + 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x08, 0x20, 0x01, + 0x28, 0x0c, 0x52, 0x0c, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x42, 0x79, 0x74, 0x65, 0x73, + 0x42, 0x14, 0x0a, 0x12, 0x5f, 0x72, 0x65, 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x61, + 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x42, 0xc8, 0x01, 0x0a, 0x19, 0x63, 0x6f, 0x6d, 0x2e, 0x78, + 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, + 0x65, 0x6e, 0x74, 0x73, 0x42, 0x0c, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x50, 0x72, 0x6f, + 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x2c, 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, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, + 0x74, 0x73, 0xa2, 0x02, 0x03, 0x58, 0x4d, 0x58, 0xaa, 0x02, 0x14, 0x58, 0x6d, 0x74, 0x70, 0x2e, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0xca, + 0x02, 0x14, 0x58, 0x6d, 0x74, 0x70, 0x5c, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x43, 0x6f, + 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0xe2, 0x02, 0x20, 0x58, 0x6d, 0x74, 0x70, 0x5c, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x5c, 0x47, 0x50, + 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x15, 0x58, 0x6d, 0x74, 0x70, + 0x3a, 0x3a, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, + 0x73, 0x4a, 0xf2, 0x14, 0x0a, 0x06, 0x12, 0x04, 0x01, 0x00, 0x4d, 0x01, 0x0a, 0x4a, 0x0a, 0x01, + 0x0c, 0x12, 0x03, 0x01, 0x00, 0x12, 0x1a, 0x40, 0x20, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x73, 0x20, 0x75, 0x73, 0x65, 0x64, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x74, 0x72, 0x61, 0x6e, 0x73, + 0x70, 0x6f, 0x72, 0x74, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, + 0x20, 0x6f, 0x66, 0x20, 0x75, 0x73, 0x65, 0x72, 0x20, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x0a, 0x0a, 0x08, 0x0a, 0x01, 0x02, 0x12, 0x03, 0x03, + 0x00, 0x1e, 0x0a, 0x09, 0x0a, 0x02, 0x03, 0x00, 0x12, 0x03, 0x05, 0x00, 0x2b, 0x0a, 0x09, 0x0a, + 0x02, 0x03, 0x01, 0x12, 0x03, 0x06, 0x00, 0x37, 0x0a, 0x09, 0x0a, 0x02, 0x03, 0x02, 0x12, 0x03, + 0x07, 0x00, 0x2b, 0x0a, 0x08, 0x0a, 0x01, 0x08, 0x12, 0x03, 0x09, 0x00, 0x43, 0x0a, 0x09, 0x0a, + 0x02, 0x08, 0x0b, 0x12, 0x03, 0x09, 0x00, 0x43, 0x0a, 0x8c, 0x01, 0x0a, 0x02, 0x04, 0x00, 0x12, + 0x04, 0x10, 0x00, 0x14, 0x01, 0x1a, 0x72, 0x20, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x20, + 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x20, 0x69, 0x73, 0x20, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x65, + 0x64, 0x20, 0x73, 0x65, 0x70, 0x61, 0x72, 0x61, 0x74, 0x65, 0x6c, 0x79, 0x20, 0x61, 0x73, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x62, 0x79, 0x74, 0x65, 0x73, 0x20, 0x61, 0x72, 0x65, 0x20, 0x61, 0x6c, + 0x73, 0x6f, 0x20, 0x75, 0x73, 0x65, 0x64, 0x0a, 0x20, 0x61, 0x73, 0x20, 0x61, 0x73, 0x73, 0x6f, + 0x63, 0x69, 0x61, 0x74, 0x65, 0x64, 0x20, 0x64, 0x61, 0x74, 0x61, 0x20, 0x66, 0x6f, 0x72, 0x20, + 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x20, 0x65, 0x6e, + 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x0a, 0x32, 0x0c, 0x20, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x20, 0x56, 0x31, 0x0a, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x00, 0x01, 0x12, 0x03, + 0x10, 0x08, 0x17, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x00, 0x02, 0x00, 0x12, 0x03, 0x11, 0x02, 0x1d, + 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x00, 0x06, 0x12, 0x03, 0x11, 0x02, 0x11, 0x0a, 0x0c, + 0x0a, 0x05, 0x04, 0x00, 0x02, 0x00, 0x01, 0x12, 0x03, 0x11, 0x12, 0x18, 0x0a, 0x0c, 0x0a, 0x05, + 0x04, 0x00, 0x02, 0x00, 0x03, 0x12, 0x03, 0x11, 0x1b, 0x1c, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x00, + 0x02, 0x01, 0x12, 0x03, 0x12, 0x02, 0x20, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x01, 0x06, + 0x12, 0x03, 0x12, 0x02, 0x11, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x01, 0x01, 0x12, 0x03, + 0x12, 0x12, 0x1b, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x01, 0x03, 0x12, 0x03, 0x12, 0x1e, + 0x1f, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x00, 0x02, 0x02, 0x12, 0x03, 0x13, 0x02, 0x17, 0x0a, 0x0c, + 0x0a, 0x05, 0x04, 0x00, 0x02, 0x02, 0x05, 0x12, 0x03, 0x13, 0x02, 0x08, 0x0a, 0x0c, 0x0a, 0x05, + 0x04, 0x00, 0x02, 0x02, 0x01, 0x12, 0x03, 0x13, 0x09, 0x12, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, + 0x02, 0x02, 0x03, 0x12, 0x03, 0x13, 0x15, 0x16, 0x0a, 0x37, 0x0a, 0x02, 0x04, 0x01, 0x12, 0x04, + 0x17, 0x00, 0x1c, 0x01, 0x1a, 0x2b, 0x20, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x20, 0x69, + 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x6f, 0x70, 0x20, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x20, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x20, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, + 0x0a, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x01, 0x01, 0x12, 0x03, 0x17, 0x08, 0x11, 0x0a, 0x33, 0x0a, + 0x04, 0x04, 0x01, 0x02, 0x00, 0x12, 0x03, 0x19, 0x02, 0x19, 0x1a, 0x26, 0x20, 0x65, 0x6e, 0x63, + 0x61, 0x70, 0x73, 0x75, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x20, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x65, + 0x64, 0x20, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x56, + 0x31, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x00, 0x05, 0x12, 0x03, 0x19, 0x02, 0x07, + 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x00, 0x01, 0x12, 0x03, 0x19, 0x08, 0x14, 0x0a, 0x0c, + 0x0a, 0x05, 0x04, 0x01, 0x02, 0x00, 0x03, 0x12, 0x03, 0x19, 0x17, 0x18, 0x0a, 0x47, 0x0a, 0x04, + 0x04, 0x01, 0x02, 0x01, 0x12, 0x03, 0x1b, 0x02, 0x1c, 0x1a, 0x3a, 0x20, 0x43, 0x69, 0x70, 0x68, + 0x65, 0x72, 0x74, 0x65, 0x78, 0x74, 0x2e, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x20, 0x4d, + 0x55, 0x53, 0x54, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x20, 0x65, 0x6e, 0x63, 0x72, + 0x79, 0x70, 0x74, 0x65, 0x64, 0x20, 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x64, 0x43, 0x6f, 0x6e, + 0x74, 0x65, 0x6e, 0x74, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x01, 0x06, 0x12, 0x03, + 0x1b, 0x02, 0x0c, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x01, 0x01, 0x12, 0x03, 0x1b, 0x0d, + 0x17, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x01, 0x03, 0x12, 0x03, 0x1b, 0x1a, 0x1b, 0x0a, + 0x88, 0x02, 0x0a, 0x02, 0x04, 0x02, 0x12, 0x04, 0x24, 0x00, 0x29, 0x01, 0x1a, 0xed, 0x01, 0x20, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x20, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x20, 0x63, + 0x61, 0x72, 0x72, 0x69, 0x65, 0x73, 0x20, 0x69, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x69, 0x73, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x65, + 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x65, 0x64, 0x2c, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x69, 0x73, + 0x20, 0x74, 0x68, 0x65, 0x72, 0x65, 0x66, 0x6f, 0x72, 0x65, 0x0a, 0x20, 0x6f, 0x62, 0x73, 0x65, + 0x72, 0x76, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x62, 0x79, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6e, 0x65, + 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x2e, 0x20, 0x49, 0x74, 0x20, 0x69, 0x73, 0x20, 0x68, 0x6f, 0x77, + 0x65, 0x76, 0x65, 0x72, 0x20, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, + 0x65, 0x64, 0x20, 0x61, 0x73, 0x20, 0x61, 0x73, 0x73, 0x6f, 0x63, 0x69, 0x61, 0x74, 0x65, 0x64, + 0x20, 0x64, 0x61, 0x74, 0x61, 0x0a, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x41, 0x45, + 0x41, 0x44, 0x20, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x75, 0x73, + 0x65, 0x64, 0x20, 0x74, 0x6f, 0x20, 0x70, 0x72, 0x6f, 0x74, 0x65, 0x63, 0x74, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2c, 0x0a, 0x20, 0x74, 0x68, 0x75, 0x73, + 0x20, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x74, 0x61, 0x6d, 0x70, 0x65, + 0x72, 0x20, 0x65, 0x76, 0x69, 0x64, 0x65, 0x6e, 0x63, 0x65, 0x2e, 0x0a, 0x32, 0x0c, 0x20, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x20, 0x56, 0x32, 0x0a, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x02, + 0x01, 0x12, 0x03, 0x24, 0x08, 0x17, 0x0a, 0x35, 0x0a, 0x04, 0x04, 0x02, 0x02, 0x00, 0x12, 0x03, + 0x26, 0x02, 0x18, 0x1a, 0x28, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x20, 0x73, 0x70, 0x65, + 0x63, 0x69, 0x66, 0x69, 0x65, 0x64, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x20, 0x63, + 0x72, 0x65, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x74, 0x69, 0x6d, 0x65, 0x0a, 0x0a, 0x0c, 0x0a, + 0x05, 0x04, 0x02, 0x02, 0x00, 0x05, 0x12, 0x03, 0x26, 0x02, 0x08, 0x0a, 0x0c, 0x0a, 0x05, 0x04, + 0x02, 0x02, 0x00, 0x01, 0x12, 0x03, 0x26, 0x09, 0x13, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, + 0x00, 0x03, 0x12, 0x03, 0x26, 0x16, 0x17, 0x0a, 0x2f, 0x0a, 0x04, 0x04, 0x02, 0x02, 0x01, 0x12, + 0x03, 0x28, 0x02, 0x13, 0x1a, 0x22, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x6f, 0x70, 0x69, 0x63, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x20, 0x62, 0x65, 0x6c, + 0x6f, 0x6e, 0x67, 0x73, 0x20, 0x74, 0x6f, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x01, + 0x05, 0x12, 0x03, 0x28, 0x02, 0x08, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x01, 0x01, 0x12, + 0x03, 0x28, 0x09, 0x0e, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x01, 0x03, 0x12, 0x03, 0x28, + 0x11, 0x12, 0x0a, 0x4d, 0x0a, 0x02, 0x04, 0x03, 0x12, 0x04, 0x2c, 0x00, 0x37, 0x01, 0x1a, 0x41, + 0x20, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x20, 0x63, 0x6f, 0x6d, 0x62, 0x69, 0x6e, 0x65, + 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x64, 0x20, 0x68, 0x65, + 0x61, 0x64, 0x65, 0x72, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x74, 0x68, 0x65, 0x20, 0x65, 0x6e, + 0x63, 0x72, 0x79, 0x70, 0x74, 0x65, 0x64, 0x20, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x2e, + 0x0a, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x03, 0x01, 0x12, 0x03, 0x2c, 0x08, 0x11, 0x0a, 0x33, 0x0a, + 0x04, 0x04, 0x03, 0x02, 0x00, 0x12, 0x03, 0x2e, 0x02, 0x19, 0x1a, 0x26, 0x20, 0x65, 0x6e, 0x63, + 0x61, 0x70, 0x73, 0x75, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x20, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x65, + 0x64, 0x20, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x56, + 0x32, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, 0x00, 0x05, 0x12, 0x03, 0x2e, 0x02, 0x07, + 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, 0x00, 0x01, 0x12, 0x03, 0x2e, 0x08, 0x14, 0x0a, 0x0c, + 0x0a, 0x05, 0x04, 0x03, 0x02, 0x00, 0x03, 0x12, 0x03, 0x2e, 0x17, 0x18, 0x0a, 0x46, 0x0a, 0x04, + 0x04, 0x03, 0x02, 0x01, 0x12, 0x03, 0x30, 0x02, 0x1c, 0x1a, 0x39, 0x20, 0x43, 0x69, 0x70, 0x68, + 0x65, 0x72, 0x74, 0x65, 0x78, 0x74, 0x2e, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x20, 0x4d, + 0x55, 0x53, 0x54, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x20, 0x65, 0x6e, 0x63, 0x72, + 0x79, 0x70, 0x74, 0x65, 0x64, 0x20, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x43, 0x6f, 0x6e, 0x74, + 0x65, 0x6e, 0x74, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, 0x01, 0x06, 0x12, 0x03, 0x30, + 0x02, 0x0c, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, 0x01, 0x01, 0x12, 0x03, 0x30, 0x0d, 0x17, + 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, 0x01, 0x03, 0x12, 0x03, 0x30, 0x1a, 0x1b, 0x0a, 0x5c, + 0x0a, 0x04, 0x04, 0x03, 0x02, 0x02, 0x12, 0x03, 0x33, 0x02, 0x21, 0x1a, 0x4f, 0x20, 0x48, 0x4d, + 0x41, 0x43, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x20, 0x63, 0x69, 0x70, 0x68, 0x65, 0x72, 0x74, 0x65, 0x78, 0x74, 0x2c, 0x20, 0x77, 0x69, + 0x74, 0x68, 0x20, 0x74, 0x68, 0x65, 0x20, 0x48, 0x4d, 0x41, 0x43, 0x20, 0x6b, 0x65, 0x79, 0x20, + 0x64, 0x65, 0x72, 0x69, 0x76, 0x65, 0x64, 0x20, 0x66, 0x72, 0x6f, 0x6d, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x0a, 0x20, 0x6b, 0x65, 0x79, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, + 0x04, 0x03, 0x02, 0x02, 0x04, 0x12, 0x03, 0x33, 0x02, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, + 0x02, 0x02, 0x05, 0x12, 0x03, 0x33, 0x0b, 0x10, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, 0x02, + 0x01, 0x12, 0x03, 0x33, 0x11, 0x1c, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, 0x02, 0x03, 0x12, + 0x03, 0x33, 0x1f, 0x20, 0x0a, 0x5f, 0x0a, 0x04, 0x04, 0x03, 0x02, 0x03, 0x12, 0x03, 0x36, 0x02, + 0x20, 0x1a, 0x52, 0x20, 0x46, 0x6c, 0x61, 0x67, 0x20, 0x69, 0x6e, 0x64, 0x69, 0x63, 0x61, 0x74, + 0x69, 0x6e, 0x67, 0x20, 0x77, 0x68, 0x65, 0x74, 0x68, 0x65, 0x72, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x20, 0x73, 0x68, 0x6f, 0x75, 0x6c, 0x64, 0x20, 0x62, + 0x65, 0x20, 0x70, 0x75, 0x73, 0x68, 0x65, 0x64, 0x20, 0x66, 0x72, 0x6f, 0x6d, 0x20, 0x61, 0x20, + 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x0a, 0x20, 0x73, 0x65, + 0x72, 0x76, 0x65, 0x72, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, 0x03, 0x04, 0x12, 0x03, + 0x36, 0x02, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, 0x03, 0x05, 0x12, 0x03, 0x36, 0x0b, + 0x0f, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, 0x03, 0x01, 0x12, 0x03, 0x36, 0x10, 0x1b, 0x0a, + 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, 0x03, 0x03, 0x12, 0x03, 0x36, 0x1e, 0x1f, 0x0a, 0x1f, 0x0a, + 0x02, 0x04, 0x04, 0x12, 0x04, 0x3a, 0x00, 0x3f, 0x01, 0x1a, 0x13, 0x20, 0x56, 0x65, 0x72, 0x73, + 0x69, 0x6f, 0x6e, 0x65, 0x64, 0x20, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x0a, 0x0a, 0x0a, + 0x0a, 0x03, 0x04, 0x04, 0x01, 0x12, 0x03, 0x3a, 0x08, 0x0f, 0x0a, 0x0c, 0x0a, 0x04, 0x04, 0x04, + 0x08, 0x00, 0x12, 0x04, 0x3b, 0x02, 0x3e, 0x03, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x08, 0x00, + 0x01, 0x12, 0x03, 0x3b, 0x08, 0x0f, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x04, 0x02, 0x00, 0x12, 0x03, + 0x3c, 0x04, 0x15, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x02, 0x00, 0x06, 0x12, 0x03, 0x3c, 0x04, + 0x0d, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x02, 0x00, 0x01, 0x12, 0x03, 0x3c, 0x0e, 0x10, 0x0a, + 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x02, 0x00, 0x03, 0x12, 0x03, 0x3c, 0x13, 0x14, 0x0a, 0x0b, 0x0a, + 0x04, 0x04, 0x04, 0x02, 0x01, 0x12, 0x03, 0x3d, 0x04, 0x15, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, + 0x02, 0x01, 0x06, 0x12, 0x03, 0x3d, 0x04, 0x0d, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x02, 0x01, + 0x01, 0x12, 0x03, 0x3d, 0x0e, 0x10, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x02, 0x01, 0x03, 0x12, + 0x03, 0x3d, 0x13, 0x14, 0x0a, 0xae, 0x01, 0x0a, 0x02, 0x04, 0x05, 0x12, 0x04, 0x44, 0x00, 0x4d, + 0x01, 0x1a, 0xa1, 0x01, 0x20, 0x44, 0x65, 0x63, 0x6f, 0x64, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x20, 0x72, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x73, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x64, 0x65, 0x63, 0x72, 0x79, 0x70, 0x74, 0x65, 0x64, 0x20, 0x6d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x0a, 0x20, + 0x44, 0x65, 0x63, 0x6f, 0x64, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x20, 0x69, + 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x20, 0x61, 0x72, 0x65, 0x20, 0x6e, 0x6f, 0x74, + 0x20, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x64, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6e, + 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x2c, 0x20, 0x62, 0x75, 0x74, 0x0a, 0x20, 0x6d, 0x61, 0x79, + 0x20, 0x62, 0x65, 0x20, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x20, 0x61, + 0x6e, 0x64, 0x20, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x64, 0x20, 0x62, 0x79, 0x20, 0x63, 0x6c, 0x69, + 0x65, 0x6e, 0x74, 0x73, 0x0a, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x05, 0x01, 0x12, 0x03, 0x44, 0x08, + 0x16, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x05, 0x02, 0x00, 0x12, 0x03, 0x45, 0x02, 0x10, 0x0a, 0x0c, + 0x0a, 0x05, 0x04, 0x05, 0x02, 0x00, 0x05, 0x12, 0x03, 0x45, 0x02, 0x08, 0x0a, 0x0c, 0x0a, 0x05, + 0x04, 0x05, 0x02, 0x00, 0x01, 0x12, 0x03, 0x45, 0x09, 0x0b, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x05, + 0x02, 0x00, 0x03, 0x12, 0x03, 0x45, 0x0e, 0x0f, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x05, 0x02, 0x01, + 0x12, 0x03, 0x46, 0x02, 0x1d, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x05, 0x02, 0x01, 0x05, 0x12, 0x03, + 0x46, 0x02, 0x08, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x05, 0x02, 0x01, 0x01, 0x12, 0x03, 0x46, 0x09, + 0x18, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x05, 0x02, 0x01, 0x03, 0x12, 0x03, 0x46, 0x1b, 0x1c, 0x0a, + 0x0b, 0x0a, 0x04, 0x04, 0x05, 0x02, 0x02, 0x12, 0x03, 0x47, 0x02, 0x1c, 0x0a, 0x0c, 0x0a, 0x05, + 0x04, 0x05, 0x02, 0x02, 0x05, 0x12, 0x03, 0x47, 0x02, 0x08, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x05, + 0x02, 0x02, 0x01, 0x12, 0x03, 0x47, 0x09, 0x17, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x05, 0x02, 0x02, + 0x03, 0x12, 0x03, 0x47, 0x1a, 0x1b, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x05, 0x02, 0x03, 0x12, 0x03, + 0x48, 0x02, 0x28, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x05, 0x02, 0x03, 0x04, 0x12, 0x03, 0x48, 0x02, + 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x05, 0x02, 0x03, 0x05, 0x12, 0x03, 0x48, 0x0b, 0x11, 0x0a, + 0x0c, 0x0a, 0x05, 0x04, 0x05, 0x02, 0x03, 0x01, 0x12, 0x03, 0x48, 0x12, 0x23, 0x0a, 0x0c, 0x0a, + 0x05, 0x04, 0x05, 0x02, 0x03, 0x03, 0x12, 0x03, 0x48, 0x26, 0x27, 0x0a, 0x0b, 0x0a, 0x04, 0x04, + 0x05, 0x02, 0x04, 0x12, 0x03, 0x49, 0x02, 0x15, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x05, 0x02, 0x04, + 0x05, 0x12, 0x03, 0x49, 0x02, 0x08, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x05, 0x02, 0x04, 0x01, 0x12, + 0x03, 0x49, 0x09, 0x10, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x05, 0x02, 0x04, 0x03, 0x12, 0x03, 0x49, + 0x13, 0x14, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x05, 0x02, 0x05, 0x12, 0x03, 0x4a, 0x02, 0x1b, 0x0a, + 0x0c, 0x0a, 0x05, 0x04, 0x05, 0x02, 0x05, 0x05, 0x12, 0x03, 0x4a, 0x02, 0x08, 0x0a, 0x0c, 0x0a, + 0x05, 0x04, 0x05, 0x02, 0x05, 0x01, 0x12, 0x03, 0x4a, 0x09, 0x16, 0x0a, 0x0c, 0x0a, 0x05, 0x04, + 0x05, 0x02, 0x05, 0x03, 0x12, 0x03, 0x4a, 0x19, 0x1a, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x05, 0x02, + 0x06, 0x12, 0x03, 0x4b, 0x02, 0x29, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x05, 0x02, 0x06, 0x06, 0x12, + 0x03, 0x4b, 0x02, 0x17, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x05, 0x02, 0x06, 0x01, 0x12, 0x03, 0x4b, + 0x18, 0x24, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x05, 0x02, 0x06, 0x03, 0x12, 0x03, 0x4b, 0x27, 0x28, + 0x0a, 0x2a, 0x0a, 0x04, 0x04, 0x05, 0x02, 0x07, 0x12, 0x03, 0x4c, 0x02, 0x1a, 0x22, 0x1d, 0x20, + 0x65, 0x6e, 0x63, 0x61, 0x70, 0x73, 0x75, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x20, 0x45, 0x6e, 0x63, + 0x6f, 0x64, 0x65, 0x64, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, + 0x04, 0x05, 0x02, 0x07, 0x05, 0x12, 0x03, 0x4c, 0x02, 0x07, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x05, + 0x02, 0x07, 0x01, 0x12, 0x03, 0x4c, 0x08, 0x15, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x05, 0x02, 0x07, + 0x03, 0x12, 0x03, 0x4c, 0x18, 0x19, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, 0x0a, 0xe0, + 0x05, 0x0a, 0x25, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, + 0x6e, 0x74, 0x73, 0x2f, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x5f, 0x70, 0x61, 0x79, 0x6c, 0x6f, + 0x61, 0x64, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x15, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x1a, + 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, + 0x73, 0x2f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x22, 0x69, 0x0a, 0x0d, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x50, 0x61, 0x79, 0x6c, 0x6f, + 0x61, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0c, 0x52, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x3e, 0x0a, 0x09, + 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x20, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, + 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, + 0x65, 0x52, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x42, 0xce, 0x01, 0x0a, + 0x19, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x42, 0x12, 0x53, 0x69, 0x67, 0x6e, + 0x65, 0x64, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, + 0x5a, 0x2c, 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, 0x6d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0xa2, 0x02, + 0x03, 0x58, 0x4d, 0x58, 0xaa, 0x02, 0x14, 0x58, 0x6d, 0x74, 0x70, 0x2e, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0xca, 0x02, 0x14, 0x58, 0x6d, + 0x74, 0x70, 0x5c, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, + 0x74, 0x73, 0xe2, 0x02, 0x20, 0x58, 0x6d, 0x74, 0x70, 0x5c, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, + 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x15, 0x58, 0x6d, 0x74, 0x70, 0x3a, 0x3a, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x4a, 0xb9, 0x02, + 0x0a, 0x06, 0x12, 0x04, 0x01, 0x00, 0x0e, 0x01, 0x0a, 0x43, 0x0a, 0x01, 0x0c, 0x12, 0x03, 0x01, + 0x00, 0x12, 0x1a, 0x39, 0x20, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x20, 0x69, + 0x73, 0x20, 0x61, 0x20, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x69, 0x63, 0x20, 0x73, 0x74, 0x72, 0x75, + 0x63, 0x74, 0x75, 0x72, 0x65, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, + 0x20, 0x62, 0x79, 0x74, 0x65, 0x20, 0x61, 0x72, 0x72, 0x61, 0x79, 0x73, 0x0a, 0x0a, 0x08, 0x0a, + 0x01, 0x02, 0x12, 0x03, 0x03, 0x00, 0x1e, 0x0a, 0x09, 0x0a, 0x02, 0x03, 0x00, 0x12, 0x03, 0x05, + 0x00, 0x2a, 0x0a, 0x08, 0x0a, 0x01, 0x08, 0x12, 0x03, 0x07, 0x00, 0x43, 0x0a, 0x09, 0x0a, 0x02, + 0x08, 0x0b, 0x12, 0x03, 0x07, 0x00, 0x43, 0x0a, 0x46, 0x0a, 0x02, 0x04, 0x00, 0x12, 0x04, 0x0b, + 0x00, 0x0e, 0x01, 0x1a, 0x3a, 0x20, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x50, 0x61, 0x79, 0x6c, + 0x6f, 0x61, 0x64, 0x20, 0x69, 0x73, 0x20, 0x61, 0x20, 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x72, + 0x20, 0x66, 0x6f, 0x72, 0x20, 0x61, 0x20, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, + 0x20, 0x61, 0x6e, 0x64, 0x20, 0x61, 0x20, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x0a, 0x0a, + 0x0a, 0x0a, 0x03, 0x04, 0x00, 0x01, 0x12, 0x03, 0x0b, 0x08, 0x15, 0x0a, 0x0b, 0x0a, 0x04, 0x04, + 0x00, 0x02, 0x00, 0x12, 0x03, 0x0c, 0x02, 0x14, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x00, + 0x05, 0x12, 0x03, 0x0c, 0x02, 0x07, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x00, 0x01, 0x12, + 0x03, 0x0c, 0x08, 0x0f, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x00, 0x03, 0x12, 0x03, 0x0c, + 0x12, 0x13, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x00, 0x02, 0x01, 0x12, 0x03, 0x0d, 0x02, 0x1a, 0x0a, + 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x01, 0x06, 0x12, 0x03, 0x0d, 0x02, 0x0b, 0x0a, 0x0c, 0x0a, + 0x05, 0x04, 0x00, 0x02, 0x01, 0x01, 0x12, 0x03, 0x0d, 0x0c, 0x15, 0x0a, 0x0c, 0x0a, 0x05, 0x04, + 0x00, 0x02, 0x01, 0x03, 0x12, 0x03, 0x0d, 0x18, 0x19, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x33, ]; include!("xmtp.message_contents.serde.rs"); // @@protoc_insertion_point(module) \ No newline at end of file diff --git a/xmtp_proto/src/gen/xmtp.message_contents.serde.rs b/xmtp_proto/src/gen/xmtp.message_contents.serde.rs index 279816e33..cdda606ee 100644 --- a/xmtp_proto/src/gen/xmtp.message_contents.serde.rs +++ b/xmtp_proto/src/gen/xmtp.message_contents.serde.rs @@ -2032,6 +2032,15 @@ impl serde::Serialize for FrameAction { if !self.action_body.is_empty() { len += 1; } + if !self.installation_signature.is_empty() { + len += 1; + } + if !self.installation_id.is_empty() { + len += 1; + } + if !self.inbox_id.is_empty() { + len += 1; + } let mut struct_ser = serializer.serialize_struct("xmtp.message_contents.FrameAction", len)?; if let Some(v) = self.signature.as_ref() { struct_ser.serialize_field("signature", v)?; @@ -2044,6 +2053,19 @@ impl serde::Serialize for FrameAction { #[allow(clippy::needless_borrows_for_generic_args)] struct_ser.serialize_field("actionBody", pbjson::private::base64::encode(&self.action_body).as_str())?; } + if !self.installation_signature.is_empty() { + #[allow(clippy::needless_borrow)] + #[allow(clippy::needless_borrows_for_generic_args)] + struct_ser.serialize_field("installationSignature", pbjson::private::base64::encode(&self.installation_signature).as_str())?; + } + if !self.installation_id.is_empty() { + #[allow(clippy::needless_borrow)] + #[allow(clippy::needless_borrows_for_generic_args)] + struct_ser.serialize_field("installationId", pbjson::private::base64::encode(&self.installation_id).as_str())?; + } + if !self.inbox_id.is_empty() { + struct_ser.serialize_field("inboxId", &self.inbox_id)?; + } struct_ser.end() } } @@ -2059,6 +2081,12 @@ impl<'de> serde::Deserialize<'de> for FrameAction { "signedPublicKeyBundle", "action_body", "actionBody", + "installation_signature", + "installationSignature", + "installation_id", + "installationId", + "inbox_id", + "inboxId", ]; #[allow(clippy::enum_variant_names)] @@ -2066,6 +2094,9 @@ impl<'de> serde::Deserialize<'de> for FrameAction { Signature, SignedPublicKeyBundle, ActionBody, + InstallationSignature, + InstallationId, + InboxId, } impl<'de> serde::Deserialize<'de> for GeneratedField { fn deserialize(deserializer: D) -> std::result::Result @@ -2090,6 +2121,9 @@ impl<'de> serde::Deserialize<'de> for FrameAction { "signature" => Ok(GeneratedField::Signature), "signedPublicKeyBundle" | "signed_public_key_bundle" => Ok(GeneratedField::SignedPublicKeyBundle), "actionBody" | "action_body" => Ok(GeneratedField::ActionBody), + "installationSignature" | "installation_signature" => Ok(GeneratedField::InstallationSignature), + "installationId" | "installation_id" => Ok(GeneratedField::InstallationId), + "inboxId" | "inbox_id" => Ok(GeneratedField::InboxId), _ => Err(serde::de::Error::unknown_field(value, FIELDS)), } } @@ -2112,6 +2146,9 @@ impl<'de> serde::Deserialize<'de> for FrameAction { let mut signature__ = None; let mut signed_public_key_bundle__ = None; let mut action_body__ = None; + let mut installation_signature__ = None; + let mut installation_id__ = None; + let mut inbox_id__ = None; while let Some(k) = map_.next_key()? { match k { GeneratedField::Signature => { @@ -2134,12 +2171,37 @@ impl<'de> serde::Deserialize<'de> for FrameAction { Some(map_.next_value::<::pbjson::private::BytesDeserialize<_>>()?.0) ; } + GeneratedField::InstallationSignature => { + if installation_signature__.is_some() { + return Err(serde::de::Error::duplicate_field("installationSignature")); + } + installation_signature__ = + Some(map_.next_value::<::pbjson::private::BytesDeserialize<_>>()?.0) + ; + } + GeneratedField::InstallationId => { + if installation_id__.is_some() { + return Err(serde::de::Error::duplicate_field("installationId")); + } + installation_id__ = + Some(map_.next_value::<::pbjson::private::BytesDeserialize<_>>()?.0) + ; + } + GeneratedField::InboxId => { + if inbox_id__.is_some() { + return Err(serde::de::Error::duplicate_field("inboxId")); + } + inbox_id__ = Some(map_.next_value()?); + } } } Ok(FrameAction { signature: signature__, signed_public_key_bundle: signed_public_key_bundle__, action_body: action_body__.unwrap_or_default(), + installation_signature: installation_signature__.unwrap_or_default(), + installation_id: installation_id__.unwrap_or_default(), + inbox_id: inbox_id__.unwrap_or_default(), }) } } diff --git a/xmtp_proto/src/gen/xmtp.mls.message_contents.rs b/xmtp_proto/src/gen/xmtp.mls.message_contents.rs index 3a270b954..2c6985f4f 100644 --- a/xmtp_proto/src/gen/xmtp.mls.message_contents.rs +++ b/xmtp_proto/src/gen/xmtp.mls.message_contents.rs @@ -224,6 +224,7 @@ impl DeviceSyncKind { } } } +/// The type of entity the user is consenting to #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] #[repr(i32)] pub enum ConsentEntityType { @@ -256,6 +257,7 @@ impl ConsentEntityType { } } } +/// Possible states of consent #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] #[repr(i32)] pub enum ConsentState { @@ -682,7 +684,7 @@ pub mod group_updated { } /// Encoded file descriptor set for the `xmtp.mls.message_contents` package pub const FILE_DESCRIPTOR_SET: &[u8] = &[ - 0x0a, 0x8b, 0x3b, 0x0a, 0x22, 0x6d, 0x6c, 0x73, 0x2f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x0a, 0xdc, 0x3b, 0x0a, 0x22, 0x6d, 0x6c, 0x73, 0x2f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x19, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, @@ -840,8 +842,8 @@ pub const FILE_DESCRIPTOR_SET: &[u8] = &[ 0x6c, 0x73, 0x5c, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x1a, 0x58, 0x6d, 0x74, 0x70, 0x3a, 0x3a, 0x4d, 0x6c, 0x73, 0x3a, 0x3a, 0x4d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x4a, 0x98, 0x27, 0x0a, 0x07, - 0x12, 0x05, 0x02, 0x00, 0x88, 0x01, 0x01, 0x0a, 0x7c, 0x0a, 0x01, 0x0c, 0x12, 0x03, 0x02, 0x00, + 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x4a, 0xe9, 0x27, 0x0a, 0x07, + 0x12, 0x05, 0x02, 0x00, 0x8a, 0x01, 0x01, 0x0a, 0x7c, 0x0a, 0x01, 0x0c, 0x12, 0x03, 0x02, 0x00, 0x12, 0x1a, 0x72, 0x20, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x20, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x75, 0x72, 0x65, 0x73, 0x0a, 0x20, 0x43, 0x6f, 0x70, 0x69, 0x65, 0x64, 0x20, @@ -1132,890 +1134,895 @@ pub const FILE_DESCRIPTOR_SET: &[u8] = &[ 0x04, 0x04, 0x06, 0x02, 0x02, 0x12, 0x03, 0x7a, 0x02, 0x14, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x06, 0x02, 0x02, 0x05, 0x12, 0x03, 0x7a, 0x02, 0x08, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x06, 0x02, 0x02, 0x01, 0x12, 0x03, 0x7a, 0x09, 0x0f, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x06, 0x02, 0x02, 0x03, 0x12, - 0x03, 0x7a, 0x12, 0x13, 0x0a, 0x0b, 0x0a, 0x02, 0x05, 0x02, 0x12, 0x05, 0x7d, 0x00, 0x82, 0x01, - 0x01, 0x0a, 0x0a, 0x0a, 0x03, 0x05, 0x02, 0x01, 0x12, 0x03, 0x7d, 0x05, 0x16, 0x0a, 0x0b, 0x0a, - 0x04, 0x05, 0x02, 0x02, 0x00, 0x12, 0x03, 0x7e, 0x02, 0x26, 0x0a, 0x0c, 0x0a, 0x05, 0x05, 0x02, - 0x02, 0x00, 0x01, 0x12, 0x03, 0x7e, 0x02, 0x21, 0x0a, 0x0c, 0x0a, 0x05, 0x05, 0x02, 0x02, 0x00, - 0x02, 0x12, 0x03, 0x7e, 0x24, 0x25, 0x0a, 0x0b, 0x0a, 0x04, 0x05, 0x02, 0x02, 0x01, 0x12, 0x03, - 0x7f, 0x02, 0x2a, 0x0a, 0x0c, 0x0a, 0x05, 0x05, 0x02, 0x02, 0x01, 0x01, 0x12, 0x03, 0x7f, 0x02, - 0x25, 0x0a, 0x0c, 0x0a, 0x05, 0x05, 0x02, 0x02, 0x01, 0x02, 0x12, 0x03, 0x7f, 0x28, 0x29, 0x0a, - 0x0c, 0x0a, 0x04, 0x05, 0x02, 0x02, 0x02, 0x12, 0x04, 0x80, 0x01, 0x02, 0x23, 0x0a, 0x0d, 0x0a, - 0x05, 0x05, 0x02, 0x02, 0x02, 0x01, 0x12, 0x04, 0x80, 0x01, 0x02, 0x1e, 0x0a, 0x0d, 0x0a, 0x05, - 0x05, 0x02, 0x02, 0x02, 0x02, 0x12, 0x04, 0x80, 0x01, 0x21, 0x22, 0x0a, 0x0c, 0x0a, 0x04, 0x05, - 0x02, 0x02, 0x03, 0x12, 0x04, 0x81, 0x01, 0x02, 0x22, 0x0a, 0x0d, 0x0a, 0x05, 0x05, 0x02, 0x02, - 0x03, 0x01, 0x12, 0x04, 0x81, 0x01, 0x02, 0x1d, 0x0a, 0x0d, 0x0a, 0x05, 0x05, 0x02, 0x02, 0x03, - 0x02, 0x12, 0x04, 0x81, 0x01, 0x20, 0x21, 0x0a, 0x0c, 0x0a, 0x02, 0x05, 0x03, 0x12, 0x06, 0x84, - 0x01, 0x00, 0x88, 0x01, 0x01, 0x0a, 0x0b, 0x0a, 0x03, 0x05, 0x03, 0x01, 0x12, 0x04, 0x84, 0x01, - 0x05, 0x11, 0x0a, 0x0c, 0x0a, 0x04, 0x05, 0x03, 0x02, 0x00, 0x12, 0x04, 0x85, 0x01, 0x02, 0x20, - 0x0a, 0x0d, 0x0a, 0x05, 0x05, 0x03, 0x02, 0x00, 0x01, 0x12, 0x04, 0x85, 0x01, 0x02, 0x1b, 0x0a, - 0x0d, 0x0a, 0x05, 0x05, 0x03, 0x02, 0x00, 0x02, 0x12, 0x04, 0x85, 0x01, 0x1e, 0x1f, 0x0a, 0x0c, - 0x0a, 0x04, 0x05, 0x03, 0x02, 0x01, 0x12, 0x04, 0x86, 0x01, 0x02, 0x1c, 0x0a, 0x0d, 0x0a, 0x05, - 0x05, 0x03, 0x02, 0x01, 0x01, 0x12, 0x04, 0x86, 0x01, 0x02, 0x17, 0x0a, 0x0d, 0x0a, 0x05, 0x05, - 0x03, 0x02, 0x01, 0x02, 0x12, 0x04, 0x86, 0x01, 0x1a, 0x1b, 0x0a, 0x0c, 0x0a, 0x04, 0x05, 0x03, - 0x02, 0x02, 0x12, 0x04, 0x87, 0x01, 0x02, 0x1b, 0x0a, 0x0d, 0x0a, 0x05, 0x05, 0x03, 0x02, 0x02, - 0x01, 0x12, 0x04, 0x87, 0x01, 0x02, 0x16, 0x0a, 0x0d, 0x0a, 0x05, 0x05, 0x03, 0x02, 0x02, 0x02, - 0x12, 0x04, 0x87, 0x01, 0x19, 0x1a, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, 0x0a, 0x90, - 0x06, 0x0a, 0x2b, 0x6d, 0x6c, 0x73, 0x2f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, - 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2f, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x5f, 0x6d, 0x65, - 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x19, - 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x22, 0xa0, 0x01, 0x0a, 0x0f, 0x47, 0x72, - 0x6f, 0x75, 0x70, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x12, 0x51, 0x0a, - 0x07, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x37, - 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, - 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x2e, 0x4d, 0x65, 0x6d, 0x62, 0x65, - 0x72, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, - 0x1a, 0x3a, 0x0a, 0x0c, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, - 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, - 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x04, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x42, 0xe9, 0x01, 0x0a, - 0x1d, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x42, 0x14, - 0x47, 0x72, 0x6f, 0x75, 0x70, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x50, - 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x30, 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, 0x6d, 0x6c, 0x73, 0x2f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, - 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0xa2, 0x02, 0x03, 0x58, 0x4d, 0x4d, 0xaa, 0x02, - 0x18, 0x58, 0x6d, 0x74, 0x70, 0x2e, 0x4d, 0x6c, 0x73, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0xca, 0x02, 0x18, 0x58, 0x6d, 0x74, 0x70, - 0x5c, 0x4d, 0x6c, 0x73, 0x5c, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x74, - 0x65, 0x6e, 0x74, 0x73, 0xe2, 0x02, 0x24, 0x58, 0x6d, 0x74, 0x70, 0x5c, 0x4d, 0x6c, 0x73, 0x5c, - 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x5c, - 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x1a, 0x58, 0x6d, - 0x74, 0x70, 0x3a, 0x3a, 0x4d, 0x6c, 0x73, 0x3a, 0x3a, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x4a, 0xae, 0x02, 0x0a, 0x06, 0x12, 0x04, 0x01, - 0x00, 0x0c, 0x01, 0x0a, 0x1c, 0x0a, 0x01, 0x0c, 0x12, 0x03, 0x01, 0x00, 0x12, 0x1a, 0x12, 0x20, - 0x47, 0x72, 0x6f, 0x75, 0x70, 0x20, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, - 0x0a, 0x0a, 0x08, 0x0a, 0x01, 0x02, 0x12, 0x03, 0x03, 0x00, 0x22, 0x0a, 0x08, 0x0a, 0x01, 0x08, - 0x12, 0x03, 0x05, 0x00, 0x47, 0x0a, 0x09, 0x0a, 0x02, 0x08, 0x0b, 0x12, 0x03, 0x05, 0x00, 0x47, - 0x0a, 0xa3, 0x01, 0x0a, 0x02, 0x04, 0x00, 0x12, 0x04, 0x0a, 0x00, 0x0c, 0x01, 0x1a, 0x96, 0x01, - 0x20, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x73, 0x20, 0x61, 0x20, 0x6d, 0x61, 0x70, 0x70, - 0x69, 0x6e, 0x67, 0x20, 0x6f, 0x66, 0x20, 0x60, 0x69, 0x6e, 0x62, 0x6f, 0x78, 0x5f, 0x69, 0x64, - 0x60, 0x20, 0x2d, 0x3e, 0x20, 0x60, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x5f, 0x69, - 0x64, 0x60, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x61, 0x6c, 0x6c, 0x20, 0x6d, 0x65, 0x6d, 0x62, 0x65, - 0x72, 0x73, 0x20, 0x6f, 0x66, 0x20, 0x61, 0x20, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x2e, 0x0a, 0x20, - 0x44, 0x65, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x20, 0x74, 0x6f, 0x20, 0x62, 0x65, 0x20, 0x73, - 0x74, 0x6f, 0x72, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x67, 0x72, 0x6f, - 0x75, 0x70, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x20, 0x65, 0x78, 0x74, 0x65, 0x6e, - 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x4d, 0x4c, 0x53, 0x20, - 0x67, 0x72, 0x6f, 0x75, 0x70, 0x0a, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x00, 0x01, 0x12, 0x03, 0x0a, - 0x08, 0x17, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x00, 0x02, 0x00, 0x12, 0x03, 0x0b, 0x02, 0x22, 0x0a, - 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x00, 0x06, 0x12, 0x03, 0x0b, 0x02, 0x15, 0x0a, 0x0c, 0x0a, - 0x05, 0x04, 0x00, 0x02, 0x00, 0x01, 0x12, 0x03, 0x0b, 0x16, 0x1d, 0x0a, 0x0c, 0x0a, 0x05, 0x04, - 0x00, 0x02, 0x00, 0x03, 0x12, 0x03, 0x0b, 0x20, 0x21, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x33, 0x0a, 0xe5, 0x0e, 0x0a, 0x29, 0x6d, 0x6c, 0x73, 0x2f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2f, 0x67, 0x72, 0x6f, 0x75, 0x70, - 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, - 0x19, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x22, 0xa6, 0x02, 0x0a, 0x0f, 0x47, - 0x72, 0x6f, 0x75, 0x70, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x56, 0x31, 0x12, 0x58, - 0x0a, 0x11, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x74, - 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2b, 0x2e, 0x78, 0x6d, 0x74, 0x70, - 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, - 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x43, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x10, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x12, 0x36, 0x0a, 0x17, 0x63, 0x72, 0x65, 0x61, - 0x74, 0x6f, 0x72, 0x5f, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x61, 0x64, 0x64, 0x72, - 0x65, 0x73, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x15, 0x63, 0x72, 0x65, 0x61, 0x74, - 0x6f, 0x72, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, - 0x12, 0x28, 0x0a, 0x10, 0x63, 0x72, 0x65, 0x61, 0x74, 0x6f, 0x72, 0x5f, 0x69, 0x6e, 0x62, 0x6f, - 0x78, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x63, 0x72, 0x65, 0x61, - 0x74, 0x6f, 0x72, 0x49, 0x6e, 0x62, 0x6f, 0x78, 0x49, 0x64, 0x12, 0x48, 0x0a, 0x0a, 0x64, 0x6d, - 0x5f, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, - 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x44, 0x6d, 0x4d, 0x65, 0x6d, - 0x62, 0x65, 0x72, 0x73, 0x48, 0x00, 0x52, 0x09, 0x64, 0x6d, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, - 0x73, 0x88, 0x01, 0x01, 0x42, 0x0d, 0x0a, 0x0b, 0x5f, 0x64, 0x6d, 0x5f, 0x6d, 0x65, 0x6d, 0x62, - 0x65, 0x72, 0x73, 0x22, 0x22, 0x0a, 0x05, 0x49, 0x6e, 0x62, 0x6f, 0x78, 0x12, 0x19, 0x0a, 0x08, - 0x69, 0x6e, 0x62, 0x6f, 0x78, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, - 0x69, 0x6e, 0x62, 0x6f, 0x78, 0x49, 0x64, 0x22, 0x97, 0x01, 0x0a, 0x09, 0x44, 0x6d, 0x4d, 0x65, - 0x6d, 0x62, 0x65, 0x72, 0x73, 0x12, 0x44, 0x0a, 0x0d, 0x64, 0x6d, 0x5f, 0x6d, 0x65, 0x6d, 0x62, - 0x65, 0x72, 0x5f, 0x6f, 0x6e, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x78, - 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, - 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x49, 0x6e, 0x62, 0x6f, 0x78, 0x52, 0x0b, - 0x64, 0x6d, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x4f, 0x6e, 0x65, 0x12, 0x44, 0x0a, 0x0d, 0x64, - 0x6d, 0x5f, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x5f, 0x74, 0x77, 0x6f, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x49, - 0x6e, 0x62, 0x6f, 0x78, 0x52, 0x0b, 0x64, 0x6d, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x54, 0x77, - 0x6f, 0x2a, 0x88, 0x01, 0x0a, 0x10, 0x43, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x12, 0x21, 0x0a, 0x1d, 0x43, 0x4f, 0x4e, 0x56, 0x45, 0x52, - 0x53, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, - 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x1b, 0x0a, 0x17, 0x43, 0x4f, 0x4e, - 0x56, 0x45, 0x52, 0x53, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x47, - 0x52, 0x4f, 0x55, 0x50, 0x10, 0x01, 0x12, 0x18, 0x0a, 0x14, 0x43, 0x4f, 0x4e, 0x56, 0x45, 0x52, - 0x53, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x44, 0x4d, 0x10, 0x02, - 0x12, 0x1a, 0x0a, 0x16, 0x43, 0x4f, 0x4e, 0x56, 0x45, 0x52, 0x53, 0x41, 0x54, 0x49, 0x4f, 0x4e, - 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x53, 0x59, 0x4e, 0x43, 0x10, 0x03, 0x42, 0xe7, 0x01, 0x0a, - 0x1d, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x42, 0x12, - 0x47, 0x72, 0x6f, 0x75, 0x70, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x50, 0x72, 0x6f, - 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x30, 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, 0x6d, 0x6c, 0x73, 0x2f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, - 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0xa2, 0x02, 0x03, 0x58, 0x4d, 0x4d, 0xaa, 0x02, 0x18, 0x58, - 0x6d, 0x74, 0x70, 0x2e, 0x4d, 0x6c, 0x73, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x43, - 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0xca, 0x02, 0x18, 0x58, 0x6d, 0x74, 0x70, 0x5c, 0x4d, - 0x6c, 0x73, 0x5c, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, - 0x74, 0x73, 0xe2, 0x02, 0x24, 0x58, 0x6d, 0x74, 0x70, 0x5c, 0x4d, 0x6c, 0x73, 0x5c, 0x4d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x5c, 0x47, 0x50, - 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x1a, 0x58, 0x6d, 0x74, 0x70, - 0x3a, 0x3a, 0x4d, 0x6c, 0x73, 0x3a, 0x3a, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x43, 0x6f, - 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x4a, 0xb8, 0x07, 0x0a, 0x06, 0x12, 0x04, 0x01, 0x00, 0x23, - 0x01, 0x0a, 0x24, 0x0a, 0x01, 0x0c, 0x12, 0x03, 0x01, 0x00, 0x12, 0x1a, 0x1a, 0x20, 0x47, 0x72, - 0x6f, 0x75, 0x70, 0x20, 0x69, 0x6d, 0x6d, 0x75, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x6d, 0x65, - 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x0a, 0x0a, 0x08, 0x0a, 0x01, 0x02, 0x12, 0x03, 0x03, 0x00, - 0x22, 0x0a, 0x08, 0x0a, 0x01, 0x08, 0x12, 0x03, 0x05, 0x00, 0x47, 0x0a, 0x09, 0x0a, 0x02, 0x08, - 0x0b, 0x12, 0x03, 0x05, 0x00, 0x47, 0x0a, 0x2f, 0x0a, 0x02, 0x04, 0x00, 0x12, 0x04, 0x09, 0x00, - 0x10, 0x01, 0x1a, 0x23, 0x20, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x20, 0x6d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x20, 0x6d, 0x65, - 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x0a, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x00, 0x01, 0x12, 0x03, - 0x09, 0x08, 0x17, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x00, 0x02, 0x00, 0x12, 0x03, 0x0a, 0x02, 0x29, - 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x00, 0x06, 0x12, 0x03, 0x0a, 0x02, 0x12, 0x0a, 0x0c, - 0x0a, 0x05, 0x04, 0x00, 0x02, 0x00, 0x01, 0x12, 0x03, 0x0a, 0x13, 0x24, 0x0a, 0x0c, 0x0a, 0x05, - 0x04, 0x00, 0x02, 0x00, 0x03, 0x12, 0x03, 0x0a, 0x27, 0x28, 0x0a, 0x28, 0x0a, 0x04, 0x04, 0x00, - 0x02, 0x01, 0x12, 0x03, 0x0c, 0x02, 0x25, 0x1a, 0x1b, 0x20, 0x54, 0x68, 0x69, 0x73, 0x20, 0x77, - 0x69, 0x6c, 0x6c, 0x20, 0x62, 0x65, 0x20, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x20, 0x73, - 0x6f, 0x6f, 0x6e, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x01, 0x05, 0x12, 0x03, 0x0c, - 0x02, 0x08, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x01, 0x01, 0x12, 0x03, 0x0c, 0x09, 0x20, - 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x01, 0x03, 0x12, 0x03, 0x0c, 0x23, 0x24, 0x0a, 0x0b, - 0x0a, 0x04, 0x04, 0x00, 0x02, 0x02, 0x12, 0x03, 0x0d, 0x02, 0x1e, 0x0a, 0x0c, 0x0a, 0x05, 0x04, - 0x00, 0x02, 0x02, 0x05, 0x12, 0x03, 0x0d, 0x02, 0x08, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, - 0x02, 0x01, 0x12, 0x03, 0x0d, 0x09, 0x19, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x02, 0x03, - 0x12, 0x03, 0x0d, 0x1c, 0x1d, 0x0a, 0x3e, 0x0a, 0x04, 0x04, 0x00, 0x02, 0x03, 0x12, 0x03, 0x0f, - 0x02, 0x24, 0x1a, 0x31, 0x20, 0x53, 0x68, 0x6f, 0x75, 0x6c, 0x64, 0x20, 0x6f, 0x6e, 0x6c, 0x79, - 0x20, 0x62, 0x65, 0x20, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x20, 0x66, 0x6f, 0x72, 0x20, - 0x43, 0x4f, 0x4e, 0x56, 0x45, 0x52, 0x53, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x54, 0x59, 0x50, - 0x45, 0x5f, 0x44, 0x4d, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x03, 0x04, 0x12, 0x03, - 0x0f, 0x02, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x03, 0x06, 0x12, 0x03, 0x0f, 0x0b, - 0x14, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x03, 0x01, 0x12, 0x03, 0x0f, 0x15, 0x1f, 0x0a, - 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x03, 0x03, 0x12, 0x03, 0x0f, 0x22, 0x23, 0x0a, 0x2e, 0x0a, - 0x02, 0x05, 0x00, 0x12, 0x04, 0x13, 0x00, 0x18, 0x01, 0x1a, 0x22, 0x20, 0x44, 0x65, 0x66, 0x69, - 0x6e, 0x65, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x79, 0x70, 0x65, 0x20, 0x6f, 0x66, 0x20, - 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x0a, 0x0a, 0x0a, 0x0a, - 0x03, 0x05, 0x00, 0x01, 0x12, 0x03, 0x13, 0x05, 0x15, 0x0a, 0x0b, 0x0a, 0x04, 0x05, 0x00, 0x02, - 0x00, 0x12, 0x03, 0x14, 0x02, 0x24, 0x0a, 0x0c, 0x0a, 0x05, 0x05, 0x00, 0x02, 0x00, 0x01, 0x12, - 0x03, 0x14, 0x02, 0x1f, 0x0a, 0x0c, 0x0a, 0x05, 0x05, 0x00, 0x02, 0x00, 0x02, 0x12, 0x03, 0x14, - 0x22, 0x23, 0x0a, 0x0b, 0x0a, 0x04, 0x05, 0x00, 0x02, 0x01, 0x12, 0x03, 0x15, 0x02, 0x1e, 0x0a, - 0x0c, 0x0a, 0x05, 0x05, 0x00, 0x02, 0x01, 0x01, 0x12, 0x03, 0x15, 0x02, 0x19, 0x0a, 0x0c, 0x0a, - 0x05, 0x05, 0x00, 0x02, 0x01, 0x02, 0x12, 0x03, 0x15, 0x1c, 0x1d, 0x0a, 0x0b, 0x0a, 0x04, 0x05, - 0x00, 0x02, 0x02, 0x12, 0x03, 0x16, 0x02, 0x1b, 0x0a, 0x0c, 0x0a, 0x05, 0x05, 0x00, 0x02, 0x02, - 0x01, 0x12, 0x03, 0x16, 0x02, 0x16, 0x0a, 0x0c, 0x0a, 0x05, 0x05, 0x00, 0x02, 0x02, 0x02, 0x12, - 0x03, 0x16, 0x19, 0x1a, 0x0a, 0x0b, 0x0a, 0x04, 0x05, 0x00, 0x02, 0x03, 0x12, 0x03, 0x17, 0x02, - 0x1d, 0x0a, 0x0c, 0x0a, 0x05, 0x05, 0x00, 0x02, 0x03, 0x01, 0x12, 0x03, 0x17, 0x02, 0x18, 0x0a, - 0x0c, 0x0a, 0x05, 0x05, 0x00, 0x02, 0x03, 0x02, 0x12, 0x03, 0x17, 0x1b, 0x1c, 0x0a, 0x28, 0x0a, - 0x02, 0x04, 0x01, 0x12, 0x04, 0x1b, 0x00, 0x1d, 0x01, 0x1a, 0x1c, 0x20, 0x57, 0x72, 0x61, 0x70, - 0x70, 0x65, 0x72, 0x20, 0x61, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x20, 0x61, 0x6e, 0x20, 0x49, 0x6e, - 0x62, 0x6f, 0x78, 0x20, 0x49, 0x64, 0x0a, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x01, 0x01, 0x12, 0x03, - 0x1b, 0x08, 0x0d, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x01, 0x02, 0x00, 0x12, 0x03, 0x1c, 0x02, 0x16, - 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x00, 0x05, 0x12, 0x03, 0x1c, 0x02, 0x08, 0x0a, 0x0c, - 0x0a, 0x05, 0x04, 0x01, 0x02, 0x00, 0x01, 0x12, 0x03, 0x1c, 0x09, 0x11, 0x0a, 0x0c, 0x0a, 0x05, - 0x04, 0x01, 0x02, 0x00, 0x03, 0x12, 0x03, 0x1c, 0x14, 0x15, 0x0a, 0x2b, 0x0a, 0x02, 0x04, 0x02, - 0x12, 0x04, 0x20, 0x00, 0x23, 0x01, 0x1a, 0x1f, 0x20, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x69, 0x6e, - 0x67, 0x20, 0x64, 0x6f, 0x65, 0x73, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x6d, 0x61, 0x74, 0x74, 0x65, - 0x72, 0x20, 0x68, 0x65, 0x72, 0x65, 0x0a, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x02, 0x01, 0x12, 0x03, - 0x20, 0x08, 0x11, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x02, 0x02, 0x00, 0x12, 0x03, 0x21, 0x02, 0x1a, - 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x00, 0x06, 0x12, 0x03, 0x21, 0x02, 0x07, 0x0a, 0x0c, - 0x0a, 0x05, 0x04, 0x02, 0x02, 0x00, 0x01, 0x12, 0x03, 0x21, 0x08, 0x15, 0x0a, 0x0c, 0x0a, 0x05, - 0x04, 0x02, 0x02, 0x00, 0x03, 0x12, 0x03, 0x21, 0x18, 0x19, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x02, - 0x02, 0x01, 0x12, 0x03, 0x22, 0x02, 0x1a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x01, 0x06, - 0x12, 0x03, 0x22, 0x02, 0x07, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x01, 0x01, 0x12, 0x03, - 0x22, 0x08, 0x15, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x01, 0x03, 0x12, 0x03, 0x22, 0x18, - 0x19, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, 0x0a, 0x92, 0x0a, 0x0a, 0x31, 0x6d, 0x6c, - 0x73, 0x2f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, - 0x74, 0x73, 0x2f, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x5f, 0x6d, 0x75, 0x74, 0x61, 0x62, 0x6c, 0x65, - 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, + 0x03, 0x7a, 0x12, 0x13, 0x0a, 0x3b, 0x0a, 0x02, 0x05, 0x02, 0x12, 0x05, 0x7e, 0x00, 0x83, 0x01, + 0x01, 0x1a, 0x2e, 0x20, 0x54, 0x68, 0x65, 0x20, 0x74, 0x79, 0x70, 0x65, 0x20, 0x6f, 0x66, 0x20, + 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x20, 0x74, 0x68, 0x65, 0x20, 0x75, 0x73, 0x65, 0x72, 0x20, + 0x69, 0x73, 0x20, 0x63, 0x6f, 0x6e, 0x73, 0x65, 0x6e, 0x74, 0x69, 0x6e, 0x67, 0x20, 0x74, 0x6f, + 0x0a, 0x0a, 0x0a, 0x0a, 0x03, 0x05, 0x02, 0x01, 0x12, 0x03, 0x7e, 0x05, 0x16, 0x0a, 0x0b, 0x0a, + 0x04, 0x05, 0x02, 0x02, 0x00, 0x12, 0x03, 0x7f, 0x02, 0x26, 0x0a, 0x0c, 0x0a, 0x05, 0x05, 0x02, + 0x02, 0x00, 0x01, 0x12, 0x03, 0x7f, 0x02, 0x21, 0x0a, 0x0c, 0x0a, 0x05, 0x05, 0x02, 0x02, 0x00, + 0x02, 0x12, 0x03, 0x7f, 0x24, 0x25, 0x0a, 0x0c, 0x0a, 0x04, 0x05, 0x02, 0x02, 0x01, 0x12, 0x04, + 0x80, 0x01, 0x02, 0x2a, 0x0a, 0x0d, 0x0a, 0x05, 0x05, 0x02, 0x02, 0x01, 0x01, 0x12, 0x04, 0x80, + 0x01, 0x02, 0x25, 0x0a, 0x0d, 0x0a, 0x05, 0x05, 0x02, 0x02, 0x01, 0x02, 0x12, 0x04, 0x80, 0x01, + 0x28, 0x29, 0x0a, 0x0c, 0x0a, 0x04, 0x05, 0x02, 0x02, 0x02, 0x12, 0x04, 0x81, 0x01, 0x02, 0x23, + 0x0a, 0x0d, 0x0a, 0x05, 0x05, 0x02, 0x02, 0x02, 0x01, 0x12, 0x04, 0x81, 0x01, 0x02, 0x1e, 0x0a, + 0x0d, 0x0a, 0x05, 0x05, 0x02, 0x02, 0x02, 0x02, 0x12, 0x04, 0x81, 0x01, 0x21, 0x22, 0x0a, 0x0c, + 0x0a, 0x04, 0x05, 0x02, 0x02, 0x03, 0x12, 0x04, 0x82, 0x01, 0x02, 0x22, 0x0a, 0x0d, 0x0a, 0x05, + 0x05, 0x02, 0x02, 0x03, 0x01, 0x12, 0x04, 0x82, 0x01, 0x02, 0x1d, 0x0a, 0x0d, 0x0a, 0x05, 0x05, + 0x02, 0x02, 0x03, 0x02, 0x12, 0x04, 0x82, 0x01, 0x20, 0x21, 0x0a, 0x2a, 0x0a, 0x02, 0x05, 0x03, + 0x12, 0x06, 0x86, 0x01, 0x00, 0x8a, 0x01, 0x01, 0x1a, 0x1c, 0x20, 0x50, 0x6f, 0x73, 0x73, 0x69, + 0x62, 0x6c, 0x65, 0x20, 0x73, 0x74, 0x61, 0x74, 0x65, 0x73, 0x20, 0x6f, 0x66, 0x20, 0x63, 0x6f, + 0x6e, 0x73, 0x65, 0x6e, 0x74, 0x0a, 0x0a, 0x0b, 0x0a, 0x03, 0x05, 0x03, 0x01, 0x12, 0x04, 0x86, + 0x01, 0x05, 0x11, 0x0a, 0x0c, 0x0a, 0x04, 0x05, 0x03, 0x02, 0x00, 0x12, 0x04, 0x87, 0x01, 0x02, + 0x20, 0x0a, 0x0d, 0x0a, 0x05, 0x05, 0x03, 0x02, 0x00, 0x01, 0x12, 0x04, 0x87, 0x01, 0x02, 0x1b, + 0x0a, 0x0d, 0x0a, 0x05, 0x05, 0x03, 0x02, 0x00, 0x02, 0x12, 0x04, 0x87, 0x01, 0x1e, 0x1f, 0x0a, + 0x0c, 0x0a, 0x04, 0x05, 0x03, 0x02, 0x01, 0x12, 0x04, 0x88, 0x01, 0x02, 0x1c, 0x0a, 0x0d, 0x0a, + 0x05, 0x05, 0x03, 0x02, 0x01, 0x01, 0x12, 0x04, 0x88, 0x01, 0x02, 0x17, 0x0a, 0x0d, 0x0a, 0x05, + 0x05, 0x03, 0x02, 0x01, 0x02, 0x12, 0x04, 0x88, 0x01, 0x1a, 0x1b, 0x0a, 0x0c, 0x0a, 0x04, 0x05, + 0x03, 0x02, 0x02, 0x12, 0x04, 0x89, 0x01, 0x02, 0x1b, 0x0a, 0x0d, 0x0a, 0x05, 0x05, 0x03, 0x02, + 0x02, 0x01, 0x12, 0x04, 0x89, 0x01, 0x02, 0x16, 0x0a, 0x0d, 0x0a, 0x05, 0x05, 0x03, 0x02, 0x02, + 0x02, 0x12, 0x04, 0x89, 0x01, 0x19, 0x1a, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, 0x0a, + 0x90, 0x06, 0x0a, 0x2b, 0x6d, 0x6c, 0x73, 0x2f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, + 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2f, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x5f, 0x6d, + 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x19, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x22, 0xcb, 0x02, 0x0a, 0x16, 0x47, - 0x72, 0x6f, 0x75, 0x70, 0x4d, 0x75, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, - 0x61, 0x74, 0x61, 0x56, 0x31, 0x12, 0x61, 0x0a, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, - 0x74, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x41, 0x2e, 0x78, 0x6d, 0x74, 0x70, - 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, - 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x4d, 0x75, 0x74, 0x61, 0x62, - 0x6c, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x56, 0x31, 0x2e, 0x41, 0x74, 0x74, - 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0a, 0x61, 0x74, - 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x12, 0x41, 0x0a, 0x0a, 0x61, 0x64, 0x6d, 0x69, - 0x6e, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x78, - 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, - 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x49, 0x6e, 0x62, 0x6f, 0x78, 0x65, 0x73, - 0x52, 0x09, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x4c, 0x0a, 0x10, 0x73, - 0x75, 0x70, 0x65, 0x72, 0x5f, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, - 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, - 0x73, 0x2e, 0x49, 0x6e, 0x62, 0x6f, 0x78, 0x65, 0x73, 0x52, 0x0e, 0x73, 0x75, 0x70, 0x65, 0x72, - 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x4c, 0x69, 0x73, 0x74, 0x1a, 0x3d, 0x0a, 0x0f, 0x41, 0x74, 0x74, - 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, - 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, - 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, - 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x26, 0x0a, 0x07, 0x49, 0x6e, 0x62, 0x6f, - 0x78, 0x65, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x69, 0x6e, 0x62, 0x6f, 0x78, 0x5f, 0x69, 0x64, 0x73, - 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x69, 0x6e, 0x62, 0x6f, 0x78, 0x49, 0x64, 0x73, - 0x42, 0xee, 0x01, 0x0a, 0x1d, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, + 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x22, 0xa0, 0x01, 0x0a, 0x0f, 0x47, + 0x72, 0x6f, 0x75, 0x70, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x12, 0x51, + 0x0a, 0x07, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x37, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x47, 0x72, 0x6f, 0x75, + 0x70, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x2e, 0x4d, 0x65, 0x6d, 0x62, + 0x65, 0x72, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, + 0x73, 0x1a, 0x3a, 0x0a, 0x0c, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x45, 0x6e, 0x74, 0x72, + 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, + 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x04, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x42, 0xe9, 0x01, + 0x0a, 0x1d, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x42, + 0x14, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, + 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x30, 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, 0x6d, 0x6c, 0x73, 0x2f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0xa2, 0x02, 0x03, 0x58, 0x4d, 0x4d, 0xaa, + 0x02, 0x18, 0x58, 0x6d, 0x74, 0x70, 0x2e, 0x4d, 0x6c, 0x73, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0xca, 0x02, 0x18, 0x58, 0x6d, 0x74, + 0x70, 0x5c, 0x4d, 0x6c, 0x73, 0x5c, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, + 0x74, 0x65, 0x6e, 0x74, 0x73, 0xe2, 0x02, 0x24, 0x58, 0x6d, 0x74, 0x70, 0x5c, 0x4d, 0x6c, 0x73, + 0x5c, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, + 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x1a, 0x58, + 0x6d, 0x74, 0x70, 0x3a, 0x3a, 0x4d, 0x6c, 0x73, 0x3a, 0x3a, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x4a, 0xae, 0x02, 0x0a, 0x06, 0x12, 0x04, + 0x01, 0x00, 0x0c, 0x01, 0x0a, 0x1c, 0x0a, 0x01, 0x0c, 0x12, 0x03, 0x01, 0x00, 0x12, 0x1a, 0x12, + 0x20, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x20, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, + 0x70, 0x0a, 0x0a, 0x08, 0x0a, 0x01, 0x02, 0x12, 0x03, 0x03, 0x00, 0x22, 0x0a, 0x08, 0x0a, 0x01, + 0x08, 0x12, 0x03, 0x05, 0x00, 0x47, 0x0a, 0x09, 0x0a, 0x02, 0x08, 0x0b, 0x12, 0x03, 0x05, 0x00, + 0x47, 0x0a, 0xa3, 0x01, 0x0a, 0x02, 0x04, 0x00, 0x12, 0x04, 0x0a, 0x00, 0x0c, 0x01, 0x1a, 0x96, + 0x01, 0x20, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x73, 0x20, 0x61, 0x20, 0x6d, 0x61, 0x70, + 0x70, 0x69, 0x6e, 0x67, 0x20, 0x6f, 0x66, 0x20, 0x60, 0x69, 0x6e, 0x62, 0x6f, 0x78, 0x5f, 0x69, + 0x64, 0x60, 0x20, 0x2d, 0x3e, 0x20, 0x60, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x5f, + 0x69, 0x64, 0x60, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x61, 0x6c, 0x6c, 0x20, 0x6d, 0x65, 0x6d, 0x62, + 0x65, 0x72, 0x73, 0x20, 0x6f, 0x66, 0x20, 0x61, 0x20, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x2e, 0x0a, + 0x20, 0x44, 0x65, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x20, 0x74, 0x6f, 0x20, 0x62, 0x65, 0x20, + 0x73, 0x74, 0x6f, 0x72, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x67, 0x72, + 0x6f, 0x75, 0x70, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x20, 0x65, 0x78, 0x74, 0x65, + 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x4d, 0x4c, 0x53, + 0x20, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x0a, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x00, 0x01, 0x12, 0x03, + 0x0a, 0x08, 0x17, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x00, 0x02, 0x00, 0x12, 0x03, 0x0b, 0x02, 0x22, + 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x00, 0x06, 0x12, 0x03, 0x0b, 0x02, 0x15, 0x0a, 0x0c, + 0x0a, 0x05, 0x04, 0x00, 0x02, 0x00, 0x01, 0x12, 0x03, 0x0b, 0x16, 0x1d, 0x0a, 0x0c, 0x0a, 0x05, + 0x04, 0x00, 0x02, 0x00, 0x03, 0x12, 0x03, 0x0b, 0x20, 0x21, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x33, 0x0a, 0xe5, 0x0e, 0x0a, 0x29, 0x6d, 0x6c, 0x73, 0x2f, 0x6d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2f, 0x67, 0x72, 0x6f, 0x75, + 0x70, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x12, 0x19, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x22, 0xa6, 0x02, 0x0a, 0x0f, + 0x47, 0x72, 0x6f, 0x75, 0x70, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x56, 0x31, 0x12, + 0x58, 0x0a, 0x11, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, + 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2b, 0x2e, 0x78, 0x6d, 0x74, + 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, + 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x43, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x10, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x12, 0x36, 0x0a, 0x17, 0x63, 0x72, 0x65, + 0x61, 0x74, 0x6f, 0x72, 0x5f, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x61, 0x64, 0x64, + 0x72, 0x65, 0x73, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x15, 0x63, 0x72, 0x65, 0x61, + 0x74, 0x6f, 0x72, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, + 0x73, 0x12, 0x28, 0x0a, 0x10, 0x63, 0x72, 0x65, 0x61, 0x74, 0x6f, 0x72, 0x5f, 0x69, 0x6e, 0x62, + 0x6f, 0x78, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x63, 0x72, 0x65, + 0x61, 0x74, 0x6f, 0x72, 0x49, 0x6e, 0x62, 0x6f, 0x78, 0x49, 0x64, 0x12, 0x48, 0x0a, 0x0a, 0x64, + 0x6d, 0x5f, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x24, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x44, 0x6d, 0x4d, 0x65, + 0x6d, 0x62, 0x65, 0x72, 0x73, 0x48, 0x00, 0x52, 0x09, 0x64, 0x6d, 0x4d, 0x65, 0x6d, 0x62, 0x65, + 0x72, 0x73, 0x88, 0x01, 0x01, 0x42, 0x0d, 0x0a, 0x0b, 0x5f, 0x64, 0x6d, 0x5f, 0x6d, 0x65, 0x6d, + 0x62, 0x65, 0x72, 0x73, 0x22, 0x22, 0x0a, 0x05, 0x49, 0x6e, 0x62, 0x6f, 0x78, 0x12, 0x19, 0x0a, + 0x08, 0x69, 0x6e, 0x62, 0x6f, 0x78, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x07, 0x69, 0x6e, 0x62, 0x6f, 0x78, 0x49, 0x64, 0x22, 0x97, 0x01, 0x0a, 0x09, 0x44, 0x6d, 0x4d, + 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x12, 0x44, 0x0a, 0x0d, 0x64, 0x6d, 0x5f, 0x6d, 0x65, 0x6d, + 0x62, 0x65, 0x72, 0x5f, 0x6f, 0x6e, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, + 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x49, 0x6e, 0x62, 0x6f, 0x78, 0x52, + 0x0b, 0x64, 0x6d, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x4f, 0x6e, 0x65, 0x12, 0x44, 0x0a, 0x0d, + 0x64, 0x6d, 0x5f, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x5f, 0x74, 0x77, 0x6f, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, + 0x49, 0x6e, 0x62, 0x6f, 0x78, 0x52, 0x0b, 0x64, 0x6d, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x54, + 0x77, 0x6f, 0x2a, 0x88, 0x01, 0x0a, 0x10, 0x43, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x12, 0x21, 0x0a, 0x1d, 0x43, 0x4f, 0x4e, 0x56, 0x45, + 0x52, 0x53, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x53, + 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x1b, 0x0a, 0x17, 0x43, 0x4f, + 0x4e, 0x56, 0x45, 0x52, 0x53, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, + 0x47, 0x52, 0x4f, 0x55, 0x50, 0x10, 0x01, 0x12, 0x18, 0x0a, 0x14, 0x43, 0x4f, 0x4e, 0x56, 0x45, + 0x52, 0x53, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x44, 0x4d, 0x10, + 0x02, 0x12, 0x1a, 0x0a, 0x16, 0x43, 0x4f, 0x4e, 0x56, 0x45, 0x52, 0x53, 0x41, 0x54, 0x49, 0x4f, + 0x4e, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x53, 0x59, 0x4e, 0x43, 0x10, 0x03, 0x42, 0xe7, 0x01, + 0x0a, 0x1d, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x42, + 0x12, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x50, 0x72, + 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x30, 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, 0x6d, 0x6c, 0x73, 0x2f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, + 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0xa2, 0x02, 0x03, 0x58, 0x4d, 0x4d, 0xaa, 0x02, 0x18, + 0x58, 0x6d, 0x74, 0x70, 0x2e, 0x4d, 0x6c, 0x73, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0xca, 0x02, 0x18, 0x58, 0x6d, 0x74, 0x70, 0x5c, + 0x4d, 0x6c, 0x73, 0x5c, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, + 0x6e, 0x74, 0x73, 0xe2, 0x02, 0x24, 0x58, 0x6d, 0x74, 0x70, 0x5c, 0x4d, 0x6c, 0x73, 0x5c, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x5c, 0x47, + 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x1a, 0x58, 0x6d, 0x74, + 0x70, 0x3a, 0x3a, 0x4d, 0x6c, 0x73, 0x3a, 0x3a, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x43, + 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x4a, 0xb8, 0x07, 0x0a, 0x06, 0x12, 0x04, 0x01, 0x00, + 0x23, 0x01, 0x0a, 0x24, 0x0a, 0x01, 0x0c, 0x12, 0x03, 0x01, 0x00, 0x12, 0x1a, 0x1a, 0x20, 0x47, + 0x72, 0x6f, 0x75, 0x70, 0x20, 0x69, 0x6d, 0x6d, 0x75, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x6d, + 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x0a, 0x0a, 0x08, 0x0a, 0x01, 0x02, 0x12, 0x03, 0x03, + 0x00, 0x22, 0x0a, 0x08, 0x0a, 0x01, 0x08, 0x12, 0x03, 0x05, 0x00, 0x47, 0x0a, 0x09, 0x0a, 0x02, + 0x08, 0x0b, 0x12, 0x03, 0x05, 0x00, 0x47, 0x0a, 0x2f, 0x0a, 0x02, 0x04, 0x00, 0x12, 0x04, 0x09, + 0x00, 0x10, 0x01, 0x1a, 0x23, 0x20, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x20, 0x6d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x20, 0x6d, + 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x0a, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x00, 0x01, 0x12, + 0x03, 0x09, 0x08, 0x17, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x00, 0x02, 0x00, 0x12, 0x03, 0x0a, 0x02, + 0x29, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x00, 0x06, 0x12, 0x03, 0x0a, 0x02, 0x12, 0x0a, + 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x00, 0x01, 0x12, 0x03, 0x0a, 0x13, 0x24, 0x0a, 0x0c, 0x0a, + 0x05, 0x04, 0x00, 0x02, 0x00, 0x03, 0x12, 0x03, 0x0a, 0x27, 0x28, 0x0a, 0x28, 0x0a, 0x04, 0x04, + 0x00, 0x02, 0x01, 0x12, 0x03, 0x0c, 0x02, 0x25, 0x1a, 0x1b, 0x20, 0x54, 0x68, 0x69, 0x73, 0x20, + 0x77, 0x69, 0x6c, 0x6c, 0x20, 0x62, 0x65, 0x20, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x20, + 0x73, 0x6f, 0x6f, 0x6e, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x01, 0x05, 0x12, 0x03, + 0x0c, 0x02, 0x08, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x01, 0x01, 0x12, 0x03, 0x0c, 0x09, + 0x20, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x01, 0x03, 0x12, 0x03, 0x0c, 0x23, 0x24, 0x0a, + 0x0b, 0x0a, 0x04, 0x04, 0x00, 0x02, 0x02, 0x12, 0x03, 0x0d, 0x02, 0x1e, 0x0a, 0x0c, 0x0a, 0x05, + 0x04, 0x00, 0x02, 0x02, 0x05, 0x12, 0x03, 0x0d, 0x02, 0x08, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, + 0x02, 0x02, 0x01, 0x12, 0x03, 0x0d, 0x09, 0x19, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x02, + 0x03, 0x12, 0x03, 0x0d, 0x1c, 0x1d, 0x0a, 0x3e, 0x0a, 0x04, 0x04, 0x00, 0x02, 0x03, 0x12, 0x03, + 0x0f, 0x02, 0x24, 0x1a, 0x31, 0x20, 0x53, 0x68, 0x6f, 0x75, 0x6c, 0x64, 0x20, 0x6f, 0x6e, 0x6c, + 0x79, 0x20, 0x62, 0x65, 0x20, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x20, 0x66, 0x6f, 0x72, + 0x20, 0x43, 0x4f, 0x4e, 0x56, 0x45, 0x52, 0x53, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x54, 0x59, + 0x50, 0x45, 0x5f, 0x44, 0x4d, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x03, 0x04, 0x12, + 0x03, 0x0f, 0x02, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x03, 0x06, 0x12, 0x03, 0x0f, + 0x0b, 0x14, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x03, 0x01, 0x12, 0x03, 0x0f, 0x15, 0x1f, + 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x03, 0x03, 0x12, 0x03, 0x0f, 0x22, 0x23, 0x0a, 0x2e, + 0x0a, 0x02, 0x05, 0x00, 0x12, 0x04, 0x13, 0x00, 0x18, 0x01, 0x1a, 0x22, 0x20, 0x44, 0x65, 0x66, + 0x69, 0x6e, 0x65, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x79, 0x70, 0x65, 0x20, 0x6f, 0x66, + 0x20, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x0a, 0x0a, 0x0a, + 0x0a, 0x03, 0x05, 0x00, 0x01, 0x12, 0x03, 0x13, 0x05, 0x15, 0x0a, 0x0b, 0x0a, 0x04, 0x05, 0x00, + 0x02, 0x00, 0x12, 0x03, 0x14, 0x02, 0x24, 0x0a, 0x0c, 0x0a, 0x05, 0x05, 0x00, 0x02, 0x00, 0x01, + 0x12, 0x03, 0x14, 0x02, 0x1f, 0x0a, 0x0c, 0x0a, 0x05, 0x05, 0x00, 0x02, 0x00, 0x02, 0x12, 0x03, + 0x14, 0x22, 0x23, 0x0a, 0x0b, 0x0a, 0x04, 0x05, 0x00, 0x02, 0x01, 0x12, 0x03, 0x15, 0x02, 0x1e, + 0x0a, 0x0c, 0x0a, 0x05, 0x05, 0x00, 0x02, 0x01, 0x01, 0x12, 0x03, 0x15, 0x02, 0x19, 0x0a, 0x0c, + 0x0a, 0x05, 0x05, 0x00, 0x02, 0x01, 0x02, 0x12, 0x03, 0x15, 0x1c, 0x1d, 0x0a, 0x0b, 0x0a, 0x04, + 0x05, 0x00, 0x02, 0x02, 0x12, 0x03, 0x16, 0x02, 0x1b, 0x0a, 0x0c, 0x0a, 0x05, 0x05, 0x00, 0x02, + 0x02, 0x01, 0x12, 0x03, 0x16, 0x02, 0x16, 0x0a, 0x0c, 0x0a, 0x05, 0x05, 0x00, 0x02, 0x02, 0x02, + 0x12, 0x03, 0x16, 0x19, 0x1a, 0x0a, 0x0b, 0x0a, 0x04, 0x05, 0x00, 0x02, 0x03, 0x12, 0x03, 0x17, + 0x02, 0x1d, 0x0a, 0x0c, 0x0a, 0x05, 0x05, 0x00, 0x02, 0x03, 0x01, 0x12, 0x03, 0x17, 0x02, 0x18, + 0x0a, 0x0c, 0x0a, 0x05, 0x05, 0x00, 0x02, 0x03, 0x02, 0x12, 0x03, 0x17, 0x1b, 0x1c, 0x0a, 0x28, + 0x0a, 0x02, 0x04, 0x01, 0x12, 0x04, 0x1b, 0x00, 0x1d, 0x01, 0x1a, 0x1c, 0x20, 0x57, 0x72, 0x61, + 0x70, 0x70, 0x65, 0x72, 0x20, 0x61, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x20, 0x61, 0x6e, 0x20, 0x49, + 0x6e, 0x62, 0x6f, 0x78, 0x20, 0x49, 0x64, 0x0a, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x01, 0x01, 0x12, + 0x03, 0x1b, 0x08, 0x0d, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x01, 0x02, 0x00, 0x12, 0x03, 0x1c, 0x02, + 0x16, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x00, 0x05, 0x12, 0x03, 0x1c, 0x02, 0x08, 0x0a, + 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x00, 0x01, 0x12, 0x03, 0x1c, 0x09, 0x11, 0x0a, 0x0c, 0x0a, + 0x05, 0x04, 0x01, 0x02, 0x00, 0x03, 0x12, 0x03, 0x1c, 0x14, 0x15, 0x0a, 0x2b, 0x0a, 0x02, 0x04, + 0x02, 0x12, 0x04, 0x20, 0x00, 0x23, 0x01, 0x1a, 0x1f, 0x20, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x69, + 0x6e, 0x67, 0x20, 0x64, 0x6f, 0x65, 0x73, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x6d, 0x61, 0x74, 0x74, + 0x65, 0x72, 0x20, 0x68, 0x65, 0x72, 0x65, 0x0a, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x02, 0x01, 0x12, + 0x03, 0x20, 0x08, 0x11, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x02, 0x02, 0x00, 0x12, 0x03, 0x21, 0x02, + 0x1a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x00, 0x06, 0x12, 0x03, 0x21, 0x02, 0x07, 0x0a, + 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x00, 0x01, 0x12, 0x03, 0x21, 0x08, 0x15, 0x0a, 0x0c, 0x0a, + 0x05, 0x04, 0x02, 0x02, 0x00, 0x03, 0x12, 0x03, 0x21, 0x18, 0x19, 0x0a, 0x0b, 0x0a, 0x04, 0x04, + 0x02, 0x02, 0x01, 0x12, 0x03, 0x22, 0x02, 0x1a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x01, + 0x06, 0x12, 0x03, 0x22, 0x02, 0x07, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x01, 0x01, 0x12, + 0x03, 0x22, 0x08, 0x15, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x01, 0x03, 0x12, 0x03, 0x22, + 0x18, 0x19, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, 0x0a, 0x92, 0x0a, 0x0a, 0x31, 0x6d, + 0x6c, 0x73, 0x2f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, + 0x6e, 0x74, 0x73, 0x2f, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x5f, 0x6d, 0x75, 0x74, 0x61, 0x62, 0x6c, + 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x12, 0x19, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x22, 0xcb, 0x02, 0x0a, 0x16, + 0x47, 0x72, 0x6f, 0x75, 0x70, 0x4d, 0x75, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x4d, 0x65, 0x74, 0x61, + 0x64, 0x61, 0x74, 0x61, 0x56, 0x31, 0x12, 0x61, 0x0a, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, + 0x75, 0x74, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x41, 0x2e, 0x78, 0x6d, 0x74, + 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, + 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x4d, 0x75, 0x74, 0x61, + 0x62, 0x6c, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x56, 0x31, 0x2e, 0x41, 0x74, + 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0a, 0x61, + 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x12, 0x41, 0x0a, 0x0a, 0x61, 0x64, 0x6d, + 0x69, 0x6e, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, + 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x49, 0x6e, 0x62, 0x6f, 0x78, 0x65, + 0x73, 0x52, 0x09, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x4c, 0x0a, 0x10, + 0x73, 0x75, 0x70, 0x65, 0x72, 0x5f, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x5f, 0x6c, 0x69, 0x73, 0x74, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, - 0x74, 0x73, 0x42, 0x19, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x4d, 0x75, 0x74, 0x61, 0x62, 0x6c, 0x65, - 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, - 0x30, 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, 0x6d, 0x6c, 0x73, - 0x2f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, - 0x73, 0xa2, 0x02, 0x03, 0x58, 0x4d, 0x4d, 0xaa, 0x02, 0x18, 0x58, 0x6d, 0x74, 0x70, 0x2e, 0x4d, - 0x6c, 0x73, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, - 0x74, 0x73, 0xca, 0x02, 0x18, 0x58, 0x6d, 0x74, 0x70, 0x5c, 0x4d, 0x6c, 0x73, 0x5c, 0x4d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0xe2, 0x02, 0x24, - 0x58, 0x6d, 0x74, 0x70, 0x5c, 0x4d, 0x6c, 0x73, 0x5c, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, - 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x1a, 0x58, 0x6d, 0x74, 0x70, 0x3a, 0x3a, 0x4d, 0x6c, 0x73, - 0x3a, 0x3a, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, - 0x73, 0x4a, 0xd2, 0x04, 0x0a, 0x06, 0x12, 0x04, 0x01, 0x00, 0x16, 0x01, 0x0a, 0x22, 0x0a, 0x01, - 0x0c, 0x12, 0x03, 0x01, 0x00, 0x12, 0x1a, 0x18, 0x20, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x20, 0x6d, - 0x75, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x0a, - 0x0a, 0x08, 0x0a, 0x01, 0x02, 0x12, 0x03, 0x03, 0x00, 0x22, 0x0a, 0x08, 0x0a, 0x01, 0x08, 0x12, - 0x03, 0x05, 0x00, 0x47, 0x0a, 0x09, 0x0a, 0x02, 0x08, 0x0b, 0x12, 0x03, 0x05, 0x00, 0x47, 0x0a, - 0x30, 0x0a, 0x02, 0x04, 0x00, 0x12, 0x04, 0x0a, 0x00, 0x11, 0x01, 0x1a, 0x24, 0x20, 0x4d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x20, + 0x74, 0x73, 0x2e, 0x49, 0x6e, 0x62, 0x6f, 0x78, 0x65, 0x73, 0x52, 0x0e, 0x73, 0x75, 0x70, 0x65, + 0x72, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x4c, 0x69, 0x73, 0x74, 0x1a, 0x3d, 0x0a, 0x0f, 0x41, 0x74, + 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, + 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, + 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x26, 0x0a, 0x07, 0x49, 0x6e, 0x62, + 0x6f, 0x78, 0x65, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x69, 0x6e, 0x62, 0x6f, 0x78, 0x5f, 0x69, 0x64, + 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x69, 0x6e, 0x62, 0x6f, 0x78, 0x49, 0x64, + 0x73, 0x42, 0xee, 0x01, 0x0a, 0x1d, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, + 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, + 0x6e, 0x74, 0x73, 0x42, 0x19, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x4d, 0x75, 0x74, 0x61, 0x62, 0x6c, + 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, + 0x5a, 0x30, 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, 0x6d, 0x6c, + 0x73, 0x2f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, + 0x74, 0x73, 0xa2, 0x02, 0x03, 0x58, 0x4d, 0x4d, 0xaa, 0x02, 0x18, 0x58, 0x6d, 0x74, 0x70, 0x2e, + 0x4d, 0x6c, 0x73, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, + 0x6e, 0x74, 0x73, 0xca, 0x02, 0x18, 0x58, 0x6d, 0x74, 0x70, 0x5c, 0x4d, 0x6c, 0x73, 0x5c, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0xe2, 0x02, + 0x24, 0x58, 0x6d, 0x74, 0x70, 0x5c, 0x4d, 0x6c, 0x73, 0x5c, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, + 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x1a, 0x58, 0x6d, 0x74, 0x70, 0x3a, 0x3a, 0x4d, 0x6c, + 0x73, 0x3a, 0x3a, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, + 0x74, 0x73, 0x4a, 0xd2, 0x04, 0x0a, 0x06, 0x12, 0x04, 0x01, 0x00, 0x16, 0x01, 0x0a, 0x22, 0x0a, + 0x01, 0x0c, 0x12, 0x03, 0x01, 0x00, 0x12, 0x1a, 0x18, 0x20, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x20, 0x6d, 0x75, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, - 0x0a, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x00, 0x01, 0x12, 0x03, 0x0a, 0x08, 0x1e, 0x0a, 0x4a, 0x0a, - 0x04, 0x04, 0x00, 0x02, 0x00, 0x12, 0x03, 0x0c, 0x02, 0x25, 0x1a, 0x3d, 0x20, 0x4d, 0x61, 0x70, - 0x20, 0x74, 0x6f, 0x20, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x20, 0x76, 0x61, 0x72, 0x69, 0x6f, 0x75, - 0x73, 0x20, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x20, 0x61, 0x74, 0x74, 0x72, 0x69, - 0x62, 0x75, 0x74, 0x65, 0x73, 0x20, 0x28, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x20, 0x6e, 0x61, 0x6d, - 0x65, 0x2c, 0x20, 0x65, 0x74, 0x63, 0x2e, 0x29, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, - 0x00, 0x06, 0x12, 0x03, 0x0c, 0x02, 0x15, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x00, 0x01, - 0x12, 0x03, 0x0c, 0x16, 0x20, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x00, 0x03, 0x12, 0x03, - 0x0c, 0x23, 0x24, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x00, 0x02, 0x01, 0x12, 0x03, 0x0d, 0x02, 0x19, - 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x01, 0x06, 0x12, 0x03, 0x0d, 0x02, 0x09, 0x0a, 0x0c, - 0x0a, 0x05, 0x04, 0x00, 0x02, 0x01, 0x01, 0x12, 0x03, 0x0d, 0x0a, 0x14, 0x0a, 0x0c, 0x0a, 0x05, - 0x04, 0x00, 0x02, 0x01, 0x03, 0x12, 0x03, 0x0d, 0x17, 0x18, 0x0a, 0x64, 0x0a, 0x04, 0x04, 0x00, - 0x02, 0x02, 0x12, 0x03, 0x10, 0x02, 0x1f, 0x1a, 0x57, 0x20, 0x43, 0x72, 0x65, 0x61, 0x74, 0x6f, - 0x72, 0x20, 0x73, 0x74, 0x61, 0x72, 0x74, 0x73, 0x20, 0x61, 0x73, 0x20, 0x6f, 0x6e, 0x6c, 0x79, - 0x20, 0x73, 0x75, 0x70, 0x65, 0x72, 0x5f, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x0a, 0x20, 0x4f, 0x6e, - 0x6c, 0x79, 0x20, 0x73, 0x75, 0x70, 0x65, 0x72, 0x5f, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x20, 0x63, - 0x61, 0x6e, 0x20, 0x61, 0x64, 0x64, 0x2f, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x20, 0x6f, 0x74, - 0x68, 0x65, 0x72, 0x20, 0x73, 0x75, 0x70, 0x65, 0x72, 0x5f, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x0a, - 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x02, 0x06, 0x12, 0x03, 0x10, 0x02, 0x09, 0x0a, 0x0c, - 0x0a, 0x05, 0x04, 0x00, 0x02, 0x02, 0x01, 0x12, 0x03, 0x10, 0x0a, 0x1a, 0x0a, 0x0c, 0x0a, 0x05, - 0x04, 0x00, 0x02, 0x02, 0x03, 0x12, 0x03, 0x10, 0x1d, 0x1e, 0x0a, 0x39, 0x0a, 0x02, 0x04, 0x01, - 0x12, 0x04, 0x14, 0x00, 0x16, 0x01, 0x1a, 0x2d, 0x20, 0x57, 0x72, 0x61, 0x70, 0x70, 0x65, 0x72, - 0x20, 0x61, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x20, 0x61, 0x20, 0x6c, 0x69, 0x73, 0x74, 0x20, 0x6f, - 0x66, 0x20, 0x72, 0x65, 0x70, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x49, 0x6e, 0x62, 0x6f, 0x78, - 0x20, 0x49, 0x64, 0x73, 0x0a, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x01, 0x01, 0x12, 0x03, 0x14, 0x08, - 0x0f, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x01, 0x02, 0x00, 0x12, 0x03, 0x15, 0x02, 0x20, 0x0a, 0x0c, - 0x0a, 0x05, 0x04, 0x01, 0x02, 0x00, 0x04, 0x12, 0x03, 0x15, 0x02, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, - 0x04, 0x01, 0x02, 0x00, 0x05, 0x12, 0x03, 0x15, 0x0b, 0x11, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, - 0x02, 0x00, 0x01, 0x12, 0x03, 0x15, 0x12, 0x1b, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x00, - 0x03, 0x12, 0x03, 0x15, 0x1e, 0x1f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, 0x0a, 0xfb, - 0x31, 0x0a, 0x2c, 0x6d, 0x6c, 0x73, 0x2f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, - 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2f, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x5f, 0x70, 0x65, - 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, - 0x19, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x22, 0x5d, 0x0a, 0x19, 0x47, 0x72, - 0x6f, 0x75, 0x70, 0x4d, 0x75, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, - 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x56, 0x31, 0x12, 0x40, 0x0a, 0x08, 0x70, 0x6f, 0x6c, 0x69, 0x63, - 0x69, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x78, 0x6d, 0x74, 0x70, - 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, - 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x53, 0x65, 0x74, 0x52, - 0x08, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x22, 0xdf, 0x05, 0x0a, 0x09, 0x50, 0x6f, - 0x6c, 0x69, 0x63, 0x79, 0x53, 0x65, 0x74, 0x12, 0x57, 0x0a, 0x11, 0x61, 0x64, 0x64, 0x5f, 0x6d, - 0x65, 0x6d, 0x62, 0x65, 0x72, 0x5f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x4d, - 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, - 0x0f, 0x61, 0x64, 0x64, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, - 0x12, 0x5d, 0x0a, 0x14, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x5f, 0x6d, 0x65, 0x6d, 0x62, 0x65, - 0x72, 0x5f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, - 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x4d, 0x65, 0x6d, 0x62, 0x65, - 0x72, 0x73, 0x68, 0x69, 0x70, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x12, 0x72, 0x65, 0x6d, - 0x6f, 0x76, 0x65, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, - 0x74, 0x0a, 0x16, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, - 0x74, 0x61, 0x5f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, - 0x3e, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x50, 0x6f, 0x6c, 0x69, - 0x63, 0x79, 0x53, 0x65, 0x74, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4d, 0x65, 0x74, 0x61, - 0x64, 0x61, 0x74, 0x61, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, - 0x14, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x50, - 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x5c, 0x0a, 0x10, 0x61, 0x64, 0x64, 0x5f, 0x61, 0x64, 0x6d, - 0x69, 0x6e, 0x5f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x32, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x50, 0x65, 0x72, 0x6d, - 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, 0x6f, 0x6c, - 0x69, 0x63, 0x79, 0x52, 0x0e, 0x61, 0x64, 0x64, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x50, 0x6f, 0x6c, - 0x69, 0x63, 0x79, 0x12, 0x62, 0x0a, 0x13, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x5f, 0x61, 0x64, - 0x6d, 0x69, 0x6e, 0x5f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, + 0x0a, 0x0a, 0x08, 0x0a, 0x01, 0x02, 0x12, 0x03, 0x03, 0x00, 0x22, 0x0a, 0x08, 0x0a, 0x01, 0x08, + 0x12, 0x03, 0x05, 0x00, 0x47, 0x0a, 0x09, 0x0a, 0x02, 0x08, 0x0b, 0x12, 0x03, 0x05, 0x00, 0x47, + 0x0a, 0x30, 0x0a, 0x02, 0x04, 0x00, 0x12, 0x04, 0x0a, 0x00, 0x11, 0x01, 0x1a, 0x24, 0x20, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x67, 0x72, 0x6f, 0x75, 0x70, + 0x20, 0x6d, 0x75, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, + 0x61, 0x0a, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x00, 0x01, 0x12, 0x03, 0x0a, 0x08, 0x1e, 0x0a, 0x4a, + 0x0a, 0x04, 0x04, 0x00, 0x02, 0x00, 0x12, 0x03, 0x0c, 0x02, 0x25, 0x1a, 0x3d, 0x20, 0x4d, 0x61, + 0x70, 0x20, 0x74, 0x6f, 0x20, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x20, 0x76, 0x61, 0x72, 0x69, 0x6f, + 0x75, 0x73, 0x20, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x20, 0x61, 0x74, 0x74, 0x72, + 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x20, 0x28, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x20, 0x6e, 0x61, + 0x6d, 0x65, 0x2c, 0x20, 0x65, 0x74, 0x63, 0x2e, 0x29, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, + 0x02, 0x00, 0x06, 0x12, 0x03, 0x0c, 0x02, 0x15, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x00, + 0x01, 0x12, 0x03, 0x0c, 0x16, 0x20, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x00, 0x03, 0x12, + 0x03, 0x0c, 0x23, 0x24, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x00, 0x02, 0x01, 0x12, 0x03, 0x0d, 0x02, + 0x19, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x01, 0x06, 0x12, 0x03, 0x0d, 0x02, 0x09, 0x0a, + 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x01, 0x01, 0x12, 0x03, 0x0d, 0x0a, 0x14, 0x0a, 0x0c, 0x0a, + 0x05, 0x04, 0x00, 0x02, 0x01, 0x03, 0x12, 0x03, 0x0d, 0x17, 0x18, 0x0a, 0x64, 0x0a, 0x04, 0x04, + 0x00, 0x02, 0x02, 0x12, 0x03, 0x10, 0x02, 0x1f, 0x1a, 0x57, 0x20, 0x43, 0x72, 0x65, 0x61, 0x74, + 0x6f, 0x72, 0x20, 0x73, 0x74, 0x61, 0x72, 0x74, 0x73, 0x20, 0x61, 0x73, 0x20, 0x6f, 0x6e, 0x6c, + 0x79, 0x20, 0x73, 0x75, 0x70, 0x65, 0x72, 0x5f, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x0a, 0x20, 0x4f, + 0x6e, 0x6c, 0x79, 0x20, 0x73, 0x75, 0x70, 0x65, 0x72, 0x5f, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x20, + 0x63, 0x61, 0x6e, 0x20, 0x61, 0x64, 0x64, 0x2f, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x20, 0x6f, + 0x74, 0x68, 0x65, 0x72, 0x20, 0x73, 0x75, 0x70, 0x65, 0x72, 0x5f, 0x61, 0x64, 0x6d, 0x69, 0x6e, + 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x02, 0x06, 0x12, 0x03, 0x10, 0x02, 0x09, 0x0a, + 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x02, 0x01, 0x12, 0x03, 0x10, 0x0a, 0x1a, 0x0a, 0x0c, 0x0a, + 0x05, 0x04, 0x00, 0x02, 0x02, 0x03, 0x12, 0x03, 0x10, 0x1d, 0x1e, 0x0a, 0x39, 0x0a, 0x02, 0x04, + 0x01, 0x12, 0x04, 0x14, 0x00, 0x16, 0x01, 0x1a, 0x2d, 0x20, 0x57, 0x72, 0x61, 0x70, 0x70, 0x65, + 0x72, 0x20, 0x61, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x20, 0x61, 0x20, 0x6c, 0x69, 0x73, 0x74, 0x20, + 0x6f, 0x66, 0x20, 0x72, 0x65, 0x70, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x49, 0x6e, 0x62, 0x6f, + 0x78, 0x20, 0x49, 0x64, 0x73, 0x0a, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x01, 0x01, 0x12, 0x03, 0x14, + 0x08, 0x0f, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x01, 0x02, 0x00, 0x12, 0x03, 0x15, 0x02, 0x20, 0x0a, + 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x00, 0x04, 0x12, 0x03, 0x15, 0x02, 0x0a, 0x0a, 0x0c, 0x0a, + 0x05, 0x04, 0x01, 0x02, 0x00, 0x05, 0x12, 0x03, 0x15, 0x0b, 0x11, 0x0a, 0x0c, 0x0a, 0x05, 0x04, + 0x01, 0x02, 0x00, 0x01, 0x12, 0x03, 0x15, 0x12, 0x1b, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, + 0x00, 0x03, 0x12, 0x03, 0x15, 0x1e, 0x1f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, 0x0a, + 0xfb, 0x31, 0x0a, 0x2c, 0x6d, 0x6c, 0x73, 0x2f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, + 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2f, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x5f, 0x70, + 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x12, 0x19, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x22, 0x5d, 0x0a, 0x19, 0x47, + 0x72, 0x6f, 0x75, 0x70, 0x4d, 0x75, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x50, 0x65, 0x72, 0x6d, 0x69, + 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x56, 0x31, 0x12, 0x40, 0x0a, 0x08, 0x70, 0x6f, 0x6c, 0x69, + 0x63, 0x69, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x78, 0x6d, 0x74, + 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, + 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x53, 0x65, 0x74, + 0x52, 0x08, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x22, 0xdf, 0x05, 0x0a, 0x09, 0x50, + 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x53, 0x65, 0x74, 0x12, 0x57, 0x0a, 0x11, 0x61, 0x64, 0x64, 0x5f, + 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x5f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, + 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, + 0x52, 0x0f, 0x61, 0x64, 0x64, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x50, 0x6f, 0x6c, 0x69, 0x63, + 0x79, 0x12, 0x5d, 0x0a, 0x14, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x5f, 0x6d, 0x65, 0x6d, 0x62, + 0x65, 0x72, 0x5f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x2b, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x4d, 0x65, 0x6d, 0x62, + 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x12, 0x72, 0x65, + 0x6d, 0x6f, 0x76, 0x65, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, + 0x12, 0x74, 0x0a, 0x16, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, + 0x61, 0x74, 0x61, 0x5f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x3e, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x50, 0x6f, 0x6c, + 0x69, 0x63, 0x79, 0x53, 0x65, 0x74, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4d, 0x65, 0x74, + 0x61, 0x64, 0x61, 0x74, 0x61, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x45, 0x6e, 0x74, 0x72, 0x79, + 0x52, 0x14, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, + 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x5c, 0x0a, 0x10, 0x61, 0x64, 0x64, 0x5f, 0x61, 0x64, + 0x6d, 0x69, 0x6e, 0x5f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x32, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, 0x6f, - 0x6c, 0x69, 0x63, 0x79, 0x52, 0x11, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x41, 0x64, 0x6d, 0x69, - 0x6e, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x6e, 0x0a, 0x19, 0x75, 0x70, 0x64, 0x61, 0x74, - 0x65, 0x5f, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x5f, 0x70, 0x6f, - 0x6c, 0x69, 0x63, 0x79, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x32, 0x2e, 0x78, 0x6d, 0x74, - 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, - 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, - 0x6e, 0x73, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x17, - 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, - 0x73, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x1a, 0x72, 0x0a, 0x19, 0x55, 0x70, 0x64, 0x61, 0x74, - 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x45, - 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x3f, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, - 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, - 0x73, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, - 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x8a, 0x05, 0x0a, 0x10, - 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, - 0x12, 0x4c, 0x0a, 0x04, 0x62, 0x61, 0x73, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x36, - 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x4d, 0x65, 0x6d, 0x62, 0x65, - 0x72, 0x73, 0x68, 0x69, 0x70, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x42, 0x61, 0x73, 0x65, - 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x48, 0x00, 0x52, 0x04, 0x62, 0x61, 0x73, 0x65, 0x12, 0x5f, - 0x0a, 0x0d, 0x61, 0x6e, 0x64, 0x5f, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x38, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, - 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, - 0x73, 0x2e, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x50, 0x6f, 0x6c, 0x69, - 0x63, 0x79, 0x2e, 0x41, 0x6e, 0x64, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x48, - 0x00, 0x52, 0x0c, 0x61, 0x6e, 0x64, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, - 0x5f, 0x0a, 0x0d, 0x61, 0x6e, 0x79, 0x5f, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x38, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, - 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, - 0x74, 0x73, 0x2e, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x50, 0x6f, 0x6c, - 0x69, 0x63, 0x79, 0x2e, 0x41, 0x6e, 0x79, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, - 0x48, 0x00, 0x52, 0x0c, 0x61, 0x6e, 0x79, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, - 0x1a, 0x57, 0x0a, 0x0c, 0x41, 0x6e, 0x64, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, - 0x12, 0x47, 0x0a, 0x08, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, - 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x4d, - 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, - 0x08, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x1a, 0x57, 0x0a, 0x0c, 0x41, 0x6e, 0x79, - 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x47, 0x0a, 0x08, 0x70, 0x6f, 0x6c, - 0x69, 0x63, 0x69, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x78, 0x6d, + 0x6c, 0x69, 0x63, 0x79, 0x52, 0x0e, 0x61, 0x64, 0x64, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x50, 0x6f, + 0x6c, 0x69, 0x63, 0x79, 0x12, 0x62, 0x0a, 0x13, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x5f, 0x61, + 0x64, 0x6d, 0x69, 0x6e, 0x5f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x32, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x50, 0x65, + 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, + 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x11, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x41, 0x64, 0x6d, + 0x69, 0x6e, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x6e, 0x0a, 0x19, 0x75, 0x70, 0x64, 0x61, + 0x74, 0x65, 0x5f, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x5f, 0x70, + 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x32, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, - 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, - 0x69, 0x70, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x08, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x69, - 0x65, 0x73, 0x22, 0xab, 0x01, 0x0a, 0x0a, 0x42, 0x61, 0x73, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, - 0x79, 0x12, 0x1b, 0x0a, 0x17, 0x42, 0x41, 0x53, 0x45, 0x5f, 0x50, 0x4f, 0x4c, 0x49, 0x43, 0x59, - 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x15, - 0x0a, 0x11, 0x42, 0x41, 0x53, 0x45, 0x5f, 0x50, 0x4f, 0x4c, 0x49, 0x43, 0x59, 0x5f, 0x41, 0x4c, - 0x4c, 0x4f, 0x57, 0x10, 0x01, 0x12, 0x14, 0x0a, 0x10, 0x42, 0x41, 0x53, 0x45, 0x5f, 0x50, 0x4f, - 0x4c, 0x49, 0x43, 0x59, 0x5f, 0x44, 0x45, 0x4e, 0x59, 0x10, 0x02, 0x12, 0x2d, 0x0a, 0x29, 0x42, - 0x41, 0x53, 0x45, 0x5f, 0x50, 0x4f, 0x4c, 0x49, 0x43, 0x59, 0x5f, 0x41, 0x4c, 0x4c, 0x4f, 0x57, - 0x5f, 0x49, 0x46, 0x5f, 0x41, 0x44, 0x4d, 0x49, 0x4e, 0x5f, 0x4f, 0x52, 0x5f, 0x53, 0x55, 0x50, - 0x45, 0x52, 0x5f, 0x41, 0x44, 0x4d, 0x49, 0x4e, 0x10, 0x03, 0x12, 0x24, 0x0a, 0x20, 0x42, 0x41, - 0x53, 0x45, 0x5f, 0x50, 0x4f, 0x4c, 0x49, 0x43, 0x59, 0x5f, 0x41, 0x4c, 0x4c, 0x4f, 0x57, 0x5f, - 0x49, 0x46, 0x5f, 0x53, 0x55, 0x50, 0x45, 0x52, 0x5f, 0x41, 0x44, 0x4d, 0x49, 0x4e, 0x10, 0x04, - 0x42, 0x06, 0x0a, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x22, 0xac, 0x05, 0x0a, 0x0e, 0x4d, 0x65, 0x74, - 0x61, 0x64, 0x61, 0x74, 0x61, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x52, 0x0a, 0x04, 0x62, - 0x61, 0x73, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x3c, 0x2e, 0x78, 0x6d, 0x74, 0x70, - 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, - 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x50, 0x6f, - 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x42, 0x61, 0x73, - 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x48, 0x00, 0x52, 0x04, 0x62, 0x61, 0x73, 0x65, 0x12, - 0x5d, 0x0a, 0x0d, 0x61, 0x6e, 0x64, 0x5f, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x36, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, + 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, + 0x6f, 0x6e, 0x73, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, + 0x17, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, + 0x6e, 0x73, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x1a, 0x72, 0x0a, 0x19, 0x55, 0x70, 0x64, 0x61, + 0x74, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, + 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x3f, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x50, 0x6f, 0x6c, 0x69, 0x63, - 0x79, 0x2e, 0x41, 0x6e, 0x64, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x00, - 0x52, 0x0c, 0x61, 0x6e, 0x64, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x5d, - 0x0a, 0x0d, 0x61, 0x6e, 0x79, 0x5f, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x36, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, - 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, - 0x73, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, - 0x2e, 0x41, 0x6e, 0x79, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, - 0x0c, 0x61, 0x6e, 0x79, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x1a, 0x55, 0x0a, - 0x0c, 0x41, 0x6e, 0x64, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x45, 0x0a, - 0x08, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, - 0x29, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x4d, 0x65, 0x74, 0x61, - 0x64, 0x61, 0x74, 0x61, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x08, 0x70, 0x6f, 0x6c, 0x69, - 0x63, 0x69, 0x65, 0x73, 0x1a, 0x55, 0x0a, 0x0c, 0x41, 0x6e, 0x79, 0x43, 0x6f, 0x6e, 0x64, 0x69, - 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x45, 0x0a, 0x08, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, - 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, + 0x79, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x8a, 0x05, 0x0a, + 0x10, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x50, 0x6f, 0x6c, 0x69, 0x63, + 0x79, 0x12, 0x4c, 0x0a, 0x04, 0x62, 0x61, 0x73, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, + 0x36, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x4d, 0x65, 0x6d, 0x62, + 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x42, 0x61, 0x73, + 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x48, 0x00, 0x52, 0x04, 0x62, 0x61, 0x73, 0x65, 0x12, + 0x5f, 0x0a, 0x0d, 0x61, 0x6e, 0x64, 0x5f, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x38, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, + 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, + 0x74, 0x73, 0x2e, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x50, 0x6f, 0x6c, + 0x69, 0x63, 0x79, 0x2e, 0x41, 0x6e, 0x64, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, + 0x48, 0x00, 0x52, 0x0c, 0x61, 0x6e, 0x64, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, + 0x12, 0x5f, 0x0a, 0x0d, 0x61, 0x6e, 0x79, 0x5f, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, + 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x38, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, + 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, + 0x6e, 0x74, 0x73, 0x2e, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x50, 0x6f, + 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x41, 0x6e, 0x79, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, + 0x6e, 0x48, 0x00, 0x52, 0x0c, 0x61, 0x6e, 0x79, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, + 0x6e, 0x1a, 0x57, 0x0a, 0x0c, 0x41, 0x6e, 0x64, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, + 0x6e, 0x12, 0x47, 0x0a, 0x08, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x18, 0x01, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, + 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, + 0x52, 0x08, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x1a, 0x57, 0x0a, 0x0c, 0x41, 0x6e, + 0x79, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x47, 0x0a, 0x08, 0x70, 0x6f, + 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x78, + 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, + 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, + 0x68, 0x69, 0x70, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x08, 0x70, 0x6f, 0x6c, 0x69, 0x63, + 0x69, 0x65, 0x73, 0x22, 0xab, 0x01, 0x0a, 0x0a, 0x42, 0x61, 0x73, 0x65, 0x50, 0x6f, 0x6c, 0x69, + 0x63, 0x79, 0x12, 0x1b, 0x0a, 0x17, 0x42, 0x41, 0x53, 0x45, 0x5f, 0x50, 0x4f, 0x4c, 0x49, 0x43, + 0x59, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, + 0x15, 0x0a, 0x11, 0x42, 0x41, 0x53, 0x45, 0x5f, 0x50, 0x4f, 0x4c, 0x49, 0x43, 0x59, 0x5f, 0x41, + 0x4c, 0x4c, 0x4f, 0x57, 0x10, 0x01, 0x12, 0x14, 0x0a, 0x10, 0x42, 0x41, 0x53, 0x45, 0x5f, 0x50, + 0x4f, 0x4c, 0x49, 0x43, 0x59, 0x5f, 0x44, 0x45, 0x4e, 0x59, 0x10, 0x02, 0x12, 0x2d, 0x0a, 0x29, + 0x42, 0x41, 0x53, 0x45, 0x5f, 0x50, 0x4f, 0x4c, 0x49, 0x43, 0x59, 0x5f, 0x41, 0x4c, 0x4c, 0x4f, + 0x57, 0x5f, 0x49, 0x46, 0x5f, 0x41, 0x44, 0x4d, 0x49, 0x4e, 0x5f, 0x4f, 0x52, 0x5f, 0x53, 0x55, + 0x50, 0x45, 0x52, 0x5f, 0x41, 0x44, 0x4d, 0x49, 0x4e, 0x10, 0x03, 0x12, 0x24, 0x0a, 0x20, 0x42, + 0x41, 0x53, 0x45, 0x5f, 0x50, 0x4f, 0x4c, 0x49, 0x43, 0x59, 0x5f, 0x41, 0x4c, 0x4c, 0x4f, 0x57, + 0x5f, 0x49, 0x46, 0x5f, 0x53, 0x55, 0x50, 0x45, 0x52, 0x5f, 0x41, 0x44, 0x4d, 0x49, 0x4e, 0x10, + 0x04, 0x42, 0x06, 0x0a, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x22, 0xac, 0x05, 0x0a, 0x0e, 0x4d, 0x65, + 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x52, 0x0a, 0x04, + 0x62, 0x61, 0x73, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x3c, 0x2e, 0x78, 0x6d, 0x74, + 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, + 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x50, + 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x42, 0x61, + 0x73, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x48, 0x00, 0x52, 0x04, 0x62, 0x61, 0x73, 0x65, + 0x12, 0x5d, 0x0a, 0x0d, 0x61, 0x6e, 0x64, 0x5f, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, + 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x36, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, + 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, + 0x6e, 0x74, 0x73, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x50, 0x6f, 0x6c, 0x69, + 0x63, 0x79, 0x2e, 0x41, 0x6e, 0x64, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x48, + 0x00, 0x52, 0x0c, 0x61, 0x6e, 0x64, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, + 0x5d, 0x0a, 0x0d, 0x61, 0x6e, 0x79, 0x5f, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x36, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x50, 0x6f, 0x6c, 0x69, 0x63, - 0x79, 0x52, 0x08, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x22, 0xd1, 0x01, 0x0a, 0x12, - 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x42, 0x61, 0x73, 0x65, 0x50, 0x6f, 0x6c, 0x69, - 0x63, 0x79, 0x12, 0x24, 0x0a, 0x20, 0x4d, 0x45, 0x54, 0x41, 0x44, 0x41, 0x54, 0x41, 0x5f, 0x42, - 0x41, 0x53, 0x45, 0x5f, 0x50, 0x4f, 0x4c, 0x49, 0x43, 0x59, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, - 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x1e, 0x0a, 0x1a, 0x4d, 0x45, 0x54, 0x41, - 0x44, 0x41, 0x54, 0x41, 0x5f, 0x42, 0x41, 0x53, 0x45, 0x5f, 0x50, 0x4f, 0x4c, 0x49, 0x43, 0x59, - 0x5f, 0x41, 0x4c, 0x4c, 0x4f, 0x57, 0x10, 0x01, 0x12, 0x1d, 0x0a, 0x19, 0x4d, 0x45, 0x54, 0x41, + 0x79, 0x2e, 0x41, 0x6e, 0x79, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x00, + 0x52, 0x0c, 0x61, 0x6e, 0x79, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x1a, 0x55, + 0x0a, 0x0c, 0x41, 0x6e, 0x64, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x45, + 0x0a, 0x08, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x29, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x4d, 0x65, 0x74, + 0x61, 0x64, 0x61, 0x74, 0x61, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x08, 0x70, 0x6f, 0x6c, + 0x69, 0x63, 0x69, 0x65, 0x73, 0x1a, 0x55, 0x0a, 0x0c, 0x41, 0x6e, 0x79, 0x43, 0x6f, 0x6e, 0x64, + 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x45, 0x0a, 0x08, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, + 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, + 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, + 0x6e, 0x74, 0x73, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x50, 0x6f, 0x6c, 0x69, + 0x63, 0x79, 0x52, 0x08, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x22, 0xd1, 0x01, 0x0a, + 0x12, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x42, 0x61, 0x73, 0x65, 0x50, 0x6f, 0x6c, + 0x69, 0x63, 0x79, 0x12, 0x24, 0x0a, 0x20, 0x4d, 0x45, 0x54, 0x41, 0x44, 0x41, 0x54, 0x41, 0x5f, + 0x42, 0x41, 0x53, 0x45, 0x5f, 0x50, 0x4f, 0x4c, 0x49, 0x43, 0x59, 0x5f, 0x55, 0x4e, 0x53, 0x50, + 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x1e, 0x0a, 0x1a, 0x4d, 0x45, 0x54, + 0x41, 0x44, 0x41, 0x54, 0x41, 0x5f, 0x42, 0x41, 0x53, 0x45, 0x5f, 0x50, 0x4f, 0x4c, 0x49, 0x43, + 0x59, 0x5f, 0x41, 0x4c, 0x4c, 0x4f, 0x57, 0x10, 0x01, 0x12, 0x1d, 0x0a, 0x19, 0x4d, 0x45, 0x54, + 0x41, 0x44, 0x41, 0x54, 0x41, 0x5f, 0x42, 0x41, 0x53, 0x45, 0x5f, 0x50, 0x4f, 0x4c, 0x49, 0x43, + 0x59, 0x5f, 0x44, 0x45, 0x4e, 0x59, 0x10, 0x02, 0x12, 0x27, 0x0a, 0x23, 0x4d, 0x45, 0x54, 0x41, 0x44, 0x41, 0x54, 0x41, 0x5f, 0x42, 0x41, 0x53, 0x45, 0x5f, 0x50, 0x4f, 0x4c, 0x49, 0x43, 0x59, - 0x5f, 0x44, 0x45, 0x4e, 0x59, 0x10, 0x02, 0x12, 0x27, 0x0a, 0x23, 0x4d, 0x45, 0x54, 0x41, 0x44, - 0x41, 0x54, 0x41, 0x5f, 0x42, 0x41, 0x53, 0x45, 0x5f, 0x50, 0x4f, 0x4c, 0x49, 0x43, 0x59, 0x5f, - 0x41, 0x4c, 0x4c, 0x4f, 0x57, 0x5f, 0x49, 0x46, 0x5f, 0x41, 0x44, 0x4d, 0x49, 0x4e, 0x10, 0x03, - 0x12, 0x2d, 0x0a, 0x29, 0x4d, 0x45, 0x54, 0x41, 0x44, 0x41, 0x54, 0x41, 0x5f, 0x42, 0x41, 0x53, - 0x45, 0x5f, 0x50, 0x4f, 0x4c, 0x49, 0x43, 0x59, 0x5f, 0x41, 0x4c, 0x4c, 0x4f, 0x57, 0x5f, 0x49, - 0x46, 0x5f, 0x53, 0x55, 0x50, 0x45, 0x52, 0x5f, 0x41, 0x44, 0x4d, 0x49, 0x4e, 0x10, 0x04, 0x42, - 0x06, 0x0a, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x22, 0xd4, 0x05, 0x0a, 0x17, 0x50, 0x65, 0x72, 0x6d, - 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, 0x6f, 0x6c, - 0x69, 0x63, 0x79, 0x12, 0x5e, 0x0a, 0x04, 0x62, 0x61, 0x73, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x0e, 0x32, 0x48, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x50, 0x65, - 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, - 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, - 0x73, 0x42, 0x61, 0x73, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x48, 0x00, 0x52, 0x04, 0x62, - 0x61, 0x73, 0x65, 0x12, 0x66, 0x0a, 0x0d, 0x61, 0x6e, 0x64, 0x5f, 0x63, 0x6f, 0x6e, 0x64, 0x69, - 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3f, 0x2e, 0x78, 0x6d, 0x74, - 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, - 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, - 0x6e, 0x73, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x41, - 0x6e, 0x64, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x0c, 0x61, - 0x6e, 0x64, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x66, 0x0a, 0x0d, 0x61, - 0x6e, 0x79, 0x5f, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x3f, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, + 0x5f, 0x41, 0x4c, 0x4c, 0x4f, 0x57, 0x5f, 0x49, 0x46, 0x5f, 0x41, 0x44, 0x4d, 0x49, 0x4e, 0x10, + 0x03, 0x12, 0x2d, 0x0a, 0x29, 0x4d, 0x45, 0x54, 0x41, 0x44, 0x41, 0x54, 0x41, 0x5f, 0x42, 0x41, + 0x53, 0x45, 0x5f, 0x50, 0x4f, 0x4c, 0x49, 0x43, 0x59, 0x5f, 0x41, 0x4c, 0x4c, 0x4f, 0x57, 0x5f, + 0x49, 0x46, 0x5f, 0x53, 0x55, 0x50, 0x45, 0x52, 0x5f, 0x41, 0x44, 0x4d, 0x49, 0x4e, 0x10, 0x04, + 0x42, 0x06, 0x0a, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x22, 0xd4, 0x05, 0x0a, 0x17, 0x50, 0x65, 0x72, + 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, 0x6f, + 0x6c, 0x69, 0x63, 0x79, 0x12, 0x5e, 0x0a, 0x04, 0x62, 0x61, 0x73, 0x65, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0e, 0x32, 0x48, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, - 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x41, 0x6e, 0x79, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, - 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x0c, 0x61, 0x6e, 0x79, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, - 0x69, 0x6f, 0x6e, 0x1a, 0x5e, 0x0a, 0x0c, 0x41, 0x6e, 0x64, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, - 0x69, 0x6f, 0x6e, 0x12, 0x4e, 0x0a, 0x08, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x18, - 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x32, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, - 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, - 0x73, 0x2e, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x55, 0x70, 0x64, - 0x61, 0x74, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x08, 0x70, 0x6f, 0x6c, 0x69, 0x63, - 0x69, 0x65, 0x73, 0x1a, 0x5e, 0x0a, 0x0c, 0x41, 0x6e, 0x79, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, - 0x69, 0x6f, 0x6e, 0x12, 0x4e, 0x0a, 0x08, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x18, - 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x32, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, + 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, + 0x6e, 0x73, 0x42, 0x61, 0x73, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x48, 0x00, 0x52, 0x04, + 0x62, 0x61, 0x73, 0x65, 0x12, 0x66, 0x0a, 0x0d, 0x61, 0x6e, 0x64, 0x5f, 0x63, 0x6f, 0x6e, 0x64, + 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3f, 0x2e, 0x78, 0x6d, + 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, + 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, + 0x6f, 0x6e, 0x73, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, + 0x41, 0x6e, 0x64, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x0c, + 0x61, 0x6e, 0x64, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x66, 0x0a, 0x0d, + 0x61, 0x6e, 0x79, 0x5f, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x3f, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, + 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x55, 0x70, 0x64, 0x61, 0x74, + 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x41, 0x6e, 0x79, 0x43, 0x6f, 0x6e, 0x64, 0x69, + 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x0c, 0x61, 0x6e, 0x79, 0x43, 0x6f, 0x6e, 0x64, 0x69, + 0x74, 0x69, 0x6f, 0x6e, 0x1a, 0x5e, 0x0a, 0x0c, 0x41, 0x6e, 0x64, 0x43, 0x6f, 0x6e, 0x64, 0x69, + 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x4e, 0x0a, 0x08, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, + 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x32, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, + 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, + 0x74, 0x73, 0x2e, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x55, 0x70, + 0x64, 0x61, 0x74, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x08, 0x70, 0x6f, 0x6c, 0x69, + 0x63, 0x69, 0x65, 0x73, 0x1a, 0x5e, 0x0a, 0x0c, 0x41, 0x6e, 0x79, 0x43, 0x6f, 0x6e, 0x64, 0x69, + 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x4e, 0x0a, 0x08, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, + 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x32, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, + 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, + 0x74, 0x73, 0x2e, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x55, 0x70, + 0x64, 0x61, 0x74, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x08, 0x70, 0x6f, 0x6c, 0x69, + 0x63, 0x69, 0x65, 0x73, 0x22, 0xc0, 0x01, 0x0a, 0x15, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, + 0x69, 0x6f, 0x6e, 0x73, 0x42, 0x61, 0x73, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x27, + 0x0a, 0x23, 0x50, 0x45, 0x52, 0x4d, 0x49, 0x53, 0x53, 0x49, 0x4f, 0x4e, 0x53, 0x5f, 0x42, 0x41, + 0x53, 0x45, 0x5f, 0x50, 0x4f, 0x4c, 0x49, 0x43, 0x59, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, + 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x20, 0x0a, 0x1c, 0x50, 0x45, 0x52, 0x4d, 0x49, + 0x53, 0x53, 0x49, 0x4f, 0x4e, 0x53, 0x5f, 0x42, 0x41, 0x53, 0x45, 0x5f, 0x50, 0x4f, 0x4c, 0x49, + 0x43, 0x59, 0x5f, 0x44, 0x45, 0x4e, 0x59, 0x10, 0x01, 0x12, 0x2a, 0x0a, 0x26, 0x50, 0x45, 0x52, + 0x4d, 0x49, 0x53, 0x53, 0x49, 0x4f, 0x4e, 0x53, 0x5f, 0x42, 0x41, 0x53, 0x45, 0x5f, 0x50, 0x4f, + 0x4c, 0x49, 0x43, 0x59, 0x5f, 0x41, 0x4c, 0x4c, 0x4f, 0x57, 0x5f, 0x49, 0x46, 0x5f, 0x41, 0x44, + 0x4d, 0x49, 0x4e, 0x10, 0x02, 0x12, 0x30, 0x0a, 0x2c, 0x50, 0x45, 0x52, 0x4d, 0x49, 0x53, 0x53, + 0x49, 0x4f, 0x4e, 0x53, 0x5f, 0x42, 0x41, 0x53, 0x45, 0x5f, 0x50, 0x4f, 0x4c, 0x49, 0x43, 0x59, + 0x5f, 0x41, 0x4c, 0x4c, 0x4f, 0x57, 0x5f, 0x49, 0x46, 0x5f, 0x53, 0x55, 0x50, 0x45, 0x52, 0x5f, + 0x41, 0x44, 0x4d, 0x49, 0x4e, 0x10, 0x03, 0x42, 0x06, 0x0a, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x42, + 0xea, 0x01, 0x0a, 0x1d, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, - 0x73, 0x2e, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x55, 0x70, 0x64, - 0x61, 0x74, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x08, 0x70, 0x6f, 0x6c, 0x69, 0x63, - 0x69, 0x65, 0x73, 0x22, 0xc0, 0x01, 0x0a, 0x15, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, - 0x6f, 0x6e, 0x73, 0x42, 0x61, 0x73, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x27, 0x0a, - 0x23, 0x50, 0x45, 0x52, 0x4d, 0x49, 0x53, 0x53, 0x49, 0x4f, 0x4e, 0x53, 0x5f, 0x42, 0x41, 0x53, - 0x45, 0x5f, 0x50, 0x4f, 0x4c, 0x49, 0x43, 0x59, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, - 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x20, 0x0a, 0x1c, 0x50, 0x45, 0x52, 0x4d, 0x49, 0x53, - 0x53, 0x49, 0x4f, 0x4e, 0x53, 0x5f, 0x42, 0x41, 0x53, 0x45, 0x5f, 0x50, 0x4f, 0x4c, 0x49, 0x43, - 0x59, 0x5f, 0x44, 0x45, 0x4e, 0x59, 0x10, 0x01, 0x12, 0x2a, 0x0a, 0x26, 0x50, 0x45, 0x52, 0x4d, - 0x49, 0x53, 0x53, 0x49, 0x4f, 0x4e, 0x53, 0x5f, 0x42, 0x41, 0x53, 0x45, 0x5f, 0x50, 0x4f, 0x4c, - 0x49, 0x43, 0x59, 0x5f, 0x41, 0x4c, 0x4c, 0x4f, 0x57, 0x5f, 0x49, 0x46, 0x5f, 0x41, 0x44, 0x4d, - 0x49, 0x4e, 0x10, 0x02, 0x12, 0x30, 0x0a, 0x2c, 0x50, 0x45, 0x52, 0x4d, 0x49, 0x53, 0x53, 0x49, - 0x4f, 0x4e, 0x53, 0x5f, 0x42, 0x41, 0x53, 0x45, 0x5f, 0x50, 0x4f, 0x4c, 0x49, 0x43, 0x59, 0x5f, - 0x41, 0x4c, 0x4c, 0x4f, 0x57, 0x5f, 0x49, 0x46, 0x5f, 0x53, 0x55, 0x50, 0x45, 0x52, 0x5f, 0x41, - 0x44, 0x4d, 0x49, 0x4e, 0x10, 0x03, 0x42, 0x06, 0x0a, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x42, 0xea, - 0x01, 0x0a, 0x1d, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, - 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, - 0x42, 0x15, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, - 0x6e, 0x73, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x30, 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, 0x6d, 0x6c, 0x73, 0x2f, 0x6d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0xa2, 0x02, 0x03, 0x58, 0x4d, - 0x4d, 0xaa, 0x02, 0x18, 0x58, 0x6d, 0x74, 0x70, 0x2e, 0x4d, 0x6c, 0x73, 0x2e, 0x4d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0xca, 0x02, 0x18, 0x58, - 0x6d, 0x74, 0x70, 0x5c, 0x4d, 0x6c, 0x73, 0x5c, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x43, - 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0xe2, 0x02, 0x24, 0x58, 0x6d, 0x74, 0x70, 0x5c, 0x4d, - 0x6c, 0x73, 0x5c, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, - 0x74, 0x73, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, - 0x1a, 0x58, 0x6d, 0x74, 0x70, 0x3a, 0x3a, 0x4d, 0x6c, 0x73, 0x3a, 0x3a, 0x4d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x4a, 0xe6, 0x18, 0x0a, 0x06, - 0x12, 0x04, 0x01, 0x00, 0x68, 0x01, 0x0a, 0x2e, 0x0a, 0x01, 0x0c, 0x12, 0x03, 0x01, 0x00, 0x12, - 0x1a, 0x24, 0x20, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x20, 0x6d, 0x75, 0x74, 0x61, 0x62, 0x6c, 0x65, - 0x20, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x6d, 0x65, 0x74, - 0x61, 0x64, 0x61, 0x74, 0x61, 0x0a, 0x0a, 0x08, 0x0a, 0x01, 0x02, 0x12, 0x03, 0x03, 0x00, 0x22, - 0x0a, 0x08, 0x0a, 0x01, 0x08, 0x12, 0x03, 0x05, 0x00, 0x47, 0x0a, 0x09, 0x0a, 0x02, 0x08, 0x0b, - 0x12, 0x03, 0x05, 0x00, 0x47, 0x0a, 0x30, 0x0a, 0x02, 0x04, 0x00, 0x12, 0x04, 0x09, 0x00, 0x0b, - 0x01, 0x1a, 0x24, 0x20, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x20, 0x66, 0x6f, 0x72, 0x20, - 0x67, 0x72, 0x6f, 0x75, 0x70, 0x20, 0x6d, 0x75, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x6d, 0x65, - 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x0a, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x00, 0x01, 0x12, 0x03, - 0x09, 0x08, 0x21, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x00, 0x02, 0x00, 0x12, 0x03, 0x0a, 0x02, 0x19, - 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x00, 0x06, 0x12, 0x03, 0x0a, 0x02, 0x0b, 0x0a, 0x0c, - 0x0a, 0x05, 0x04, 0x00, 0x02, 0x00, 0x01, 0x12, 0x03, 0x0a, 0x0c, 0x14, 0x0a, 0x0c, 0x0a, 0x05, - 0x04, 0x00, 0x02, 0x00, 0x03, 0x12, 0x03, 0x0a, 0x17, 0x18, 0x0a, 0x37, 0x0a, 0x02, 0x04, 0x01, - 0x12, 0x04, 0x0e, 0x00, 0x15, 0x01, 0x1a, 0x2b, 0x20, 0x54, 0x68, 0x65, 0x20, 0x73, 0x65, 0x74, - 0x20, 0x6f, 0x66, 0x20, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x20, 0x74, 0x68, 0x61, - 0x74, 0x20, 0x67, 0x6f, 0x76, 0x65, 0x72, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x67, 0x72, 0x6f, - 0x75, 0x70, 0x0a, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x01, 0x01, 0x12, 0x03, 0x0e, 0x08, 0x11, 0x0a, - 0x0b, 0x0a, 0x04, 0x04, 0x01, 0x02, 0x00, 0x12, 0x03, 0x0f, 0x02, 0x29, 0x0a, 0x0c, 0x0a, 0x05, - 0x04, 0x01, 0x02, 0x00, 0x06, 0x12, 0x03, 0x0f, 0x02, 0x12, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, - 0x02, 0x00, 0x01, 0x12, 0x03, 0x0f, 0x13, 0x24, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x00, - 0x03, 0x12, 0x03, 0x0f, 0x27, 0x28, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x01, 0x02, 0x01, 0x12, 0x03, - 0x10, 0x02, 0x2c, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x01, 0x06, 0x12, 0x03, 0x10, 0x02, - 0x12, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x01, 0x01, 0x12, 0x03, 0x10, 0x13, 0x27, 0x0a, - 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x01, 0x03, 0x12, 0x03, 0x10, 0x2a, 0x2b, 0x0a, 0x0b, 0x0a, - 0x04, 0x04, 0x01, 0x02, 0x02, 0x12, 0x03, 0x11, 0x02, 0x39, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, - 0x02, 0x02, 0x06, 0x12, 0x03, 0x11, 0x02, 0x1d, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x02, - 0x01, 0x12, 0x03, 0x11, 0x1e, 0x34, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x02, 0x03, 0x12, - 0x03, 0x11, 0x37, 0x38, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x01, 0x02, 0x03, 0x12, 0x03, 0x12, 0x02, - 0x2f, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x03, 0x06, 0x12, 0x03, 0x12, 0x02, 0x19, 0x0a, - 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x03, 0x01, 0x12, 0x03, 0x12, 0x1a, 0x2a, 0x0a, 0x0c, 0x0a, - 0x05, 0x04, 0x01, 0x02, 0x03, 0x03, 0x12, 0x03, 0x12, 0x2d, 0x2e, 0x0a, 0x0b, 0x0a, 0x04, 0x04, - 0x01, 0x02, 0x04, 0x12, 0x03, 0x13, 0x02, 0x32, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x04, - 0x06, 0x12, 0x03, 0x13, 0x02, 0x19, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x04, 0x01, 0x12, - 0x03, 0x13, 0x1a, 0x2d, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x04, 0x03, 0x12, 0x03, 0x13, - 0x30, 0x31, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x01, 0x02, 0x05, 0x12, 0x03, 0x14, 0x02, 0x38, 0x0a, - 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x05, 0x06, 0x12, 0x03, 0x14, 0x02, 0x19, 0x0a, 0x0c, 0x0a, - 0x05, 0x04, 0x01, 0x02, 0x05, 0x01, 0x12, 0x03, 0x14, 0x1a, 0x33, 0x0a, 0x0c, 0x0a, 0x05, 0x04, - 0x01, 0x02, 0x05, 0x03, 0x12, 0x03, 0x14, 0x36, 0x37, 0x0a, 0x4c, 0x0a, 0x02, 0x04, 0x02, 0x12, - 0x04, 0x18, 0x00, 0x31, 0x01, 0x1a, 0x40, 0x20, 0x41, 0x20, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, - 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x67, 0x6f, 0x76, 0x65, 0x72, 0x6e, 0x73, 0x20, 0x61, 0x64, - 0x64, 0x69, 0x6e, 0x67, 0x2f, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x69, 0x6e, 0x67, 0x20, 0x6d, 0x65, - 0x6d, 0x62, 0x65, 0x72, 0x73, 0x20, 0x6f, 0x72, 0x20, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x0a, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x02, 0x01, 0x12, 0x03, - 0x18, 0x08, 0x18, 0x0a, 0x1b, 0x0a, 0x04, 0x04, 0x02, 0x04, 0x00, 0x12, 0x04, 0x1a, 0x02, 0x20, - 0x03, 0x1a, 0x0d, 0x20, 0x42, 0x61, 0x73, 0x65, 0x20, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x0a, - 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x04, 0x00, 0x01, 0x12, 0x03, 0x1a, 0x07, 0x11, 0x0a, 0x0d, - 0x0a, 0x06, 0x04, 0x02, 0x04, 0x00, 0x02, 0x00, 0x12, 0x03, 0x1b, 0x04, 0x20, 0x0a, 0x0e, 0x0a, - 0x07, 0x04, 0x02, 0x04, 0x00, 0x02, 0x00, 0x01, 0x12, 0x03, 0x1b, 0x04, 0x1b, 0x0a, 0x0e, 0x0a, - 0x07, 0x04, 0x02, 0x04, 0x00, 0x02, 0x00, 0x02, 0x12, 0x03, 0x1b, 0x1e, 0x1f, 0x0a, 0x0d, 0x0a, - 0x06, 0x04, 0x02, 0x04, 0x00, 0x02, 0x01, 0x12, 0x03, 0x1c, 0x04, 0x1a, 0x0a, 0x0e, 0x0a, 0x07, - 0x04, 0x02, 0x04, 0x00, 0x02, 0x01, 0x01, 0x12, 0x03, 0x1c, 0x04, 0x15, 0x0a, 0x0e, 0x0a, 0x07, - 0x04, 0x02, 0x04, 0x00, 0x02, 0x01, 0x02, 0x12, 0x03, 0x1c, 0x18, 0x19, 0x0a, 0x0d, 0x0a, 0x06, - 0x04, 0x02, 0x04, 0x00, 0x02, 0x02, 0x12, 0x03, 0x1d, 0x04, 0x19, 0x0a, 0x0e, 0x0a, 0x07, 0x04, - 0x02, 0x04, 0x00, 0x02, 0x02, 0x01, 0x12, 0x03, 0x1d, 0x04, 0x14, 0x0a, 0x0e, 0x0a, 0x07, 0x04, - 0x02, 0x04, 0x00, 0x02, 0x02, 0x02, 0x12, 0x03, 0x1d, 0x17, 0x18, 0x0a, 0x0d, 0x0a, 0x06, 0x04, - 0x02, 0x04, 0x00, 0x02, 0x03, 0x12, 0x03, 0x1e, 0x04, 0x32, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, - 0x04, 0x00, 0x02, 0x03, 0x01, 0x12, 0x03, 0x1e, 0x04, 0x2d, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, - 0x04, 0x00, 0x02, 0x03, 0x02, 0x12, 0x03, 0x1e, 0x30, 0x31, 0x0a, 0x0d, 0x0a, 0x06, 0x04, 0x02, - 0x04, 0x00, 0x02, 0x04, 0x12, 0x03, 0x1f, 0x04, 0x29, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x04, - 0x00, 0x02, 0x04, 0x01, 0x12, 0x03, 0x1f, 0x04, 0x24, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x04, - 0x00, 0x02, 0x04, 0x02, 0x12, 0x03, 0x1f, 0x27, 0x28, 0x0a, 0x44, 0x0a, 0x04, 0x04, 0x02, 0x03, - 0x00, 0x12, 0x04, 0x23, 0x02, 0x25, 0x03, 0x1a, 0x36, 0x20, 0x43, 0x6f, 0x6d, 0x62, 0x69, 0x6e, - 0x65, 0x20, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x20, 0x70, 0x6f, 0x6c, 0x69, 0x63, - 0x69, 0x65, 0x73, 0x2e, 0x20, 0x41, 0x6c, 0x6c, 0x20, 0x6d, 0x75, 0x73, 0x74, 0x20, 0x65, 0x76, - 0x61, 0x6c, 0x75, 0x61, 0x74, 0x65, 0x20, 0x74, 0x6f, 0x20, 0x74, 0x72, 0x75, 0x65, 0x0a, 0x0a, - 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x03, 0x00, 0x01, 0x12, 0x03, 0x23, 0x0a, 0x16, 0x0a, 0x0d, 0x0a, - 0x06, 0x04, 0x02, 0x03, 0x00, 0x02, 0x00, 0x12, 0x03, 0x24, 0x04, 0x2b, 0x0a, 0x0e, 0x0a, 0x07, - 0x04, 0x02, 0x03, 0x00, 0x02, 0x00, 0x04, 0x12, 0x03, 0x24, 0x04, 0x0c, 0x0a, 0x0e, 0x0a, 0x07, - 0x04, 0x02, 0x03, 0x00, 0x02, 0x00, 0x06, 0x12, 0x03, 0x24, 0x0d, 0x1d, 0x0a, 0x0e, 0x0a, 0x07, - 0x04, 0x02, 0x03, 0x00, 0x02, 0x00, 0x01, 0x12, 0x03, 0x24, 0x1e, 0x26, 0x0a, 0x0e, 0x0a, 0x07, - 0x04, 0x02, 0x03, 0x00, 0x02, 0x00, 0x03, 0x12, 0x03, 0x24, 0x29, 0x2a, 0x0a, 0x44, 0x0a, 0x04, - 0x04, 0x02, 0x03, 0x01, 0x12, 0x04, 0x28, 0x02, 0x2a, 0x03, 0x1a, 0x36, 0x20, 0x43, 0x6f, 0x6d, - 0x62, 0x69, 0x6e, 0x65, 0x20, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x20, 0x70, 0x6f, - 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x2e, 0x20, 0x41, 0x6e, 0x79, 0x20, 0x6d, 0x75, 0x73, 0x74, - 0x20, 0x65, 0x76, 0x61, 0x6c, 0x75, 0x61, 0x74, 0x65, 0x20, 0x74, 0x6f, 0x20, 0x74, 0x72, 0x75, - 0x65, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x03, 0x01, 0x01, 0x12, 0x03, 0x28, 0x0a, 0x16, - 0x0a, 0x0d, 0x0a, 0x06, 0x04, 0x02, 0x03, 0x01, 0x02, 0x00, 0x12, 0x03, 0x29, 0x04, 0x2b, 0x0a, - 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, 0x01, 0x02, 0x00, 0x04, 0x12, 0x03, 0x29, 0x04, 0x0c, 0x0a, - 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, 0x01, 0x02, 0x00, 0x06, 0x12, 0x03, 0x29, 0x0d, 0x1d, 0x0a, - 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, 0x01, 0x02, 0x00, 0x01, 0x12, 0x03, 0x29, 0x1e, 0x26, 0x0a, - 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, 0x01, 0x02, 0x00, 0x03, 0x12, 0x03, 0x29, 0x29, 0x2a, 0x0a, - 0x0c, 0x0a, 0x04, 0x04, 0x02, 0x08, 0x00, 0x12, 0x04, 0x2c, 0x02, 0x30, 0x03, 0x0a, 0x0c, 0x0a, - 0x05, 0x04, 0x02, 0x08, 0x00, 0x01, 0x12, 0x03, 0x2c, 0x08, 0x0c, 0x0a, 0x0b, 0x0a, 0x04, 0x04, - 0x02, 0x02, 0x00, 0x12, 0x03, 0x2d, 0x04, 0x18, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x00, - 0x06, 0x12, 0x03, 0x2d, 0x04, 0x0e, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x00, 0x01, 0x12, - 0x03, 0x2d, 0x0f, 0x13, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x00, 0x03, 0x12, 0x03, 0x2d, - 0x16, 0x17, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x02, 0x02, 0x01, 0x12, 0x03, 0x2e, 0x04, 0x23, 0x0a, - 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x01, 0x06, 0x12, 0x03, 0x2e, 0x04, 0x10, 0x0a, 0x0c, 0x0a, - 0x05, 0x04, 0x02, 0x02, 0x01, 0x01, 0x12, 0x03, 0x2e, 0x11, 0x1e, 0x0a, 0x0c, 0x0a, 0x05, 0x04, - 0x02, 0x02, 0x01, 0x03, 0x12, 0x03, 0x2e, 0x21, 0x22, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x02, 0x02, - 0x02, 0x12, 0x03, 0x2f, 0x04, 0x23, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x02, 0x06, 0x12, - 0x03, 0x2f, 0x04, 0x10, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x02, 0x01, 0x12, 0x03, 0x2f, - 0x11, 0x1e, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x02, 0x03, 0x12, 0x03, 0x2f, 0x21, 0x22, - 0x0a, 0x35, 0x0a, 0x02, 0x04, 0x03, 0x12, 0x04, 0x34, 0x00, 0x4d, 0x01, 0x1a, 0x29, 0x20, 0x41, - 0x20, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x67, 0x6f, 0x76, - 0x65, 0x72, 0x6e, 0x73, 0x20, 0x75, 0x70, 0x64, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x20, 0x6d, 0x65, - 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x0a, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x03, 0x01, 0x12, 0x03, - 0x34, 0x08, 0x16, 0x0a, 0x1b, 0x0a, 0x04, 0x04, 0x03, 0x04, 0x00, 0x12, 0x04, 0x36, 0x02, 0x3c, - 0x03, 0x1a, 0x0d, 0x20, 0x42, 0x61, 0x73, 0x65, 0x20, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x0a, - 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x04, 0x00, 0x01, 0x12, 0x03, 0x36, 0x07, 0x19, 0x0a, 0x0d, - 0x0a, 0x06, 0x04, 0x03, 0x04, 0x00, 0x02, 0x00, 0x12, 0x03, 0x37, 0x04, 0x29, 0x0a, 0x0e, 0x0a, - 0x07, 0x04, 0x03, 0x04, 0x00, 0x02, 0x00, 0x01, 0x12, 0x03, 0x37, 0x04, 0x24, 0x0a, 0x0e, 0x0a, - 0x07, 0x04, 0x03, 0x04, 0x00, 0x02, 0x00, 0x02, 0x12, 0x03, 0x37, 0x27, 0x28, 0x0a, 0x0d, 0x0a, - 0x06, 0x04, 0x03, 0x04, 0x00, 0x02, 0x01, 0x12, 0x03, 0x38, 0x04, 0x23, 0x0a, 0x0e, 0x0a, 0x07, - 0x04, 0x03, 0x04, 0x00, 0x02, 0x01, 0x01, 0x12, 0x03, 0x38, 0x04, 0x1e, 0x0a, 0x0e, 0x0a, 0x07, - 0x04, 0x03, 0x04, 0x00, 0x02, 0x01, 0x02, 0x12, 0x03, 0x38, 0x21, 0x22, 0x0a, 0x0d, 0x0a, 0x06, - 0x04, 0x03, 0x04, 0x00, 0x02, 0x02, 0x12, 0x03, 0x39, 0x04, 0x22, 0x0a, 0x0e, 0x0a, 0x07, 0x04, - 0x03, 0x04, 0x00, 0x02, 0x02, 0x01, 0x12, 0x03, 0x39, 0x04, 0x1d, 0x0a, 0x0e, 0x0a, 0x07, 0x04, - 0x03, 0x04, 0x00, 0x02, 0x02, 0x02, 0x12, 0x03, 0x39, 0x20, 0x21, 0x0a, 0x0d, 0x0a, 0x06, 0x04, - 0x03, 0x04, 0x00, 0x02, 0x03, 0x12, 0x03, 0x3a, 0x04, 0x2c, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x03, - 0x04, 0x00, 0x02, 0x03, 0x01, 0x12, 0x03, 0x3a, 0x04, 0x27, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x03, - 0x04, 0x00, 0x02, 0x03, 0x02, 0x12, 0x03, 0x3a, 0x2a, 0x2b, 0x0a, 0x0d, 0x0a, 0x06, 0x04, 0x03, - 0x04, 0x00, 0x02, 0x04, 0x12, 0x03, 0x3b, 0x04, 0x32, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x03, 0x04, - 0x00, 0x02, 0x04, 0x01, 0x12, 0x03, 0x3b, 0x04, 0x2d, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x03, 0x04, - 0x00, 0x02, 0x04, 0x02, 0x12, 0x03, 0x3b, 0x30, 0x31, 0x0a, 0x44, 0x0a, 0x04, 0x04, 0x03, 0x03, - 0x00, 0x12, 0x04, 0x3f, 0x02, 0x41, 0x03, 0x1a, 0x36, 0x20, 0x43, 0x6f, 0x6d, 0x62, 0x69, 0x6e, - 0x65, 0x20, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x20, 0x70, 0x6f, 0x6c, 0x69, 0x63, - 0x69, 0x65, 0x73, 0x2e, 0x20, 0x41, 0x6c, 0x6c, 0x20, 0x6d, 0x75, 0x73, 0x74, 0x20, 0x65, 0x76, - 0x61, 0x6c, 0x75, 0x61, 0x74, 0x65, 0x20, 0x74, 0x6f, 0x20, 0x74, 0x72, 0x75, 0x65, 0x0a, 0x0a, - 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x03, 0x00, 0x01, 0x12, 0x03, 0x3f, 0x0a, 0x16, 0x0a, 0x0d, 0x0a, - 0x06, 0x04, 0x03, 0x03, 0x00, 0x02, 0x00, 0x12, 0x03, 0x40, 0x04, 0x29, 0x0a, 0x0e, 0x0a, 0x07, - 0x04, 0x03, 0x03, 0x00, 0x02, 0x00, 0x04, 0x12, 0x03, 0x40, 0x04, 0x0c, 0x0a, 0x0e, 0x0a, 0x07, - 0x04, 0x03, 0x03, 0x00, 0x02, 0x00, 0x06, 0x12, 0x03, 0x40, 0x0d, 0x1b, 0x0a, 0x0e, 0x0a, 0x07, - 0x04, 0x03, 0x03, 0x00, 0x02, 0x00, 0x01, 0x12, 0x03, 0x40, 0x1c, 0x24, 0x0a, 0x0e, 0x0a, 0x07, - 0x04, 0x03, 0x03, 0x00, 0x02, 0x00, 0x03, 0x12, 0x03, 0x40, 0x27, 0x28, 0x0a, 0x44, 0x0a, 0x04, - 0x04, 0x03, 0x03, 0x01, 0x12, 0x04, 0x44, 0x02, 0x46, 0x03, 0x1a, 0x36, 0x20, 0x43, 0x6f, 0x6d, - 0x62, 0x69, 0x6e, 0x65, 0x20, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x20, 0x70, 0x6f, - 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x2e, 0x20, 0x41, 0x6e, 0x79, 0x20, 0x6d, 0x75, 0x73, 0x74, - 0x20, 0x65, 0x76, 0x61, 0x6c, 0x75, 0x61, 0x74, 0x65, 0x20, 0x74, 0x6f, 0x20, 0x74, 0x72, 0x75, - 0x65, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x03, 0x01, 0x01, 0x12, 0x03, 0x44, 0x0a, 0x16, - 0x0a, 0x0d, 0x0a, 0x06, 0x04, 0x03, 0x03, 0x01, 0x02, 0x00, 0x12, 0x03, 0x45, 0x04, 0x29, 0x0a, - 0x0e, 0x0a, 0x07, 0x04, 0x03, 0x03, 0x01, 0x02, 0x00, 0x04, 0x12, 0x03, 0x45, 0x04, 0x0c, 0x0a, - 0x0e, 0x0a, 0x07, 0x04, 0x03, 0x03, 0x01, 0x02, 0x00, 0x06, 0x12, 0x03, 0x45, 0x0d, 0x1b, 0x0a, - 0x0e, 0x0a, 0x07, 0x04, 0x03, 0x03, 0x01, 0x02, 0x00, 0x01, 0x12, 0x03, 0x45, 0x1c, 0x24, 0x0a, - 0x0e, 0x0a, 0x07, 0x04, 0x03, 0x03, 0x01, 0x02, 0x00, 0x03, 0x12, 0x03, 0x45, 0x27, 0x28, 0x0a, - 0x0c, 0x0a, 0x04, 0x04, 0x03, 0x08, 0x00, 0x12, 0x04, 0x48, 0x02, 0x4c, 0x03, 0x0a, 0x0c, 0x0a, - 0x05, 0x04, 0x03, 0x08, 0x00, 0x01, 0x12, 0x03, 0x48, 0x08, 0x0c, 0x0a, 0x0b, 0x0a, 0x04, 0x04, - 0x03, 0x02, 0x00, 0x12, 0x03, 0x49, 0x04, 0x20, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, 0x00, - 0x06, 0x12, 0x03, 0x49, 0x04, 0x16, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, 0x00, 0x01, 0x12, - 0x03, 0x49, 0x17, 0x1b, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, 0x00, 0x03, 0x12, 0x03, 0x49, - 0x1e, 0x1f, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x03, 0x02, 0x01, 0x12, 0x03, 0x4a, 0x04, 0x23, 0x0a, - 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, 0x01, 0x06, 0x12, 0x03, 0x4a, 0x04, 0x10, 0x0a, 0x0c, 0x0a, - 0x05, 0x04, 0x03, 0x02, 0x01, 0x01, 0x12, 0x03, 0x4a, 0x11, 0x1e, 0x0a, 0x0c, 0x0a, 0x05, 0x04, - 0x03, 0x02, 0x01, 0x03, 0x12, 0x03, 0x4a, 0x21, 0x22, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x03, 0x02, - 0x02, 0x12, 0x03, 0x4b, 0x04, 0x23, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, 0x02, 0x06, 0x12, - 0x03, 0x4b, 0x04, 0x10, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, 0x02, 0x01, 0x12, 0x03, 0x4b, - 0x11, 0x1e, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, 0x02, 0x03, 0x12, 0x03, 0x4b, 0x21, 0x22, - 0x0a, 0x38, 0x0a, 0x02, 0x04, 0x04, 0x12, 0x04, 0x50, 0x00, 0x68, 0x01, 0x1a, 0x2c, 0x20, 0x41, - 0x20, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x67, 0x6f, 0x76, - 0x65, 0x72, 0x6e, 0x73, 0x20, 0x75, 0x70, 0x64, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x20, 0x70, 0x65, - 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x0a, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x04, - 0x01, 0x12, 0x03, 0x50, 0x08, 0x1f, 0x0a, 0x1b, 0x0a, 0x04, 0x04, 0x04, 0x04, 0x00, 0x12, 0x04, - 0x52, 0x02, 0x57, 0x03, 0x1a, 0x0d, 0x20, 0x42, 0x61, 0x73, 0x65, 0x20, 0x70, 0x6f, 0x6c, 0x69, - 0x63, 0x79, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x04, 0x00, 0x01, 0x12, 0x03, 0x52, 0x07, - 0x1c, 0x0a, 0x0d, 0x0a, 0x06, 0x04, 0x04, 0x04, 0x00, 0x02, 0x00, 0x12, 0x03, 0x53, 0x04, 0x2c, - 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x04, 0x04, 0x00, 0x02, 0x00, 0x01, 0x12, 0x03, 0x53, 0x04, 0x27, - 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x04, 0x04, 0x00, 0x02, 0x00, 0x02, 0x12, 0x03, 0x53, 0x2a, 0x2b, - 0x0a, 0x0d, 0x0a, 0x06, 0x04, 0x04, 0x04, 0x00, 0x02, 0x01, 0x12, 0x03, 0x54, 0x04, 0x25, 0x0a, - 0x0e, 0x0a, 0x07, 0x04, 0x04, 0x04, 0x00, 0x02, 0x01, 0x01, 0x12, 0x03, 0x54, 0x04, 0x20, 0x0a, - 0x0e, 0x0a, 0x07, 0x04, 0x04, 0x04, 0x00, 0x02, 0x01, 0x02, 0x12, 0x03, 0x54, 0x23, 0x24, 0x0a, - 0x0d, 0x0a, 0x06, 0x04, 0x04, 0x04, 0x00, 0x02, 0x02, 0x12, 0x03, 0x55, 0x04, 0x2f, 0x0a, 0x0e, - 0x0a, 0x07, 0x04, 0x04, 0x04, 0x00, 0x02, 0x02, 0x01, 0x12, 0x03, 0x55, 0x04, 0x2a, 0x0a, 0x0e, - 0x0a, 0x07, 0x04, 0x04, 0x04, 0x00, 0x02, 0x02, 0x02, 0x12, 0x03, 0x55, 0x2d, 0x2e, 0x0a, 0x0d, - 0x0a, 0x06, 0x04, 0x04, 0x04, 0x00, 0x02, 0x03, 0x12, 0x03, 0x56, 0x04, 0x35, 0x0a, 0x0e, 0x0a, - 0x07, 0x04, 0x04, 0x04, 0x00, 0x02, 0x03, 0x01, 0x12, 0x03, 0x56, 0x04, 0x30, 0x0a, 0x0e, 0x0a, - 0x07, 0x04, 0x04, 0x04, 0x00, 0x02, 0x03, 0x02, 0x12, 0x03, 0x56, 0x33, 0x34, 0x0a, 0x44, 0x0a, - 0x04, 0x04, 0x04, 0x03, 0x00, 0x12, 0x04, 0x5a, 0x02, 0x5c, 0x03, 0x1a, 0x36, 0x20, 0x43, 0x6f, + 0x73, 0x42, 0x15, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, + 0x6f, 0x6e, 0x73, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x30, 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, 0x6d, 0x6c, 0x73, 0x2f, 0x6d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0xa2, 0x02, 0x03, 0x58, + 0x4d, 0x4d, 0xaa, 0x02, 0x18, 0x58, 0x6d, 0x74, 0x70, 0x2e, 0x4d, 0x6c, 0x73, 0x2e, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0xca, 0x02, 0x18, + 0x58, 0x6d, 0x74, 0x70, 0x5c, 0x4d, 0x6c, 0x73, 0x5c, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0xe2, 0x02, 0x24, 0x58, 0x6d, 0x74, 0x70, 0x5c, + 0x4d, 0x6c, 0x73, 0x5c, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, + 0x6e, 0x74, 0x73, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, + 0x02, 0x1a, 0x58, 0x6d, 0x74, 0x70, 0x3a, 0x3a, 0x4d, 0x6c, 0x73, 0x3a, 0x3a, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x4a, 0xe6, 0x18, 0x0a, + 0x06, 0x12, 0x04, 0x01, 0x00, 0x68, 0x01, 0x0a, 0x2e, 0x0a, 0x01, 0x0c, 0x12, 0x03, 0x01, 0x00, + 0x12, 0x1a, 0x24, 0x20, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x20, 0x6d, 0x75, 0x74, 0x61, 0x62, 0x6c, + 0x65, 0x20, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x6d, 0x65, + 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x0a, 0x0a, 0x08, 0x0a, 0x01, 0x02, 0x12, 0x03, 0x03, 0x00, + 0x22, 0x0a, 0x08, 0x0a, 0x01, 0x08, 0x12, 0x03, 0x05, 0x00, 0x47, 0x0a, 0x09, 0x0a, 0x02, 0x08, + 0x0b, 0x12, 0x03, 0x05, 0x00, 0x47, 0x0a, 0x30, 0x0a, 0x02, 0x04, 0x00, 0x12, 0x04, 0x09, 0x00, + 0x0b, 0x01, 0x1a, 0x24, 0x20, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x20, 0x66, 0x6f, 0x72, + 0x20, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x20, 0x6d, 0x75, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x6d, + 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x0a, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x00, 0x01, 0x12, + 0x03, 0x09, 0x08, 0x21, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x00, 0x02, 0x00, 0x12, 0x03, 0x0a, 0x02, + 0x19, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x00, 0x06, 0x12, 0x03, 0x0a, 0x02, 0x0b, 0x0a, + 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x00, 0x01, 0x12, 0x03, 0x0a, 0x0c, 0x14, 0x0a, 0x0c, 0x0a, + 0x05, 0x04, 0x00, 0x02, 0x00, 0x03, 0x12, 0x03, 0x0a, 0x17, 0x18, 0x0a, 0x37, 0x0a, 0x02, 0x04, + 0x01, 0x12, 0x04, 0x0e, 0x00, 0x15, 0x01, 0x1a, 0x2b, 0x20, 0x54, 0x68, 0x65, 0x20, 0x73, 0x65, + 0x74, 0x20, 0x6f, 0x66, 0x20, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x20, 0x74, 0x68, + 0x61, 0x74, 0x20, 0x67, 0x6f, 0x76, 0x65, 0x72, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x67, 0x72, + 0x6f, 0x75, 0x70, 0x0a, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x01, 0x01, 0x12, 0x03, 0x0e, 0x08, 0x11, + 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x01, 0x02, 0x00, 0x12, 0x03, 0x0f, 0x02, 0x29, 0x0a, 0x0c, 0x0a, + 0x05, 0x04, 0x01, 0x02, 0x00, 0x06, 0x12, 0x03, 0x0f, 0x02, 0x12, 0x0a, 0x0c, 0x0a, 0x05, 0x04, + 0x01, 0x02, 0x00, 0x01, 0x12, 0x03, 0x0f, 0x13, 0x24, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, + 0x00, 0x03, 0x12, 0x03, 0x0f, 0x27, 0x28, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x01, 0x02, 0x01, 0x12, + 0x03, 0x10, 0x02, 0x2c, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x01, 0x06, 0x12, 0x03, 0x10, + 0x02, 0x12, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x01, 0x01, 0x12, 0x03, 0x10, 0x13, 0x27, + 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x01, 0x03, 0x12, 0x03, 0x10, 0x2a, 0x2b, 0x0a, 0x0b, + 0x0a, 0x04, 0x04, 0x01, 0x02, 0x02, 0x12, 0x03, 0x11, 0x02, 0x39, 0x0a, 0x0c, 0x0a, 0x05, 0x04, + 0x01, 0x02, 0x02, 0x06, 0x12, 0x03, 0x11, 0x02, 0x1d, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, + 0x02, 0x01, 0x12, 0x03, 0x11, 0x1e, 0x34, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x02, 0x03, + 0x12, 0x03, 0x11, 0x37, 0x38, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x01, 0x02, 0x03, 0x12, 0x03, 0x12, + 0x02, 0x2f, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x03, 0x06, 0x12, 0x03, 0x12, 0x02, 0x19, + 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x03, 0x01, 0x12, 0x03, 0x12, 0x1a, 0x2a, 0x0a, 0x0c, + 0x0a, 0x05, 0x04, 0x01, 0x02, 0x03, 0x03, 0x12, 0x03, 0x12, 0x2d, 0x2e, 0x0a, 0x0b, 0x0a, 0x04, + 0x04, 0x01, 0x02, 0x04, 0x12, 0x03, 0x13, 0x02, 0x32, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, + 0x04, 0x06, 0x12, 0x03, 0x13, 0x02, 0x19, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x04, 0x01, + 0x12, 0x03, 0x13, 0x1a, 0x2d, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x04, 0x03, 0x12, 0x03, + 0x13, 0x30, 0x31, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x01, 0x02, 0x05, 0x12, 0x03, 0x14, 0x02, 0x38, + 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x05, 0x06, 0x12, 0x03, 0x14, 0x02, 0x19, 0x0a, 0x0c, + 0x0a, 0x05, 0x04, 0x01, 0x02, 0x05, 0x01, 0x12, 0x03, 0x14, 0x1a, 0x33, 0x0a, 0x0c, 0x0a, 0x05, + 0x04, 0x01, 0x02, 0x05, 0x03, 0x12, 0x03, 0x14, 0x36, 0x37, 0x0a, 0x4c, 0x0a, 0x02, 0x04, 0x02, + 0x12, 0x04, 0x18, 0x00, 0x31, 0x01, 0x1a, 0x40, 0x20, 0x41, 0x20, 0x70, 0x6f, 0x6c, 0x69, 0x63, + 0x79, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x67, 0x6f, 0x76, 0x65, 0x72, 0x6e, 0x73, 0x20, 0x61, + 0x64, 0x64, 0x69, 0x6e, 0x67, 0x2f, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x69, 0x6e, 0x67, 0x20, 0x6d, + 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x20, 0x6f, 0x72, 0x20, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, + 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x0a, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x02, 0x01, 0x12, + 0x03, 0x18, 0x08, 0x18, 0x0a, 0x1b, 0x0a, 0x04, 0x04, 0x02, 0x04, 0x00, 0x12, 0x04, 0x1a, 0x02, + 0x20, 0x03, 0x1a, 0x0d, 0x20, 0x42, 0x61, 0x73, 0x65, 0x20, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, + 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x04, 0x00, 0x01, 0x12, 0x03, 0x1a, 0x07, 0x11, 0x0a, + 0x0d, 0x0a, 0x06, 0x04, 0x02, 0x04, 0x00, 0x02, 0x00, 0x12, 0x03, 0x1b, 0x04, 0x20, 0x0a, 0x0e, + 0x0a, 0x07, 0x04, 0x02, 0x04, 0x00, 0x02, 0x00, 0x01, 0x12, 0x03, 0x1b, 0x04, 0x1b, 0x0a, 0x0e, + 0x0a, 0x07, 0x04, 0x02, 0x04, 0x00, 0x02, 0x00, 0x02, 0x12, 0x03, 0x1b, 0x1e, 0x1f, 0x0a, 0x0d, + 0x0a, 0x06, 0x04, 0x02, 0x04, 0x00, 0x02, 0x01, 0x12, 0x03, 0x1c, 0x04, 0x1a, 0x0a, 0x0e, 0x0a, + 0x07, 0x04, 0x02, 0x04, 0x00, 0x02, 0x01, 0x01, 0x12, 0x03, 0x1c, 0x04, 0x15, 0x0a, 0x0e, 0x0a, + 0x07, 0x04, 0x02, 0x04, 0x00, 0x02, 0x01, 0x02, 0x12, 0x03, 0x1c, 0x18, 0x19, 0x0a, 0x0d, 0x0a, + 0x06, 0x04, 0x02, 0x04, 0x00, 0x02, 0x02, 0x12, 0x03, 0x1d, 0x04, 0x19, 0x0a, 0x0e, 0x0a, 0x07, + 0x04, 0x02, 0x04, 0x00, 0x02, 0x02, 0x01, 0x12, 0x03, 0x1d, 0x04, 0x14, 0x0a, 0x0e, 0x0a, 0x07, + 0x04, 0x02, 0x04, 0x00, 0x02, 0x02, 0x02, 0x12, 0x03, 0x1d, 0x17, 0x18, 0x0a, 0x0d, 0x0a, 0x06, + 0x04, 0x02, 0x04, 0x00, 0x02, 0x03, 0x12, 0x03, 0x1e, 0x04, 0x32, 0x0a, 0x0e, 0x0a, 0x07, 0x04, + 0x02, 0x04, 0x00, 0x02, 0x03, 0x01, 0x12, 0x03, 0x1e, 0x04, 0x2d, 0x0a, 0x0e, 0x0a, 0x07, 0x04, + 0x02, 0x04, 0x00, 0x02, 0x03, 0x02, 0x12, 0x03, 0x1e, 0x30, 0x31, 0x0a, 0x0d, 0x0a, 0x06, 0x04, + 0x02, 0x04, 0x00, 0x02, 0x04, 0x12, 0x03, 0x1f, 0x04, 0x29, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, + 0x04, 0x00, 0x02, 0x04, 0x01, 0x12, 0x03, 0x1f, 0x04, 0x24, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, + 0x04, 0x00, 0x02, 0x04, 0x02, 0x12, 0x03, 0x1f, 0x27, 0x28, 0x0a, 0x44, 0x0a, 0x04, 0x04, 0x02, + 0x03, 0x00, 0x12, 0x04, 0x23, 0x02, 0x25, 0x03, 0x1a, 0x36, 0x20, 0x43, 0x6f, 0x6d, 0x62, 0x69, + 0x6e, 0x65, 0x20, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x20, 0x70, 0x6f, 0x6c, 0x69, + 0x63, 0x69, 0x65, 0x73, 0x2e, 0x20, 0x41, 0x6c, 0x6c, 0x20, 0x6d, 0x75, 0x73, 0x74, 0x20, 0x65, + 0x76, 0x61, 0x6c, 0x75, 0x61, 0x74, 0x65, 0x20, 0x74, 0x6f, 0x20, 0x74, 0x72, 0x75, 0x65, 0x0a, + 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x03, 0x00, 0x01, 0x12, 0x03, 0x23, 0x0a, 0x16, 0x0a, 0x0d, + 0x0a, 0x06, 0x04, 0x02, 0x03, 0x00, 0x02, 0x00, 0x12, 0x03, 0x24, 0x04, 0x2b, 0x0a, 0x0e, 0x0a, + 0x07, 0x04, 0x02, 0x03, 0x00, 0x02, 0x00, 0x04, 0x12, 0x03, 0x24, 0x04, 0x0c, 0x0a, 0x0e, 0x0a, + 0x07, 0x04, 0x02, 0x03, 0x00, 0x02, 0x00, 0x06, 0x12, 0x03, 0x24, 0x0d, 0x1d, 0x0a, 0x0e, 0x0a, + 0x07, 0x04, 0x02, 0x03, 0x00, 0x02, 0x00, 0x01, 0x12, 0x03, 0x24, 0x1e, 0x26, 0x0a, 0x0e, 0x0a, + 0x07, 0x04, 0x02, 0x03, 0x00, 0x02, 0x00, 0x03, 0x12, 0x03, 0x24, 0x29, 0x2a, 0x0a, 0x44, 0x0a, + 0x04, 0x04, 0x02, 0x03, 0x01, 0x12, 0x04, 0x28, 0x02, 0x2a, 0x03, 0x1a, 0x36, 0x20, 0x43, 0x6f, 0x6d, 0x62, 0x69, 0x6e, 0x65, 0x20, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x20, 0x70, - 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x2e, 0x20, 0x41, 0x6c, 0x6c, 0x20, 0x6d, 0x75, 0x73, + 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x2e, 0x20, 0x41, 0x6e, 0x79, 0x20, 0x6d, 0x75, 0x73, 0x74, 0x20, 0x65, 0x76, 0x61, 0x6c, 0x75, 0x61, 0x74, 0x65, 0x20, 0x74, 0x6f, 0x20, 0x74, 0x72, - 0x75, 0x65, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x03, 0x00, 0x01, 0x12, 0x03, 0x5a, 0x0a, - 0x16, 0x0a, 0x0d, 0x0a, 0x06, 0x04, 0x04, 0x03, 0x00, 0x02, 0x00, 0x12, 0x03, 0x5b, 0x04, 0x32, - 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x04, 0x03, 0x00, 0x02, 0x00, 0x04, 0x12, 0x03, 0x5b, 0x04, 0x0c, - 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x04, 0x03, 0x00, 0x02, 0x00, 0x06, 0x12, 0x03, 0x5b, 0x0d, 0x24, - 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x04, 0x03, 0x00, 0x02, 0x00, 0x01, 0x12, 0x03, 0x5b, 0x25, 0x2d, - 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x04, 0x03, 0x00, 0x02, 0x00, 0x03, 0x12, 0x03, 0x5b, 0x30, 0x31, - 0x0a, 0x44, 0x0a, 0x04, 0x04, 0x04, 0x03, 0x01, 0x12, 0x04, 0x5f, 0x02, 0x61, 0x03, 0x1a, 0x36, - 0x20, 0x43, 0x6f, 0x6d, 0x62, 0x69, 0x6e, 0x65, 0x20, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, - 0x65, 0x20, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x2e, 0x20, 0x41, 0x6e, 0x79, 0x20, - 0x6d, 0x75, 0x73, 0x74, 0x20, 0x65, 0x76, 0x61, 0x6c, 0x75, 0x61, 0x74, 0x65, 0x20, 0x74, 0x6f, - 0x20, 0x74, 0x72, 0x75, 0x65, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x03, 0x01, 0x01, 0x12, - 0x03, 0x5f, 0x0a, 0x16, 0x0a, 0x0d, 0x0a, 0x06, 0x04, 0x04, 0x03, 0x01, 0x02, 0x00, 0x12, 0x03, - 0x60, 0x04, 0x32, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x04, 0x03, 0x01, 0x02, 0x00, 0x04, 0x12, 0x03, - 0x60, 0x04, 0x0c, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x04, 0x03, 0x01, 0x02, 0x00, 0x06, 0x12, 0x03, - 0x60, 0x0d, 0x24, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x04, 0x03, 0x01, 0x02, 0x00, 0x01, 0x12, 0x03, - 0x60, 0x25, 0x2d, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x04, 0x03, 0x01, 0x02, 0x00, 0x03, 0x12, 0x03, - 0x60, 0x30, 0x31, 0x0a, 0x0c, 0x0a, 0x04, 0x04, 0x04, 0x08, 0x00, 0x12, 0x04, 0x63, 0x02, 0x67, - 0x03, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x08, 0x00, 0x01, 0x12, 0x03, 0x63, 0x08, 0x0c, 0x0a, - 0x0b, 0x0a, 0x04, 0x04, 0x04, 0x02, 0x00, 0x12, 0x03, 0x64, 0x04, 0x23, 0x0a, 0x0c, 0x0a, 0x05, - 0x04, 0x04, 0x02, 0x00, 0x06, 0x12, 0x03, 0x64, 0x04, 0x19, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, - 0x02, 0x00, 0x01, 0x12, 0x03, 0x64, 0x1a, 0x1e, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x02, 0x00, - 0x03, 0x12, 0x03, 0x64, 0x21, 0x22, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x04, 0x02, 0x01, 0x12, 0x03, - 0x65, 0x04, 0x23, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x02, 0x01, 0x06, 0x12, 0x03, 0x65, 0x04, - 0x10, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x02, 0x01, 0x01, 0x12, 0x03, 0x65, 0x11, 0x1e, 0x0a, - 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x02, 0x01, 0x03, 0x12, 0x03, 0x65, 0x21, 0x22, 0x0a, 0x0b, 0x0a, - 0x04, 0x04, 0x04, 0x02, 0x02, 0x12, 0x03, 0x66, 0x04, 0x23, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, - 0x02, 0x02, 0x06, 0x12, 0x03, 0x66, 0x04, 0x10, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x02, 0x02, - 0x01, 0x12, 0x03, 0x66, 0x11, 0x1e, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x02, 0x02, 0x03, 0x12, - 0x03, 0x66, 0x21, 0x22, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, 0x0a, 0xb8, 0x1a, 0x0a, - 0x2e, 0x6d, 0x6c, 0x73, 0x2f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, - 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, - 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, - 0x19, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x22, 0xa7, 0x01, 0x0a, 0x10, 0x4d, - 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x12, - 0x29, 0x0a, 0x10, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, - 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x0f, 0x69, 0x6e, 0x73, 0x74, 0x61, - 0x6c, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x73, 0x12, 0x27, 0x0a, 0x0f, 0x61, 0x63, - 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x0e, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x41, 0x64, 0x64, 0x72, - 0x65, 0x73, 0x73, 0x12, 0x3f, 0x0a, 0x1c, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x74, 0x65, 0x64, - 0x5f, 0x62, 0x79, 0x5f, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x61, 0x64, 0x64, 0x72, - 0x65, 0x73, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x19, 0x69, 0x6e, 0x69, 0x74, 0x69, - 0x61, 0x74, 0x65, 0x64, 0x42, 0x79, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x41, 0x64, 0x64, - 0x72, 0x65, 0x73, 0x73, 0x22, 0x80, 0x03, 0x0a, 0x16, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x4d, 0x65, - 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x12, - 0x50, 0x0a, 0x0d, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x5f, 0x61, 0x64, 0x64, 0x65, 0x64, - 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, - 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, - 0x74, 0x73, 0x2e, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x43, 0x68, 0x61, - 0x6e, 0x67, 0x65, 0x52, 0x0c, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x41, 0x64, 0x64, 0x65, - 0x64, 0x12, 0x54, 0x0a, 0x0f, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x5f, 0x72, 0x65, 0x6d, - 0x6f, 0x76, 0x65, 0x64, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x78, 0x6d, 0x74, - 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, - 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, - 0x70, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x0e, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, - 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x12, 0x5c, 0x0a, 0x13, 0x69, 0x6e, 0x73, 0x74, 0x61, - 0x6c, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x5f, 0x61, 0x64, 0x64, 0x65, 0x64, 0x18, 0x03, - 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, - 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, - 0x2e, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x43, 0x68, 0x61, 0x6e, 0x67, - 0x65, 0x52, 0x12, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, - 0x41, 0x64, 0x64, 0x65, 0x64, 0x12, 0x60, 0x0a, 0x15, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x5f, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x18, 0x04, - 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, - 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, - 0x2e, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x43, 0x68, 0x61, 0x6e, 0x67, - 0x65, 0x52, 0x14, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, - 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x22, 0x9b, 0x04, 0x0a, 0x0c, 0x47, 0x72, 0x6f, 0x75, - 0x70, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x12, 0x31, 0x0a, 0x15, 0x69, 0x6e, 0x69, 0x74, - 0x69, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x62, 0x79, 0x5f, 0x69, 0x6e, 0x62, 0x6f, 0x78, 0x5f, 0x69, - 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x12, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x74, - 0x65, 0x64, 0x42, 0x79, 0x49, 0x6e, 0x62, 0x6f, 0x78, 0x49, 0x64, 0x12, 0x52, 0x0a, 0x0d, 0x61, - 0x64, 0x64, 0x65, 0x64, 0x5f, 0x69, 0x6e, 0x62, 0x6f, 0x78, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, - 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x47, - 0x72, 0x6f, 0x75, 0x70, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x2e, 0x49, 0x6e, 0x62, 0x6f, - 0x78, 0x52, 0x0c, 0x61, 0x64, 0x64, 0x65, 0x64, 0x49, 0x6e, 0x62, 0x6f, 0x78, 0x65, 0x73, 0x12, - 0x56, 0x0a, 0x0f, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x5f, 0x69, 0x6e, 0x62, 0x6f, 0x78, - 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, - 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, - 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, - 0x64, 0x2e, 0x49, 0x6e, 0x62, 0x6f, 0x78, 0x52, 0x0e, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, - 0x49, 0x6e, 0x62, 0x6f, 0x78, 0x65, 0x73, 0x12, 0x71, 0x0a, 0x16, 0x6d, 0x65, 0x74, 0x61, 0x64, - 0x61, 0x74, 0x61, 0x5f, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, - 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x3b, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, + 0x75, 0x65, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x03, 0x01, 0x01, 0x12, 0x03, 0x28, 0x0a, + 0x16, 0x0a, 0x0d, 0x0a, 0x06, 0x04, 0x02, 0x03, 0x01, 0x02, 0x00, 0x12, 0x03, 0x29, 0x04, 0x2b, + 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, 0x01, 0x02, 0x00, 0x04, 0x12, 0x03, 0x29, 0x04, 0x0c, + 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, 0x01, 0x02, 0x00, 0x06, 0x12, 0x03, 0x29, 0x0d, 0x1d, + 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, 0x01, 0x02, 0x00, 0x01, 0x12, 0x03, 0x29, 0x1e, 0x26, + 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, 0x01, 0x02, 0x00, 0x03, 0x12, 0x03, 0x29, 0x29, 0x2a, + 0x0a, 0x0c, 0x0a, 0x04, 0x04, 0x02, 0x08, 0x00, 0x12, 0x04, 0x2c, 0x02, 0x30, 0x03, 0x0a, 0x0c, + 0x0a, 0x05, 0x04, 0x02, 0x08, 0x00, 0x01, 0x12, 0x03, 0x2c, 0x08, 0x0c, 0x0a, 0x0b, 0x0a, 0x04, + 0x04, 0x02, 0x02, 0x00, 0x12, 0x03, 0x2d, 0x04, 0x18, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, + 0x00, 0x06, 0x12, 0x03, 0x2d, 0x04, 0x0e, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x00, 0x01, + 0x12, 0x03, 0x2d, 0x0f, 0x13, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x00, 0x03, 0x12, 0x03, + 0x2d, 0x16, 0x17, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x02, 0x02, 0x01, 0x12, 0x03, 0x2e, 0x04, 0x23, + 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x01, 0x06, 0x12, 0x03, 0x2e, 0x04, 0x10, 0x0a, 0x0c, + 0x0a, 0x05, 0x04, 0x02, 0x02, 0x01, 0x01, 0x12, 0x03, 0x2e, 0x11, 0x1e, 0x0a, 0x0c, 0x0a, 0x05, + 0x04, 0x02, 0x02, 0x01, 0x03, 0x12, 0x03, 0x2e, 0x21, 0x22, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x02, + 0x02, 0x02, 0x12, 0x03, 0x2f, 0x04, 0x23, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x02, 0x06, + 0x12, 0x03, 0x2f, 0x04, 0x10, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x02, 0x01, 0x12, 0x03, + 0x2f, 0x11, 0x1e, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x02, 0x03, 0x12, 0x03, 0x2f, 0x21, + 0x22, 0x0a, 0x35, 0x0a, 0x02, 0x04, 0x03, 0x12, 0x04, 0x34, 0x00, 0x4d, 0x01, 0x1a, 0x29, 0x20, + 0x41, 0x20, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x67, 0x6f, + 0x76, 0x65, 0x72, 0x6e, 0x73, 0x20, 0x75, 0x70, 0x64, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x20, 0x6d, + 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x0a, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x03, 0x01, 0x12, + 0x03, 0x34, 0x08, 0x16, 0x0a, 0x1b, 0x0a, 0x04, 0x04, 0x03, 0x04, 0x00, 0x12, 0x04, 0x36, 0x02, + 0x3c, 0x03, 0x1a, 0x0d, 0x20, 0x42, 0x61, 0x73, 0x65, 0x20, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, + 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x04, 0x00, 0x01, 0x12, 0x03, 0x36, 0x07, 0x19, 0x0a, + 0x0d, 0x0a, 0x06, 0x04, 0x03, 0x04, 0x00, 0x02, 0x00, 0x12, 0x03, 0x37, 0x04, 0x29, 0x0a, 0x0e, + 0x0a, 0x07, 0x04, 0x03, 0x04, 0x00, 0x02, 0x00, 0x01, 0x12, 0x03, 0x37, 0x04, 0x24, 0x0a, 0x0e, + 0x0a, 0x07, 0x04, 0x03, 0x04, 0x00, 0x02, 0x00, 0x02, 0x12, 0x03, 0x37, 0x27, 0x28, 0x0a, 0x0d, + 0x0a, 0x06, 0x04, 0x03, 0x04, 0x00, 0x02, 0x01, 0x12, 0x03, 0x38, 0x04, 0x23, 0x0a, 0x0e, 0x0a, + 0x07, 0x04, 0x03, 0x04, 0x00, 0x02, 0x01, 0x01, 0x12, 0x03, 0x38, 0x04, 0x1e, 0x0a, 0x0e, 0x0a, + 0x07, 0x04, 0x03, 0x04, 0x00, 0x02, 0x01, 0x02, 0x12, 0x03, 0x38, 0x21, 0x22, 0x0a, 0x0d, 0x0a, + 0x06, 0x04, 0x03, 0x04, 0x00, 0x02, 0x02, 0x12, 0x03, 0x39, 0x04, 0x22, 0x0a, 0x0e, 0x0a, 0x07, + 0x04, 0x03, 0x04, 0x00, 0x02, 0x02, 0x01, 0x12, 0x03, 0x39, 0x04, 0x1d, 0x0a, 0x0e, 0x0a, 0x07, + 0x04, 0x03, 0x04, 0x00, 0x02, 0x02, 0x02, 0x12, 0x03, 0x39, 0x20, 0x21, 0x0a, 0x0d, 0x0a, 0x06, + 0x04, 0x03, 0x04, 0x00, 0x02, 0x03, 0x12, 0x03, 0x3a, 0x04, 0x2c, 0x0a, 0x0e, 0x0a, 0x07, 0x04, + 0x03, 0x04, 0x00, 0x02, 0x03, 0x01, 0x12, 0x03, 0x3a, 0x04, 0x27, 0x0a, 0x0e, 0x0a, 0x07, 0x04, + 0x03, 0x04, 0x00, 0x02, 0x03, 0x02, 0x12, 0x03, 0x3a, 0x2a, 0x2b, 0x0a, 0x0d, 0x0a, 0x06, 0x04, + 0x03, 0x04, 0x00, 0x02, 0x04, 0x12, 0x03, 0x3b, 0x04, 0x32, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x03, + 0x04, 0x00, 0x02, 0x04, 0x01, 0x12, 0x03, 0x3b, 0x04, 0x2d, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x03, + 0x04, 0x00, 0x02, 0x04, 0x02, 0x12, 0x03, 0x3b, 0x30, 0x31, 0x0a, 0x44, 0x0a, 0x04, 0x04, 0x03, + 0x03, 0x00, 0x12, 0x04, 0x3f, 0x02, 0x41, 0x03, 0x1a, 0x36, 0x20, 0x43, 0x6f, 0x6d, 0x62, 0x69, + 0x6e, 0x65, 0x20, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x20, 0x70, 0x6f, 0x6c, 0x69, + 0x63, 0x69, 0x65, 0x73, 0x2e, 0x20, 0x41, 0x6c, 0x6c, 0x20, 0x6d, 0x75, 0x73, 0x74, 0x20, 0x65, + 0x76, 0x61, 0x6c, 0x75, 0x61, 0x74, 0x65, 0x20, 0x74, 0x6f, 0x20, 0x74, 0x72, 0x75, 0x65, 0x0a, + 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x03, 0x00, 0x01, 0x12, 0x03, 0x3f, 0x0a, 0x16, 0x0a, 0x0d, + 0x0a, 0x06, 0x04, 0x03, 0x03, 0x00, 0x02, 0x00, 0x12, 0x03, 0x40, 0x04, 0x29, 0x0a, 0x0e, 0x0a, + 0x07, 0x04, 0x03, 0x03, 0x00, 0x02, 0x00, 0x04, 0x12, 0x03, 0x40, 0x04, 0x0c, 0x0a, 0x0e, 0x0a, + 0x07, 0x04, 0x03, 0x03, 0x00, 0x02, 0x00, 0x06, 0x12, 0x03, 0x40, 0x0d, 0x1b, 0x0a, 0x0e, 0x0a, + 0x07, 0x04, 0x03, 0x03, 0x00, 0x02, 0x00, 0x01, 0x12, 0x03, 0x40, 0x1c, 0x24, 0x0a, 0x0e, 0x0a, + 0x07, 0x04, 0x03, 0x03, 0x00, 0x02, 0x00, 0x03, 0x12, 0x03, 0x40, 0x27, 0x28, 0x0a, 0x44, 0x0a, + 0x04, 0x04, 0x03, 0x03, 0x01, 0x12, 0x04, 0x44, 0x02, 0x46, 0x03, 0x1a, 0x36, 0x20, 0x43, 0x6f, + 0x6d, 0x62, 0x69, 0x6e, 0x65, 0x20, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x20, 0x70, + 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x2e, 0x20, 0x41, 0x6e, 0x79, 0x20, 0x6d, 0x75, 0x73, + 0x74, 0x20, 0x65, 0x76, 0x61, 0x6c, 0x75, 0x61, 0x74, 0x65, 0x20, 0x74, 0x6f, 0x20, 0x74, 0x72, + 0x75, 0x65, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x03, 0x01, 0x01, 0x12, 0x03, 0x44, 0x0a, + 0x16, 0x0a, 0x0d, 0x0a, 0x06, 0x04, 0x03, 0x03, 0x01, 0x02, 0x00, 0x12, 0x03, 0x45, 0x04, 0x29, + 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x03, 0x03, 0x01, 0x02, 0x00, 0x04, 0x12, 0x03, 0x45, 0x04, 0x0c, + 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x03, 0x03, 0x01, 0x02, 0x00, 0x06, 0x12, 0x03, 0x45, 0x0d, 0x1b, + 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x03, 0x03, 0x01, 0x02, 0x00, 0x01, 0x12, 0x03, 0x45, 0x1c, 0x24, + 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x03, 0x03, 0x01, 0x02, 0x00, 0x03, 0x12, 0x03, 0x45, 0x27, 0x28, + 0x0a, 0x0c, 0x0a, 0x04, 0x04, 0x03, 0x08, 0x00, 0x12, 0x04, 0x48, 0x02, 0x4c, 0x03, 0x0a, 0x0c, + 0x0a, 0x05, 0x04, 0x03, 0x08, 0x00, 0x01, 0x12, 0x03, 0x48, 0x08, 0x0c, 0x0a, 0x0b, 0x0a, 0x04, + 0x04, 0x03, 0x02, 0x00, 0x12, 0x03, 0x49, 0x04, 0x20, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, + 0x00, 0x06, 0x12, 0x03, 0x49, 0x04, 0x16, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, 0x00, 0x01, + 0x12, 0x03, 0x49, 0x17, 0x1b, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, 0x00, 0x03, 0x12, 0x03, + 0x49, 0x1e, 0x1f, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x03, 0x02, 0x01, 0x12, 0x03, 0x4a, 0x04, 0x23, + 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, 0x01, 0x06, 0x12, 0x03, 0x4a, 0x04, 0x10, 0x0a, 0x0c, + 0x0a, 0x05, 0x04, 0x03, 0x02, 0x01, 0x01, 0x12, 0x03, 0x4a, 0x11, 0x1e, 0x0a, 0x0c, 0x0a, 0x05, + 0x04, 0x03, 0x02, 0x01, 0x03, 0x12, 0x03, 0x4a, 0x21, 0x22, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x03, + 0x02, 0x02, 0x12, 0x03, 0x4b, 0x04, 0x23, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, 0x02, 0x06, + 0x12, 0x03, 0x4b, 0x04, 0x10, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, 0x02, 0x01, 0x12, 0x03, + 0x4b, 0x11, 0x1e, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, 0x02, 0x03, 0x12, 0x03, 0x4b, 0x21, + 0x22, 0x0a, 0x38, 0x0a, 0x02, 0x04, 0x04, 0x12, 0x04, 0x50, 0x00, 0x68, 0x01, 0x1a, 0x2c, 0x20, + 0x41, 0x20, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x67, 0x6f, + 0x76, 0x65, 0x72, 0x6e, 0x73, 0x20, 0x75, 0x70, 0x64, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x20, 0x70, + 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x0a, 0x0a, 0x0a, 0x0a, 0x03, 0x04, + 0x04, 0x01, 0x12, 0x03, 0x50, 0x08, 0x1f, 0x0a, 0x1b, 0x0a, 0x04, 0x04, 0x04, 0x04, 0x00, 0x12, + 0x04, 0x52, 0x02, 0x57, 0x03, 0x1a, 0x0d, 0x20, 0x42, 0x61, 0x73, 0x65, 0x20, 0x70, 0x6f, 0x6c, + 0x69, 0x63, 0x79, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x04, 0x00, 0x01, 0x12, 0x03, 0x52, + 0x07, 0x1c, 0x0a, 0x0d, 0x0a, 0x06, 0x04, 0x04, 0x04, 0x00, 0x02, 0x00, 0x12, 0x03, 0x53, 0x04, + 0x2c, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x04, 0x04, 0x00, 0x02, 0x00, 0x01, 0x12, 0x03, 0x53, 0x04, + 0x27, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x04, 0x04, 0x00, 0x02, 0x00, 0x02, 0x12, 0x03, 0x53, 0x2a, + 0x2b, 0x0a, 0x0d, 0x0a, 0x06, 0x04, 0x04, 0x04, 0x00, 0x02, 0x01, 0x12, 0x03, 0x54, 0x04, 0x25, + 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x04, 0x04, 0x00, 0x02, 0x01, 0x01, 0x12, 0x03, 0x54, 0x04, 0x20, + 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x04, 0x04, 0x00, 0x02, 0x01, 0x02, 0x12, 0x03, 0x54, 0x23, 0x24, + 0x0a, 0x0d, 0x0a, 0x06, 0x04, 0x04, 0x04, 0x00, 0x02, 0x02, 0x12, 0x03, 0x55, 0x04, 0x2f, 0x0a, + 0x0e, 0x0a, 0x07, 0x04, 0x04, 0x04, 0x00, 0x02, 0x02, 0x01, 0x12, 0x03, 0x55, 0x04, 0x2a, 0x0a, + 0x0e, 0x0a, 0x07, 0x04, 0x04, 0x04, 0x00, 0x02, 0x02, 0x02, 0x12, 0x03, 0x55, 0x2d, 0x2e, 0x0a, + 0x0d, 0x0a, 0x06, 0x04, 0x04, 0x04, 0x00, 0x02, 0x03, 0x12, 0x03, 0x56, 0x04, 0x35, 0x0a, 0x0e, + 0x0a, 0x07, 0x04, 0x04, 0x04, 0x00, 0x02, 0x03, 0x01, 0x12, 0x03, 0x56, 0x04, 0x30, 0x0a, 0x0e, + 0x0a, 0x07, 0x04, 0x04, 0x04, 0x00, 0x02, 0x03, 0x02, 0x12, 0x03, 0x56, 0x33, 0x34, 0x0a, 0x44, + 0x0a, 0x04, 0x04, 0x04, 0x03, 0x00, 0x12, 0x04, 0x5a, 0x02, 0x5c, 0x03, 0x1a, 0x36, 0x20, 0x43, + 0x6f, 0x6d, 0x62, 0x69, 0x6e, 0x65, 0x20, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x20, + 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x2e, 0x20, 0x41, 0x6c, 0x6c, 0x20, 0x6d, 0x75, + 0x73, 0x74, 0x20, 0x65, 0x76, 0x61, 0x6c, 0x75, 0x61, 0x74, 0x65, 0x20, 0x74, 0x6f, 0x20, 0x74, + 0x72, 0x75, 0x65, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x03, 0x00, 0x01, 0x12, 0x03, 0x5a, + 0x0a, 0x16, 0x0a, 0x0d, 0x0a, 0x06, 0x04, 0x04, 0x03, 0x00, 0x02, 0x00, 0x12, 0x03, 0x5b, 0x04, + 0x32, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x04, 0x03, 0x00, 0x02, 0x00, 0x04, 0x12, 0x03, 0x5b, 0x04, + 0x0c, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x04, 0x03, 0x00, 0x02, 0x00, 0x06, 0x12, 0x03, 0x5b, 0x0d, + 0x24, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x04, 0x03, 0x00, 0x02, 0x00, 0x01, 0x12, 0x03, 0x5b, 0x25, + 0x2d, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x04, 0x03, 0x00, 0x02, 0x00, 0x03, 0x12, 0x03, 0x5b, 0x30, + 0x31, 0x0a, 0x44, 0x0a, 0x04, 0x04, 0x04, 0x03, 0x01, 0x12, 0x04, 0x5f, 0x02, 0x61, 0x03, 0x1a, + 0x36, 0x20, 0x43, 0x6f, 0x6d, 0x62, 0x69, 0x6e, 0x65, 0x20, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, + 0x6c, 0x65, 0x20, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x2e, 0x20, 0x41, 0x6e, 0x79, + 0x20, 0x6d, 0x75, 0x73, 0x74, 0x20, 0x65, 0x76, 0x61, 0x6c, 0x75, 0x61, 0x74, 0x65, 0x20, 0x74, + 0x6f, 0x20, 0x74, 0x72, 0x75, 0x65, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x03, 0x01, 0x01, + 0x12, 0x03, 0x5f, 0x0a, 0x16, 0x0a, 0x0d, 0x0a, 0x06, 0x04, 0x04, 0x03, 0x01, 0x02, 0x00, 0x12, + 0x03, 0x60, 0x04, 0x32, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x04, 0x03, 0x01, 0x02, 0x00, 0x04, 0x12, + 0x03, 0x60, 0x04, 0x0c, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x04, 0x03, 0x01, 0x02, 0x00, 0x06, 0x12, + 0x03, 0x60, 0x0d, 0x24, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x04, 0x03, 0x01, 0x02, 0x00, 0x01, 0x12, + 0x03, 0x60, 0x25, 0x2d, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x04, 0x03, 0x01, 0x02, 0x00, 0x03, 0x12, + 0x03, 0x60, 0x30, 0x31, 0x0a, 0x0c, 0x0a, 0x04, 0x04, 0x04, 0x08, 0x00, 0x12, 0x04, 0x63, 0x02, + 0x67, 0x03, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x08, 0x00, 0x01, 0x12, 0x03, 0x63, 0x08, 0x0c, + 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x04, 0x02, 0x00, 0x12, 0x03, 0x64, 0x04, 0x23, 0x0a, 0x0c, 0x0a, + 0x05, 0x04, 0x04, 0x02, 0x00, 0x06, 0x12, 0x03, 0x64, 0x04, 0x19, 0x0a, 0x0c, 0x0a, 0x05, 0x04, + 0x04, 0x02, 0x00, 0x01, 0x12, 0x03, 0x64, 0x1a, 0x1e, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x02, + 0x00, 0x03, 0x12, 0x03, 0x64, 0x21, 0x22, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x04, 0x02, 0x01, 0x12, + 0x03, 0x65, 0x04, 0x23, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x02, 0x01, 0x06, 0x12, 0x03, 0x65, + 0x04, 0x10, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x02, 0x01, 0x01, 0x12, 0x03, 0x65, 0x11, 0x1e, + 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x02, 0x01, 0x03, 0x12, 0x03, 0x65, 0x21, 0x22, 0x0a, 0x0b, + 0x0a, 0x04, 0x04, 0x04, 0x02, 0x02, 0x12, 0x03, 0x66, 0x04, 0x23, 0x0a, 0x0c, 0x0a, 0x05, 0x04, + 0x04, 0x02, 0x02, 0x06, 0x12, 0x03, 0x66, 0x04, 0x10, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x02, + 0x02, 0x01, 0x12, 0x03, 0x66, 0x11, 0x1e, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x02, 0x02, 0x03, + 0x12, 0x03, 0x66, 0x21, 0x22, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, 0x0a, 0xb8, 0x1a, + 0x0a, 0x2e, 0x6d, 0x6c, 0x73, 0x2f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, + 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x63, 0x72, 0x69, 0x70, + 0x74, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x12, 0x19, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x22, 0xa7, 0x01, 0x0a, 0x10, + 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, + 0x12, 0x29, 0x0a, 0x10, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x5f, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x0f, 0x69, 0x6e, 0x73, 0x74, + 0x61, 0x6c, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x73, 0x12, 0x27, 0x0a, 0x0f, 0x61, + 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x41, 0x64, 0x64, + 0x72, 0x65, 0x73, 0x73, 0x12, 0x3f, 0x0a, 0x1c, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x74, 0x65, + 0x64, 0x5f, 0x62, 0x79, 0x5f, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x61, 0x64, 0x64, + 0x72, 0x65, 0x73, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x19, 0x69, 0x6e, 0x69, 0x74, + 0x69, 0x61, 0x74, 0x65, 0x64, 0x42, 0x79, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x41, 0x64, + 0x64, 0x72, 0x65, 0x73, 0x73, 0x22, 0x80, 0x03, 0x0a, 0x16, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x4d, + 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x73, + 0x12, 0x50, 0x0a, 0x0d, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x5f, 0x61, 0x64, 0x64, 0x65, + 0x64, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, - 0x6e, 0x74, 0x73, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, - 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x43, 0x68, - 0x61, 0x6e, 0x67, 0x65, 0x52, 0x14, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x46, 0x69, - 0x65, 0x6c, 0x64, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x1a, 0x22, 0x0a, 0x05, 0x49, 0x6e, - 0x62, 0x6f, 0x78, 0x12, 0x19, 0x0a, 0x08, 0x69, 0x6e, 0x62, 0x6f, 0x78, 0x5f, 0x69, 0x64, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x69, 0x6e, 0x62, 0x6f, 0x78, 0x49, 0x64, 0x1a, 0x94, - 0x01, 0x0a, 0x13, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x46, 0x69, 0x65, 0x6c, 0x64, - 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x5f, - 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x66, 0x69, 0x65, 0x6c, - 0x64, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x09, 0x6f, 0x6c, 0x64, 0x5f, 0x76, 0x61, 0x6c, - 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x08, 0x6f, 0x6c, 0x64, 0x56, - 0x61, 0x6c, 0x75, 0x65, 0x88, 0x01, 0x01, 0x12, 0x20, 0x0a, 0x09, 0x6e, 0x65, 0x77, 0x5f, 0x76, - 0x61, 0x6c, 0x75, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x48, 0x01, 0x52, 0x08, 0x6e, 0x65, - 0x77, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x88, 0x01, 0x01, 0x42, 0x0c, 0x0a, 0x0a, 0x5f, 0x6f, 0x6c, - 0x64, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x42, 0x0c, 0x0a, 0x0a, 0x5f, 0x6e, 0x65, 0x77, 0x5f, - 0x76, 0x61, 0x6c, 0x75, 0x65, 0x42, 0xec, 0x01, 0x0a, 0x1d, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x6d, + 0x6e, 0x74, 0x73, 0x2e, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x43, 0x68, + 0x61, 0x6e, 0x67, 0x65, 0x52, 0x0c, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x41, 0x64, 0x64, + 0x65, 0x64, 0x12, 0x54, 0x0a, 0x0f, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x5f, 0x72, 0x65, + 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, - 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x42, 0x17, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x63, 0x72, - 0x69, 0x70, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x50, 0x72, 0x6f, 0x74, 0x6f, - 0x50, 0x01, 0x5a, 0x30, 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, - 0x6d, 0x6c, 0x73, 0x2f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, - 0x65, 0x6e, 0x74, 0x73, 0xa2, 0x02, 0x03, 0x58, 0x4d, 0x4d, 0xaa, 0x02, 0x18, 0x58, 0x6d, 0x74, - 0x70, 0x2e, 0x4d, 0x6c, 0x73, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, - 0x74, 0x65, 0x6e, 0x74, 0x73, 0xca, 0x02, 0x18, 0x58, 0x6d, 0x74, 0x70, 0x5c, 0x4d, 0x6c, 0x73, - 0x5c, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, - 0xe2, 0x02, 0x24, 0x58, 0x6d, 0x74, 0x70, 0x5c, 0x4d, 0x6c, 0x73, 0x5c, 0x4d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x5c, 0x47, 0x50, 0x42, 0x4d, - 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x1a, 0x58, 0x6d, 0x74, 0x70, 0x3a, 0x3a, - 0x4d, 0x6c, 0x73, 0x3a, 0x3a, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x74, - 0x65, 0x6e, 0x74, 0x73, 0x4a, 0xa8, 0x0f, 0x0a, 0x06, 0x12, 0x04, 0x01, 0x00, 0x38, 0x01, 0x0a, - 0x2f, 0x0a, 0x01, 0x0c, 0x12, 0x03, 0x01, 0x00, 0x12, 0x1a, 0x25, 0x20, 0x4d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x20, 0x65, 0x6e, 0x63, 0x6f, - 0x64, 0x69, 0x6e, 0x67, 0x20, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x75, 0x72, 0x65, 0x73, 0x0a, - 0x0a, 0x08, 0x0a, 0x01, 0x02, 0x12, 0x03, 0x03, 0x00, 0x22, 0x0a, 0x08, 0x0a, 0x01, 0x08, 0x12, - 0x03, 0x05, 0x00, 0x47, 0x0a, 0x09, 0x0a, 0x02, 0x08, 0x0b, 0x12, 0x03, 0x05, 0x00, 0x47, 0x0a, - 0x3a, 0x0a, 0x02, 0x04, 0x00, 0x12, 0x04, 0x09, 0x00, 0x0d, 0x01, 0x1a, 0x2e, 0x20, 0x41, 0x20, - 0x67, 0x72, 0x6f, 0x75, 0x70, 0x20, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x20, 0x61, 0x6e, 0x64, - 0x20, 0x61, 0x66, 0x66, 0x65, 0x63, 0x74, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, - 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x49, 0x44, 0x73, 0x0a, 0x0a, 0x0a, 0x0a, 0x03, 0x04, - 0x00, 0x01, 0x12, 0x03, 0x09, 0x08, 0x18, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x00, 0x02, 0x00, 0x12, - 0x03, 0x0a, 0x02, 0x26, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x00, 0x04, 0x12, 0x03, 0x0a, - 0x02, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x00, 0x05, 0x12, 0x03, 0x0a, 0x0b, 0x10, - 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x00, 0x01, 0x12, 0x03, 0x0a, 0x11, 0x21, 0x0a, 0x0c, - 0x0a, 0x05, 0x04, 0x00, 0x02, 0x00, 0x03, 0x12, 0x03, 0x0a, 0x24, 0x25, 0x0a, 0x0b, 0x0a, 0x04, - 0x04, 0x00, 0x02, 0x01, 0x12, 0x03, 0x0b, 0x02, 0x1d, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, - 0x01, 0x05, 0x12, 0x03, 0x0b, 0x02, 0x08, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x01, 0x01, - 0x12, 0x03, 0x0b, 0x09, 0x18, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x01, 0x03, 0x12, 0x03, - 0x0b, 0x1b, 0x1c, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x00, 0x02, 0x02, 0x12, 0x03, 0x0c, 0x02, 0x2a, - 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x02, 0x05, 0x12, 0x03, 0x0c, 0x02, 0x08, 0x0a, 0x0c, - 0x0a, 0x05, 0x04, 0x00, 0x02, 0x02, 0x01, 0x12, 0x03, 0x0c, 0x09, 0x25, 0x0a, 0x0c, 0x0a, 0x05, - 0x04, 0x00, 0x02, 0x02, 0x03, 0x12, 0x03, 0x0c, 0x28, 0x29, 0x0a, 0x64, 0x0a, 0x02, 0x04, 0x01, - 0x12, 0x04, 0x10, 0x00, 0x1d, 0x01, 0x1a, 0x23, 0x20, 0x54, 0x68, 0x65, 0x20, 0x67, 0x72, 0x6f, - 0x75, 0x70, 0x20, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x20, 0x63, 0x68, - 0x61, 0x6e, 0x67, 0x65, 0x20, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x0a, 0x22, 0x33, 0x20, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x6c, 0x69, 0x6e, 0x74, 0x3a, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x20, - 0x52, 0x45, 0x50, 0x45, 0x41, 0x54, 0x45, 0x44, 0x5f, 0x46, 0x49, 0x45, 0x4c, 0x44, 0x5f, 0x4e, - 0x41, 0x4d, 0x45, 0x53, 0x5f, 0x50, 0x4c, 0x55, 0x52, 0x41, 0x4c, 0x49, 0x5a, 0x45, 0x44, 0x0a, - 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x01, 0x01, 0x12, 0x03, 0x10, 0x08, 0x1e, 0x0a, 0x39, 0x0a, 0x04, - 0x04, 0x01, 0x02, 0x00, 0x12, 0x03, 0x14, 0x02, 0x2e, 0x1a, 0x2c, 0x20, 0x4d, 0x65, 0x6d, 0x62, - 0x65, 0x72, 0x73, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x68, 0x61, 0x76, 0x65, 0x20, 0x62, 0x65, - 0x65, 0x6e, 0x20, 0x61, 0x64, 0x64, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, - 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x00, 0x04, - 0x12, 0x03, 0x14, 0x02, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x00, 0x06, 0x12, 0x03, - 0x14, 0x0b, 0x1b, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x00, 0x01, 0x12, 0x03, 0x14, 0x1c, - 0x29, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x00, 0x03, 0x12, 0x03, 0x14, 0x2c, 0x2d, 0x0a, - 0x3b, 0x0a, 0x04, 0x04, 0x01, 0x02, 0x01, 0x12, 0x03, 0x16, 0x02, 0x30, 0x1a, 0x2e, 0x20, 0x4d, - 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x68, 0x61, 0x76, 0x65, - 0x20, 0x62, 0x65, 0x65, 0x6e, 0x20, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x20, 0x69, 0x6e, - 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, - 0x04, 0x01, 0x02, 0x01, 0x04, 0x12, 0x03, 0x16, 0x02, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, - 0x02, 0x01, 0x06, 0x12, 0x03, 0x16, 0x0b, 0x1b, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x01, - 0x01, 0x12, 0x03, 0x16, 0x1c, 0x2b, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x01, 0x03, 0x12, - 0x03, 0x16, 0x2e, 0x2f, 0x0a, 0x52, 0x0a, 0x04, 0x04, 0x01, 0x02, 0x02, 0x12, 0x03, 0x18, 0x02, - 0x34, 0x1a, 0x45, 0x20, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x73, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x68, 0x61, 0x76, 0x65, 0x20, 0x62, 0x65, 0x65, 0x6e, - 0x20, 0x61, 0x64, 0x64, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6f, + 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, + 0x69, 0x70, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x0e, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, + 0x73, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x12, 0x5c, 0x0a, 0x13, 0x69, 0x6e, 0x73, 0x74, + 0x61, 0x6c, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x5f, 0x61, 0x64, 0x64, 0x65, 0x64, 0x18, + 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, + 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, + 0x73, 0x2e, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x43, 0x68, 0x61, 0x6e, + 0x67, 0x65, 0x52, 0x12, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x73, 0x41, 0x64, 0x64, 0x65, 0x64, 0x12, 0x60, 0x0a, 0x15, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, + 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x5f, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x18, + 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, + 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, + 0x73, 0x2e, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x43, 0x68, 0x61, 0x6e, + 0x67, 0x65, 0x52, 0x14, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x73, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x22, 0x9b, 0x04, 0x0a, 0x0c, 0x47, 0x72, 0x6f, + 0x75, 0x70, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x12, 0x31, 0x0a, 0x15, 0x69, 0x6e, 0x69, + 0x74, 0x69, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x62, 0x79, 0x5f, 0x69, 0x6e, 0x62, 0x6f, 0x78, 0x5f, + 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x12, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x61, + 0x74, 0x65, 0x64, 0x42, 0x79, 0x49, 0x6e, 0x62, 0x6f, 0x78, 0x49, 0x64, 0x12, 0x52, 0x0a, 0x0d, + 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x69, 0x6e, 0x62, 0x6f, 0x78, 0x65, 0x73, 0x18, 0x02, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, + 0x47, 0x72, 0x6f, 0x75, 0x70, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x2e, 0x49, 0x6e, 0x62, + 0x6f, 0x78, 0x52, 0x0c, 0x61, 0x64, 0x64, 0x65, 0x64, 0x49, 0x6e, 0x62, 0x6f, 0x78, 0x65, 0x73, + 0x12, 0x56, 0x0a, 0x0f, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x5f, 0x69, 0x6e, 0x62, 0x6f, + 0x78, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x78, 0x6d, 0x74, 0x70, + 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, + 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x55, 0x70, 0x64, 0x61, 0x74, + 0x65, 0x64, 0x2e, 0x49, 0x6e, 0x62, 0x6f, 0x78, 0x52, 0x0e, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, + 0x64, 0x49, 0x6e, 0x62, 0x6f, 0x78, 0x65, 0x73, 0x12, 0x71, 0x0a, 0x16, 0x6d, 0x65, 0x74, 0x61, + 0x64, 0x61, 0x74, 0x61, 0x5f, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x67, + 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x3b, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, + 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, + 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, + 0x64, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x43, + 0x68, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x14, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x46, + 0x69, 0x65, 0x6c, 0x64, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x1a, 0x22, 0x0a, 0x05, 0x49, + 0x6e, 0x62, 0x6f, 0x78, 0x12, 0x19, 0x0a, 0x08, 0x69, 0x6e, 0x62, 0x6f, 0x78, 0x5f, 0x69, 0x64, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x69, 0x6e, 0x62, 0x6f, 0x78, 0x49, 0x64, 0x1a, + 0x94, 0x01, 0x0a, 0x13, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x46, 0x69, 0x65, 0x6c, + 0x64, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x66, 0x69, 0x65, 0x6c, 0x64, + 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x66, 0x69, 0x65, + 0x6c, 0x64, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x09, 0x6f, 0x6c, 0x64, 0x5f, 0x76, 0x61, + 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x08, 0x6f, 0x6c, 0x64, + 0x56, 0x61, 0x6c, 0x75, 0x65, 0x88, 0x01, 0x01, 0x12, 0x20, 0x0a, 0x09, 0x6e, 0x65, 0x77, 0x5f, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x48, 0x01, 0x52, 0x08, 0x6e, + 0x65, 0x77, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x88, 0x01, 0x01, 0x42, 0x0c, 0x0a, 0x0a, 0x5f, 0x6f, + 0x6c, 0x64, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x42, 0x0c, 0x0a, 0x0a, 0x5f, 0x6e, 0x65, 0x77, + 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x42, 0xec, 0x01, 0x0a, 0x1d, 0x63, 0x6f, 0x6d, 0x2e, 0x78, + 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, + 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x42, 0x17, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x63, + 0x72, 0x69, 0x70, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x50, 0x72, 0x6f, 0x74, + 0x6f, 0x50, 0x01, 0x5a, 0x30, 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, 0x6d, 0x6c, 0x73, 0x2f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, + 0x74, 0x65, 0x6e, 0x74, 0x73, 0xa2, 0x02, 0x03, 0x58, 0x4d, 0x4d, 0xaa, 0x02, 0x18, 0x58, 0x6d, + 0x74, 0x70, 0x2e, 0x4d, 0x6c, 0x73, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x43, 0x6f, + 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0xca, 0x02, 0x18, 0x58, 0x6d, 0x74, 0x70, 0x5c, 0x4d, 0x6c, + 0x73, 0x5c, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, + 0x73, 0xe2, 0x02, 0x24, 0x58, 0x6d, 0x74, 0x70, 0x5c, 0x4d, 0x6c, 0x73, 0x5c, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x5c, 0x47, 0x50, 0x42, + 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x1a, 0x58, 0x6d, 0x74, 0x70, 0x3a, + 0x3a, 0x4d, 0x6c, 0x73, 0x3a, 0x3a, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, + 0x74, 0x65, 0x6e, 0x74, 0x73, 0x4a, 0xa8, 0x0f, 0x0a, 0x06, 0x12, 0x04, 0x01, 0x00, 0x38, 0x01, + 0x0a, 0x2f, 0x0a, 0x01, 0x0c, 0x12, 0x03, 0x01, 0x00, 0x12, 0x1a, 0x25, 0x20, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x20, 0x65, 0x6e, 0x63, + 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x75, 0x72, 0x65, 0x73, + 0x0a, 0x0a, 0x08, 0x0a, 0x01, 0x02, 0x12, 0x03, 0x03, 0x00, 0x22, 0x0a, 0x08, 0x0a, 0x01, 0x08, + 0x12, 0x03, 0x05, 0x00, 0x47, 0x0a, 0x09, 0x0a, 0x02, 0x08, 0x0b, 0x12, 0x03, 0x05, 0x00, 0x47, + 0x0a, 0x3a, 0x0a, 0x02, 0x04, 0x00, 0x12, 0x04, 0x09, 0x00, 0x0d, 0x01, 0x1a, 0x2e, 0x20, 0x41, + 0x20, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x20, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x20, 0x61, 0x6e, + 0x64, 0x20, 0x61, 0x66, 0x66, 0x65, 0x63, 0x74, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x73, 0x74, 0x61, + 0x6c, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x49, 0x44, 0x73, 0x0a, 0x0a, 0x0a, 0x0a, 0x03, + 0x04, 0x00, 0x01, 0x12, 0x03, 0x09, 0x08, 0x18, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x00, 0x02, 0x00, + 0x12, 0x03, 0x0a, 0x02, 0x26, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x00, 0x04, 0x12, 0x03, + 0x0a, 0x02, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x00, 0x05, 0x12, 0x03, 0x0a, 0x0b, + 0x10, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x00, 0x01, 0x12, 0x03, 0x0a, 0x11, 0x21, 0x0a, + 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x00, 0x03, 0x12, 0x03, 0x0a, 0x24, 0x25, 0x0a, 0x0b, 0x0a, + 0x04, 0x04, 0x00, 0x02, 0x01, 0x12, 0x03, 0x0b, 0x02, 0x1d, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, + 0x02, 0x01, 0x05, 0x12, 0x03, 0x0b, 0x02, 0x08, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x01, + 0x01, 0x12, 0x03, 0x0b, 0x09, 0x18, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x01, 0x03, 0x12, + 0x03, 0x0b, 0x1b, 0x1c, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x00, 0x02, 0x02, 0x12, 0x03, 0x0c, 0x02, + 0x2a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x02, 0x05, 0x12, 0x03, 0x0c, 0x02, 0x08, 0x0a, + 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x02, 0x01, 0x12, 0x03, 0x0c, 0x09, 0x25, 0x0a, 0x0c, 0x0a, + 0x05, 0x04, 0x00, 0x02, 0x02, 0x03, 0x12, 0x03, 0x0c, 0x28, 0x29, 0x0a, 0x64, 0x0a, 0x02, 0x04, + 0x01, 0x12, 0x04, 0x10, 0x00, 0x1d, 0x01, 0x1a, 0x23, 0x20, 0x54, 0x68, 0x65, 0x20, 0x67, 0x72, + 0x6f, 0x75, 0x70, 0x20, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x20, 0x63, + 0x68, 0x61, 0x6e, 0x67, 0x65, 0x20, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x0a, 0x22, 0x33, 0x20, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x6c, 0x69, 0x6e, 0x74, 0x3a, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, + 0x20, 0x52, 0x45, 0x50, 0x45, 0x41, 0x54, 0x45, 0x44, 0x5f, 0x46, 0x49, 0x45, 0x4c, 0x44, 0x5f, + 0x4e, 0x41, 0x4d, 0x45, 0x53, 0x5f, 0x50, 0x4c, 0x55, 0x52, 0x41, 0x4c, 0x49, 0x5a, 0x45, 0x44, + 0x0a, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x01, 0x01, 0x12, 0x03, 0x10, 0x08, 0x1e, 0x0a, 0x39, 0x0a, + 0x04, 0x04, 0x01, 0x02, 0x00, 0x12, 0x03, 0x14, 0x02, 0x2e, 0x1a, 0x2c, 0x20, 0x4d, 0x65, 0x6d, + 0x62, 0x65, 0x72, 0x73, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x68, 0x61, 0x76, 0x65, 0x20, 0x62, + 0x65, 0x65, 0x6e, 0x20, 0x61, 0x64, 0x64, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x00, + 0x04, 0x12, 0x03, 0x14, 0x02, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x00, 0x06, 0x12, + 0x03, 0x14, 0x0b, 0x1b, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x00, 0x01, 0x12, 0x03, 0x14, + 0x1c, 0x29, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x00, 0x03, 0x12, 0x03, 0x14, 0x2c, 0x2d, + 0x0a, 0x3b, 0x0a, 0x04, 0x04, 0x01, 0x02, 0x01, 0x12, 0x03, 0x16, 0x02, 0x30, 0x1a, 0x2e, 0x20, + 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x68, 0x61, 0x76, + 0x65, 0x20, 0x62, 0x65, 0x65, 0x6e, 0x20, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x20, 0x69, + 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x0a, 0x0a, 0x0c, 0x0a, + 0x05, 0x04, 0x01, 0x02, 0x01, 0x04, 0x12, 0x03, 0x16, 0x02, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, + 0x01, 0x02, 0x01, 0x06, 0x12, 0x03, 0x16, 0x0b, 0x1b, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, + 0x01, 0x01, 0x12, 0x03, 0x16, 0x1c, 0x2b, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x01, 0x03, + 0x12, 0x03, 0x16, 0x2e, 0x2f, 0x0a, 0x52, 0x0a, 0x04, 0x04, 0x01, 0x02, 0x02, 0x12, 0x03, 0x18, + 0x02, 0x34, 0x1a, 0x45, 0x20, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x73, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x68, 0x61, 0x76, 0x65, 0x20, 0x62, 0x65, 0x65, + 0x6e, 0x20, 0x61, 0x64, 0x64, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, + 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x2c, 0x20, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x65, 0x64, 0x20, 0x62, + 0x79, 0x20, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, + 0x02, 0x04, 0x12, 0x03, 0x18, 0x02, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x02, 0x06, + 0x12, 0x03, 0x18, 0x0b, 0x1b, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x02, 0x01, 0x12, 0x03, + 0x18, 0x1c, 0x2f, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x02, 0x03, 0x12, 0x03, 0x18, 0x32, + 0x33, 0x0a, 0x45, 0x0a, 0x04, 0x04, 0x01, 0x02, 0x03, 0x12, 0x03, 0x1a, 0x02, 0x36, 0x1a, 0x38, + 0x20, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x72, + 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x2c, 0x20, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x65, 0x64, 0x20, 0x62, 0x79, - 0x20, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x02, - 0x04, 0x12, 0x03, 0x18, 0x02, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x02, 0x06, 0x12, - 0x03, 0x18, 0x0b, 0x1b, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x02, 0x01, 0x12, 0x03, 0x18, - 0x1c, 0x2f, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x02, 0x03, 0x12, 0x03, 0x18, 0x32, 0x33, - 0x0a, 0x45, 0x0a, 0x04, 0x04, 0x01, 0x02, 0x03, 0x12, 0x03, 0x1a, 0x02, 0x36, 0x1a, 0x38, 0x20, - 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x72, 0x65, - 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6f, 0x6d, - 0x6d, 0x69, 0x74, 0x2c, 0x20, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x65, 0x64, 0x20, 0x62, 0x79, 0x20, - 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x03, 0x04, - 0x12, 0x03, 0x1a, 0x02, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x03, 0x06, 0x12, 0x03, - 0x1a, 0x0b, 0x1b, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x03, 0x01, 0x12, 0x03, 0x1a, 0x1c, - 0x31, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x03, 0x03, 0x12, 0x03, 0x1a, 0x34, 0x35, 0x0a, - 0x6b, 0x0a, 0x02, 0x04, 0x02, 0x12, 0x04, 0x21, 0x00, 0x38, 0x01, 0x1a, 0x5f, 0x20, 0x41, 0x20, - 0x73, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, - 0x68, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x20, 0x69, 0x6e, 0x20, 0x61, 0x20, 0x63, 0x6f, 0x6d, 0x6d, - 0x69, 0x74, 0x2e, 0x0a, 0x20, 0x49, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x73, 0x20, 0x61, 0x64, - 0x64, 0x65, 0x64, 0x2f, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x62, 0x6f, - 0x78, 0x65, 0x73, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x20, - 0x74, 0x6f, 0x20, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x0a, 0x0a, 0x0a, 0x0a, 0x03, - 0x04, 0x02, 0x01, 0x12, 0x03, 0x21, 0x08, 0x14, 0x0a, 0x41, 0x0a, 0x04, 0x04, 0x02, 0x03, 0x00, - 0x12, 0x04, 0x23, 0x02, 0x25, 0x03, 0x1a, 0x33, 0x20, 0x41, 0x6e, 0x20, 0x69, 0x6e, 0x62, 0x6f, - 0x78, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x77, 0x61, 0x73, 0x20, 0x61, 0x64, 0x64, 0x65, 0x64, - 0x20, 0x6f, 0x72, 0x20, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x20, 0x74, - 0x68, 0x69, 0x73, 0x20, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, - 0x02, 0x03, 0x00, 0x01, 0x12, 0x03, 0x23, 0x0a, 0x0f, 0x0a, 0x0d, 0x0a, 0x06, 0x04, 0x02, 0x03, - 0x00, 0x02, 0x00, 0x12, 0x03, 0x24, 0x04, 0x18, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, 0x00, - 0x02, 0x00, 0x05, 0x12, 0x03, 0x24, 0x04, 0x0a, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, 0x00, - 0x02, 0x00, 0x01, 0x12, 0x03, 0x24, 0x0b, 0x13, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, 0x00, - 0x02, 0x00, 0x03, 0x12, 0x03, 0x24, 0x16, 0x17, 0x0a, 0x3d, 0x0a, 0x04, 0x04, 0x02, 0x03, 0x01, - 0x12, 0x04, 0x28, 0x02, 0x2f, 0x03, 0x1a, 0x2f, 0x20, 0x41, 0x20, 0x73, 0x75, 0x6d, 0x6d, 0x61, - 0x72, 0x79, 0x20, 0x6f, 0x66, 0x20, 0x61, 0x20, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x20, 0x74, - 0x6f, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6d, 0x75, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x6d, 0x65, - 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x03, 0x01, 0x01, - 0x12, 0x03, 0x28, 0x0a, 0x1d, 0x0a, 0x2b, 0x0a, 0x06, 0x04, 0x02, 0x03, 0x01, 0x02, 0x00, 0x12, - 0x03, 0x2a, 0x04, 0x1a, 0x1a, 0x1c, 0x20, 0x54, 0x68, 0x65, 0x20, 0x66, 0x69, 0x65, 0x6c, 0x64, - 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x77, 0x61, 0x73, 0x20, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, - 0x64, 0x0a, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, 0x01, 0x02, 0x00, 0x05, 0x12, 0x03, 0x2a, - 0x04, 0x0a, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, 0x01, 0x02, 0x00, 0x01, 0x12, 0x03, 0x2a, - 0x0b, 0x15, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, 0x01, 0x02, 0x00, 0x03, 0x12, 0x03, 0x2a, - 0x18, 0x19, 0x0a, 0x23, 0x0a, 0x06, 0x04, 0x02, 0x03, 0x01, 0x02, 0x01, 0x12, 0x03, 0x2c, 0x04, - 0x22, 0x1a, 0x14, 0x20, 0x54, 0x68, 0x65, 0x20, 0x70, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, - 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x0a, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, 0x01, 0x02, - 0x01, 0x04, 0x12, 0x03, 0x2c, 0x04, 0x0c, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, 0x01, 0x02, - 0x01, 0x05, 0x12, 0x03, 0x2c, 0x0d, 0x13, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, 0x01, 0x02, - 0x01, 0x01, 0x12, 0x03, 0x2c, 0x14, 0x1d, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, 0x01, 0x02, - 0x01, 0x03, 0x12, 0x03, 0x2c, 0x20, 0x21, 0x0a, 0x22, 0x0a, 0x06, 0x04, 0x02, 0x03, 0x01, 0x02, - 0x02, 0x12, 0x03, 0x2e, 0x04, 0x22, 0x1a, 0x13, 0x20, 0x54, 0x68, 0x65, 0x20, 0x75, 0x70, 0x64, - 0x61, 0x74, 0x65, 0x64, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x0a, 0x0a, 0x0e, 0x0a, 0x07, 0x04, - 0x02, 0x03, 0x01, 0x02, 0x02, 0x04, 0x12, 0x03, 0x2e, 0x04, 0x0c, 0x0a, 0x0e, 0x0a, 0x07, 0x04, - 0x02, 0x03, 0x01, 0x02, 0x02, 0x05, 0x12, 0x03, 0x2e, 0x0d, 0x13, 0x0a, 0x0e, 0x0a, 0x07, 0x04, - 0x02, 0x03, 0x01, 0x02, 0x02, 0x01, 0x12, 0x03, 0x2e, 0x14, 0x1d, 0x0a, 0x0e, 0x0a, 0x07, 0x04, - 0x02, 0x03, 0x01, 0x02, 0x02, 0x03, 0x12, 0x03, 0x2e, 0x20, 0x21, 0x0a, 0x0b, 0x0a, 0x04, 0x04, - 0x02, 0x02, 0x00, 0x12, 0x03, 0x31, 0x02, 0x23, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x00, - 0x05, 0x12, 0x03, 0x31, 0x02, 0x08, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x00, 0x01, 0x12, - 0x03, 0x31, 0x09, 0x1e, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x00, 0x03, 0x12, 0x03, 0x31, - 0x21, 0x22, 0x0a, 0x2e, 0x0a, 0x04, 0x04, 0x02, 0x02, 0x01, 0x12, 0x03, 0x33, 0x02, 0x23, 0x1a, - 0x21, 0x20, 0x54, 0x68, 0x65, 0x20, 0x69, 0x6e, 0x62, 0x6f, 0x78, 0x65, 0x73, 0x20, 0x61, 0x64, - 0x64, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6f, 0x6d, 0x6d, 0x69, - 0x74, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x01, 0x04, 0x12, 0x03, 0x33, 0x02, 0x0a, - 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x01, 0x06, 0x12, 0x03, 0x33, 0x0b, 0x10, 0x0a, 0x0c, - 0x0a, 0x05, 0x04, 0x02, 0x02, 0x01, 0x01, 0x12, 0x03, 0x33, 0x11, 0x1e, 0x0a, 0x0c, 0x0a, 0x05, - 0x04, 0x02, 0x02, 0x01, 0x03, 0x12, 0x03, 0x33, 0x21, 0x22, 0x0a, 0x30, 0x0a, 0x04, 0x04, 0x02, - 0x02, 0x02, 0x12, 0x03, 0x35, 0x02, 0x25, 0x1a, 0x23, 0x20, 0x54, 0x68, 0x65, 0x20, 0x69, 0x6e, - 0x62, 0x6f, 0x78, 0x65, 0x73, 0x20, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x20, 0x69, 0x6e, - 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, - 0x04, 0x02, 0x02, 0x02, 0x04, 0x12, 0x03, 0x35, 0x02, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, - 0x02, 0x02, 0x06, 0x12, 0x03, 0x35, 0x0b, 0x10, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x02, - 0x01, 0x12, 0x03, 0x35, 0x11, 0x20, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x02, 0x03, 0x12, - 0x03, 0x35, 0x23, 0x24, 0x0a, 0x31, 0x0a, 0x04, 0x04, 0x02, 0x02, 0x03, 0x12, 0x03, 0x37, 0x02, - 0x3a, 0x1a, 0x24, 0x20, 0x54, 0x68, 0x65, 0x20, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, - 0x20, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, - 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x03, 0x04, - 0x12, 0x03, 0x37, 0x02, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x03, 0x06, 0x12, 0x03, - 0x37, 0x0b, 0x1e, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x03, 0x01, 0x12, 0x03, 0x37, 0x1f, - 0x35, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x03, 0x03, 0x12, 0x03, 0x37, 0x38, 0x39, 0x62, - 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x20, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x03, + 0x04, 0x12, 0x03, 0x1a, 0x02, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x03, 0x06, 0x12, + 0x03, 0x1a, 0x0b, 0x1b, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x03, 0x01, 0x12, 0x03, 0x1a, + 0x1c, 0x31, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x03, 0x03, 0x12, 0x03, 0x1a, 0x34, 0x35, + 0x0a, 0x6b, 0x0a, 0x02, 0x04, 0x02, 0x12, 0x04, 0x21, 0x00, 0x38, 0x01, 0x1a, 0x5f, 0x20, 0x41, + 0x20, 0x73, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x20, 0x69, 0x6e, 0x20, 0x61, 0x20, 0x63, 0x6f, 0x6d, + 0x6d, 0x69, 0x74, 0x2e, 0x0a, 0x20, 0x49, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x73, 0x20, 0x61, + 0x64, 0x64, 0x65, 0x64, 0x2f, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x62, + 0x6f, 0x78, 0x65, 0x73, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x73, + 0x20, 0x74, 0x6f, 0x20, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x0a, 0x0a, 0x0a, 0x0a, + 0x03, 0x04, 0x02, 0x01, 0x12, 0x03, 0x21, 0x08, 0x14, 0x0a, 0x41, 0x0a, 0x04, 0x04, 0x02, 0x03, + 0x00, 0x12, 0x04, 0x23, 0x02, 0x25, 0x03, 0x1a, 0x33, 0x20, 0x41, 0x6e, 0x20, 0x69, 0x6e, 0x62, + 0x6f, 0x78, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x77, 0x61, 0x73, 0x20, 0x61, 0x64, 0x64, 0x65, + 0x64, 0x20, 0x6f, 0x72, 0x20, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x20, + 0x74, 0x68, 0x69, 0x73, 0x20, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, + 0x04, 0x02, 0x03, 0x00, 0x01, 0x12, 0x03, 0x23, 0x0a, 0x0f, 0x0a, 0x0d, 0x0a, 0x06, 0x04, 0x02, + 0x03, 0x00, 0x02, 0x00, 0x12, 0x03, 0x24, 0x04, 0x18, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, + 0x00, 0x02, 0x00, 0x05, 0x12, 0x03, 0x24, 0x04, 0x0a, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, + 0x00, 0x02, 0x00, 0x01, 0x12, 0x03, 0x24, 0x0b, 0x13, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, + 0x00, 0x02, 0x00, 0x03, 0x12, 0x03, 0x24, 0x16, 0x17, 0x0a, 0x3d, 0x0a, 0x04, 0x04, 0x02, 0x03, + 0x01, 0x12, 0x04, 0x28, 0x02, 0x2f, 0x03, 0x1a, 0x2f, 0x20, 0x41, 0x20, 0x73, 0x75, 0x6d, 0x6d, + 0x61, 0x72, 0x79, 0x20, 0x6f, 0x66, 0x20, 0x61, 0x20, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x20, + 0x74, 0x6f, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6d, 0x75, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x6d, + 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x03, 0x01, + 0x01, 0x12, 0x03, 0x28, 0x0a, 0x1d, 0x0a, 0x2b, 0x0a, 0x06, 0x04, 0x02, 0x03, 0x01, 0x02, 0x00, + 0x12, 0x03, 0x2a, 0x04, 0x1a, 0x1a, 0x1c, 0x20, 0x54, 0x68, 0x65, 0x20, 0x66, 0x69, 0x65, 0x6c, + 0x64, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x77, 0x61, 0x73, 0x20, 0x63, 0x68, 0x61, 0x6e, 0x67, + 0x65, 0x64, 0x0a, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, 0x01, 0x02, 0x00, 0x05, 0x12, 0x03, + 0x2a, 0x04, 0x0a, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, 0x01, 0x02, 0x00, 0x01, 0x12, 0x03, + 0x2a, 0x0b, 0x15, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, 0x01, 0x02, 0x00, 0x03, 0x12, 0x03, + 0x2a, 0x18, 0x19, 0x0a, 0x23, 0x0a, 0x06, 0x04, 0x02, 0x03, 0x01, 0x02, 0x01, 0x12, 0x03, 0x2c, + 0x04, 0x22, 0x1a, 0x14, 0x20, 0x54, 0x68, 0x65, 0x20, 0x70, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, + 0x73, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x0a, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, 0x01, + 0x02, 0x01, 0x04, 0x12, 0x03, 0x2c, 0x04, 0x0c, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, 0x01, + 0x02, 0x01, 0x05, 0x12, 0x03, 0x2c, 0x0d, 0x13, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, 0x01, + 0x02, 0x01, 0x01, 0x12, 0x03, 0x2c, 0x14, 0x1d, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, 0x01, + 0x02, 0x01, 0x03, 0x12, 0x03, 0x2c, 0x20, 0x21, 0x0a, 0x22, 0x0a, 0x06, 0x04, 0x02, 0x03, 0x01, + 0x02, 0x02, 0x12, 0x03, 0x2e, 0x04, 0x22, 0x1a, 0x13, 0x20, 0x54, 0x68, 0x65, 0x20, 0x75, 0x70, + 0x64, 0x61, 0x74, 0x65, 0x64, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x0a, 0x0a, 0x0e, 0x0a, 0x07, + 0x04, 0x02, 0x03, 0x01, 0x02, 0x02, 0x04, 0x12, 0x03, 0x2e, 0x04, 0x0c, 0x0a, 0x0e, 0x0a, 0x07, + 0x04, 0x02, 0x03, 0x01, 0x02, 0x02, 0x05, 0x12, 0x03, 0x2e, 0x0d, 0x13, 0x0a, 0x0e, 0x0a, 0x07, + 0x04, 0x02, 0x03, 0x01, 0x02, 0x02, 0x01, 0x12, 0x03, 0x2e, 0x14, 0x1d, 0x0a, 0x0e, 0x0a, 0x07, + 0x04, 0x02, 0x03, 0x01, 0x02, 0x02, 0x03, 0x12, 0x03, 0x2e, 0x20, 0x21, 0x0a, 0x0b, 0x0a, 0x04, + 0x04, 0x02, 0x02, 0x00, 0x12, 0x03, 0x31, 0x02, 0x23, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, + 0x00, 0x05, 0x12, 0x03, 0x31, 0x02, 0x08, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x00, 0x01, + 0x12, 0x03, 0x31, 0x09, 0x1e, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x00, 0x03, 0x12, 0x03, + 0x31, 0x21, 0x22, 0x0a, 0x2e, 0x0a, 0x04, 0x04, 0x02, 0x02, 0x01, 0x12, 0x03, 0x33, 0x02, 0x23, + 0x1a, 0x21, 0x20, 0x54, 0x68, 0x65, 0x20, 0x69, 0x6e, 0x62, 0x6f, 0x78, 0x65, 0x73, 0x20, 0x61, + 0x64, 0x64, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6f, 0x6d, 0x6d, + 0x69, 0x74, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x01, 0x04, 0x12, 0x03, 0x33, 0x02, + 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x01, 0x06, 0x12, 0x03, 0x33, 0x0b, 0x10, 0x0a, + 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x01, 0x01, 0x12, 0x03, 0x33, 0x11, 0x1e, 0x0a, 0x0c, 0x0a, + 0x05, 0x04, 0x02, 0x02, 0x01, 0x03, 0x12, 0x03, 0x33, 0x21, 0x22, 0x0a, 0x30, 0x0a, 0x04, 0x04, + 0x02, 0x02, 0x02, 0x12, 0x03, 0x35, 0x02, 0x25, 0x1a, 0x23, 0x20, 0x54, 0x68, 0x65, 0x20, 0x69, + 0x6e, 0x62, 0x6f, 0x78, 0x65, 0x73, 0x20, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x20, 0x69, + 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x0a, 0x0a, 0x0c, 0x0a, + 0x05, 0x04, 0x02, 0x02, 0x02, 0x04, 0x12, 0x03, 0x35, 0x02, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, + 0x02, 0x02, 0x02, 0x06, 0x12, 0x03, 0x35, 0x0b, 0x10, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, + 0x02, 0x01, 0x12, 0x03, 0x35, 0x11, 0x20, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x02, 0x03, + 0x12, 0x03, 0x35, 0x23, 0x24, 0x0a, 0x31, 0x0a, 0x04, 0x04, 0x02, 0x02, 0x03, 0x12, 0x03, 0x37, + 0x02, 0x3a, 0x1a, 0x24, 0x20, 0x54, 0x68, 0x65, 0x20, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, + 0x61, 0x20, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x03, + 0x04, 0x12, 0x03, 0x37, 0x02, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x03, 0x06, 0x12, + 0x03, 0x37, 0x0b, 0x1e, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x03, 0x01, 0x12, 0x03, 0x37, + 0x1f, 0x35, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x03, 0x03, 0x12, 0x03, 0x37, 0x38, 0x39, + 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, ]; include!("xmtp.mls.message_contents.serde.rs"); // @@protoc_insertion_point(module) \ No newline at end of file From e498595c07726f0d2c1e4dfc492383a008e026ba Mon Sep 17 00:00:00 2001 From: Dakota Brink <779390+codabrink@users.noreply.github.com> Date: Mon, 25 Nov 2024 14:52:02 -0500 Subject: [PATCH 07/46] fix cargo deny (#1337) --- Cargo.lock | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 71c4eae62..63d6dbd5e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2640,7 +2640,7 @@ dependencies = [ "http 1.1.0", "hyper 1.5.0", "hyper-util", - "rustls 0.23.17", + "rustls 0.23.18", "rustls-pki-types", "tokio", "tokio-rustls 0.26.0", @@ -4873,9 +4873,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.17" +version = "0.23.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f1a745511c54ba6d4465e8d5dfbd81b45791756de28d4981af70d6dca128f1e" +checksum = "9c9cc1d47e243d655ace55ed38201c19ae02c148ae56412ab8750e8f0166ab7f" dependencies = [ "log", "once_cell", @@ -5861,7 +5861,7 @@ version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4" dependencies = [ - "rustls 0.23.17", + "rustls 0.23.18", "rustls-pki-types", "tokio", ] @@ -6462,9 +6462,9 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "url" -version = "2.5.3" +version = "2.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d157f1b96d14500ffdc1f10ba712e780825526c03d9a49b4d0324b0d9113ada" +checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" dependencies = [ "form_urlencoded", "idna", From faae68c9fec4ebf33ca6169a9028d50e7c852d60 Mon Sep 17 00:00:00 2001 From: Dakota Brink <779390+codabrink@users.noreply.github.com> Date: Mon, 25 Nov 2024 15:49:09 -0500 Subject: [PATCH 08/46] Check if address/installation is in association state (#1336) * unintentional rabbit hole * wip * cleanup * lint * lint * cleanup * more lint * take an inbox_id param * lint --- bindings_ffi/src/mls.rs | 5 +- bindings_node/src/client.rs | 44 ++++++++++++++- xmtp_debug/src/app/generate/identity.rs | 4 +- xmtp_debug/src/app/inspect.rs | 2 +- xmtp_id/src/associations/association_log.rs | 8 +-- xmtp_id/src/associations/state.rs | 4 +- xmtp_mls/src/client.rs | 11 +--- xmtp_mls/src/groups/members.rs | 2 +- xmtp_mls/src/groups/mod.rs | 4 +- xmtp_mls/src/groups/scoped_client.rs | 40 ++++++------- xmtp_mls/src/groups/validated_commit.rs | 6 +- xmtp_mls/src/identity_updates.rs | 62 ++++++++++----------- 12 files changed, 112 insertions(+), 80 deletions(-) diff --git a/bindings_ffi/src/mls.rs b/bindings_ffi/src/mls.rs index f8c9ab19a..3404de771 100644 --- a/bindings_ffi/src/mls.rs +++ b/bindings_ffi/src/mls.rs @@ -330,7 +330,10 @@ impl FfiXmtpClient { ) -> Result, GenericError> { let state = self .inner_client - .inbox_addresses(refresh_from_network, inbox_ids) + .inbox_addresses( + refresh_from_network, + inbox_ids.iter().map(String::as_str).collect(), + ) .await?; Ok(state.into_iter().map(Into::into).collect()) } diff --git a/bindings_node/src/client.rs b/bindings_node/src/client.rs index 2ca5f5c9f..83022d492 100644 --- a/bindings_node/src/client.rs +++ b/bindings_node/src/client.rs @@ -13,6 +13,7 @@ use tracing_subscriber::{fmt, prelude::*}; pub use xmtp_api_grpc::grpc_api_helper::Client as TonicApiClient; use xmtp_cryptography::signature::ed25519_public_key_to_address; use xmtp_id::associations::builder::SignatureRequest; +use xmtp_id::associations::MemberIdentifier; use xmtp_mls::builder::ClientBuilder; use xmtp_mls::groups::scoped_client::LocalScopedGroupClient; use xmtp_mls::identity::IdentityStrategy; @@ -292,9 +293,50 @@ impl Client { ) -> Result> { let state = self .inner_client - .inbox_addresses(refresh_from_network, inbox_ids) + .inbox_addresses( + refresh_from_network, + inbox_ids.iter().map(String::as_str).collect(), + ) .await .map_err(ErrorWrapper::from)?; Ok(state.into_iter().map(Into::into).collect()) } + + #[napi] + pub async fn is_address_authorized(&self, inbox_id: String, address: String) -> Result { + self + .is_member_of_association_state(&inbox_id, &MemberIdentifier::Address(address)) + .await + } + + #[napi] + pub async fn is_installation_authorized( + &self, + inbox_id: String, + installation: Vec, + ) -> Result { + self + .is_member_of_association_state(&inbox_id, &MemberIdentifier::Installation(installation)) + .await + } + + async fn is_member_of_association_state( + &self, + inbox_id: &str, + identifier: &MemberIdentifier, + ) -> Result { + let client = &self.inner_client; + let conn = self + .inner_client + .store() + .conn() + .map_err(ErrorWrapper::from)?; + + let association_state = client + .get_association_state(&conn, inbox_id, None) + .await + .map_err(ErrorWrapper::from)?; + + Ok(association_state.get(identifier).is_some()) + } } diff --git a/xmtp_debug/src/app/generate/identity.rs b/xmtp_debug/src/app/generate/identity.rs index 01df562d6..838d129c3 100644 --- a/xmtp_debug/src/app/generate/identity.rs +++ b/xmtp_debug/src/app/generate/identity.rs @@ -47,7 +47,7 @@ impl GenerateIdentity { let first = identities.next().ok_or(eyre::eyre!("Does not exist"))??; let state = client - .get_latest_association_state(&connection, hex::encode(first.inbox_id)) + .get_latest_association_state(&connection, &hex::encode(first.inbox_id)) .await?; info!("Found generated identities, checking for registration on backend...",); // we assume that if the first identity is registered, they all are @@ -114,7 +114,7 @@ impl GenerateIdentity { let future = |inbox_id: [u8; 32]| async move { let id = hex::encode(inbox_id); trace!(inbox_id = id, "getting association state"); - let state = tmp.get_latest_association_state(&conn, id).await?; + let state = tmp.get_latest_association_state(&conn, &id).await?; bar_ref.inc(1); Ok(state) }; diff --git a/xmtp_debug/src/app/inspect.rs b/xmtp_debug/src/app/inspect.rs index bf500632e..b09f68ba0 100644 --- a/xmtp_debug/src/app/inspect.rs +++ b/xmtp_debug/src/app/inspect.rs @@ -38,7 +38,7 @@ impl Inspect { match kind { Associations => { let state = client - .get_latest_association_state(&conn, hex::encode(*inbox_id)) + .get_latest_association_state(&conn, &hex::encode(*inbox_id)) .await?; info!( inbox_id = state.inbox_id(), diff --git a/xmtp_id/src/associations/association_log.rs b/xmtp_id/src/associations/association_log.rs index 6588b3551..2160314a9 100644 --- a/xmtp_id/src/associations/association_log.rs +++ b/xmtp_id/src/associations/association_log.rs @@ -160,7 +160,7 @@ impl IdentityAction for AddAssociation { let existing_entity_id = match existing_member { // If there is an existing member of the XID, use that member's ID - Some(member) => member.identifier, + Some(member) => member.identifier.clone(), None => { // Get the recovery address from the state as a MemberIdentifier let recovery_identifier: MemberIdentifier = @@ -228,7 +228,7 @@ impl IdentityAction for RevokeAssociation { // Ensure that the new signature is on the same chain as the signature to create the account let existing_member = existing_state.get(&self.recovery_address_signature.signer); if let Some(member) = existing_member { - verify_chain_id_matches(&member, &self.recovery_address_signature)?; + verify_chain_id_matches(member, &self.recovery_address_signature)?; } if is_legacy_signature(&self.recovery_address_signature) { @@ -289,7 +289,7 @@ impl IdentityAction for ChangeRecoveryAddress { let existing_member = existing_state.get(&self.recovery_address_signature.signer); if let Some(member) = existing_member { - verify_chain_id_matches(&member, &self.recovery_address_signature)?; + verify_chain_id_matches(member, &self.recovery_address_signature)?; } if is_legacy_signature(&self.recovery_address_signature) { @@ -459,7 +459,7 @@ fn verify_chain_id_matches( member: &Member, signature: &VerifiedSignature, ) -> Result<(), AssociationError> { - if member.added_on_chain_id.ne(&signature.chain_id) { + if member.added_on_chain_id != signature.chain_id { return Err(AssociationError::ChainIdMismatch( member.added_on_chain_id.unwrap_or(0), signature.chain_id.unwrap_or(0), diff --git a/xmtp_id/src/associations/state.rs b/xmtp_id/src/associations/state.rs index a086945bb..a9339be88 100644 --- a/xmtp_id/src/associations/state.rs +++ b/xmtp_id/src/associations/state.rs @@ -74,8 +74,8 @@ impl AssociationState { new_state } - pub fn get(&self, identifier: &MemberIdentifier) -> Option { - self.members.get(identifier).cloned() + pub fn get(&self, identifier: &MemberIdentifier) -> Option<&Member> { + self.members.get(identifier) } pub fn add_seen_signatures(&self, signatures: Vec>) -> Self { diff --git a/xmtp_mls/src/client.rs b/xmtp_mls/src/client.rs index d025705d9..a33a24462 100644 --- a/xmtp_mls/src/client.rs +++ b/xmtp_mls/src/client.rs @@ -365,19 +365,14 @@ where } /// Get the [`AssociationState`] for each `inbox_id` - pub async fn inbox_addresses>( + pub async fn inbox_addresses<'a>( &self, refresh_from_network: bool, - inbox_ids: Vec, + inbox_ids: Vec>, ) -> Result, ClientError> { let conn = self.store().conn()?; if refresh_from_network { - load_identity_updates( - &self.api_client, - &conn, - &inbox_ids.iter().map(|s| s.as_ref()).collect::>(), - ) - .await?; + load_identity_updates(&self.api_client, &conn, &inbox_ids).await?; } let state = self .batch_get_association_state( diff --git a/xmtp_mls/src/groups/members.rs b/xmtp_mls/src/groups/members.rs index 71a4595c2..5ca53a40a 100644 --- a/xmtp_mls/src/groups/members.rs +++ b/xmtp_mls/src/groups/members.rs @@ -66,7 +66,7 @@ where { return None; } - Some((id.clone(), Some(*sequence))) + Some((id.as_str(), Some(*sequence))) }) .collect(); diff --git a/xmtp_mls/src/groups/mod.rs b/xmtp_mls/src/groups/mod.rs index 34232239b..f6de6dd48 100644 --- a/xmtp_mls/src/groups/mod.rs +++ b/xmtp_mls/src/groups/mod.rs @@ -1493,9 +1493,9 @@ async fn validate_initial_group_membership( let futures: Vec<_> = membership .members - .into_iter() + .iter() .map(|(inbox_id, sequence_id)| { - client.get_association_state(conn, inbox_id, Some(sequence_id as i64)) + client.get_association_state(conn, inbox_id, Some(*sequence_id as i64)) }) .collect(); diff --git a/xmtp_mls/src/groups/scoped_client.rs b/xmtp_mls/src/groups/scoped_client.rs index 49f25c319..75700d432 100644 --- a/xmtp_mls/src/groups/scoped_client.rs +++ b/xmtp_mls/src/groups/scoped_client.rs @@ -62,17 +62,17 @@ pub trait LocalScopedGroupClient: Send + Sync + Sized { installation_ids: Vec>, ) -> Result, ClientError>; - async fn get_association_state( + async fn get_association_state<'a>( &self, conn: &DbConnection, - inbox_id: String, + inbox_id: InboxIdRef<'a>, to_sequence_id: Option, ) -> Result; - async fn batch_get_association_state( + async fn batch_get_association_state<'a>( &self, conn: &DbConnection, - identifiers: &[(String, Option)], + identifiers: &[(InboxIdRef<'a>, Option)], ) -> Result, ClientError>; async fn query_group_messages( @@ -126,17 +126,17 @@ pub trait ScopedGroupClient: Sized { installation_ids: Vec>, ) -> Result, ClientError>; - async fn get_association_state( + async fn get_association_state<'a>( &self, conn: &DbConnection, - inbox_id: String, + inbox_id: InboxIdRef<'a>, to_sequence_id: Option, ) -> Result; - async fn batch_get_association_state( + async fn batch_get_association_state<'a>( &self, conn: &DbConnection, - identifiers: &[(String, Option)], + identifiers: &[(InboxIdRef<'a>, Option)], ) -> Result, ClientError>; async fn query_group_messages( @@ -201,10 +201,10 @@ where .await } - async fn get_association_state( + async fn get_association_state<'a>( &self, conn: &DbConnection, - inbox_id: String, + inbox_id: InboxIdRef<'a>, to_sequence_id: Option, ) -> Result { crate::Client::::get_association_state( @@ -216,10 +216,10 @@ where .await } - async fn batch_get_association_state( + async fn batch_get_association_state<'a>( &self, conn: &DbConnection, - identifiers: &[(String, Option)], + identifiers: &[(InboxIdRef<'a>, Option)], ) -> Result, ClientError> { crate::Client::::batch_get_association_state(self, conn, identifiers) .await @@ -298,10 +298,10 @@ where .await } - async fn get_association_state( + async fn get_association_state<'a>( &self, conn: &DbConnection, - inbox_id: String, + inbox_id: InboxIdRef<'a>, to_sequence_id: Option, ) -> Result { (**self) @@ -309,10 +309,10 @@ where .await } - async fn batch_get_association_state( + async fn batch_get_association_state<'a>( &self, conn: &DbConnection, - identifiers: &[(String, Option)], + identifiers: &[(InboxIdRef<'a>, Option)], ) -> Result, ClientError> { (**self) .batch_get_association_state(conn, identifiers) @@ -392,10 +392,10 @@ where .await } - async fn get_association_state( + async fn get_association_state<'a>( &self, conn: &DbConnection, - inbox_id: String, + inbox_id: InboxIdRef<'a>, to_sequence_id: Option, ) -> Result { (**self) @@ -403,10 +403,10 @@ where .await } - async fn batch_get_association_state( + async fn batch_get_association_state<'a>( &self, conn: &DbConnection, - identifiers: &[(String, Option)], + identifiers: &[(InboxIdRef<'a>, Option)], ) -> Result, ClientError> { (**self) .batch_get_association_state(conn, identifiers) diff --git a/xmtp_mls/src/groups/validated_commit.rs b/xmtp_mls/src/groups/validated_commit.rs index 567603a3d..45cb5cc75 100644 --- a/xmtp_mls/src/groups/validated_commit.rs +++ b/xmtp_mls/src/groups/validated_commit.rs @@ -303,11 +303,7 @@ impl ValidatedCommit { .ok_or(CommitValidationError::SubjectDoesNotExist)?; let inbox_state = client - .get_association_state( - conn, - participant.inbox_id.clone(), - Some(*to_sequence_id as i64), - ) + .get_association_state(conn, &participant.inbox_id, Some(*to_sequence_id as i64)) .await .map_err(InstallationDiffError::from)?; diff --git a/xmtp_mls/src/identity_updates.rs b/xmtp_mls/src/identity_updates.rs index 23d08e69a..53d938a78 100644 --- a/xmtp_mls/src/identity_updates.rs +++ b/xmtp_mls/src/identity_updates.rs @@ -93,10 +93,10 @@ where /// Get the association state for all provided `inbox_id`/optional `sequence_id` tuples, using the cache when available /// If the association state is not available in the cache, this falls back to reconstructing the association state /// from Identity Updates in the network. - pub async fn batch_get_association_state>( + pub async fn batch_get_association_state( &self, conn: &DbConnection, - identifiers: &[(InboxId, Option)], + identifiers: &[(InboxIdRef<'a>, Option)], ) -> Result, ClientError> { let association_states = try_join_all( identifiers @@ -112,25 +112,24 @@ where } /// Get the latest association state available on the network for the given `inbox_id` - pub async fn get_latest_association_state>( + pub async fn get_latest_association_state( &self, conn: &DbConnection, - inbox_id: InboxId, + inbox_id: InboxIdRef<'a>, ) -> Result { - load_identity_updates(&self.api_client, conn, &[inbox_id.as_ref()]).await?; + load_identity_updates(&self.api_client, conn, &[inbox_id]).await?; self.get_association_state(conn, inbox_id, None).await } /// Get the association state for a given inbox_id up to the (and inclusive of) the `to_sequence_id` /// If no `to_sequence_id` is provided, use the latest value in the database - pub async fn get_association_state>( + pub async fn get_association_state( &self, conn: &DbConnection, - inbox_id: InboxId, + inbox_id: InboxIdRef<'a>, to_sequence_id: Option, ) -> Result { - let inbox_id = inbox_id.as_ref(); let updates = conn.get_identity_updates(inbox_id, None, to_sequence_id)?; let last_sequence_id = updates .last() @@ -168,35 +167,35 @@ where /// Calculate the changes between the `starting_sequence_id` and `ending_sequence_id` for the /// provided `inbox_id` - pub(crate) async fn get_association_state_diff>( + pub(crate) async fn get_association_state_diff( &self, conn: &DbConnection, - inbox_id: InboxId, + inbox_id: InboxIdRef<'a>, starting_sequence_id: Option, ending_sequence_id: Option, ) -> Result { tracing::debug!( "Computing diff for {:?} from {:?} to {:?}", - inbox_id.as_ref(), + inbox_id, starting_sequence_id, ending_sequence_id ); // If no starting sequence ID, get all updates from the beginning of the inbox's history up to the ending sequence ID if starting_sequence_id.is_none() { return Ok(self - .get_association_state(conn, inbox_id.as_ref(), ending_sequence_id) + .get_association_state(conn, inbox_id, ending_sequence_id) .await? .as_diff()); } // Get the initial state to compare against let initial_state = self - .get_association_state(conn, inbox_id.as_ref(), starting_sequence_id) + .get_association_state(conn, inbox_id, starting_sequence_id) .await?; // Get any identity updates that need to be applied let incremental_updates = - conn.get_identity_updates(inbox_id.as_ref(), starting_sequence_id, ending_sequence_id)?; + conn.get_identity_updates(inbox_id, starting_sequence_id, ending_sequence_id)?; let last_sequence_id = incremental_updates.last().map(|update| update.sequence_id); if ending_sequence_id.is_some() @@ -228,7 +227,7 @@ where if let Some(last_sequence_id) = last_sequence_id { StoredAssociationState::write_to_cache( conn, - inbox_id.as_ref().to_string(), + inbox_id.to_string(), last_sequence_id, final_state.clone(), )?; @@ -314,7 +313,7 @@ where let current_state = retry_async!( Retry::default(), (async { - self.get_association_state(&self.store().conn()?, &inbox_id, None) + self.get_association_state(&self.store().conn()?, inbox_id, None) .await }) )?; @@ -340,7 +339,7 @@ where let current_state = retry_async!( Retry::default(), (async { - self.get_association_state(&self.store().conn()?, &inbox_id, None) + self.get_association_state(&self.store().conn()?, inbox_id, None) .await }) )?; @@ -445,7 +444,7 @@ where let state_diff = self .get_association_state_diff( conn, - inbox_id, + inbox_id.as_str(), starting_sequence_id, new_group_membership.get(inbox_id).map(|i| *i as i64), ) @@ -555,14 +554,14 @@ pub(crate) mod tests { async fn get_association_state( client: &Client, - inbox_id: String, + inbox_id: &str, ) -> AssociationState where ApiClient: XmtpApi, Verifier: SmartContractSignatureVerifier, { let conn = client.store().conn().unwrap(); - load_identity_updates(&client.api_client, &conn, &[inbox_id.as_str()]) + load_identity_updates(&client.api_client, &conn, &[inbox_id]) .await .unwrap(); @@ -600,7 +599,7 @@ pub(crate) mod tests { .await .unwrap(); - let association_state = get_association_state(&client, inbox_id.to_string()).await; + let association_state = get_association_state(&client, &inbox_id).await; assert_eq!(association_state.members().len(), 2); assert_eq!(association_state.recovery_address(), &wallet_address); @@ -628,7 +627,7 @@ pub(crate) mod tests { .await .unwrap(); - let association_state = get_association_state(&client, client.inbox_id().to_string()).await; + let association_state = get_association_state(&client, client.inbox_id()).await; let members = association_state.members_by_parent(&MemberIdentifier::Address(wallet_address.clone())); @@ -654,12 +653,12 @@ pub(crate) mod tests { let client = ClientBuilder::new_test_client(&wallet).await; let inbox_id = client.inbox_id(); - get_association_state(&client, inbox_id.to_string()).await; + get_association_state(&client, inbox_id).await; assert_logged!("Loaded association", 0); assert_logged!("Wrote association", 1); - let association_state = get_association_state(&client, inbox_id.to_string()).await; + let association_state = get_association_state(&client, inbox_id).await; assert_eq!(association_state.members().len(), 2); assert_eq!(association_state.recovery_address(), &wallet_address); @@ -682,12 +681,12 @@ pub(crate) mod tests { .await .unwrap(); - get_association_state(&client, inbox_id.to_string()).await; + get_association_state(&client, inbox_id).await; assert_logged!("Loaded association", 1); assert_logged!("Wrote association", 2); - let association_state = get_association_state(&client, inbox_id.to_string()).await; + let association_state = get_association_state(&client, inbox_id).await; assert_logged!("Loaded association", 2); assert_logged!("Wrote association", 2); @@ -843,8 +842,7 @@ pub(crate) mod tests { .await .unwrap(); - let association_state_after_add = - get_association_state(&client, client.inbox_id().to_string()).await; + let association_state_after_add = get_association_state(&client, client.inbox_id()).await; assert_eq!(association_state_after_add.account_addresses().len(), 2); // Make sure the inbox ID is correctly registered @@ -870,7 +868,7 @@ pub(crate) mod tests { // Make sure that the association state has removed the second wallet let association_state_after_revoke = - get_association_state(&client, client.inbox_id().to_string()).await; + get_association_state(&client, client.inbox_id()).await; assert_eq!(association_state_after_revoke.account_addresses().len(), 1); // Make sure the inbox ID is correctly unregistered @@ -889,8 +887,7 @@ pub(crate) mod tests { let client1: FullXmtpClient = ClientBuilder::new_test_client(&wallet).await; let client2: FullXmtpClient = ClientBuilder::new_test_client(&wallet).await; - let association_state = - get_association_state(&client1, client1.inbox_id().to_string()).await; + let association_state = get_association_state(&client1, client1.inbox_id()).await; // Ensure there are two installations on the inbox assert_eq!(association_state.installation_ids().len(), 2); @@ -906,8 +903,7 @@ pub(crate) mod tests { .unwrap(); // Make sure there is only one installation on the inbox - let association_state = - get_association_state(&client1, client1.inbox_id().to_string()).await; + let association_state = get_association_state(&client1, client1.inbox_id()).await; assert_eq!(association_state.installation_ids().len(), 1); } } From 0c1ae68801003f4e5c92c20f111ded9ff8e26ba5 Mon Sep 17 00:00:00 2001 From: Dakota Brink <779390+codabrink@users.noreply.github.com> Date: Mon, 25 Nov 2024 16:46:12 -0500 Subject: [PATCH 09/46] bump node version (#1338) --- bindings_node/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bindings_node/package.json b/bindings_node/package.json index 83b153584..0ee3d5940 100644 --- a/bindings_node/package.json +++ b/bindings_node/package.json @@ -1,6 +1,6 @@ { "name": "@xmtp/node-bindings", - "version": "0.0.22", + "version": "0.0.23", "repository": { "type": "git", "url": "git+https://git@github.com/xmtp/libxmtp.git", From 1413c38f72aa092196f224b7e453b729b0b67af7 Mon Sep 17 00:00:00 2001 From: Dakota Brink <779390+codabrink@users.noreply.github.com> Date: Tue, 26 Nov 2024 10:22:58 -0500 Subject: [PATCH 10/46] use a Uint8Array instead of a vec (#1341) --- bindings_node/package.json | 2 +- bindings_node/src/client.rs | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/bindings_node/package.json b/bindings_node/package.json index 0ee3d5940..a1de4326c 100644 --- a/bindings_node/package.json +++ b/bindings_node/package.json @@ -1,6 +1,6 @@ { "name": "@xmtp/node-bindings", - "version": "0.0.23", + "version": "0.0.24", "repository": { "type": "git", "url": "git+https://git@github.com/xmtp/libxmtp.git", diff --git a/bindings_node/src/client.rs b/bindings_node/src/client.rs index 83022d492..32740d90c 100644 --- a/bindings_node/src/client.rs +++ b/bindings_node/src/client.rs @@ -313,10 +313,13 @@ impl Client { pub async fn is_installation_authorized( &self, inbox_id: String, - installation: Vec, + installation_id: Uint8Array, ) -> Result { self - .is_member_of_association_state(&inbox_id, &MemberIdentifier::Installation(installation)) + .is_member_of_association_state( + &inbox_id, + &MemberIdentifier::Installation(installation_id.to_vec()), + ) .await } From 14df3bc7537df5c6bbf98d53212405cfb6756246 Mon Sep 17 00:00:00 2001 From: Naomi Plasterer Date: Tue, 26 Nov 2024 09:04:38 -0800 Subject: [PATCH 11/46] Sync all conversations syncs all (#1340) * Revert "Live Consent Sync (#1234)" This reverts commit 0b0bcdebc982f5aedff99b851d64b54eb0f5193f. * make sync all sync all * do the web side * clean up the logic * cargo fmt --- bindings_ffi/src/mls.rs | 14 +++++--------- bindings_node/src/conversations.rs | 9 ++++++--- bindings_wasm/src/conversations.rs | 13 ++++++++++--- xmtp_mls/src/client.rs | 13 +++++++++++++ 4 files changed, 34 insertions(+), 15 deletions(-) diff --git a/bindings_ffi/src/mls.rs b/bindings_ffi/src/mls.rs index 3404de771..1261d2ef9 100644 --- a/bindings_ffi/src/mls.rs +++ b/bindings_ffi/src/mls.rs @@ -917,19 +917,15 @@ impl FfiConversations { pub async fn sync_all_conversations(&self) -> Result { let inner = self.inner_client.as_ref(); - let groups = inner.find_groups(GroupQueryArgs::default().include_sync_groups())?; + let conn = inner.store().conn()?; - log::info!( - "groups for client inbox id {:?}: {:?}", - self.inner_client.inbox_id(), - groups.len() - ); + let num_groups_synced: usize = inner.sync_all_welcomes_and_groups(&conn).await?; - let num_groups_synced: usize = inner.sync_all_groups(groups).await?; - // Uniffi does not work with usize, so we need to convert to u32 + // Convert usize to u32 for compatibility with Uniffi let num_groups_synced: u32 = num_groups_synced .try_into() .map_err(|_| GenericError::FailedToConvertToU32)?; + Ok(num_groups_synced) } @@ -2569,7 +2565,7 @@ mod tests { .unwrap(); } - bo.conversations().sync().await.unwrap(); + bo.conversations().sync_all_conversations().await.unwrap(); let alix_groups = alix .conversations() .list(FfiListConversationsOptions::default()) diff --git a/bindings_node/src/conversations.rs b/bindings_node/src/conversations.rs index 24b618a40..d6a449e70 100644 --- a/bindings_node/src/conversations.rs +++ b/bindings_node/src/conversations.rs @@ -250,15 +250,18 @@ impl Conversations { #[napi] pub async fn sync_all_conversations(&self) -> Result { - let groups = self + let conn = self .inner_client - .find_groups(GroupQueryArgs::default()) + .store() + .conn() .map_err(ErrorWrapper::from)?; + let num_groups_synced = self .inner_client - .sync_all_groups(groups) + .sync_all_welcomes_and_groups(&conn) .await .map_err(ErrorWrapper::from)?; + Ok(num_groups_synced) } diff --git a/bindings_wasm/src/conversations.rs b/bindings_wasm/src/conversations.rs index 07931f5b4..c33cd901d 100644 --- a/bindings_wasm/src/conversations.rs +++ b/bindings_wasm/src/conversations.rs @@ -285,11 +285,18 @@ impl Conversations { #[wasm_bindgen(js_name = syncAllConversations)] pub async fn sync_all_conversations(&self) -> Result { - let groups = self + let conn = self + .inner_client + .store() + .conn() + .map_err(|e| JsError::new(format!("{}", e).as_str()))?; + + let num_groups_synced = self .inner_client - .find_groups(GroupQueryArgs::default()) + .sync_all_welcomes_and_groups(&conn) + .await .map_err(|e| JsError::new(format!("{}", e).as_str()))?; - let num_groups_synced = self.inner_client.sync_all_groups(groups).await?; + Ok(num_groups_synced) } diff --git a/xmtp_mls/src/client.rs b/xmtp_mls/src/client.rs index a33a24462..d680e3018 100644 --- a/xmtp_mls/src/client.rs +++ b/xmtp_mls/src/client.rs @@ -842,6 +842,19 @@ where Ok(active_group_count.load(Ordering::SeqCst)) } + /// Sync all unread welcome messages and then sync all groups. + /// Returns the total number of active groups synced. + pub async fn sync_all_welcomes_and_groups( + &self, + conn: &DbConnection, + ) -> Result { + self.sync_welcomes(conn).await?; + let groups = self.find_groups(GroupQueryArgs::default().include_sync_groups())?; + let active_groups_count = self.sync_all_groups(groups).await?; + + Ok(active_groups_count) + } + /** * Validates a credential against the given installation public key * From 8d637a981292d8943cc0f338171dccca7eb761b9 Mon Sep 17 00:00:00 2001 From: Andrew Plaza Date: Tue, 26 Nov 2024 12:22:59 -0500 Subject: [PATCH 12/46] Node Streams Debugging + Logging (#1342) * more logs around streaming and api queries * fix node streams * fix IdentityStrategy and lints --- Cargo.lock | 1 + bindings_ffi/src/mls.rs | 2 +- bindings_node/Cargo.toml | 2 + bindings_node/src/client.rs | 2 +- bindings_node/src/conversations.rs | 10 +++++ bindings_node/src/streams.rs | 8 ++++ bindings_node/test/Client.test.ts | 40 ++++++++++++++++- bindings_node/test/helpers.ts | 6 +++ bindings_wasm/src/client.rs | 2 +- examples/cli/cli-client.rs | 2 +- xmtp_debug/src/app/clients.rs | 2 +- xmtp_mls/src/api/mls.rs | 22 +++++++++ xmtp_mls/src/api/mod.rs | 10 ++++- xmtp_mls/src/builder.rs | 42 ++++++++--------- xmtp_mls/src/client.rs | 4 +- xmtp_mls/src/groups/intents.rs | 1 + xmtp_mls/src/groups/mod.rs | 1 + xmtp_mls/src/groups/subscriptions.rs | 8 +++- xmtp_mls/src/identity.rs | 45 ++++++++++++++++--- xmtp_mls/src/storage/encrypted_store/group.rs | 12 +++++ xmtp_mls/src/subscriptions.rs | 17 +++++-- xmtp_mls/src/utils/test/mod.rs | 4 +- 22 files changed, 201 insertions(+), 42 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 63d6dbd5e..c6e3452c5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -431,6 +431,7 @@ dependencies = [ name = "bindings_node" version = "0.1.0" dependencies = [ + "futures", "hex", "napi", "napi-build", diff --git a/bindings_ffi/src/mls.rs b/bindings_ffi/src/mls.rs index 1261d2ef9..1dc95f2a7 100644 --- a/bindings_ffi/src/mls.rs +++ b/bindings_ffi/src/mls.rs @@ -112,7 +112,7 @@ pub async fn create_client( None => EncryptedMessageStore::new_unencrypted(storage_option).await?, }; log::info!("Creating XMTP client"); - let identity_strategy = IdentityStrategy::CreateIfNotFound( + let identity_strategy = IdentityStrategy::new( inbox_id.clone(), account_address.clone(), nonce, diff --git a/bindings_node/Cargo.toml b/bindings_node/Cargo.toml index e3beae204..8cc4ee49e 100644 --- a/bindings_node/Cargo.toml +++ b/bindings_node/Cargo.toml @@ -10,6 +10,7 @@ crate-type = ["cdylib"] # Default enable napi4 feature, see https://nodejs.org/api/n-api.html#node-api-version-matrix hex.workspace = true napi = { version = "2.12.2", default-features = false, features = [ + "napi4", "napi6", "async", ] } @@ -23,6 +24,7 @@ xmtp_cryptography = { path = "../xmtp_cryptography" } xmtp_id = { path = "../xmtp_id" } xmtp_mls = { path = "../xmtp_mls" } xmtp_proto = { path = "../xmtp_proto", features = ["proto_full"] } +futures.workspace = true [build-dependencies] napi-build = "2.0.1" diff --git a/bindings_node/src/client.rs b/bindings_node/src/client.rs index 32740d90c..d554274f0 100644 --- a/bindings_node/src/client.rs +++ b/bindings_node/src/client.rs @@ -155,7 +155,7 @@ pub async fn create_client( .map_err(|_| Error::from_reason("Error creating unencrypted message store"))?, }; - let identity_strategy = IdentityStrategy::CreateIfNotFound( + let identity_strategy = IdentityStrategy::new( inbox_id.clone(), account_address.clone().to_lowercase(), // this is a temporary solution diff --git a/bindings_node/src/conversations.rs b/bindings_node/src/conversations.rs index d6a449e70..fb35a4d83 100644 --- a/bindings_node/src/conversations.rs +++ b/bindings_node/src/conversations.rs @@ -345,12 +345,22 @@ impl Conversations { callback: JsFunction, conversation_type: Option, ) -> Result { + tracing::trace!( + inbox_id = self.inner_client.inbox_id(), + conversation_type = ?conversation_type, + ); let tsfn: ThreadsafeFunction = callback.create_threadsafe_function(0, |ctx| Ok(vec![ctx.value]))?; + let inbox_id = self.inner_client.inbox_id().to_string(); let stream_closer = RustXmtpClient::stream_all_messages_with_callback( self.inner_client.clone(), conversation_type.map(Into::into), move |message| { + tracing::trace!( + inbox_id, + conversation_type = ?conversation_type, + "[received] calling tsfn callback" + ); tsfn.call( message .map(Into::into) diff --git a/bindings_node/src/streams.rs b/bindings_node/src/streams.rs index 1094bf54d..782f85edc 100644 --- a/bindings_node/src/streams.rs +++ b/bindings_node/src/streams.rs @@ -63,6 +63,14 @@ impl StreamCloser { } } + #[napi] + pub async fn wait_for_ready(&self) -> Result<(), Error> { + let mut stream_handle = self.handle.lock().await; + futures::future::OptionFuture::from((*stream_handle).as_mut().map(|s| s.wait_for_ready())) + .await; + Ok(()) + } + /// Checks if this stream is closed #[napi] pub fn is_closed(&self) -> bool { diff --git a/bindings_node/test/Client.test.ts b/bindings_node/test/Client.test.ts index ea84ea155..ee10c30bc 100644 --- a/bindings_node/test/Client.test.ts +++ b/bindings_node/test/Client.test.ts @@ -1,7 +1,13 @@ import { v4 } from 'uuid' import { toBytes } from 'viem' import { describe, expect, it } from 'vitest' -import { createClient, createRegisteredClient, createUser } from '@test/helpers' +import { + createClient, + createRegisteredClient, + createUser, + encodeTextMessage, + sleep, +} from '@test/helpers' import { ConsentEntityType, ConsentState, @@ -250,3 +256,35 @@ describe('Client', () => { ).toThrow() }) }) + +describe('Streams', () => { + it('should stream all messages', async () => { + const user = createUser() + const client1 = await createRegisteredClient(user) + + const user2 = createUser() + const client2 = await createRegisteredClient(user2) + + const group = await client1 + .conversations() + .createGroup([user2.account.address]) + + await client2.conversations().sync() + const group2 = client2.conversations().findGroupById(group.id()) + + let messages = new Array() + client2.conversations().syncAllConversations() + let stream = client2.conversations().streamAllMessages((msg) => { + console.log('Message', msg) + messages.push(msg) + }) + await stream.waitForReady() + group.send(encodeTextMessage('Test1')) + group.send(encodeTextMessage('Test2')) + group.send(encodeTextMessage('Test3')) + group.send(encodeTextMessage('Test4')) + await sleep(1000) + await stream.endAndWait() + expect(messages.length).toBe(4) + }) +}) diff --git a/bindings_node/test/helpers.ts b/bindings_node/test/helpers.ts index 1d3260925..fc44c2229 100644 --- a/bindings_node/test/helpers.ts +++ b/bindings_node/test/helpers.ts @@ -80,3 +80,9 @@ export const encodeTextMessage = (text: string) => { content: new TextEncoder().encode(text), } } + +export function sleep(ms) { + return new Promise((resolve) => { + setTimeout(resolve, ms) + }) +} diff --git a/bindings_wasm/src/client.rs b/bindings_wasm/src/client.rs index be29aea38..1db20bf67 100644 --- a/bindings_wasm/src/client.rs +++ b/bindings_wasm/src/client.rs @@ -153,7 +153,7 @@ pub async fn create_client( .map_err(|_| JsError::new("Error creating unencrypted message store"))?, }; - let identity_strategy = IdentityStrategy::CreateIfNotFound( + let identity_strategy = IdentityStrategy::new( inbox_id.clone(), account_address.clone().to_lowercase(), // this is a temporary solution diff --git a/examples/cli/cli-client.rs b/examples/cli/cli-client.rs index 0448e03b4..9e28e9cc8 100755 --- a/examples/cli/cli-client.rs +++ b/examples/cli/cli-client.rs @@ -535,7 +535,7 @@ where let inbox_id = generate_inbox_id(&w.get_address(), &nonce)?; let client = create_client( cli, - IdentityStrategy::CreateIfNotFound(inbox_id, w.get_address(), nonce, None), + IdentityStrategy::new(inbox_id, w.get_address(), nonce, None), client, ) .await?; diff --git a/xmtp_debug/src/app/clients.rs b/xmtp_debug/src/app/clients.rs index 6ed848eeb..fe07c5a9c 100644 --- a/xmtp_debug/src/app/clients.rs +++ b/xmtp_debug/src/app/clients.rs @@ -72,7 +72,7 @@ async fn new_client_inner( dir.join(db_name) }; - let client = crate::DbgClient::builder(IdentityStrategy::CreateIfNotFound( + let client = crate::DbgClient::builder(IdentityStrategy::new( inbox_id, wallet.get_address(), nonce, diff --git a/xmtp_mls/src/api/mls.rs b/xmtp_mls/src/api/mls.rs index 01f903546..826f84325 100644 --- a/xmtp_mls/src/api/mls.rs +++ b/xmtp_mls/src/api/mls.rs @@ -70,6 +70,12 @@ where group_id: Vec, id_cursor: Option, ) -> Result, ApiError> { + tracing::debug!( + group_id = hex::encode(&group_id), + id_cursor, + inbox_id = self.inbox_id, + "query group messages" + ); let mut out: Vec = vec![]; let page_size = 100; let mut id_cursor = id_cursor; @@ -114,6 +120,12 @@ where installation_id: Vec, id_cursor: Option, ) -> Result, ApiError> { + tracing::debug!( + installation_id = hex::encode(&installation_id), + cursor = id_cursor, + inbox_id = self.inbox_id, + "query welcomes" + ); let mut out: Vec = vec![]; let page_size = 100; let mut id_cursor = id_cursor; @@ -162,6 +174,7 @@ where key_package: Vec, is_inbox_id_credential: bool, ) -> Result<(), ApiError> { + tracing::debug!(inbox_id = self.inbox_id, "upload key packages"); retry_async!( self.retry_strategy, (async { @@ -184,6 +197,7 @@ where &self, installation_keys: Vec>, ) -> Result { + tracing::debug!(inbox_id = self.inbox_id, "fetch key packages"); let res = retry_async!( self.retry_strategy, (async { @@ -220,6 +234,7 @@ where &self, messages: &[WelcomeMessageInput], ) -> Result<(), ApiError> { + tracing::debug!(inbox_id = self.inbox_id, "send welcome messages"); retry_async!( self.retry_strategy, (async { @@ -236,6 +251,11 @@ where #[tracing::instrument(level = "trace", skip_all)] pub async fn send_group_messages(&self, group_messages: Vec<&[u8]>) -> Result<(), ApiError> { + tracing::debug!( + inbox_id = self.inbox_id, + "sending [{}] group messages", + group_messages.len() + ); let to_send: Vec = group_messages .iter() .map(|msg| GroupMessageInput { @@ -267,6 +287,7 @@ where where ApiClient: XmtpMlsStreams, { + tracing::debug!(inbox_id = self.inbox_id, "subscribing to group messages"); self.api_client .subscribe_group_messages(SubscribeGroupMessagesRequest { filters: filters.into_iter().map(|f| f.into()).collect(), @@ -282,6 +303,7 @@ where where ApiClient: XmtpMlsStreams, { + tracing::debug!(inbox_id = self.inbox_id, "subscribing to welcome messages"); self.api_client .subscribe_welcome_messages(SubscribeWelcomeMessagesRequest { filters: vec![WelcomeFilterProto { diff --git a/xmtp_mls/src/api/mod.rs b/xmtp_mls/src/api/mod.rs index 64d173c13..c9255e01f 100644 --- a/xmtp_mls/src/api/mod.rs +++ b/xmtp_mls/src/api/mod.rs @@ -10,7 +10,7 @@ use crate::{ XmtpApi, }; use thiserror::Error; -use xmtp_id::associations::DeserializationError as AssociationDeserializationError; +use xmtp_id::{associations::DeserializationError as AssociationDeserializationError, InboxId}; use xmtp_proto::Error as ApiError; pub use identity::*; @@ -34,6 +34,7 @@ impl RetryableError for WrappedApiError { pub struct ApiClientWrapper { pub(crate) api_client: Arc, pub(crate) retry_strategy: Retry, + pub(crate) inbox_id: Option, } impl ApiClientWrapper @@ -44,6 +45,13 @@ where Self { api_client, retry_strategy, + inbox_id: None, } } + + /// Attach an InboxId to this API Client Wrapper. + /// Attaches an inbox_id context to tracing logs, useful for debugging + pub(crate) fn attach_inbox_id(&mut self, inbox_id: Option) { + self.inbox_id = inbox_id; + } } diff --git a/xmtp_mls/src/builder.rs b/xmtp_mls/src/builder.rs index 1e0fc216f..e8303e1ec 100644 --- a/xmtp_mls/src/builder.rs +++ b/xmtp_mls/src/builder.rs @@ -186,7 +186,11 @@ where let store = store .take() .ok_or(ClientBuilderError::MissingParameter { parameter: "store" })?; - debug!("Initializing identity"); + + debug!( + inbox_id = identity_strategy.inbox_id(), + "Initializing identity" + ); let identity = identity_strategy .initialize_identity(&api_client_wrapper, &store, &scw_verifier) @@ -340,7 +344,7 @@ pub(crate) mod tests { IdentityStrategyTestCase { strategy: { let (legacy_key, legacy_account_address) = generate_random_legacy_key().await; - IdentityStrategy::CreateIfNotFound( + IdentityStrategy::new( generate_inbox_id(&legacy_account_address, &1).unwrap(), legacy_account_address.clone(), 1, @@ -352,7 +356,7 @@ pub(crate) mod tests { IdentityStrategyTestCase { strategy: { let (legacy_key, legacy_account_address) = generate_random_legacy_key().await; - IdentityStrategy::CreateIfNotFound( + IdentityStrategy::new( generate_inbox_id(&legacy_account_address, &1).unwrap(), legacy_account_address.clone(), 0, @@ -364,7 +368,7 @@ pub(crate) mod tests { IdentityStrategyTestCase { strategy: { let (legacy_key, legacy_account_address) = generate_random_legacy_key().await; - IdentityStrategy::CreateIfNotFound( + IdentityStrategy::new( generate_inbox_id(&legacy_account_address, &0).unwrap(), legacy_account_address.clone(), 0, @@ -377,7 +381,7 @@ pub(crate) mod tests { IdentityStrategyTestCase { strategy: { let account_address = generate_local_wallet().get_address(); - IdentityStrategy::CreateIfNotFound( + IdentityStrategy::new( generate_inbox_id(&account_address, &1).unwrap(), account_address.clone(), 0, @@ -390,7 +394,7 @@ pub(crate) mod tests { strategy: { let nonce = 1; let account_address = generate_local_wallet().get_address(); - IdentityStrategy::CreateIfNotFound( + IdentityStrategy::new( generate_inbox_id(&account_address, &nonce).unwrap(), account_address.clone(), nonce, @@ -403,7 +407,7 @@ pub(crate) mod tests { strategy: { let nonce = 0; let account_address = generate_local_wallet().get_address(); - IdentityStrategy::CreateIfNotFound( + IdentityStrategy::new( generate_inbox_id(&account_address, &nonce).unwrap(), account_address.clone(), nonce, @@ -446,7 +450,7 @@ pub(crate) mod tests { let id = generate_inbox_id(&legacy_account_address, &0).unwrap(); println!("{}", id.len()); - let identity_strategy = IdentityStrategy::CreateIfNotFound( + let identity_strategy = IdentityStrategy::new( generate_inbox_id(&legacy_account_address, &0).unwrap(), legacy_account_address.clone(), 0, @@ -479,7 +483,7 @@ pub(crate) mod tests { assert!(client1.inbox_id() == client2.inbox_id()); assert!(client1.installation_public_key() == client2.installation_public_key()); - let client3 = ClientBuilder::new(IdentityStrategy::CreateIfNotFound( + let client3 = ClientBuilder::new(IdentityStrategy::new( generate_inbox_id(&legacy_account_address, &0).unwrap(), legacy_account_address.to_string(), 0, @@ -495,7 +499,7 @@ pub(crate) mod tests { assert!(client1.inbox_id() == client3.inbox_id()); assert!(client1.installation_public_key() == client3.installation_public_key()); - let client4 = ClientBuilder::new(IdentityStrategy::CreateIfNotFound( + let client4 = ClientBuilder::new(IdentityStrategy::new( generate_inbox_id(&legacy_account_address, &0).unwrap(), legacy_account_address.to_string(), 0, @@ -544,8 +548,7 @@ pub(crate) mod tests { let wrapper = ApiClientWrapper::new(mock_api.into(), Retry::default()); - let identity = - IdentityStrategy::CreateIfNotFound("other_inbox_id".to_string(), address, nonce, None); + let identity = IdentityStrategy::new("other_inbox_id".to_string(), address, nonce, None); assert!(matches!( identity .initialize_identity(&wrapper, &store, &scw_verifier) @@ -586,7 +589,7 @@ pub(crate) mod tests { let wrapper = ApiClientWrapper::new(mock_api.into(), Retry::default()); - let identity = IdentityStrategy::CreateIfNotFound(inbox_id.clone(), address, nonce, None); + let identity = IdentityStrategy::new(inbox_id.clone(), address, nonce, None); assert!(dbg!( identity .initialize_identity(&wrapper, &store, &scw_verifier) @@ -625,7 +628,7 @@ pub(crate) mod tests { stored.store(&store.conn().unwrap()).unwrap(); let wrapper = ApiClientWrapper::new(mock_api.into(), Retry::default()); - let identity = IdentityStrategy::CreateIfNotFound(inbox_id.clone(), address, nonce, None); + let identity = IdentityStrategy::new(inbox_id.clone(), address, nonce, None); assert!(identity .initialize_identity(&wrapper, &store, &scw_verifier) .await @@ -665,8 +668,7 @@ pub(crate) mod tests { let wrapper = ApiClientWrapper::new(mock_api.into(), Retry::default()); let inbox_id = "inbox_id".to_string(); - let identity = - IdentityStrategy::CreateIfNotFound(inbox_id.clone(), address.clone(), nonce, None); + let identity = IdentityStrategy::new(inbox_id.clone(), address.clone(), nonce, None); let err = identity .initialize_identity(&wrapper, &store, &scw_verifier) .await @@ -691,7 +693,7 @@ pub(crate) mod tests { let nonce = 1; let inbox_id = generate_inbox_id(&wallet.get_address(), &nonce).unwrap(); - let client_a = Client::builder(IdentityStrategy::CreateIfNotFound( + let client_a = Client::builder(IdentityStrategy::new( inbox_id.clone(), wallet.get_address(), nonce, @@ -715,7 +717,7 @@ pub(crate) mod tests { .await .unwrap(); - let client_b = Client::builder(IdentityStrategy::CreateIfNotFound( + let client_b = Client::builder(IdentityStrategy::new( inbox_id, wallet.get_address(), nonce, @@ -739,7 +741,7 @@ pub(crate) mod tests { // EncryptedMessageStore::new_unencrypted(StorageOption::Persistent(tmpdb.clone())) // .unwrap(); - // ClientBuilder::new(IdentityStrategy::CreateIfNotFound( + // ClientBuilder::new(IdentityStrategy::new( // generate_local_wallet().get_address(), // None, // )) @@ -801,7 +803,7 @@ pub(crate) mod tests { let account_address = format!("{scw_addr:?}"); let account_id = AccountId::new_evm(anvil_meta.chain_id, account_address.clone()); - let identity_strategy = IdentityStrategy::CreateIfNotFound( + let identity_strategy = IdentityStrategy::new( generate_inbox_id(&account_address, &0).unwrap(), account_address, 0, diff --git a/xmtp_mls/src/client.rs b/xmtp_mls/src/client.rs index d680e3018..055252832 100644 --- a/xmtp_mls/src/client.rs +++ b/xmtp_mls/src/client.rs @@ -218,7 +218,7 @@ where /// It is expected that most users will use the [`ClientBuilder`](crate::builder::ClientBuilder) instead of instantiating /// a client directly. pub fn new( - api_client: ApiClientWrapper, + mut api_client: ApiClientWrapper, identity: Identity, store: EncryptedMessageStore, scw_verifier: V, @@ -227,6 +227,7 @@ where where V: SmartContractSignatureVerifier, { + api_client.attach_inbox_id(Some(identity.inbox_id().to_string())); let context = Arc::new(XmtpMlsLocalContext { identity, store, @@ -723,6 +724,7 @@ where /// Download all unread welcome messages and converts to a group struct, ignoring malformed messages. /// Returns any new groups created in the operation + #[tracing::instrument(level = "debug", skip_all)] pub async fn sync_welcomes( &self, conn: &DbConnection, diff --git a/xmtp_mls/src/groups/intents.rs b/xmtp_mls/src/groups/intents.rs index 13767ff5c..80f5eb167 100644 --- a/xmtp_mls/src/groups/intents.rs +++ b/xmtp_mls/src/groups/intents.rs @@ -86,6 +86,7 @@ impl MlsGroup { if intent_kind != IntentKind::SendMessage { conn.update_rotated_at_ns(self.group_id.clone())?; } + tracing::debug!(inbox_id = self.client.inbox_id(), intent_kind = %intent_kind, "queued intent"); Ok(intent) } diff --git a/xmtp_mls/src/groups/mod.rs b/xmtp_mls/src/groups/mod.rs index f6de6dd48..143ca5f28 100644 --- a/xmtp_mls/src/groups/mod.rs +++ b/xmtp_mls/src/groups/mod.rs @@ -591,6 +591,7 @@ impl MlsGroup { /// Send a message on this users XMTP [`Client`]. pub async fn send_message(&self, message: &[u8]) -> Result, GroupError> { + tracing::debug!(inbox_id = self.client.inbox_id(), "sending message"); let conn = self.context().store().conn()?; let provider = XmtpOpenMlsProvider::from(conn); self.send_message_with_provider(message, &provider).await diff --git a/xmtp_mls/src/groups/subscriptions.rs b/xmtp_mls/src/groups/subscriptions.rs index 5701bb882..2caf9bec9 100644 --- a/xmtp_mls/src/groups/subscriptions.rs +++ b/xmtp_mls/src/groups/subscriptions.rs @@ -180,6 +180,7 @@ impl MlsGroup { } /// Stream messages from groups in `group_id_to_info` +#[tracing::instrument(level = "debug", skip_all)] pub(crate) async fn stream_messages( client: &ScopedClient, group_id_to_info: Arc, MessagesStreamInfo>>, @@ -200,9 +201,12 @@ where let group_id_to_info = group_id_to_info.clone(); async move { let envelope = res.map_err(GroupError::from)?; - tracing::info!("Received message streaming payload"); let group_id = extract_group_id(&envelope)?; - tracing::info!("Extracted group id {}", hex::encode(&group_id)); + tracing::info!( + inbox_id = client.inbox_id(), + group_id = hex::encode(&group_id), + "Received message streaming payload" + ); let stream_info = group_id_to_info .get(&group_id) diff --git a/xmtp_mls/src/identity.rs b/xmtp_mls/src/identity.rs index 0f7ffdaa5..0b73a784d 100644 --- a/xmtp_mls/src/identity.rs +++ b/xmtp_mls/src/identity.rs @@ -60,7 +60,12 @@ use xmtp_proto::xmtp::identity::MlsCredential; #[derive(Debug, Clone)] pub enum IdentityStrategy { /// Tries to get an identity from the disk store. If not found, getting one from backend. - CreateIfNotFound(InboxId, String, u64, Option>), // (inbox_id, address, nonce, legacy_signed_private_key) + CreateIfNotFound { + inbox_id: InboxId, + address: String, + nonce: u64, + legacy_signed_private_key: Option>, + }, /// Identity that is already in the disk store CachedOnly, /// An already-built Identity for testing purposes @@ -68,6 +73,32 @@ pub enum IdentityStrategy { ExternalIdentity(Identity), } +impl IdentityStrategy { + pub fn inbox_id(&self) -> Option> { + use IdentityStrategy::*; + match self { + CreateIfNotFound { ref inbox_id, .. } => Some(inbox_id), + _ => None, + } + } + + /// Create a new Identity Strategy, with [`IdentityStrategy::CreateIfNotFound`]. + /// If an Identity is not found in the local store, creates a new one. + pub fn new( + inbox_id: InboxId, + address: String, + nonce: u64, + legacy_signed_private_key: Option>, + ) -> Self { + Self::CreateIfNotFound { + inbox_id, + address, + nonce, + legacy_signed_private_key, + } + } +} + impl IdentityStrategy { /** * Initialize an identity from the given strategy. If a stored identity is found in the database, @@ -83,6 +114,8 @@ impl IdentityStrategy { store: &EncryptedMessageStore, scw_signature_verifier: impl SmartContractSignatureVerifier, ) -> Result { + use IdentityStrategy::*; + info!("Initializing identity"); let conn = store.conn()?; let provider = XmtpOpenMlsProvider::new(conn); @@ -94,15 +127,13 @@ impl IdentityStrategy { debug!("identity in store: {:?}", stored_identity); match self { - IdentityStrategy::CachedOnly => { - stored_identity.ok_or(IdentityError::RequiredIdentityNotFound) - } - IdentityStrategy::CreateIfNotFound( + CachedOnly => stored_identity.ok_or(IdentityError::RequiredIdentityNotFound), + CreateIfNotFound { inbox_id, address, nonce, legacy_signed_private_key, - ) => { + } => { if let Some(stored_identity) = stored_identity { if inbox_id != stored_identity.inbox_id { return Err(IdentityError::InboxIdMismatch { @@ -126,7 +157,7 @@ impl IdentityStrategy { } } #[cfg(test)] - IdentityStrategy::ExternalIdentity(identity) => Ok(identity), + ExternalIdentity(identity) => Ok(identity), } } } diff --git a/xmtp_mls/src/storage/encrypted_store/group.rs b/xmtp_mls/src/storage/encrypted_store/group.rs index f5241f53e..1bd426db7 100644 --- a/xmtp_mls/src/storage/encrypted_store/group.rs +++ b/xmtp_mls/src/storage/encrypted_store/group.rs @@ -492,6 +492,7 @@ pub enum ConversationType { Dm = 2, Sync = 3, } + impl ToSql for ConversationType where i32: ToSql, @@ -516,6 +517,17 @@ where } } +impl std::fmt::Display for ConversationType { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + use ConversationType::*; + match self { + Group => write!(f, "group"), + Dm => write!(f, "dm"), + Sync => write!(f, "sync"), + } + } +} + #[cfg(test)] pub(crate) mod tests { #[cfg(target_arch = "wasm32")] diff --git a/xmtp_mls/src/subscriptions.rs b/xmtp_mls/src/subscriptions.rs index 90de8461f..c4d958f7b 100644 --- a/xmtp_mls/src/subscriptions.rs +++ b/xmtp_mls/src/subscriptions.rs @@ -235,6 +235,7 @@ where match result { Ok(Some(group)) => { tracing::info!( + inbox_id = self.inbox_id(), group_id = hex::encode(&group.id), welcome_id = ?group.welcome_id, "Loading existing group for welcome_id: {:?}", @@ -261,6 +262,7 @@ where Ok(welcome) } + #[tracing::instrument(level = "debug", skip_all)] pub async fn stream_conversations( &self, conversation_type: Option, @@ -298,7 +300,7 @@ where let installation_key = self.installation_public_key(); let id_cursor = 0; - tracing::info!("Setting up conversation stream"); + tracing::info!(inbox_id = self.inbox_id(), "Setting up conversation stream"); let subscription = self .api_client .subscribe_welcome_messages(installation_key, Some(id_cursor)) @@ -306,7 +308,10 @@ where let stream = subscription .map(|welcome| async { - tracing::info!("Received conversation streaming payload"); + tracing::info!( + inbox_id = self.inbox_id(), + "Received conversation streaming payload" + ); self.process_streamed_welcome(welcome?).await }) .filter_map(|v| async { Some(v.await) }); @@ -340,11 +345,18 @@ where }) } + #[tracing::instrument(level = "debug", skip_all)] pub async fn stream_all_messages( &self, conversation_type: Option, ) -> Result> + '_, ClientError> { + tracing::debug!( + inbox_id = self.inbox_id(), + conversation_type = ?conversation_type, + "stream all messages" + ); + let conn = self.store().conn()?; self.sync_welcomes(&conn).await?; @@ -364,7 +376,6 @@ where .await?; futures::pin_mut!(messages_stream); - tracing::info!("Setting up conversation stream in stream_all_messages"); let convo_stream = self.stream_conversations(conversation_type).await?; futures::pin_mut!(convo_stream); diff --git a/xmtp_mls/src/utils/test/mod.rs b/xmtp_mls/src/utils/test/mod.rs index 1616556ea..952b31988 100755 --- a/xmtp_mls/src/utils/test/mod.rs +++ b/xmtp_mls/src/utils/test/mod.rs @@ -175,7 +175,7 @@ where let nonce = 1; let inbox_id = generate_inbox_id(&owner.get_address(), &nonce).unwrap(); - let client = Client::::builder(IdentityStrategy::CreateIfNotFound( + let client = Client::::builder(IdentityStrategy::new( inbox_id, owner.get_address(), nonce, @@ -208,7 +208,7 @@ where let nonce = 1; let inbox_id = generate_inbox_id(&owner.get_address(), &nonce).unwrap(); - let mut builder = Client::::builder(IdentityStrategy::CreateIfNotFound( + let mut builder = Client::::builder(IdentityStrategy::new( inbox_id, owner.get_address(), nonce, From 964a227ccde1fb7417674f08b2dff1acf1334efc Mon Sep 17 00:00:00 2001 From: Andrew Plaza Date: Tue, 26 Nov 2024 12:49:43 -0500 Subject: [PATCH 13/46] release(node): bump node version and modify changelog (#1343) --- bindings_node/CHANGELOG.md | 25 +++++++++++++++++++++---- bindings_node/package.json | 2 +- 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/bindings_node/CHANGELOG.md b/bindings_node/CHANGELOG.md index abbea749a..0170dc8f4 100644 --- a/bindings_node/CHANGELOG.md +++ b/bindings_node/CHANGELOG.md @@ -1,5 +1,18 @@ # @xmtp/node-bindings +## 0.0.25 + + - Fixed streaming by adding `napi4` feature to napi-rs + +## 0.0.24 + + - Fixed using `Vec` instead rust `Uint8Array` type in `is_installation_authorized` + +## 0.0.23 + + - Added `is_installation_authorized` to `Client` + - Added `is_address_authorized` to `Client` + ## 0.0.22 - Moved `verify_signed_with_public_key` out of `Client` @@ -17,7 +30,8 @@ - Renamed `Level` to `LogLevel` - Filtered out group membership messages from DM groups - Fixed `syncAllConversations` export -- Added `sign_with_installation_key`, `verify_signed_with_installation_key`, and `verify_signed_with_public_key` to `Client` +- Added `sign_with_installation_key`, `verify_signed_with_installation_key`, and + `verify_signed_with_public_key` to `Client` ## 0.0.18 @@ -35,9 +49,12 @@ - Added sort direction to `NapiListMessagesOptions` - Added `dm_peer_inbox_id` method to `NapiGroup` -- Added `allowed_states` and `conversation_type` to `NapiListConversationsOptions` -- Added `create_dm`, `list_groups`, and `list_dms` methods to `NapiConversations` -- Added `stream_groups`, `stream_dms`, `stream_all_group_messages`, and `stream_all_dm_messages` streaming methods to `NapiConversations` +- Added `allowed_states` and `conversation_type` to + `NapiListConversationsOptions` +- Added `create_dm`, `list_groups`, and `list_dms` methods to + `NapiConversations` +- Added `stream_groups`, `stream_dms`, `stream_all_group_messages`, and + `stream_all_dm_messages` streaming methods to `NapiConversations` ## 0.0.15 diff --git a/bindings_node/package.json b/bindings_node/package.json index a1de4326c..3710b3740 100644 --- a/bindings_node/package.json +++ b/bindings_node/package.json @@ -1,6 +1,6 @@ { "name": "@xmtp/node-bindings", - "version": "0.0.24", + "version": "0.0.25", "repository": { "type": "git", "url": "git+https://git@github.com/xmtp/libxmtp.git", From 41204ab88f9098eb39c71d138831dd220a94e9c8 Mon Sep 17 00:00:00 2001 From: Martin Kysel Date: Tue, 26 Nov 2024 16:31:58 -0500 Subject: [PATCH 14/46] Teach testnet to use separate endpoints for payer and grpc APIs (#1346) We have split the payer service from the API service. --- examples/cli/cli-client.rs | 22 +++++++++++++++------ xmtp_api_grpc/src/replication_client.rs | 26 ++++++++++++++++++------- 2 files changed, 35 insertions(+), 13 deletions(-) diff --git a/examples/cli/cli-client.rs b/examples/cli/cli-client.rs index 9e28e9cc8..5598ee25a 100755 --- a/examples/cli/cli-client.rs +++ b/examples/cli/cli-client.rs @@ -235,12 +235,22 @@ async fn main() -> color_eyre::eyre::Result<()> { info!("Starting CLI Client...."); let grpc: Box = match (cli.testnet, &cli.env) { - (true, Env::Local) => { - Box::new(ClientV4::create("http://localhost:5050".into(), false).await?) - } - (true, Env::Dev) => { - Box::new(ClientV4::create("https://grpc.testnet.xmtp.network:443".into(), true).await?) - } + (true, Env::Local) => Box::new( + ClientV4::create( + "http://localhost:5050".into(), + "http://localhost:5050".into(), + false, + ) + .await?, + ), + (true, Env::Dev) => Box::new( + ClientV4::create( + "https://grpc.testnet.xmtp.network:443".into(), + "https://payer.testnet.xmtp.network:443".into(), + true, + ) + .await?, + ), (false, Env::Local) => { Box::new(ClientV3::create("http://localhost:5556".into(), false).await?) } diff --git a/xmtp_api_grpc/src/replication_client.rs b/xmtp_api_grpc/src/replication_client.rs index 97f7fa5c5..ee9a33141 100644 --- a/xmtp_api_grpc/src/replication_client.rs +++ b/xmtp_api_grpc/src/replication_client.rs @@ -72,16 +72,28 @@ pub struct ClientV4 { } impl ClientV4 { - pub async fn create(host: String, is_secure: bool) -> Result { - let host = host.to_string(); + pub async fn create( + grpc_url: String, + payer_url: String, + is_secure: bool, + ) -> Result { let app_version = MetadataValue::try_from(&String::from("0.0.0")) .map_err(|e| Error::new(ErrorKind::MetadataError).with(e))?; let libxmtp_version = MetadataValue::try_from(&String::from("0.0.0")) .map_err(|e| Error::new(ErrorKind::MetadataError).with(e))?; - let channel = match is_secure { - true => create_tls_channel(host).await?, - false => Channel::from_shared(host) + let grpc_channel = match is_secure { + true => create_tls_channel(grpc_url).await?, + false => Channel::from_shared(grpc_url) + .map_err(|e| Error::new(ErrorKind::SetupCreateChannelError).with(e))? + .connect() + .await + .map_err(|e| Error::new(ErrorKind::SetupConnectionError).with(e))?, + }; + + let payer_channel = match is_secure { + true => create_tls_channel(payer_url).await?, + false => Channel::from_shared(payer_url) .map_err(|e| Error::new(ErrorKind::SetupCreateChannelError).with(e))? .connect() .await @@ -89,8 +101,8 @@ impl ClientV4 { }; // GroupMessageInputTODO(mkysel) for now we assume both payer and replication are on the same host - let client = ReplicationApiClient::new(channel.clone()); - let payer_client = PayerApiClient::new(channel.clone()); + let client = ReplicationApiClient::new(grpc_channel.clone()); + let payer_client = PayerApiClient::new(payer_channel.clone()); Ok(Self { client, From 6ff8ae4535cdb3821ec2ed114bfbac7c5eca9ae3 Mon Sep 17 00:00:00 2001 From: Andrew Plaza Date: Wed, 27 Nov 2024 11:35:47 -0500 Subject: [PATCH 15/46] sqlcipher check (#1348) --- .../src/storage/encrypted_store/native.rs | 8 ++++ .../encrypted_store/sqlcipher_connection.rs | 39 ++++++++++++++++++- 2 files changed, 45 insertions(+), 2 deletions(-) diff --git a/xmtp_mls/src/storage/encrypted_store/native.rs b/xmtp_mls/src/storage/encrypted_store/native.rs index f951116b3..b254f820e 100644 --- a/xmtp_mls/src/storage/encrypted_store/native.rs +++ b/xmtp_mls/src/storage/encrypted_store/native.rs @@ -79,6 +79,14 @@ impl StorageOption { Ephemeral => SqliteConnection::establish(":memory:"), } } + + pub(super) fn path(&self) -> Option<&String> { + use StorageOption::*; + match self { + Persistent(path) => Some(path), + _ => None, + } + } } #[derive(Clone, Debug)] diff --git a/xmtp_mls/src/storage/encrypted_store/sqlcipher_connection.rs b/xmtp_mls/src/storage/encrypted_store/sqlcipher_connection.rs index 19b0e6145..25dfb379f 100644 --- a/xmtp_mls/src/storage/encrypted_store/sqlcipher_connection.rs +++ b/xmtp_mls/src/storage/encrypted_store/sqlcipher_connection.rs @@ -46,6 +46,8 @@ impl EncryptedConnection { /// Creates a file for the salt and stores it pub fn new(key: EncryptionKey, opts: &StorageOption) -> Result { use super::StorageOption::*; + Self::check_for_sqlcipher(opts)?; + let salt = match opts { Ephemeral => None, Persistent(ref db_path) => { @@ -56,6 +58,13 @@ impl EncryptedConnection { match (salt_path.try_exists()?, db_pathbuf.try_exists()?) { // db and salt exist (true, true) => { + tracing::debug!( + salt = %salt_path.display(), + db = %db_pathbuf.display(), + "salt and database exist, db=[{}], salt=[{}]", + db_pathbuf.display(), + salt_path.display(), + ); let file = File::open(salt_path)?; salt = ::from_hex( file.bytes().take(32).collect::, _>>()?, @@ -63,18 +72,31 @@ impl EncryptedConnection { } // the db exists and needs to be migrated (false, true) => { - tracing::debug!("migrating sqlcipher db to plaintext header."); + tracing::debug!( + "migrating sqlcipher db=[{}] to plaintext header with salt=[{}]", + db_pathbuf.display(), + salt_path.display() + ); Self::migrate(db_path, key, &mut salt)?; } // the db doesn't exist yet and needs to be created (false, false) => { - tracing::debug!("creating new sqlcipher db"); + tracing::debug!( + "creating new sqlcipher db=[{}] with salt=[{}]", + db_pathbuf.display(), + salt_path.display() + ); Self::create(db_path, key, &mut salt)?; } // the db doesn't exist but the salt does // This generally doesn't make sense & shouldn't happen. // Create a new database and delete the salt file. (true, false) => { + tracing::debug!( + "database [{}] does not exist, but the salt [{}] does, re-creating", + db_pathbuf.display(), + salt_path.display(), + ); std::fs::remove_file(salt_path)?; Self::create(db_path, key, &mut salt)?; } @@ -199,6 +221,19 @@ impl EncryptedConnection { ) } } + + fn check_for_sqlcipher(opts: &StorageOption) -> Result<(), StorageError> { + if let Some(path) = opts.path() { + let exists = std::path::Path::new(path).exists(); + tracing::debug!("db @ [{}] exists? [{}]", path, exists); + } + let conn = &mut opts.conn()?; + let cipher_version = sql_query("PRAGMA cipher_version").load::(conn)?; + if cipher_version.is_empty() { + return Err(StorageError::SqlCipherNotLoaded); + } + Ok(()) + } } impl super::native::ValidatedConnection for EncryptedConnection { From de9757e1e2e10384e6e43f01145fc01982d42931 Mon Sep 17 00:00:00 2001 From: Dakota Brink <779390+codabrink@users.noreply.github.com> Date: Wed, 27 Nov 2024 18:58:48 -0500 Subject: [PATCH 16/46] Static association state checking (#1350) * This is it on a high level * move the logic to a better spot * use the remote service * napi, bump version * lint * test cleanup * cleanup * comments * do it faster * add the option to provide your own scw verifier --- bindings_node/Cargo.toml | 9 ++- bindings_node/package.json | 2 +- bindings_node/src/client.rs | 49 +++++++++++++- bindings_node/src/inbox_id.rs | 2 +- examples/cli/cli-client.rs | 12 ++-- xmtp_api_grpc/src/grpc_api_helper.rs | 2 +- xmtp_api_grpc/src/lib.rs | 4 +- xmtp_mls/src/identity_updates.rs | 98 ++++++++++++++++++++++++++-- xmtp_mls/src/lib.rs | 2 +- 9 files changed, 158 insertions(+), 22 deletions(-) diff --git a/bindings_node/Cargo.toml b/bindings_node/Cargo.toml index 8cc4ee49e..aa1038961 100644 --- a/bindings_node/Cargo.toml +++ b/bindings_node/Cargo.toml @@ -8,6 +8,7 @@ crate-type = ["cdylib"] [dependencies] # Default enable napi4 feature, see https://nodejs.org/api/n-api.html#node-api-version-matrix +futures.workspace = true hex.workspace = true napi = { version = "2.12.2", default-features = false, features = [ "napi4", @@ -17,14 +18,18 @@ napi = { version = "2.12.2", default-features = false, features = [ napi-derive = "2.12.2" prost.workspace = true tokio = { workspace = true, features = ["sync"] } -tracing-subscriber = { workspace = true, features = ["env-filter", "fmt", "json", "chrono"] } +tracing-subscriber = { workspace = true, features = [ + "env-filter", + "fmt", + "json", + "chrono", +] } tracing.workspace = true xmtp_api_grpc = { path = "../xmtp_api_grpc" } xmtp_cryptography = { path = "../xmtp_cryptography" } xmtp_id = { path = "../xmtp_id" } xmtp_mls = { path = "../xmtp_mls" } xmtp_proto = { path = "../xmtp_proto", features = ["proto_full"] } -futures.workspace = true [build-dependencies] napi-build = "2.0.1" diff --git a/bindings_node/package.json b/bindings_node/package.json index 3710b3740..55165b85f 100644 --- a/bindings_node/package.json +++ b/bindings_node/package.json @@ -1,6 +1,6 @@ { "name": "@xmtp/node-bindings", - "version": "0.0.25", + "version": "0.0.26", "repository": { "type": "git", "url": "git+https://git@github.com/xmtp/libxmtp.git", diff --git a/bindings_node/src/client.rs b/bindings_node/src/client.rs index d554274f0..9a8e094e7 100644 --- a/bindings_node/src/client.rs +++ b/bindings_node/src/client.rs @@ -14,9 +14,11 @@ pub use xmtp_api_grpc::grpc_api_helper::Client as TonicApiClient; use xmtp_cryptography::signature::ed25519_public_key_to_address; use xmtp_id::associations::builder::SignatureRequest; use xmtp_id::associations::MemberIdentifier; +use xmtp_mls::api::ApiClientWrapper; use xmtp_mls::builder::ClientBuilder; use xmtp_mls::groups::scoped_client::LocalScopedGroupClient; use xmtp_mls::identity::IdentityStrategy; +use xmtp_mls::retry::Retry; use xmtp_mls::storage::{EncryptedMessageStore, EncryptionKey, StorageOption}; use xmtp_mls::Client as MlsClient; use xmtp_proto::xmtp::mls::message_contents::DeviceSyncKind; @@ -131,7 +133,7 @@ pub async fn create_client( log_options: Option, ) -> Result { init_logging(log_options.unwrap_or_default())?; - let api_client = TonicApiClient::create(host.clone(), is_secure) + let api_client = TonicApiClient::create(&host, is_secure) .await .map_err(|_| Error::from_reason("Error creating Tonic API client"))?; @@ -343,3 +345,48 @@ impl Client { Ok(association_state.get(identifier).is_some()) } } + +#[napi] +pub async fn is_installation_authorized( + host: String, + inbox_id: String, + installation_id: Uint8Array, +) -> Result { + is_member_of_association_state( + &host, + &inbox_id, + &MemberIdentifier::Installation(installation_id.to_vec()), + ) + .await +} + +#[napi] +pub async fn is_address_authorized( + host: String, + inbox_id: String, + address: String, +) -> Result { + is_member_of_association_state(&host, &inbox_id, &MemberIdentifier::Address(address)).await +} + +async fn is_member_of_association_state( + host: &str, + inbox_id: &str, + identifier: &MemberIdentifier, +) -> Result { + let api_client = TonicApiClient::create(host, true) + .await + .map_err(ErrorWrapper::from)?; + let api_client = ApiClientWrapper::new(Arc::new(api_client), Retry::default()); + + let is_member = xmtp_mls::identity_updates::is_member_of_association_state( + &api_client, + inbox_id, + identifier, + None, + ) + .await + .map_err(ErrorWrapper::from)?; + + Ok(is_member) +} diff --git a/bindings_node/src/inbox_id.rs b/bindings_node/src/inbox_id.rs index ebe93c6d7..34821514a 100644 --- a/bindings_node/src/inbox_id.rs +++ b/bindings_node/src/inbox_id.rs @@ -14,7 +14,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, is_secure) .await .map_err(ErrorWrapper::from)? .into(), diff --git a/examples/cli/cli-client.rs b/examples/cli/cli-client.rs index 5598ee25a..709c7a8a6 100755 --- a/examples/cli/cli-client.rs +++ b/examples/cli/cli-client.rs @@ -251,15 +251,13 @@ async fn main() -> color_eyre::eyre::Result<()> { ) .await?, ), - (false, Env::Local) => { - Box::new(ClientV3::create("http://localhost:5556".into(), false).await?) - } + (false, Env::Local) => Box::new(ClientV3::create("http://localhost:5556", false).await?), (false, Env::Dev) => { - Box::new(ClientV3::create("https://grpc.dev.xmtp.network:443".into(), true).await?) + Box::new(ClientV3::create("https://grpc.dev.xmtp.network:443", true).await?) + } + (false, Env::Production) => { + Box::new(ClientV3::create("https://grpc.production.xmtp.network:443", true).await?) } - (false, Env::Production) => Box::new( - ClientV3::create("https://grpc.production.xmtp.network:443".into(), true).await?, - ), (true, Env::Production) => todo!("not supported"), }; diff --git a/xmtp_api_grpc/src/grpc_api_helper.rs b/xmtp_api_grpc/src/grpc_api_helper.rs index 150e0b57c..fa7683de7 100644 --- a/xmtp_api_grpc/src/grpc_api_helper.rs +++ b/xmtp_api_grpc/src/grpc_api_helper.rs @@ -74,7 +74,7 @@ pub struct Client { } impl Client { - pub async fn create(host: String, is_secure: bool) -> Result { + pub async fn create(host: impl ToString, is_secure: 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))?; diff --git a/xmtp_api_grpc/src/lib.rs b/xmtp_api_grpc/src/lib.rs index d6bfe96e1..6da24430a 100644 --- a/xmtp_api_grpc/src/lib.rs +++ b/xmtp_api_grpc/src/lib.rs @@ -16,13 +16,13 @@ mod utils { #[async_trait::async_trait] impl XmtpTestClient for crate::Client { async fn create_local() -> Self { - crate::Client::create("http://localhost:5556".into(), false) + crate::Client::create("http://localhost:5556", false) .await .unwrap() } async fn create_dev() -> Self { - crate::Client::create("https://grpc.dev.xmtp.network:443".into(), false) + crate::Client::create("https://grpc.dev.xmtp.network:443", false) .await .unwrap() } diff --git a/xmtp_mls/src/identity_updates.rs b/xmtp_mls/src/identity_updates.rs index 53d938a78..7c7220aa9 100644 --- a/xmtp_mls/src/identity_updates.rs +++ b/xmtp_mls/src/identity_updates.rs @@ -1,11 +1,10 @@ -use std::collections::{HashMap, HashSet}; - use crate::{ retry::{Retry, RetryableError}, retry_async, retryable, storage::association_state::StoredAssociationState, }; use futures::future::try_join_all; +use std::collections::{HashMap, HashSet}; use thiserror::Error; use xmtp_cryptography::CredentialSign; use xmtp_id::{ @@ -16,12 +15,13 @@ use xmtp_id::{ unverified::{ UnverifiedIdentityUpdate, UnverifiedInstallationKeySignature, UnverifiedSignature, }, - AssociationError, AssociationState, AssociationStateDiff, IdentityUpdate, + AssociationError, AssociationState, AssociationStateDiff, IdentityAction, IdentityUpdate, InstallationKeyContext, MemberIdentifier, SignatureError, }, - scw_verifier::SmartContractSignatureVerifier, + scw_verifier::{RemoteSignatureVerifier, SmartContractSignatureVerifier}, InboxIdRef, }; +use xmtp_proto::api_client::{ClientWithMetadata, XmtpIdentityClient, XmtpMlsClient}; use crate::{ api::{ApiClientWrapper, GetIdentityUpdatesV2Filter, InboxUpdate}, @@ -284,7 +284,7 @@ where let inbox_id = self.inbox_id(); let builder = SignatureRequestBuilder::new(inbox_id); let installation_public_key = self.identity().installation_keys.verifying_key(); - let new_member_identifier: MemberIdentifier = new_wallet_address.into(); + let new_member_identifier = MemberIdentifier::Address(new_wallet_address); let mut signature_request = builder .add_association(new_member_identifier, installation_public_key.into()) @@ -528,6 +528,53 @@ async fn verify_updates( .await } +/// A static lookup method to verify if an identity is a member of an inbox +pub async fn is_member_of_association_state( + api_client: &ApiClientWrapper, + inbox_id: &str, + identifier: &MemberIdentifier, + scw_verifier: Option>, +) -> Result +where + Client: XmtpMlsClient + XmtpIdentityClient + ClientWithMetadata + Send + Sync, +{ + let filters = vec![GetIdentityUpdatesV2Filter { + inbox_id: inbox_id.to_string(), + sequence_id: None, + }]; + let mut updates = api_client.get_identity_updates_v2(filters).await?; + + let Some(updates) = updates.remove(inbox_id) else { + return Err(ClientError::Generic( + "Unable to find provided inbox_id".to_string(), + )); + }; + let updates: Vec<_> = updates.into_iter().map(|u| u.update).collect(); + + let mut association_state = None; + + let scw_verifier = scw_verifier.unwrap_or_else(|| { + Box::new(RemoteSignatureVerifier::new(api_client.api_client.clone())) + as Box + }); + + let updates: Vec<_> = updates + .iter() + .map(|u| u.to_verified(&scw_verifier)) + .collect(); + let updates = try_join_all(updates).await?; + + for update in updates { + association_state = + Some(update.update_state(association_state, update.client_timestamp_ns)?); + } + let association_state = association_state.ok_or(ClientError::Generic( + "Unable to create association state".to_string(), + ))?; + + Ok(association_state.get(identifier).is_some()) +} + #[cfg(test)] pub(crate) mod tests { #[cfg(target_arch = "wasm32")] @@ -550,7 +597,7 @@ pub(crate) mod tests { Client, XmtpApi, }; - use super::load_identity_updates; + use super::{is_member_of_association_state, load_identity_updates}; async fn get_association_state( client: &Client, @@ -579,6 +626,45 @@ pub(crate) mod tests { .expect("insert should succeed"); } + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] + async fn test_is_member_of_association_state() { + let wallet = generate_local_wallet(); + let client = ClientBuilder::new_test_client(&wallet).await; + + let wallet2 = generate_local_wallet(); + + let mut request = client + .associate_wallet(wallet2.get_address()) + .await + .unwrap(); + add_wallet_signature(&mut request, &wallet2).await; + client.apply_signature_request(request).await.unwrap(); + + let conn = client.store().conn().unwrap(); + let state = client + .get_latest_association_state(&conn, client.inbox_id()) + .await + .unwrap(); + + // The installation, wallet1 address, and the newly associated wallet2 address + assert_eq!(state.members().len(), 3); + + let api_client = &client.api_client; + + // Check that the second wallet is associated with our new static helper + let is_member = is_member_of_association_state( + api_client, + client.inbox_id(), + &MemberIdentifier::Address(wallet2.get_address()), + None, + ) + .await + .unwrap(); + + assert!(is_member); + } + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] async fn create_inbox_round_trip() { diff --git a/xmtp_mls/src/lib.rs b/xmtp_mls/src/lib.rs index 86095c223..6384cc5de 100644 --- a/xmtp_mls/src/lib.rs +++ b/xmtp_mls/src/lib.rs @@ -9,7 +9,7 @@ pub mod configuration; pub mod groups; mod hpke; pub mod identity; -mod identity_updates; +pub mod identity_updates; mod intents; mod mutex_registry; pub mod retry; From 8cf44468d2dd918e7418d527817df343f92f4dc3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 2 Dec 2024 14:31:39 +0000 Subject: [PATCH 17/46] Bump the node-dev group in /bindings_node with 3 updates (#1353) --- bindings_node/package.json | 6 +- bindings_node/yarn.lock | 429 +++++++++++++++++++------------------ 2 files changed, 227 insertions(+), 208 deletions(-) diff --git a/bindings_node/package.json b/bindings_node/package.json index 55165b85f..d859c7816 100644 --- a/bindings_node/package.json +++ b/bindings_node/package.json @@ -38,14 +38,14 @@ "devDependencies": { "@ianvs/prettier-plugin-sort-imports": "^4.4.0", "@napi-rs/cli": "^3.0.0-alpha.64", - "@types/node": "^22.9.0", + "@types/node": "^22.10.1", "@types/uuid": "^10.0.0", - "prettier": "^3.3.3", + "prettier": "^3.4.1", "prettier-plugin-packagejson": "^2.5.3", "typescript": "^5.7.2", "uuid": "^11.0.3", "viem": "^2.21.47", - "vite": "^5.4.11", + "vite": "^6.0.1", "vite-tsconfig-paths": "^5.1.2", "vitest": "^2.1.5" }, diff --git a/bindings_node/yarn.lock b/bindings_node/yarn.lock index d81c31878..5f2bdde7b 100644 --- a/bindings_node/yarn.lock +++ b/bindings_node/yarn.lock @@ -132,9 +132,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/aix-ppc64@npm:0.21.5": - version: 0.21.5 - resolution: "@esbuild/aix-ppc64@npm:0.21.5" +"@esbuild/aix-ppc64@npm:0.24.0": + version: 0.24.0 + resolution: "@esbuild/aix-ppc64@npm:0.24.0" conditions: os=aix & cpu=ppc64 languageName: node linkType: hard @@ -146,9 +146,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/android-arm64@npm:0.21.5": - version: 0.21.5 - resolution: "@esbuild/android-arm64@npm:0.21.5" +"@esbuild/android-arm64@npm:0.24.0": + version: 0.24.0 + resolution: "@esbuild/android-arm64@npm:0.24.0" conditions: os=android & cpu=arm64 languageName: node linkType: hard @@ -160,9 +160,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/android-arm@npm:0.21.5": - version: 0.21.5 - resolution: "@esbuild/android-arm@npm:0.21.5" +"@esbuild/android-arm@npm:0.24.0": + version: 0.24.0 + resolution: "@esbuild/android-arm@npm:0.24.0" conditions: os=android & cpu=arm languageName: node linkType: hard @@ -174,9 +174,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/android-x64@npm:0.21.5": - version: 0.21.5 - resolution: "@esbuild/android-x64@npm:0.21.5" +"@esbuild/android-x64@npm:0.24.0": + version: 0.24.0 + resolution: "@esbuild/android-x64@npm:0.24.0" conditions: os=android & cpu=x64 languageName: node linkType: hard @@ -188,9 +188,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/darwin-arm64@npm:0.21.5": - version: 0.21.5 - resolution: "@esbuild/darwin-arm64@npm:0.21.5" +"@esbuild/darwin-arm64@npm:0.24.0": + version: 0.24.0 + resolution: "@esbuild/darwin-arm64@npm:0.24.0" conditions: os=darwin & cpu=arm64 languageName: node linkType: hard @@ -202,9 +202,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/darwin-x64@npm:0.21.5": - version: 0.21.5 - resolution: "@esbuild/darwin-x64@npm:0.21.5" +"@esbuild/darwin-x64@npm:0.24.0": + version: 0.24.0 + resolution: "@esbuild/darwin-x64@npm:0.24.0" conditions: os=darwin & cpu=x64 languageName: node linkType: hard @@ -216,9 +216,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/freebsd-arm64@npm:0.21.5": - version: 0.21.5 - resolution: "@esbuild/freebsd-arm64@npm:0.21.5" +"@esbuild/freebsd-arm64@npm:0.24.0": + version: 0.24.0 + resolution: "@esbuild/freebsd-arm64@npm:0.24.0" conditions: os=freebsd & cpu=arm64 languageName: node linkType: hard @@ -230,9 +230,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/freebsd-x64@npm:0.21.5": - version: 0.21.5 - resolution: "@esbuild/freebsd-x64@npm:0.21.5" +"@esbuild/freebsd-x64@npm:0.24.0": + version: 0.24.0 + resolution: "@esbuild/freebsd-x64@npm:0.24.0" conditions: os=freebsd & cpu=x64 languageName: node linkType: hard @@ -244,9 +244,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/linux-arm64@npm:0.21.5": - version: 0.21.5 - resolution: "@esbuild/linux-arm64@npm:0.21.5" +"@esbuild/linux-arm64@npm:0.24.0": + version: 0.24.0 + resolution: "@esbuild/linux-arm64@npm:0.24.0" conditions: os=linux & cpu=arm64 languageName: node linkType: hard @@ -258,9 +258,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/linux-arm@npm:0.21.5": - version: 0.21.5 - resolution: "@esbuild/linux-arm@npm:0.21.5" +"@esbuild/linux-arm@npm:0.24.0": + version: 0.24.0 + resolution: "@esbuild/linux-arm@npm:0.24.0" conditions: os=linux & cpu=arm languageName: node linkType: hard @@ -272,9 +272,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/linux-ia32@npm:0.21.5": - version: 0.21.5 - resolution: "@esbuild/linux-ia32@npm:0.21.5" +"@esbuild/linux-ia32@npm:0.24.0": + version: 0.24.0 + resolution: "@esbuild/linux-ia32@npm:0.24.0" conditions: os=linux & cpu=ia32 languageName: node linkType: hard @@ -286,9 +286,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/linux-loong64@npm:0.21.5": - version: 0.21.5 - resolution: "@esbuild/linux-loong64@npm:0.21.5" +"@esbuild/linux-loong64@npm:0.24.0": + version: 0.24.0 + resolution: "@esbuild/linux-loong64@npm:0.24.0" conditions: os=linux & cpu=loong64 languageName: node linkType: hard @@ -300,9 +300,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/linux-mips64el@npm:0.21.5": - version: 0.21.5 - resolution: "@esbuild/linux-mips64el@npm:0.21.5" +"@esbuild/linux-mips64el@npm:0.24.0": + version: 0.24.0 + resolution: "@esbuild/linux-mips64el@npm:0.24.0" conditions: os=linux & cpu=mips64el languageName: node linkType: hard @@ -314,9 +314,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/linux-ppc64@npm:0.21.5": - version: 0.21.5 - resolution: "@esbuild/linux-ppc64@npm:0.21.5" +"@esbuild/linux-ppc64@npm:0.24.0": + version: 0.24.0 + resolution: "@esbuild/linux-ppc64@npm:0.24.0" conditions: os=linux & cpu=ppc64 languageName: node linkType: hard @@ -328,9 +328,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/linux-riscv64@npm:0.21.5": - version: 0.21.5 - resolution: "@esbuild/linux-riscv64@npm:0.21.5" +"@esbuild/linux-riscv64@npm:0.24.0": + version: 0.24.0 + resolution: "@esbuild/linux-riscv64@npm:0.24.0" conditions: os=linux & cpu=riscv64 languageName: node linkType: hard @@ -342,9 +342,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/linux-s390x@npm:0.21.5": - version: 0.21.5 - resolution: "@esbuild/linux-s390x@npm:0.21.5" +"@esbuild/linux-s390x@npm:0.24.0": + version: 0.24.0 + resolution: "@esbuild/linux-s390x@npm:0.24.0" conditions: os=linux & cpu=s390x languageName: node linkType: hard @@ -356,9 +356,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/linux-x64@npm:0.21.5": - version: 0.21.5 - resolution: "@esbuild/linux-x64@npm:0.21.5" +"@esbuild/linux-x64@npm:0.24.0": + version: 0.24.0 + resolution: "@esbuild/linux-x64@npm:0.24.0" conditions: os=linux & cpu=x64 languageName: node linkType: hard @@ -370,13 +370,20 @@ __metadata: languageName: node linkType: hard -"@esbuild/netbsd-x64@npm:0.21.5": - version: 0.21.5 - resolution: "@esbuild/netbsd-x64@npm:0.21.5" +"@esbuild/netbsd-x64@npm:0.24.0": + version: 0.24.0 + resolution: "@esbuild/netbsd-x64@npm:0.24.0" conditions: os=netbsd & cpu=x64 languageName: node linkType: hard +"@esbuild/openbsd-arm64@npm:0.24.0": + version: 0.24.0 + resolution: "@esbuild/openbsd-arm64@npm:0.24.0" + conditions: os=openbsd & cpu=arm64 + languageName: node + linkType: hard + "@esbuild/openbsd-x64@npm:0.20.2": version: 0.20.2 resolution: "@esbuild/openbsd-x64@npm:0.20.2" @@ -384,9 +391,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/openbsd-x64@npm:0.21.5": - version: 0.21.5 - resolution: "@esbuild/openbsd-x64@npm:0.21.5" +"@esbuild/openbsd-x64@npm:0.24.0": + version: 0.24.0 + resolution: "@esbuild/openbsd-x64@npm:0.24.0" conditions: os=openbsd & cpu=x64 languageName: node linkType: hard @@ -398,9 +405,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/sunos-x64@npm:0.21.5": - version: 0.21.5 - resolution: "@esbuild/sunos-x64@npm:0.21.5" +"@esbuild/sunos-x64@npm:0.24.0": + version: 0.24.0 + resolution: "@esbuild/sunos-x64@npm:0.24.0" conditions: os=sunos & cpu=x64 languageName: node linkType: hard @@ -412,9 +419,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/win32-arm64@npm:0.21.5": - version: 0.21.5 - resolution: "@esbuild/win32-arm64@npm:0.21.5" +"@esbuild/win32-arm64@npm:0.24.0": + version: 0.24.0 + resolution: "@esbuild/win32-arm64@npm:0.24.0" conditions: os=win32 & cpu=arm64 languageName: node linkType: hard @@ -426,9 +433,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/win32-ia32@npm:0.21.5": - version: 0.21.5 - resolution: "@esbuild/win32-ia32@npm:0.21.5" +"@esbuild/win32-ia32@npm:0.24.0": + version: 0.24.0 + resolution: "@esbuild/win32-ia32@npm:0.24.0" conditions: os=win32 & cpu=ia32 languageName: node linkType: hard @@ -440,9 +447,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/win32-x64@npm:0.21.5": - version: 0.21.5 - resolution: "@esbuild/win32-x64@npm:0.21.5" +"@esbuild/win32-x64@npm:0.24.0": + version: 0.24.0 + resolution: "@esbuild/win32-x64@npm:0.24.0" conditions: os=win32 & cpu=x64 languageName: node linkType: hard @@ -1450,9 +1457,9 @@ __metadata: languageName: node linkType: hard -"@rollup/rollup-android-arm-eabi@npm:4.24.4": - version: 4.24.4 - resolution: "@rollup/rollup-android-arm-eabi@npm:4.24.4" +"@rollup/rollup-android-arm-eabi@npm:4.28.0": + version: 4.28.0 + resolution: "@rollup/rollup-android-arm-eabi@npm:4.28.0" conditions: os=android & cpu=arm languageName: node linkType: hard @@ -1464,9 +1471,9 @@ __metadata: languageName: node linkType: hard -"@rollup/rollup-android-arm64@npm:4.24.4": - version: 4.24.4 - resolution: "@rollup/rollup-android-arm64@npm:4.24.4" +"@rollup/rollup-android-arm64@npm:4.28.0": + version: 4.28.0 + resolution: "@rollup/rollup-android-arm64@npm:4.28.0" conditions: os=android & cpu=arm64 languageName: node linkType: hard @@ -1478,9 +1485,9 @@ __metadata: languageName: node linkType: hard -"@rollup/rollup-darwin-arm64@npm:4.24.4": - version: 4.24.4 - resolution: "@rollup/rollup-darwin-arm64@npm:4.24.4" +"@rollup/rollup-darwin-arm64@npm:4.28.0": + version: 4.28.0 + resolution: "@rollup/rollup-darwin-arm64@npm:4.28.0" conditions: os=darwin & cpu=arm64 languageName: node linkType: hard @@ -1492,23 +1499,23 @@ __metadata: languageName: node linkType: hard -"@rollup/rollup-darwin-x64@npm:4.24.4": - version: 4.24.4 - resolution: "@rollup/rollup-darwin-x64@npm:4.24.4" +"@rollup/rollup-darwin-x64@npm:4.28.0": + version: 4.28.0 + resolution: "@rollup/rollup-darwin-x64@npm:4.28.0" conditions: os=darwin & cpu=x64 languageName: node linkType: hard -"@rollup/rollup-freebsd-arm64@npm:4.24.4": - version: 4.24.4 - resolution: "@rollup/rollup-freebsd-arm64@npm:4.24.4" +"@rollup/rollup-freebsd-arm64@npm:4.28.0": + version: 4.28.0 + resolution: "@rollup/rollup-freebsd-arm64@npm:4.28.0" conditions: os=freebsd & cpu=arm64 languageName: node linkType: hard -"@rollup/rollup-freebsd-x64@npm:4.24.4": - version: 4.24.4 - resolution: "@rollup/rollup-freebsd-x64@npm:4.24.4" +"@rollup/rollup-freebsd-x64@npm:4.28.0": + version: 4.28.0 + resolution: "@rollup/rollup-freebsd-x64@npm:4.28.0" conditions: os=freebsd & cpu=x64 languageName: node linkType: hard @@ -1520,9 +1527,9 @@ __metadata: languageName: node linkType: hard -"@rollup/rollup-linux-arm-gnueabihf@npm:4.24.4": - version: 4.24.4 - resolution: "@rollup/rollup-linux-arm-gnueabihf@npm:4.24.4" +"@rollup/rollup-linux-arm-gnueabihf@npm:4.28.0": + version: 4.28.0 + resolution: "@rollup/rollup-linux-arm-gnueabihf@npm:4.28.0" conditions: os=linux & cpu=arm & libc=glibc languageName: node linkType: hard @@ -1534,9 +1541,9 @@ __metadata: languageName: node linkType: hard -"@rollup/rollup-linux-arm-musleabihf@npm:4.24.4": - version: 4.24.4 - resolution: "@rollup/rollup-linux-arm-musleabihf@npm:4.24.4" +"@rollup/rollup-linux-arm-musleabihf@npm:4.28.0": + version: 4.28.0 + resolution: "@rollup/rollup-linux-arm-musleabihf@npm:4.28.0" conditions: os=linux & cpu=arm & libc=musl languageName: node linkType: hard @@ -1548,9 +1555,9 @@ __metadata: languageName: node linkType: hard -"@rollup/rollup-linux-arm64-gnu@npm:4.24.4": - version: 4.24.4 - resolution: "@rollup/rollup-linux-arm64-gnu@npm:4.24.4" +"@rollup/rollup-linux-arm64-gnu@npm:4.28.0": + version: 4.28.0 + resolution: "@rollup/rollup-linux-arm64-gnu@npm:4.28.0" conditions: os=linux & cpu=arm64 & libc=glibc languageName: node linkType: hard @@ -1562,9 +1569,9 @@ __metadata: languageName: node linkType: hard -"@rollup/rollup-linux-arm64-musl@npm:4.24.4": - version: 4.24.4 - resolution: "@rollup/rollup-linux-arm64-musl@npm:4.24.4" +"@rollup/rollup-linux-arm64-musl@npm:4.28.0": + version: 4.28.0 + resolution: "@rollup/rollup-linux-arm64-musl@npm:4.28.0" conditions: os=linux & cpu=arm64 & libc=musl languageName: node linkType: hard @@ -1576,9 +1583,9 @@ __metadata: languageName: node linkType: hard -"@rollup/rollup-linux-powerpc64le-gnu@npm:4.24.4": - version: 4.24.4 - resolution: "@rollup/rollup-linux-powerpc64le-gnu@npm:4.24.4" +"@rollup/rollup-linux-powerpc64le-gnu@npm:4.28.0": + version: 4.28.0 + resolution: "@rollup/rollup-linux-powerpc64le-gnu@npm:4.28.0" conditions: os=linux & cpu=ppc64 & libc=glibc languageName: node linkType: hard @@ -1590,9 +1597,9 @@ __metadata: languageName: node linkType: hard -"@rollup/rollup-linux-riscv64-gnu@npm:4.24.4": - version: 4.24.4 - resolution: "@rollup/rollup-linux-riscv64-gnu@npm:4.24.4" +"@rollup/rollup-linux-riscv64-gnu@npm:4.28.0": + version: 4.28.0 + resolution: "@rollup/rollup-linux-riscv64-gnu@npm:4.28.0" conditions: os=linux & cpu=riscv64 & libc=glibc languageName: node linkType: hard @@ -1604,9 +1611,9 @@ __metadata: languageName: node linkType: hard -"@rollup/rollup-linux-s390x-gnu@npm:4.24.4": - version: 4.24.4 - resolution: "@rollup/rollup-linux-s390x-gnu@npm:4.24.4" +"@rollup/rollup-linux-s390x-gnu@npm:4.28.0": + version: 4.28.0 + resolution: "@rollup/rollup-linux-s390x-gnu@npm:4.28.0" conditions: os=linux & cpu=s390x & libc=glibc languageName: node linkType: hard @@ -1618,9 +1625,9 @@ __metadata: languageName: node linkType: hard -"@rollup/rollup-linux-x64-gnu@npm:4.24.4": - version: 4.24.4 - resolution: "@rollup/rollup-linux-x64-gnu@npm:4.24.4" +"@rollup/rollup-linux-x64-gnu@npm:4.28.0": + version: 4.28.0 + resolution: "@rollup/rollup-linux-x64-gnu@npm:4.28.0" conditions: os=linux & cpu=x64 & libc=glibc languageName: node linkType: hard @@ -1632,9 +1639,9 @@ __metadata: languageName: node linkType: hard -"@rollup/rollup-linux-x64-musl@npm:4.24.4": - version: 4.24.4 - resolution: "@rollup/rollup-linux-x64-musl@npm:4.24.4" +"@rollup/rollup-linux-x64-musl@npm:4.28.0": + version: 4.28.0 + resolution: "@rollup/rollup-linux-x64-musl@npm:4.28.0" conditions: os=linux & cpu=x64 & libc=musl languageName: node linkType: hard @@ -1646,9 +1653,9 @@ __metadata: languageName: node linkType: hard -"@rollup/rollup-win32-arm64-msvc@npm:4.24.4": - version: 4.24.4 - resolution: "@rollup/rollup-win32-arm64-msvc@npm:4.24.4" +"@rollup/rollup-win32-arm64-msvc@npm:4.28.0": + version: 4.28.0 + resolution: "@rollup/rollup-win32-arm64-msvc@npm:4.28.0" conditions: os=win32 & cpu=arm64 languageName: node linkType: hard @@ -1660,9 +1667,9 @@ __metadata: languageName: node linkType: hard -"@rollup/rollup-win32-ia32-msvc@npm:4.24.4": - version: 4.24.4 - resolution: "@rollup/rollup-win32-ia32-msvc@npm:4.24.4" +"@rollup/rollup-win32-ia32-msvc@npm:4.28.0": + version: 4.28.0 + resolution: "@rollup/rollup-win32-ia32-msvc@npm:4.28.0" conditions: os=win32 & cpu=ia32 languageName: node linkType: hard @@ -1674,9 +1681,9 @@ __metadata: languageName: node linkType: hard -"@rollup/rollup-win32-x64-msvc@npm:4.24.4": - version: 4.24.4 - resolution: "@rollup/rollup-win32-x64-msvc@npm:4.24.4" +"@rollup/rollup-win32-x64-msvc@npm:4.28.0": + version: 4.28.0 + resolution: "@rollup/rollup-win32-x64-msvc@npm:4.28.0" conditions: os=win32 & cpu=x64 languageName: node linkType: hard @@ -1732,12 +1739,12 @@ __metadata: languageName: node linkType: hard -"@types/node@npm:^22.9.0": - version: 22.9.0 - resolution: "@types/node@npm:22.9.0" +"@types/node@npm:^22.10.1": + version: 22.10.1 + resolution: "@types/node@npm:22.10.1" dependencies: - undici-types: "npm:~6.19.8" - checksum: 10/a7df3426891868b0f5fb03e46aeddd8446178233521c624a44531c92a040cf08a82d8235f7e1e02af731fd16984665d4d71f3418caf9c2788313b10f040d615d + undici-types: "npm:~6.20.0" + checksum: 10/c802a526da2f3fa3ccefd00a71244e7cb825329951719e79e8fec62b1dbc2855388c830489770611584665ce10be23c05ed585982038b24924e1ba2c2cce03fd languageName: node linkType: hard @@ -1835,14 +1842,14 @@ __metadata: dependencies: "@ianvs/prettier-plugin-sort-imports": "npm:^4.4.0" "@napi-rs/cli": "npm:^3.0.0-alpha.64" - "@types/node": "npm:^22.9.0" + "@types/node": "npm:^22.10.1" "@types/uuid": "npm:^10.0.0" - prettier: "npm:^3.3.3" + prettier: "npm:^3.4.1" prettier-plugin-packagejson: "npm:^2.5.3" typescript: "npm:^5.7.2" uuid: "npm:^11.0.3" viem: "npm:^2.21.47" - vite: "npm:^5.4.11" + vite: "npm:^6.0.1" vite-tsconfig-paths: "npm:^5.1.2" vitest: "npm:^2.1.5" languageName: unknown @@ -2291,33 +2298,34 @@ __metadata: languageName: node linkType: hard -"esbuild@npm:^0.21.3": - version: 0.21.5 - resolution: "esbuild@npm:0.21.5" - dependencies: - "@esbuild/aix-ppc64": "npm:0.21.5" - "@esbuild/android-arm": "npm:0.21.5" - "@esbuild/android-arm64": "npm:0.21.5" - "@esbuild/android-x64": "npm:0.21.5" - "@esbuild/darwin-arm64": "npm:0.21.5" - "@esbuild/darwin-x64": "npm:0.21.5" - "@esbuild/freebsd-arm64": "npm:0.21.5" - "@esbuild/freebsd-x64": "npm:0.21.5" - "@esbuild/linux-arm": "npm:0.21.5" - "@esbuild/linux-arm64": "npm:0.21.5" - "@esbuild/linux-ia32": "npm:0.21.5" - "@esbuild/linux-loong64": "npm:0.21.5" - "@esbuild/linux-mips64el": "npm:0.21.5" - "@esbuild/linux-ppc64": "npm:0.21.5" - "@esbuild/linux-riscv64": "npm:0.21.5" - "@esbuild/linux-s390x": "npm:0.21.5" - "@esbuild/linux-x64": "npm:0.21.5" - "@esbuild/netbsd-x64": "npm:0.21.5" - "@esbuild/openbsd-x64": "npm:0.21.5" - "@esbuild/sunos-x64": "npm:0.21.5" - "@esbuild/win32-arm64": "npm:0.21.5" - "@esbuild/win32-ia32": "npm:0.21.5" - "@esbuild/win32-x64": "npm:0.21.5" +"esbuild@npm:^0.24.0": + version: 0.24.0 + resolution: "esbuild@npm:0.24.0" + dependencies: + "@esbuild/aix-ppc64": "npm:0.24.0" + "@esbuild/android-arm": "npm:0.24.0" + "@esbuild/android-arm64": "npm:0.24.0" + "@esbuild/android-x64": "npm:0.24.0" + "@esbuild/darwin-arm64": "npm:0.24.0" + "@esbuild/darwin-x64": "npm:0.24.0" + "@esbuild/freebsd-arm64": "npm:0.24.0" + "@esbuild/freebsd-x64": "npm:0.24.0" + "@esbuild/linux-arm": "npm:0.24.0" + "@esbuild/linux-arm64": "npm:0.24.0" + "@esbuild/linux-ia32": "npm:0.24.0" + "@esbuild/linux-loong64": "npm:0.24.0" + "@esbuild/linux-mips64el": "npm:0.24.0" + "@esbuild/linux-ppc64": "npm:0.24.0" + "@esbuild/linux-riscv64": "npm:0.24.0" + "@esbuild/linux-s390x": "npm:0.24.0" + "@esbuild/linux-x64": "npm:0.24.0" + "@esbuild/netbsd-x64": "npm:0.24.0" + "@esbuild/openbsd-arm64": "npm:0.24.0" + "@esbuild/openbsd-x64": "npm:0.24.0" + "@esbuild/sunos-x64": "npm:0.24.0" + "@esbuild/win32-arm64": "npm:0.24.0" + "@esbuild/win32-ia32": "npm:0.24.0" + "@esbuild/win32-x64": "npm:0.24.0" dependenciesMeta: "@esbuild/aix-ppc64": optional: true @@ -2355,6 +2363,8 @@ __metadata: optional: true "@esbuild/netbsd-x64": optional: true + "@esbuild/openbsd-arm64": + optional: true "@esbuild/openbsd-x64": optional: true "@esbuild/sunos-x64": @@ -2367,7 +2377,7 @@ __metadata: optional: true bin: esbuild: bin/esbuild - checksum: 10/d2ff2ca84d30cce8e871517374d6c2290835380dc7cd413b2d49189ed170d45e407be14de2cb4794cf76f75cf89955c4714726ebd3de7444b3046f5cab23ab6b + checksum: 10/500f83a1216d6548053007b85c070d8293395db344605b17418c6cf1217e5e8d338fa77fc8af27c23faa121c5528e5b0004d46d3a0cdeb87d48f1b5fa0164bc5 languageName: node linkType: hard @@ -3070,7 +3080,7 @@ __metadata: languageName: node linkType: hard -"picocolors@npm:^1.1.0": +"picocolors@npm:^1.1.1": version: 1.1.1 resolution: "picocolors@npm:1.1.1" checksum: 10/e1cf46bf84886c79055fdfa9dcb3e4711ad259949e3565154b004b260cd356c5d54b31a1437ce9782624bf766272fe6b0154f5f0c744fb7af5d454d2b60db045 @@ -3095,14 +3105,14 @@ __metadata: languageName: node linkType: hard -"postcss@npm:^8.4.43": - version: 8.4.47 - resolution: "postcss@npm:8.4.47" +"postcss@npm:^8.4.49": + version: 8.4.49 + resolution: "postcss@npm:8.4.49" dependencies: nanoid: "npm:^3.3.7" - picocolors: "npm:^1.1.0" + picocolors: "npm:^1.1.1" source-map-js: "npm:^1.2.1" - checksum: 10/f2b50ba9b6fcb795232b6bb20de7cdc538c0025989a8ed9c4438d1960196ba3b7eaff41fdb1a5c701b3504651ea87aeb685577707f0ae4d6ce6f3eae5df79a81 + checksum: 10/28fe1005b1339870e0a5006375ba5ac1213fd69800f79e7db09c398e074421ba6e162898e94f64942fed554037fd292db3811d87835d25ab5ef7f3c9daacb6ca languageName: node linkType: hard @@ -3121,12 +3131,12 @@ __metadata: languageName: node linkType: hard -"prettier@npm:^3.3.3": - version: 3.3.3 - resolution: "prettier@npm:3.3.3" +"prettier@npm:^3.4.1": + version: 3.4.1 + resolution: "prettier@npm:3.4.1" bin: prettier: bin/prettier.cjs - checksum: 10/5beac1f30b5b40162532b8e2f7c3a4eb650910a2695e9c8512a62ffdc09dae93190c29db9107fa7f26d1b6c71aad3628ecb9b5de1ecb0911191099be109434d7 + checksum: 10/1ee4d1b1a9b6761cbb847cd81b9d87e51a0f4b2a4d5fe5755627c24828afe057a7ee9b764c3ee777d84abd46218d173d8a204ee9cb3acdd321ff9a6b25f99c1c languageName: node linkType: hard @@ -3238,28 +3248,28 @@ __metadata: languageName: node linkType: hard -"rollup@npm:^4.20.0": - version: 4.24.4 - resolution: "rollup@npm:4.24.4" - dependencies: - "@rollup/rollup-android-arm-eabi": "npm:4.24.4" - "@rollup/rollup-android-arm64": "npm:4.24.4" - "@rollup/rollup-darwin-arm64": "npm:4.24.4" - "@rollup/rollup-darwin-x64": "npm:4.24.4" - "@rollup/rollup-freebsd-arm64": "npm:4.24.4" - "@rollup/rollup-freebsd-x64": "npm:4.24.4" - "@rollup/rollup-linux-arm-gnueabihf": "npm:4.24.4" - "@rollup/rollup-linux-arm-musleabihf": "npm:4.24.4" - "@rollup/rollup-linux-arm64-gnu": "npm:4.24.4" - "@rollup/rollup-linux-arm64-musl": "npm:4.24.4" - "@rollup/rollup-linux-powerpc64le-gnu": "npm:4.24.4" - "@rollup/rollup-linux-riscv64-gnu": "npm:4.24.4" - "@rollup/rollup-linux-s390x-gnu": "npm:4.24.4" - "@rollup/rollup-linux-x64-gnu": "npm:4.24.4" - "@rollup/rollup-linux-x64-musl": "npm:4.24.4" - "@rollup/rollup-win32-arm64-msvc": "npm:4.24.4" - "@rollup/rollup-win32-ia32-msvc": "npm:4.24.4" - "@rollup/rollup-win32-x64-msvc": "npm:4.24.4" +"rollup@npm:^4.23.0": + version: 4.28.0 + resolution: "rollup@npm:4.28.0" + dependencies: + "@rollup/rollup-android-arm-eabi": "npm:4.28.0" + "@rollup/rollup-android-arm64": "npm:4.28.0" + "@rollup/rollup-darwin-arm64": "npm:4.28.0" + "@rollup/rollup-darwin-x64": "npm:4.28.0" + "@rollup/rollup-freebsd-arm64": "npm:4.28.0" + "@rollup/rollup-freebsd-x64": "npm:4.28.0" + "@rollup/rollup-linux-arm-gnueabihf": "npm:4.28.0" + "@rollup/rollup-linux-arm-musleabihf": "npm:4.28.0" + "@rollup/rollup-linux-arm64-gnu": "npm:4.28.0" + "@rollup/rollup-linux-arm64-musl": "npm:4.28.0" + "@rollup/rollup-linux-powerpc64le-gnu": "npm:4.28.0" + "@rollup/rollup-linux-riscv64-gnu": "npm:4.28.0" + "@rollup/rollup-linux-s390x-gnu": "npm:4.28.0" + "@rollup/rollup-linux-x64-gnu": "npm:4.28.0" + "@rollup/rollup-linux-x64-musl": "npm:4.28.0" + "@rollup/rollup-win32-arm64-msvc": "npm:4.28.0" + "@rollup/rollup-win32-ia32-msvc": "npm:4.28.0" + "@rollup/rollup-win32-x64-msvc": "npm:4.28.0" "@types/estree": "npm:1.0.6" fsevents: "npm:~2.3.2" dependenciesMeta: @@ -3303,7 +3313,7 @@ __metadata: optional: true bin: rollup: dist/bin/rollup - checksum: 10/a8ffde17d7cd5d9eaaf91bb025de83329b034771254d34b977df3f294e0992f6d89a444a0c8e9d73c8721d60cedf5be32fa8bd6f157874700bb8043c61ca660a + checksum: 10/e604ff8d866818fff5b15864eab09011b497117774de413a566c17bda5fc6878ea101b6124421e29d7c3478280b8e6a864b2b1f1c7c4422e7fe31cb6846a09fc languageName: node linkType: hard @@ -3661,10 +3671,10 @@ __metadata: languageName: node linkType: hard -"undici-types@npm:~6.19.8": - version: 6.19.8 - resolution: "undici-types@npm:6.19.8" - checksum: 10/cf0b48ed4fc99baf56584afa91aaffa5010c268b8842f62e02f752df209e3dea138b372a60a963b3b2576ed932f32329ce7ddb9cb5f27a6c83040d8cd74b7a70 +"undici-types@npm:~6.20.0": + version: 6.20.0 + resolution: "undici-types@npm:6.20.0" + checksum: 10/583ac7bbf4ff69931d3985f4762cde2690bb607844c16a5e2fbb92ed312fe4fa1b365e953032d469fa28ba8b224e88a595f0b10a449332f83fa77c695e567dbe languageName: node linkType: hard @@ -3795,29 +3805,34 @@ __metadata: languageName: node linkType: hard -"vite@npm:^5.4.11": - version: 5.4.11 - resolution: "vite@npm:5.4.11" +"vite@npm:^6.0.1": + version: 6.0.1 + resolution: "vite@npm:6.0.1" dependencies: - esbuild: "npm:^0.21.3" + esbuild: "npm:^0.24.0" fsevents: "npm:~2.3.3" - postcss: "npm:^8.4.43" - rollup: "npm:^4.20.0" + postcss: "npm:^8.4.49" + rollup: "npm:^4.23.0" peerDependencies: - "@types/node": ^18.0.0 || >=20.0.0 + "@types/node": ^18.0.0 || ^20.0.0 || >=22.0.0 + jiti: ">=1.21.0" less: "*" lightningcss: ^1.21.0 sass: "*" sass-embedded: "*" stylus: "*" sugarss: "*" - terser: ^5.4.0 + terser: ^5.16.0 + tsx: ^4.8.1 + yaml: ^2.4.2 dependenciesMeta: fsevents: optional: true peerDependenciesMeta: "@types/node": optional: true + jiti: + optional: true less: optional: true lightningcss: @@ -3832,9 +3847,13 @@ __metadata: optional: true terser: optional: true + tsx: + optional: true + yaml: + optional: true bin: vite: bin/vite.js - checksum: 10/719c4dea896e9547958643354003c8c9ea98e5367196d98f5f46cffb3ec963fead3ea5853f5af941c79bbfb73583dec19bbb0d28d2f644b95d7f59c55e22919d + checksum: 10/a42bf6e92425920335175b59d0e4d98cae8f2bfa473c1e32bd62e1feb4b808341992f92632d1883103351f8e9ec4ae53179266b0a815731e9c109a2e3768cde5 languageName: node linkType: hard From 96dbb65a7d6deb4971b9bb97675e26ede945c518 Mon Sep 17 00:00:00 2001 From: Andrew Plaza Date: Mon, 2 Dec 2024 12:35:52 -0500 Subject: [PATCH 18/46] fix clippy for rust 1.83 (#1354) * fix clippy for rust 1.83 * disable clippy for generated bindings code --- Cargo.lock | 54 ++++++++++--------- Cargo.toml | 4 +- bindings_ffi/src/lib.rs | 7 ++- xmtp_cryptography/src/basic_credential.rs | 2 +- xmtp_debug/src/app/store.rs | 15 ++++-- xmtp_debug/src/app/store/groups.rs | 2 +- xmtp_debug/src/app/store/identity.rs | 2 +- xmtp_debug/src/app/store/metadata.rs | 2 +- xmtp_debug/src/app/types.rs | 12 +++-- xmtp_mls/src/groups/group_metadata.rs | 1 - xmtp_mls/src/groups/group_mutable_metadata.rs | 4 +- xmtp_mls/src/groups/mls_sync.rs | 4 +- xmtp_mls/src/groups/mod.rs | 12 ++--- xmtp_mls/src/xmtp_openmls_provider.rs | 2 +- xmtp_proto/src/api_client.rs | 6 ++- xmtp_v2/src/k256_helper.rs | 6 +-- 16 files changed, 76 insertions(+), 59 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c6e3452c5..f192de44a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1262,7 +1262,7 @@ dependencies = [ [[package]] name = "diesel-wasm-sqlite" version = "0.0.1" -source = "git+https://github.com/xmtp/diesel-wasm-sqlite?branch=main#df437741e19c4e1bad27af8d0680479a73472332" +source = "git+https://github.com/xmtp/diesel-wasm-sqlite?branch=main#1eb449b79ed50e00042efb0bc9ca0a9f302ba7ef" dependencies = [ "diesel", "diesel_derives", @@ -3051,10 +3051,11 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.72" +version = "0.3.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a88f1bda2bd75b0452a14784937d796722fdebfe50df998aeb3f0b7603019a9" +checksum = "a865e038f7f6ed956f788f0d7d60c541fff74c7bd74272c5d4cf15c63743e705" dependencies = [ + "once_cell", "wasm-bindgen", ] @@ -3170,7 +3171,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4" dependencies = [ "cfg-if", - "windows-targets 0.48.5", + "windows-targets 0.52.6", ] [[package]] @@ -4453,7 +4454,7 @@ checksum = "0c1318b19085f08681016926435853bbf7858f9c082d0999b80550ff5d9abe15" dependencies = [ "bytes", "heck", - "itertools 0.10.5", + "itertools 0.13.0", "log", "multimap", "once_cell", @@ -4473,7 +4474,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e9552f850d5f0964a4e4d0bf306459ac29323ddfbae05e35a7c0d35cb0803cc5" dependencies = [ "anyhow", - "itertools 0.10.5", + "itertools 0.13.0", "proc-macro2", "quote", "syn 2.0.87", @@ -6628,9 +6629,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.95" +version = "0.2.97" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "128d1e363af62632b8eb57219c8fd7877144af57558fb2ef0368d0087bddeb2e" +checksum = "d15e63b4482863c109d70a7b8706c1e364eb6ea449b201a76c5b89cedcec2d5c" dependencies = [ "cfg-if", "once_cell", @@ -6639,9 +6640,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.95" +version = "0.2.97" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb6dd4d3ca0ddffd1dd1c9c04f94b868c37ff5fac97c30b97cff2d74fce3a358" +checksum = "8d36ef12e3aaca16ddd3f67922bc63e48e953f126de60bd33ccc0101ef9998cd" dependencies = [ "bumpalo", "log", @@ -6654,21 +6655,22 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.45" +version = "0.4.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc7ec4f8827a71586374db3e87abdb5a2bb3a15afed140221307c3ec06b1f63b" +checksum = "9dfaf8f50e5f293737ee323940c7d8b08a66a95a419223d9f41610ca08b0833d" dependencies = [ "cfg-if", "js-sys", + "once_cell", "wasm-bindgen", "web-sys", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.95" +version = "0.2.97" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e79384be7f8f5a9dd5d7167216f022090cf1f9ec128e6e6a482a2cb5c5422c56" +checksum = "705440e08b42d3e4b36de7d66c944be628d579796b8090bfa3471478a2260051" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -6676,9 +6678,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.95" +version = "0.2.97" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68" +checksum = "98c9ae5a76e46f4deecd0f0255cc223cfa18dc9b261213b8aa0c7b36f61b3f1d" dependencies = [ "proc-macro2", "quote", @@ -6689,19 +6691,19 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.95" +version = "0.2.97" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d" +checksum = "6ee99da9c5ba11bd675621338ef6fa52296b76b83305e9b6e5c77d4c286d6d49" [[package]] name = "wasm-bindgen-test" -version = "0.3.45" +version = "0.3.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d381749acb0943d357dcbd8f0b100640679883fcdeeef04def49daf8d33a5426" +checksum = "3d919bb60ebcecb9160afee6c71b43a58a4f0517a2de0054cd050d02cec08201" dependencies = [ - "console_error_panic_hook", "js-sys", "minicov", + "once_cell", "scoped-tls", "wasm-bindgen", "wasm-bindgen-futures", @@ -6710,9 +6712,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-test-macro" -version = "0.3.45" +version = "0.3.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c97b2ef2c8d627381e51c071c2ab328eac606d3f69dd82bcbca20a9e389d95f0" +checksum = "222ebde6ea87fbfa6bdd2e9f1fd8a91d60aee5db68792632176c4e16a74fc7d8" dependencies = [ "proc-macro2", "quote", @@ -6749,9 +6751,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.72" +version = "0.3.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6488b90108c040df0fe62fa815cbdee25124641df01814dd7282749234c6112" +checksum = "a98bc3c33f0fe7e59ad7cd041b89034fa82a7c2d4365ca538dda6cdaf513863c" dependencies = [ "js-sys", "wasm-bindgen", @@ -6813,7 +6815,7 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" dependencies = [ - "windows-sys 0.48.0", + "windows-sys 0.59.0", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 28432cadc..5398ef292 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -75,8 +75,8 @@ diesel-wasm-sqlite = "0.0.1" diesel_migrations = { version = "2.2", default-features = false } parking_lot = "0.12.3" wasm-bindgen-futures = "0.4" -wasm-bindgen = "=0.2.95" -wasm-bindgen-test = "0.3.45" +wasm-bindgen = "=0.2.97" +wasm-bindgen-test = "0.3.47" gloo-timers = "0.3" web-sys = "0.3" js-sys = "0.3" diff --git a/bindings_ffi/src/lib.rs b/bindings_ffi/src/lib.rs index 3d16186be..e60e1fe34 100755 --- a/bindings_ffi/src/lib.rs +++ b/bindings_ffi/src/lib.rs @@ -11,7 +11,12 @@ use logger::FfiLogger; pub use mls::*; use std::error::Error; -uniffi::include_scaffolding!("xmtpv3"); +pub use ffi::*; +#[allow(clippy::all)] +mod ffi { + use super::*; + uniffi::include_scaffolding!("xmtpv3"); +} #[derive(uniffi::Error, thiserror::Error, Debug)] #[uniffi(flat_error)] diff --git a/xmtp_cryptography/src/basic_credential.rs b/xmtp_cryptography/src/basic_credential.rs index 3f76cb33b..5e7e02337 100644 --- a/xmtp_cryptography/src/basic_credential.rs +++ b/xmtp_cryptography/src/basic_credential.rs @@ -159,7 +159,7 @@ impl Signer for XmtpInstallationCredential { } // The signer here must maintain compatability with `SignatureKeyPair` -impl<'a> Signer for &'a XmtpInstallationCredential { +impl Signer for &XmtpInstallationCredential { fn sign(&self, payload: &[u8]) -> Result, signatures::SignerError> { SignatureKeyPair::from(*self).sign(payload) } diff --git a/xmtp_debug/src/app/store.rs b/xmtp_debug/src/app/store.rs index 8fd0c85df..6d5fc4608 100644 --- a/xmtp_debug/src/app/store.rs +++ b/xmtp_debug/src/app/store.rs @@ -78,11 +78,14 @@ impl Writable for NetworkKey { } impl redb::Value for NetworkKey { - type SelfType<'a> = NetworkKey + type SelfType<'a> + = NetworkKey where Self: 'a; - type AsBytes<'a> = Vec // TODO: It _has_ be possible to make this a const [u8; N] somehow. + type AsBytes<'a> + = Vec + // TODO: It _has_ be possible to make this a const [u8; N] somehow. // We're not allowed to use `size_of::>()` yet, even though size_of and N are // both constant where @@ -197,7 +200,7 @@ pub struct KeyValueStore<'db, Storage> { store: Storage, } -impl<'db, Storage> KeyValueStore<'db, Storage> { +impl KeyValueStore<'_, Storage> { fn apply_write(&self, op: impl FnOnce(&WriteTransaction) -> Result<()>) -> Result<()> { use DatabaseOrTransaction::*; match self.db { @@ -376,11 +379,13 @@ pub struct Metadata { } impl redb::Value for Metadata { - type SelfType<'a> = Metadata + type SelfType<'a> + = Metadata where Self: 'a; - type AsBytes<'a> = [u8; size_of::()] + type AsBytes<'a> + = [u8; size_of::()] where Self: 'a; diff --git a/xmtp_debug/src/app/store/groups.rs b/xmtp_debug/src/app/store/groups.rs index f9d6d5140..a10c69d98 100644 --- a/xmtp_debug/src/app/store/groups.rs +++ b/xmtp_debug/src/app/store/groups.rs @@ -23,7 +23,7 @@ impl super::DeriveKey for Group { } } -impl<'a> super::DeriveKey for &'a Group { +impl super::DeriveKey for &Group { fn key(&self, network: u64) -> GroupKey { GroupKey { network, diff --git a/xmtp_debug/src/app/store/identity.rs b/xmtp_debug/src/app/store/identity.rs index 674aed515..6a5a468bb 100644 --- a/xmtp_debug/src/app/store/identity.rs +++ b/xmtp_debug/src/app/store/identity.rs @@ -33,7 +33,7 @@ impl super::DeriveKey for Identity { } } -impl<'a> super::DeriveKey for &'a Identity { +impl super::DeriveKey for &Identity { fn key(&self, network: u64) -> IdentityKey { IdentityKey { network, diff --git a/xmtp_debug/src/app/store/metadata.rs b/xmtp_debug/src/app/store/metadata.rs index bf44f1909..7bae6db65 100644 --- a/xmtp_debug/src/app/store/metadata.rs +++ b/xmtp_debug/src/app/store/metadata.rs @@ -96,7 +96,7 @@ impl super::DeriveKey for Metadata { } } -impl<'a> super::DeriveKey for &'a Metadata { +impl super::DeriveKey for &Metadata { fn key(&self, network: u64) -> MetaKey { MetaKey { network, diff --git a/xmtp_debug/src/app/types.rs b/xmtp_debug/src/app/types.rs index 28d39e2e0..073f26dce 100644 --- a/xmtp_debug/src/app/types.rs +++ b/xmtp_debug/src/app/types.rs @@ -135,11 +135,13 @@ struct ForeignIdentity { } impl redb::Value for Identity { - type SelfType<'a> = Identity + type SelfType<'a> + = Identity where Self: 'a; - type AsBytes<'a> = [u8; size_of::()] + type AsBytes<'a> + = [u8; size_of::()] where Self: 'a; @@ -184,11 +186,13 @@ pub struct Group { } impl redb::Value for Group { - type SelfType<'a> = Group + type SelfType<'a> + = Group where Self: 'a; - type AsBytes<'a> = Vec + type AsBytes<'a> + = Vec where Self: 'a; diff --git a/xmtp_mls/src/groups/group_metadata.rs b/xmtp_mls/src/groups/group_metadata.rs index 528e0e9ce..e06c7e6a1 100644 --- a/xmtp_mls/src/groups/group_metadata.rs +++ b/xmtp_mls/src/groups/group_metadata.rs @@ -106,7 +106,6 @@ impl TryFrom<&Extensions> for GroupMetadata { * *DM*: A conversation between 2 members with simplified permissions * *Sync*: A conversation between all the devices of a single member with simplified permissions */ - impl From for ConversationTypeProto { fn from(value: ConversationType) -> Self { match value { diff --git a/xmtp_mls/src/groups/group_mutable_metadata.rs b/xmtp_mls/src/groups/group_mutable_metadata.rs index 36facf8d5..2db12769e 100644 --- a/xmtp_mls/src/groups/group_mutable_metadata.rs +++ b/xmtp_mls/src/groups/group_mutable_metadata.rs @@ -220,12 +220,12 @@ impl TryFrom for GroupMutableMetadata { fn try_from(value: GroupMutableMetadataProto) -> Result { let admin_list = value .admin_list - .ok_or_else(|| GroupMutableMetadataError::MissingMetadataField)? + .ok_or(GroupMutableMetadataError::MissingMetadataField)? .inbox_ids; let super_admin_list = value .super_admin_list - .ok_or_else(|| GroupMutableMetadataError::MissingMetadataField)? + .ok_or(GroupMutableMetadataError::MissingMetadataField)? .inbox_ids; Ok(Self::new( diff --git a/xmtp_mls/src/groups/mls_sync.rs b/xmtp_mls/src/groups/mls_sync.rs index e52b85547..778c41c4a 100644 --- a/xmtp_mls/src/groups/mls_sync.rs +++ b/xmtp_mls/src/groups/mls_sync.rs @@ -1353,10 +1353,10 @@ fn extract_message_sender( } let basic_credential = BasicCredential::try_from(decrypted_message.credential().clone())?; - return Err(GroupMessageProcessingError::InvalidSender { + Err(GroupMessageProcessingError::InvalidSender { message_time_ns: message_created_ns, credential: basic_credential.identity().to_vec(), - }); + }) } // Takes UpdateGroupMembershipIntentData and applies it to the openmls group diff --git a/xmtp_mls/src/groups/mod.rs b/xmtp_mls/src/groups/mod.rs index 143ca5f28..bd0b3807b 100644 --- a/xmtp_mls/src/groups/mod.rs +++ b/xmtp_mls/src/groups/mod.rs @@ -2419,7 +2419,7 @@ pub(crate) mod tests { .attributes .get(&MetadataField::GroupName.to_string()) .unwrap() - .eq("")); + .is_empty()); // Add bola to the group amal_group @@ -2441,7 +2441,7 @@ pub(crate) mod tests { .attributes .get(&MetadataField::GroupName.to_string()) .unwrap() - .eq("")); + .is_empty()); // Update group name amal_group @@ -2510,7 +2510,7 @@ pub(crate) mod tests { .attributes .get(&MetadataField::GroupImageUrlSquare.to_string()) .unwrap() - .eq("")); + .is_empty()); // Update group name amal_group @@ -2549,7 +2549,7 @@ pub(crate) mod tests { .attributes .get(&MetadataField::GroupPinnedFrameUrl.to_string()) .unwrap() - .eq("")); + .is_empty()); // Update group name amal_group @@ -2590,7 +2590,7 @@ pub(crate) mod tests { .attributes .get(&MetadataField::GroupName.to_string()) .unwrap() - .eq("")); + .is_empty()); // Add bola to the group amal_group @@ -2611,7 +2611,7 @@ pub(crate) mod tests { .attributes .get(&MetadataField::GroupName.to_string()) .unwrap() - .eq("")); + .is_empty()); // Update group name amal_group diff --git a/xmtp_mls/src/xmtp_openmls_provider.rs b/xmtp_mls/src/xmtp_openmls_provider.rs index cfe695fd6..77dd51494 100644 --- a/xmtp_mls/src/xmtp_openmls_provider.rs +++ b/xmtp_mls/src/xmtp_openmls_provider.rs @@ -45,7 +45,7 @@ where } } -impl<'a, C> OpenMlsProvider for &'a XmtpOpenMlsProviderPrivate +impl OpenMlsProvider for &XmtpOpenMlsProviderPrivate where C: diesel::Connection + diesel::connection::LoadConnection, { diff --git a/xmtp_proto/src/api_client.rs b/xmtp_proto/src/api_client.rs index d531bb867..03afb8df3 100644 --- a/xmtp_proto/src/api_client.rs +++ b/xmtp_proto/src/api_client.rs @@ -311,11 +311,13 @@ impl XmtpMlsStreams for Box where T: XmtpMlsStreams + Sync + ?Sized, { - type GroupMessageStream<'a> = ::GroupMessageStream<'a> + type GroupMessageStream<'a> + = ::GroupMessageStream<'a> where Self: 'a; - type WelcomeMessageStream<'a> = ::WelcomeMessageStream<'a> + type WelcomeMessageStream<'a> + = ::WelcomeMessageStream<'a> where Self: 'a; diff --git a/xmtp_v2/src/k256_helper.rs b/xmtp_v2/src/k256_helper.rs index 338ab2e28..ae671100e 100644 --- a/xmtp_v2/src/k256_helper.rs +++ b/xmtp_v2/src/k256_helper.rs @@ -9,9 +9,9 @@ use sha3::Keccak256; /// diffie_hellman - compute the shared secret between a secret key and a public key /// NOTE: This is a custom implementation of the diffie_hellman operation /// because RustCrypto hides the `y` coordinate from visibility when constructing a SharedSecret. - +/// /// [Read more](https://github.com/RustCrypto/traits/blob/d57b54b9fcf5b28745547cb9fef313ab09780918/elliptic-curve/src/ecdh.rs#L60) - +/// /// XMTP uses the entire point in uncompressed format as secret material fn diffie_hellman(secret_key: &SecretKey, public_key: &PublicKey) -> Result, String> { // Get the public projective point from the public key @@ -20,7 +20,7 @@ fn diffie_hellman(secret_key: &SecretKey, public_key: &PublicKey) -> Result Date: Mon, 2 Dec 2024 11:45:05 -0600 Subject: [PATCH 19/46] Switch to ubuntu 22.04 for node builds (#1356) * Switch to ubuntu 22.04 for node builds * Add note about publishing node bindings --- .github/workflows/release-node-bindings.yml | 2 +- bindings_node/README.md | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/release-node-bindings.yml b/.github/workflows/release-node-bindings.yml index 57f92afc1..31e81cc15 100644 --- a/.github/workflows/release-node-bindings.yml +++ b/.github/workflows/release-node-bindings.yml @@ -5,7 +5,7 @@ on: jobs: build-linux: - runs-on: warp-ubuntu-latest-x64-16x + runs-on: warp-ubuntu-2204-x64-16x strategy: fail-fast: false matrix: diff --git a/bindings_node/README.md b/bindings_node/README.md index 6ffd0180a..750a5e7bf 100644 --- a/bindings_node/README.md +++ b/bindings_node/README.md @@ -13,3 +13,7 @@ ## Testing Before running the test suite, a local XMTP node must be running. This can be achieved by running `./dev/up` at the root of this repository. Docker is required. + +# Publishing + +To release a new version of the bindings, update the version in `package.json` with the appropriate semver value and add an entry to the CHANGELOG.md file. Once merged, manually trigger the `Release Node Bindings` workflow to build and publish the bindings. From 0dea885b18f5749f869a4eca137dcdf6cde8057b Mon Sep 17 00:00:00 2001 From: Ry Racherbaumer Date: Mon, 2 Dec 2024 12:01:27 -0600 Subject: [PATCH 20/46] Prepare node bindings release (#1357) --- bindings_node/CHANGELOG.md | 12 ++++++++---- bindings_node/package.json | 2 +- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/bindings_node/CHANGELOG.md b/bindings_node/CHANGELOG.md index 0170dc8f4..9c6b66051 100644 --- a/bindings_node/CHANGELOG.md +++ b/bindings_node/CHANGELOG.md @@ -1,17 +1,21 @@ # @xmtp/node-bindings +## 0.0.27 + +- Switched to Ubuntu 22.04 for builds + ## 0.0.25 - - Fixed streaming by adding `napi4` feature to napi-rs +- Fixed streaming by adding `napi4` feature to napi-rs ## 0.0.24 - - Fixed using `Vec` instead rust `Uint8Array` type in `is_installation_authorized` +- Fixed using `Vec` instead rust `Uint8Array` type in `is_installation_authorized` ## 0.0.23 - - Added `is_installation_authorized` to `Client` - - Added `is_address_authorized` to `Client` +- Added `is_installation_authorized` to `Client` +- Added `is_address_authorized` to `Client` ## 0.0.22 diff --git a/bindings_node/package.json b/bindings_node/package.json index d859c7816..ba8c0e33f 100644 --- a/bindings_node/package.json +++ b/bindings_node/package.json @@ -1,6 +1,6 @@ { "name": "@xmtp/node-bindings", - "version": "0.0.26", + "version": "0.0.27", "repository": { "type": "git", "url": "git+https://git@github.com/xmtp/libxmtp.git", From c27fa03b971f420a3ffaaff8e08b6baf4d3912a2 Mon Sep 17 00:00:00 2001 From: Andrew Plaza Date: Mon, 2 Dec 2024 13:02:36 -0500 Subject: [PATCH 21/46] send message (#1355) --- xmtp_debug/src/app.rs | 3 ++ xmtp_debug/src/app/generate/groups.rs | 1 + xmtp_debug/src/app/send.rs | 58 +++++++++++++++++++++++++++ xmtp_debug/src/args.rs | 14 +++++++ 4 files changed, 76 insertions(+) create mode 100644 xmtp_debug/src/app/send.rs diff --git a/xmtp_debug/src/app.rs b/xmtp_debug/src/app.rs index 880349463..79f6c6473 100644 --- a/xmtp_debug/src/app.rs +++ b/xmtp_debug/src/app.rs @@ -14,6 +14,8 @@ mod inspect; mod modify; /// Query for data on the network mod query; +/// Send functionality +mod send; /// Local storage mod store; /// Types shared between App Functions @@ -96,6 +98,7 @@ impl App { if let Some(cmd) = cmd { match cmd { Generate(g) => generate::Generate::new(g, backend, db).run().await, + Send(s) => send::Send::new(s, backend, db).run().await, Inspect(i) => inspect::Inspect::new(i, backend, db).run().await, Query(_q) => todo!(), Info(i) => info::Info::new(i, backend, db).run().await, diff --git a/xmtp_debug/src/app/generate/groups.rs b/xmtp_debug/src/app/generate/groups.rs index fb828c93f..e8f33b550 100644 --- a/xmtp_debug/src/app/generate/groups.rs +++ b/xmtp_debug/src/app/generate/groups.rs @@ -34,6 +34,7 @@ impl GenerateGroups { } pub async fn create_groups(&self, n: usize, invitees: usize) -> Result> { + // TODO: Check if identities still exist let mut groups: Vec = Vec::with_capacity(n); let style = ProgressStyle::with_template( "{bar} {pos}/{len} elapsed {elapsed} remaining {eta_precise}", diff --git a/xmtp_debug/src/app/send.rs b/xmtp_debug/src/app/send.rs new file mode 100644 index 000000000..59601d4fe --- /dev/null +++ b/xmtp_debug/src/app/send.rs @@ -0,0 +1,58 @@ +use std::sync::Arc; + +use crate::args; +use color_eyre::eyre::{eyre, Result}; +use rand::prelude::*; + +use super::store::{Database, GroupStore, IdentityStore}; + +#[derive(Debug)] +pub struct Send { + db: Arc, + opts: args::Send, + network: args::BackendOpts, +} + +impl Send { + pub fn new(opts: args::Send, network: args::BackendOpts, db: Arc) -> Self { + Self { opts, network, db } + } + + pub async fn run(self) -> Result<()> { + use args::ActionKind::*; + let args::Send { ref action, .. } = self.opts; + + match action { + Message => self.message().await, + } + } + + async fn message(&self) -> Result<()> { + let Self { ref network, .. } = self; + let args::Send { + ref data, group_id, .. + } = &self.opts; + + let group_store: GroupStore = self.db.clone().into(); + let identity_store: IdentityStore = self.db.clone().into(); + let key = (u64::from(network), **group_id); + let group = group_store + .get(key.into())? + .ok_or(eyre!("No group with id {}", group_id))?; + let member = group + .members + .choose(&mut rand::thread_rng()) + .ok_or(eyre!("Empty group, no members to send message!"))?; + let key = (u64::from(network), *member); + let identity = identity_store + .get(key.into())? + .ok_or(eyre!("No Identity with inbox_id [{}]", hex::encode(member)))?; + + let client = crate::app::client_from_identity(&identity, network).await?; + let conn = client.store().conn()?; + client.sync_welcomes(&conn).await?; + let xmtp_group = client.group(group.id.to_vec())?; + xmtp_group.send_message(data.as_bytes()).await?; + Ok(()) + } +} diff --git a/xmtp_debug/src/args.rs b/xmtp_debug/src/args.rs index 17c03ea32..d4ca414ce 100644 --- a/xmtp_debug/src/args.rs +++ b/xmtp_debug/src/args.rs @@ -27,11 +27,25 @@ pub enum Commands { Generate(Generate), Modify(Modify), Inspect(Inspect), + Send(Send), Query(Query), Info(InfoOpts), Export(ExportOpts), } +/// Send Data on the network +#[derive(Args, Debug)] +pub struct Send { + pub action: ActionKind, + pub data: String, + pub group_id: GroupId, +} + +#[derive(ValueEnum, Debug, Clone)] +pub enum ActionKind { + Message, +} + /// Generate Groups/Messages/Users #[derive(Args, Debug)] pub struct Generate { From e747eec369a5afc8ec1461f8445aecdfe070c65b Mon Sep 17 00:00:00 2001 From: Andrew Plaza Date: Mon, 2 Dec 2024 13:20:04 -0500 Subject: [PATCH 22/46] identity benchmarks (#1358) --- Cargo.lock | 1 + dev/flamegraph | 2 +- xmtp_api_grpc/src/lib.rs | 2 +- xmtp_mls/Cargo.toml | 6 ++ xmtp_mls/benches/group_limit.rs | 18 ++--- xmtp_mls/benches/identity.rs | 120 ++++++++++++++++++++++++++++++++ xmtp_mls/src/utils/bench.rs | 12 ++++ xmtp_proto/Cargo.toml | 3 +- 8 files changed, 148 insertions(+), 16 deletions(-) create mode 100644 xmtp_mls/benches/identity.rs diff --git a/Cargo.lock b/Cargo.lock index f192de44a..51d6be477 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7340,6 +7340,7 @@ dependencies = [ "prost", "serde", "tonic", + "tracing", "wasm-bindgen-test", ] diff --git a/dev/flamegraph b/dev/flamegraph index 9dbedbc26..cb0eba67f 100755 --- a/dev/flamegraph +++ b/dev/flamegraph @@ -12,4 +12,4 @@ else XMTP_FLAMEGRAPH=trace cargo bench --no-fail-fast --features bench -- "$1" fi -inferno-flamegraph > tracing-flamegraph.svg +cat xmtp_mls/tracing.foldeed | inferno-flamegraph > tracing-flamegraph.svg diff --git a/xmtp_api_grpc/src/lib.rs b/xmtp_api_grpc/src/lib.rs index 6da24430a..91bfced7f 100644 --- a/xmtp_api_grpc/src/lib.rs +++ b/xmtp_api_grpc/src/lib.rs @@ -22,7 +22,7 @@ mod utils { } async fn create_dev() -> Self { - crate::Client::create("https://grpc.dev.xmtp.network:443", false) + crate::Client::create("https://grpc.dev.xmtp.network:443", true) .await .unwrap() } diff --git a/xmtp_mls/Cargo.toml b/xmtp_mls/Cargo.toml index 63aa3aba1..697914898 100644 --- a/xmtp_mls/Cargo.toml +++ b/xmtp_mls/Cargo.toml @@ -175,3 +175,9 @@ required-features = ["bench"] harness = false name = "crypto" required-features = ["bench"] + +[[bench]] +harness = false +name = "identity" +required-features = ["bench"] + diff --git a/xmtp_mls/benches/group_limit.rs b/xmtp_mls/benches/group_limit.rs index c2c5a6909..1a2bc954c 100755 --- a/xmtp_mls/benches/group_limit.rs +++ b/xmtp_mls/benches/group_limit.rs @@ -4,13 +4,16 @@ //! may be used to generate a flamegraph of execution from tracing logs. use criterion::{criterion_group, criterion_main, BatchSize, BenchmarkId, Criterion, Throughput}; use std::{collections::HashMap, sync::Arc}; -use tokio::runtime::{Builder, Handle, Runtime}; +use tokio::runtime::{Builder, Runtime}; use tracing::{trace_span, Instrument}; use xmtp_mls::{ builder::ClientBuilder, groups::GroupMetadataOptions, utils::{ - bench::{create_identities_if_dont_exist, init_logging, Identity, BENCH_ROOT_SPAN}, + bench::{ + bench_async_setup, create_identities_if_dont_exist, init_logging, Identity, + BENCH_ROOT_SPAN, + }, test::TestClient, }, Client, @@ -52,17 +55,6 @@ fn setup() -> (Arc, Vec, Runtime) { (client, identities, runtime) } -/// criterion `batch_iter` surrounds the closure in a `Runtime.block_on` despite being a sync -/// function, even in the async 'to_async` setup. Therefore we do this (only _slightly_) hacky -/// workaround to allow us to async setup some groups. -fn bench_async_setup(fun: F) -> T -where - F: Fn() -> Fut, - Fut: futures::future::Future, -{ - tokio::task::block_in_place(move || Handle::current().block_on(async move { fun().await })) -} - fn add_to_empty_group(c: &mut Criterion) { init_logging(); let mut benchmark_group = c.benchmark_group("add_to_empty_group"); diff --git a/xmtp_mls/benches/identity.rs b/xmtp_mls/benches/identity.rs new file mode 100644 index 000000000..437e6af17 --- /dev/null +++ b/xmtp_mls/benches/identity.rs @@ -0,0 +1,120 @@ +use crate::tracing::Instrument; +use criterion::{criterion_group, criterion_main, BatchSize, Criterion}; +use ethers::signers::LocalWallet; +use tokio::runtime::{Builder, Runtime}; +use xmtp_id::{ + associations::{ + builder::SignatureRequest, + generate_inbox_id, + unverified::{UnverifiedRecoverableEcdsaSignature, UnverifiedSignature}, + }, + InboxOwner, +}; +use xmtp_mls::utils::{bench::init_logging, test::TestClient as TestApiClient}; +use xmtp_mls::{ + client::Client, + identity::IdentityStrategy, + utils::bench::{bench_async_setup, BENCH_ROOT_SPAN}, +}; +use xmtp_proto::api_client::XmtpTestClient; + +type BenchClient = Client; + +#[macro_use] +extern crate tracing; + +fn setup() -> Runtime { + Builder::new_multi_thread() + .enable_time() + .enable_io() + .thread_name("xmtp-bencher") + .build() + .unwrap() +} + +async fn new_client() -> (BenchClient, LocalWallet) { + let nonce = 1; + let wallet = xmtp_cryptography::utils::generate_local_wallet(); + let inbox_id = generate_inbox_id(&wallet.get_address(), &nonce).unwrap(); + + let dev = std::env::var("DEV_GRPC"); + let is_dev_network = matches!(dev, Ok(d) if d == "true" || d == "1"); + + let api_client = if is_dev_network { + tracing::info!("Using Dev GRPC"); + ::create_dev().await + } else { + tracing::info!("Using Local GRPC"); + ::create_local().await + }; + + let client = BenchClient::builder(IdentityStrategy::new( + inbox_id, + wallet.get_address(), + nonce, + None, + )); + + let client = client + .temp_store() + .await + .api_client(api_client) + .build() + .await + .unwrap(); + + (client, wallet) +} + +async fn ecdsa_signature(client: &BenchClient, owner: impl InboxOwner) -> SignatureRequest { + let mut signature_request = client.context().signature_request().unwrap(); + let signature_text = signature_request.signature_text(); + let unverified_signature = UnverifiedSignature::RecoverableEcdsa( + UnverifiedRecoverableEcdsaSignature::new(owner.sign(&signature_text).unwrap().into()), + ); + signature_request + .add_signature(unverified_signature, client.scw_verifier()) + .await + .unwrap(); + + signature_request +} + +fn register_identity_eoa(c: &mut Criterion) { + init_logging(); + + let runtime = setup(); + + let mut benchmark_group = c.benchmark_group("register_identity"); + benchmark_group.sample_size(10); + benchmark_group.bench_function("register_identity_eoa", |b| { + let span = trace_span!(BENCH_ROOT_SPAN); + b.to_async(&runtime).iter_batched( + || { + bench_async_setup(|| async { + let (client, wallet) = new_client().await; + let signature_request = ecdsa_signature(&client, wallet).await; + + (client, signature_request, span.clone()) + }) + }, + |(client, request, span)| async move { + client + .register_identity(request) + .instrument(span) + .await + .unwrap() + }, + BatchSize::SmallInput, + ) + }); + + benchmark_group.finish(); +} + +criterion_group!( + name = identity; + config = Criterion::default().sample_size(10); + targets = register_identity_eoa +); +criterion_main!(identity); diff --git a/xmtp_mls/src/utils/bench.rs b/xmtp_mls/src/utils/bench.rs index 781e61bf8..1416b83d9 100644 --- a/xmtp_mls/src/utils/bench.rs +++ b/xmtp_mls/src/utils/bench.rs @@ -65,6 +65,18 @@ pub fn init_logging() { }) } +/// criterion `batch_iter` surrounds the closure in a `Runtime.block_on` despite being a sync +/// function, even in the async 'to_async` setup. Therefore we do this (only _slightly_) hacky +/// workaround to allow us to async setup some groups. +pub fn bench_async_setup(fun: F) -> T +where + F: Fn() -> Fut, + Fut: futures::future::Future, +{ + use tokio::runtime::Handle; + tokio::task::block_in_place(move || Handle::current().block_on(async move { fun().await })) +} + /// Filters for only spans where the root span name is "bench" pub struct BenchFilter; diff --git a/xmtp_proto/Cargo.toml b/xmtp_proto/Cargo.toml index bca40bd06..1a6a2905a 100644 --- a/xmtp_proto/Cargo.toml +++ b/xmtp_proto/Cargo.toml @@ -14,6 +14,7 @@ serde = { workspace = true } async-trait = "0.1" hex.workspace = true openmls_rust_crypto = { workspace = true, optional = true } +tracing.workspace = true [target.'cfg(not(target_arch = "wasm32"))'.dependencies] tonic = { workspace = true } @@ -43,4 +44,4 @@ proto_full = ["xmtp-identity","xmtp-identity-api-v1","xmtp-identity-associations "xmtp-xmtpv4-envelopes" = ["xmtp-identity-associations","xmtp-mls-api-v1"] "xmtp-xmtpv4-message_api" = ["xmtp-xmtpv4-envelopes"] "xmtp-xmtpv4-payer_api" = ["xmtp-xmtpv4-envelopes"] -## @@protoc_insertion_point(features) \ No newline at end of file +## @@protoc_insertion_point(features) From 0a078b02b0c572e537dd6a11b6d4cc8844f406b9 Mon Sep 17 00:00:00 2001 From: Ry Racherbaumer Date: Mon, 2 Dec 2024 16:10:39 -0600 Subject: [PATCH 23/46] Lowercase address when checking association state (#1362) * Lowercase address when checking assoc state * Fix test helper types * Prepare release --- bindings_node/CHANGELOG.md | 5 ++ bindings_node/package.json | 2 +- bindings_node/src/client.rs | 89 ------------------------------ bindings_node/src/inbox_id.rs | 53 ++++++++++++++++++ bindings_node/test/helpers.ts | 5 +- bindings_node/test/inboxId.test.ts | 33 ++++++++++- 6 files changed, 94 insertions(+), 93 deletions(-) diff --git a/bindings_node/CHANGELOG.md b/bindings_node/CHANGELOG.md index 9c6b66051..3a46a8658 100644 --- a/bindings_node/CHANGELOG.md +++ b/bindings_node/CHANGELOG.md @@ -1,5 +1,10 @@ # @xmtp/node-bindings +## 0.0.28 + +- Removed `is_installation_authorized` and `is_address_authorized` from `Client` +- Lowercased `address` passed to `is_address_authorized` + ## 0.0.27 - Switched to Ubuntu 22.04 for builds diff --git a/bindings_node/package.json b/bindings_node/package.json index ba8c0e33f..a8a0907b0 100644 --- a/bindings_node/package.json +++ b/bindings_node/package.json @@ -1,6 +1,6 @@ { "name": "@xmtp/node-bindings", - "version": "0.0.27", + "version": "0.0.28", "repository": { "type": "git", "url": "git+https://git@github.com/xmtp/libxmtp.git", diff --git a/bindings_node/src/client.rs b/bindings_node/src/client.rs index 9a8e094e7..5190525f5 100644 --- a/bindings_node/src/client.rs +++ b/bindings_node/src/client.rs @@ -13,12 +13,9 @@ use tracing_subscriber::{fmt, prelude::*}; pub use xmtp_api_grpc::grpc_api_helper::Client as TonicApiClient; use xmtp_cryptography::signature::ed25519_public_key_to_address; use xmtp_id::associations::builder::SignatureRequest; -use xmtp_id::associations::MemberIdentifier; -use xmtp_mls::api::ApiClientWrapper; use xmtp_mls::builder::ClientBuilder; use xmtp_mls::groups::scoped_client::LocalScopedGroupClient; use xmtp_mls::identity::IdentityStrategy; -use xmtp_mls::retry::Retry; use xmtp_mls::storage::{EncryptedMessageStore, EncryptionKey, StorageOption}; use xmtp_mls::Client as MlsClient; use xmtp_proto::xmtp::mls::message_contents::DeviceSyncKind; @@ -303,90 +300,4 @@ impl Client { .map_err(ErrorWrapper::from)?; Ok(state.into_iter().map(Into::into).collect()) } - - #[napi] - pub async fn is_address_authorized(&self, inbox_id: String, address: String) -> Result { - self - .is_member_of_association_state(&inbox_id, &MemberIdentifier::Address(address)) - .await - } - - #[napi] - pub async fn is_installation_authorized( - &self, - inbox_id: String, - installation_id: Uint8Array, - ) -> Result { - self - .is_member_of_association_state( - &inbox_id, - &MemberIdentifier::Installation(installation_id.to_vec()), - ) - .await - } - - async fn is_member_of_association_state( - &self, - inbox_id: &str, - identifier: &MemberIdentifier, - ) -> Result { - let client = &self.inner_client; - let conn = self - .inner_client - .store() - .conn() - .map_err(ErrorWrapper::from)?; - - let association_state = client - .get_association_state(&conn, inbox_id, None) - .await - .map_err(ErrorWrapper::from)?; - - Ok(association_state.get(identifier).is_some()) - } -} - -#[napi] -pub async fn is_installation_authorized( - host: String, - inbox_id: String, - installation_id: Uint8Array, -) -> Result { - is_member_of_association_state( - &host, - &inbox_id, - &MemberIdentifier::Installation(installation_id.to_vec()), - ) - .await -} - -#[napi] -pub async fn is_address_authorized( - host: String, - inbox_id: String, - address: String, -) -> Result { - is_member_of_association_state(&host, &inbox_id, &MemberIdentifier::Address(address)).await -} - -async fn is_member_of_association_state( - host: &str, - inbox_id: &str, - identifier: &MemberIdentifier, -) -> Result { - let api_client = TonicApiClient::create(host, true) - .await - .map_err(ErrorWrapper::from)?; - let api_client = ApiClientWrapper::new(Arc::new(api_client), Retry::default()); - - let is_member = xmtp_mls::identity_updates::is_member_of_association_state( - &api_client, - inbox_id, - identifier, - None, - ) - .await - .map_err(ErrorWrapper::from)?; - - Ok(is_member) } diff --git a/bindings_node/src/inbox_id.rs b/bindings_node/src/inbox_id.rs index 34821514a..b9a4d34a9 100644 --- a/bindings_node/src/inbox_id.rs +++ b/bindings_node/src/inbox_id.rs @@ -1,8 +1,11 @@ use crate::ErrorWrapper; use napi::bindgen_prelude::Result; +use napi::bindgen_prelude::Uint8Array; use napi_derive::napi; +use std::sync::Arc; use xmtp_api_grpc::grpc_api_helper::Client as TonicApiClient; use xmtp_id::associations::generate_inbox_id as xmtp_id_generate_inbox_id; +use xmtp_id::associations::MemberIdentifier; use xmtp_mls::api::ApiClientWrapper; use xmtp_mls::retry::Retry; @@ -37,3 +40,53 @@ pub fn generate_inbox_id(account_address: String) -> Result { let result = xmtp_id_generate_inbox_id(&account_address, &1).map_err(ErrorWrapper::from)?; Ok(result) } + +#[napi] +pub async fn is_installation_authorized( + host: String, + inbox_id: String, + installation_id: Uint8Array, +) -> Result { + is_member_of_association_state( + &host, + &inbox_id, + &MemberIdentifier::Installation(installation_id.to_vec()), + ) + .await +} + +#[napi] +pub async fn is_address_authorized( + host: String, + inbox_id: String, + address: String, +) -> Result { + is_member_of_association_state( + &host, + &inbox_id, + &MemberIdentifier::Address(address.to_lowercase()), + ) + .await +} + +async fn is_member_of_association_state( + host: &str, + inbox_id: &str, + identifier: &MemberIdentifier, +) -> Result { + let api_client = TonicApiClient::create(host, true) + .await + .map_err(ErrorWrapper::from)?; + let api_client = ApiClientWrapper::new(Arc::new(api_client), Retry::default()); + + let is_member = xmtp_mls::identity_updates::is_member_of_association_state( + &api_client, + inbox_id, + identifier, + None, + ) + .await + .map_err(ErrorWrapper::from)?; + + Ok(is_member) +} diff --git a/bindings_node/test/helpers.ts b/bindings_node/test/helpers.ts index fc44c2229..989063d38 100644 --- a/bindings_node/test/helpers.ts +++ b/bindings_node/test/helpers.ts @@ -8,6 +8,7 @@ import { createClient as create, generateInboxId, getInboxIdForAddress, + LogLevel, SignatureRequestType, } from '../dist/index' @@ -44,7 +45,7 @@ export const createClient = async (user: User) => { user.account.address, undefined, undefined, - { level: 'info' } + { level: LogLevel.info } ) } @@ -81,7 +82,7 @@ export const encodeTextMessage = (text: string) => { } } -export function sleep(ms) { +export function sleep(ms: number) { return new Promise((resolve) => { setTimeout(resolve, ms) }) diff --git a/bindings_node/test/inboxId.test.ts b/bindings_node/test/inboxId.test.ts index bb771853f..d4e4e2139 100644 --- a/bindings_node/test/inboxId.test.ts +++ b/bindings_node/test/inboxId.test.ts @@ -1,6 +1,11 @@ import { describe, expect, it } from 'vitest' import { createRegisteredClient, createUser, TEST_API_URL } from '@test/helpers' -import { generateInboxId, getInboxIdForAddress } from '../dist/index' +import { + generateInboxId, + getInboxIdForAddress, + isAddressAuthorized, + isInstallationAuthorized, +} from '../dist/index' describe('generateInboxId', () => { it('should generate an inbox id', () => { @@ -32,3 +37,29 @@ describe('getInboxIdForAddress', () => { expect(inboxId).toBe(client.inboxId()) }) }) + +describe('isInstallationAuthorized', () => { + it('should return true if installation is authorized', async () => { + const user = createUser() + const client = await createRegisteredClient(user) + const isAuthorized = await isInstallationAuthorized( + TEST_API_URL, + client.inboxId(), + client.installationIdBytes() + ) + expect(isAuthorized).toBe(true) + }) +}) + +describe('isAddressAuthorized', () => { + it('should return true if address is authorized', async () => { + const user = createUser() + const client = await createRegisteredClient(user) + const isAuthorized = await isAddressAuthorized( + TEST_API_URL, + client.inboxId(), + user.account.address + ) + expect(isAuthorized).toBe(true) + }) +}) From 85dd6d36f46db1ed74fe98273eea6871fea2e078 Mon Sep 17 00:00:00 2001 From: Andrew Plaza Date: Mon, 2 Dec 2024 17:54:37 -0500 Subject: [PATCH 24/46] Benchmark `sync_worker` (#1360) * benchmark syncs * fix missing dependency --- Cargo.lock | 2 + Cargo.toml | 2 + dev/bench | 6 +- dev/flamegraph | 4 +- xmtp_debug/Cargo.toml | 4 +- xmtp_debug/src/app/clients.rs | 1 + xmtp_mls/Cargo.toml | 13 +++ xmtp_mls/benches/group_limit.rs | 12 +-- xmtp_mls/benches/identity.rs | 49 +-------- xmtp_mls/benches/sync.rs | 56 ++++++++++ xmtp_mls/src/groups/device_sync.rs | 7 +- .../src/groups/device_sync/message_sync.rs | 19 ++-- xmtp_mls/src/subscriptions.rs | 2 + xmtp_mls/src/utils/bench/clients.rs | 72 +++++++++++++ .../utils/{bench.rs => bench/identity_gen.rs} | 101 +----------------- xmtp_mls/src/utils/bench/mod.rs | 99 +++++++++++++++++ xmtp_mls/src/utils/test/mod.rs | 7 ++ 17 files changed, 287 insertions(+), 169 deletions(-) create mode 100644 xmtp_mls/benches/sync.rs create mode 100644 xmtp_mls/src/utils/bench/clients.rs rename xmtp_mls/src/utils/{bench.rs => bench/identity_gen.rs} (54%) create mode 100644 xmtp_mls/src/utils/bench/mod.rs diff --git a/Cargo.lock b/Cargo.lock index 51d6be477..b19d63c22 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7275,6 +7275,7 @@ dependencies = [ "bincode", "chrono", "console_error_panic_hook", + "const_format", "criterion", "ctor", "diesel", @@ -7282,6 +7283,7 @@ dependencies = [ "diesel_migrations", "dyn-clone", "ethers", + "fdlimit", "futures", "getrandom", "gloo-timers 0.3.0", diff --git a/Cargo.toml b/Cargo.toml index 5398ef292..0c2025a8e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -89,6 +89,8 @@ url = "2.5.0" zeroize = "1.8" bincode = "1.3" console_error_panic_hook = "0.1" +fdlimit = "0.3" +const_format = "0.2" # Internal Crate Dependencies xmtp_cryptography = { path = "xmtp_cryptography" } diff --git a/dev/bench b/dev/bench index c4ec1e38e..b7b8f89c7 100755 --- a/dev/bench +++ b/dev/bench @@ -2,7 +2,9 @@ set -eou pipefail if [[ -z "${1-}" ]]; then - cargo bench --no-fail-fast --features bench + cargo bench --no-fail-fast --features bench -p xmtp_mls else - cargo bench --no-fail-fast --features bench -- "$1" + cargo bench --no-fail-fast --features bench -p xmtp_mls -- "$1" fi + +echo "Open benchmarks at target/criterion/report.html" diff --git a/dev/flamegraph b/dev/flamegraph index cb0eba67f..872257321 100755 --- a/dev/flamegraph +++ b/dev/flamegraph @@ -7,9 +7,9 @@ if [[ "${OSTYPE}" == "darwin"* ]]; then fi if [[ -z "${1-}" ]]; then - XMTP_FLAMEGRAPH=trace cargo bench --no-fail-fast --features bench + XMTP_FLAMEGRAPH=trace cargo bench --no-fail-fast --features bench -p xmtp_mls else - XMTP_FLAMEGRAPH=trace cargo bench --no-fail-fast --features bench -- "$1" + XMTP_FLAMEGRAPH=trace cargo bench --no-fail-fast --features bench -p xmtp_mls -- "$1" fi cat xmtp_mls/tracing.foldeed | inferno-flamegraph > tracing-flamegraph.svg diff --git a/xmtp_debug/Cargo.toml b/xmtp_debug/Cargo.toml index d1ca81f23..f1ec81d46 100644 --- a/xmtp_debug/Cargo.toml +++ b/xmtp_debug/Cargo.toml @@ -23,7 +23,7 @@ owo-colors = "4.1" url.workspace = true redb = "2.2" directories = "5.0" -const_format = "0.2" +const_format.workspace = true speedy = "0.8" hex.workspace = true prost.workspace = true @@ -40,5 +40,5 @@ rand.workspace = true fs_extra = "1.3" ethers.workspace = true miniserde = "0.1" -fdlimit = "0.3" +fdlimit.workspace = true lipsum = "0.9" diff --git a/xmtp_debug/src/app/clients.rs b/xmtp_debug/src/app/clients.rs index fe07c5a9c..6824ca39e 100644 --- a/xmtp_debug/src/app/clients.rs +++ b/xmtp_debug/src/app/clients.rs @@ -1,4 +1,5 @@ //! Different ways to create a [`crate::DbgClient`] + use super::*; use crate::app::types::*; diff --git a/xmtp_mls/Cargo.toml b/xmtp_mls/Cargo.toml index 697914898..11f9582b0 100644 --- a/xmtp_mls/Cargo.toml +++ b/xmtp_mls/Cargo.toml @@ -23,6 +23,9 @@ bench = [ "once_cell", "dep:xmtp_api_grpc", "criterion", + "dep:fdlimit", + "dep:ethers", + "dep:const_format" ] default = ["grpc-api"] grpc-api = ["dep:xmtp_api_grpc"] @@ -35,6 +38,7 @@ test-utils = [ "xmtp_proto/test-utils", "xmtp_api_http/test-utils", "xmtp_api_grpc/test-utils", + "dep:const_format" ] update-schema = ["toml"] @@ -74,6 +78,9 @@ console_error_panic_hook = { workspace = true, optional = true } toml = { version = "0.8.4", optional = true } tracing-wasm = { version = "0.2", optional = true } xmtp_api_http = { path = "../xmtp_api_http", optional = true } +fdlimit = { workspace = true, optional = true } +ethers = { workspace = true, features = ["openssl"], optional = true } +const_format = { workspace = true, optional = true } # Test/Bench Utils anyhow = { workspace = true, optional = true } @@ -132,6 +139,7 @@ mockall = "0.13.1" openmls_basic_credential.workspace = true xmtp_id = { path = "../xmtp_id", features = ["test-utils"] } xmtp_proto = { workspace = true, features = ["test-utils"] } +const_format.workspace = true [target.'cfg(not(target_arch = "wasm32"))'.dev-dependencies] ctor.workspace = true @@ -181,3 +189,8 @@ harness = false name = "identity" required-features = ["bench"] +[[bench]] +harness = false +name = "sync" +required-features = ["bench"] + diff --git a/xmtp_mls/benches/group_limit.rs b/xmtp_mls/benches/group_limit.rs index 1a2bc954c..ba3027eb3 100755 --- a/xmtp_mls/benches/group_limit.rs +++ b/xmtp_mls/benches/group_limit.rs @@ -9,18 +9,12 @@ use tracing::{trace_span, Instrument}; use xmtp_mls::{ builder::ClientBuilder, groups::GroupMetadataOptions, - utils::{ - bench::{ - bench_async_setup, create_identities_if_dont_exist, init_logging, Identity, - BENCH_ROOT_SPAN, - }, - test::TestClient, + utils::bench::{ + bench_async_setup, create_identities_if_dont_exist, init_logging, BenchClient, Identity, + BENCH_ROOT_SPAN, }, - Client, }; -pub type BenchClient = Client; - pub const IDENTITY_SAMPLES: [usize; 9] = [10, 20, 40, 80, 100, 200, 300, 400, 450]; pub const MAX_IDENTITIES: usize = 1_000; pub const SAMPLE_SIZE: usize = 10; diff --git a/xmtp_mls/benches/identity.rs b/xmtp_mls/benches/identity.rs index 437e6af17..a7b10709f 100644 --- a/xmtp_mls/benches/identity.rs +++ b/xmtp_mls/benches/identity.rs @@ -1,24 +1,15 @@ use crate::tracing::Instrument; use criterion::{criterion_group, criterion_main, BatchSize, Criterion}; -use ethers::signers::LocalWallet; use tokio::runtime::{Builder, Runtime}; use xmtp_id::{ associations::{ builder::SignatureRequest, - generate_inbox_id, unverified::{UnverifiedRecoverableEcdsaSignature, UnverifiedSignature}, }, InboxOwner, }; -use xmtp_mls::utils::{bench::init_logging, test::TestClient as TestApiClient}; -use xmtp_mls::{ - client::Client, - identity::IdentityStrategy, - utils::bench::{bench_async_setup, BENCH_ROOT_SPAN}, -}; -use xmtp_proto::api_client::XmtpTestClient; - -type BenchClient = Client; +use xmtp_mls::utils::bench::{bench_async_setup, BenchClient, BENCH_ROOT_SPAN}; +use xmtp_mls::utils::bench::{clients, init_logging}; #[macro_use] extern crate tracing; @@ -32,40 +23,6 @@ fn setup() -> Runtime { .unwrap() } -async fn new_client() -> (BenchClient, LocalWallet) { - let nonce = 1; - let wallet = xmtp_cryptography::utils::generate_local_wallet(); - let inbox_id = generate_inbox_id(&wallet.get_address(), &nonce).unwrap(); - - let dev = std::env::var("DEV_GRPC"); - let is_dev_network = matches!(dev, Ok(d) if d == "true" || d == "1"); - - let api_client = if is_dev_network { - tracing::info!("Using Dev GRPC"); - ::create_dev().await - } else { - tracing::info!("Using Local GRPC"); - ::create_local().await - }; - - let client = BenchClient::builder(IdentityStrategy::new( - inbox_id, - wallet.get_address(), - nonce, - None, - )); - - let client = client - .temp_store() - .await - .api_client(api_client) - .build() - .await - .unwrap(); - - (client, wallet) -} - async fn ecdsa_signature(client: &BenchClient, owner: impl InboxOwner) -> SignatureRequest { let mut signature_request = client.context().signature_request().unwrap(); let signature_text = signature_request.signature_text(); @@ -92,7 +49,7 @@ fn register_identity_eoa(c: &mut Criterion) { b.to_async(&runtime).iter_batched( || { bench_async_setup(|| async { - let (client, wallet) = new_client().await; + let (client, wallet) = clients::new_unregistered_client(false).await; let signature_request = ecdsa_signature(&client, wallet).await; (client, signature_request, span.clone()) diff --git a/xmtp_mls/benches/sync.rs b/xmtp_mls/benches/sync.rs new file mode 100644 index 000000000..3dd215f88 --- /dev/null +++ b/xmtp_mls/benches/sync.rs @@ -0,0 +1,56 @@ +//! Benchmarking for syncing functions +use crate::tracing::Instrument; +use criterion::{criterion_group, criterion_main, BatchSize, Criterion}; +use tokio::runtime::{Builder, Runtime}; +use xmtp_mls::utils::bench::{bench_async_setup, BENCH_ROOT_SPAN}; +use xmtp_mls::utils::bench::{clients, init_logging}; + +#[macro_use] +extern crate tracing; + +fn setup() -> Runtime { + Builder::new_multi_thread() + .enable_time() + .enable_io() + .thread_name("xmtp-bencher") + .build() + .unwrap() +} + +fn start_sync_worker(c: &mut Criterion) { + init_logging(); + + let runtime = setup(); + let mut benchmark_group = c.benchmark_group("start_sync_worker"); + benchmark_group.sample_size(10); + benchmark_group.bench_function("start_sync_worker", |b| { + let span = trace_span!(BENCH_ROOT_SPAN); + b.to_async(&runtime).iter_batched( + || { + bench_async_setup(|| async { + let client = clients::new_client(true).await; + let provider = client.mls_provider().unwrap(); + // set history sync URL + (client, provider, span.clone()) + }) + }, + |(client, provider, span)| async move { + client + .start_sync_worker(&provider) + .instrument(span) + .await + .unwrap() + }, + BatchSize::SmallInput, + ) + }); + + benchmark_group.finish(); +} + +criterion_group!( + name = sync; + config = Criterion::default().sample_size(10); + targets = start_sync_worker +); +criterion_main!(sync); diff --git a/xmtp_mls/src/groups/device_sync.rs b/xmtp_mls/src/groups/device_sync.rs index 872a2e53e..d9c442daf 100644 --- a/xmtp_mls/src/groups/device_sync.rs +++ b/xmtp_mls/src/groups/device_sync.rs @@ -31,7 +31,7 @@ use rand::{ use serde::{Deserialize, Serialize}; use std::time::Duration; use thiserror::Error; -use tracing::warn; +use tracing::{instrument, warn}; use xmtp_cryptography::utils as crypto_utils; use xmtp_id::scw_verifier::SmartContractSignatureVerifier; use xmtp_proto::api_client::trait_impls::XmtpApi; @@ -118,6 +118,7 @@ where ApiClient: XmtpApi + Send + Sync + 'static, V: SmartContractSignatureVerifier + Send + Sync + 'static, { + #[instrument(level = "trace", skip_all)] pub async fn start_sync_worker( &self, provider: &XmtpOpenMlsProvider, @@ -231,6 +232,7 @@ where * Ideally called when the client is registered. * Will auto-send a sync request if sync group is created. */ + #[instrument(level = "trace", skip_all)] pub async fn sync_init(&self, provider: &XmtpOpenMlsProvider) -> Result<(), DeviceSyncError> { tracing::info!( "Initializing device sync... url: {:?}", @@ -249,6 +251,7 @@ where Ok(()) } + #[instrument(level = "trace", skip_all)] async fn ensure_sync_group( &self, provider: &XmtpOpenMlsProvider, @@ -265,6 +268,7 @@ where Ok(sync_group) } + #[instrument(level = "trace", skip_all)] pub async fn send_sync_request( &self, provider: &XmtpOpenMlsProvider, @@ -585,6 +589,7 @@ where Ok(()) } + #[instrument(level = "trace", skip_all)] pub fn get_sync_group(&self) -> Result, GroupError> { let conn = self.store().conn()?; let sync_group_id = conn diff --git a/xmtp_mls/src/groups/device_sync/message_sync.rs b/xmtp_mls/src/groups/device_sync/message_sync.rs index 44748ff61..3edab260f 100644 --- a/xmtp_mls/src/groups/device_sync/message_sync.rs +++ b/xmtp_mls/src/groups/device_sync/message_sync.rs @@ -47,21 +47,19 @@ pub(crate) mod tests { #[cfg(target_arch = "wasm32")] wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_dedicated_worker); - const HISTORY_SERVER_HOST: &str = "localhost"; - const HISTORY_SERVER_PORT: u16 = 5558; - use super::*; - use crate::{assert_ok, builder::ClientBuilder, groups::GroupMetadataOptions}; + use crate::{ + assert_ok, builder::ClientBuilder, groups::GroupMetadataOptions, + utils::test::HISTORY_SYNC_URL, + }; use std::time::{Duration, Instant}; use xmtp_cryptography::utils::generate_local_wallet; use xmtp_id::InboxOwner; #[tokio::test(flavor = "multi_thread", worker_threads = 1)] async fn test_message_history_sync() { - let history_sync_url = format!("http://{}:{}", HISTORY_SERVER_HOST, HISTORY_SERVER_PORT); - let wallet = generate_local_wallet(); - let amal_a = ClientBuilder::new_test_client_with_history(&wallet, &history_sync_url).await; + let amal_a = ClientBuilder::new_test_client_with_history(&wallet, HISTORY_SYNC_URL).await; let amal_a_provider = amal_a.mls_provider().unwrap(); let amal_a_conn = amal_a_provider.conn_ref(); @@ -87,7 +85,7 @@ pub(crate) mod tests { assert_eq!(syncable_messages.len(), 2); // welcome message, and message that was just sent // Create a second installation for amal. - let amal_b = ClientBuilder::new_test_client_with_history(&wallet, &history_sync_url).await; + let amal_b = ClientBuilder::new_test_client_with_history(&wallet, HISTORY_SYNC_URL).await; let amal_b_provider = amal_b.mls_provider().unwrap(); let amal_b_conn = amal_b_provider.conn_ref(); @@ -161,16 +159,15 @@ pub(crate) mod tests { #[tokio::test] async fn test_externals_cant_join_sync_group() { - let history_sync_url = format!("http://{}:{}", HISTORY_SERVER_HOST, HISTORY_SERVER_PORT); let wallet = generate_local_wallet(); - let amal = ClientBuilder::new_test_client_with_history(&wallet, &history_sync_url).await; + let amal = ClientBuilder::new_test_client_with_history(&wallet, HISTORY_SYNC_URL).await; amal.sync_welcomes(&amal.store().conn().unwrap()) .await .expect("sync welcomes"); let external_wallet = generate_local_wallet(); let external_client = - ClientBuilder::new_test_client_with_history(&external_wallet, &history_sync_url).await; + ClientBuilder::new_test_client_with_history(&external_wallet, HISTORY_SYNC_URL).await; external_client .sync_welcomes(&external_client.store().conn().unwrap()) diff --git a/xmtp_mls/src/subscriptions.rs b/xmtp_mls/src/subscriptions.rs index c4d958f7b..d5c9dbf6a 100644 --- a/xmtp_mls/src/subscriptions.rs +++ b/xmtp_mls/src/subscriptions.rs @@ -6,6 +6,7 @@ use tokio::{ task::JoinHandle, }; use tokio_stream::wrappers::BroadcastStream; +use tracing::instrument; use xmtp_id::scw_verifier::SmartContractSignatureVerifier; use xmtp_proto::{api_client::XmtpMlsStreams, xmtp::mls::api::v1::WelcomeMessage}; @@ -104,6 +105,7 @@ impl StreamMessages for broadcast::Receiver> where C: Clone + Send + Sync + 'static, { + #[instrument(level = "trace", skip_all)] fn stream_sync_messages(self) -> impl Stream, SubscribeError>> { BroadcastStream::new(self).filter_map(|event| async { crate::optify!(event, "Missed message due to event queue lag") diff --git a/xmtp_mls/src/utils/bench/clients.rs b/xmtp_mls/src/utils/bench/clients.rs new file mode 100644 index 000000000..90eaaf666 --- /dev/null +++ b/xmtp_mls/src/utils/bench/clients.rs @@ -0,0 +1,72 @@ +use crate::utils::test::{TestClient as TestApiClient, HISTORY_SYNC_URL}; +use crate::{client::Client, identity::IdentityStrategy}; +use ethers::signers::LocalWallet; +use xmtp_id::{ + associations::{ + builder::SignatureRequest, + generate_inbox_id, + unverified::{UnverifiedRecoverableEcdsaSignature, UnverifiedSignature}, + }, + InboxOwner, +}; +use xmtp_proto::api_client::XmtpTestClient; + +pub type BenchClient = Client; + +/// Create a new, yet-unregistered client +pub async fn new_unregistered_client(history_sync: bool) -> (BenchClient, LocalWallet) { + let _ = fdlimit::raise_fd_limit(); + + let nonce = 1; + let wallet = xmtp_cryptography::utils::generate_local_wallet(); + let inbox_id = generate_inbox_id(&wallet.get_address(), &nonce).unwrap(); + + let dev = std::env::var("DEV_GRPC"); + let is_dev_network = matches!(dev, Ok(d) if d == "true" || d == "1"); + + let api_client = if is_dev_network { + tracing::info!("Using Dev GRPC"); + ::create_dev().await + } else { + tracing::info!("Using Local GRPC"); + ::create_local().await + }; + + let client = BenchClient::builder(IdentityStrategy::new( + inbox_id, + wallet.get_address(), + nonce, + None, + )); + + let mut client = client.temp_store().await.api_client(api_client); + if history_sync { + client = client.history_sync_url(HISTORY_SYNC_URL); + } + let client = client.build().await.unwrap(); + + (client, wallet) +} + +/// Add ECDSA Signature to a client +pub async fn ecdsa_signature(client: &BenchClient, owner: impl InboxOwner) -> SignatureRequest { + let mut signature_request = client.context().signature_request().unwrap(); + let signature_text = signature_request.signature_text(); + let unverified_signature = UnverifiedSignature::RecoverableEcdsa( + UnverifiedRecoverableEcdsaSignature::new(owner.sign(&signature_text).unwrap().into()), + ); + signature_request + .add_signature(unverified_signature, client.scw_verifier()) + .await + .unwrap(); + + signature_request +} + +/// Create a new registered client with an EOA +pub async fn new_client(history_sync: bool) -> BenchClient { + let (client, wallet) = new_unregistered_client(history_sync).await; + let signature_request = ecdsa_signature(&client, wallet).await; + client.register_identity(signature_request).await.unwrap(); + client +} diff --git a/xmtp_mls/src/utils/bench.rs b/xmtp_mls/src/utils/bench/identity_gen.rs similarity index 54% rename from xmtp_mls/src/utils/bench.rs rename to xmtp_mls/src/utils/bench/identity_gen.rs index 1416b83d9..8c1b42489 100644 --- a/xmtp_mls/src/utils/bench.rs +++ b/xmtp_mls/src/utils/bench/identity_gen.rs @@ -1,104 +1,12 @@ -//! Utilities for xmtp_mls benchmarks -//! Utilities mostly include pre-generating identities in order to save time when writing/testing -//! benchmarks. -#![allow(clippy::unwrap_used)] +//! Identity Generation -use crate::{builder::ClientBuilder, Client}; +use crate::builder::ClientBuilder; use indicatif::{ProgressBar, ProgressStyle}; -use once_cell::sync::OnceCell; use serde::{Deserialize, Serialize}; -use std::sync::Once; -use thiserror::Error; -use tracing::{Metadata, Subscriber}; -use tracing_flame::{FlameLayer, FlushGuard}; -use tracing_subscriber::{ - layer::{Context, Filter, Layer, SubscriberExt}, - registry::LookupSpan, - util::SubscriberInitExt, - EnvFilter, -}; use xmtp_cryptography::utils::generate_local_wallet; use xmtp_id::InboxOwner; -use super::test::TestClient; - -pub const BENCH_ROOT_SPAN: &str = "xmtp-trace-bench"; - -/// Re-export of functions in private modules for benchmarks -pub mod re_export { - pub use crate::hpke::encrypt_welcome; -} - -#[derive(Debug, Error)] -pub enum BenchError { - #[error(transparent)] - Serde(#[from] serde_json::Error), - #[error(transparent)] - Io(#[from] std::io::Error), -} - -static INIT: Once = Once::new(); - -static LOGGER: OnceCell>> = OnceCell::new(); - -/// initializes logging for benchmarks -/// - FMT logging is enabled by passing the normal `RUST_LOG` environment variable options. -/// - Generate a flamegraph from tracing data by passing `XMTP_FLAMEGRAPH=trace` -pub fn init_logging() { - INIT.call_once(|| { - let (flame_layer, guard) = FlameLayer::with_file("./tracing.folded").unwrap(); - let flame_layer = flame_layer - .with_threads_collapsed(true) - .with_module_path(true); - // .with_empty_samples(false); - - tracing_subscriber::registry() - .with(tracing_subscriber::fmt::layer().with_filter(EnvFilter::from_default_env())) - .with( - flame_layer - .with_filter(BenchFilter) - .with_filter(EnvFilter::from_env("XMTP_FLAMEGRAPH")), - ) - .init(); - - LOGGER.set(guard).unwrap(); - }) -} - -/// criterion `batch_iter` surrounds the closure in a `Runtime.block_on` despite being a sync -/// function, even in the async 'to_async` setup. Therefore we do this (only _slightly_) hacky -/// workaround to allow us to async setup some groups. -pub fn bench_async_setup(fun: F) -> T -where - F: Fn() -> Fut, - Fut: futures::future::Future, -{ - use tokio::runtime::Handle; - tokio::task::block_in_place(move || Handle::current().block_on(async move { fun().await })) -} - -/// Filters for only spans where the root span name is "bench" -pub struct BenchFilter; - -impl Filter for BenchFilter -where - S: Subscriber + for<'lookup> LookupSpan<'lookup> + std::fmt::Debug, - for<'lookup> >::Data: std::fmt::Debug, -{ - fn enabled(&self, meta: &Metadata<'_>, cx: &Context<'_, S>) -> bool { - if meta.name() == BENCH_ROOT_SPAN { - return true; - } - if let Some(id) = cx.current_span().id() { - if let Some(s) = cx.span_scope(id) { - if let Some(s) = s.from_root().take(1).collect::>().first() { - return s.name() == BENCH_ROOT_SPAN; - } - } - } - false - } -} +use super::{BenchClient, BenchError}; pub fn file_path(is_dev_network: bool) -> String { if is_dev_network { @@ -188,9 +96,10 @@ async fn create_identities(n: usize, is_dev_network: bool) -> Vec { /// node still has those identities. pub async fn create_identities_if_dont_exist( identities: usize, - client: &Client, + client: &BenchClient, is_dev_network: bool, ) -> Vec { + let _ = fdlimit::raise_fd_limit(); match load_identities(is_dev_network) { Ok(identities) => { tracing::info!( diff --git a/xmtp_mls/src/utils/bench/mod.rs b/xmtp_mls/src/utils/bench/mod.rs new file mode 100644 index 000000000..5466c6dd9 --- /dev/null +++ b/xmtp_mls/src/utils/bench/mod.rs @@ -0,0 +1,99 @@ +//! Utilities for xmtp_mls benchmarks +//! Utilities mostly include pre-generating identities in order to save time when writing/testing +//! benchmarks. +#![allow(clippy::unwrap_used)] + +mod identity_gen; +pub use identity_gen::*; +pub mod clients; +pub use clients::*; + +use once_cell::sync::OnceCell; +use std::sync::Once; +use thiserror::Error; +use tracing::{Metadata, Subscriber}; +use tracing_flame::{FlameLayer, FlushGuard}; +use tracing_subscriber::{ + layer::{Context, Filter, Layer, SubscriberExt}, + registry::LookupSpan, + util::SubscriberInitExt, + EnvFilter, +}; + +pub const BENCH_ROOT_SPAN: &str = "xmtp-trace-bench"; + +/// Re-export of functions in private modules for benchmarks +pub mod re_export { + pub use crate::hpke::encrypt_welcome; +} + +#[derive(Debug, Error)] +pub enum BenchError { + #[error(transparent)] + Serde(#[from] serde_json::Error), + #[error(transparent)] + Io(#[from] std::io::Error), +} + +static INIT: Once = Once::new(); + +static LOGGER: OnceCell>> = OnceCell::new(); + +/// initializes logging for benchmarks +/// - FMT logging is enabled by passing the normal `RUST_LOG` environment variable options. +/// - Generate a flamegraph from tracing data by passing `XMTP_FLAMEGRAPH=trace` +pub fn init_logging() { + INIT.call_once(|| { + let (flame_layer, guard) = FlameLayer::with_file("./tracing.folded").unwrap(); + let flame_layer = flame_layer + .with_threads_collapsed(true) + .with_module_path(true); + // .with_empty_samples(false); + + tracing_subscriber::registry() + .with(tracing_subscriber::fmt::layer().with_filter(EnvFilter::from_default_env())) + .with( + flame_layer + .with_filter(BenchFilter) + .with_filter(EnvFilter::from_env("XMTP_FLAMEGRAPH")), + ) + .init(); + + LOGGER.set(guard).unwrap(); + }) +} + +/// criterion `batch_iter` surrounds the closure in a `Runtime.block_on` despite being a sync +/// function, even in the async 'to_async` setup. Therefore we do this (only _slightly_) hacky +/// workaround to allow us to async setup some groups. +pub fn bench_async_setup(fun: F) -> T +where + F: Fn() -> Fut, + Fut: futures::future::Future, +{ + use tokio::runtime::Handle; + tokio::task::block_in_place(move || Handle::current().block_on(async move { fun().await })) +} + +/// Filters for only spans where the root span name is "bench" +pub struct BenchFilter; + +impl Filter for BenchFilter +where + S: Subscriber + for<'lookup> LookupSpan<'lookup> + std::fmt::Debug, + for<'lookup> >::Data: std::fmt::Debug, +{ + fn enabled(&self, meta: &Metadata<'_>, cx: &Context<'_, S>) -> bool { + if meta.name() == BENCH_ROOT_SPAN { + return true; + } + if let Some(id) = cx.current_span().id() { + if let Some(s) = cx.span_scope(id) { + if let Some(s) = s.from_root().take(1).collect::>().first() { + return s.name() == BENCH_ROOT_SPAN; + } + } + } + false + } +} diff --git a/xmtp_mls/src/utils/test/mod.rs b/xmtp_mls/src/utils/test/mod.rs index 952b31988..47b56c2bb 100755 --- a/xmtp_mls/src/utils/test/mod.rs +++ b/xmtp_mls/src/utils/test/mod.rs @@ -31,6 +31,12 @@ pub use traced_test::traced_test; pub type FullXmtpClient = Client; +// TODO: Dev-Versions of URL +const HISTORY_SERVER_HOST: &str = "localhost"; +const HISTORY_SERVER_PORT: u16 = 5558; +pub const HISTORY_SYNC_URL: &str = + const_format::concatcp!("http://", HISTORY_SERVER_HOST, ":", HISTORY_SERVER_PORT); + #[cfg(not(any(feature = "http-api", target_arch = "wasm32")))] pub type TestClient = xmtp_api_grpc::grpc_api_helper::Client; @@ -92,6 +98,7 @@ impl EncryptedMessageStore { impl ClientBuilder { pub async fn temp_store(self) -> Self { let tmpdb = tmp_path(); + tracing::info!("Opening Database at [{}]", tmpdb); self.store( EncryptedMessageStore::new( StorageOption::Persistent(tmpdb), From f6f9af92e51c0b0f6698e4d61fbded854eafd2b7 Mon Sep 17 00:00:00 2001 From: Andrew Plaza Date: Tue, 3 Dec 2024 15:02:58 -0500 Subject: [PATCH 25/46] speed up sync init (#1363) --- bindings_ffi/src/mls.rs | 19 ++-- bindings_node/src/signatures.rs | 2 +- bindings_wasm/src/signatures.rs | 2 +- examples/cli/cli-client.rs | 4 +- examples/cli/debug.rs | 2 +- xmtp_mls/Cargo.toml | 5 +- xmtp_mls/benches/sync.rs | 7 +- xmtp_mls/src/api/mls.rs | 6 +- xmtp_mls/src/builder.rs | 6 +- xmtp_mls/src/client.rs | 56 ++++++----- xmtp_mls/src/groups/device_sync.rs | 94 ++++++++++++++----- .../src/groups/device_sync/consent_sync.rs | 27 ++++-- .../src/groups/device_sync/message_sync.rs | 16 +++- xmtp_mls/src/groups/mls_sync.rs | 28 ++++-- xmtp_mls/src/groups/mod.rs | 6 +- xmtp_mls/src/groups/scoped_client.rs | 8 ++ xmtp_mls/src/identity_updates.rs | 10 +- xmtp_mls/src/intents.rs | 2 +- xmtp_mls/src/lib.rs | 45 +++++++-- .../storage/encrypted_store/refresh_state.rs | 2 +- xmtp_mls/src/subscriptions.rs | 2 +- xmtp_mls/src/utils/test/mod.rs | 68 ++++++++++++-- 22 files changed, 302 insertions(+), 115 deletions(-) diff --git a/bindings_ffi/src/mls.rs b/bindings_ffi/src/mls.rs index 1dc95f2a7..93f534aea 100644 --- a/bindings_ffi/src/mls.rs +++ b/bindings_ffi/src/mls.rs @@ -285,7 +285,7 @@ impl FfiXmtpClient { } pub fn installation_id(&self) -> Vec { - self.inner_client.installation_public_key() + self.inner_client.installation_public_key().to_vec() } pub fn release_db_connection(&self) -> Result<(), GenericError> { @@ -380,7 +380,7 @@ impl FfiXmtpClient { signature_bytes: Vec, ) -> Result<(), GenericError> { let inner = self.inner_client.as_ref(); - let public_key = inner.installation_public_key(); + let public_key = inner.installation_public_key().to_vec(); self.verify_signed_with_public_key(signature_text, signature_bytes, public_key) } @@ -454,12 +454,8 @@ impl FfiXmtpClient { return Ok(()); } - let provider = self - .inner_client - .mls_provider() - .map_err(GenericError::from_error)?; self.inner_client - .start_sync_worker(&provider) + .start_sync_worker() .await .map_err(GenericError::from_error)?; @@ -537,7 +533,7 @@ impl FfiXmtpClient { let other_installation_ids = inbox_state .installation_ids() .into_iter() - .filter(|id| id != &installation_id) + .filter(|id| id != installation_id) .collect(); let signature_request = self @@ -911,7 +907,8 @@ impl FfiConversations { pub fn get_sync_group(&self) -> Result { let inner = self.inner_client.as_ref(); - let sync_group = inner.get_sync_group()?; + let conn = inner.store().conn()?; + let sync_group = inner.get_sync_group(&conn)?; Ok(sync_group.into()) } @@ -2096,7 +2093,7 @@ mod tests { .unwrap(); register_client(&ffi_inbox_owner, &client_a).await; - let installation_pub_key = client_a.inner_client.installation_public_key(); + let installation_pub_key = client_a.inner_client.installation_public_key().to_vec(); drop(client_a); let client_b = create_client( @@ -2114,7 +2111,7 @@ mod tests { .await .unwrap(); - let other_installation_pub_key = client_b.inner_client.installation_public_key(); + let other_installation_pub_key = client_b.inner_client.installation_public_key().to_vec(); drop(client_b); assert!( diff --git a/bindings_node/src/signatures.rs b/bindings_node/src/signatures.rs index d32ae8e5f..246ae5325 100644 --- a/bindings_node/src/signatures.rs +++ b/bindings_node/src/signatures.rs @@ -97,7 +97,7 @@ impl Client { let other_installation_ids = inbox_state .installation_ids() .into_iter() - .filter(|id| id != &installation_id) + .filter(|id| id != installation_id) .collect(); let signature_request = self .inner_client() diff --git a/bindings_wasm/src/signatures.rs b/bindings_wasm/src/signatures.rs index 8265c88d0..9a660b947 100644 --- a/bindings_wasm/src/signatures.rs +++ b/bindings_wasm/src/signatures.rs @@ -101,7 +101,7 @@ impl Client { let other_installation_ids = inbox_state .installation_ids() .into_iter() - .filter(|id| id != &installation_id) + .filter(|id| id != installation_id) .collect(); let signature_request = self .inner_client() diff --git a/examples/cli/cli-client.rs b/examples/cli/cli-client.rs index 709c7a8a6..df7fa4c42 100755 --- a/examples/cli/cli-client.rs +++ b/examples/cli/cli-client.rs @@ -443,7 +443,7 @@ async fn main() -> color_eyre::eyre::Result<()> { let conn = client.store().conn().unwrap(); let provider = client.mls_provider().unwrap(); client.sync_welcomes(&conn).await.unwrap(); - client.start_sync_worker(&provider).await.unwrap(); + client.start_sync_worker().await.unwrap(); client .send_sync_request(&provider, DeviceSyncKind::MessageHistory) .await @@ -453,7 +453,7 @@ async fn main() -> color_eyre::eyre::Result<()> { Commands::ListHistorySyncMessages {} => { let conn = client.store().conn()?; client.sync_welcomes(&conn).await?; - let group = client.get_sync_group()?; + let group = client.get_sync_group(&conn)?; let group_id_str = hex::encode(group.group_id.clone()); group.sync().await?; let messages = group diff --git a/examples/cli/debug.rs b/examples/cli/debug.rs index 80311e7ff..c177911dc 100644 --- a/examples/cli/debug.rs +++ b/examples/cli/debug.rs @@ -71,7 +71,7 @@ pub async fn debug_welcome_messages( ) -> Result<(), String> { let api_client = client.api(); let envelopes = api_client - .query_welcome_messages(installation_id, None) + .query_welcome_messages(&installation_id, None) .await .unwrap(); for envelope in envelopes { diff --git a/xmtp_mls/Cargo.toml b/xmtp_mls/Cargo.toml index 11f9582b0..e900fcf95 100644 --- a/xmtp_mls/Cargo.toml +++ b/xmtp_mls/Cargo.toml @@ -95,6 +95,8 @@ tracing-subscriber = { workspace = true, features = [ "env-filter", "fmt", "ansi", + "json", + "registry" ], optional = true } @@ -151,6 +153,7 @@ tracing-subscriber = { workspace = true, features = [ "env-filter", "fmt", "ansi", + "json", ] } xmtp_api_grpc = { path = "../xmtp_api_grpc", features = ["test-utils"] } xmtp_api_http = { path = "../xmtp_api_http", features = ["test-utils"] } @@ -163,7 +166,7 @@ diesel-wasm-sqlite = { workspace = true, features = [ ] } ethers = { workspace = true, features = ["rustls"] } openmls = { workspace = true, features = ["js"] } -tracing-subscriber = { workspace = true, features = ["env-filter"] } +tracing-subscriber = { workspace = true, features = ["env-filter", "json"] } tracing-wasm = { version = "0.2" } wasm-bindgen-test.workspace = true xmtp_api_http = { path = "../xmtp_api_http", features = ["test-utils"] } diff --git a/xmtp_mls/benches/sync.rs b/xmtp_mls/benches/sync.rs index 3dd215f88..970cfaecd 100644 --- a/xmtp_mls/benches/sync.rs +++ b/xmtp_mls/benches/sync.rs @@ -29,14 +29,13 @@ fn start_sync_worker(c: &mut Criterion) { || { bench_async_setup(|| async { let client = clients::new_client(true).await; - let provider = client.mls_provider().unwrap(); // set history sync URL - (client, provider, span.clone()) + (client, span.clone()) }) }, - |(client, provider, span)| async move { + |(client, span)| async move { client - .start_sync_worker(&provider) + .start_sync_worker() .instrument(span) .await .unwrap() diff --git a/xmtp_mls/src/api/mls.rs b/xmtp_mls/src/api/mls.rs index 826f84325..4000467e6 100644 --- a/xmtp_mls/src/api/mls.rs +++ b/xmtp_mls/src/api/mls.rs @@ -117,11 +117,11 @@ where #[tracing::instrument(level = "trace", skip_all)] pub async fn query_welcome_messages( &self, - installation_id: Vec, + installation_id: &[u8], id_cursor: Option, ) -> Result, ApiError> { tracing::debug!( - installation_id = hex::encode(&installation_id), + installation_id = hex::encode(installation_id), cursor = id_cursor, inbox_id = self.inbox_id, "query welcomes" @@ -135,7 +135,7 @@ where (async { self.api_client .query_welcome_messages(QueryWelcomeMessagesRequest { - installation_key: installation_id.clone(), + installation_key: installation_id.to_vec(), paging_info: Some(PagingInfo { id_cursor: id_cursor.unwrap_or(0), limit: page_size, diff --git a/xmtp_mls/src/builder.rs b/xmtp_mls/src/builder.rs index e8303e1ec..450b84666 100644 --- a/xmtp_mls/src/builder.rs +++ b/xmtp_mls/src/builder.rs @@ -709,7 +709,7 @@ pub(crate) mod tests { register_client(&client_a, wallet).await; assert!(client_a.identity().is_ready()); - let keybytes_a = client_a.installation_public_key(); + let keybytes_a = client_a.installation_public_key().to_vec(); drop(client_a); // Reload the existing store and wallet @@ -729,7 +729,7 @@ pub(crate) mod tests { .build_with_verifier() .await .unwrap(); - let keybytes_b = client_b.installation_public_key(); + let keybytes_b = client_b.installation_public_key().to_vec(); drop(client_b); // Ensure the persistence was used to store the generated keys @@ -762,7 +762,7 @@ pub(crate) mod tests { .build_with_verifier() .await .unwrap(); - assert_eq!(client_d.installation_public_key(), keybytes_a); + assert_eq!(client_d.installation_public_key().to_vec(), keybytes_a); } /// anvil cannot be used in WebAssembly diff --git a/xmtp_mls/src/client.rs b/xmtp_mls/src/client.rs index 055252832..8efd0da2d 100644 --- a/xmtp_mls/src/client.rs +++ b/xmtp_mls/src/client.rs @@ -172,8 +172,8 @@ pub struct XmtpMlsLocalContext { impl XmtpMlsLocalContext { /// The installation public key is the primary identifier for an installation - pub fn installation_public_key(&self) -> Vec { - self.identity.installation_keys.public_slice().to_vec() + pub fn installation_public_key(&self) -> &[u8; 32] { + self.identity.installation_keys.public_bytes() } /// Get the account address of the blockchain account associated with this client @@ -259,7 +259,7 @@ where V: SmartContractSignatureVerifier, { /// Retrieves the client's installation public key, sometimes also called `installation_id` - pub fn installation_public_key(&self) -> Vec { + pub fn installation_public_key(&self) -> &[u8; 32] { self.context.installation_public_key() } /// Retrieves the client's inbox ID @@ -560,20 +560,25 @@ where Ok(group) } - pub(crate) fn create_sync_group(&self) -> Result, ClientError> { + pub(crate) fn create_sync_group( + &self, + provider: &XmtpOpenMlsProvider, + ) -> Result, ClientError> { tracing::info!("creating sync group"); - let sync_group = MlsGroup::create_and_insert_sync_group(Arc::new(self.clone()))?; + let sync_group = MlsGroup::create_and_insert_sync_group(Arc::new(self.clone()), provider)?; Ok(sync_group) } - /** - * Look up a group by its ID - * - * Returns a [`MlsGroup`] if the group exists, or an error if it does not - */ - pub fn group(&self, group_id: Vec) -> Result, ClientError> { - let conn = &mut self.store().conn()?; + /// Look up a group by its ID + /// + /// Returns a [`MlsGroup`] if the group exists, or an error if it does not + /// + pub fn group_with_conn( + &self, + conn: &DbConnection, + group_id: Vec, + ) -> Result, ClientError> { let stored_group: Option = conn.fetch(&group_id)?; match stored_group { Some(group) => Ok(MlsGroup::new(self.clone(), group.id, group.created_at_ns)), @@ -584,6 +589,15 @@ where } } + /// Look up a group by its ID + /// + /// Returns a [`MlsGroup`] if the group exists, or an error if it does not + /// + pub fn group(&self, group_id: Vec) -> Result, ClientError> { + let conn = &mut self.store().conn()?; + self.group_with_conn(conn, group_id) + } + /** * Look up a DM group by the target's inbox_id. * @@ -697,7 +711,7 @@ where conn: &DbConnection, ) -> Result, ClientError> { let installation_id = self.installation_public_key(); - let id_cursor = conn.get_last_cursor_for_id(&installation_id, EntityKind::Welcome)?; + let id_cursor = conn.get_last_cursor_for_id(installation_id, EntityKind::Welcome)?; let welcomes = self .api_client @@ -747,7 +761,7 @@ where (async { let welcome_v1 = &welcome_v1; self.intents.process_for_id( - &id, + id, EntityKind::Welcome, welcome_v1.id, |provider| async move { @@ -1021,7 +1035,7 @@ pub(crate) mod tests { // Get original KeyPackage. let kp1 = client - .get_key_packages_for_installation_ids(vec![client.installation_public_key()]) + .get_key_packages_for_installation_ids(vec![client.installation_public_key().to_vec()]) .await .unwrap(); assert_eq!(kp1.len(), 1); @@ -1031,7 +1045,7 @@ pub(crate) mod tests { client.rotate_key_package().await.unwrap(); let kp2 = client - .get_key_packages_for_installation_ids(vec![client.installation_public_key()]) + .get_key_packages_for_installation_ids(vec![client.installation_public_key().to_vec()]) .await .unwrap(); assert_eq!(kp2.len(), 1); @@ -1299,9 +1313,9 @@ pub(crate) mod tests { let bo_store = bo.store(); let alix_original_init_key = - get_key_package_init_key(&alix, &alix.installation_public_key()).await; + get_key_package_init_key(&alix, alix.installation_public_key()).await; let bo_original_init_key = - get_key_package_init_key(&bo, &bo.installation_public_key()).await; + get_key_package_init_key(&bo, bo.installation_public_key()).await; // Bo's original key should be deleted let bo_original_from_db = bo_store @@ -1320,19 +1334,19 @@ pub(crate) mod tests { bo.sync_welcomes(&bo.store().conn().unwrap()).await.unwrap(); - let bo_new_key = get_key_package_init_key(&bo, &bo.installation_public_key()).await; + let bo_new_key = get_key_package_init_key(&bo, bo.installation_public_key()).await; // Bo's key should have changed assert_ne!(bo_original_init_key, bo_new_key); bo.sync_welcomes(&bo.store().conn().unwrap()).await.unwrap(); - let bo_new_key_2 = get_key_package_init_key(&bo, &bo.installation_public_key()).await; + let bo_new_key_2 = get_key_package_init_key(&bo, bo.installation_public_key()).await; // Bo's key should not have changed syncing the second time. assert_eq!(bo_new_key, bo_new_key_2); alix.sync_welcomes(&alix.store().conn().unwrap()) .await .unwrap(); - let alix_key_2 = get_key_package_init_key(&alix, &alix.installation_public_key()).await; + let alix_key_2 = get_key_package_init_key(&alix, alix.installation_public_key()).await; // Alix's key should not have changed at all assert_eq!(alix_original_init_key, alix_key_2); diff --git a/xmtp_mls/src/groups/device_sync.rs b/xmtp_mls/src/groups/device_sync.rs index d9c442daf..8f887f81c 100644 --- a/xmtp_mls/src/groups/device_sync.rs +++ b/xmtp_mls/src/groups/device_sync.rs @@ -118,25 +118,43 @@ where ApiClient: XmtpApi + Send + Sync + 'static, V: SmartContractSignatureVerifier + Send + Sync + 'static, { + // TODO: Should we ensure that only one sync worker is running at a time? #[instrument(level = "trace", skip_all)] - pub async fn start_sync_worker( - &self, - provider: &XmtpOpenMlsProvider, - ) -> Result<(), DeviceSyncError> { - self.sync_init(provider).await?; - + pub async fn start_sync_worker(&self) -> Result<(), DeviceSyncError> { crate::spawn(None, { let client = self.clone(); - + tracing::debug!( + inbox_id = client.inbox_id(), + installation_id = hex::encode(client.installation_public_key()), + "starting sync worker" + ); let receiver = client.local_events.subscribe(); let sync_stream = receiver.stream_sync_messages(); async move { pin_mut!(sync_stream); + let inbox_id = client.inbox_id(); + let installation_id = hex::encode(client.installation_public_key()); + // scope ensures the provider is dropped once init is finished, and not + // held for entirety of sync. + let res = async { + let provider = client.mls_provider()?; + client.sync_init(&provider).await?; + Ok::<_, DeviceSyncError>(()) + }; + + if let Err(e) = res.await { + tracing::error!( + inbox_id, + installation_id, + "sync worker failed to init error = {e}" + ); + } while let Err(err) = client.sync_worker(&mut sync_stream).await { - tracing::error!("Sync worker error: {err}"); + tracing::error!(inbox_id, installation_id, "Sync worker error: {err}"); } + Ok::<_, DeviceSyncError>(()) } }); @@ -184,7 +202,11 @@ where }; if let Err(err) = self.process_sync_reply(&provider, reply).await { - tracing::warn!("Sync worker error: {err}"); + tracing::warn!( + inbox_id = self.inbox_id(), + installation_id = hex::encode(self.installation_public_key()), + "Sync worker error: {err}" + ); } } SyncMessage::Request { message_id } => { @@ -207,7 +229,11 @@ where }; if let Err(err) = self.reply_to_sync_request(&provider, request).await { - tracing::warn!("Sync worker error: {err}"); + tracing::warn!( + inbox_id = self.inbox_id(), + installation_id = hex::encode(self.installation_public_key()), + "Sync worker error: {err}" + ); } } }, @@ -235,10 +261,12 @@ where #[instrument(level = "trace", skip_all)] pub async fn sync_init(&self, provider: &XmtpOpenMlsProvider) -> Result<(), DeviceSyncError> { tracing::info!( + inbox_id = self.inbox_id(), + installation_id = hex::encode(self.installation_public_key()), "Initializing device sync... url: {:?}", self.history_sync_url ); - if self.get_sync_group().is_err() { + if self.get_sync_group(provider.conn_ref()).is_err() { self.ensure_sync_group(provider).await?; self.send_sync_request(provider, DeviceSyncKind::Consent) @@ -246,7 +274,11 @@ where self.send_sync_request(provider, DeviceSyncKind::MessageHistory) .await?; } - tracing::info!("Device sync initialized."); + tracing::info!( + inbox_id = self.inbox_id(), + installation_id = hex::encode(self.installation_public_key()), + "Device sync initialized." + ); Ok(()) } @@ -256,9 +288,9 @@ where &self, provider: &XmtpOpenMlsProvider, ) -> Result, GroupError> { - let sync_group = match self.get_sync_group() { + let sync_group = match self.get_sync_group(provider.conn_ref()) { Ok(group) => group, - Err(_) => self.create_sync_group()?, + Err(_) => self.create_sync_group(provider)?, }; sync_group .maybe_update_installations(provider, None) @@ -274,11 +306,15 @@ where provider: &XmtpOpenMlsProvider, kind: DeviceSyncKind, ) -> Result { - tracing::info!("Sending a sync request for {kind:?}"); + tracing::info!( + inbox_id = self.inbox_id(), + installation_id = hex::encode(self.installation_public_key()), + "Sending a sync request for {kind:?}" + ); let request = DeviceSyncRequest::new(kind); // find the sync group - let sync_group = self.get_sync_group()?; + let sync_group = self.get_sync_group(provider.conn_ref())?; // sync the group sync_group.sync_with_conn(provider).await?; @@ -306,7 +342,12 @@ where // publish the intent if let Err(err) = sync_group.publish_intents(provider).await { - tracing::error!("error publishing sync group intents: {:?}", err); + tracing::error!( + inbox_id = self.inbox_id(), + installation_id = hex::encode(self.installation_public_key()), + "error publishing sync group intents: {:?}", + err + ); } Ok(request) @@ -342,7 +383,7 @@ where ) -> Result<(), DeviceSyncError> { let conn = provider.conn_ref(); // find the sync group - let sync_group = self.get_sync_group()?; + let sync_group = self.get_sync_group(provider.conn_ref())?; // sync the group sync_group.sync_with_conn(provider).await?; @@ -383,7 +424,7 @@ where provider: &XmtpOpenMlsProvider, kind: DeviceSyncKind, ) -> Result<(StoredGroupMessage, DeviceSyncRequestProto), DeviceSyncError> { - let sync_group = self.get_sync_group()?; + let sync_group = self.get_sync_group(provider.conn_ref())?; sync_group.sync_with_conn(provider).await?; let messages = sync_group @@ -416,7 +457,7 @@ where provider: &XmtpOpenMlsProvider, kind: DeviceSyncKind, ) -> Result, DeviceSyncError> { - let sync_group = self.get_sync_group()?; + let sync_group = self.get_sync_group(provider.conn_ref())?; sync_group.sync_with_conn(provider).await?; let messages = sync_group @@ -500,7 +541,11 @@ where return Err(DeviceSyncError::MissingHistorySyncUrl); }; let upload_url = format!("{url}/upload"); - tracing::info!("Using upload url {upload_url}"); + tracing::info!( + inbox_id = self.inbox_id(), + installation_id = hex::encode(self.installation_public_key()), + "Using upload url {upload_url}" + ); let response = reqwest::Client::new() .post(upload_url) @@ -510,6 +555,8 @@ where if !response.status().is_success() { tracing::error!( + inbox_id = self.inbox_id(), + installation_id = hex::encode(self.installation_public_key()), "Failed to upload file. Status code: {} Response: {response:?}", response.status() ); @@ -590,13 +637,12 @@ where } #[instrument(level = "trace", skip_all)] - pub fn get_sync_group(&self) -> Result, GroupError> { - let conn = self.store().conn()?; + pub fn get_sync_group(&self, conn: &DbConnection) -> Result, GroupError> { let sync_group_id = conn .latest_sync_group()? .ok_or(GroupError::GroupNotFound)? .id; - let sync_group = self.group(sync_group_id.clone())?; + let sync_group = self.group_with_conn(conn, sync_group_id.clone())?; Ok(sync_group) } diff --git a/xmtp_mls/src/groups/device_sync/consent_sync.rs b/xmtp_mls/src/groups/device_sync/consent_sync.rs index cd23e10b0..82142f863 100644 --- a/xmtp_mls/src/groups/device_sync/consent_sync.rs +++ b/xmtp_mls/src/groups/device_sync/consent_sync.rs @@ -18,7 +18,12 @@ where provider: &XmtpOpenMlsProvider, record: &StoredConsentRecord, ) -> Result<(), DeviceSyncError> { - tracing::info!("Streaming consent update. {:?}", record); + tracing::info!( + inbox_id = self.inbox_id(), + installation_id = hex::encode(self.installation_public_key()), + "Streaming consent update. {:?}", + record + ); let conn = provider.conn_ref(); let consent_update_proto = ConsentUpdateProto { @@ -75,6 +80,7 @@ pub(crate) mod tests { builder::ClientBuilder, groups::scoped_client::LocalScopedGroupClient, storage::consent_record::{ConsentState, ConsentType}, + utils::test::wait_for_min_intents, }; use xmtp_cryptography::utils::generate_local_wallet; use xmtp_id::InboxOwner; @@ -106,21 +112,30 @@ pub(crate) mod tests { let amal_b = ClientBuilder::new_test_client_with_history(&wallet, &history_sync_url).await; let amal_b_provider = amal_b.mls_provider().unwrap(); let amal_b_conn = amal_b_provider.conn_ref(); - let consent_records_b = amal_b.syncable_consent_records(amal_b_conn).unwrap(); assert_eq!(consent_records_b.len(), 0); - let old_group_id = amal_a.get_sync_group().unwrap().group_id; + // make sure amal's worker has time to sync + // 3 Intents: + // 1.) UpdateGroupMembership Intent for new sync group + // 2.) Device Sync Request + // 3.) MessageHistory Sync Request + wait_for_min_intents(amal_b_conn, 3).await; + tracing::info!("Waiting for intents published"); + + let old_group_id = amal_a.get_sync_group(amal_a_conn).unwrap().group_id; + tracing::info!("Old Group Id: {}", hex::encode(&old_group_id)); // Check for new welcomes to new groups in the first installation (should be welcomed to a new sync group from amal_b). amal_a.sync_welcomes(amal_a_conn).await.unwrap(); - let new_group_id = amal_a.get_sync_group().unwrap().group_id; + let new_group_id = amal_a.get_sync_group(amal_a_conn).unwrap().group_id; + tracing::info!("New Group Id: {}", hex::encode(&new_group_id)); // group id should have changed to the new sync group created by the second installation assert_ne!(old_group_id, new_group_id); let consent_a = amal_a.syncable_consent_records(amal_a_conn).unwrap().len(); // Have amal_a receive the message (and auto-process) - let amal_a_sync_group = amal_a.get_sync_group().unwrap(); + let amal_a_sync_group = amal_a.get_sync_group(amal_a_conn).unwrap(); assert_ok!(amal_a_sync_group.sync_with_conn(&amal_a_provider).await); // Wait for up to 3 seconds for the reply on amal_b (usually is almost instant) @@ -148,7 +163,7 @@ pub(crate) mod tests { } // Test consent streaming - let amal_b_sync_group = amal_b.get_sync_group().unwrap(); + let amal_b_sync_group = amal_b.get_sync_group(amal_b_conn).unwrap(); let bo_wallet = generate_local_wallet(); // Ensure bo is not consented with amal_b diff --git a/xmtp_mls/src/groups/device_sync/message_sync.rs b/xmtp_mls/src/groups/device_sync/message_sync.rs index 3edab260f..c2e4976a7 100644 --- a/xmtp_mls/src/groups/device_sync/message_sync.rs +++ b/xmtp_mls/src/groups/device_sync/message_sync.rs @@ -50,7 +50,7 @@ pub(crate) mod tests { use super::*; use crate::{ assert_ok, builder::ClientBuilder, groups::GroupMetadataOptions, - utils::test::HISTORY_SYNC_URL, + utils::test::wait_for_min_intents, utils::test::HISTORY_SYNC_URL, }; use std::time::{Duration, Instant}; use xmtp_cryptography::utils::generate_local_wallet; @@ -92,13 +92,21 @@ pub(crate) mod tests { let groups_b = amal_b.syncable_groups(amal_b_conn).unwrap(); assert_eq!(groups_b.len(), 0); - let old_group_id = amal_a.get_sync_group().unwrap().group_id; + // make sure amal's worker has time to sync + // 3 Intents: + // 1.) UpdateGroupMembership Intent for new sync group + // 2.) Device Sync Request + // 3.) MessageHistory Sync Request + wait_for_min_intents(amal_b_conn, 3).await; + tracing::info!("Waiting for intents published"); + + let old_group_id = amal_a.get_sync_group(amal_a_conn).unwrap().group_id; // Check for new welcomes to new groups in the first installation (should be welcomed to a new sync group from amal_b). amal_a .sync_welcomes(amal_a_conn) .await .expect("sync_welcomes"); - let new_group_id = amal_a.get_sync_group().unwrap().group_id; + let new_group_id = amal_a.get_sync_group(amal_a_conn).unwrap().group_id; // group id should have changed to the new sync group created by the second installation assert_ne!(old_group_id, new_group_id); @@ -109,7 +117,7 @@ pub(crate) mod tests { .unwrap(); // Have amal_a receive the message (and auto-process) - let amal_a_sync_group = amal_a.get_sync_group().unwrap(); + let amal_a_sync_group = amal_a.get_sync_group(amal_a_conn).unwrap(); assert_ok!(amal_a_sync_group.sync_with_conn(&amal_a_provider).await); // Wait for up to 3 seconds for the reply on amal_b (usually is almost instant) diff --git a/xmtp_mls/src/groups/mls_sync.rs b/xmtp_mls/src/groups/mls_sync.rs index 778c41c4a..a47ec3f9a 100644 --- a/xmtp_mls/src/groups/mls_sync.rs +++ b/xmtp_mls/src/groups/mls_sync.rs @@ -58,7 +58,6 @@ use std::{ mem::{discriminant, Discriminant}, }; use thiserror::Error; -use tracing::debug; use xmtp_id::{InboxId, InboxIdRef}; use xmtp_proto::xmtp::mls::{ api::v1::{ @@ -364,6 +363,7 @@ where let group_epoch = openmls_group.epoch(); debug!( inbox_id = self.client.inbox_id(), + installation_id = hex::encode(self.client.installation_id()), group_id = hex::encode(&self.group_id), current_epoch = openmls_group.epoch().as_u64(), msg_id, @@ -973,9 +973,10 @@ where openmls_group.epoch().as_u64() as i64, )?; tracing::debug!( + inbox_id = self.client.inbox_id(), + installation_id = hex::encode(self.client.installation_id()), intent.id, intent.kind = %intent.kind, - inbox_id = self.client.inbox_id(), group_id = hex::encode(&self.group_id), "client [{}] set stored intent [{}] to state `published`", self.client.inbox_id(), @@ -991,6 +992,7 @@ where intent.id, intent.kind = %intent.kind, inbox_id = self.client.inbox_id(), + installation_id = hex::encode(self.client.installation_id()), group_id = hex::encode(&self.group_id), "[{}] published intent [{}] of type [{}]", self.client.inbox_id(), @@ -1003,7 +1005,11 @@ where } } Ok(None) => { - tracing::info!("Skipping intent because no publish data returned"); + tracing::info!( + inbox_id = self.client.inbox_id(), + installation_id = hex::encode(self.client.installation_id()), + "Skipping intent because no publish data returned" + ); let deleter: &dyn Delete = provider.conn_ref(); deleter.delete(intent.id)?; } @@ -1140,7 +1146,12 @@ where for intent in intents { if let Some(post_commit_data) = intent.post_commit_data { - tracing::debug!(intent.id, intent.kind = %intent.kind, "taking post commit action"); + tracing::debug!( + inbox_id = self.client.inbox_id(), + installation_id = hex::encode(self.client.installation_id()), + intent.id, + intent.kind = %intent.kind, "taking post commit action" + ); let post_commit_action = PostCommitAction::from_bytes(post_commit_data.as_slice())?; match post_commit_action { @@ -1203,7 +1214,12 @@ where return Ok(()); } - debug!("Adding missing installations {:?}", intent_data); + debug!( + inbox_id = self.client.inbox_id(), + installation_id = hex::encode(self.client.installation_id()), + "Adding missing installations {:?}", + intent_data + ); let intent = self.queue_intent_with_conn( provider.conn_ref(), @@ -1392,7 +1408,7 @@ async fn apply_update_group_membership_intent( let mut new_key_packages: Vec = vec![]; if !installation_diff.added_installations.is_empty() { - let my_installation_id = &client.context().installation_public_key(); + let my_installation_id = &client.context().installation_public_key().to_vec(); // Go to the network and load the key packages for any new installation let key_packages = client .get_key_packages_for_installation_ids( diff --git a/xmtp_mls/src/groups/mod.rs b/xmtp_mls/src/groups/mod.rs index bd0b3807b..8060040df 100644 --- a/xmtp_mls/src/groups/mod.rs +++ b/xmtp_mls/src/groups/mod.rs @@ -546,10 +546,10 @@ impl MlsGroup { pub(crate) fn create_and_insert_sync_group( client: Arc, + provider: &XmtpOpenMlsProvider, ) -> Result, GroupError> { let context = client.context(); let creator_inbox_id = context.inbox_id(); - let provider = client.mls_provider()?; let protected_metadata = build_protected_metadata_extension(creator_inbox_id, ConversationType::Sync)?; @@ -687,7 +687,7 @@ impl MlsGroup { decrypted_message_bytes: message.to_vec(), sent_at_ns: now, kind: GroupMessageKind::Application, - sender_installation_id: self.context().installation_public_key(), + sender_installation_id: self.context().installation_public_key().into(), sender_inbox_id: self.context().inbox_id().to_string(), delivery_status: DeliveryStatus::Unpublished, }; @@ -1668,7 +1668,7 @@ pub(crate) mod tests { let serialized_welcome = welcome.tls_serialize_detached().unwrap(); let send_welcomes_action = SendWelcomesAction::new( vec![Installation { - installation_key: new_member_client.installation_public_key(), + installation_key: new_member_client.installation_public_key().into(), hpke_public_key: hpke_init_key, }], serialized_welcome, diff --git a/xmtp_mls/src/groups/scoped_client.rs b/xmtp_mls/src/groups/scoped_client.rs index 75700d432..808fee0e0 100644 --- a/xmtp_mls/src/groups/scoped_client.rs +++ b/xmtp_mls/src/groups/scoped_client.rs @@ -37,6 +37,10 @@ pub trait LocalScopedGroupClient: Send + Sync + Sized { self.context_ref().inbox_id() } + fn installation_id(&self) -> &[u8] { + self.context_ref().installation_public_key() + } + fn mls_provider(&self) -> Result { self.context_ref().mls_provider() } @@ -101,6 +105,10 @@ pub trait ScopedGroupClient: Sized { self.context_ref().inbox_id() } + fn installation_id(&self) -> &[u8] { + self.context_ref().installation_public_key() + } + fn mls_provider(&self) -> Result { self.context_ref().mls_provider() } diff --git a/xmtp_mls/src/identity_updates.rs b/xmtp_mls/src/identity_updates.rs index 7c7220aa9..e4a6cef10 100644 --- a/xmtp_mls/src/identity_updates.rs +++ b/xmtp_mls/src/identity_updates.rs @@ -812,8 +812,8 @@ pub(crate) mod tests { let client_2 = ClientBuilder::new_test_client(&wallet_2).await; let client_3 = ClientBuilder::new_test_client(&wallet_3).await; - let client_2_installation_key = client_2.installation_public_key(); - let client_3_installation_key = client_3.installation_public_key(); + let client_2_installation_key = client_2.installation_public_key().to_vec(); + let client_3_installation_key = client_3.installation_public_key().to_vec(); let mut inbox_ids: Vec = vec![]; @@ -902,11 +902,11 @@ pub(crate) mod tests { assert_eq!(installation_diff.added_installations.len(), 1); assert!(installation_diff .added_installations - .contains(&client_3_installation_key),); + .contains(&client_3_installation_key.to_vec()),); assert_eq!(installation_diff.removed_installations.len(), 1); assert!(installation_diff .removed_installations - .contains(&client_2_installation_key)); + .contains(&client_2_installation_key.to_vec())); } #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] @@ -979,7 +979,7 @@ pub(crate) mod tests { // Now revoke the second client let mut revoke_installation_request = client1 - .revoke_installations(vec![client2.installation_public_key()]) + .revoke_installations(vec![client2.installation_public_key().to_vec()]) .await .unwrap(); add_wallet_signature(&mut revoke_installation_request, &wallet).await; diff --git a/xmtp_mls/src/intents.rs b/xmtp_mls/src/intents.rs index b7b06ef06..7f54daa6d 100644 --- a/xmtp_mls/src/intents.rs +++ b/xmtp_mls/src/intents.rs @@ -52,7 +52,7 @@ impl Intents { /// apply the update after the provided `ProcessingFn` has completed successfully. pub(crate) async fn process_for_id( &self, - entity_id: &Vec, + entity_id: &[u8], entity_kind: EntityKind, cursor: u64, process_envelope: ProcessingFn, diff --git a/xmtp_mls/src/lib.rs b/xmtp_mls/src/lib.rs index 6384cc5de..fb21ba10b 100644 --- a/xmtp_mls/src/lib.rs +++ b/xmtp_mls/src/lib.rs @@ -28,6 +28,9 @@ pub use xmtp_openmls_provider::XmtpOpenMlsProvider; pub use xmtp_id::InboxOwner; pub use xmtp_proto::api_client::trait_impls::*; +#[macro_use] +extern crate tracing; + /// Global Marker trait for WebAssembly #[cfg(target_arch = "wasm32")] pub trait Wasm {} @@ -119,15 +122,45 @@ pub(crate) mod tests { #[cfg_attr(not(target_arch = "wasm32"), ctor::ctor)] #[cfg(not(target_arch = "wasm32"))] fn _setup() { - use tracing_subscriber::{fmt, layer::SubscriberExt, util::SubscriberInitExt, EnvFilter}; + use tracing_subscriber::{ + fmt::{self, format}, + layer::SubscriberExt, + util::SubscriberInitExt, + EnvFilter, Layer, + }; - let filter = EnvFilter::builder() - .with_default_directive(tracing::metadata::LevelFilter::INFO.into()) - .from_env_lossy(); + let structured = std::env::var("STRUCTURED"); + let is_structured = matches!(structured, Ok(s) if s == "true" || s == "1"); + + let filter = || { + EnvFilter::builder() + .with_default_directive(tracing::metadata::LevelFilter::INFO.into()) + .from_env_lossy() + }; tracing_subscriber::registry() - .with(fmt::layer().pretty()) - .with(filter) + // structured JSON logger + .with(is_structured.then(|| { + tracing_subscriber::fmt::layer() + .json() + .flatten_event(true) + .with_level(true) + .with_filter(filter()) + })) + // default logger + .with((!is_structured).then(|| { + fmt::layer() + .compact() + .fmt_fields({ + format::debug_fn(move |writer, field, value| { + if field.name() == "message" { + write!(writer, "{:?}", value)?; + } + Ok(()) + }) + }) + .with_filter(filter()) + })) .init(); } diff --git a/xmtp_mls/src/storage/encrypted_store/refresh_state.rs b/xmtp_mls/src/storage/encrypted_store/refresh_state.rs index 19b6b28cc..34efa6220 100644 --- a/xmtp_mls/src/storage/encrypted_store/refresh_state.rs +++ b/xmtp_mls/src/storage/encrypted_store/refresh_state.rs @@ -92,7 +92,7 @@ impl DbConnection { pub fn update_cursor( &self, - entity_id: &Vec, + entity_id: &[u8], entity_kind: EntityKind, cursor: i64, ) -> Result { diff --git a/xmtp_mls/src/subscriptions.rs b/xmtp_mls/src/subscriptions.rs index d5c9dbf6a..67606dae8 100644 --- a/xmtp_mls/src/subscriptions.rs +++ b/xmtp_mls/src/subscriptions.rs @@ -305,7 +305,7 @@ where tracing::info!(inbox_id = self.inbox_id(), "Setting up conversation stream"); let subscription = self .api_client - .subscribe_welcome_messages(installation_key, Some(id_cursor)) + .subscribe_welcome_messages(installation_key.into(), Some(id_cursor)) .await?; let stream = subscription diff --git a/xmtp_mls/src/utils/test/mod.rs b/xmtp_mls/src/utils/test/mod.rs index 47b56c2bb..aded954b2 100755 --- a/xmtp_mls/src/utils/test/mod.rs +++ b/xmtp_mls/src/utils/test/mod.rs @@ -1,5 +1,13 @@ #![allow(clippy::unwrap_used)] +use crate::storage::DbConnection; +use crate::{ + builder::ClientBuilder, + identity::IdentityStrategy, + storage::{EncryptedMessageStore, StorageOption}, + types::Address, + Client, InboxOwner, XmtpApi, +}; use rand::{ distributions::{Alphanumeric, DistString}, Rng, RngCore, @@ -16,14 +24,6 @@ use xmtp_id::{ }; use xmtp_proto::api_client::XmtpTestClient; -use crate::{ - builder::ClientBuilder, - identity::IdentityStrategy, - storage::{EncryptedMessageStore, StorageOption}, - types::Address, - Client, InboxOwner, XmtpApi, -}; - #[cfg(not(target_arch = "wasm32"))] pub mod traced_test; #[cfg(not(target_arch = "wasm32"))] @@ -109,6 +109,7 @@ impl ClientBuilder { ) } } + impl ClientBuilder { pub async fn new_test_client(owner: &impl InboxOwner) -> FullXmtpClient { let api_client = ::create_local().await; @@ -235,8 +236,7 @@ where register_client(&client, owner).await; if client.history_sync_url.is_some() { - let provider = client.mls_provider().unwrap(); - client.start_sync_worker(&provider).await.unwrap(); + client.start_sync_worker().await.unwrap(); } client @@ -298,3 +298,51 @@ pub async fn register_client( client.register_identity(signature_request).await.unwrap(); } + +/// waits for all intents to finish +/// TODO: Should wrap with a timeout +pub async fn wait_for_all_intents_published(conn: &DbConnection) { + use crate::storage::group_intent::IntentState; + use crate::storage::group_intent::StoredGroupIntent; + use crate::storage::schema::group_intents::dsl; + use diesel::{ExpressionMethods, QueryDsl, RunQueryDsl}; + + let mut query = dsl::group_intents.into_boxed(); + let states = vec![IntentState::ToPublish]; + query = query.filter(dsl::state.eq_any(states)); + query = query.order(dsl::id.asc()); + + let intents = conn + .raw_query(|conn| query.load::(conn)) + .unwrap(); + + tracing::info!("{} intents left", intents.len()); + if intents.is_empty() { + tokio::time::sleep(std::time::Duration::from_secs(1)).await; + Box::pin(wait_for_all_intents_published(conn)).await + } +} + +/// wait for a minimum amount of intent +/// TODO: Should wrap with a timeout +pub async fn wait_for_min_intents(conn: &DbConnection, n: usize) { + use crate::storage::group_intent::IntentState; + use crate::storage::group_intent::StoredGroupIntent; + use crate::storage::schema::group_intents::dsl; + use diesel::{ExpressionMethods, QueryDsl, RunQueryDsl}; + + let mut query = dsl::group_intents.into_boxed(); + let states = vec![IntentState::Published]; + query = query.filter(dsl::state.eq_any(states)); + query = query.order(dsl::id.asc()); + + let intents = conn + .raw_query(|conn| query.load::(conn)) + .unwrap(); + + tracing::info!("{} intents left", intents.len()); + if intents.len() < n { + tokio::time::sleep(std::time::Duration::from_secs(1)).await; + Box::pin(wait_for_min_intents(conn, n - intents.len())).await + } +} From 4620d939c4ab234e528f7fbd4af48177be212eae Mon Sep 17 00:00:00 2001 From: Andrew Plaza Date: Tue, 3 Dec 2024 19:01:39 -0500 Subject: [PATCH 26/46] try with dep target (#1370) --- .github/workflows/release-swift-bindings.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/release-swift-bindings.yml b/.github/workflows/release-swift-bindings.yml index 5fbb052b9..b5b841651 100644 --- a/.github/workflows/release-swift-bindings.yml +++ b/.github/workflows/release-swift-bindings.yml @@ -31,6 +31,7 @@ jobs: - name: Build target env: CROSS_NO_WARNINGS: "0" + IPHONEOS_DEPLOYMENT_TARGET: 10 run: | cross build --release --target ${{ matrix.target }} --manifest-path bindings_ffi/Cargo.toml - name: Upload binary From 34427c9df3e8c98482d6607f1e8091bc672849f6 Mon Sep 17 00:00:00 2001 From: Andrew Plaza Date: Wed, 4 Dec 2024 12:44:15 -0500 Subject: [PATCH 27/46] native logging for android and ios (#1372) --- .cargo/nextest.toml | 2 + .github/workflows/test-ffi-bindings.yml | 2 +- .github/workflows/test-workspace.yml | 4 +- Cargo.lock | 106 +++++++++++++++++++--- bindings_ffi/Cargo.toml | 10 ++- bindings_ffi/src/lib.rs | 3 +- bindings_ffi/src/logger.rs | 111 +++++++++++++++++------- bindings_ffi/src/mls.rs | 35 ++------ bindings_ffi/src/xmtpv3.udl | 4 - bindings_ffi/tests/test_android.kts | 9 +- dev/release-kotlin | 1 + flake.nix | 37 +++++--- rust-toolchain | 4 - xmtp_proto/Cargo.toml | 2 +- 14 files changed, 225 insertions(+), 105 deletions(-) create mode 100644 .cargo/nextest.toml diff --git a/.cargo/nextest.toml b/.cargo/nextest.toml new file mode 100644 index 000000000..07216b1ff --- /dev/null +++ b/.cargo/nextest.toml @@ -0,0 +1,2 @@ +[profile.default] +retries = 3 diff --git a/.github/workflows/test-ffi-bindings.yml b/.github/workflows/test-ffi-bindings.yml index 43b4cc61e..d23ca46ef 100644 --- a/.github/workflows/test-ffi-bindings.yml +++ b/.github/workflows/test-ffi-bindings.yml @@ -50,4 +50,4 @@ jobs: - name: Run cargo nextest on FFI bindings run: | export CLASSPATH="${{ env.CLASSPATH }}" - cargo nextest run --manifest-path bindings_ffi/Cargo.toml --test-threads 2 + cargo nextest --config-file ".cargo/nextest.toml" run --manifest-path bindings_ffi/Cargo.toml --test-threads 2 diff --git a/.github/workflows/test-workspace.yml b/.github/workflows/test-workspace.yml index e565fe64c..a3fc82477 100644 --- a/.github/workflows/test-workspace.yml +++ b/.github/workflows/test-workspace.yml @@ -43,6 +43,6 @@ jobs: - name: Install nextest uses: taiki-e/install-action@nextest - name: build tests - run: cargo nextest run --no-run --workspace --tests --exclude xmtpv3 --exclude bindings_node --exclude bindings_wasm + run: cargo nextest --config-file ".cargo/nextest.toml" run --no-run --workspace --tests --exclude xmtpv3 --exclude bindings_node --exclude bindings_wasm - name: cargo test - run: cargo nextest run --workspace --test-threads 2 --exclude xmtpv3 --exclude bindings_node --exclude bindings_wasm + run: cargo nextest --config-file ".cargo/nextest.toml" run --workspace --test-threads 2 --exclude xmtpv3 --exclude bindings_node --exclude bindings_wasm diff --git a/Cargo.lock b/Cargo.lock index b19d63c22..084c38557 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -427,6 +427,26 @@ dependencies = [ "serde", ] +[[package]] +name = "bindgen" +version = "0.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f49d8fed880d473ea71efb9bf597651e77201bdd4893efe54c9e5d65ae04ce6f" +dependencies = [ + "bitflags 2.6.0", + "cexpr", + "clang-sys", + "itertools 0.13.0", + "log", + "prettyplease", + "proc-macro2", + "quote", + "regex", + "rustc-hash", + "shlex", + "syn 2.0.87", +] + [[package]] name = "bindings_node" version = "0.1.0" @@ -649,6 +669,15 @@ dependencies = [ "shlex", ] +[[package]] +name = "cexpr" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" +dependencies = [ + "nom", +] + [[package]] name = "cfg-if" version = "1.0.0" @@ -731,6 +760,17 @@ dependencies = [ "zeroize", ] +[[package]] +name = "clang-sys" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" +dependencies = [ + "glob", + "libc", + "libloading", +] + [[package]] name = "clap" version = "4.5.21" @@ -3040,6 +3080,12 @@ version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" +[[package]] +name = "jni-sys" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" + [[package]] name = "jobserver" version = "0.1.32" @@ -3617,6 +3663,15 @@ dependencies = [ "tempfile", ] +[[package]] +name = "ndk-sys" +version = "0.5.0+25.2.9519653" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c196769dd60fd4f363e11d948139556a344e79d451aeb2fa2fd040738ef7691" +dependencies = [ + "jni-sys", +] + [[package]] name = "new_debug_unreachable" version = "1.0.6" @@ -3949,6 +4004,20 @@ dependencies = [ "primeorder", ] +[[package]] +name = "paranoid-android" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "101795d63d371b43e38d6e7254677657be82f17022f7f7893c268f33ac0caadc" +dependencies = [ + "lazy_static", + "ndk-sys", + "sharded-slab", + "smallvec", + "tracing-core", + "tracing-subscriber", +] + [[package]] name = "parity-scale-codec" version = "3.7.0" @@ -4833,6 +4902,12 @@ version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + [[package]] name = "rustc-hex" version = "2.1.0" @@ -5678,16 +5753,6 @@ dependencies = [ "syn 2.0.87", ] -[[package]] -name = "thread-id" -version = "5.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99043e46c5a15af379c06add30d9c93a6c0e8849de00d244c4a2c417da128d80" -dependencies = [ - "libc", - "windows-sys 0.59.0", -] - [[package]] name = "thread_local" version = "1.1.8" @@ -6133,6 +6198,21 @@ dependencies = [ "tracing-subscriber", ] +[[package]] +name = "tracing-oslog" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "528bdd1f0e27b5dd9a4ededf154e824b0532731e4af73bb531de46276e0aab1e" +dependencies = [ + "bindgen", + "cc", + "cfg-if", + "once_cell", + "parking_lot 0.12.3", + "tracing-core", + "tracing-subscriber", +] + [[package]] name = "tracing-serde" version = "0.1.3" @@ -7380,12 +7460,14 @@ version = "0.1.0" dependencies = [ "ethers", "futures", - "log", + "paranoid-android", "parking_lot 0.12.3", "rand", "thiserror 2.0.3", - "thread-id", "tokio", + "tracing", + "tracing-oslog", + "tracing-subscriber", "uniffi", "uuid 1.11.0", "xmtp_api_grpc", diff --git a/bindings_ffi/Cargo.toml b/bindings_ffi/Cargo.toml index 00ba44467..938ab78b8 100644 --- a/bindings_ffi/Cargo.toml +++ b/bindings_ffi/Cargo.toml @@ -9,10 +9,10 @@ crate-type = ["lib", "cdylib", "staticlib"] [dependencies] futures.workspace = true -log = { version = "0.4", features = ["std"] } +tracing.workspace = true +tracing-subscriber = { workspace = true, features = ["registry", "env-filter", "fmt", "json"] } parking_lot.workspace = true thiserror.workspace = true -thread-id = "5.0.0" tokio = { workspace = true, features = ["macros"] } uniffi = { version = "0.28.0", default-features = false, features = ["tokio"] } xmtp_api_grpc = { path = "../xmtp_api_grpc" } @@ -23,6 +23,12 @@ xmtp_proto = { path = "../xmtp_proto", features = ["proto_full"] } xmtp_user_preferences = { path = "../xmtp_user_preferences" } xmtp_v2 = { path = "../xmtp_v2" } +[target.'cfg(target_os = "android")'.dependencies] +paranoid-android = "0.2" + +[target.'cfg(target_os = "ios")'.dependencies] +tracing-oslog = "0.2" + [build-dependencies] uniffi = { version = "0.28.0", features = ["build"] } diff --git a/bindings_ffi/src/lib.rs b/bindings_ffi/src/lib.rs index e60e1fe34..670ec176e 100755 --- a/bindings_ffi/src/lib.rs +++ b/bindings_ffi/src/lib.rs @@ -7,10 +7,11 @@ pub mod v2; pub use crate::inbox_owner::SigningError; use inbox_owner::FfiInboxOwner; -use logger::FfiLogger; pub use mls::*; use std::error::Error; +extern crate tracing as log; + pub use ffi::*; #[allow(clippy::all)] mod ffi { diff --git a/bindings_ffi/src/logger.rs b/bindings_ffi/src/logger.rs index 5e9d0c623..c4b00e349 100644 --- a/bindings_ffi/src/logger.rs +++ b/bindings_ffi/src/logger.rs @@ -1,43 +1,96 @@ -use log::{LevelFilter, Metadata, Record}; +use log::Subscriber; use std::sync::Once; +use tracing_subscriber::{ + layer::SubscriberExt, registry::LookupSpan, util::SubscriberInitExt, Layer, +}; -pub trait FfiLogger: Send + Sync { - fn log(&self, level: u32, level_label: String, message: String); +#[cfg(target_os = "android")] +pub use android::*; +#[cfg(target_os = "android")] +mod android { + use super::*; + pub fn native_layer() -> impl Layer + where + S: Subscriber + for<'a> LookupSpan<'a>, + { + paranoid_android::layer(env!("CARGO_PKG_NAME")).with_thread_names(true) + } } -struct RustLogger { - logger: parking_lot::Mutex>, +#[cfg(target_os = "ios")] +pub use ios::*; +#[cfg(target_os = "ios")] +mod ios { + use super::*; + // use tracing_subscriber::Layer; + pub fn native_layer() -> impl Layer + where + S: Subscriber + for<'a> LookupSpan<'a>, + { + use tracing_oslog::OsLogger; + let subsystem = format!("org.xmtp.{}", env!("CARGO_PKG_NAME")); + OsLogger::new(subsystem, "default") + } } -impl log::Log for RustLogger { - fn enabled(&self, _metadata: &Metadata) -> bool { - true - } +#[cfg(not(any(target_os = "ios", target_os = "android")))] +pub use other::*; +#[cfg(not(any(target_os = "ios", target_os = "android")))] +mod other { + use super::*; - fn log(&self, record: &Record) { - if self.enabled(record.metadata()) { - // TODO handle errors - self.logger.lock().log( - record.level() as u32, - record.level().to_string(), - format!("[libxmtp][t:{}] {}", thread_id::get(), record.args()), - ); - } - } + pub fn native_layer() -> impl Layer + where + S: Subscriber + for<'a> LookupSpan<'a>, + { + use tracing_subscriber::{ + fmt::{self, format}, + EnvFilter, Layer, + }; + let structured = std::env::var("STRUCTURED"); + let is_structured = matches!(structured, Ok(s) if s == "true" || s == "1"); - fn flush(&self) {} + let filter = || { + EnvFilter::builder() + .with_default_directive(tracing::metadata::LevelFilter::INFO.into()) + .from_env_lossy() + }; + + vec![ + // structured JSON logger + is_structured + .then(|| { + tracing_subscriber::fmt::layer() + .json() + .flatten_event(true) + .with_level(true) + .with_filter(filter()) + }) + .boxed(), + // default logger + (!is_structured) + .then(|| { + fmt::layer() + .compact() + .fmt_fields({ + format::debug_fn(move |writer, field, value| { + if field.name() == "message" { + write!(writer, "{:?}", value)?; + } + Ok(()) + }) + }) + .with_filter(filter()) + }) + .boxed(), + ] + } } static LOGGER_INIT: Once = Once::new(); -pub fn init_logger(logger: Box) { - // TODO handle errors +pub fn init_logger() { LOGGER_INIT.call_once(|| { - let logger = RustLogger { - logger: parking_lot::Mutex::new(logger), - }; - log::set_boxed_logger(Box::new(logger)) - .map(|()| log::set_max_level(LevelFilter::Info)) - .expect("Failed to initialize logger"); - log::info!("Logger initialized"); + let native_layer = native_layer(); + tracing_subscriber::registry().with(native_layer).init() }); } diff --git a/bindings_ffi/src/mls.rs b/bindings_ffi/src/mls.rs index 93f534aea..e899374bf 100644 --- a/bindings_ffi/src/mls.rs +++ b/bindings_ffi/src/mls.rs @@ -1,6 +1,5 @@ pub use crate::inbox_owner::SigningError; use crate::logger::init_logger; -use crate::logger::FfiLogger; use crate::{FfiSubscribeError, GenericError}; use std::{collections::HashMap, convert::TryInto, sync::Arc}; use tokio::sync::Mutex; @@ -71,7 +70,6 @@ pub type RustXmtpClient = MlsClient; #[allow(clippy::too_many_arguments)] #[uniffi::export(async_runtime = "tokio")] pub async fn create_client( - logger: Box, host: String, is_secure: bool, db: Option, @@ -82,7 +80,7 @@ pub async fn create_client( legacy_signed_private_key_proto: Option>, history_sync_url: Option, ) -> Result, GenericError> { - init_logger(logger); + init_logger(); log::info!( "Creating API client for host: {}, isSecure: {}", host, @@ -142,7 +140,6 @@ pub async fn create_client( #[allow(unused)] #[uniffi::export(async_runtime = "tokio")] pub async fn get_inbox_id_for_address( - logger: Box, host: String, is_secure: bool, account_address: String, @@ -1798,11 +1795,11 @@ impl FfiGroupPermissions { mod tests { use super::{create_client, FfiConsentCallback, FfiMessage, FfiMessageCallback, FfiXmtpClient}; use crate::{ - get_inbox_id_for_address, inbox_owner::SigningError, logger::FfiLogger, FfiConsent, - FfiConsentEntityType, FfiConsentState, FfiConversation, FfiConversationCallback, - FfiConversationMessageKind, FfiCreateGroupOptions, FfiGroupPermissionsOptions, - FfiInboxOwner, FfiListConversationsOptions, FfiListMessagesOptions, FfiMetadataField, - FfiPermissionPolicy, FfiPermissionPolicySet, FfiPermissionUpdateType, FfiSubscribeError, + get_inbox_id_for_address, inbox_owner::SigningError, FfiConsent, FfiConsentEntityType, + FfiConsentState, FfiConversation, FfiConversationCallback, FfiConversationMessageKind, + FfiCreateGroupOptions, FfiGroupPermissionsOptions, FfiInboxOwner, + FfiListConversationsOptions, FfiListMessagesOptions, FfiMetadataField, FfiPermissionPolicy, + FfiPermissionPolicySet, FfiPermissionUpdateType, FfiSubscribeError, }; use ethers::utils::hex; use rand::distributions::{Alphanumeric, DistString}; @@ -1859,14 +1856,6 @@ mod tests { } } - pub struct MockLogger {} - - impl FfiLogger for MockLogger { - fn log(&self, _level: u32, level_label: String, message: String) { - println!("[{}]{}", level_label, message) - } - } - #[derive(Default)] struct RustStreamCallback { num_messages: AtomicU32, @@ -1988,7 +1977,6 @@ mod tests { let inbox_id = generate_inbox_id(&ffi_inbox_owner.get_address(), &nonce).unwrap(); let client = create_client( - Box::new(MockLogger {}), xmtp_api_grpc::LOCALHOST_ADDRESS.to_string(), false, Some(tmp_path()), @@ -2031,7 +2019,6 @@ mod tests { let real_inbox_id = client.inbox_id(); let from_network = get_inbox_id_for_address( - Box::new(MockLogger {}), xmtp_api_grpc::LOCALHOST_ADDRESS.to_string(), false, client.account_address.clone(), @@ -2052,7 +2039,6 @@ mod tests { let inbox_id = generate_inbox_id(&account_address, &nonce).unwrap(); let client = create_client( - Box::new(MockLogger {}), xmtp_api_grpc::LOCALHOST_ADDRESS.to_string(), false, Some(tmp_path()), @@ -2078,7 +2064,6 @@ mod tests { let path = tmp_path(); let client_a = create_client( - Box::new(MockLogger {}), xmtp_api_grpc::LOCALHOST_ADDRESS.to_string(), false, Some(path.clone()), @@ -2097,7 +2082,6 @@ mod tests { drop(client_a); let client_b = create_client( - Box::new(MockLogger {}), xmtp_api_grpc::LOCALHOST_ADDRESS.to_string(), false, Some(path), @@ -2131,7 +2115,6 @@ mod tests { let key = static_enc_key().to_vec(); let client_a = create_client( - Box::new(MockLogger {}), xmtp_api_grpc::LOCALHOST_ADDRESS.to_string(), false, Some(path.clone()), @@ -2151,7 +2134,6 @@ mod tests { other_key[31] = 1; let result_errored = create_client( - Box::new(MockLogger {}), xmtp_api_grpc::LOCALHOST_ADDRESS.to_string(), false, Some(path), @@ -2204,7 +2186,6 @@ mod tests { let path = tmp_path(); let key = static_enc_key().to_vec(); let client = create_client( - Box::new(MockLogger {}), xmtp_api_grpc::LOCALHOST_ADDRESS.to_string(), false, Some(path.clone()), @@ -2270,7 +2251,6 @@ mod tests { let path = tmp_path(); let key = static_enc_key().to_vec(); let client = create_client( - Box::new(MockLogger {}), xmtp_api_grpc::LOCALHOST_ADDRESS.to_string(), false, Some(path.clone()), @@ -2358,7 +2338,6 @@ mod tests { let path = tmp_path(); let client = create_client( - Box::new(MockLogger {}), xmtp_api_grpc::LOCALHOST_ADDRESS.to_string(), false, Some(path.clone()), @@ -2386,7 +2365,6 @@ mod tests { let path = tmp_path(); let client_amal = create_client( - Box::new(MockLogger {}), xmtp_api_grpc::LOCALHOST_ADDRESS.to_string(), false, Some(path.clone()), @@ -2413,7 +2391,6 @@ mod tests { ); let client_bola = create_client( - Box::new(MockLogger {}), xmtp_api_grpc::LOCALHOST_ADDRESS.to_string(), false, Some(path.clone()), diff --git a/bindings_ffi/src/xmtpv3.udl b/bindings_ffi/src/xmtpv3.udl index fa7fef7a1..635ba512e 100644 --- a/bindings_ffi/src/xmtpv3.udl +++ b/bindings_ffi/src/xmtpv3.udl @@ -12,7 +12,3 @@ callback interface FfiInboxOwner { [Throws=SigningError] bytes sign(string text); }; - -callback interface FfiLogger { - void log(u32 level, string level_label, string message); -}; \ No newline at end of file diff --git a/bindings_ffi/tests/test_android.kts b/bindings_ffi/tests/test_android.kts index 21871d2db..fd787db1d 100644 --- a/bindings_ffi/tests/test_android.kts +++ b/bindings_ffi/tests/test_android.kts @@ -17,20 +17,15 @@ class Web3jInboxOwner(private val credentials: Credentials) : FfiInboxOwner { } } -class MockLogger : FfiLogger { - override fun log(level: UInt, levelLabel: String, message: String) {} -} - val privateKey: ByteArray = SecureRandom().generateSeed(32) val credentials: Credentials = Credentials.create(ECKeyPair.create(privateKey)) val inboxOwner = Web3jInboxOwner(credentials) -var logger = MockLogger() // TODO Tests sometimes hang and never complete // runBlocking { // val apiUrl: String = System.getenv("XMTP_API_URL") ?: "http://localhost:5556" // try { -// val client = uniffi.xmtpv3.createClient(logger, inboxOwner, apiUrl, false) +// val client = uniffi.xmtpv3.createClient(inboxOwner, apiUrl, false) // assert(client.walletAddress() != null) { // "Should be able to get wallet address" // } @@ -43,7 +38,7 @@ var logger = MockLogger() // runBlocking { // try { -// val client = uniffi.xmtpv3.createClient(logger, inboxOwner, "http://malformed:5556", false); +// val client = uniffi.xmtpv3.createClient(inboxOwner, "http://malformed:5556", false); // assert(false) { // "Should throw error with malformed network address" // } diff --git a/dev/release-kotlin b/dev/release-kotlin index 86c1ff670..74e507509 100755 --- a/dev/release-kotlin +++ b/dev/release-kotlin @@ -42,6 +42,7 @@ nix develop . --command cargo ndk -o bindings_ffi/jniLibs/ --manifest-path ./bin -t armv7-linux-androideabi \ -- build --release + for arch in arm64-v8a armeabi-v7a x86 x86_64; do mv "./bindings_ffi/jniLibs/$arch/$LIBRARY_NAME.so" "./bindings_ffi/jniLibs/$arch/$TARGET_NAME.so" done diff --git a/flake.nix b/flake.nix index 006af47ec..df8aaf766 100644 --- a/flake.nix +++ b/flake.nix @@ -41,12 +41,21 @@ includeNDK = true; }; - fenixPkgs = fenix.packages.${system}; + androidTargets = [ + "aarch64-linux-android" + "armv7-linux-androideabi" + "x86_64-linux-android" + "i686-linux-android" + ]; + # Pinned Rust Version - rust-toolchain = fenixPkgs.fromToolchainFile { - file = ./rust-toolchain; - sha256 = "sha256-yMuSb5eQPO/bHv+Bcf/US8LVMbf/G/0MSfiPwBhiPpk="; - }; + rust-toolchain = with fenix.packages.${system}; combine [ + stable.cargo + stable.rustc + (pkgs.lib.forEach + androidTargets + (target: targets."${target}".stable.rust-std)) + ]; # https://github.com/NixOS/nixpkgs/blob/master/doc/languages-frameworks/android.section.md androidHome = "${androidComposition.androidsdk}/libexec/android-sdk"; @@ -66,7 +75,8 @@ # System Libraries sqlite openssl - ] ++ lib.optionals isDarwin [ # optional packages if on darwin, in order to check if build passes locally + ] ++ lib.optionals isDarwin [ + # optional packages if on darwin, in order to check if build passes locally libiconv frameworks.CoreServices frameworks.Carbon @@ -74,14 +84,15 @@ frameworks.AppKit darwin.cctools ]; - in { + in + { devShells.default = pkgs.mkShell { - OPENSSL_DIR = "${pkgs.openssl.dev}"; - ANDROID_HOME = androidHome; - ANDROID_SDK_ROOT = androidHome; # ANDROID_SDK_ROOT is deprecated, but some tools may still use it; - ANDROID_NDK_ROOT = "${androidHome}/ndk-bundle"; + OPENSSL_DIR = "${pkgs.openssl.dev}"; + ANDROID_HOME = androidHome; + ANDROID_SDK_ROOT = androidHome; # ANDROID_SDK_ROOT is deprecated, but some tools may still use it; + ANDROID_NDK_ROOT = "${androidHome}/ndk-bundle"; - inherit buildInputs nativeBuildInputs; - }; + inherit buildInputs nativeBuildInputs; + }; }); } diff --git a/rust-toolchain b/rust-toolchain index d408d6b65..d9aa0516c 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -4,10 +4,6 @@ components = [ "rustc", "cargo", "clippy", "rustfmt", "rust-analyzer" ] targets = [ "wasm32-unknown-unknown", "x86_64-unknown-linux-gnu", - "aarch64-linux-android", - "armv7-linux-androideabi", - "x86_64-linux-android", - "i686-linux-android", "x86_64-apple-ios", "x86_64-apple-darwin", "aarch64-apple-ios" diff --git a/xmtp_proto/Cargo.toml b/xmtp_proto/Cargo.toml index 1a6a2905a..c376941a1 100644 --- a/xmtp_proto/Cargo.toml +++ b/xmtp_proto/Cargo.toml @@ -14,7 +14,7 @@ serde = { workspace = true } async-trait = "0.1" hex.workspace = true openmls_rust_crypto = { workspace = true, optional = true } -tracing.workspace = true +tracing.workspace = true [target.'cfg(not(target_arch = "wasm32"))'.dependencies] tonic = { workspace = true } From 76114b271f4c81f281748ab2494e04d4c6d01909 Mon Sep 17 00:00:00 2001 From: Dakota Brink <779390+codabrink@users.noreply.github.com> Date: Wed, 4 Dec 2024 14:58:44 -0500 Subject: [PATCH 28/46] Do not error out when there is no receiver (#1375) --- xmtp_mls/src/groups/mod.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/xmtp_mls/src/groups/mod.rs b/xmtp_mls/src/groups/mod.rs index 8060040df..12440397c 100644 --- a/xmtp_mls/src/groups/mod.rs +++ b/xmtp_mls/src/groups/mod.rs @@ -1090,10 +1090,10 @@ impl MlsGroup { if self.client.history_sync_url().is_some() { // Dispatch an update event so it can be synced across devices - self.client + let _ = self + .client .local_events() - .send(LocalEvents::OutgoingConsentUpdates(vec![consent_record])) - .map_err(|e| GroupError::Generic(e.to_string()))?; + .send(LocalEvents::OutgoingConsentUpdates(vec![consent_record])); } Ok(()) From 3103e7b9374297eece7c68a52fb6ba6fd082ffe3 Mon Sep 17 00:00:00 2001 From: Andrew Plaza Date: Wed, 4 Dec 2024 19:24:03 -0500 Subject: [PATCH 29/46] fix sync worker err loop (#1378) --- bindings_ffi/src/mls.rs | 15 +- examples/cli/cli-client.rs | 2 +- xmtp_mls/Cargo.toml | 8 +- xmtp_mls/benches/sync.rs | 102 +++--- xmtp_mls/src/client.rs | 26 +- xmtp_mls/src/groups/device_sync.rs | 323 ++++++++++-------- .../src/groups/device_sync/message_sync.rs | 90 +++++ xmtp_mls/src/utils/test/mod.rs | 2 +- 8 files changed, 352 insertions(+), 216 deletions(-) diff --git a/bindings_ffi/src/mls.rs b/bindings_ffi/src/mls.rs index e899374bf..248e2621d 100644 --- a/bindings_ffi/src/mls.rs +++ b/bindings_ffi/src/mls.rs @@ -440,23 +440,16 @@ impl FfiXmtpClient { .register_identity(signature_request.clone()) .await?; - self.maybe_start_sync_worker().await?; + self.maybe_start_sync_worker(); Ok(()) } /// Starts the sync worker if the history sync url is present. - async fn maybe_start_sync_worker(&self) -> Result<(), GenericError> { - if self.inner_client.history_sync_url().is_none() { - return Ok(()); + fn maybe_start_sync_worker(&self) { + if self.inner_client.history_sync_url().is_some() { + self.inner_client.start_sync_worker(); } - - self.inner_client - .start_sync_worker() - .await - .map_err(GenericError::from_error)?; - - Ok(()) } pub async fn send_sync_request(&self, kind: FfiDeviceSyncKind) -> Result<(), GenericError> { diff --git a/examples/cli/cli-client.rs b/examples/cli/cli-client.rs index df7fa4c42..b371edef1 100755 --- a/examples/cli/cli-client.rs +++ b/examples/cli/cli-client.rs @@ -443,7 +443,7 @@ async fn main() -> color_eyre::eyre::Result<()> { let conn = client.store().conn().unwrap(); let provider = client.mls_provider().unwrap(); client.sync_welcomes(&conn).await.unwrap(); - client.start_sync_worker().await.unwrap(); + client.start_sync_worker(); client .send_sync_request(&provider, DeviceSyncKind::MessageHistory) .await diff --git a/xmtp_mls/Cargo.toml b/xmtp_mls/Cargo.toml index e900fcf95..2c9350b25 100644 --- a/xmtp_mls/Cargo.toml +++ b/xmtp_mls/Cargo.toml @@ -192,8 +192,8 @@ harness = false name = "identity" required-features = ["bench"] -[[bench]] -harness = false -name = "sync" -required-features = ["bench"] +#[[bench]] +#harness = false +#name = "sync" +#required-features = ["bench"] diff --git a/xmtp_mls/benches/sync.rs b/xmtp_mls/benches/sync.rs index 970cfaecd..821a1de20 100644 --- a/xmtp_mls/benches/sync.rs +++ b/xmtp_mls/benches/sync.rs @@ -1,55 +1,49 @@ -//! Benchmarking for syncing functions -use crate::tracing::Instrument; -use criterion::{criterion_group, criterion_main, BatchSize, Criterion}; -use tokio::runtime::{Builder, Runtime}; -use xmtp_mls::utils::bench::{bench_async_setup, BENCH_ROOT_SPAN}; -use xmtp_mls::utils::bench::{clients, init_logging}; +// //! Benchmarking for syncing functions +// use crate::tracing::Instrument; +// use criterion::{criterion_group, criterion_main, BatchSize, Criterion}; +// use tokio::runtime::{Builder, Runtime}; +// use xmtp_mls::utils::bench::{bench_async_setup, BENCH_ROOT_SPAN}; +// use xmtp_mls::utils::bench::{clients, init_logging}; +// +// #[macro_use] +// extern crate tracing; +// +// fn setup() -> Runtime { +// Builder::new_multi_thread() +// .enable_time() +// .enable_io() +// .thread_name("xmtp-bencher") +// .build() +// .unwrap() +// } +// +// fn start_sync_worker(c: &mut Criterion) { +// init_logging(); +// +// let runtime = setup(); +// let mut benchmark_group = c.benchmark_group("start_sync_worker"); +// benchmark_group.sample_size(10); +// benchmark_group.bench_function("start_sync_worker", |b| { +// let span = trace_span!(BENCH_ROOT_SPAN); +// b.to_async(&runtime).iter_batched( +// || { +// bench_async_setup(|| async { +// let client = clients::new_client(true).await; +// // set history sync URL +// (client, span.clone()) +// }) +// }, +// |(client, span)| async move { client.start_sync_worker().instrument(span) }, +// BatchSize::SmallInput, +// ) +// }); +// +// benchmark_group.finish(); +// } -#[macro_use] -extern crate tracing; - -fn setup() -> Runtime { - Builder::new_multi_thread() - .enable_time() - .enable_io() - .thread_name("xmtp-bencher") - .build() - .unwrap() -} - -fn start_sync_worker(c: &mut Criterion) { - init_logging(); - - let runtime = setup(); - let mut benchmark_group = c.benchmark_group("start_sync_worker"); - benchmark_group.sample_size(10); - benchmark_group.bench_function("start_sync_worker", |b| { - let span = trace_span!(BENCH_ROOT_SPAN); - b.to_async(&runtime).iter_batched( - || { - bench_async_setup(|| async { - let client = clients::new_client(true).await; - // set history sync URL - (client, span.clone()) - }) - }, - |(client, span)| async move { - client - .start_sync_worker() - .instrument(span) - .await - .unwrap() - }, - BatchSize::SmallInput, - ) - }); - - benchmark_group.finish(); -} - -criterion_group!( - name = sync; - config = Criterion::default().sample_size(10); - targets = start_sync_worker -); -criterion_main!(sync); +// criterion_group!( +// name = sync; +// config = Criterion::default().sample_size(10); +// targets = start_sync_worker +// ); +// criterion_main!(sync); diff --git a/xmtp_mls/src/client.rs b/xmtp_mls/src/client.rs index 8efd0da2d..eb6a86ab1 100644 --- a/xmtp_mls/src/client.rs +++ b/xmtp_mls/src/client.rs @@ -40,13 +40,13 @@ use crate::{ mutex_registry::MutexRegistry, retry::Retry, retry_async, retryable, - storage::wallet_addresses::WalletEntry, storage::{ consent_record::{ConsentState, ConsentType, StoredConsentRecord}, db_connection::DbConnection, group::{GroupMembershipState, GroupQueryArgs, StoredGroup}, group_message::StoredGroupMessage, refresh_state::EntityKind, + wallet_addresses::WalletEntry, EncryptedMessageStore, StorageError, }, subscriptions::{LocalEventError, LocalEvents}, @@ -253,6 +253,25 @@ where } } +impl Client +where + ApiClient: XmtpApi + Send + Sync + 'static, + V: SmartContractSignatureVerifier + Send + Sync + 'static, +{ + /// Reconnect to the client's database if it has previously been released + pub fn reconnect_db(&self) -> Result<(), ClientError> { + self.context.store.reconnect()?; + // restart all the workers + // TODO: The only worker we have right now are the + // sync workers. if we have other workers we + // should create a better way to track them. + if self.history_sync_url.is_some() { + self.start_sync_worker(); + } + Ok(()) + } +} + impl Client where ApiClient: XmtpApi, @@ -467,11 +486,6 @@ where Ok(()) } - /// Reconnect to the client's database if it has previously been released - pub fn reconnect_db(&self) -> Result<(), ClientError> { - self.context.store.reconnect()?; - Ok(()) - } /// Get a reference to the client's identity struct pub fn identity(&self) -> &Identity { &self.context.identity diff --git a/xmtp_mls/src/groups/device_sync.rs b/xmtp_mls/src/groups/device_sync.rs index 8f887f81c..e2f6ae4d9 100644 --- a/xmtp_mls/src/groups/device_sync.rs +++ b/xmtp_mls/src/groups/device_sync.rs @@ -1,6 +1,6 @@ use super::{GroupError, MlsGroup}; use crate::configuration::NS_IN_HOUR; -use crate::retry::{RetryBuilder, RetryableError}; +use crate::retry::{Retry, RetryableError}; use crate::storage::group::{ConversationType, GroupQueryArgs}; use crate::storage::group_message::MsgQueryArgs; use crate::storage::DbConnection; @@ -23,14 +23,16 @@ use aes_gcm::{ aead::{Aead, KeyInit}, Aes256Gcm, }; -use futures::{pin_mut, Stream, StreamExt}; +use futures::{Stream, StreamExt}; use rand::{ distributions::{Alphanumeric, DistString}, Rng, RngCore, }; use serde::{Deserialize, Serialize}; +use std::pin::Pin; use std::time::Duration; use thiserror::Error; +use tokio::sync::OnceCell; use tracing::{instrument, warn}; use xmtp_cryptography::utils as crypto_utils; use xmtp_id::scw_verifier::SmartContractSignatureVerifier; @@ -120,169 +122,219 @@ where { // TODO: Should we ensure that only one sync worker is running at a time? #[instrument(level = "trace", skip_all)] - pub async fn start_sync_worker(&self) -> Result<(), DeviceSyncError> { - crate::spawn(None, { - let client = self.clone(); - tracing::debug!( - inbox_id = client.inbox_id(), - installation_id = hex::encode(client.installation_public_key()), - "starting sync worker" - ); - let receiver = client.local_events.subscribe(); - let sync_stream = receiver.stream_sync_messages(); - - async move { - pin_mut!(sync_stream); - let inbox_id = client.inbox_id(); - let installation_id = hex::encode(client.installation_public_key()); - // scope ensures the provider is dropped once init is finished, and not - // held for entirety of sync. - let res = async { - let provider = client.mls_provider()?; - client.sync_init(&provider).await?; - Ok::<_, DeviceSyncError>(()) - }; - - if let Err(e) = res.await { - tracing::error!( - inbox_id, - installation_id, - "sync worker failed to init error = {e}" - ); - } - - while let Err(err) = client.sync_worker(&mut sync_stream).await { - tracing::error!(inbox_id, installation_id, "Sync worker error: {err}"); - } - Ok::<_, DeviceSyncError>(()) - } - }); + pub fn start_sync_worker(&self) { + let client = self.clone(); + tracing::debug!( + inbox_id = client.inbox_id(), + installation_id = hex::encode(client.installation_public_key()), + "starting sync worker" + ); - Ok(()) + SyncWorker::new(client).spawn_worker(); } } -impl Client +pub struct SyncWorker { + client: Client, + /// The sync events stream + #[allow(clippy::type_complexity)] + stream: Pin< + Box>, SubscribeError>> + Send>, + >, + init: OnceCell<()>, + retry: Retry, +} + +impl SyncWorker where - ApiClient: XmtpApi, - V: SmartContractSignatureVerifier, + ApiClient: XmtpApi + 'static, + V: SmartContractSignatureVerifier + 'static, { - pub(crate) async fn sync_worker( - &self, - sync_stream: &mut (impl Stream, SubscribeError>> + Unpin), - ) -> Result<(), DeviceSyncError> { - let provider = self.mls_provider()?; + async fn run(&mut self) -> Result<(), DeviceSyncError> { + self.sync_init().await?; - let query_retry = RetryBuilder::default() - .retries(5) - .duration(Duration::from_millis(20)) - .build(); - - while let Some(event) = sync_stream.next().await { + while let Some(event) = self.stream.next().await { let event = event?; match event { LocalEvents::SyncMessage(msg) => match msg { SyncMessage::Reply { message_id } => { - let conn = provider.conn_ref(); - let msg = retry_async!( - &query_retry, - (async { - conn.get_group_message(&message_id)?.ok_or( - DeviceSyncError::Storage(StorageError::NotFound(format!( - "Message id {message_id:?} not found." - ))), - ) - }) - )?; - - let msg_content: DeviceSyncContent = - serde_json::from_slice(&msg.decrypted_message_bytes)?; - let DeviceSyncContent::Reply(reply) = msg_content else { - unreachable!(); - }; - - if let Err(err) = self.process_sync_reply(&provider, reply).await { - tracing::warn!( - inbox_id = self.inbox_id(), - installation_id = hex::encode(self.installation_public_key()), - "Sync worker error: {err}" - ); - } + let provider = self.client.mls_provider()?; + self.on_reply(message_id, &provider).await? } SyncMessage::Request { message_id } => { - let conn = provider.conn_ref(); - let msg = retry_async!( - &query_retry, - (async { - conn.get_group_message(&message_id)?.ok_or( - DeviceSyncError::Storage(StorageError::NotFound(format!( - "Message id {message_id:?} not found." - ))), - ) - }) - )?; - - let msg_content: DeviceSyncContent = - serde_json::from_slice(&msg.decrypted_message_bytes)?; - let DeviceSyncContent::Request(request) = msg_content else { - unreachable!(); - }; - - if let Err(err) = self.reply_to_sync_request(&provider, request).await { - tracing::warn!( - inbox_id = self.inbox_id(), - installation_id = hex::encode(self.installation_public_key()), - "Sync worker error: {err}" - ); - } + let provider = self.client.mls_provider()?; + self.on_request(message_id, &provider).await? } }, LocalEvents::OutgoingConsentUpdates(consent_records) => { + let provider = self.client.mls_provider()?; for consent_record in consent_records { - self.send_consent_update(&provider, &consent_record).await?; + self.client + .send_consent_update(&provider, &consent_record) + .await?; } } LocalEvents::IncomingConsentUpdates(consent_records) => { - let conn = provider.conn_ref(); - - conn.insert_or_replace_consent_records(&consent_records)?; + let provider = self.client.mls_provider()?; + provider + .conn_ref() + .insert_or_replace_consent_records(&consent_records)?; } _ => {} } } + Ok(()) + } + + async fn on_reply( + &mut self, + message_id: Vec, + provider: &XmtpOpenMlsProvider, + ) -> Result<(), DeviceSyncError> { + let conn = provider.conn_ref(); + let Self { + ref client, + ref retry, + .. + } = self; + + let msg = retry_async!( + retry, + (async { + conn.get_group_message(&message_id)? + .ok_or(DeviceSyncError::Storage(StorageError::NotFound(format!( + "Message id {message_id:?} not found." + )))) + }) + )?; + + let msg_content: DeviceSyncContent = serde_json::from_slice(&msg.decrypted_message_bytes)?; + let DeviceSyncContent::Reply(reply) = msg_content else { + unreachable!(); + }; + + client.process_sync_reply(provider, reply).await?; + Ok(()) + } + async fn on_request( + &mut self, + message_id: Vec, + provider: &XmtpOpenMlsProvider, + ) -> Result<(), DeviceSyncError> { + let conn = provider.conn_ref(); + let Self { + ref client, retry, .. + } = self; + + let msg = retry_async!( + retry, + (async { + conn.get_group_message(&message_id)? + .ok_or(DeviceSyncError::Storage(StorageError::NotFound(format!( + "Message id {message_id:?} not found." + )))) + }) + )?; + + let msg_content: DeviceSyncContent = serde_json::from_slice(&msg.decrypted_message_bytes)?; + let DeviceSyncContent::Request(request) = msg_content else { + unreachable!(); + }; + + client.reply_to_sync_request(provider, request).await?; Ok(()) } - /** - * Ideally called when the client is registered. - * Will auto-send a sync request if sync group is created. - */ + //// Ideally called when the client is registered. + //// Will auto-send a sync request if sync group is created. #[instrument(level = "trace", skip_all)] - pub async fn sync_init(&self, provider: &XmtpOpenMlsProvider) -> Result<(), DeviceSyncError> { - tracing::info!( - inbox_id = self.inbox_id(), - installation_id = hex::encode(self.installation_public_key()), - "Initializing device sync... url: {:?}", - self.history_sync_url - ); - if self.get_sync_group(provider.conn_ref()).is_err() { - self.ensure_sync_group(provider).await?; + pub async fn sync_init(&mut self) -> Result<(), DeviceSyncError> { + let Self { + ref init, + ref client, + .. + } = self; + + init.get_or_try_init(|| async { + let provider = self.client.mls_provider()?; + tracing::info!( + inbox_id = client.inbox_id(), + installation_id = hex::encode(client.installation_public_key()), + "Initializing device sync... url: {:?}", + client.history_sync_url + ); + if client.get_sync_group(provider.conn_ref()).is_err() { + client.ensure_sync_group(&provider).await?; + + client + .send_sync_request(&provider, DeviceSyncKind::Consent) + .await?; + client + .send_sync_request(&provider, DeviceSyncKind::MessageHistory) + .await?; + } + tracing::info!( + inbox_id = client.inbox_id(), + installation_id = hex::encode(client.installation_public_key()), + "Device sync initialized." + ); + + Ok(()) + }) + .await + .copied() + } +} - self.send_sync_request(provider, DeviceSyncKind::Consent) - .await?; - self.send_sync_request(provider, DeviceSyncKind::MessageHistory) - .await?; +impl SyncWorker +where + ApiClient: XmtpApi + Send + Sync + 'static, + V: SmartContractSignatureVerifier + Send + Sync + 'static, +{ + fn new(client: Client) -> Self { + let retry = Retry::builder() + .retries(5) + .duration(Duration::from_millis(20)) + .build(); + + let receiver = client.local_events.subscribe(); + let stream = Box::pin(receiver.stream_sync_messages()); + + Self { + client, + stream, + init: OnceCell::new(), + retry, } - tracing::info!( - inbox_id = self.inbox_id(), - installation_id = hex::encode(self.installation_public_key()), - "Device sync initialized." - ); + } - Ok(()) + fn spawn_worker(mut self) { + crate::spawn(None, async move { + let inbox_id = self.client.inbox_id().to_string(); + let installation_id = hex::encode(self.client.installation_public_key()); + while let Err(err) = self.run().await { + match err { + DeviceSyncError::Client(ClientError::Storage( + StorageError::PoolNeedsConnection, + )) => { + tracing::warn!("Pool disconnected. task will restart on reconnect"); + break; + } + _ => { + tracing::error!(inbox_id, installation_id, "sync worker error {err}"); + } + } + } + }); } +} +impl Client +where + ApiClient: XmtpApi, + V: SmartContractSignatureVerifier, +{ #[instrument(level = "trace", skip_all)] async fn ensure_sync_group( &self, @@ -341,14 +393,7 @@ where })?; // publish the intent - if let Err(err) = sync_group.publish_intents(provider).await { - tracing::error!( - inbox_id = self.inbox_id(), - installation_id = hex::encode(self.installation_public_key()), - "error publishing sync group intents: {:?}", - err - ); - } + sync_group.publish_intents(provider).await?; Ok(request) } diff --git a/xmtp_mls/src/groups/device_sync/message_sync.rs b/xmtp_mls/src/groups/device_sync/message_sync.rs index c2e4976a7..9d2c05362 100644 --- a/xmtp_mls/src/groups/device_sync/message_sync.rs +++ b/xmtp_mls/src/groups/device_sync/message_sync.rs @@ -148,6 +148,96 @@ pub(crate) mod tests { } } + #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + async fn test_sync_continues_during_db_disconnect() { + let wallet = generate_local_wallet(); + let amal_a = ClientBuilder::new_test_client_with_history(&wallet, HISTORY_SYNC_URL).await; + + let amal_a_provider = amal_a.mls_provider().unwrap(); + let amal_a_conn = amal_a_provider.conn_ref(); + + // make sure amal's worker has time to sync + // 3 Intents: + // 1.) UpdateGroupMembership Intent for new sync group + // 2.) Device Sync Request + // 3.) MessageHistory Sync Request + wait_for_min_intents(amal_a_conn, 3).await; + tracing::info!("Waiting for intents published"); + let old_group_id = amal_a.get_sync_group(amal_a_conn).unwrap().group_id; + + // let old_group_id = amal_a.get_sync_group(amal_a_conn).unwrap().group_id; + tracing::info!("Disconnecting"); + amal_a.release_db_connection().unwrap(); + + // Create a second installation for amal. + let amal_b = ClientBuilder::new_test_client_with_history(&wallet, HISTORY_SYNC_URL).await; + let amal_b_provider = amal_b.mls_provider().unwrap(); + let amal_b_conn = amal_b_provider.conn_ref(); + + let groups_b = amal_b.syncable_groups(amal_b_conn).unwrap(); + assert_eq!(groups_b.len(), 0); + + // make sure amal's worker has time to sync + // 3 Intents: + // 1.) UpdateGroupMembership Intent for new sync group + // 2.) Device Sync Request + // 3.) MessageHistory Sync Request + wait_for_min_intents(amal_b_conn, 3).await; + tracing::info!("Waiting for intents published"); + + // Have the second installation request for a consent sync. + amal_b + .send_sync_request(&amal_b_provider, DeviceSyncKind::MessageHistory) + .await + .unwrap(); + + amal_a.reconnect_db().unwrap(); + + // make sure amal's worker has time to sync + // 2 Intents: + // 1.) Device Sync Request + // 2.) MessageHistory Sync Request + wait_for_min_intents(amal_a_conn, 2).await; + tracing::info!("Waiting for intents published"); + + // Check for new welcomes to new groups in the first installation (should be welcomed to a new sync group from amal_b). + amal_a + .sync_welcomes(amal_a_conn) + .await + .expect("sync_welcomes"); + let new_group_id = amal_a.get_sync_group(amal_a_conn).unwrap().group_id; + // group id should have changed to the new sync group created by the second installation + assert_ne!(old_group_id, new_group_id); + } + + #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + async fn disconnect_does_not_effect_init() { + let wallet = generate_local_wallet(); + let amal_a = ClientBuilder::new_test_client_with_history(&wallet, HISTORY_SYNC_URL).await; + + let amal_a_provider = amal_a.mls_provider().unwrap(); + let amal_a_conn = amal_a_provider.conn_ref(); + + //release db conn right after creating client, not giving the worker time to do initial + //sync + amal_a.release_db_connection().unwrap(); + + let sync_group = amal_a.get_sync_group(amal_a_conn); + crate::assert_err!(sync_group, GroupError::GroupNotFound); + + amal_a.reconnect_db().unwrap(); + + // make sure amal's worker has time to sync + // 3 Intents: + // 1.) Sync Group Creation + // 2.) Device Sync Request + // 3.) MessageHistory Sync Request + wait_for_min_intents(amal_a_conn, 3).await; + tracing::info!("Waiting for intents published"); + let sync_group = amal_a.get_sync_group(amal_a_conn); + assert!(sync_group.is_ok()); + } + #[tokio::test(flavor = "multi_thread", worker_threads = 1)] async fn test_prepare_groups_to_sync() { let wallet = generate_local_wallet(); diff --git a/xmtp_mls/src/utils/test/mod.rs b/xmtp_mls/src/utils/test/mod.rs index aded954b2..5bfc36341 100755 --- a/xmtp_mls/src/utils/test/mod.rs +++ b/xmtp_mls/src/utils/test/mod.rs @@ -236,7 +236,7 @@ where register_client(&client, owner).await; if client.history_sync_url.is_some() { - client.start_sync_worker().await.unwrap(); + client.start_sync_worker(); } client From 07c84704fcb0a0b9a5c676705472af51be5d5af1 Mon Sep 17 00:00:00 2001 From: Cameron Voell <1103838+cameronvoell@users.noreply.github.com> Date: Wed, 4 Dec 2024 16:51:05 -0800 Subject: [PATCH 30/46] Prevents future migrations from hitting error (#1344) * prevents future migrations from hitting error * Try extra derives for improving error checking * Revert "Try extra derives for improving error checking" This reverts commit dd9289bd94b34c32b8b3cecef02dd48313466e38. --------- Co-authored-by: cameronvoell --- xmtp_mls/src/storage/encrypted_store/group.rs | 4 ++-- xmtp_mls/src/storage/encrypted_store/schema.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/xmtp_mls/src/storage/encrypted_store/group.rs b/xmtp_mls/src/storage/encrypted_store/group.rs index 1bd426db7..c9e28051b 100644 --- a/xmtp_mls/src/storage/encrypted_store/group.rs +++ b/xmtp_mls/src/storage/encrypted_store/group.rs @@ -32,8 +32,6 @@ pub struct StoredGroup { pub membership_state: GroupMembershipState, /// Track when the latest, most recent installations were checked pub installations_last_checked: i64, - /// Enum, [`ConversationType`] signifies the group conversation type which extends to who can access it. - pub conversation_type: ConversationType, /// The inbox_id of who added the user to a group. pub added_by_inbox_id: String, /// The sequence id of the welcome message @@ -42,6 +40,8 @@ pub struct StoredGroup { pub dm_inbox_id: Option, /// The last time the leaf node encryption key was rotated pub rotated_at_ns: i64, + /// Enum, [`ConversationType`] signifies the group conversation type which extends to who can access it. + pub conversation_type: ConversationType, } impl_fetch!(StoredGroup, groups, Vec); diff --git a/xmtp_mls/src/storage/encrypted_store/schema.rs b/xmtp_mls/src/storage/encrypted_store/schema.rs index 5a6e3385b..db79db920 100644 --- a/xmtp_mls/src/storage/encrypted_store/schema.rs +++ b/xmtp_mls/src/storage/encrypted_store/schema.rs @@ -50,11 +50,11 @@ diesel::table! { created_at_ns -> BigInt, membership_state -> Integer, installations_last_checked -> BigInt, - conversation_type -> Integer, added_by_inbox_id -> Text, welcome_id -> Nullable, dm_inbox_id -> Nullable, rotated_at_ns -> BigInt, + conversation_type -> Integer, } } From 5849947903f796085fb3a0102d00968728e47f47 Mon Sep 17 00:00:00 2001 From: Dakota Brink <779390+codabrink@users.noreply.github.com> Date: Wed, 4 Dec 2024 21:12:47 -0500 Subject: [PATCH 31/46] Start the sync worker in the builder (#1365) * Start the sync worker in the builder * wait for identity * tweak test * keep life simple rn * helpers * stop, web time * test fix * Some WASM help from Andrew * test fix * Add sync and send constraints * lint * Add send, sync to wasm sync worker * propagate sync, send a bit more * propagate * propagate * propagate * wait for identity to be ready * cleanup * cleanup --- Cargo.lock | 1 + Cargo.toml | 53 +++++++++--------- bindings_ffi/src/mls.rs | 49 +++++++++++------ xmtp_mls/Cargo.toml | 19 ++++--- xmtp_mls/src/api/mod.rs | 2 +- xmtp_mls/src/api/test_utils.rs | 55 +++++++++++++++++++ xmtp_mls/src/builder.rs | 20 ++++--- xmtp_mls/src/groups/device_sync.rs | 5 +- .../src/groups/device_sync/consent_sync.rs | 2 +- .../src/groups/device_sync/message_sync.rs | 37 ++++++------- xmtp_mls/src/storage/encrypted_store/group.rs | 8 +++ xmtp_mls/src/utils/test/mod.rs | 8 +-- 12 files changed, 175 insertions(+), 84 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 084c38557..07e02c708 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7400,6 +7400,7 @@ dependencies = [ "wasm-bindgen-test", "wasm-timer", "web-sys", + "web-time", "xmtp_api_grpc", "xmtp_api_http", "xmtp_cryptography", diff --git a/Cargo.toml b/Cargo.toml index 0c2025a8e..41a238589 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,7 +14,7 @@ members = [ "bindings_node", "bindings_ffi", "xtask", - "xmtp_debug" + "xmtp_debug", ] # Make the feature resolver explicit. @@ -22,15 +22,15 @@ members = [ resolver = "2" [workspace.package] -version = "0.1.0" license = "MIT" +version = "0.1.0" [workspace.dependencies] anyhow = "1.0" async-stream = "0.3" async-trait = "0.1.77" +base64 = "0.22" chrono = "0.4.38" -wasm-timer = "0.2" ctor = "0.2" ed25519 = "2.2.3" ed25519-dalek = { version = "2.1.1", features = ["zeroize"] } @@ -48,8 +48,6 @@ pbjson-types = "0.7.0" prost = "^0.13" prost-types = "^0.13" rand = "0.8.5" -uuid = "1.10" -base64 = "0.22" regex = "1.10.4" rustc-hex = "2.1.0" serde = { version = "1.0", default-features = false } @@ -59,6 +57,9 @@ sha3 = "0.10.8" thiserror = "2.0" tls_codec = "0.4.1" tokio = { version = "1.35.1", default-features = false } +uuid = "1.10" +wasm-timer = "0.2" +web-time = "1.1" # Changing this version and rustls may potentially break the android build. Use Caution. # Test with Android and Swift first. # Its probably preferable to one day use https://github.com/rustls/rustls-platform-verifier @@ -67,34 +68,36 @@ tokio = { version = "1.35.1", default-features = false } # - https://github.com/seanmonstar/reqwest/issues/2159 # - https://github.com/hyperium/tonic/pull/1974 # - https://github.com/rustls/rustls-platform-verifier/issues/58 -tonic = { version = "0.12", default-features = false } -tracing = { version = "0.1", features = ["log"] } -tracing-subscriber = { version = "0.3", default-features = false } +bincode = "1.3" +console_error_panic_hook = "0.1" +const_format = "0.2" diesel = { version = "2.2", default-features = false } diesel-wasm-sqlite = "0.0.1" diesel_migrations = { version = "2.2", default-features = false } -parking_lot = "0.12.3" -wasm-bindgen-futures = "0.4" -wasm-bindgen = "=0.2.97" -wasm-bindgen-test = "0.3.47" +dyn-clone = "1" +fdlimit = "0.3" gloo-timers = "0.3" -web-sys = "0.3" js-sys = "0.3" -openssl-sys = { version = "0.9", features = ["vendored"] } +libsqlite3-sys = { version = "0.29", features = [ + "bundled-sqlcipher-vendored-openssl", +] } openssl = { version = "0.10", features = ["vendored"] } -libsqlite3-sys = { version = "0.29", features = ["bundled-sqlcipher-vendored-openssl" ] } -dyn-clone = "1" +openssl-sys = { version = "0.9", features = ["vendored"] } +parking_lot = "0.12.3" +tonic = { version = "0.12", default-features = false } +tracing = { version = "0.1", features = ["log"] } +tracing-subscriber = { version = "0.3", default-features = false } trait-variant = "0.1.2" url = "2.5.0" +wasm-bindgen = "=0.2.97" +wasm-bindgen-futures = "0.4" +wasm-bindgen-test = "0.3.47" +web-sys = "0.3" zeroize = "1.8" -bincode = "1.3" -console_error_panic_hook = "0.1" -fdlimit = "0.3" -const_format = "0.2" # Internal Crate Dependencies -xmtp_cryptography = { path = "xmtp_cryptography" } xmtp_api_grpc = { path = "xmtp_api_grpc" } +xmtp_cryptography = { path = "xmtp_cryptography" } xmtp_id = { path = "xmtp_id" } xmtp_mls = { path = "xmtp_mls" } xmtp_proto = { path = "xmtp_proto" } @@ -124,10 +127,10 @@ strip = "symbols" # NOTE: The release profile reduces bundle size from 230M to 41M - may have performance impliciations # https://stackoverflow.com/a/54842093 [profile.release.package.xmtpv3] +codegen-units = 1 # Reduce number of codegen units to increase optimizations inherits = "release-with-lto" -codegen-units = 1 # Reduce number of codegen units to increase optimizations -opt-level = 'z' # Optimize for size + loop vectorization -strip = true # Strip symbols from binary* +opt-level = 'z' # Optimize for size + loop vectorization +strip = true # Strip symbols from binary* [profile.release.package.bindings_wasm] inherits = "release-with-lto" @@ -138,7 +141,7 @@ opt-level = "s" # are made public for third-party dependencies: https://github.com/diesel-rs/diesel/pull/4236 # (cfg-specific patche support does not exist) [patch.crates-io] -diesel-wasm-sqlite = { git = "https://github.com/xmtp/diesel-wasm-sqlite", branch = "main" } diesel = { git = "https://github.com/diesel-rs/diesel", branch = "master" } +diesel-wasm-sqlite = { git = "https://github.com/xmtp/diesel-wasm-sqlite", branch = "main" } diesel_derives = { git = "https://github.com/diesel-rs/diesel", branch = "master" } diesel_migrations = { git = "https://github.com/diesel-rs/diesel", branch = "master" } diff --git a/bindings_ffi/src/mls.rs b/bindings_ffi/src/mls.rs index 248e2621d..6c58ee573 100644 --- a/bindings_ffi/src/mls.rs +++ b/bindings_ffi/src/mls.rs @@ -440,18 +440,9 @@ impl FfiXmtpClient { .register_identity(signature_request.clone()) .await?; - self.maybe_start_sync_worker(); - Ok(()) } - /// Starts the sync worker if the history sync url is present. - fn maybe_start_sync_worker(&self) { - if self.inner_client.history_sync_url().is_some() { - self.inner_client.start_sync_worker(); - } - } - pub async fn send_sync_request(&self, kind: FfiDeviceSyncKind) -> Result<(), GenericError> { let provider = self.inner_client.mls_provider()?; self.inner_client @@ -1811,6 +1802,7 @@ mod tests { unverified::{UnverifiedRecoverableEcdsaSignature, UnverifiedSignature}, }; use xmtp_mls::{ + api::test_utils::{wait_for_eq, wait_for_ok}, groups::{scoped_client::LocalScopedGroupClient, GroupError}, storage::EncryptionKey, InboxOwner, @@ -2585,7 +2577,7 @@ mod tests { } bo.conversations().sync().await.unwrap(); let num_groups_synced_1: u32 = bo.conversations().sync_all_conversations().await.unwrap(); - assert!(num_groups_synced_1 == 30); + assert_eq!(num_groups_synced_1, 30); // Remove bo from all groups and sync for group in alix @@ -2602,11 +2594,11 @@ mod tests { // First sync after removal needs to process all groups and set them to inactive let num_groups_synced_2: u32 = bo.conversations().sync_all_conversations().await.unwrap(); - assert!(num_groups_synced_2 == 30); + assert_eq!(num_groups_synced_2, 30); // Second sync after removal will not process inactive groups let num_groups_synced_3: u32 = bo.conversations().sync_all_conversations().await.unwrap(); - assert!(num_groups_synced_3 == 0); + assert_eq!(num_groups_synced_3, 0); } #[tokio::test(flavor = "multi_thread", worker_threads = 5)] @@ -4061,15 +4053,40 @@ mod tests { async fn test_stream_consent() { let wallet = generate_local_wallet(); let alix_a = new_test_client_with_wallet_and_history(wallet.clone()).await; + let alix_a_conn = alix_a.inner_client.store().conn().unwrap(); + // wait for alix_a's sync worker to create a sync group + let _ = wait_for_ok(|| async { alix_a.inner_client.get_sync_group(&alix_a_conn) }).await; + let alix_b = new_test_client_with_wallet_and_history(wallet).await; + wait_for_eq(|| async { alix_b.inner_client.identity().is_ready() }, true).await; + let bo = new_test_client_with_history().await; - // have alix_a pull down the new sync group created by alix_b - assert!(alix_a.conversations().sync().await.is_ok()); + // wait for the first installation to get invited to the new sync group + wait_for_eq( + || async { + assert!(alix_a.conversations().sync().await.is_ok()); + alix_a + .inner_client + .store() + .conn() + .unwrap() + .all_sync_groups() + .unwrap() + .len() + }, + 2, + ) + .await; // check that they have the same sync group - let sync_group_a = alix_a.conversations().get_sync_group().unwrap(); - let sync_group_b = alix_b.conversations().get_sync_group().unwrap(); + let sync_group_a = wait_for_ok(|| async { alix_a.conversations().get_sync_group() }) + .await + .unwrap(); + let sync_group_b = wait_for_ok(|| async { alix_b.conversations().get_sync_group() }) + .await + .unwrap(); + assert_eq!(sync_group_a.id(), sync_group_b.id()); // create a stream from both installations diff --git a/xmtp_mls/Cargo.toml b/xmtp_mls/Cargo.toml index 2c9350b25..1d10929c6 100644 --- a/xmtp_mls/Cargo.toml +++ b/xmtp_mls/Cargo.toml @@ -25,7 +25,7 @@ bench = [ "criterion", "dep:fdlimit", "dep:ethers", - "dep:const_format" + "dep:const_format", ] default = ["grpc-api"] grpc-api = ["dep:xmtp_api_grpc"] @@ -38,7 +38,8 @@ test-utils = [ "xmtp_proto/test-utils", "xmtp_api_http/test-utils", "xmtp_api_grpc/test-utils", - "dep:const_format" + "dep:const_format", + "mockall", ] update-schema = ["toml"] @@ -66,6 +67,7 @@ tokio-stream = { version = "0.1", default-features = false, features = [ tracing.workspace = true trait-variant.workspace = true wasm-timer.workspace = true +web-time.workspace = true zeroize.workspace = true # XMTP/Local @@ -75,12 +77,12 @@ xmtp_proto = { workspace = true, features = ["convert"] } # Optional/Features console_error_panic_hook = { workspace = true, optional = true } +const_format = { workspace = true, optional = true } +ethers = { workspace = true, features = ["openssl"], optional = true } +fdlimit = { workspace = true, optional = true } toml = { version = "0.8.4", optional = true } tracing-wasm = { version = "0.2", optional = true } xmtp_api_http = { path = "../xmtp_api_http", optional = true } -fdlimit = { workspace = true, optional = true } -ethers = { workspace = true, features = ["openssl"], optional = true } -const_format = { workspace = true, optional = true } # Test/Bench Utils anyhow = { workspace = true, optional = true } @@ -89,6 +91,7 @@ criterion = { version = "0.5", features = [ "async_tokio", ], optional = true } indicatif = { version = "0.17", optional = true } +mockall = { version = "0.13.1", optional = true } once_cell = { version = "1.19", optional = true } tracing-flame = { version = "0.2", optional = true } tracing-subscriber = { workspace = true, features = [ @@ -96,7 +99,7 @@ tracing-subscriber = { workspace = true, features = [ "fmt", "ansi", "json", - "registry" + "registry", ], optional = true } @@ -137,11 +140,11 @@ web-sys.workspace = true [dev-dependencies] anyhow.workspace = true +const_format.workspace = true mockall = "0.13.1" openmls_basic_credential.workspace = true xmtp_id = { path = "../xmtp_id", features = ["test-utils"] } xmtp_proto = { workspace = true, features = ["test-utils"] } -const_format.workspace = true [target.'cfg(not(target_arch = "wasm32"))'.dev-dependencies] ctor.workspace = true @@ -192,8 +195,8 @@ harness = false name = "identity" required-features = ["bench"] + #[[bench]] #harness = false #name = "sync" #required-features = ["bench"] - diff --git a/xmtp_mls/src/api/mod.rs b/xmtp_mls/src/api/mod.rs index c9255e01f..8cd71039d 100644 --- a/xmtp_mls/src/api/mod.rs +++ b/xmtp_mls/src/api/mod.rs @@ -1,6 +1,6 @@ pub mod identity; pub mod mls; -#[cfg(test)] +#[cfg(any(test, feature = "test-utils"))] pub mod test_utils; use std::sync::Arc; diff --git a/xmtp_mls/src/api/test_utils.rs b/xmtp_mls/src/api/test_utils.rs index 829166507..087877624 100644 --- a/xmtp_mls/src/api/test_utils.rs +++ b/xmtp_mls/src/api/test_utils.rs @@ -1,3 +1,6 @@ +use std::{future::Future, time::Duration}; +use web_time::Instant; + use mockall::mock; use xmtp_proto::{ api_client::{ClientWithMetadata, XmtpIdentityClient, XmtpMlsClient, XmtpMlsStreams}, @@ -176,3 +179,55 @@ mod wasm { } } } + +pub async fn wait_for_some(f: F) -> Option +where + F: Fn() -> Fut, + Fut: Future>, +{ + let start = Instant::now(); + while start.elapsed() < Duration::from_secs(3) { + let result = f().await; + if result.is_some() { + return result; + } + crate::sleep(Duration::from_millis(100)).await; + } + None +} + +pub async fn wait_for_ok(f: F) -> Result +where + F: Fn() -> Fut, + Fut: Future>, +{ + let start = Instant::now(); + let mut result = f().await; + while start.elapsed() < Duration::from_secs(3) { + if result.is_ok() { + return result; + } + crate::sleep(Duration::from_millis(100)).await; + result = f().await; + } + result +} + +pub async fn wait_for_eq(f: F, expected: T) +where + F: Fn() -> Fut, + Fut: Future, + T: std::fmt::Debug + PartialEq, +{ + let start = Instant::now(); + let mut result = f().await; + while start.elapsed() < Duration::from_secs(3) { + if result == expected { + break; + } + crate::sleep(Duration::from_millis(100)).await; + result = f().await; + } + + assert_eq!(expected, result); +} diff --git a/xmtp_mls/src/builder.rs b/xmtp_mls/src/builder.rs index 450b84666..930c81506 100644 --- a/xmtp_mls/src/builder.rs +++ b/xmtp_mls/src/builder.rs @@ -110,8 +110,8 @@ impl ClientBuilder { impl ClientBuilder where - ApiClient: XmtpApi + 'static, - V: SmartContractSignatureVerifier + 'static, + ApiClient: XmtpApi + 'static + Send + Sync, + V: SmartContractSignatureVerifier + 'static + Send + Sync, { /// Build with a custom smart contract wallet verifier pub async fn build_with_verifier(self) -> Result, ClientBuilderError> { @@ -122,7 +122,7 @@ where impl ClientBuilder> where - ApiClient: XmtpApi + 'static, + ApiClient: XmtpApi + 'static + Send + Sync, { /// Build with the default [`RemoteSignatureVerifier`] pub async fn build(self) -> Result, ClientBuilderError> { @@ -163,8 +163,8 @@ async fn inner_build( api_client: Arc, ) -> Result, ClientBuilderError> where - C: XmtpApi + 'static, - V: SmartContractSignatureVerifier + 'static, + C: XmtpApi + 'static + Send + Sync, + V: SmartContractSignatureVerifier + 'static + Send + Sync, { let ClientBuilder { mut store, @@ -204,13 +204,19 @@ where ) .await?; - Ok(Client::new( + let client = Client::new( api_client_wrapper, identity, store, scw_verifier, history_sync_url.clone(), - )) + ); + + if history_sync_url.is_some() { + client.start_sync_worker(); + } + + Ok(client) } #[cfg(test)] diff --git a/xmtp_mls/src/groups/device_sync.rs b/xmtp_mls/src/groups/device_sync.rs index e2f6ae4d9..2a8d65983 100644 --- a/xmtp_mls/src/groups/device_sync.rs +++ b/xmtp_mls/src/groups/device_sync.rs @@ -120,7 +120,6 @@ where ApiClient: XmtpApi + Send + Sync + 'static, V: SmartContractSignatureVerifier + Send + Sync + 'static, { - // TODO: Should we ensure that only one sync worker is running at a time? #[instrument(level = "trace", skip_all)] pub fn start_sync_worker(&self) { let client = self.clone(); @@ -151,6 +150,10 @@ where V: SmartContractSignatureVerifier + 'static, { async fn run(&mut self) -> Result<(), DeviceSyncError> { + // Wait for the identity to be ready before doing anything + while !self.client.identity().is_ready() { + crate::sleep(Duration::from_millis(200)).await; + } self.sync_init().await?; while let Some(event) = self.stream.next().await { diff --git a/xmtp_mls/src/groups/device_sync/consent_sync.rs b/xmtp_mls/src/groups/device_sync/consent_sync.rs index 82142f863..0075c1230 100644 --- a/xmtp_mls/src/groups/device_sync/consent_sync.rs +++ b/xmtp_mls/src/groups/device_sync/consent_sync.rs @@ -120,8 +120,8 @@ pub(crate) mod tests { // 1.) UpdateGroupMembership Intent for new sync group // 2.) Device Sync Request // 3.) MessageHistory Sync Request - wait_for_min_intents(amal_b_conn, 3).await; tracing::info!("Waiting for intents published"); + wait_for_min_intents(amal_b_conn, 3).await; let old_group_id = amal_a.get_sync_group(amal_a_conn).unwrap().group_id; tracing::info!("Old Group Id: {}", hex::encode(&old_group_id)); diff --git a/xmtp_mls/src/groups/device_sync/message_sync.rs b/xmtp_mls/src/groups/device_sync/message_sync.rs index 9d2c05362..056f0c3e7 100644 --- a/xmtp_mls/src/groups/device_sync/message_sync.rs +++ b/xmtp_mls/src/groups/device_sync/message_sync.rs @@ -49,8 +49,11 @@ pub(crate) mod tests { use super::*; use crate::{ - assert_ok, builder::ClientBuilder, groups::GroupMetadataOptions, - utils::test::wait_for_min_intents, utils::test::HISTORY_SYNC_URL, + api::test_utils::wait_for_some, + assert_ok, + builder::ClientBuilder, + groups::GroupMetadataOptions, + utils::test::{wait_for_min_intents, HISTORY_SYNC_URL}, }; use std::time::{Duration, Instant}; use xmtp_cryptography::utils::generate_local_wallet; @@ -263,35 +266,31 @@ pub(crate) mod tests { .await .expect("sync welcomes"); - let external_wallet = generate_local_wallet(); - let external_client = - ClientBuilder::new_test_client_with_history(&external_wallet, HISTORY_SYNC_URL).await; + let bo_wallet = generate_local_wallet(); + let bo_client = + ClientBuilder::new_test_client_with_history(&bo_wallet, HISTORY_SYNC_URL).await; - external_client - .sync_welcomes(&external_client.store().conn().unwrap()) + bo_client + .sync_welcomes(&bo_client.store().conn().unwrap()) .await .expect("sync welcomes"); - let amal_sync_group = amal - .store() - .conn() - .unwrap() - .latest_sync_group() - .expect("find sync group"); + let amal_sync_group = + wait_for_some(|| async { amal.store().conn().unwrap().latest_sync_group().unwrap() }) + .await; + assert!(amal_sync_group.is_some()); + let amal_sync_group = amal_sync_group.unwrap(); // try to join amal's sync group let sync_group_id = amal_sync_group.id.clone(); let created_at_ns = amal_sync_group.created_at_ns; - let external_client_group = MlsGroup::new( - external_client.clone(), - sync_group_id.clone(), - created_at_ns, - ); + let external_client_group = + MlsGroup::new(bo_client.clone(), sync_group_id.clone(), created_at_ns); let result = external_client_group - .add_members(&[external_wallet.get_address()]) + .add_members(&[bo_wallet.get_address()]) .await; assert!(result.is_err()); } diff --git a/xmtp_mls/src/storage/encrypted_store/group.rs b/xmtp_mls/src/storage/encrypted_store/group.rs index c9e28051b..2cecc9b4f 100644 --- a/xmtp_mls/src/storage/encrypted_store/group.rs +++ b/xmtp_mls/src/storage/encrypted_store/group.rs @@ -285,6 +285,14 @@ impl DbConnection { Ok(self.raw_query(|conn| super::schema::consent_records::table.load(conn))?) } + pub fn all_sync_groups(&self) -> Result, StorageError> { + let query = dsl::groups + .order(dsl::created_at_ns.desc()) + .filter(dsl::conversation_type.eq(ConversationType::Sync)); + + Ok(self.raw_query(|conn| query.load(conn))?) + } + pub fn latest_sync_group(&self) -> Result, StorageError> { let query = dsl::groups .order(dsl::created_at_ns.desc()) diff --git a/xmtp_mls/src/utils/test/mod.rs b/xmtp_mls/src/utils/test/mod.rs index 5bfc36341..7067f0537 100755 --- a/xmtp_mls/src/utils/test/mod.rs +++ b/xmtp_mls/src/utils/test/mod.rs @@ -178,7 +178,7 @@ impl ClientBuilder { async fn inner_build(owner: impl InboxOwner, api_client: A) -> Client where - A: XmtpApi + 'static, + A: XmtpApi + 'static + Send + Sync, { let nonce = 1; let inbox_id = generate_inbox_id(&owner.get_address(), &nonce).unwrap(); @@ -235,10 +235,6 @@ where register_client(&client, owner).await; - if client.history_sync_url.is_some() { - client.start_sync_worker(); - } - client } @@ -342,7 +338,7 @@ pub async fn wait_for_min_intents(conn: &DbConnection, n: usize) { tracing::info!("{} intents left", intents.len()); if intents.len() < n { - tokio::time::sleep(std::time::Duration::from_secs(1)).await; + tokio::time::sleep(std::time::Duration::from_millis(200)).await; Box::pin(wait_for_min_intents(conn, n - intents.len())).await } } From df1583ff65a8f35d891d8d646d7253e975b5a10c Mon Sep 17 00:00:00 2001 From: Dakota Brink <779390+codabrink@users.noreply.github.com> Date: Thu, 5 Dec 2024 16:07:22 -0500 Subject: [PATCH 32/46] User Preferences Table (#1384) * check * remove on conflict * impl store --- .../down.sql | 1 + .../up.sql | 6 ++ xmtp_mls/src/storage/encrypted_store/mod.rs | 1 + .../src/storage/encrypted_store/schema.rs | 8 ++ .../encrypted_store/user_preferences.rs | 76 +++++++++++++++++++ 5 files changed, 92 insertions(+) create mode 100644 xmtp_mls/migrations/2024-12-05-185829_create_user_preferences/down.sql create mode 100644 xmtp_mls/migrations/2024-12-05-185829_create_user_preferences/up.sql create mode 100644 xmtp_mls/src/storage/encrypted_store/user_preferences.rs diff --git a/xmtp_mls/migrations/2024-12-05-185829_create_user_preferences/down.sql b/xmtp_mls/migrations/2024-12-05-185829_create_user_preferences/down.sql new file mode 100644 index 000000000..f6b21295a --- /dev/null +++ b/xmtp_mls/migrations/2024-12-05-185829_create_user_preferences/down.sql @@ -0,0 +1 @@ +DROP TABLE IF EXISTS "user_preferences"; diff --git a/xmtp_mls/migrations/2024-12-05-185829_create_user_preferences/up.sql b/xmtp_mls/migrations/2024-12-05-185829_create_user_preferences/up.sql new file mode 100644 index 000000000..751210aec --- /dev/null +++ b/xmtp_mls/migrations/2024-12-05-185829_create_user_preferences/up.sql @@ -0,0 +1,6 @@ +CREATE TABLE "user_preferences"( + -- The latest id is the current preference + id INTEGER PRIMARY KEY ASC, + -- HMAC root key + hmac_key BLOB +); diff --git a/xmtp_mls/src/storage/encrypted_store/mod.rs b/xmtp_mls/src/storage/encrypted_store/mod.rs index bc72fa7cc..58ff1eff8 100644 --- a/xmtp_mls/src/storage/encrypted_store/mod.rs +++ b/xmtp_mls/src/storage/encrypted_store/mod.rs @@ -26,6 +26,7 @@ pub mod refresh_state; pub mod schema; #[cfg(not(target_arch = "wasm32"))] mod sqlcipher_connection; +pub mod user_preferences; pub mod wallet_addresses; #[cfg(target_arch = "wasm32")] mod wasm; diff --git a/xmtp_mls/src/storage/encrypted_store/schema.rs b/xmtp_mls/src/storage/encrypted_store/schema.rs index db79db920..2c1f722fa 100644 --- a/xmtp_mls/src/storage/encrypted_store/schema.rs +++ b/xmtp_mls/src/storage/encrypted_store/schema.rs @@ -107,6 +107,13 @@ diesel::table! { } } +diesel::table! { + user_preferences (id) { + id -> Nullable, + hmac_key -> Nullable, + } +} + diesel::table! { wallet_addresses (wallet_address) { inbox_id -> Text, @@ -129,5 +136,6 @@ diesel::allow_tables_to_appear_in_same_query!( openmls_key_store, openmls_key_value, refresh_state, + user_preferences, wallet_addresses, ); diff --git a/xmtp_mls/src/storage/encrypted_store/user_preferences.rs b/xmtp_mls/src/storage/encrypted_store/user_preferences.rs new file mode 100644 index 000000000..0810a415b --- /dev/null +++ b/xmtp_mls/src/storage/encrypted_store/user_preferences.rs @@ -0,0 +1,76 @@ +use crate::{impl_store, storage::StorageError, Store}; + +use super::{ + schema::user_preferences::{self, dsl}, + DbConnection, +}; +use diesel::prelude::*; + +#[derive(Identifiable, Insertable, Queryable, Debug, Clone, PartialEq, Eq, Default)] +#[diesel(table_name = user_preferences)] +#[diesel(primary_key(id))] +pub struct StoredUserPreferences { + /// Primary key - latest key is the "current" preference + pub id: Option, + /// Randomly generated hmac key root + pub hmac_key: Option>, +} +impl_store!(StoredUserPreferences, user_preferences); + +impl StoredUserPreferences { + pub fn load(conn: &DbConnection) -> Result { + let query = dsl::user_preferences.order(dsl::id.desc()).limit(1); + let mut result = conn.raw_query(|conn| query.load::(conn))?; + + Ok(result.pop().unwrap_or_default()) + } + + pub fn set_hmac_key(conn: &DbConnection, hmac_key: Vec) -> Result<(), StorageError> { + let mut preferences = Self::load(conn)?; + preferences.id = None; + preferences.hmac_key = Some(hmac_key); + + preferences.store(conn)?; + + Ok(()) + } +} + +#[cfg(test)] +mod tests { + use crate::{storage::encrypted_store::tests::with_connection, Store}; + #[cfg(target_arch = "wasm32")] + wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_dedicated_worker); + + use super::*; + + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] + async fn test_insert_and_upate_preferences() { + with_connection(|conn| { + // loads a default + let pref = StoredUserPreferences::load(conn).unwrap(); + assert_eq!(pref, StoredUserPreferences::default()); + assert_eq!(pref.id, None); + // save that default + pref.store(conn).unwrap(); + + // set an hmac key + let hmac_key = vec![1, 2, 1, 2, 1, 2, 1, 2, 1, 2]; + StoredUserPreferences::set_hmac_key(conn, hmac_key.clone()).unwrap(); + + // load preferences from db + let pref = StoredUserPreferences::load(conn).unwrap(); + assert_eq!(pref.hmac_key, Some(hmac_key)); + assert_eq!(pref.id, Some(2)); + + // check that there are two preferences stored + let query = dsl::user_preferences.order(dsl::id.desc()); + let result = conn + .raw_query(|conn| query.load::(conn)) + .unwrap(); + assert_eq!(result.len(), 2); + }) + .await; + } +} From 29b2b16e19304de03eea17e9db267b40b049b3c8 Mon Sep 17 00:00:00 2001 From: Naomi Plasterer Date: Thu, 5 Dec 2024 15:02:52 -0800 Subject: [PATCH 33/46] add the ability to sync based on consent state (#1385) --- bindings_ffi/src/mls.rs | 49 +++++++++--- bindings_node/src/conversations.rs | 2 +- bindings_wasm/src/conversations.rs | 2 +- xmtp_mls/src/client.rs | 119 ++++++++++++++++++++++++++++- 4 files changed, 159 insertions(+), 13 deletions(-) diff --git a/bindings_ffi/src/mls.rs b/bindings_ffi/src/mls.rs index 6c58ee573..4861deb56 100644 --- a/bindings_ffi/src/mls.rs +++ b/bindings_ffi/src/mls.rs @@ -893,11 +893,16 @@ impl FfiConversations { Ok(sync_group.into()) } - pub async fn sync_all_conversations(&self) -> Result { + pub async fn sync_all_conversations( + &self, + consent_state: Option, + ) -> Result { let inner = self.inner_client.as_ref(); let conn = inner.store().conn()?; - let num_groups_synced: usize = inner.sync_all_welcomes_and_groups(&conn).await?; + let consent: Option = consent_state.map(|state| state.into()); + + let num_groups_synced: usize = inner.sync_all_welcomes_and_groups(&conn, consent).await?; // Convert usize to u32 for compatibility with Uniffi let num_groups_synced: u32 = num_groups_synced @@ -2524,7 +2529,10 @@ mod tests { .unwrap(); } - bo.conversations().sync_all_conversations().await.unwrap(); + bo.conversations() + .sync_all_conversations(None) + .await + .unwrap(); let alix_groups = alix .conversations() .list(FfiListConversationsOptions::default()) @@ -2548,7 +2556,10 @@ mod tests { assert_eq!(bo_messages1.len(), 0); assert_eq!(bo_messages5.len(), 0); - bo.conversations().sync_all_conversations().await.unwrap(); + bo.conversations() + .sync_all_conversations(None) + .await + .unwrap(); let bo_messages1 = bo_group1 .find_messages(FfiListMessagesOptions::default()) @@ -2576,7 +2587,11 @@ mod tests { .unwrap(); } bo.conversations().sync().await.unwrap(); - let num_groups_synced_1: u32 = bo.conversations().sync_all_conversations().await.unwrap(); + let num_groups_synced_1: u32 = bo + .conversations() + .sync_all_conversations(None) + .await + .unwrap(); assert_eq!(num_groups_synced_1, 30); // Remove bo from all groups and sync @@ -2593,11 +2608,19 @@ mod tests { } // First sync after removal needs to process all groups and set them to inactive - let num_groups_synced_2: u32 = bo.conversations().sync_all_conversations().await.unwrap(); + let num_groups_synced_2: u32 = bo + .conversations() + .sync_all_conversations(None) + .await + .unwrap(); assert_eq!(num_groups_synced_2, 30); // Second sync after removal will not process inactive groups - let num_groups_synced_3: u32 = bo.conversations().sync_all_conversations().await.unwrap(); + let num_groups_synced_3: u32 = bo + .conversations() + .sync_all_conversations(None) + .await + .unwrap(); assert_eq!(num_groups_synced_3, 0); } @@ -3837,9 +3860,15 @@ mod tests { .create_dm(bola.account_address.clone()) .await .unwrap(); - let alix_num_sync = alix_conversations.sync_all_conversations().await.unwrap(); + let alix_num_sync = alix_conversations + .sync_all_conversations(None) + .await + .unwrap(); bola_conversations.sync().await.unwrap(); - let bola_num_sync = bola_conversations.sync_all_conversations().await.unwrap(); + let bola_num_sync = bola_conversations + .sync_all_conversations(None) + .await + .unwrap(); assert_eq!(alix_num_sync, 1); assert_eq!(bola_num_sync, 1); @@ -4121,7 +4150,7 @@ mod tests { // update the sync group's messages to pipe them into the events alix_b .conversations() - .sync_all_conversations() + .sync_all_conversations(None) .await .unwrap(); diff --git a/bindings_node/src/conversations.rs b/bindings_node/src/conversations.rs index fb35a4d83..2ee01f5c6 100644 --- a/bindings_node/src/conversations.rs +++ b/bindings_node/src/conversations.rs @@ -258,7 +258,7 @@ impl Conversations { let num_groups_synced = self .inner_client - .sync_all_welcomes_and_groups(&conn) + .sync_all_welcomes_and_groups(&conn, None) .await .map_err(ErrorWrapper::from)?; diff --git a/bindings_wasm/src/conversations.rs b/bindings_wasm/src/conversations.rs index c33cd901d..790868d29 100644 --- a/bindings_wasm/src/conversations.rs +++ b/bindings_wasm/src/conversations.rs @@ -293,7 +293,7 @@ impl Conversations { let num_groups_synced = self .inner_client - .sync_all_welcomes_and_groups(&conn) + .sync_all_welcomes_and_groups(&conn, None) .await .map_err(|e| JsError::new(format!("{}", e).as_str()))?; diff --git a/xmtp_mls/src/client.rs b/xmtp_mls/src/client.rs index eb6a86ab1..75a1f9f21 100644 --- a/xmtp_mls/src/client.rs +++ b/xmtp_mls/src/client.rs @@ -877,9 +877,17 @@ where pub async fn sync_all_welcomes_and_groups( &self, conn: &DbConnection, + consent_state: Option, ) -> Result { self.sync_welcomes(conn).await?; - let groups = self.find_groups(GroupQueryArgs::default().include_sync_groups())?; + + let query_args = GroupQueryArgs { + consent_state, + include_sync_groups: true, + ..GroupQueryArgs::default() + }; + + let groups = self.find_groups(query_args)?; let active_groups_count = self.sync_all_groups(groups).await?; Ok(active_groups_count) @@ -1185,6 +1193,115 @@ pub(crate) mod tests { assert_eq!(bo_messages2.len(), 1); } + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr( + not(target_arch = "wasm32"), + tokio::test(flavor = "multi_thread", worker_threads = 2) + )] + async fn test_sync_all_groups_and_welcomes() { + let alix = ClientBuilder::new_test_client(&generate_local_wallet()).await; + let bo = ClientBuilder::new_test_client(&generate_local_wallet()).await; + + // Create two groups and add Bob + let alix_bo_group1 = alix + .create_group(None, GroupMetadataOptions::default()) + .unwrap(); + let alix_bo_group2 = alix + .create_group(None, GroupMetadataOptions::default()) + .unwrap(); + + alix_bo_group1 + .add_members_by_inbox_id(&[bo.inbox_id()]) + .await + .unwrap(); + alix_bo_group2 + .add_members_by_inbox_id(&[bo.inbox_id()]) + .await + .unwrap(); + + // Initial sync (None): Bob should fetch both groups + let bob_received_groups = bo + .sync_all_welcomes_and_groups(&bo.store().conn().unwrap(), None) + .await + .unwrap(); + assert_eq!(bob_received_groups, 2); + + // Verify Bob initially has no messages + let bo_group1 = bo.group(alix_bo_group1.group_id.clone()).unwrap(); + assert_eq!( + bo_group1 + .find_messages(&MsgQueryArgs::default()) + .unwrap() + .len(), + 0 + ); + let bo_group2 = bo.group(alix_bo_group2.group_id.clone()).unwrap(); + assert_eq!( + bo_group2 + .find_messages(&MsgQueryArgs::default()) + .unwrap() + .len(), + 0 + ); + + // Alix sends a message to both groups + alix_bo_group1 + .send_message(vec![1, 2, 3].as_slice()) + .await + .unwrap(); + alix_bo_group2 + .send_message(vec![4, 5, 6].as_slice()) + .await + .unwrap(); + + // Sync with `Unknown`: Bob should not fetch new messages + let bob_received_groups_unknown = bo + .sync_all_welcomes_and_groups(&bo.store().conn().unwrap(), Some(ConsentState::Allowed)) + .await + .unwrap(); + assert_eq!(bob_received_groups_unknown, 0); + + // Verify Bob still has no messages + assert_eq!( + bo_group1 + .find_messages(&MsgQueryArgs::default()) + .unwrap() + .len(), + 0 + ); + assert_eq!( + bo_group2 + .find_messages(&MsgQueryArgs::default()) + .unwrap() + .len(), + 0 + ); + + // Alix sends another message to both groups + alix_bo_group1 + .send_message(vec![7, 8, 9].as_slice()) + .await + .unwrap(); + alix_bo_group2 + .send_message(vec![10, 11, 12].as_slice()) + .await + .unwrap(); + + // Sync with `None`: Bob should fetch all messages + let bob_received_groups_all = bo + .sync_all_welcomes_and_groups(&bo.store().conn().unwrap(), Some(ConsentState::Unknown)) + .await + .unwrap(); + assert_eq!(bob_received_groups_all, 2); + + // Verify Bob now has all messages + let bo_messages1 = bo_group1.find_messages(&MsgQueryArgs::default()).unwrap(); + assert_eq!(bo_messages1.len(), 2); + + let bo_messages2 = bo_group2.find_messages(&MsgQueryArgs::default()).unwrap(); + assert_eq!(bo_messages2.len(), 2); + } + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] #[cfg_attr( not(target_arch = "wasm32"), From 2d0640c9c4e584278a28724cdd5a8f13524b1699 Mon Sep 17 00:00:00 2001 From: Dakota Brink <779390+codabrink@users.noreply.github.com> Date: Fri, 6 Dec 2024 09:45:12 -0500 Subject: [PATCH 34/46] Add UserPreferenceUpdate Message Compat (#1387) * proto update * swap out consent updates * ok to fail * missing file * lint * update name * Less aggressive restarting --- xmtp_id/src/associations/serialization.rs | 2 + xmtp_mls/src/client.rs | 7 +- xmtp_mls/src/groups/device_sync.rs | 28 +- .../src/groups/device_sync/consent_sync.rs | 33 +- xmtp_mls/src/groups/mls_sync.rs | 22 +- xmtp_mls/src/groups/mod.rs | 5 +- xmtp_mls/src/lib.rs | 1 + xmtp_mls/src/preferences.rs | 30 + .../storage/encrypted_store/consent_record.rs | 27 - xmtp_mls/src/subscriptions.rs | 31 +- xmtp_proto/Cargo.toml | 2 +- .../src/gen/xmtp.mls.message_contents.rs | 813 ++++++++---------- .../gen/xmtp.mls.message_contents.serde.rs | 394 +++------ 13 files changed, 558 insertions(+), 837 deletions(-) create mode 100644 xmtp_mls/src/preferences.rs diff --git a/xmtp_id/src/associations/serialization.rs b/xmtp_id/src/associations/serialization.rs index fd53a28e9..15c5ca2b5 100644 --- a/xmtp_id/src/associations/serialization.rs +++ b/xmtp_id/src/associations/serialization.rs @@ -74,6 +74,8 @@ pub enum DeserializationError { Unspecified(&'static str), #[error("Error creating public key from proto bytes")] Ed25519(#[from] ed25519_dalek::ed25519::Error), + #[error("Unable to deserialize")] + Bincode, } impl TryFrom for UnverifiedIdentityUpdate { diff --git a/xmtp_mls/src/client.rs b/xmtp_mls/src/client.rs index 75a1f9f21..051c12500 100644 --- a/xmtp_mls/src/client.rs +++ b/xmtp_mls/src/client.rs @@ -38,6 +38,7 @@ use crate::{ identity_updates::{load_identity_updates, IdentityUpdateError}, intents::Intents, mutex_registry::MutexRegistry, + preferences::UserPreferenceUpdate, retry::Retry, retry_async, retryable, storage::{ @@ -443,8 +444,12 @@ where if self.history_sync_url.is_some() { let mut records = records.to_vec(); records.append(&mut new_records); + let records = records + .into_iter() + .map(UserPreferenceUpdate::ConsentUpdate) + .collect(); self.local_events - .send(LocalEvents::OutgoingConsentUpdates(records)) + .send(LocalEvents::OutgoingPreferenceUpdates(records)) .map_err(|e| ClientError::Generic(e.to_string()))?; } diff --git a/xmtp_mls/src/groups/device_sync.rs b/xmtp_mls/src/groups/device_sync.rs index 2a8d65983..89c86cb7a 100644 --- a/xmtp_mls/src/groups/device_sync.rs +++ b/xmtp_mls/src/groups/device_sync.rs @@ -1,5 +1,6 @@ use super::{GroupError, MlsGroup}; use crate::configuration::NS_IN_HOUR; +use crate::preferences::UserPreferenceUpdate; use crate::retry::{Retry, RetryableError}; use crate::storage::group::{ConversationType, GroupQueryArgs}; use crate::storage::group_message::MsgQueryArgs; @@ -107,6 +108,8 @@ pub enum DeviceSyncError { SyncPayloadTooOld, #[error(transparent)] Subscribe(#[from] SubscribeError), + #[error("Unable to serialize: {0}")] + Bincode(String), } impl RetryableError for DeviceSyncError { @@ -169,16 +172,27 @@ where self.on_request(message_id, &provider).await? } }, - LocalEvents::OutgoingConsentUpdates(consent_records) => { + LocalEvents::OutgoingPreferenceUpdates(consent_records) => { let provider = self.client.mls_provider()?; - for consent_record in consent_records { + for record in consent_records { + let UserPreferenceUpdate::ConsentUpdate(consent_record) = record else { + continue; + }; + self.client - .send_consent_update(&provider, &consent_record) + .send_consent_update(&provider, consent_record) .await?; } } - LocalEvents::IncomingConsentUpdates(consent_records) => { + LocalEvents::IncomingPreferenceUpdate(updates) => { let provider = self.client.mls_provider()?; + let consent_records = updates + .into_iter() + .filter_map(|pu| match pu { + UserPreferenceUpdate::ConsentUpdate(cr) => Some(cr), + _ => None, + }) + .collect::>(); provider .conn_ref() .insert_or_replace_consent_records(&consent_records)?; @@ -326,6 +340,8 @@ where } _ => { tracing::error!(inbox_id, installation_id, "sync worker error {err}"); + // Wait 2 seconds before restarting. + crate::sleep(Duration::from_secs(2)).await; } } } @@ -671,8 +687,8 @@ where if existing_consent_record.state != consent_record.state { warn!("Existing consent record exists and does not match payload state. Streaming consent_record update to sync group."); self.local_events - .send(LocalEvents::OutgoingConsentUpdates(vec![ - existing_consent_record, + .send(LocalEvents::OutgoingPreferenceUpdates(vec![ + UserPreferenceUpdate::ConsentUpdate(existing_consent_record), ])) .map_err(|e| DeviceSyncError::Generic(e.to_string()))?; } diff --git a/xmtp_mls/src/groups/device_sync/consent_sync.rs b/xmtp_mls/src/groups/device_sync/consent_sync.rs index 0075c1230..a4053288b 100644 --- a/xmtp_mls/src/groups/device_sync/consent_sync.rs +++ b/xmtp_mls/src/groups/device_sync/consent_sync.rs @@ -1,12 +1,7 @@ use super::*; -use crate::{ - storage::consent_record::{ConsentState, ConsentType}, - Client, XmtpApi, -}; +use crate::{preferences::UserPreferenceUpdate, Client, XmtpApi}; use xmtp_id::scw_verifier::SmartContractSignatureVerifier; -use xmtp_proto::xmtp::mls::message_contents::{ - ConsentEntityType, ConsentState as ConsentStateProto, ConsentUpdate as ConsentUpdateProto, -}; +use xmtp_proto::xmtp::mls::message_contents::UserPreferenceUpdate as UserPreferenceUpdateProto; impl Client where @@ -16,7 +11,7 @@ where pub(crate) async fn send_consent_update( &self, provider: &XmtpOpenMlsProvider, - record: &StoredConsentRecord, + record: StoredConsentRecord, ) -> Result<(), DeviceSyncError> { tracing::info!( inbox_id = self.inbox_id(), @@ -26,26 +21,16 @@ where ); let conn = provider.conn_ref(); - let consent_update_proto = ConsentUpdateProto { - entity: record.entity.clone(), - entity_type: match record.entity_type { - ConsentType::Address => ConsentEntityType::Address, - ConsentType::ConversationId => ConsentEntityType::ConversationId, - ConsentType::InboxId => ConsentEntityType::InboxId, - } as i32, - state: match record.state { - ConsentState::Allowed => ConsentStateProto::Allowed, - ConsentState::Denied => ConsentStateProto::Denied, - ConsentState::Unknown => ConsentStateProto::Unspecified, - } as i32, - }; - let sync_group = self.ensure_sync_group(provider).await?; - let content_bytes = serde_json::to_vec(&consent_update_proto)?; + + let update_proto: UserPreferenceUpdateProto = UserPreferenceUpdate::ConsentUpdate(record) + .try_into() + .map_err(|e| DeviceSyncError::Bincode(format!("{e:?}")))?; + let content_bytes = serde_json::to_vec(&update_proto)?; sync_group.prepare_message(&content_bytes, conn, |_time_ns| PlaintextEnvelope { content: Some(Content::V2(V2 { idempotency_key: new_request_id(), - message_type: Some(MessageType::ConsentUpdate(consent_update_proto)), + message_type: Some(MessageType::UserPreferenceUpdate(update_proto)), })), })?; diff --git a/xmtp_mls/src/groups/mls_sync.rs b/xmtp_mls/src/groups/mls_sync.rs index a47ec3f9a..60a609cd4 100644 --- a/xmtp_mls/src/groups/mls_sync.rs +++ b/xmtp_mls/src/groups/mls_sync.rs @@ -606,17 +606,17 @@ where SyncMessage::Reply { message_id }, )); } - Some(MessageType::ConsentUpdate(update)) => { - tracing::info!( - "Incoming streamed consent update: {:?} {} updated to {:?}.", - update.entity_type(), - update.entity, - update.state() - ); - - let _ = self.client.local_events().send( - LocalEvents::IncomingConsentUpdates(vec![update.try_into()?]), - ); + Some(MessageType::UserPreferenceUpdate(update)) => { + // Ignore errors since this may come from a newer version of the lib + // that has new update types. + if let Ok(update) = update.try_into() { + let _ = self + .client + .local_events() + .send(LocalEvents::IncomingPreferenceUpdate(vec![update])); + } else { + tracing::warn!("Failed to deserialize preference update. Is this libxmtp version old?"); + } } _ => { return Err(GroupMessageProcessingError::InvalidPayload); diff --git a/xmtp_mls/src/groups/mod.rs b/xmtp_mls/src/groups/mod.rs index 12440397c..ad9d92d34 100644 --- a/xmtp_mls/src/groups/mod.rs +++ b/xmtp_mls/src/groups/mod.rs @@ -83,6 +83,7 @@ use crate::{ identity::{parse_credential, IdentityError}, identity_updates::{load_identity_updates, InstallationDiffError}, intents::ProcessIntentError, + preferences::UserPreferenceUpdate, retry::RetryableError, storage::{ consent_record::{ConsentState, ConsentType, StoredConsentRecord}, @@ -1093,7 +1094,9 @@ impl MlsGroup { let _ = self .client .local_events() - .send(LocalEvents::OutgoingConsentUpdates(vec![consent_record])); + .send(LocalEvents::OutgoingPreferenceUpdates(vec![ + UserPreferenceUpdate::ConsentUpdate(consent_record), + ])); } Ok(()) diff --git a/xmtp_mls/src/lib.rs b/xmtp_mls/src/lib.rs index fb21ba10b..cf0a08702 100644 --- a/xmtp_mls/src/lib.rs +++ b/xmtp_mls/src/lib.rs @@ -12,6 +12,7 @@ pub mod identity; pub mod identity_updates; mod intents; mod mutex_registry; +mod preferences; pub mod retry; pub mod storage; mod stream_handles; diff --git a/xmtp_mls/src/preferences.rs b/xmtp_mls/src/preferences.rs new file mode 100644 index 000000000..5f4bb90a7 --- /dev/null +++ b/xmtp_mls/src/preferences.rs @@ -0,0 +1,30 @@ +use serde::{Deserialize, Serialize}; +use xmtp_id::associations::DeserializationError; +use xmtp_proto::xmtp::mls::message_contents::UserPreferenceUpdate as UserPreferenceUpdateProto; + +use crate::storage::consent_record::StoredConsentRecord; + +#[derive(Serialize, Deserialize, Clone)] +pub enum UserPreferenceUpdate { + ConsentUpdate(StoredConsentRecord), + HmacKeyUpdate { key: Vec }, +} + +impl TryFrom for UserPreferenceUpdate { + type Error = DeserializationError; + fn try_from(value: UserPreferenceUpdateProto) -> Result { + let update = + bincode::deserialize(&value.content).map_err(|_| DeserializationError::Bincode)?; + + Ok(update) + } +} + +impl TryInto for UserPreferenceUpdate { + type Error = bincode::Error; + + fn try_into(self) -> Result { + let content = bincode::serialize(&self)?; + Ok(UserPreferenceUpdateProto { content }) + } +} diff --git a/xmtp_mls/src/storage/encrypted_store/consent_record.rs b/xmtp_mls/src/storage/encrypted_store/consent_record.rs index f0c7b9498..b39b17eda 100644 --- a/xmtp_mls/src/storage/encrypted_store/consent_record.rs +++ b/xmtp_mls/src/storage/encrypted_store/consent_record.rs @@ -15,10 +15,6 @@ use diesel::{ upsert::excluded, }; use serde::{Deserialize, Serialize}; -use xmtp_id::associations::DeserializationError; -use xmtp_proto::xmtp::mls::message_contents::{ - ConsentEntityType, ConsentState as ConsentStateProto, ConsentUpdate as ConsentUpdateProto, -}; /// StoredConsentRecord holds a serialized ConsentRecord #[derive(Insertable, Queryable, Debug, Clone, PartialEq, Eq, Deserialize, Serialize)] @@ -182,29 +178,6 @@ where } } -impl TryFrom for StoredConsentRecord { - type Error = DeserializationError; - - fn try_from(update: ConsentUpdateProto) -> Result { - Ok(Self { - entity_type: match update.entity_type() { - ConsentEntityType::Address => ConsentType::Address, - ConsentEntityType::ConversationId => ConsentType::ConversationId, - ConsentEntityType::InboxId => ConsentType::InboxId, - ConsentEntityType::Unspecified => { - return Err(DeserializationError::Unspecified("entity_type")) - } - }, - state: match update.state() { - ConsentStateProto::Unspecified => ConsentState::Unknown, - ConsentStateProto::Allowed => ConsentState::Allowed, - ConsentStateProto::Denied => ConsentState::Denied, - }, - entity: update.entity, - }) - } -} - #[cfg(test)] mod tests { use crate::storage::encrypted_store::tests::with_connection; diff --git a/xmtp_mls/src/subscriptions.rs b/xmtp_mls/src/subscriptions.rs index 67606dae8..9a89fb014 100644 --- a/xmtp_mls/src/subscriptions.rs +++ b/xmtp_mls/src/subscriptions.rs @@ -13,6 +13,7 @@ use xmtp_proto::{api_client::XmtpMlsStreams, xmtp::mls::api::v1::WelcomeMessage} use crate::{ client::{extract_welcome_message, ClientError}, groups::{mls_sync::GroupMessageProcessingError, subscriptions, GroupError, MlsGroup}, + preferences::UserPreferenceUpdate, retry::{Retry, RetryableError}, retry_async, retryable, storage::{ @@ -52,8 +53,8 @@ pub enum LocalEvents { // a new group was created NewGroup(MlsGroup), SyncMessage(SyncMessage), - OutgoingConsentUpdates(Vec), - IncomingConsentUpdates(Vec), + OutgoingPreferenceUpdates(Vec), + IncomingPreferenceUpdate(Vec), } #[derive(Clone)] @@ -77,8 +78,8 @@ impl LocalEvents { match &self { SyncMessage(_) => Some(self), - OutgoingConsentUpdates(_) => Some(self), - IncomingConsentUpdates(_) => Some(self), + OutgoingPreferenceUpdates(_) => Some(self), + IncomingPreferenceUpdate(_) => Some(self), _ => None, } } @@ -87,8 +88,26 @@ impl LocalEvents { use LocalEvents::*; match self { - OutgoingConsentUpdates(cr) => Some(cr), - IncomingConsentUpdates(cr) => Some(cr), + OutgoingPreferenceUpdates(updates) => { + let updates = updates + .into_iter() + .filter_map(|pu| match pu { + UserPreferenceUpdate::ConsentUpdate(cr) => Some(cr), + _ => None, + }) + .collect(); + Some(updates) + } + IncomingPreferenceUpdate(updates) => { + let updates = updates + .into_iter() + .filter_map(|pu| match pu { + UserPreferenceUpdate::ConsentUpdate(cr) => Some(cr), + _ => None, + }) + .collect(); + Some(updates) + } _ => None, } } diff --git a/xmtp_proto/Cargo.toml b/xmtp_proto/Cargo.toml index c376941a1..d4bb67c97 100644 --- a/xmtp_proto/Cargo.toml +++ b/xmtp_proto/Cargo.toml @@ -44,4 +44,4 @@ proto_full = ["xmtp-identity","xmtp-identity-api-v1","xmtp-identity-associations "xmtp-xmtpv4-envelopes" = ["xmtp-identity-associations","xmtp-mls-api-v1"] "xmtp-xmtpv4-message_api" = ["xmtp-xmtpv4-envelopes"] "xmtp-xmtpv4-payer_api" = ["xmtp-xmtpv4-envelopes"] -## @@protoc_insertion_point(features) +## @@protoc_insertion_point(features) \ No newline at end of file diff --git a/xmtp_proto/src/gen/xmtp.mls.message_contents.rs b/xmtp_proto/src/gen/xmtp.mls.message_contents.rs index 2c6985f4f..dad2c1b77 100644 --- a/xmtp_proto/src/gen/xmtp.mls.message_contents.rs +++ b/xmtp_proto/src/gen/xmtp.mls.message_contents.rs @@ -89,9 +89,9 @@ pub mod plaintext_envelope { /// Some other authorized installation sends a reply with a link to payload #[prost(message, tag="4")] DeviceSyncReply(super::super::DeviceSyncReply), - /// A streamed cosnent update + /// A serialized user preference update #[prost(message, tag="5")] - ConsentUpdate(super::super::ConsentUpdate), + UserPreferenceUpdate(super::super::UserPreferenceUpdate), } } /// Selector which declares which version of the EncodedContent this @@ -155,16 +155,11 @@ pub mod device_sync_key_type { Aes256Gcm(::prost::alloc::vec::Vec), } } -/// A streamed consent update #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] -pub struct ConsentUpdate { - #[prost(enumeration="ConsentEntityType", tag="1")] - pub entity_type: i32, - #[prost(enumeration="ConsentState", tag="2")] - pub state: i32, - #[prost(string, tag="3")] - pub entity: ::prost::alloc::string::String, +pub struct UserPreferenceUpdate { + #[prost(bytes="vec", tag="1")] + pub content: ::prost::alloc::vec::Vec, } /// Recognized compression algorithms /// protolint:disable ENUM_FIELD_NAMES_ZERO_VALUE_END_WITH @@ -224,69 +219,6 @@ impl DeviceSyncKind { } } } -/// The type of entity the user is consenting to -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] -#[repr(i32)] -pub enum ConsentEntityType { - Unspecified = 0, - ConversationId = 1, - InboxId = 2, - Address = 3, -} -impl ConsentEntityType { - /// String value of the enum field names used in the ProtoBuf definition. - /// - /// The values are not transformed in any way and thus are considered stable - /// (if the ProtoBuf definition does not change) and safe for programmatic use. - pub fn as_str_name(&self) -> &'static str { - match self { - ConsentEntityType::Unspecified => "CONSENT_ENTITY_TYPE_UNSPECIFIED", - ConsentEntityType::ConversationId => "CONSENT_ENTITY_TYPE_CONVERSATION_ID", - ConsentEntityType::InboxId => "CONSENT_ENTITY_TYPE_INBOX_ID", - ConsentEntityType::Address => "CONSENT_ENTITY_TYPE_ADDRESS", - } - } - /// Creates an enum from field names used in the ProtoBuf definition. - pub fn from_str_name(value: &str) -> ::core::option::Option { - match value { - "CONSENT_ENTITY_TYPE_UNSPECIFIED" => Some(Self::Unspecified), - "CONSENT_ENTITY_TYPE_CONVERSATION_ID" => Some(Self::ConversationId), - "CONSENT_ENTITY_TYPE_INBOX_ID" => Some(Self::InboxId), - "CONSENT_ENTITY_TYPE_ADDRESS" => Some(Self::Address), - _ => None, - } - } -} -/// Possible states of consent -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] -#[repr(i32)] -pub enum ConsentState { - Unspecified = 0, - Allowed = 1, - Denied = 2, -} -impl ConsentState { - /// String value of the enum field names used in the ProtoBuf definition. - /// - /// The values are not transformed in any way and thus are considered stable - /// (if the ProtoBuf definition does not change) and safe for programmatic use. - pub fn as_str_name(&self) -> &'static str { - match self { - ConsentState::Unspecified => "CONSENT_STATE_UNSPECIFIED", - ConsentState::Allowed => "CONSENT_STATE_ALLOWED", - ConsentState::Denied => "CONSENT_STATE_DENIED", - } - } - /// Creates an enum from field names used in the ProtoBuf definition. - pub fn from_str_name(value: &str) -> ::core::option::Option { - match value { - "CONSENT_STATE_UNSPECIFIED" => Some(Self::Unspecified), - "CONSENT_STATE_ALLOWED" => Some(Self::Allowed), - "CONSENT_STATE_DENIED" => Some(Self::Denied), - _ => None, - } - } -} /// Contains a mapping of `inbox_id` -> `sequence_id` for all members of a group. /// Designed to be stored in the group context extension of the MLS group #[allow(clippy::derive_partial_eq_without_eq)] @@ -684,7 +616,7 @@ pub mod group_updated { } /// Encoded file descriptor set for the `xmtp.mls.message_contents` package pub const FILE_DESCRIPTOR_SET: &[u8] = &[ - 0x0a, 0xdc, 0x3b, 0x0a, 0x22, 0x6d, 0x6c, 0x73, 0x2f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x0a, 0xac, 0x34, 0x0a, 0x22, 0x6d, 0x6c, 0x73, 0x2f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x19, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, @@ -722,7 +654,7 @@ pub const FILE_DESCRIPTOR_SET: &[u8] = &[ 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x42, 0x0b, 0x0a, 0x09, 0x5f, 0x66, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x42, 0x0e, 0x0a, 0x0c, - 0x5f, 0x63, 0x6f, 0x6d, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0xd6, 0x04, 0x0a, + 0x5f, 0x63, 0x6f, 0x6d, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0xec, 0x04, 0x0a, 0x11, 0x50, 0x6c, 0x61, 0x69, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x45, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x12, 0x41, 0x0a, 0x02, 0x76, 0x31, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, @@ -737,7 +669,7 @@ pub const FILE_DESCRIPTOR_SET: &[u8] = &[ 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x12, 0x27, 0x0a, 0x0f, 0x69, 0x64, 0x65, 0x6d, 0x70, 0x6f, 0x74, 0x65, 0x6e, 0x63, 0x79, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x69, 0x64, 0x65, 0x6d, 0x70, 0x6f, 0x74, 0x65, 0x6e, 0x63, 0x79, 0x4b, 0x65, - 0x79, 0x1a, 0xe6, 0x02, 0x0a, 0x02, 0x56, 0x32, 0x12, 0x27, 0x0a, 0x0f, 0x69, 0x64, 0x65, 0x6d, + 0x79, 0x1a, 0xfc, 0x02, 0x0a, 0x02, 0x56, 0x32, 0x12, 0x27, 0x0a, 0x0f, 0x69, 0x64, 0x65, 0x6d, 0x70, 0x6f, 0x74, 0x65, 0x6e, 0x63, 0x79, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x69, 0x64, 0x65, 0x6d, 0x70, 0x6f, 0x74, 0x65, 0x6e, 0x63, 0x79, 0x4b, 0x65, 0x79, 0x12, 0x1a, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, @@ -753,54 +685,47 @@ pub const FILE_DESCRIPTOR_SET: &[u8] = &[ 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x53, 0x79, 0x6e, 0x63, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x48, 0x00, 0x52, 0x0f, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x53, 0x79, - 0x6e, 0x63, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x51, 0x0a, 0x0e, 0x63, 0x6f, 0x6e, 0x73, 0x65, - 0x6e, 0x74, 0x5f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x28, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x43, 0x6f, 0x6e, 0x73, - 0x65, 0x6e, 0x74, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x48, 0x00, 0x52, 0x0d, 0x63, 0x6f, 0x6e, - 0x73, 0x65, 0x6e, 0x74, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x42, 0x0e, 0x0a, 0x0c, 0x6d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x42, 0x09, 0x0a, 0x07, 0x63, 0x6f, - 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x22, 0x8c, 0x01, 0x0a, 0x11, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, - 0x53, 0x79, 0x6e, 0x63, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x72, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x09, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x70, 0x69, - 0x6e, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x70, 0x69, - 0x6e, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x3d, 0x0a, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x18, 0x03, 0x20, - 0x01, 0x28, 0x0e, 0x32, 0x29, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, - 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x53, 0x79, 0x6e, 0x63, 0x4b, 0x69, 0x6e, 0x64, 0x52, 0x04, - 0x6b, 0x69, 0x6e, 0x64, 0x22, 0xf9, 0x01, 0x0a, 0x0f, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x53, - 0x79, 0x6e, 0x63, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x72, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x72, 0x6c, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x6c, 0x12, 0x53, 0x0a, 0x0e, 0x65, 0x6e, 0x63, - 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x2c, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x44, 0x65, - 0x76, 0x69, 0x63, 0x65, 0x53, 0x79, 0x6e, 0x63, 0x4b, 0x65, 0x79, 0x54, 0x79, 0x70, 0x65, 0x52, - 0x0d, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x4b, 0x65, 0x79, 0x12, 0x21, - 0x0a, 0x0c, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x5f, 0x6e, 0x73, 0x18, 0x04, - 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x4e, - 0x73, 0x12, 0x3d, 0x0a, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0e, 0x32, - 0x29, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x44, 0x65, 0x76, 0x69, - 0x63, 0x65, 0x53, 0x79, 0x6e, 0x63, 0x4b, 0x69, 0x6e, 0x64, 0x52, 0x04, 0x6b, 0x69, 0x6e, 0x64, - 0x22, 0x3c, 0x0a, 0x11, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x53, 0x79, 0x6e, 0x63, 0x4b, 0x65, - 0x79, 0x54, 0x79, 0x70, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x61, 0x65, 0x73, 0x5f, 0x32, 0x35, 0x36, - 0x5f, 0x67, 0x63, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x00, 0x52, 0x09, 0x61, 0x65, - 0x73, 0x32, 0x35, 0x36, 0x47, 0x63, 0x6d, 0x42, 0x05, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x22, 0xb5, - 0x01, 0x0a, 0x0d, 0x43, 0x6f, 0x6e, 0x73, 0x65, 0x6e, 0x74, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, - 0x12, 0x4d, 0x0a, 0x0b, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2c, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, + 0x6e, 0x63, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x67, 0x0a, 0x16, 0x75, 0x73, 0x65, 0x72, 0x5f, + 0x70, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x5f, 0x75, 0x70, 0x64, 0x61, 0x74, + 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, + 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, + 0x6e, 0x74, 0x73, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x50, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, + 0x63, 0x65, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x48, 0x00, 0x52, 0x14, 0x75, 0x73, 0x65, 0x72, + 0x50, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, + 0x42, 0x0e, 0x0a, 0x0c, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, + 0x42, 0x09, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x22, 0x8c, 0x01, 0x0a, 0x11, + 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x53, 0x79, 0x6e, 0x63, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x64, + 0x12, 0x19, 0x0a, 0x08, 0x70, 0x69, 0x6e, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x07, 0x70, 0x69, 0x6e, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x3d, 0x0a, 0x04, 0x6b, + 0x69, 0x6e, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x29, 0x2e, 0x78, 0x6d, 0x74, 0x70, + 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, + 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x53, 0x79, 0x6e, 0x63, + 0x4b, 0x69, 0x6e, 0x64, 0x52, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x22, 0xf9, 0x01, 0x0a, 0x0f, 0x44, + 0x65, 0x76, 0x69, 0x63, 0x65, 0x53, 0x79, 0x6e, 0x63, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x1d, + 0x0a, 0x0a, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x09, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x64, 0x12, 0x10, 0x0a, + 0x03, 0x75, 0x72, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x6c, 0x12, + 0x53, 0x0a, 0x0e, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6b, 0x65, + 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, + 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, + 0x6e, 0x74, 0x73, 0x2e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x53, 0x79, 0x6e, 0x63, 0x4b, 0x65, + 0x79, 0x54, 0x79, 0x70, 0x65, 0x52, 0x0d, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, + 0x6e, 0x4b, 0x65, 0x79, 0x12, 0x21, 0x0a, 0x0c, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, + 0x70, 0x5f, 0x6e, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x74, 0x69, 0x6d, 0x65, + 0x73, 0x74, 0x61, 0x6d, 0x70, 0x4e, 0x73, 0x12, 0x3d, 0x0a, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x18, + 0x05, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x29, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, - 0x73, 0x2e, 0x43, 0x6f, 0x6e, 0x73, 0x65, 0x6e, 0x74, 0x45, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x54, - 0x79, 0x70, 0x65, 0x52, 0x0a, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x54, 0x79, 0x70, 0x65, 0x12, - 0x3d, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x27, - 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x43, 0x6f, 0x6e, 0x73, 0x65, - 0x6e, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x12, 0x16, - 0x0a, 0x06, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, - 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2a, 0x3c, 0x0a, 0x0b, 0x43, 0x6f, 0x6d, 0x70, 0x72, 0x65, + 0x73, 0x2e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x53, 0x79, 0x6e, 0x63, 0x4b, 0x69, 0x6e, 0x64, + 0x52, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x22, 0x3c, 0x0a, 0x11, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, + 0x53, 0x79, 0x6e, 0x63, 0x4b, 0x65, 0x79, 0x54, 0x79, 0x70, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x61, + 0x65, 0x73, 0x5f, 0x32, 0x35, 0x36, 0x5f, 0x67, 0x63, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, + 0x48, 0x00, 0x52, 0x09, 0x61, 0x65, 0x73, 0x32, 0x35, 0x36, 0x47, 0x63, 0x6d, 0x42, 0x05, 0x0a, + 0x03, 0x6b, 0x65, 0x79, 0x22, 0x30, 0x0a, 0x14, 0x55, 0x73, 0x65, 0x72, 0x50, 0x72, 0x65, 0x66, + 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x18, 0x0a, 0x07, + 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x63, + 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2a, 0x3c, 0x0a, 0x0b, 0x43, 0x6f, 0x6d, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x17, 0x0a, 0x13, 0x43, 0x4f, 0x4d, 0x50, 0x52, 0x45, 0x53, 0x53, 0x49, 0x4f, 0x4e, 0x5f, 0x44, 0x45, 0x46, 0x4c, 0x41, 0x54, 0x45, 0x10, 0x00, 0x12, 0x14, 0x0a, 0x10, 0x43, 0x4f, 0x4d, 0x50, 0x52, 0x45, 0x53, 0x53, 0x49, 0x4f, 0x4e, 0x5f, 0x47, 0x5a, @@ -811,357 +736,305 @@ pub const FILE_DESCRIPTOR_SET: &[u8] = &[ 0x43, 0x45, 0x5f, 0x53, 0x59, 0x4e, 0x43, 0x5f, 0x4b, 0x49, 0x4e, 0x44, 0x5f, 0x4d, 0x45, 0x53, 0x53, 0x41, 0x47, 0x45, 0x5f, 0x48, 0x49, 0x53, 0x54, 0x4f, 0x52, 0x59, 0x10, 0x01, 0x12, 0x1c, 0x0a, 0x18, 0x44, 0x45, 0x56, 0x49, 0x43, 0x45, 0x5f, 0x53, 0x59, 0x4e, 0x43, 0x5f, 0x4b, 0x49, - 0x4e, 0x44, 0x5f, 0x43, 0x4f, 0x4e, 0x53, 0x45, 0x4e, 0x54, 0x10, 0x02, 0x2a, 0xa4, 0x01, 0x0a, - 0x11, 0x43, 0x6f, 0x6e, 0x73, 0x65, 0x6e, 0x74, 0x45, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x54, 0x79, - 0x70, 0x65, 0x12, 0x23, 0x0a, 0x1f, 0x43, 0x4f, 0x4e, 0x53, 0x45, 0x4e, 0x54, 0x5f, 0x45, 0x4e, - 0x54, 0x49, 0x54, 0x59, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, - 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x27, 0x0a, 0x23, 0x43, 0x4f, 0x4e, 0x53, 0x45, - 0x4e, 0x54, 0x5f, 0x45, 0x4e, 0x54, 0x49, 0x54, 0x59, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x43, - 0x4f, 0x4e, 0x56, 0x45, 0x52, 0x53, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x49, 0x44, 0x10, 0x01, - 0x12, 0x20, 0x0a, 0x1c, 0x43, 0x4f, 0x4e, 0x53, 0x45, 0x4e, 0x54, 0x5f, 0x45, 0x4e, 0x54, 0x49, - 0x54, 0x59, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x49, 0x4e, 0x42, 0x4f, 0x58, 0x5f, 0x49, 0x44, - 0x10, 0x02, 0x12, 0x1f, 0x0a, 0x1b, 0x43, 0x4f, 0x4e, 0x53, 0x45, 0x4e, 0x54, 0x5f, 0x45, 0x4e, - 0x54, 0x49, 0x54, 0x59, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x41, 0x44, 0x44, 0x52, 0x45, 0x53, - 0x53, 0x10, 0x03, 0x2a, 0x62, 0x0a, 0x0c, 0x43, 0x6f, 0x6e, 0x73, 0x65, 0x6e, 0x74, 0x53, 0x74, - 0x61, 0x74, 0x65, 0x12, 0x1d, 0x0a, 0x19, 0x43, 0x4f, 0x4e, 0x53, 0x45, 0x4e, 0x54, 0x5f, 0x53, - 0x54, 0x41, 0x54, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, - 0x10, 0x00, 0x12, 0x19, 0x0a, 0x15, 0x43, 0x4f, 0x4e, 0x53, 0x45, 0x4e, 0x54, 0x5f, 0x53, 0x54, - 0x41, 0x54, 0x45, 0x5f, 0x41, 0x4c, 0x4c, 0x4f, 0x57, 0x45, 0x44, 0x10, 0x01, 0x12, 0x18, 0x0a, - 0x14, 0x43, 0x4f, 0x4e, 0x53, 0x45, 0x4e, 0x54, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x44, - 0x45, 0x4e, 0x49, 0x45, 0x44, 0x10, 0x02, 0x42, 0xe1, 0x01, 0x0a, 0x1d, 0x63, 0x6f, 0x6d, 0x2e, - 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x42, 0x0c, 0x43, 0x6f, 0x6e, 0x74, 0x65, - 0x6e, 0x74, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x30, 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, 0x6d, 0x6c, 0x73, 0x2f, 0x6d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0xa2, 0x02, 0x03, 0x58, 0x4d, - 0x4d, 0xaa, 0x02, 0x18, 0x58, 0x6d, 0x74, 0x70, 0x2e, 0x4d, 0x6c, 0x73, 0x2e, 0x4d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0xca, 0x02, 0x18, 0x58, + 0x4e, 0x44, 0x5f, 0x43, 0x4f, 0x4e, 0x53, 0x45, 0x4e, 0x54, 0x10, 0x02, 0x42, 0xe1, 0x01, 0x0a, + 0x1d, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x42, 0x0c, + 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x30, + 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, 0x6d, 0x6c, 0x73, 0x2f, + 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, + 0xa2, 0x02, 0x03, 0x58, 0x4d, 0x4d, 0xaa, 0x02, 0x18, 0x58, 0x6d, 0x74, 0x70, 0x2e, 0x4d, 0x6c, + 0x73, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, + 0x73, 0xca, 0x02, 0x18, 0x58, 0x6d, 0x74, 0x70, 0x5c, 0x4d, 0x6c, 0x73, 0x5c, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0xe2, 0x02, 0x24, 0x58, 0x6d, 0x74, 0x70, 0x5c, 0x4d, 0x6c, 0x73, 0x5c, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x43, - 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0xe2, 0x02, 0x24, 0x58, 0x6d, 0x74, 0x70, 0x5c, 0x4d, - 0x6c, 0x73, 0x5c, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, - 0x74, 0x73, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, - 0x1a, 0x58, 0x6d, 0x74, 0x70, 0x3a, 0x3a, 0x4d, 0x6c, 0x73, 0x3a, 0x3a, 0x4d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x4a, 0xe9, 0x27, 0x0a, 0x07, - 0x12, 0x05, 0x02, 0x00, 0x8a, 0x01, 0x01, 0x0a, 0x7c, 0x0a, 0x01, 0x0c, 0x12, 0x03, 0x02, 0x00, - 0x12, 0x1a, 0x72, 0x20, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x20, 0x63, 0x6f, 0x6e, 0x74, - 0x65, 0x6e, 0x74, 0x20, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x73, 0x74, 0x72, - 0x75, 0x63, 0x74, 0x75, 0x72, 0x65, 0x73, 0x0a, 0x20, 0x43, 0x6f, 0x70, 0x69, 0x65, 0x64, 0x20, - 0x66, 0x72, 0x6f, 0x6d, 0x20, 0x56, 0x32, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x20, 0x73, 0x6f, 0x20, - 0x74, 0x68, 0x61, 0x74, 0x20, 0x77, 0x65, 0x20, 0x63, 0x61, 0x6e, 0x20, 0x65, 0x76, 0x65, 0x6e, - 0x74, 0x75, 0x61, 0x6c, 0x6c, 0x79, 0x20, 0x72, 0x65, 0x74, 0x69, 0x72, 0x65, 0x20, 0x61, 0x6c, - 0x6c, 0x20, 0x56, 0x32, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x20, 0x63, 0x6f, 0x6e, - 0x74, 0x65, 0x6e, 0x74, 0x0a, 0x0a, 0x08, 0x0a, 0x01, 0x02, 0x12, 0x03, 0x04, 0x00, 0x22, 0x0a, - 0x08, 0x0a, 0x01, 0x08, 0x12, 0x03, 0x06, 0x00, 0x47, 0x0a, 0x09, 0x0a, 0x02, 0x08, 0x0b, 0x12, - 0x03, 0x06, 0x00, 0x47, 0x0a, 0x58, 0x0a, 0x02, 0x04, 0x00, 0x12, 0x04, 0x0a, 0x00, 0x0f, 0x01, - 0x1a, 0x4c, 0x20, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x49, 0x64, - 0x20, 0x69, 0x73, 0x20, 0x75, 0x73, 0x65, 0x64, 0x20, 0x74, 0x6f, 0x20, 0x69, 0x64, 0x65, 0x6e, - 0x74, 0x69, 0x66, 0x79, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x79, 0x70, 0x65, 0x20, 0x6f, 0x66, - 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x20, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x64, 0x20, - 0x69, 0x6e, 0x20, 0x61, 0x20, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x0a, 0x0a, 0x0a, - 0x0a, 0x03, 0x04, 0x00, 0x01, 0x12, 0x03, 0x0a, 0x08, 0x15, 0x0a, 0x34, 0x0a, 0x04, 0x04, 0x00, - 0x02, 0x00, 0x12, 0x03, 0x0b, 0x02, 0x1a, 0x22, 0x27, 0x20, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, - 0x69, 0x74, 0x79, 0x20, 0x67, 0x6f, 0x76, 0x65, 0x72, 0x6e, 0x69, 0x6e, 0x67, 0x20, 0x74, 0x68, - 0x69, 0x73, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x20, 0x74, 0x79, 0x70, 0x65, 0x0a, - 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x00, 0x05, 0x12, 0x03, 0x0b, 0x02, 0x08, 0x0a, 0x0c, - 0x0a, 0x05, 0x04, 0x00, 0x02, 0x00, 0x01, 0x12, 0x03, 0x0b, 0x09, 0x15, 0x0a, 0x0c, 0x0a, 0x05, - 0x04, 0x00, 0x02, 0x00, 0x03, 0x12, 0x03, 0x0b, 0x18, 0x19, 0x0a, 0x1e, 0x0a, 0x04, 0x04, 0x00, - 0x02, 0x01, 0x12, 0x03, 0x0c, 0x02, 0x15, 0x22, 0x11, 0x20, 0x74, 0x79, 0x70, 0x65, 0x20, 0x69, - 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, - 0x02, 0x01, 0x05, 0x12, 0x03, 0x0c, 0x02, 0x08, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x01, - 0x01, 0x12, 0x03, 0x0c, 0x09, 0x10, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x01, 0x03, 0x12, - 0x03, 0x0c, 0x13, 0x14, 0x0a, 0x28, 0x0a, 0x04, 0x04, 0x00, 0x02, 0x02, 0x12, 0x03, 0x0d, 0x02, - 0x1b, 0x22, 0x1b, 0x20, 0x6d, 0x61, 0x6a, 0x6f, 0x72, 0x20, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, - 0x6e, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x79, 0x70, 0x65, 0x0a, 0x0a, 0x0c, - 0x0a, 0x05, 0x04, 0x00, 0x02, 0x02, 0x05, 0x12, 0x03, 0x0d, 0x02, 0x08, 0x0a, 0x0c, 0x0a, 0x05, - 0x04, 0x00, 0x02, 0x02, 0x01, 0x12, 0x03, 0x0d, 0x09, 0x16, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, - 0x02, 0x02, 0x03, 0x12, 0x03, 0x0d, 0x19, 0x1a, 0x0a, 0x28, 0x0a, 0x04, 0x04, 0x00, 0x02, 0x03, - 0x12, 0x03, 0x0e, 0x02, 0x1b, 0x22, 0x1b, 0x20, 0x6d, 0x69, 0x6e, 0x6f, 0x72, 0x20, 0x76, 0x65, + 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, + 0x61, 0x74, 0x61, 0xea, 0x02, 0x1a, 0x58, 0x6d, 0x74, 0x70, 0x3a, 0x3a, 0x4d, 0x6c, 0x73, 0x3a, + 0x3a, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, + 0x4a, 0xb4, 0x23, 0x0a, 0x06, 0x12, 0x04, 0x02, 0x00, 0x78, 0x01, 0x0a, 0x7c, 0x0a, 0x01, 0x0c, + 0x12, 0x03, 0x02, 0x00, 0x12, 0x1a, 0x72, 0x20, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x20, + 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x20, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, + 0x20, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x75, 0x72, 0x65, 0x73, 0x0a, 0x20, 0x43, 0x6f, 0x70, + 0x69, 0x65, 0x64, 0x20, 0x66, 0x72, 0x6f, 0x6d, 0x20, 0x56, 0x32, 0x20, 0x63, 0x6f, 0x64, 0x65, + 0x20, 0x73, 0x6f, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x77, 0x65, 0x20, 0x63, 0x61, 0x6e, 0x20, + 0x65, 0x76, 0x65, 0x6e, 0x74, 0x75, 0x61, 0x6c, 0x6c, 0x79, 0x20, 0x72, 0x65, 0x74, 0x69, 0x72, + 0x65, 0x20, 0x61, 0x6c, 0x6c, 0x20, 0x56, 0x32, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x0a, 0x0a, 0x08, 0x0a, 0x01, 0x02, 0x12, 0x03, + 0x04, 0x00, 0x22, 0x0a, 0x08, 0x0a, 0x01, 0x08, 0x12, 0x03, 0x06, 0x00, 0x47, 0x0a, 0x09, 0x0a, + 0x02, 0x08, 0x0b, 0x12, 0x03, 0x06, 0x00, 0x47, 0x0a, 0x58, 0x0a, 0x02, 0x04, 0x00, 0x12, 0x04, + 0x0a, 0x00, 0x0f, 0x01, 0x1a, 0x4c, 0x20, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x54, 0x79, + 0x70, 0x65, 0x49, 0x64, 0x20, 0x69, 0x73, 0x20, 0x75, 0x73, 0x65, 0x64, 0x20, 0x74, 0x6f, 0x20, + 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x79, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x79, 0x70, + 0x65, 0x20, 0x6f, 0x66, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x20, 0x73, 0x74, 0x6f, + 0x72, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x20, 0x61, 0x20, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x2e, 0x0a, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x00, 0x01, 0x12, 0x03, 0x0a, 0x08, 0x15, 0x0a, 0x34, + 0x0a, 0x04, 0x04, 0x00, 0x02, 0x00, 0x12, 0x03, 0x0b, 0x02, 0x1a, 0x22, 0x27, 0x20, 0x61, 0x75, + 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x67, 0x6f, 0x76, 0x65, 0x72, 0x6e, 0x69, 0x6e, + 0x67, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x20, 0x74, + 0x79, 0x70, 0x65, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x00, 0x05, 0x12, 0x03, 0x0b, + 0x02, 0x08, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x00, 0x01, 0x12, 0x03, 0x0b, 0x09, 0x15, + 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x00, 0x03, 0x12, 0x03, 0x0b, 0x18, 0x19, 0x0a, 0x1e, + 0x0a, 0x04, 0x04, 0x00, 0x02, 0x01, 0x12, 0x03, 0x0c, 0x02, 0x15, 0x22, 0x11, 0x20, 0x74, 0x79, + 0x70, 0x65, 0x20, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x0a, 0x0a, 0x0c, + 0x0a, 0x05, 0x04, 0x00, 0x02, 0x01, 0x05, 0x12, 0x03, 0x0c, 0x02, 0x08, 0x0a, 0x0c, 0x0a, 0x05, + 0x04, 0x00, 0x02, 0x01, 0x01, 0x12, 0x03, 0x0c, 0x09, 0x10, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, + 0x02, 0x01, 0x03, 0x12, 0x03, 0x0c, 0x13, 0x14, 0x0a, 0x28, 0x0a, 0x04, 0x04, 0x00, 0x02, 0x02, + 0x12, 0x03, 0x0d, 0x02, 0x1b, 0x22, 0x1b, 0x20, 0x6d, 0x61, 0x6a, 0x6f, 0x72, 0x20, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x79, 0x70, - 0x65, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x03, 0x05, 0x12, 0x03, 0x0e, 0x02, 0x08, - 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x03, 0x01, 0x12, 0x03, 0x0e, 0x09, 0x16, 0x0a, 0x0c, - 0x0a, 0x05, 0x04, 0x00, 0x02, 0x03, 0x03, 0x12, 0x03, 0x0e, 0x19, 0x1a, 0x0a, 0x67, 0x0a, 0x02, - 0x05, 0x00, 0x12, 0x04, 0x13, 0x00, 0x16, 0x01, 0x1a, 0x5b, 0x20, 0x52, 0x65, 0x63, 0x6f, 0x67, - 0x6e, 0x69, 0x7a, 0x65, 0x64, 0x20, 0x63, 0x6f, 0x6d, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, - 0x6e, 0x20, 0x61, 0x6c, 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x73, 0x0a, 0x20, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x6c, 0x69, 0x6e, 0x74, 0x3a, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x20, - 0x45, 0x4e, 0x55, 0x4d, 0x5f, 0x46, 0x49, 0x45, 0x4c, 0x44, 0x5f, 0x4e, 0x41, 0x4d, 0x45, 0x53, - 0x5f, 0x5a, 0x45, 0x52, 0x4f, 0x5f, 0x56, 0x41, 0x4c, 0x55, 0x45, 0x5f, 0x45, 0x4e, 0x44, 0x5f, - 0x57, 0x49, 0x54, 0x48, 0x0a, 0x0a, 0x0a, 0x0a, 0x03, 0x05, 0x00, 0x01, 0x12, 0x03, 0x13, 0x05, - 0x10, 0x0a, 0x0b, 0x0a, 0x04, 0x05, 0x00, 0x02, 0x00, 0x12, 0x03, 0x14, 0x02, 0x1a, 0x0a, 0x0c, - 0x0a, 0x05, 0x05, 0x00, 0x02, 0x00, 0x01, 0x12, 0x03, 0x14, 0x02, 0x15, 0x0a, 0x0c, 0x0a, 0x05, - 0x05, 0x00, 0x02, 0x00, 0x02, 0x12, 0x03, 0x14, 0x18, 0x19, 0x0a, 0x0b, 0x0a, 0x04, 0x05, 0x00, - 0x02, 0x01, 0x12, 0x03, 0x15, 0x02, 0x17, 0x0a, 0x0c, 0x0a, 0x05, 0x05, 0x00, 0x02, 0x01, 0x01, - 0x12, 0x03, 0x15, 0x02, 0x12, 0x0a, 0x0c, 0x0a, 0x05, 0x05, 0x00, 0x02, 0x01, 0x02, 0x12, 0x03, - 0x15, 0x15, 0x16, 0x0a, 0xa3, 0x01, 0x0a, 0x02, 0x04, 0x01, 0x12, 0x04, 0x1b, 0x00, 0x29, 0x01, - 0x1a, 0x96, 0x01, 0x20, 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x64, 0x43, 0x6f, 0x6e, 0x74, 0x65, - 0x6e, 0x74, 0x20, 0x62, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, - 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x6d, 0x65, 0x74, 0x61, - 0x64, 0x61, 0x74, 0x61, 0x20, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x79, 0x69, 0x6e, 0x67, - 0x20, 0x69, 0x74, 0x73, 0x20, 0x74, 0x79, 0x70, 0x65, 0x0a, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x70, - 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x20, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, - 0x65, 0x64, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x63, 0x6f, 0x72, 0x72, 0x65, 0x63, 0x74, 0x20, 0x64, - 0x65, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x70, 0x72, 0x65, 0x73, - 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, - 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x0a, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x01, 0x01, - 0x12, 0x03, 0x1b, 0x08, 0x16, 0x0a, 0x65, 0x0a, 0x04, 0x04, 0x01, 0x02, 0x00, 0x12, 0x03, 0x1e, - 0x02, 0x19, 0x1a, 0x58, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x20, 0x74, 0x79, 0x70, - 0x65, 0x20, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x20, 0x75, 0x73, 0x65, - 0x64, 0x20, 0x74, 0x6f, 0x20, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, - 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x0a, 0x20, 0x74, 0x68, 0x65, - 0x20, 0x63, 0x6f, 0x72, 0x72, 0x65, 0x63, 0x74, 0x20, 0x64, 0x65, 0x63, 0x6f, 0x64, 0x69, 0x6e, - 0x67, 0x20, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x72, 0x79, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, - 0x04, 0x01, 0x02, 0x00, 0x06, 0x12, 0x03, 0x1e, 0x02, 0x0f, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, - 0x02, 0x00, 0x01, 0x12, 0x03, 0x1e, 0x10, 0x14, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x00, - 0x03, 0x12, 0x03, 0x1e, 0x17, 0x18, 0x0a, 0x54, 0x0a, 0x04, 0x04, 0x01, 0x02, 0x01, 0x12, 0x03, - 0x20, 0x02, 0x25, 0x1a, 0x47, 0x20, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x20, 0x65, - 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, - 0x72, 0x73, 0x20, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x20, 0x74, 0x6f, 0x20, 0x63, - 0x6f, 0x72, 0x72, 0x65, 0x63, 0x74, 0x6c, 0x79, 0x20, 0x64, 0x65, 0x63, 0x6f, 0x64, 0x65, 0x20, - 0x74, 0x68, 0x65, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, - 0x04, 0x01, 0x02, 0x01, 0x06, 0x12, 0x03, 0x20, 0x02, 0x15, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, - 0x02, 0x01, 0x01, 0x12, 0x03, 0x20, 0x16, 0x20, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x01, - 0x03, 0x12, 0x03, 0x20, 0x23, 0x24, 0x0a, 0x84, 0x01, 0x0a, 0x04, 0x04, 0x01, 0x02, 0x02, 0x12, - 0x03, 0x23, 0x02, 0x1f, 0x1a, 0x77, 0x20, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x20, - 0x66, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x20, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, - 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6f, 0x6e, 0x74, - 0x65, 0x6e, 0x74, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x63, 0x61, 0x6e, 0x20, 0x62, 0x65, 0x20, - 0x75, 0x73, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x20, 0x63, 0x61, 0x73, 0x65, 0x0a, 0x20, 0x74, 0x68, - 0x65, 0x20, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x20, 0x63, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x20, - 0x64, 0x65, 0x63, 0x6f, 0x64, 0x65, 0x20, 0x6f, 0x72, 0x20, 0x72, 0x65, 0x6e, 0x64, 0x65, 0x72, - 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x0a, 0x0a, 0x0c, 0x0a, - 0x05, 0x04, 0x01, 0x02, 0x02, 0x04, 0x12, 0x03, 0x23, 0x02, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, - 0x01, 0x02, 0x02, 0x05, 0x12, 0x03, 0x23, 0x0b, 0x11, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, - 0x02, 0x01, 0x12, 0x03, 0x23, 0x12, 0x1a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x02, 0x03, - 0x12, 0x03, 0x23, 0x1d, 0x1e, 0x0a, 0x6e, 0x0a, 0x04, 0x04, 0x01, 0x02, 0x03, 0x12, 0x03, 0x26, - 0x02, 0x27, 0x1a, 0x61, 0x20, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x20, 0x63, 0x6f, - 0x6d, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x3b, 0x20, 0x74, 0x68, 0x65, 0x20, 0x76, - 0x61, 0x6c, 0x75, 0x65, 0x20, 0x69, 0x6e, 0x64, 0x69, 0x63, 0x61, 0x74, 0x65, 0x73, 0x20, 0x61, - 0x6c, 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x20, 0x75, 0x73, 0x65, 0x64, 0x20, 0x74, 0x6f, - 0x0a, 0x20, 0x63, 0x6f, 0x6d, 0x70, 0x72, 0x65, 0x73, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x65, - 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x64, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x20, 0x62, - 0x79, 0x74, 0x65, 0x73, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x03, 0x04, 0x12, 0x03, - 0x26, 0x02, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x03, 0x06, 0x12, 0x03, 0x26, 0x0b, - 0x16, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x03, 0x01, 0x12, 0x03, 0x26, 0x17, 0x22, 0x0a, - 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x03, 0x03, 0x12, 0x03, 0x26, 0x25, 0x26, 0x0a, 0x25, 0x0a, - 0x04, 0x04, 0x01, 0x02, 0x04, 0x12, 0x03, 0x28, 0x02, 0x14, 0x1a, 0x18, 0x20, 0x65, 0x6e, 0x63, - 0x6f, 0x64, 0x65, 0x64, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x20, 0x69, 0x74, 0x73, - 0x65, 0x6c, 0x66, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x04, 0x05, 0x12, 0x03, 0x28, - 0x02, 0x07, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x04, 0x01, 0x12, 0x03, 0x28, 0x08, 0x0f, - 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x04, 0x03, 0x12, 0x03, 0x28, 0x12, 0x13, 0x0a, 0x55, - 0x0a, 0x02, 0x04, 0x02, 0x12, 0x04, 0x2c, 0x00, 0x4e, 0x01, 0x1a, 0x49, 0x20, 0x41, 0x20, 0x50, - 0x6c, 0x61, 0x69, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x45, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, - 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x6d, 0x6f, 0x73, - 0x74, 0x20, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x67, - 0x65, 0x74, 0x73, 0x20, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x65, 0x64, 0x20, 0x62, 0x79, - 0x20, 0x4d, 0x4c, 0x53, 0x0a, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x02, 0x01, 0x12, 0x03, 0x2c, 0x08, - 0x19, 0x0a, 0x33, 0x0a, 0x04, 0x04, 0x02, 0x03, 0x00, 0x12, 0x04, 0x2e, 0x02, 0x34, 0x03, 0x1a, - 0x25, 0x20, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x31, 0x20, 0x6f, 0x66, 0x20, 0x74, - 0x68, 0x65, 0x20, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x65, 0x64, 0x20, 0x65, 0x6e, 0x76, - 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x03, 0x00, 0x01, 0x12, - 0x03, 0x2e, 0x0a, 0x0c, 0x0a, 0x2e, 0x0a, 0x06, 0x04, 0x02, 0x03, 0x00, 0x02, 0x00, 0x12, 0x03, - 0x30, 0x04, 0x16, 0x1a, 0x1f, 0x20, 0x45, 0x78, 0x70, 0x65, 0x63, 0x74, 0x65, 0x64, 0x20, 0x74, - 0x6f, 0x20, 0x62, 0x65, 0x20, 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x64, 0x43, 0x6f, 0x6e, 0x74, - 0x65, 0x6e, 0x74, 0x0a, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, 0x00, 0x02, 0x00, 0x05, 0x12, - 0x03, 0x30, 0x04, 0x09, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, 0x00, 0x02, 0x00, 0x01, 0x12, - 0x03, 0x30, 0x0a, 0x11, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, 0x00, 0x02, 0x00, 0x03, 0x12, - 0x03, 0x30, 0x14, 0x15, 0x0a, 0x8c, 0x01, 0x0a, 0x06, 0x04, 0x02, 0x03, 0x00, 0x02, 0x01, 0x12, - 0x03, 0x33, 0x04, 0x1f, 0x1a, 0x7d, 0x20, 0x41, 0x20, 0x75, 0x6e, 0x69, 0x71, 0x75, 0x65, 0x20, - 0x76, 0x61, 0x6c, 0x75, 0x65, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x63, 0x61, 0x6e, 0x20, 0x62, - 0x65, 0x20, 0x75, 0x73, 0x65, 0x64, 0x20, 0x74, 0x6f, 0x20, 0x65, 0x6e, 0x73, 0x75, 0x72, 0x65, - 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x61, 0x6d, 0x65, 0x20, 0x63, - 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x20, 0x63, 0x61, 0x6e, 0x0a, 0x20, 0x70, 0x72, 0x6f, 0x64, - 0x75, 0x63, 0x65, 0x20, 0x64, 0x69, 0x66, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x74, 0x20, 0x68, 0x61, - 0x73, 0x68, 0x65, 0x73, 0x2e, 0x20, 0x4d, 0x61, 0x79, 0x20, 0x62, 0x65, 0x20, 0x74, 0x68, 0x65, - 0x20, 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x20, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, - 0x70, 0x2e, 0x0a, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, 0x00, 0x02, 0x01, 0x05, 0x12, 0x03, - 0x33, 0x04, 0x0a, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, 0x00, 0x02, 0x01, 0x01, 0x12, 0x03, - 0x33, 0x0b, 0x1a, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, 0x00, 0x02, 0x01, 0x03, 0x12, 0x03, - 0x33, 0x1d, 0x1e, 0x0a, 0x33, 0x0a, 0x04, 0x04, 0x02, 0x03, 0x01, 0x12, 0x04, 0x37, 0x02, 0x46, - 0x03, 0x1a, 0x25, 0x20, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x32, 0x20, 0x6f, 0x66, - 0x20, 0x74, 0x68, 0x65, 0x20, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x65, 0x64, 0x20, 0x65, - 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x03, 0x01, - 0x01, 0x12, 0x03, 0x37, 0x0a, 0x0c, 0x0a, 0x8c, 0x01, 0x0a, 0x06, 0x04, 0x02, 0x03, 0x01, 0x02, - 0x00, 0x12, 0x03, 0x3a, 0x04, 0x1f, 0x1a, 0x7d, 0x20, 0x41, 0x20, 0x75, 0x6e, 0x69, 0x71, 0x75, - 0x65, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x63, 0x61, 0x6e, - 0x20, 0x62, 0x65, 0x20, 0x75, 0x73, 0x65, 0x64, 0x20, 0x74, 0x6f, 0x20, 0x65, 0x6e, 0x73, 0x75, - 0x72, 0x65, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x61, 0x6d, 0x65, - 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x20, 0x63, 0x61, 0x6e, 0x0a, 0x20, 0x70, 0x72, - 0x6f, 0x64, 0x75, 0x63, 0x65, 0x20, 0x64, 0x69, 0x66, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x74, 0x20, - 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x2e, 0x20, 0x4d, 0x61, 0x79, 0x20, 0x62, 0x65, 0x20, 0x74, - 0x68, 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x20, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, - 0x61, 0x6d, 0x70, 0x2e, 0x0a, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, 0x01, 0x02, 0x00, 0x05, - 0x12, 0x03, 0x3a, 0x04, 0x0a, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, 0x01, 0x02, 0x00, 0x01, - 0x12, 0x03, 0x3a, 0x0b, 0x1a, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, 0x01, 0x02, 0x00, 0x03, - 0x12, 0x03, 0x3a, 0x1d, 0x1e, 0x0a, 0x0e, 0x0a, 0x06, 0x04, 0x02, 0x03, 0x01, 0x08, 0x00, 0x12, - 0x04, 0x3c, 0x04, 0x45, 0x05, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, 0x01, 0x08, 0x00, 0x01, - 0x12, 0x03, 0x3c, 0x0a, 0x16, 0x0a, 0x2e, 0x0a, 0x06, 0x04, 0x02, 0x03, 0x01, 0x02, 0x01, 0x12, - 0x03, 0x3e, 0x06, 0x18, 0x1a, 0x1f, 0x20, 0x45, 0x78, 0x70, 0x65, 0x63, 0x74, 0x65, 0x64, 0x20, - 0x74, 0x6f, 0x20, 0x62, 0x65, 0x20, 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x64, 0x43, 0x6f, 0x6e, - 0x74, 0x65, 0x6e, 0x74, 0x0a, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, 0x01, 0x02, 0x01, 0x05, - 0x12, 0x03, 0x3e, 0x06, 0x0b, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, 0x01, 0x02, 0x01, 0x01, - 0x12, 0x03, 0x3e, 0x0c, 0x13, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, 0x01, 0x02, 0x01, 0x03, - 0x12, 0x03, 0x3e, 0x16, 0x17, 0x0a, 0x42, 0x0a, 0x06, 0x04, 0x02, 0x03, 0x01, 0x02, 0x02, 0x12, - 0x03, 0x40, 0x06, 0x30, 0x1a, 0x33, 0x20, 0x49, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x74, 0x6f, 0x72, - 0x20, 0x73, 0x65, 0x6e, 0x64, 0x73, 0x20, 0x61, 0x20, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x20, 0x74, 0x6f, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20, 0x73, 0x79, 0x6e, 0x63, - 0x20, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x0a, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, - 0x01, 0x02, 0x02, 0x06, 0x12, 0x03, 0x40, 0x06, 0x17, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, - 0x01, 0x02, 0x02, 0x01, 0x12, 0x03, 0x40, 0x18, 0x2b, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, - 0x01, 0x02, 0x02, 0x03, 0x12, 0x03, 0x40, 0x2e, 0x2f, 0x0a, 0x58, 0x0a, 0x06, 0x04, 0x02, 0x03, - 0x01, 0x02, 0x03, 0x12, 0x03, 0x42, 0x06, 0x2c, 0x1a, 0x49, 0x20, 0x53, 0x6f, 0x6d, 0x65, 0x20, - 0x6f, 0x74, 0x68, 0x65, 0x72, 0x20, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, - 0x20, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x73, 0x65, - 0x6e, 0x64, 0x73, 0x20, 0x61, 0x20, 0x72, 0x65, 0x70, 0x6c, 0x79, 0x20, 0x77, 0x69, 0x74, 0x68, - 0x20, 0x61, 0x20, 0x6c, 0x69, 0x6e, 0x6b, 0x20, 0x74, 0x6f, 0x20, 0x70, 0x61, 0x79, 0x6c, 0x6f, - 0x61, 0x64, 0x0a, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, 0x01, 0x02, 0x03, 0x06, 0x12, 0x03, - 0x42, 0x06, 0x15, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, 0x01, 0x02, 0x03, 0x01, 0x12, 0x03, - 0x42, 0x16, 0x27, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, 0x01, 0x02, 0x03, 0x03, 0x12, 0x03, - 0x42, 0x2a, 0x2b, 0x0a, 0x2a, 0x0a, 0x06, 0x04, 0x02, 0x03, 0x01, 0x02, 0x04, 0x12, 0x03, 0x44, - 0x06, 0x27, 0x1a, 0x1b, 0x20, 0x41, 0x20, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x65, 0x64, 0x20, - 0x63, 0x6f, 0x73, 0x6e, 0x65, 0x6e, 0x74, 0x20, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x0a, 0x0a, - 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, 0x01, 0x02, 0x04, 0x06, 0x12, 0x03, 0x44, 0x06, 0x13, 0x0a, - 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, 0x01, 0x02, 0x04, 0x01, 0x12, 0x03, 0x44, 0x14, 0x22, 0x0a, - 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, 0x01, 0x02, 0x04, 0x03, 0x12, 0x03, 0x44, 0x25, 0x26, 0x0a, - 0x66, 0x0a, 0x04, 0x04, 0x02, 0x08, 0x00, 0x12, 0x04, 0x4a, 0x02, 0x4d, 0x03, 0x1a, 0x58, 0x20, - 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x20, 0x77, 0x68, 0x69, 0x63, 0x68, 0x20, 0x64, - 0x65, 0x63, 0x6c, 0x61, 0x72, 0x65, 0x73, 0x20, 0x77, 0x68, 0x69, 0x63, 0x68, 0x20, 0x76, 0x65, - 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x45, 0x6e, 0x63, - 0x6f, 0x64, 0x65, 0x64, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x20, 0x74, 0x68, 0x69, 0x73, - 0x0a, 0x20, 0x50, 0x6c, 0x61, 0x69, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x45, 0x6e, 0x76, 0x65, 0x6c, - 0x6f, 0x70, 0x65, 0x20, 0x69, 0x73, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x08, 0x00, 0x01, - 0x12, 0x03, 0x4a, 0x08, 0x0f, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x02, 0x02, 0x00, 0x12, 0x03, 0x4b, - 0x04, 0x0e, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x00, 0x06, 0x12, 0x03, 0x4b, 0x04, 0x06, - 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x00, 0x01, 0x12, 0x03, 0x4b, 0x07, 0x09, 0x0a, 0x0c, - 0x0a, 0x05, 0x04, 0x02, 0x02, 0x00, 0x03, 0x12, 0x03, 0x4b, 0x0c, 0x0d, 0x0a, 0x0b, 0x0a, 0x04, - 0x04, 0x02, 0x02, 0x01, 0x12, 0x03, 0x4c, 0x04, 0x0e, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, - 0x01, 0x06, 0x12, 0x03, 0x4c, 0x04, 0x06, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x01, 0x01, - 0x12, 0x03, 0x4c, 0x07, 0x09, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x01, 0x03, 0x12, 0x03, - 0x4c, 0x0c, 0x0d, 0x0a, 0x57, 0x0a, 0x02, 0x04, 0x03, 0x12, 0x04, 0x51, 0x00, 0x58, 0x01, 0x1a, - 0x4b, 0x20, 0x49, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x74, 0x6f, 0x72, 0x20, 0x6f, 0x72, 0x20, 0x6e, - 0x65, 0x77, 0x20, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, - 0x69, 0x64, 0x20, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x20, 0x61, 0x20, - 0x73, 0x79, 0x6e, 0x63, 0x20, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x20, 0x73, 0x65, 0x6e, - 0x64, 0x20, 0x61, 0x20, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x0a, 0x0a, 0x0a, 0x0a, 0x03, - 0x04, 0x03, 0x01, 0x12, 0x03, 0x51, 0x08, 0x19, 0x0a, 0x31, 0x0a, 0x04, 0x04, 0x03, 0x02, 0x00, - 0x12, 0x03, 0x53, 0x02, 0x18, 0x1a, 0x24, 0x20, 0x55, 0x6e, 0x69, 0x71, 0x75, 0x65, 0x20, 0x69, - 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x65, 0x61, - 0x63, 0x68, 0x20, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, - 0x03, 0x02, 0x00, 0x05, 0x12, 0x03, 0x53, 0x02, 0x08, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, - 0x00, 0x01, 0x12, 0x03, 0x53, 0x09, 0x13, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, 0x00, 0x03, - 0x12, 0x03, 0x53, 0x16, 0x17, 0x0a, 0x2d, 0x0a, 0x04, 0x04, 0x03, 0x02, 0x01, 0x12, 0x03, 0x55, - 0x02, 0x16, 0x1a, 0x20, 0x20, 0x45, 0x6e, 0x73, 0x75, 0x72, 0x65, 0x73, 0x20, 0x61, 0x20, 0x68, - 0x75, 0x6d, 0x61, 0x6e, 0x20, 0x69, 0x73, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6c, - 0x6f, 0x6f, 0x70, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, 0x01, 0x05, 0x12, 0x03, 0x55, - 0x02, 0x08, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, 0x01, 0x01, 0x12, 0x03, 0x55, 0x09, 0x11, - 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, 0x01, 0x03, 0x12, 0x03, 0x55, 0x14, 0x15, 0x0a, 0x1b, - 0x0a, 0x04, 0x04, 0x03, 0x02, 0x02, 0x12, 0x03, 0x57, 0x02, 0x1a, 0x1a, 0x0e, 0x20, 0x72, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x20, 0x6b, 0x69, 0x6e, 0x64, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, - 0x03, 0x02, 0x02, 0x06, 0x12, 0x03, 0x57, 0x02, 0x10, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, - 0x02, 0x01, 0x12, 0x03, 0x57, 0x11, 0x15, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, 0x02, 0x03, - 0x12, 0x03, 0x57, 0x18, 0x19, 0x0a, 0x5f, 0x0a, 0x02, 0x04, 0x04, 0x12, 0x04, 0x5b, 0x00, 0x66, - 0x01, 0x1a, 0x53, 0x20, 0x50, 0x72, 0x65, 0x2d, 0x65, 0x78, 0x69, 0x73, 0x74, 0x69, 0x6e, 0x67, + 0x65, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x02, 0x05, 0x12, 0x03, 0x0d, 0x02, 0x08, + 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x02, 0x01, 0x12, 0x03, 0x0d, 0x09, 0x16, 0x0a, 0x0c, + 0x0a, 0x05, 0x04, 0x00, 0x02, 0x02, 0x03, 0x12, 0x03, 0x0d, 0x19, 0x1a, 0x0a, 0x28, 0x0a, 0x04, + 0x04, 0x00, 0x02, 0x03, 0x12, 0x03, 0x0e, 0x02, 0x1b, 0x22, 0x1b, 0x20, 0x6d, 0x69, 0x6e, 0x6f, + 0x72, 0x20, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x74, 0x79, 0x70, 0x65, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x03, 0x05, 0x12, + 0x03, 0x0e, 0x02, 0x08, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x03, 0x01, 0x12, 0x03, 0x0e, + 0x09, 0x16, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x03, 0x03, 0x12, 0x03, 0x0e, 0x19, 0x1a, + 0x0a, 0x67, 0x0a, 0x02, 0x05, 0x00, 0x12, 0x04, 0x13, 0x00, 0x16, 0x01, 0x1a, 0x5b, 0x20, 0x52, + 0x65, 0x63, 0x6f, 0x67, 0x6e, 0x69, 0x7a, 0x65, 0x64, 0x20, 0x63, 0x6f, 0x6d, 0x70, 0x72, 0x65, + 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x61, 0x6c, 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x73, + 0x0a, 0x20, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x6c, 0x69, 0x6e, 0x74, 0x3a, 0x64, 0x69, 0x73, 0x61, + 0x62, 0x6c, 0x65, 0x20, 0x45, 0x4e, 0x55, 0x4d, 0x5f, 0x46, 0x49, 0x45, 0x4c, 0x44, 0x5f, 0x4e, + 0x41, 0x4d, 0x45, 0x53, 0x5f, 0x5a, 0x45, 0x52, 0x4f, 0x5f, 0x56, 0x41, 0x4c, 0x55, 0x45, 0x5f, + 0x45, 0x4e, 0x44, 0x5f, 0x57, 0x49, 0x54, 0x48, 0x0a, 0x0a, 0x0a, 0x0a, 0x03, 0x05, 0x00, 0x01, + 0x12, 0x03, 0x13, 0x05, 0x10, 0x0a, 0x0b, 0x0a, 0x04, 0x05, 0x00, 0x02, 0x00, 0x12, 0x03, 0x14, + 0x02, 0x1a, 0x0a, 0x0c, 0x0a, 0x05, 0x05, 0x00, 0x02, 0x00, 0x01, 0x12, 0x03, 0x14, 0x02, 0x15, + 0x0a, 0x0c, 0x0a, 0x05, 0x05, 0x00, 0x02, 0x00, 0x02, 0x12, 0x03, 0x14, 0x18, 0x19, 0x0a, 0x0b, + 0x0a, 0x04, 0x05, 0x00, 0x02, 0x01, 0x12, 0x03, 0x15, 0x02, 0x17, 0x0a, 0x0c, 0x0a, 0x05, 0x05, + 0x00, 0x02, 0x01, 0x01, 0x12, 0x03, 0x15, 0x02, 0x12, 0x0a, 0x0c, 0x0a, 0x05, 0x05, 0x00, 0x02, + 0x01, 0x02, 0x12, 0x03, 0x15, 0x15, 0x16, 0x0a, 0xa3, 0x01, 0x0a, 0x02, 0x04, 0x01, 0x12, 0x04, + 0x1b, 0x00, 0x29, 0x01, 0x1a, 0x96, 0x01, 0x20, 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x64, 0x43, + 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x20, 0x62, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x73, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, + 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x20, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, + 0x79, 0x69, 0x6e, 0x67, 0x20, 0x69, 0x74, 0x73, 0x20, 0x74, 0x79, 0x70, 0x65, 0x0a, 0x20, 0x61, + 0x6e, 0x64, 0x20, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x20, 0x72, 0x65, + 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x63, 0x6f, 0x72, 0x72, 0x65, + 0x63, 0x74, 0x20, 0x64, 0x65, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x61, 0x6e, 0x64, 0x20, + 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6f, 0x66, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x0a, 0x0a, 0x0a, 0x0a, + 0x03, 0x04, 0x01, 0x01, 0x12, 0x03, 0x1b, 0x08, 0x16, 0x0a, 0x65, 0x0a, 0x04, 0x04, 0x01, 0x02, + 0x00, 0x12, 0x03, 0x1e, 0x02, 0x19, 0x1a, 0x58, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, + 0x20, 0x74, 0x79, 0x70, 0x65, 0x20, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, + 0x20, 0x75, 0x73, 0x65, 0x64, 0x20, 0x74, 0x6f, 0x20, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x0a, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6f, 0x72, 0x72, 0x65, 0x63, 0x74, 0x20, 0x64, 0x65, 0x63, + 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x72, 0x79, 0x0a, + 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x00, 0x06, 0x12, 0x03, 0x1e, 0x02, 0x0f, 0x0a, 0x0c, + 0x0a, 0x05, 0x04, 0x01, 0x02, 0x00, 0x01, 0x12, 0x03, 0x1e, 0x10, 0x14, 0x0a, 0x0c, 0x0a, 0x05, + 0x04, 0x01, 0x02, 0x00, 0x03, 0x12, 0x03, 0x1e, 0x17, 0x18, 0x0a, 0x54, 0x0a, 0x04, 0x04, 0x01, + 0x02, 0x01, 0x12, 0x03, 0x20, 0x02, 0x25, 0x1a, 0x47, 0x20, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, + 0x61, 0x6c, 0x20, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x70, 0x61, 0x72, 0x61, + 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x20, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x20, + 0x74, 0x6f, 0x20, 0x63, 0x6f, 0x72, 0x72, 0x65, 0x63, 0x74, 0x6c, 0x79, 0x20, 0x64, 0x65, 0x63, + 0x6f, 0x64, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x0a, + 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x01, 0x06, 0x12, 0x03, 0x20, 0x02, 0x15, 0x0a, 0x0c, + 0x0a, 0x05, 0x04, 0x01, 0x02, 0x01, 0x01, 0x12, 0x03, 0x20, 0x16, 0x20, 0x0a, 0x0c, 0x0a, 0x05, + 0x04, 0x01, 0x02, 0x01, 0x03, 0x12, 0x03, 0x20, 0x23, 0x24, 0x0a, 0x84, 0x01, 0x0a, 0x04, 0x04, + 0x01, 0x02, 0x02, 0x12, 0x03, 0x23, 0x02, 0x1f, 0x1a, 0x77, 0x20, 0x6f, 0x70, 0x74, 0x69, 0x6f, + 0x6e, 0x61, 0x6c, 0x20, 0x66, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x20, 0x64, 0x65, 0x73, + 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x63, 0x61, 0x6e, + 0x20, 0x62, 0x65, 0x20, 0x75, 0x73, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x20, 0x63, 0x61, 0x73, 0x65, + 0x0a, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x20, 0x63, 0x61, 0x6e, + 0x6e, 0x6f, 0x74, 0x20, 0x64, 0x65, 0x63, 0x6f, 0x64, 0x65, 0x20, 0x6f, 0x72, 0x20, 0x72, 0x65, + 0x6e, 0x64, 0x65, 0x72, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, + 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x02, 0x04, 0x12, 0x03, 0x23, 0x02, 0x0a, 0x0a, + 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x02, 0x05, 0x12, 0x03, 0x23, 0x0b, 0x11, 0x0a, 0x0c, 0x0a, + 0x05, 0x04, 0x01, 0x02, 0x02, 0x01, 0x12, 0x03, 0x23, 0x12, 0x1a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, + 0x01, 0x02, 0x02, 0x03, 0x12, 0x03, 0x23, 0x1d, 0x1e, 0x0a, 0x6e, 0x0a, 0x04, 0x04, 0x01, 0x02, + 0x03, 0x12, 0x03, 0x26, 0x02, 0x27, 0x1a, 0x61, 0x20, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x61, + 0x6c, 0x20, 0x63, 0x6f, 0x6d, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x3b, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x20, 0x69, 0x6e, 0x64, 0x69, 0x63, 0x61, 0x74, + 0x65, 0x73, 0x20, 0x61, 0x6c, 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x20, 0x75, 0x73, 0x65, + 0x64, 0x20, 0x74, 0x6f, 0x0a, 0x20, 0x63, 0x6f, 0x6d, 0x70, 0x72, 0x65, 0x73, 0x73, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x64, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x65, + 0x6e, 0x74, 0x20, 0x62, 0x79, 0x74, 0x65, 0x73, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, + 0x03, 0x04, 0x12, 0x03, 0x26, 0x02, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x03, 0x06, + 0x12, 0x03, 0x26, 0x0b, 0x16, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x03, 0x01, 0x12, 0x03, + 0x26, 0x17, 0x22, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x03, 0x03, 0x12, 0x03, 0x26, 0x25, + 0x26, 0x0a, 0x25, 0x0a, 0x04, 0x04, 0x01, 0x02, 0x04, 0x12, 0x03, 0x28, 0x02, 0x14, 0x1a, 0x18, + 0x20, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x64, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, + 0x20, 0x69, 0x74, 0x73, 0x65, 0x6c, 0x66, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x04, + 0x05, 0x12, 0x03, 0x28, 0x02, 0x07, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x04, 0x01, 0x12, + 0x03, 0x28, 0x08, 0x0f, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x04, 0x03, 0x12, 0x03, 0x28, + 0x12, 0x13, 0x0a, 0x55, 0x0a, 0x02, 0x04, 0x02, 0x12, 0x04, 0x2c, 0x00, 0x4e, 0x01, 0x1a, 0x49, + 0x20, 0x41, 0x20, 0x50, 0x6c, 0x61, 0x69, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x45, 0x6e, 0x76, 0x65, + 0x6c, 0x6f, 0x70, 0x65, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6f, 0x75, 0x74, 0x65, + 0x72, 0x6d, 0x6f, 0x73, 0x74, 0x20, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x20, 0x74, 0x68, + 0x61, 0x74, 0x20, 0x67, 0x65, 0x74, 0x73, 0x20, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x65, + 0x64, 0x20, 0x62, 0x79, 0x20, 0x4d, 0x4c, 0x53, 0x0a, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x02, 0x01, + 0x12, 0x03, 0x2c, 0x08, 0x19, 0x0a, 0x33, 0x0a, 0x04, 0x04, 0x02, 0x03, 0x00, 0x12, 0x04, 0x2e, + 0x02, 0x34, 0x03, 0x1a, 0x25, 0x20, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x31, 0x20, + 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x65, 0x64, + 0x20, 0x65, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, + 0x03, 0x00, 0x01, 0x12, 0x03, 0x2e, 0x0a, 0x0c, 0x0a, 0x2e, 0x0a, 0x06, 0x04, 0x02, 0x03, 0x00, + 0x02, 0x00, 0x12, 0x03, 0x30, 0x04, 0x16, 0x1a, 0x1f, 0x20, 0x45, 0x78, 0x70, 0x65, 0x63, 0x74, + 0x65, 0x64, 0x20, 0x74, 0x6f, 0x20, 0x62, 0x65, 0x20, 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x64, + 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x0a, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, 0x00, + 0x02, 0x00, 0x05, 0x12, 0x03, 0x30, 0x04, 0x09, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, 0x00, + 0x02, 0x00, 0x01, 0x12, 0x03, 0x30, 0x0a, 0x11, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, 0x00, + 0x02, 0x00, 0x03, 0x12, 0x03, 0x30, 0x14, 0x15, 0x0a, 0x8c, 0x01, 0x0a, 0x06, 0x04, 0x02, 0x03, + 0x00, 0x02, 0x01, 0x12, 0x03, 0x33, 0x04, 0x1f, 0x1a, 0x7d, 0x20, 0x41, 0x20, 0x75, 0x6e, 0x69, + 0x71, 0x75, 0x65, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x63, + 0x61, 0x6e, 0x20, 0x62, 0x65, 0x20, 0x75, 0x73, 0x65, 0x64, 0x20, 0x74, 0x6f, 0x20, 0x65, 0x6e, + 0x73, 0x75, 0x72, 0x65, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x61, + 0x6d, 0x65, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x20, 0x63, 0x61, 0x6e, 0x0a, 0x20, + 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x65, 0x20, 0x64, 0x69, 0x66, 0x66, 0x65, 0x72, 0x65, 0x6e, + 0x74, 0x20, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x2e, 0x20, 0x4d, 0x61, 0x79, 0x20, 0x62, 0x65, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x20, 0x74, 0x69, 0x6d, 0x65, + 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x0a, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, 0x00, 0x02, + 0x01, 0x05, 0x12, 0x03, 0x33, 0x04, 0x0a, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, 0x00, 0x02, + 0x01, 0x01, 0x12, 0x03, 0x33, 0x0b, 0x1a, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, 0x00, 0x02, + 0x01, 0x03, 0x12, 0x03, 0x33, 0x1d, 0x1e, 0x0a, 0x33, 0x0a, 0x04, 0x04, 0x02, 0x03, 0x01, 0x12, + 0x04, 0x37, 0x02, 0x46, 0x03, 0x1a, 0x25, 0x20, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x20, + 0x32, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, + 0x65, 0x64, 0x20, 0x65, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, + 0x04, 0x02, 0x03, 0x01, 0x01, 0x12, 0x03, 0x37, 0x0a, 0x0c, 0x0a, 0x8c, 0x01, 0x0a, 0x06, 0x04, + 0x02, 0x03, 0x01, 0x02, 0x00, 0x12, 0x03, 0x3a, 0x04, 0x1f, 0x1a, 0x7d, 0x20, 0x41, 0x20, 0x75, + 0x6e, 0x69, 0x71, 0x75, 0x65, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x20, 0x74, 0x68, 0x61, 0x74, + 0x20, 0x63, 0x61, 0x6e, 0x20, 0x62, 0x65, 0x20, 0x75, 0x73, 0x65, 0x64, 0x20, 0x74, 0x6f, 0x20, + 0x65, 0x6e, 0x73, 0x75, 0x72, 0x65, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x73, 0x61, 0x6d, 0x65, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x20, 0x63, 0x61, 0x6e, + 0x0a, 0x20, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x65, 0x20, 0x64, 0x69, 0x66, 0x66, 0x65, 0x72, + 0x65, 0x6e, 0x74, 0x20, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x2e, 0x20, 0x4d, 0x61, 0x79, 0x20, + 0x62, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x20, 0x74, 0x69, + 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x0a, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, + 0x01, 0x02, 0x00, 0x05, 0x12, 0x03, 0x3a, 0x04, 0x0a, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, + 0x01, 0x02, 0x00, 0x01, 0x12, 0x03, 0x3a, 0x0b, 0x1a, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, + 0x01, 0x02, 0x00, 0x03, 0x12, 0x03, 0x3a, 0x1d, 0x1e, 0x0a, 0x0e, 0x0a, 0x06, 0x04, 0x02, 0x03, + 0x01, 0x08, 0x00, 0x12, 0x04, 0x3c, 0x04, 0x45, 0x05, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, + 0x01, 0x08, 0x00, 0x01, 0x12, 0x03, 0x3c, 0x0a, 0x16, 0x0a, 0x2e, 0x0a, 0x06, 0x04, 0x02, 0x03, + 0x01, 0x02, 0x01, 0x12, 0x03, 0x3e, 0x06, 0x18, 0x1a, 0x1f, 0x20, 0x45, 0x78, 0x70, 0x65, 0x63, + 0x74, 0x65, 0x64, 0x20, 0x74, 0x6f, 0x20, 0x62, 0x65, 0x20, 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x65, + 0x64, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x0a, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, + 0x01, 0x02, 0x01, 0x05, 0x12, 0x03, 0x3e, 0x06, 0x0b, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, + 0x01, 0x02, 0x01, 0x01, 0x12, 0x03, 0x3e, 0x0c, 0x13, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, + 0x01, 0x02, 0x01, 0x03, 0x12, 0x03, 0x3e, 0x16, 0x17, 0x0a, 0x42, 0x0a, 0x06, 0x04, 0x02, 0x03, + 0x01, 0x02, 0x02, 0x12, 0x03, 0x40, 0x06, 0x30, 0x1a, 0x33, 0x20, 0x49, 0x6e, 0x69, 0x74, 0x69, + 0x61, 0x74, 0x6f, 0x72, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x73, 0x20, 0x61, 0x20, 0x72, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x20, 0x74, 0x6f, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20, + 0x73, 0x79, 0x6e, 0x63, 0x20, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x0a, 0x0a, 0x0e, 0x0a, + 0x07, 0x04, 0x02, 0x03, 0x01, 0x02, 0x02, 0x06, 0x12, 0x03, 0x40, 0x06, 0x17, 0x0a, 0x0e, 0x0a, + 0x07, 0x04, 0x02, 0x03, 0x01, 0x02, 0x02, 0x01, 0x12, 0x03, 0x40, 0x18, 0x2b, 0x0a, 0x0e, 0x0a, + 0x07, 0x04, 0x02, 0x03, 0x01, 0x02, 0x02, 0x03, 0x12, 0x03, 0x40, 0x2e, 0x2f, 0x0a, 0x58, 0x0a, + 0x06, 0x04, 0x02, 0x03, 0x01, 0x02, 0x03, 0x12, 0x03, 0x42, 0x06, 0x2c, 0x1a, 0x49, 0x20, 0x53, + 0x6f, 0x6d, 0x65, 0x20, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x20, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, + 0x69, 0x7a, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x73, 0x20, 0x61, 0x20, 0x72, 0x65, 0x70, 0x6c, 0x79, 0x20, + 0x77, 0x69, 0x74, 0x68, 0x20, 0x61, 0x20, 0x6c, 0x69, 0x6e, 0x6b, 0x20, 0x74, 0x6f, 0x20, 0x70, + 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x0a, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, 0x01, 0x02, + 0x03, 0x06, 0x12, 0x03, 0x42, 0x06, 0x15, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, 0x01, 0x02, + 0x03, 0x01, 0x12, 0x03, 0x42, 0x16, 0x27, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, 0x01, 0x02, + 0x03, 0x03, 0x12, 0x03, 0x42, 0x2a, 0x2b, 0x0a, 0x34, 0x0a, 0x06, 0x04, 0x02, 0x03, 0x01, 0x02, + 0x04, 0x12, 0x03, 0x44, 0x06, 0x36, 0x1a, 0x25, 0x20, 0x41, 0x20, 0x73, 0x65, 0x72, 0x69, 0x61, + 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x20, 0x75, 0x73, 0x65, 0x72, 0x20, 0x70, 0x72, 0x65, 0x66, 0x65, + 0x72, 0x65, 0x6e, 0x63, 0x65, 0x20, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x0a, 0x0a, 0x0e, 0x0a, + 0x07, 0x04, 0x02, 0x03, 0x01, 0x02, 0x04, 0x06, 0x12, 0x03, 0x44, 0x06, 0x1a, 0x0a, 0x0e, 0x0a, + 0x07, 0x04, 0x02, 0x03, 0x01, 0x02, 0x04, 0x01, 0x12, 0x03, 0x44, 0x1b, 0x31, 0x0a, 0x0e, 0x0a, + 0x07, 0x04, 0x02, 0x03, 0x01, 0x02, 0x04, 0x03, 0x12, 0x03, 0x44, 0x34, 0x35, 0x0a, 0x66, 0x0a, + 0x04, 0x04, 0x02, 0x08, 0x00, 0x12, 0x04, 0x4a, 0x02, 0x4d, 0x03, 0x1a, 0x58, 0x20, 0x53, 0x65, + 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x20, 0x77, 0x68, 0x69, 0x63, 0x68, 0x20, 0x64, 0x65, 0x63, + 0x6c, 0x61, 0x72, 0x65, 0x73, 0x20, 0x77, 0x68, 0x69, 0x63, 0x68, 0x20, 0x76, 0x65, 0x72, 0x73, + 0x69, 0x6f, 0x6e, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x45, 0x6e, 0x63, 0x6f, 0x64, + 0x65, 0x64, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x20, 0x74, 0x68, 0x69, 0x73, 0x0a, 0x20, + 0x50, 0x6c, 0x61, 0x69, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x45, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, + 0x65, 0x20, 0x69, 0x73, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x08, 0x00, 0x01, 0x12, 0x03, + 0x4a, 0x08, 0x0f, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x02, 0x02, 0x00, 0x12, 0x03, 0x4b, 0x04, 0x0e, + 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x00, 0x06, 0x12, 0x03, 0x4b, 0x04, 0x06, 0x0a, 0x0c, + 0x0a, 0x05, 0x04, 0x02, 0x02, 0x00, 0x01, 0x12, 0x03, 0x4b, 0x07, 0x09, 0x0a, 0x0c, 0x0a, 0x05, + 0x04, 0x02, 0x02, 0x00, 0x03, 0x12, 0x03, 0x4b, 0x0c, 0x0d, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x02, + 0x02, 0x01, 0x12, 0x03, 0x4c, 0x04, 0x0e, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x01, 0x06, + 0x12, 0x03, 0x4c, 0x04, 0x06, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x01, 0x01, 0x12, 0x03, + 0x4c, 0x07, 0x09, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x01, 0x03, 0x12, 0x03, 0x4c, 0x0c, + 0x0d, 0x0a, 0x57, 0x0a, 0x02, 0x04, 0x03, 0x12, 0x04, 0x51, 0x00, 0x58, 0x01, 0x1a, 0x4b, 0x20, + 0x49, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x74, 0x6f, 0x72, 0x20, 0x6f, 0x72, 0x20, 0x6e, 0x65, 0x77, 0x20, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x69, 0x64, - 0x20, 0x63, 0x61, 0x70, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x73, 0x75, 0x70, 0x70, - 0x6c, 0x79, 0x69, 0x6e, 0x67, 0x20, 0x61, 0x20, 0x73, 0x79, 0x6e, 0x63, 0x20, 0x70, 0x61, 0x79, - 0x6c, 0x6f, 0x61, 0x64, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x73, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, - 0x72, 0x65, 0x70, 0x6c, 0x79, 0x0a, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x04, 0x01, 0x12, 0x03, 0x5b, - 0x08, 0x17, 0x0a, 0x4f, 0x0a, 0x04, 0x04, 0x04, 0x02, 0x00, 0x12, 0x03, 0x5d, 0x02, 0x18, 0x1a, - 0x42, 0x20, 0x4d, 0x75, 0x73, 0x74, 0x20, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x20, 0x61, 0x6e, 0x20, - 0x65, 0x78, 0x69, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x20, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x5f, 0x69, 0x64, 0x20, 0x66, 0x72, 0x6f, 0x6d, 0x20, 0x61, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x20, 0x68, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x20, 0x72, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x02, 0x00, 0x05, 0x12, 0x03, 0x5d, 0x02, - 0x08, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x02, 0x00, 0x01, 0x12, 0x03, 0x5d, 0x09, 0x13, 0x0a, - 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x02, 0x00, 0x03, 0x12, 0x03, 0x5d, 0x16, 0x17, 0x0a, 0x37, 0x0a, - 0x04, 0x04, 0x04, 0x02, 0x01, 0x12, 0x03, 0x5f, 0x02, 0x11, 0x1a, 0x2a, 0x20, 0x57, 0x68, 0x65, - 0x72, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x20, - 0x63, 0x61, 0x6e, 0x20, 0x62, 0x65, 0x20, 0x72, 0x65, 0x74, 0x72, 0x69, 0x65, 0x76, 0x65, 0x64, - 0x20, 0x66, 0x72, 0x6f, 0x6d, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x02, 0x01, 0x05, 0x12, - 0x03, 0x5f, 0x02, 0x08, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x02, 0x01, 0x01, 0x12, 0x03, 0x5f, - 0x09, 0x0c, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x02, 0x01, 0x03, 0x12, 0x03, 0x5f, 0x0f, 0x10, - 0x0a, 0x5a, 0x0a, 0x04, 0x04, 0x04, 0x02, 0x02, 0x12, 0x03, 0x61, 0x02, 0x27, 0x1a, 0x4d, 0x20, - 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x20, - 0x27, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x27, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x74, 0x68, 0x65, - 0x20, 0x41, 0x45, 0x53, 0x20, 0x4b, 0x65, 0x79, 0x20, 0x75, 0x73, 0x65, 0x64, 0x20, 0x74, 0x6f, - 0x20, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x2d, 0x62, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, - 0x04, 0x04, 0x02, 0x02, 0x06, 0x12, 0x03, 0x61, 0x02, 0x13, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, - 0x02, 0x02, 0x01, 0x12, 0x03, 0x61, 0x14, 0x22, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x02, 0x02, - 0x03, 0x12, 0x03, 0x61, 0x25, 0x26, 0x0a, 0x3b, 0x0a, 0x04, 0x04, 0x04, 0x02, 0x03, 0x12, 0x03, - 0x63, 0x02, 0x1a, 0x1a, 0x2e, 0x20, 0x6e, 0x73, 0x20, 0x75, 0x6e, 0x69, 0x78, 0x20, 0x74, 0x69, - 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x20, 0x6f, 0x66, 0x20, 0x77, 0x68, 0x65, 0x6e, 0x20, - 0x74, 0x68, 0x65, 0x20, 0x72, 0x65, 0x70, 0x6c, 0x79, 0x20, 0x77, 0x61, 0x73, 0x20, 0x73, 0x65, - 0x6e, 0x74, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x02, 0x03, 0x05, 0x12, 0x03, 0x63, 0x02, - 0x08, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x02, 0x03, 0x01, 0x12, 0x03, 0x63, 0x09, 0x15, 0x0a, - 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x02, 0x03, 0x03, 0x12, 0x03, 0x63, 0x18, 0x19, 0x0a, 0x1b, 0x0a, - 0x04, 0x04, 0x04, 0x02, 0x04, 0x12, 0x03, 0x65, 0x02, 0x1a, 0x1a, 0x0e, 0x20, 0x72, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x20, 0x6b, 0x69, 0x6e, 0x64, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, - 0x02, 0x04, 0x06, 0x12, 0x03, 0x65, 0x02, 0x10, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x02, 0x04, - 0x01, 0x12, 0x03, 0x65, 0x11, 0x15, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x02, 0x04, 0x03, 0x12, - 0x03, 0x65, 0x18, 0x19, 0x0a, 0x34, 0x0a, 0x02, 0x04, 0x05, 0x12, 0x04, 0x69, 0x00, 0x6d, 0x01, - 0x1a, 0x28, 0x20, 0x4b, 0x65, 0x79, 0x20, 0x75, 0x73, 0x65, 0x64, 0x20, 0x74, 0x6f, 0x20, 0x65, + 0x20, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x20, 0x61, 0x20, 0x73, 0x79, + 0x6e, 0x63, 0x20, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20, + 0x61, 0x20, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x0a, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x03, + 0x01, 0x12, 0x03, 0x51, 0x08, 0x19, 0x0a, 0x31, 0x0a, 0x04, 0x04, 0x03, 0x02, 0x00, 0x12, 0x03, + 0x53, 0x02, 0x18, 0x1a, 0x24, 0x20, 0x55, 0x6e, 0x69, 0x71, 0x75, 0x65, 0x20, 0x69, 0x64, 0x65, + 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x65, 0x61, 0x63, 0x68, + 0x20, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, + 0x00, 0x05, 0x12, 0x03, 0x53, 0x02, 0x08, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, 0x00, 0x01, + 0x12, 0x03, 0x53, 0x09, 0x13, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, 0x00, 0x03, 0x12, 0x03, + 0x53, 0x16, 0x17, 0x0a, 0x2d, 0x0a, 0x04, 0x04, 0x03, 0x02, 0x01, 0x12, 0x03, 0x55, 0x02, 0x16, + 0x1a, 0x20, 0x20, 0x45, 0x6e, 0x73, 0x75, 0x72, 0x65, 0x73, 0x20, 0x61, 0x20, 0x68, 0x75, 0x6d, + 0x61, 0x6e, 0x20, 0x69, 0x73, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6c, 0x6f, 0x6f, + 0x70, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, 0x01, 0x05, 0x12, 0x03, 0x55, 0x02, 0x08, + 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, 0x01, 0x01, 0x12, 0x03, 0x55, 0x09, 0x11, 0x0a, 0x0c, + 0x0a, 0x05, 0x04, 0x03, 0x02, 0x01, 0x03, 0x12, 0x03, 0x55, 0x14, 0x15, 0x0a, 0x1b, 0x0a, 0x04, + 0x04, 0x03, 0x02, 0x02, 0x12, 0x03, 0x57, 0x02, 0x1a, 0x1a, 0x0e, 0x20, 0x72, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x20, 0x6b, 0x69, 0x6e, 0x64, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, + 0x02, 0x06, 0x12, 0x03, 0x57, 0x02, 0x10, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, 0x02, 0x01, + 0x12, 0x03, 0x57, 0x11, 0x15, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, 0x02, 0x03, 0x12, 0x03, + 0x57, 0x18, 0x19, 0x0a, 0x5f, 0x0a, 0x02, 0x04, 0x04, 0x12, 0x04, 0x5b, 0x00, 0x66, 0x01, 0x1a, + 0x53, 0x20, 0x50, 0x72, 0x65, 0x2d, 0x65, 0x78, 0x69, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x20, 0x69, + 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x69, 0x64, 0x20, 0x63, + 0x61, 0x70, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x73, 0x75, 0x70, 0x70, 0x6c, 0x79, + 0x69, 0x6e, 0x67, 0x20, 0x61, 0x20, 0x73, 0x79, 0x6e, 0x63, 0x20, 0x70, 0x61, 0x79, 0x6c, 0x6f, + 0x61, 0x64, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x73, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x72, 0x65, + 0x70, 0x6c, 0x79, 0x0a, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x04, 0x01, 0x12, 0x03, 0x5b, 0x08, 0x17, + 0x0a, 0x4f, 0x0a, 0x04, 0x04, 0x04, 0x02, 0x00, 0x12, 0x03, 0x5d, 0x02, 0x18, 0x1a, 0x42, 0x20, + 0x4d, 0x75, 0x73, 0x74, 0x20, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x20, 0x61, 0x6e, 0x20, 0x65, 0x78, + 0x69, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x20, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x69, + 0x64, 0x20, 0x66, 0x72, 0x6f, 0x6d, 0x20, 0x61, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x20, 0x68, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x20, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x02, 0x00, 0x05, 0x12, 0x03, 0x5d, 0x02, 0x08, 0x0a, + 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x02, 0x00, 0x01, 0x12, 0x03, 0x5d, 0x09, 0x13, 0x0a, 0x0c, 0x0a, + 0x05, 0x04, 0x04, 0x02, 0x00, 0x03, 0x12, 0x03, 0x5d, 0x16, 0x17, 0x0a, 0x37, 0x0a, 0x04, 0x04, + 0x04, 0x02, 0x01, 0x12, 0x03, 0x5f, 0x02, 0x11, 0x1a, 0x2a, 0x20, 0x57, 0x68, 0x65, 0x72, 0x65, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x20, 0x63, 0x61, + 0x6e, 0x20, 0x62, 0x65, 0x20, 0x72, 0x65, 0x74, 0x72, 0x69, 0x65, 0x76, 0x65, 0x64, 0x20, 0x66, + 0x72, 0x6f, 0x6d, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x02, 0x01, 0x05, 0x12, 0x03, 0x5f, + 0x02, 0x08, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x02, 0x01, 0x01, 0x12, 0x03, 0x5f, 0x09, 0x0c, + 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x02, 0x01, 0x03, 0x12, 0x03, 0x5f, 0x0f, 0x10, 0x0a, 0x5a, + 0x0a, 0x04, 0x04, 0x04, 0x02, 0x02, 0x12, 0x03, 0x61, 0x02, 0x27, 0x1a, 0x4d, 0x20, 0x47, 0x65, + 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x20, 0x27, 0x73, + 0x65, 0x63, 0x72, 0x65, 0x74, 0x27, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x74, 0x68, 0x65, 0x20, 0x41, + 0x45, 0x53, 0x20, 0x4b, 0x65, 0x79, 0x20, 0x75, 0x73, 0x65, 0x64, 0x20, 0x74, 0x6f, 0x20, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x2d, 0x62, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x0a, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x05, - 0x01, 0x12, 0x03, 0x69, 0x08, 0x19, 0x0a, 0x0c, 0x0a, 0x04, 0x04, 0x05, 0x08, 0x00, 0x12, 0x04, - 0x6a, 0x02, 0x6c, 0x03, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x05, 0x08, 0x00, 0x01, 0x12, 0x03, 0x6a, - 0x08, 0x0b, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x05, 0x02, 0x00, 0x12, 0x03, 0x6b, 0x04, 0x1a, 0x0a, - 0x0c, 0x0a, 0x05, 0x04, 0x05, 0x02, 0x00, 0x05, 0x12, 0x03, 0x6b, 0x04, 0x09, 0x0a, 0x0c, 0x0a, - 0x05, 0x04, 0x05, 0x02, 0x00, 0x01, 0x12, 0x03, 0x6b, 0x0a, 0x15, 0x0a, 0x0c, 0x0a, 0x05, 0x04, - 0x05, 0x02, 0x00, 0x03, 0x12, 0x03, 0x6b, 0x18, 0x19, 0x0a, 0x38, 0x0a, 0x02, 0x05, 0x01, 0x12, - 0x04, 0x70, 0x00, 0x74, 0x01, 0x1a, 0x2c, 0x20, 0x54, 0x68, 0x65, 0x20, 0x6b, 0x69, 0x6e, 0x64, - 0x20, 0x6f, 0x66, 0x20, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x20, 0x73, 0x79, 0x6e, 0x63, 0x20, - 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x20, 0x62, 0x65, 0x69, 0x6e, 0x67, 0x20, 0x73, 0x65, - 0x6e, 0x74, 0x0a, 0x0a, 0x0a, 0x0a, 0x03, 0x05, 0x01, 0x01, 0x12, 0x03, 0x70, 0x05, 0x13, 0x0a, - 0x0b, 0x0a, 0x04, 0x05, 0x01, 0x02, 0x00, 0x12, 0x03, 0x71, 0x02, 0x23, 0x0a, 0x0c, 0x0a, 0x05, - 0x05, 0x01, 0x02, 0x00, 0x01, 0x12, 0x03, 0x71, 0x02, 0x1e, 0x0a, 0x0c, 0x0a, 0x05, 0x05, 0x01, - 0x02, 0x00, 0x02, 0x12, 0x03, 0x71, 0x21, 0x22, 0x0a, 0x0b, 0x0a, 0x04, 0x05, 0x01, 0x02, 0x01, - 0x12, 0x03, 0x72, 0x02, 0x27, 0x0a, 0x0c, 0x0a, 0x05, 0x05, 0x01, 0x02, 0x01, 0x01, 0x12, 0x03, - 0x72, 0x02, 0x22, 0x0a, 0x0c, 0x0a, 0x05, 0x05, 0x01, 0x02, 0x01, 0x02, 0x12, 0x03, 0x72, 0x25, - 0x26, 0x0a, 0x0b, 0x0a, 0x04, 0x05, 0x01, 0x02, 0x02, 0x12, 0x03, 0x73, 0x02, 0x1f, 0x0a, 0x0c, - 0x0a, 0x05, 0x05, 0x01, 0x02, 0x02, 0x01, 0x12, 0x03, 0x73, 0x02, 0x1a, 0x0a, 0x0c, 0x0a, 0x05, - 0x05, 0x01, 0x02, 0x02, 0x02, 0x12, 0x03, 0x73, 0x1d, 0x1e, 0x0a, 0x27, 0x0a, 0x02, 0x04, 0x06, - 0x12, 0x04, 0x77, 0x00, 0x7b, 0x01, 0x1a, 0x1b, 0x20, 0x41, 0x20, 0x73, 0x74, 0x72, 0x65, 0x61, - 0x6d, 0x65, 0x64, 0x20, 0x63, 0x6f, 0x6e, 0x73, 0x65, 0x6e, 0x74, 0x20, 0x75, 0x70, 0x64, 0x61, - 0x74, 0x65, 0x0a, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x06, 0x01, 0x12, 0x03, 0x77, 0x08, 0x15, 0x0a, - 0x0b, 0x0a, 0x04, 0x04, 0x06, 0x02, 0x00, 0x12, 0x03, 0x78, 0x02, 0x24, 0x0a, 0x0c, 0x0a, 0x05, - 0x04, 0x06, 0x02, 0x00, 0x06, 0x12, 0x03, 0x78, 0x02, 0x13, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x06, - 0x02, 0x00, 0x01, 0x12, 0x03, 0x78, 0x14, 0x1f, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x06, 0x02, 0x00, - 0x03, 0x12, 0x03, 0x78, 0x22, 0x23, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x06, 0x02, 0x01, 0x12, 0x03, - 0x79, 0x02, 0x19, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x06, 0x02, 0x01, 0x06, 0x12, 0x03, 0x79, 0x02, - 0x0e, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x06, 0x02, 0x01, 0x01, 0x12, 0x03, 0x79, 0x0f, 0x14, 0x0a, - 0x0c, 0x0a, 0x05, 0x04, 0x06, 0x02, 0x01, 0x03, 0x12, 0x03, 0x79, 0x17, 0x18, 0x0a, 0x0b, 0x0a, - 0x04, 0x04, 0x06, 0x02, 0x02, 0x12, 0x03, 0x7a, 0x02, 0x14, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x06, - 0x02, 0x02, 0x05, 0x12, 0x03, 0x7a, 0x02, 0x08, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x06, 0x02, 0x02, - 0x01, 0x12, 0x03, 0x7a, 0x09, 0x0f, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x06, 0x02, 0x02, 0x03, 0x12, - 0x03, 0x7a, 0x12, 0x13, 0x0a, 0x3b, 0x0a, 0x02, 0x05, 0x02, 0x12, 0x05, 0x7e, 0x00, 0x83, 0x01, - 0x01, 0x1a, 0x2e, 0x20, 0x54, 0x68, 0x65, 0x20, 0x74, 0x79, 0x70, 0x65, 0x20, 0x6f, 0x66, 0x20, - 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x20, 0x74, 0x68, 0x65, 0x20, 0x75, 0x73, 0x65, 0x72, 0x20, - 0x69, 0x73, 0x20, 0x63, 0x6f, 0x6e, 0x73, 0x65, 0x6e, 0x74, 0x69, 0x6e, 0x67, 0x20, 0x74, 0x6f, - 0x0a, 0x0a, 0x0a, 0x0a, 0x03, 0x05, 0x02, 0x01, 0x12, 0x03, 0x7e, 0x05, 0x16, 0x0a, 0x0b, 0x0a, - 0x04, 0x05, 0x02, 0x02, 0x00, 0x12, 0x03, 0x7f, 0x02, 0x26, 0x0a, 0x0c, 0x0a, 0x05, 0x05, 0x02, - 0x02, 0x00, 0x01, 0x12, 0x03, 0x7f, 0x02, 0x21, 0x0a, 0x0c, 0x0a, 0x05, 0x05, 0x02, 0x02, 0x00, - 0x02, 0x12, 0x03, 0x7f, 0x24, 0x25, 0x0a, 0x0c, 0x0a, 0x04, 0x05, 0x02, 0x02, 0x01, 0x12, 0x04, - 0x80, 0x01, 0x02, 0x2a, 0x0a, 0x0d, 0x0a, 0x05, 0x05, 0x02, 0x02, 0x01, 0x01, 0x12, 0x04, 0x80, - 0x01, 0x02, 0x25, 0x0a, 0x0d, 0x0a, 0x05, 0x05, 0x02, 0x02, 0x01, 0x02, 0x12, 0x04, 0x80, 0x01, - 0x28, 0x29, 0x0a, 0x0c, 0x0a, 0x04, 0x05, 0x02, 0x02, 0x02, 0x12, 0x04, 0x81, 0x01, 0x02, 0x23, - 0x0a, 0x0d, 0x0a, 0x05, 0x05, 0x02, 0x02, 0x02, 0x01, 0x12, 0x04, 0x81, 0x01, 0x02, 0x1e, 0x0a, - 0x0d, 0x0a, 0x05, 0x05, 0x02, 0x02, 0x02, 0x02, 0x12, 0x04, 0x81, 0x01, 0x21, 0x22, 0x0a, 0x0c, - 0x0a, 0x04, 0x05, 0x02, 0x02, 0x03, 0x12, 0x04, 0x82, 0x01, 0x02, 0x22, 0x0a, 0x0d, 0x0a, 0x05, - 0x05, 0x02, 0x02, 0x03, 0x01, 0x12, 0x04, 0x82, 0x01, 0x02, 0x1d, 0x0a, 0x0d, 0x0a, 0x05, 0x05, - 0x02, 0x02, 0x03, 0x02, 0x12, 0x04, 0x82, 0x01, 0x20, 0x21, 0x0a, 0x2a, 0x0a, 0x02, 0x05, 0x03, - 0x12, 0x06, 0x86, 0x01, 0x00, 0x8a, 0x01, 0x01, 0x1a, 0x1c, 0x20, 0x50, 0x6f, 0x73, 0x73, 0x69, - 0x62, 0x6c, 0x65, 0x20, 0x73, 0x74, 0x61, 0x74, 0x65, 0x73, 0x20, 0x6f, 0x66, 0x20, 0x63, 0x6f, - 0x6e, 0x73, 0x65, 0x6e, 0x74, 0x0a, 0x0a, 0x0b, 0x0a, 0x03, 0x05, 0x03, 0x01, 0x12, 0x04, 0x86, - 0x01, 0x05, 0x11, 0x0a, 0x0c, 0x0a, 0x04, 0x05, 0x03, 0x02, 0x00, 0x12, 0x04, 0x87, 0x01, 0x02, - 0x20, 0x0a, 0x0d, 0x0a, 0x05, 0x05, 0x03, 0x02, 0x00, 0x01, 0x12, 0x04, 0x87, 0x01, 0x02, 0x1b, - 0x0a, 0x0d, 0x0a, 0x05, 0x05, 0x03, 0x02, 0x00, 0x02, 0x12, 0x04, 0x87, 0x01, 0x1e, 0x1f, 0x0a, - 0x0c, 0x0a, 0x04, 0x05, 0x03, 0x02, 0x01, 0x12, 0x04, 0x88, 0x01, 0x02, 0x1c, 0x0a, 0x0d, 0x0a, - 0x05, 0x05, 0x03, 0x02, 0x01, 0x01, 0x12, 0x04, 0x88, 0x01, 0x02, 0x17, 0x0a, 0x0d, 0x0a, 0x05, - 0x05, 0x03, 0x02, 0x01, 0x02, 0x12, 0x04, 0x88, 0x01, 0x1a, 0x1b, 0x0a, 0x0c, 0x0a, 0x04, 0x05, - 0x03, 0x02, 0x02, 0x12, 0x04, 0x89, 0x01, 0x02, 0x1b, 0x0a, 0x0d, 0x0a, 0x05, 0x05, 0x03, 0x02, - 0x02, 0x01, 0x12, 0x04, 0x89, 0x01, 0x02, 0x16, 0x0a, 0x0d, 0x0a, 0x05, 0x05, 0x03, 0x02, 0x02, - 0x02, 0x12, 0x04, 0x89, 0x01, 0x19, 0x1a, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, 0x0a, + 0x67, 0x65, 0x2d, 0x62, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, + 0x02, 0x02, 0x06, 0x12, 0x03, 0x61, 0x02, 0x13, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x02, 0x02, + 0x01, 0x12, 0x03, 0x61, 0x14, 0x22, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x02, 0x02, 0x03, 0x12, + 0x03, 0x61, 0x25, 0x26, 0x0a, 0x3b, 0x0a, 0x04, 0x04, 0x04, 0x02, 0x03, 0x12, 0x03, 0x63, 0x02, + 0x1a, 0x1a, 0x2e, 0x20, 0x6e, 0x73, 0x20, 0x75, 0x6e, 0x69, 0x78, 0x20, 0x74, 0x69, 0x6d, 0x65, + 0x73, 0x74, 0x61, 0x6d, 0x70, 0x20, 0x6f, 0x66, 0x20, 0x77, 0x68, 0x65, 0x6e, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x72, 0x65, 0x70, 0x6c, 0x79, 0x20, 0x77, 0x61, 0x73, 0x20, 0x73, 0x65, 0x6e, 0x74, + 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x02, 0x03, 0x05, 0x12, 0x03, 0x63, 0x02, 0x08, 0x0a, + 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x02, 0x03, 0x01, 0x12, 0x03, 0x63, 0x09, 0x15, 0x0a, 0x0c, 0x0a, + 0x05, 0x04, 0x04, 0x02, 0x03, 0x03, 0x12, 0x03, 0x63, 0x18, 0x19, 0x0a, 0x1b, 0x0a, 0x04, 0x04, + 0x04, 0x02, 0x04, 0x12, 0x03, 0x65, 0x02, 0x1a, 0x1a, 0x0e, 0x20, 0x72, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x20, 0x6b, 0x69, 0x6e, 0x64, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x02, 0x04, + 0x06, 0x12, 0x03, 0x65, 0x02, 0x10, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x02, 0x04, 0x01, 0x12, + 0x03, 0x65, 0x11, 0x15, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x02, 0x04, 0x03, 0x12, 0x03, 0x65, + 0x18, 0x19, 0x0a, 0x34, 0x0a, 0x02, 0x04, 0x05, 0x12, 0x04, 0x69, 0x00, 0x6d, 0x01, 0x1a, 0x28, + 0x20, 0x4b, 0x65, 0x79, 0x20, 0x75, 0x73, 0x65, 0x64, 0x20, 0x74, 0x6f, 0x20, 0x65, 0x6e, 0x63, + 0x72, 0x79, 0x70, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x2d, 0x62, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x0a, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x05, 0x01, 0x12, + 0x03, 0x69, 0x08, 0x19, 0x0a, 0x0c, 0x0a, 0x04, 0x04, 0x05, 0x08, 0x00, 0x12, 0x04, 0x6a, 0x02, + 0x6c, 0x03, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x05, 0x08, 0x00, 0x01, 0x12, 0x03, 0x6a, 0x08, 0x0b, + 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x05, 0x02, 0x00, 0x12, 0x03, 0x6b, 0x04, 0x1a, 0x0a, 0x0c, 0x0a, + 0x05, 0x04, 0x05, 0x02, 0x00, 0x05, 0x12, 0x03, 0x6b, 0x04, 0x09, 0x0a, 0x0c, 0x0a, 0x05, 0x04, + 0x05, 0x02, 0x00, 0x01, 0x12, 0x03, 0x6b, 0x0a, 0x15, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x05, 0x02, + 0x00, 0x03, 0x12, 0x03, 0x6b, 0x18, 0x19, 0x0a, 0x38, 0x0a, 0x02, 0x05, 0x01, 0x12, 0x04, 0x70, + 0x00, 0x74, 0x01, 0x1a, 0x2c, 0x20, 0x54, 0x68, 0x65, 0x20, 0x6b, 0x69, 0x6e, 0x64, 0x20, 0x6f, + 0x66, 0x20, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x20, 0x73, 0x79, 0x6e, 0x63, 0x20, 0x70, 0x61, + 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x20, 0x62, 0x65, 0x69, 0x6e, 0x67, 0x20, 0x73, 0x65, 0x6e, 0x74, + 0x0a, 0x0a, 0x0a, 0x0a, 0x03, 0x05, 0x01, 0x01, 0x12, 0x03, 0x70, 0x05, 0x13, 0x0a, 0x0b, 0x0a, + 0x04, 0x05, 0x01, 0x02, 0x00, 0x12, 0x03, 0x71, 0x02, 0x23, 0x0a, 0x0c, 0x0a, 0x05, 0x05, 0x01, + 0x02, 0x00, 0x01, 0x12, 0x03, 0x71, 0x02, 0x1e, 0x0a, 0x0c, 0x0a, 0x05, 0x05, 0x01, 0x02, 0x00, + 0x02, 0x12, 0x03, 0x71, 0x21, 0x22, 0x0a, 0x0b, 0x0a, 0x04, 0x05, 0x01, 0x02, 0x01, 0x12, 0x03, + 0x72, 0x02, 0x27, 0x0a, 0x0c, 0x0a, 0x05, 0x05, 0x01, 0x02, 0x01, 0x01, 0x12, 0x03, 0x72, 0x02, + 0x22, 0x0a, 0x0c, 0x0a, 0x05, 0x05, 0x01, 0x02, 0x01, 0x02, 0x12, 0x03, 0x72, 0x25, 0x26, 0x0a, + 0x0b, 0x0a, 0x04, 0x05, 0x01, 0x02, 0x02, 0x12, 0x03, 0x73, 0x02, 0x1f, 0x0a, 0x0c, 0x0a, 0x05, + 0x05, 0x01, 0x02, 0x02, 0x01, 0x12, 0x03, 0x73, 0x02, 0x1a, 0x0a, 0x0c, 0x0a, 0x05, 0x05, 0x01, + 0x02, 0x02, 0x02, 0x12, 0x03, 0x73, 0x1d, 0x1e, 0x0a, 0x0a, 0x0a, 0x02, 0x04, 0x06, 0x12, 0x04, + 0x76, 0x00, 0x78, 0x01, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x06, 0x01, 0x12, 0x03, 0x76, 0x08, 0x1c, + 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x06, 0x02, 0x00, 0x12, 0x03, 0x77, 0x02, 0x14, 0x0a, 0x0c, 0x0a, + 0x05, 0x04, 0x06, 0x02, 0x00, 0x05, 0x12, 0x03, 0x77, 0x02, 0x07, 0x0a, 0x0c, 0x0a, 0x05, 0x04, + 0x06, 0x02, 0x00, 0x01, 0x12, 0x03, 0x77, 0x08, 0x0f, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x06, 0x02, + 0x00, 0x03, 0x12, 0x03, 0x77, 0x12, 0x13, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, 0x0a, 0x90, 0x06, 0x0a, 0x2b, 0x6d, 0x6c, 0x73, 0x2f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2f, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x5f, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, diff --git a/xmtp_proto/src/gen/xmtp.mls.message_contents.serde.rs b/xmtp_proto/src/gen/xmtp.mls.message_contents.serde.rs index 97bee139c..cfda67548 100644 --- a/xmtp_proto/src/gen/xmtp.mls.message_contents.serde.rs +++ b/xmtp_proto/src/gen/xmtp.mls.message_contents.serde.rs @@ -70,287 +70,6 @@ impl<'de> serde::Deserialize<'de> for Compression { deserializer.deserialize_any(GeneratedVisitor) } } -impl serde::Serialize for ConsentEntityType { - #[allow(deprecated)] - fn serialize(&self, serializer: S) -> std::result::Result - where - S: serde::Serializer, - { - let variant = match self { - Self::Unspecified => "CONSENT_ENTITY_TYPE_UNSPECIFIED", - Self::ConversationId => "CONSENT_ENTITY_TYPE_CONVERSATION_ID", - Self::InboxId => "CONSENT_ENTITY_TYPE_INBOX_ID", - Self::Address => "CONSENT_ENTITY_TYPE_ADDRESS", - }; - serializer.serialize_str(variant) - } -} -impl<'de> serde::Deserialize<'de> for ConsentEntityType { - #[allow(deprecated)] - fn deserialize(deserializer: D) -> std::result::Result - where - D: serde::Deserializer<'de>, - { - const FIELDS: &[&str] = &[ - "CONSENT_ENTITY_TYPE_UNSPECIFIED", - "CONSENT_ENTITY_TYPE_CONVERSATION_ID", - "CONSENT_ENTITY_TYPE_INBOX_ID", - "CONSENT_ENTITY_TYPE_ADDRESS", - ]; - - struct GeneratedVisitor; - - impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { - type Value = ConsentEntityType; - - fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(formatter, "expected one of: {:?}", &FIELDS) - } - - fn visit_i64(self, v: i64) -> std::result::Result - where - E: serde::de::Error, - { - i32::try_from(v) - .ok() - .and_then(|x| x.try_into().ok()) - .ok_or_else(|| { - serde::de::Error::invalid_value(serde::de::Unexpected::Signed(v), &self) - }) - } - - fn visit_u64(self, v: u64) -> std::result::Result - where - E: serde::de::Error, - { - i32::try_from(v) - .ok() - .and_then(|x| x.try_into().ok()) - .ok_or_else(|| { - serde::de::Error::invalid_value(serde::de::Unexpected::Unsigned(v), &self) - }) - } - - fn visit_str(self, value: &str) -> std::result::Result - where - E: serde::de::Error, - { - match value { - "CONSENT_ENTITY_TYPE_UNSPECIFIED" => Ok(ConsentEntityType::Unspecified), - "CONSENT_ENTITY_TYPE_CONVERSATION_ID" => Ok(ConsentEntityType::ConversationId), - "CONSENT_ENTITY_TYPE_INBOX_ID" => Ok(ConsentEntityType::InboxId), - "CONSENT_ENTITY_TYPE_ADDRESS" => Ok(ConsentEntityType::Address), - _ => Err(serde::de::Error::unknown_variant(value, FIELDS)), - } - } - } - deserializer.deserialize_any(GeneratedVisitor) - } -} -impl serde::Serialize for ConsentState { - #[allow(deprecated)] - fn serialize(&self, serializer: S) -> std::result::Result - where - S: serde::Serializer, - { - let variant = match self { - Self::Unspecified => "CONSENT_STATE_UNSPECIFIED", - Self::Allowed => "CONSENT_STATE_ALLOWED", - Self::Denied => "CONSENT_STATE_DENIED", - }; - serializer.serialize_str(variant) - } -} -impl<'de> serde::Deserialize<'de> for ConsentState { - #[allow(deprecated)] - fn deserialize(deserializer: D) -> std::result::Result - where - D: serde::Deserializer<'de>, - { - const FIELDS: &[&str] = &[ - "CONSENT_STATE_UNSPECIFIED", - "CONSENT_STATE_ALLOWED", - "CONSENT_STATE_DENIED", - ]; - - struct GeneratedVisitor; - - impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { - type Value = ConsentState; - - fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(formatter, "expected one of: {:?}", &FIELDS) - } - - fn visit_i64(self, v: i64) -> std::result::Result - where - E: serde::de::Error, - { - i32::try_from(v) - .ok() - .and_then(|x| x.try_into().ok()) - .ok_or_else(|| { - serde::de::Error::invalid_value(serde::de::Unexpected::Signed(v), &self) - }) - } - - fn visit_u64(self, v: u64) -> std::result::Result - where - E: serde::de::Error, - { - i32::try_from(v) - .ok() - .and_then(|x| x.try_into().ok()) - .ok_or_else(|| { - serde::de::Error::invalid_value(serde::de::Unexpected::Unsigned(v), &self) - }) - } - - fn visit_str(self, value: &str) -> std::result::Result - where - E: serde::de::Error, - { - match value { - "CONSENT_STATE_UNSPECIFIED" => Ok(ConsentState::Unspecified), - "CONSENT_STATE_ALLOWED" => Ok(ConsentState::Allowed), - "CONSENT_STATE_DENIED" => Ok(ConsentState::Denied), - _ => Err(serde::de::Error::unknown_variant(value, FIELDS)), - } - } - } - deserializer.deserialize_any(GeneratedVisitor) - } -} -impl serde::Serialize for ConsentUpdate { - #[allow(deprecated)] - fn serialize(&self, serializer: S) -> std::result::Result - where - S: serde::Serializer, - { - use serde::ser::SerializeStruct; - let mut len = 0; - if self.entity_type != 0 { - len += 1; - } - if self.state != 0 { - len += 1; - } - if !self.entity.is_empty() { - len += 1; - } - let mut struct_ser = serializer.serialize_struct("xmtp.mls.message_contents.ConsentUpdate", len)?; - if self.entity_type != 0 { - let v = ConsentEntityType::try_from(self.entity_type) - .map_err(|_| serde::ser::Error::custom(format!("Invalid variant {}", self.entity_type)))?; - struct_ser.serialize_field("entityType", &v)?; - } - if self.state != 0 { - let v = ConsentState::try_from(self.state) - .map_err(|_| serde::ser::Error::custom(format!("Invalid variant {}", self.state)))?; - struct_ser.serialize_field("state", &v)?; - } - if !self.entity.is_empty() { - struct_ser.serialize_field("entity", &self.entity)?; - } - struct_ser.end() - } -} -impl<'de> serde::Deserialize<'de> for ConsentUpdate { - #[allow(deprecated)] - fn deserialize(deserializer: D) -> std::result::Result - where - D: serde::Deserializer<'de>, - { - const FIELDS: &[&str] = &[ - "entity_type", - "entityType", - "state", - "entity", - ]; - - #[allow(clippy::enum_variant_names)] - enum GeneratedField { - EntityType, - State, - Entity, - } - 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 { - "entityType" | "entity_type" => Ok(GeneratedField::EntityType), - "state" => Ok(GeneratedField::State), - "entity" => Ok(GeneratedField::Entity), - _ => Err(serde::de::Error::unknown_field(value, FIELDS)), - } - } - } - deserializer.deserialize_identifier(GeneratedVisitor) - } - } - struct GeneratedVisitor; - impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { - type Value = ConsentUpdate; - - fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - formatter.write_str("struct xmtp.mls.message_contents.ConsentUpdate") - } - - fn visit_map(self, mut map_: V) -> std::result::Result - where - V: serde::de::MapAccess<'de>, - { - let mut entity_type__ = None; - let mut state__ = None; - let mut entity__ = None; - while let Some(k) = map_.next_key()? { - match k { - GeneratedField::EntityType => { - if entity_type__.is_some() { - return Err(serde::de::Error::duplicate_field("entityType")); - } - entity_type__ = Some(map_.next_value::()? as i32); - } - GeneratedField::State => { - if state__.is_some() { - return Err(serde::de::Error::duplicate_field("state")); - } - state__ = Some(map_.next_value::()? as i32); - } - GeneratedField::Entity => { - if entity__.is_some() { - return Err(serde::de::Error::duplicate_field("entity")); - } - entity__ = Some(map_.next_value()?); - } - } - } - Ok(ConsentUpdate { - entity_type: entity_type__.unwrap_or_default(), - state: state__.unwrap_or_default(), - entity: entity__.unwrap_or_default(), - }) - } - } - deserializer.deserialize_struct("xmtp.mls.message_contents.ConsentUpdate", FIELDS, GeneratedVisitor) - } -} impl serde::Serialize for ContentTypeId { #[allow(deprecated)] fn serialize(&self, serializer: S) -> std::result::Result @@ -4026,8 +3745,8 @@ impl serde::Serialize for plaintext_envelope::V2 { plaintext_envelope::v2::MessageType::DeviceSyncReply(v) => { struct_ser.serialize_field("deviceSyncReply", v)?; } - plaintext_envelope::v2::MessageType::ConsentUpdate(v) => { - struct_ser.serialize_field("consentUpdate", v)?; + plaintext_envelope::v2::MessageType::UserPreferenceUpdate(v) => { + struct_ser.serialize_field("userPreferenceUpdate", v)?; } } } @@ -4048,8 +3767,8 @@ impl<'de> serde::Deserialize<'de> for plaintext_envelope::V2 { "deviceSyncRequest", "device_sync_reply", "deviceSyncReply", - "consent_update", - "consentUpdate", + "user_preference_update", + "userPreferenceUpdate", ]; #[allow(clippy::enum_variant_names)] @@ -4058,7 +3777,7 @@ impl<'de> serde::Deserialize<'de> for plaintext_envelope::V2 { Content, DeviceSyncRequest, DeviceSyncReply, - ConsentUpdate, + UserPreferenceUpdate, } impl<'de> serde::Deserialize<'de> for GeneratedField { fn deserialize(deserializer: D) -> std::result::Result @@ -4084,7 +3803,7 @@ impl<'de> serde::Deserialize<'de> for plaintext_envelope::V2 { "content" => Ok(GeneratedField::Content), "deviceSyncRequest" | "device_sync_request" => Ok(GeneratedField::DeviceSyncRequest), "deviceSyncReply" | "device_sync_reply" => Ok(GeneratedField::DeviceSyncReply), - "consentUpdate" | "consent_update" => Ok(GeneratedField::ConsentUpdate), + "userPreferenceUpdate" | "user_preference_update" => Ok(GeneratedField::UserPreferenceUpdate), _ => Err(serde::de::Error::unknown_field(value, FIELDS)), } } @@ -4134,11 +3853,11 @@ impl<'de> serde::Deserialize<'de> for plaintext_envelope::V2 { message_type__ = map_.next_value::<::std::option::Option<_>>()?.map(plaintext_envelope::v2::MessageType::DeviceSyncReply) ; } - GeneratedField::ConsentUpdate => { + GeneratedField::UserPreferenceUpdate => { if message_type__.is_some() { - return Err(serde::de::Error::duplicate_field("consentUpdate")); + return Err(serde::de::Error::duplicate_field("userPreferenceUpdate")); } - message_type__ = map_.next_value::<::std::option::Option<_>>()?.map(plaintext_envelope::v2::MessageType::ConsentUpdate) + message_type__ = map_.next_value::<::std::option::Option<_>>()?.map(plaintext_envelope::v2::MessageType::UserPreferenceUpdate) ; } } @@ -4336,3 +4055,98 @@ impl<'de> serde::Deserialize<'de> for PolicySet { deserializer.deserialize_struct("xmtp.mls.message_contents.PolicySet", FIELDS, GeneratedVisitor) } } +impl serde::Serialize for UserPreferenceUpdate { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + use serde::ser::SerializeStruct; + let mut len = 0; + if !self.content.is_empty() { + len += 1; + } + let mut struct_ser = serializer.serialize_struct("xmtp.mls.message_contents.UserPreferenceUpdate", len)?; + if !self.content.is_empty() { + #[allow(clippy::needless_borrow)] + #[allow(clippy::needless_borrows_for_generic_args)] + struct_ser.serialize_field("content", pbjson::private::base64::encode(&self.content).as_str())?; + } + struct_ser.end() + } +} +impl<'de> serde::Deserialize<'de> for UserPreferenceUpdate { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &[ + "content", + ]; + + #[allow(clippy::enum_variant_names)] + enum GeneratedField { + Content, + } + 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 { + "content" => Ok(GeneratedField::Content), + _ => Err(serde::de::Error::unknown_field(value, FIELDS)), + } + } + } + deserializer.deserialize_identifier(GeneratedVisitor) + } + } + struct GeneratedVisitor; + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = UserPreferenceUpdate; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("struct xmtp.mls.message_contents.UserPreferenceUpdate") + } + + fn visit_map(self, mut map_: V) -> std::result::Result + where + V: serde::de::MapAccess<'de>, + { + let mut content__ = None; + while let Some(k) = map_.next_key()? { + match k { + GeneratedField::Content => { + if content__.is_some() { + return Err(serde::de::Error::duplicate_field("content")); + } + content__ = + Some(map_.next_value::<::pbjson::private::BytesDeserialize<_>>()?.0) + ; + } + } + } + Ok(UserPreferenceUpdate { + content: content__.unwrap_or_default(), + }) + } + } + deserializer.deserialize_struct("xmtp.mls.message_contents.UserPreferenceUpdate", FIELDS, GeneratedVisitor) + } +} From e1178cc3f49caa4af14cc24d67ab63d92bb5f695 Mon Sep 17 00:00:00 2001 From: Dakota Brink <779390+codabrink@users.noreply.github.com> Date: Fri, 6 Dec 2024 10:09:41 -0500 Subject: [PATCH 35/46] Test for deserialization between versions (#1389) --- xmtp_mls/src/preferences.rs | 36 ++++++++++++++++++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/xmtp_mls/src/preferences.rs b/xmtp_mls/src/preferences.rs index 5f4bb90a7..fa9c48628 100644 --- a/xmtp_mls/src/preferences.rs +++ b/xmtp_mls/src/preferences.rs @@ -5,9 +5,10 @@ use xmtp_proto::xmtp::mls::message_contents::UserPreferenceUpdate as UserPrefere use crate::storage::consent_record::StoredConsentRecord; #[derive(Serialize, Deserialize, Clone)] +#[repr(i32)] pub enum UserPreferenceUpdate { - ConsentUpdate(StoredConsentRecord), - HmacKeyUpdate { key: Vec }, + ConsentUpdate(StoredConsentRecord) = 1, + HmacKeyUpdate { key: Vec } = 2, } impl TryFrom for UserPreferenceUpdate { @@ -28,3 +29,34 @@ impl TryInto for UserPreferenceUpdate { Ok(UserPreferenceUpdateProto { content }) } } + +#[cfg(test)] +mod tests { + use crate::storage::consent_record::{ConsentState, ConsentType}; + + use super::*; + + #[derive(Serialize, Deserialize, Clone)] + #[repr(i32)] + enum OldUserPreferenceUpdate { + ConsentUpdate(StoredConsentRecord) = 1, + } + + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] + async fn test_can_deserialize_between_versions() { + let consent_record = StoredConsentRecord { + entity: "hello there".to_string(), + entity_type: ConsentType::Address, + state: ConsentState::Allowed, + }; + let update = UserPreferenceUpdate::ConsentUpdate(consent_record); + + let bytes = bincode::serialize(&update).unwrap(); + + let old_update: OldUserPreferenceUpdate = bincode::deserialize(&bytes).unwrap(); + + let OldUserPreferenceUpdate::ConsentUpdate(update) = old_update; + assert_eq!(update.state, ConsentState::Allowed); + } +} From 44fdabfbc9f7d74de6a3e111cb1269d5f39cc510 Mon Sep 17 00:00:00 2001 From: Dakota Brink <779390+codabrink@users.noreply.github.com> Date: Fri, 6 Dec 2024 14:15:45 -0500 Subject: [PATCH 36/46] make include sync groups work unconditionally (#1391) --- xmtp_mls/src/storage/encrypted_store/group.rs | 33 ++++++++++++++----- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/xmtp_mls/src/storage/encrypted_store/group.rs b/xmtp_mls/src/storage/encrypted_store/group.rs index 2cecc9b4f..63906099e 100644 --- a/xmtp_mls/src/storage/encrypted_store/group.rs +++ b/xmtp_mls/src/storage/encrypted_store/group.rs @@ -215,6 +215,8 @@ impl DbConnection { } = args.as_ref(); let mut query = groups_dsl::groups + // Filter out sync groups from the main query + .filter(groups_dsl::conversation_type.ne(ConversationType::Sync)) .order(groups_dsl::created_at_ns.asc()) .into_boxed(); @@ -238,13 +240,7 @@ impl DbConnection { query = query.filter(groups_dsl::conversation_type.eq(conversation_type)); } - // Were sync groups explicitly asked for? Was the include_sync_groups flag set to true? - // Otherwise filter sync groups out by default. - if !matches!(conversation_type, Some(ConversationType::Sync)) && !include_sync_groups { - query = query.filter(groups_dsl::conversation_type.ne(ConversationType::Sync)); - } - - let groups = if let Some(consent_state) = consent_state { + let mut groups = if let Some(consent_state) = consent_state { if *consent_state == ConsentState::Unknown { let query = query .left_join( @@ -278,6 +274,15 @@ impl DbConnection { self.raw_query(|conn| query.load::(conn))? }; + // Were sync groups explicitly asked for? Was the include_sync_groups flag set to true? + // Then query for those separately + if matches!(conversation_type, Some(ConversationType::Sync)) || *include_sync_groups { + let query = + groups_dsl::groups.filter(groups_dsl::conversation_type.eq(ConversationType::Sync)); + let mut sync_groups = self.raw_query(|conn| query.load(conn))?; + groups.append(&mut sync_groups); + } + Ok(groups) } @@ -781,7 +786,19 @@ pub(crate) mod tests { let found = conn.latest_sync_group().unwrap(); assert!(found.is_some()); - assert_eq!(found.unwrap().conversation_type, ConversationType::Sync) + assert_eq!(found.unwrap().conversation_type, ConversationType::Sync); + + // Load the sync group with a consent filter + let allowed_groups = conn + .find_groups(&GroupQueryArgs { + consent_state: Some(ConsentState::Allowed), + include_sync_groups: true, + ..Default::default() + }) + .unwrap(); + + assert_eq!(allowed_groups.len(), 1); + assert_eq!(allowed_groups[0].id, sync_group.id); }) .await } From 4524216365a8eefd634377e3386d96fd0b96335d Mon Sep 17 00:00:00 2001 From: Andrew Plaza Date: Mon, 9 Dec 2024 16:41:21 -0500 Subject: [PATCH 37/46] share provider with transactions & everywhere else (#1390) --- bindings_ffi/src/lib.rs | 2 + bindings_ffi/src/mls.rs | 69 +++-- bindings_node/src/client.rs | 7 +- bindings_node/src/conversation.rs | 3 +- bindings_node/src/conversations.rs | 14 +- bindings_wasm/src/client.rs | 8 +- bindings_wasm/src/conversations.rs | 14 +- examples/cli/cli-client.rs | 17 +- xmtp_debug/src/app/generate/messages.rs | 6 +- xmtp_debug/src/app/send.rs | 4 +- xmtp_mls/src/api/mls.rs | 10 +- xmtp_mls/src/builder.rs | 26 +- xmtp_mls/src/client.rs | 247 ++++++++++-------- xmtp_mls/src/groups/device_sync.rs | 30 ++- .../src/groups/device_sync/consent_sync.rs | 6 +- .../src/groups/device_sync/message_sync.rs | 8 +- xmtp_mls/src/groups/intents.rs | 8 +- xmtp_mls/src/groups/mls_sync.rs | 88 +++++-- xmtp_mls/src/groups/mod.rs | 134 +++++----- xmtp_mls/src/groups/scoped_client.rs | 32 +-- xmtp_mls/src/groups/subscriptions.rs | 45 ++-- xmtp_mls/src/identity.rs | 7 +- xmtp_mls/src/intents.rs | 66 +---- .../storage/encrypted_store/db_connection.rs | 2 + xmtp_mls/src/storage/encrypted_store/mod.rs | 73 ++++-- .../storage/encrypted_store/refresh_state.rs | 8 +- xmtp_mls/src/subscriptions.rs | 148 ++++++----- xmtp_mls/src/types.rs | 86 +++++- xmtp_mls/src/xmtp_openmls_provider.rs | 6 +- 29 files changed, 668 insertions(+), 506 deletions(-) diff --git a/bindings_ffi/src/lib.rs b/bindings_ffi/src/lib.rs index 670ec176e..7cd5a5b65 100755 --- a/bindings_ffi/src/lib.rs +++ b/bindings_ffi/src/lib.rs @@ -63,6 +63,8 @@ pub enum GenericError { pub enum FfiSubscribeError { #[error("Subscribe Error {0}")] Subscribe(#[from] xmtp_mls::subscriptions::SubscribeError), + #[error("Storage error: {0}")] + Storage(#[from] xmtp_mls::storage::StorageError), } impl From for GenericError { diff --git a/bindings_ffi/src/mls.rs b/bindings_ffi/src/mls.rs index 4861deb56..f5014e982 100644 --- a/bindings_ffi/src/mls.rs +++ b/bindings_ffi/src/mls.rs @@ -295,8 +295,8 @@ impl FfiXmtpClient { pub async fn find_inbox_id(&self, address: String) -> Result, GenericError> { let inner = self.inner_client.as_ref(); - - let result = inner.find_inbox_id_from_address(address).await?; + let conn = self.inner_client.store().conn()?; + let result = inner.find_inbox_id_from_address(&conn, address).await?; Ok(result) } @@ -881,8 +881,8 @@ impl FfiConversations { pub async fn sync(&self) -> Result<(), GenericError> { let inner = self.inner_client.as_ref(); - let conn = inner.store().conn()?; - inner.sync_welcomes(&conn).await?; + let provider = inner.mls_provider()?; + inner.sync_welcomes(&provider).await?; Ok(()) } @@ -898,12 +898,11 @@ impl FfiConversations { consent_state: Option, ) -> Result { let inner = self.inner_client.as_ref(); - let conn = inner.store().conn()?; - + let provider = inner.mls_provider()?; let consent: Option = consent_state.map(|state| state.into()); - - let num_groups_synced: usize = inner.sync_all_welcomes_and_groups(&conn, consent).await?; - + let num_groups_synced: usize = inner + .sync_all_welcomes_and_groups(&provider, consent) + .await?; // Convert usize to u32 for compatibility with Uniffi let num_groups_synced: u32 = num_groups_synced .try_into() @@ -1267,9 +1266,10 @@ impl FfiConversation { &self, envelope_bytes: Vec, ) -> Result { + let provider = self.inner.mls_provider()?; let message = self .inner - .process_streamed_group_message(envelope_bytes) + .process_streamed_group_message(&provider, envelope_bytes) .await?; let ffi_message = message.into(); @@ -1853,6 +1853,8 @@ mod tests { conversations: Mutex>>, consent_updates: Mutex>, notify: Notify, + inbox_id: Option, + installation_id: Option, } impl RustStreamCallback { @@ -1872,12 +1874,22 @@ mod tests { .await?; Ok(()) } + + pub fn from_client(client: &FfiXmtpClient) -> Self { + RustStreamCallback { + inbox_id: Some(client.inner_client.inbox_id().to_string()), + installation_id: Some(hex::encode(client.inner_client.installation_public_key())), + ..Default::default() + } + } } impl FfiMessageCallback for RustStreamCallback { fn on_message(&self, message: FfiMessage) { let mut messages = self.messages.lock().unwrap(); log::info!( + inbox_id = self.inbox_id, + installation_id = self.installation_id, "ON MESSAGE Received\n-------- \n{}\n----------", String::from_utf8_lossy(&message.content) ); @@ -1893,7 +1905,11 @@ mod tests { impl FfiConversationCallback for RustStreamCallback { fn on_conversation(&self, group: Arc) { - log::debug!("received conversation"); + log::debug!( + inbox_id = self.inbox_id, + installation_id = self.installation_id, + "received conversation" + ); let _ = self.num_messages.fetch_add(1, Ordering::SeqCst); let mut convos = self.conversations.lock().unwrap(); convos.push(group); @@ -1907,7 +1923,11 @@ mod tests { impl FfiConsentCallback for RustStreamCallback { fn on_consent_update(&self, mut consent: Vec) { - log::debug!("received consent update"); + log::debug!( + inbox_id = self.inbox_id, + installation_id = self.installation_id, + "received consent update" + ); let mut consent_updates = self.consent_updates.lock().unwrap(); consent_updates.append(&mut consent); self.notify.notify_one(); @@ -2774,7 +2794,7 @@ mod tests { let caro = new_test_client().await; // Alix begins a stream for all messages - let message_callbacks = Arc::new(RustStreamCallback::default()); + let message_callbacks = Arc::new(RustStreamCallback::from_client(&alix)); let stream_messages = alix .conversations() .stream_all_messages(message_callbacks.clone()) @@ -2821,12 +2841,12 @@ mod tests { let bo2 = new_test_client_with_wallet(bo_wallet).await; // Bo begins a stream for all messages - let bo_message_callbacks = Arc::new(RustStreamCallback::default()); - let bo_stream_messages = bo2 + let bo2_message_callbacks = Arc::new(RustStreamCallback::from_client(&bo2)); + let bo2_stream_messages = bo2 .conversations() - .stream_all_messages(bo_message_callbacks.clone()) + .stream_all_messages(bo2_message_callbacks.clone()) .await; - bo_stream_messages.wait_for_ready().await; + bo2_stream_messages.wait_for_ready().await; alix_group.update_installations().await.unwrap(); @@ -3190,7 +3210,7 @@ mod tests { let bo = new_test_client().await; let caro = new_test_client().await; - let caro_conn = caro.inner_client.store().conn().unwrap(); + let caro_provider = caro.inner_client.mls_provider().unwrap(); let alix_group = alix .conversations() @@ -3220,7 +3240,11 @@ mod tests { ) .await .unwrap(); - let _ = caro.inner_client.sync_welcomes(&caro_conn).await.unwrap(); + let _ = caro + .inner_client + .sync_welcomes(&caro_provider) + .await + .unwrap(); bo_group.send("second".as_bytes().to_vec()).await.unwrap(); stream_callback.wait_for_delivery(None).await.unwrap(); @@ -3239,7 +3263,7 @@ mod tests { let amal = new_test_client().await; let bola = new_test_client().await; - let bola_conn = bola.inner_client.store().conn().unwrap(); + let bola_provider = bola.inner_client.mls_provider().unwrap(); let amal_group: Arc = amal .conversations() @@ -3250,7 +3274,10 @@ mod tests { .await .unwrap(); - bola.inner_client.sync_welcomes(&bola_conn).await.unwrap(); + bola.inner_client + .sync_welcomes(&bola_provider) + .await + .unwrap(); let bola_group = bola.conversation(amal_group.id()).unwrap(); let stream_callback = Arc::new(RustStreamCallback::default()); diff --git a/bindings_node/src/client.rs b/bindings_node/src/client.rs index 5190525f5..cbe595bd9 100644 --- a/bindings_node/src/client.rs +++ b/bindings_node/src/client.rs @@ -275,9 +275,14 @@ impl Client { #[napi] pub async fn find_inbox_id_by_address(&self, address: String) -> Result> { + let conn = self + .inner_client() + .store() + .conn() + .map_err(ErrorWrapper::from)?; let inbox_id = self .inner_client - .find_inbox_id_from_address(address) + .find_inbox_id_from_address(&conn, address) .await .map_err(ErrorWrapper::from)?; diff --git a/bindings_node/src/conversation.rs b/bindings_node/src/conversation.rs index aeeffa6b1..897662463 100644 --- a/bindings_node/src/conversation.rs +++ b/bindings_node/src/conversation.rs @@ -197,8 +197,9 @@ impl Conversation { self.created_at_ns, ); let envelope_bytes: Vec = envelope_bytes.deref().to_vec(); + let provider = group.mls_provider().map_err(ErrorWrapper::from)?; let message = group - .process_streamed_group_message(envelope_bytes) + .process_streamed_group_message(&provider, envelope_bytes) .await .map_err(ErrorWrapper::from)?; diff --git a/bindings_node/src/conversations.rs b/bindings_node/src/conversations.rs index 2ee01f5c6..f957a9807 100644 --- a/bindings_node/src/conversations.rs +++ b/bindings_node/src/conversations.rs @@ -235,14 +235,13 @@ impl Conversations { #[napi] pub async fn sync(&self) -> Result<()> { - let conn = self + let provider = self .inner_client - .store() - .conn() + .mls_provider() .map_err(ErrorWrapper::from)?; self .inner_client - .sync_welcomes(&conn) + .sync_welcomes(&provider) .await .map_err(ErrorWrapper::from)?; Ok(()) @@ -250,15 +249,14 @@ impl Conversations { #[napi] pub async fn sync_all_conversations(&self) -> Result { - let conn = self + let provider = self .inner_client - .store() - .conn() + .mls_provider() .map_err(ErrorWrapper::from)?; let num_groups_synced = self .inner_client - .sync_all_welcomes_and_groups(&conn, None) + .sync_all_welcomes_and_groups(&provider, None) .await .map_err(ErrorWrapper::from)?; diff --git a/bindings_wasm/src/client.rs b/bindings_wasm/src/client.rs index 1db20bf67..f00088619 100644 --- a/bindings_wasm/src/client.rs +++ b/bindings_wasm/src/client.rs @@ -12,7 +12,6 @@ use xmtp_api_http::XmtpHttpApiClient; use xmtp_cryptography::signature::ed25519_public_key_to_address; use xmtp_id::associations::builder::SignatureRequest; use xmtp_mls::builder::ClientBuilder; -use xmtp_mls::groups::scoped_client::ScopedGroupClient; use xmtp_mls::identity::IdentityStrategy; use xmtp_mls::storage::{EncryptedMessageStore, EncryptionKey, StorageOption}; use xmtp_mls::Client as MlsClient; @@ -273,9 +272,14 @@ impl Client { #[wasm_bindgen(js_name = findInboxIdByAddress)] pub async fn find_inbox_id_by_address(&self, address: String) -> Result, JsError> { + let conn = self + .inner_client + .store() + .conn() + .map_err(|e| JsError::new(format!("{}", e).as_str()))?; let inbox_id = self .inner_client - .find_inbox_id_from_address(address) + .find_inbox_id_from_address(&conn, address) .await .map_err(|e| JsError::new(format!("{}", e).as_str()))?; diff --git a/bindings_wasm/src/conversations.rs b/bindings_wasm/src/conversations.rs index 790868d29..50f0790a2 100644 --- a/bindings_wasm/src/conversations.rs +++ b/bindings_wasm/src/conversations.rs @@ -269,14 +269,13 @@ impl Conversations { #[wasm_bindgen] pub async fn sync(&self) -> Result<(), JsError> { - let conn = self + let provider = self .inner_client - .store() - .conn() + .mls_provider() .map_err(|e| JsError::new(format!("{}", e).as_str()))?; self .inner_client - .sync_welcomes(&conn) + .sync_welcomes(&provider) .await .map_err(|e| JsError::new(format!("{}", e).as_str()))?; @@ -285,15 +284,14 @@ impl Conversations { #[wasm_bindgen(js_name = syncAllConversations)] pub async fn sync_all_conversations(&self) -> Result { - let conn = self + let provider = self .inner_client - .store() - .conn() + .mls_provider() .map_err(|e| JsError::new(format!("{}", e).as_str()))?; let num_groups_synced = self .inner_client - .sync_all_welcomes_and_groups(&conn, None) + .sync_all_welcomes_and_groups(&provider, None) .await .map_err(|e| JsError::new(format!("{}", e).as_str()))?; diff --git a/examples/cli/cli-client.rs b/examples/cli/cli-client.rs index b371edef1..a9513bec5 100755 --- a/examples/cli/cli-client.rs +++ b/examples/cli/cli-client.rs @@ -290,9 +290,9 @@ async fn main() -> color_eyre::eyre::Result<()> { } Commands::ListGroups {} => { info!("List Groups"); - let conn = client.store().conn()?; + let provider = client.mls_provider()?; client - .sync_welcomes(&conn) + .sync_welcomes(&provider) .await .expect("failed to sync welcomes"); @@ -440,9 +440,8 @@ async fn main() -> color_eyre::eyre::Result<()> { ); } Commands::RequestHistorySync {} => { - let conn = client.store().conn().unwrap(); let provider = client.mls_provider().unwrap(); - client.sync_welcomes(&conn).await.unwrap(); + client.sync_welcomes(&provider).await.unwrap(); client.start_sync_worker(); client .send_sync_request(&provider, DeviceSyncKind::MessageHistory) @@ -451,9 +450,9 @@ async fn main() -> color_eyre::eyre::Result<()> { info!("Sent history sync request in sync group.") } Commands::ListHistorySyncMessages {} => { - let conn = client.store().conn()?; - client.sync_welcomes(&conn).await?; - let group = client.get_sync_group(&conn)?; + let provider = client.mls_provider()?; + client.sync_welcomes(&provider).await?; + let group = client.get_sync_group(provider.conn_ref())?; let group_id_str = hex::encode(group.group_id.clone()); group.sync().await?; let messages = group @@ -574,8 +573,8 @@ where } async fn get_group(client: &Client, group_id: Vec) -> Result { - let conn = client.store().conn().unwrap(); - client.sync_welcomes(&conn).await?; + let provider = client.mls_provider().unwrap(); + client.sync_welcomes(&provider).await?; let group = client.group(group_id)?; group .sync() diff --git a/xmtp_debug/src/app/generate/messages.rs b/xmtp_debug/src/app/generate/messages.rs index aeb118ff7..fc6006d85 100644 --- a/xmtp_debug/src/app/generate/messages.rs +++ b/xmtp_debug/src/app/generate/messages.rs @@ -8,7 +8,6 @@ use crate::{ use color_eyre::eyre::{self, eyre, Result}; use rand::{rngs::SmallRng, seq::SliceRandom, Rng, SeedableRng}; use std::sync::Arc; -use xmtp_mls::XmtpOpenMlsProvider; mod content_type; @@ -118,10 +117,9 @@ impl GenerateMessages { hex::encode(inbox_id) ))?; let client = app::client_from_identity(&identity, &network).await?; - let conn = client.store().conn()?; - client.sync_welcomes(&conn).await?; + let provider = client.mls_provider()?; + client.sync_welcomes(&provider).await?; let group = client.group(group.id.into())?; - let provider: XmtpOpenMlsProvider = conn.into(); group.maybe_update_installations(&provider, None).await?; group.sync_with_conn(&provider).await?; let words = rng.gen_range(0..*max_message_size); diff --git a/xmtp_debug/src/app/send.rs b/xmtp_debug/src/app/send.rs index 59601d4fe..35a95cbf7 100644 --- a/xmtp_debug/src/app/send.rs +++ b/xmtp_debug/src/app/send.rs @@ -49,8 +49,8 @@ impl Send { .ok_or(eyre!("No Identity with inbox_id [{}]", hex::encode(member)))?; let client = crate::app::client_from_identity(&identity, network).await?; - let conn = client.store().conn()?; - client.sync_welcomes(&conn).await?; + let provider = client.mls_provider()?; + client.sync_welcomes(&provider).await?; let xmtp_group = client.group(group.id.to_vec())?; xmtp_group.send_message(data.as_bytes()).await?; Ok(()) diff --git a/xmtp_mls/src/api/mls.rs b/xmtp_mls/src/api/mls.rs index 4000467e6..33a42a577 100644 --- a/xmtp_mls/src/api/mls.rs +++ b/xmtp_mls/src/api/mls.rs @@ -115,9 +115,9 @@ where } #[tracing::instrument(level = "trace", skip_all)] - pub async fn query_welcome_messages( + pub async fn query_welcome_messages + Copy>( &self, - installation_id: &[u8], + installation_id: Id, id_cursor: Option, ) -> Result, ApiError> { tracing::debug!( @@ -135,7 +135,7 @@ where (async { self.api_client .query_welcome_messages(QueryWelcomeMessagesRequest { - installation_key: installation_id.to_vec(), + installation_key: installation_id.as_ref().to_vec(), paging_info: Some(PagingInfo { id_cursor: id_cursor.unwrap_or(0), limit: page_size, @@ -297,7 +297,7 @@ where pub async fn subscribe_welcome_messages( &self, - installation_key: Vec, + installation_key: &[u8], id_cursor: Option, ) -> Result> + '_, ApiError> where @@ -307,7 +307,7 @@ where self.api_client .subscribe_welcome_messages(SubscribeWelcomeMessagesRequest { filters: vec![WelcomeFilterProto { - installation_key, + installation_key: installation_key.to_vec(), id_cursor: id_cursor.unwrap_or(0), }], }) diff --git a/xmtp_mls/src/builder.rs b/xmtp_mls/src/builder.rs index 930c81506..997a92ce8 100644 --- a/xmtp_mls/src/builder.rs +++ b/xmtp_mls/src/builder.rs @@ -13,7 +13,7 @@ use crate::{ identity_updates::load_identity_updates, retry::Retry, storage::EncryptedMessageStore, - StorageError, XmtpApi, + StorageError, XmtpApi, XmtpOpenMlsProvider, }; #[derive(Error, Debug)] @@ -186,20 +186,22 @@ where let store = store .take() .ok_or(ClientBuilderError::MissingParameter { parameter: "store" })?; + let conn = store.conn()?; + let provider = XmtpOpenMlsProvider::new(conn); + let identity = identity_strategy + .initialize_identity(&api_client_wrapper, &provider, &scw_verifier) + .await?; debug!( - inbox_id = identity_strategy.inbox_id(), - "Initializing identity" + inbox_id = identity.inbox_id(), + installation_id = hex::encode(identity.installation_keys.public_bytes()), + "Initialized identity" ); - let identity = identity_strategy - .initialize_identity(&api_client_wrapper, &store, &scw_verifier) - .await?; - // get sequence_id from identity updates and loaded into the DB load_identity_updates( &api_client_wrapper, - &store.conn()?, + provider.conn_ref(), vec![identity.inbox_id.as_str()].as_slice(), ) .await?; @@ -557,7 +559,7 @@ pub(crate) mod tests { let identity = IdentityStrategy::new("other_inbox_id".to_string(), address, nonce, None); assert!(matches!( identity - .initialize_identity(&wrapper, &store, &scw_verifier) + .initialize_identity(&wrapper, &store.mls_provider().unwrap(), &scw_verifier) .await .unwrap_err(), IdentityError::NewIdentity(msg) if msg == "Inbox ID mismatch" @@ -598,7 +600,7 @@ pub(crate) mod tests { let identity = IdentityStrategy::new(inbox_id.clone(), address, nonce, None); assert!(dbg!( identity - .initialize_identity(&wrapper, &store, &scw_verifier) + .initialize_identity(&wrapper, &store.mls_provider().unwrap(), &scw_verifier) .await ) .is_ok()); @@ -636,7 +638,7 @@ pub(crate) mod tests { let wrapper = ApiClientWrapper::new(mock_api.into(), Retry::default()); let identity = IdentityStrategy::new(inbox_id.clone(), address, nonce, None); assert!(identity - .initialize_identity(&wrapper, &store, &scw_verifier) + .initialize_identity(&wrapper, &store.mls_provider().unwrap(), &scw_verifier) .await .is_ok()); } @@ -676,7 +678,7 @@ pub(crate) mod tests { let inbox_id = "inbox_id".to_string(); let identity = IdentityStrategy::new(inbox_id.clone(), address.clone(), nonce, None); let err = identity - .initialize_identity(&wrapper, &store, &scw_verifier) + .initialize_identity(&wrapper, &store.mls_provider().unwrap(), &scw_verifier) .await .unwrap_err(); diff --git a/xmtp_mls/src/client.rs b/xmtp_mls/src/client.rs index 051c12500..81751d5a8 100644 --- a/xmtp_mls/src/client.rs +++ b/xmtp_mls/src/client.rs @@ -12,7 +12,6 @@ use openmls::{ messages::Welcome, prelude::tls_codec::{Deserialize, Error as TlsCodecError}, }; -use openmls_traits::OpenMlsProvider; use thiserror::Error; use tokio::sync::broadcast; @@ -36,7 +35,7 @@ use crate::{ groups::{group_permissions::PolicySet, GroupError, GroupMetadataOptions, MlsGroup}, identity::{parse_credential, Identity, IdentityError}, identity_updates::{load_identity_updates, IdentityUpdateError}, - intents::Intents, + intents::ProcessIntentError, mutex_registry::MutexRegistry, preferences::UserPreferenceUpdate, retry::Retry, @@ -51,6 +50,7 @@ use crate::{ EncryptedMessageStore, StorageError, }, subscriptions::{LocalEventError, LocalEvents}, + types::InstallationId, verified_key_package_v2::{KeyPackageVerificationError, VerifiedKeyPackageV2}, xmtp_openmls_provider::XmtpOpenMlsProvider, Fetch, Store, XmtpApi, @@ -138,7 +138,6 @@ impl From<&str> for ClientError { /// Clients manage access to the network, identity, and data store pub struct Client> { pub(crate) api_client: Arc>, - pub(crate) intents: Arc, pub(crate) context: Arc, pub(crate) history_sync_url: Option, pub(crate) local_events: broadcast::Sender>, @@ -155,7 +154,6 @@ impl Clone for Client { history_sync_url: self.history_sync_url.clone(), local_events: self.local_events.clone(), scw_verifier: self.scw_verifier.clone(), - intents: self.intents.clone(), } } } @@ -173,8 +171,8 @@ pub struct XmtpMlsLocalContext { impl XmtpMlsLocalContext { /// The installation public key is the primary identifier for an installation - pub fn installation_public_key(&self) -> &[u8; 32] { - self.identity.installation_keys.public_bytes() + pub fn installation_public_key(&self) -> InstallationId { + (*self.identity.installation_keys.public_bytes()).into() } /// Get the account address of the blockchain account associated with this client @@ -192,7 +190,7 @@ impl XmtpMlsLocalContext { } /// Pulls a new database connection and creates a new provider - pub fn mls_provider(&self) -> Result { + pub fn mls_provider(&self) -> Result { Ok(self.store.conn()?.into()) } @@ -234,9 +232,6 @@ where store, mutexes: MutexRegistry::new(), }); - let intents = Arc::new(Intents { - context: context.clone(), - }); let (tx, _) = broadcast::channel(32); Self { @@ -245,7 +240,6 @@ where history_sync_url, local_events: tx, scw_verifier: scw_verifier.into(), - intents, } } @@ -279,7 +273,7 @@ where V: SmartContractSignatureVerifier, { /// Retrieves the client's installation public key, sometimes also called `installation_id` - pub fn installation_public_key(&self) -> &[u8; 32] { + pub fn installation_public_key(&self) -> InstallationId { self.context.installation_public_key() } /// Retrieves the client's inbox ID @@ -287,12 +281,8 @@ where self.context.inbox_id() } - pub fn intents(&self) -> &Arc { - &self.intents - } - /// Pulls a connection and creates a new MLS Provider - pub fn mls_provider(&self) -> Result { + pub fn mls_provider(&self) -> Result { self.context.mls_provider() } @@ -303,9 +293,10 @@ where /// Calls the server to look up the `inbox_id` associated with a given address pub async fn find_inbox_id_from_address( &self, + conn: &DbConnection, address: String, ) -> Result, ClientError> { - let results = self.find_inbox_ids_from_addresses(&[address]).await?; + let results = self.find_inbox_ids_from_addresses(conn, &[address]).await?; if let Some(first_result) = results.into_iter().next() { Ok(first_result) } else { @@ -315,12 +306,12 @@ where /// Calls the server to look up the `inbox_id`s` associated with a list of addresses. /// If no `inbox_id` is found, returns None. - pub async fn find_inbox_ids_from_addresses( + pub(crate) async fn find_inbox_ids_from_addresses( &self, + conn: &DbConnection, addresses: &[String], ) -> Result>, ClientError> { let sanitized_addresses = sanitize_evm_addresses(addresses)?; - let conn = self.store().conn()?; let local_results: Vec = conn.fetch_wallets_list_with_key(&sanitized_addresses)?; @@ -354,7 +345,7 @@ where inbox_id: InboxId::from(inbox_id), wallet_address: address, }; - new_entry.store(&conn).ok(); + new_entry.store(conn).ok(); } let inbox_ids: Vec> = sanitized_addresses @@ -424,7 +415,7 @@ where } let inbox_ids = self - .find_inbox_ids_from_addresses(&addresses_to_lookup) + .find_inbox_ids_from_addresses(&conn, &addresses_to_lookup) .await?; for (i, inbox_id_opt) in inbox_ids.into_iter().enumerate() { @@ -464,7 +455,10 @@ where ) -> Result { let conn = self.store().conn()?; let record = if entity_type == ConsentType::Address { - if let Some(inbox_id) = self.find_inbox_id_from_address(entity.clone()).await? { + if let Some(inbox_id) = self + .find_inbox_id_from_address(&conn, entity.clone()) + .await? + { conn.get_consent_record(inbox_id, ConsentType::InboxId)? } else { conn.get_consent_record(entity, entity_type)? @@ -509,9 +503,10 @@ where opts: GroupMetadataOptions, ) -> Result, ClientError> { tracing::info!("creating group"); - + let provider = self.mls_provider()?; let group: MlsGroup> = MlsGroup::create_and_insert( Arc::new(self.clone()), + &provider, GroupMembershipState::Allowed, permissions_policy_set.unwrap_or_default(), opts, @@ -541,9 +536,10 @@ where /// Create a new Direct Message with the default settings pub async fn create_dm(&self, account_address: String) -> Result, ClientError> { tracing::info!("creating dm with address: {}", account_address); + let provider = self.mls_provider()?; let inbox_id = match self - .find_inbox_id_from_address(account_address.clone()) + .find_inbox_id_from_address(provider.conn_ref(), account_address.clone()) .await? { Some(id) => id, @@ -555,23 +551,26 @@ where } }; - self.create_dm_by_inbox_id(inbox_id).await + self.create_dm_by_inbox_id(&provider, inbox_id).await } /// Create a new Direct Message with the default settings - pub async fn create_dm_by_inbox_id( + pub(crate) async fn create_dm_by_inbox_id( &self, + provider: &XmtpOpenMlsProvider, dm_target_inbox_id: InboxId, ) -> Result, ClientError> { tracing::info!("creating dm with {}", dm_target_inbox_id); - let group: MlsGroup> = MlsGroup::create_dm_and_insert( + provider, Arc::new(self.clone()), GroupMembershipState::Allowed, dm_target_inbox_id.clone(), )?; - group.add_members_by_inbox_id(&[dm_target_inbox_id]).await?; + group + .add_members_by_inbox_id_with_provider(provider, &[dm_target_inbox_id]) + .await?; // notify any streams of the new group let _ = self.local_events.send(LocalEvents::NewGroup(group.clone())); @@ -694,12 +693,19 @@ where /// Upload a new key package to the network replacing an existing key package /// This is expected to be run any time the client receives new Welcome messages - pub async fn rotate_key_package(&self) -> Result<(), ClientError> { + pub async fn rotate_key_package( + &self, + provider: &XmtpOpenMlsProvider, + ) -> Result<(), ClientError> { self.store() - .transaction_async(|provider| async move { - self.identity() - .rotate_key_package(&provider, &self.api_client) - .await + .transaction_async(provider, move |provider| { + let provider = &provider; + async { + self.identity() + .rotate_key_package(provider, &self.api_client) + .await?; + Ok::<_, IdentityError>(()) + } }) .await?; @@ -734,7 +740,7 @@ where let welcomes = self .api_client - .query_welcome_messages(installation_id, Some(id_cursor as u64)) + .query_welcome_messages(installation_id.as_ref(), Some(id_cursor as u64)) .await?; Ok(welcomes) @@ -748,10 +754,10 @@ where ) -> Result, ClientError> { let key_package_results = self.api_client.fetch_key_packages(installation_ids).await?; - let mls_provider = self.mls_provider()?; + let crypto_provider = XmtpOpenMlsProvider::new_crypto(); Ok(key_package_results .values() - .map(|bytes| VerifiedKeyPackageV2::from_bytes(mls_provider.crypto(), bytes.as_slice())) + .map(|bytes| VerifiedKeyPackageV2::from_bytes(&crypto_provider, bytes.as_slice())) .collect::>()?) } @@ -760,11 +766,10 @@ where #[tracing::instrument(level = "debug", skip_all)] pub async fn sync_welcomes( &self, - conn: &DbConnection, + provider: &XmtpOpenMlsProvider, ) -> Result>, ClientError> { - let envelopes = self.query_welcome_messages(conn).await?; + let envelopes = self.query_welcome_messages(provider.conn_ref()).await?; let num_envelopes = envelopes.len(); - let id = self.installation_public_key(); let groups: Vec> = stream::iter(envelopes.into_iter()) .filter_map(|envelope: WelcomeMessage| async { @@ -777,73 +782,86 @@ where }; retry_async!( Retry::default(), - (async { - let welcome_v1 = &welcome_v1; - self.intents.process_for_id( - id, - EntityKind::Welcome, - welcome_v1.id, - |provider| async move { - let result = MlsGroup::create_from_encrypted_welcome( - Arc::new(self.clone()), - &provider, - welcome_v1.hpke_public_key.as_slice(), - &welcome_v1.data, - welcome_v1.id as i64, - ) - .await; - - match result { - Ok(mls_group) => Ok(Some(mls_group)), - Err(err) => { - use crate::StorageError::*; - use crate::DuplicateItem::*; - - if matches!(err, GroupError::Storage(Duplicate(WelcomeId(_)))) { - tracing::warn!("failed to create group from welcome due to duplicate welcome ID: {}", err); - } else { - tracing::error!("failed to create group from welcome: {}", err); - } - - Err(err) - } - } - }, - ) - .await - }) + (async { self.process_new_welcome(provider, &welcome_v1).await }) ) .ok() - .flatten() }) .collect() .await; // If any welcomes were found, rotate your key package if num_envelopes > 0 { - self.rotate_key_package().await?; + self.rotate_key_package(provider).await?; } Ok(groups) } + /// Internal API to process a unread welcome message and convert to a group. + /// In a database transaction, increments the cursor for a given installation and + /// applies the update after the welcome processed succesfully. + async fn process_new_welcome( + &self, + provider: &XmtpOpenMlsProvider, + welcome: &WelcomeMessageV1, + ) -> Result, GroupError> { + self.store() + .transaction_async(provider, |provider| async move { + let cursor = welcome.id; + let is_updated = provider.conn_ref().update_cursor( + self.installation_public_key(), + EntityKind::Welcome, + welcome.id as i64, + )?; + if !is_updated { + return Err(ProcessIntentError::AlreadyProcessed(cursor).into()); + } + let result = MlsGroup::create_from_encrypted_welcome( + Arc::new(self.clone()), + provider, + welcome.hpke_public_key.as_slice(), + &welcome.data, + welcome.id as i64, + ) + .await; + + match result { + Ok(mls_group) => Ok(mls_group), + Err(err) => { + use crate::DuplicateItem::*; + use crate::StorageError::*; + + if matches!(err, GroupError::Storage(Duplicate(WelcomeId(_)))) { + tracing::warn!( + "failed to create group from welcome due to duplicate welcome ID: {}", + err + ); + } else { + tracing::error!("failed to create group from welcome: {}", err); + } + + Err(err) + } + } + }) + .await + } + /// Sync all groups for the current installation and return the number of groups that were synced. /// Only active groups will be synced. - pub async fn sync_all_groups(&self, groups: Vec>) -> Result { - // Acquire a single connection to be reused - let provider: XmtpOpenMlsProvider = self.mls_provider()?; - + pub async fn sync_all_groups( + &self, + groups: Vec>, + provider: &XmtpOpenMlsProvider, + ) -> Result { let active_group_count = Arc::new(AtomicUsize::new(0)); let sync_futures = groups .into_iter() .map(|group| { - // create new provider ref that gets moved, leaving original - // provider alone. - let provider_ref = &provider; let active_group_count = Arc::clone(&active_group_count); async move { - let mls_group = group.load_mls_group(provider_ref)?; + let mls_group = group.load_mls_group(provider)?; tracing::info!( inbox_id = self.inbox_id(), "[{}] syncing group", @@ -857,9 +875,9 @@ where mls_group.epoch() ); if mls_group.is_active() { - group.maybe_update_installations(provider_ref, None).await?; + group.maybe_update_installations(provider, None).await?; - group.sync_with_conn(provider_ref).await?; + group.sync_with_conn(provider).await?; active_group_count.fetch_add(1, Ordering::SeqCst); } @@ -881,19 +899,22 @@ where /// Returns the total number of active groups synced. pub async fn sync_all_welcomes_and_groups( &self, - conn: &DbConnection, + provider: &XmtpOpenMlsProvider, consent_state: Option, ) -> Result { - self.sync_welcomes(conn).await?; - + self.sync_welcomes(provider).await?; let query_args = GroupQueryArgs { consent_state, include_sync_groups: true, ..GroupQueryArgs::default() }; - - let groups = self.find_groups(query_args)?; - let active_groups_count = self.sync_all_groups(groups).await?; + let groups = provider + .conn_ref() + .find_groups(query_args)? + .into_iter() + .map(|g| MlsGroup::new(self.clone(), g.id, g.created_at_ns)) + .collect(); + let active_groups_count = self.sync_all_groups(groups, provider).await?; Ok(active_groups_count) } @@ -1069,7 +1090,10 @@ pub(crate) mod tests { let init1 = kp1[0].inner.hpke_init_key(); // Rotate and fetch again. - client.rotate_key_package().await.unwrap(); + client + .rotate_key_package(&client.mls_provider().unwrap()) + .await + .unwrap(); let kp2 = client .get_key_packages_for_installation_ids(vec![client.installation_public_key().to_vec()]) @@ -1105,7 +1129,7 @@ pub(crate) mod tests { let client = ClientBuilder::new_test_client(&wallet).await; assert_eq!( client - .find_inbox_id_from_address(wallet.get_address()) + .find_inbox_id_from_address(&client.store().conn().unwrap(), wallet.get_address()) .await .unwrap(), Some(client.inbox_id().to_string()) @@ -1130,7 +1154,7 @@ pub(crate) mod tests { .unwrap(); let bob_received_groups = bob - .sync_welcomes(&bob.store().conn().unwrap()) + .sync_welcomes(&bob.mls_provider().unwrap()) .await .unwrap(); assert_eq!(bob_received_groups.len(), 1); @@ -1140,7 +1164,7 @@ pub(crate) mod tests { ); let duplicate_received_groups = bob - .sync_welcomes(&bob.store().conn().unwrap()) + .sync_welcomes(&bob.mls_provider().unwrap()) .await .unwrap(); assert_eq!(duplicate_received_groups.len(), 0); @@ -1170,7 +1194,7 @@ pub(crate) mod tests { .await .unwrap(); - let bob_received_groups = bo.sync_welcomes(&bo.store().conn().unwrap()).await.unwrap(); + let bob_received_groups = bo.sync_welcomes(&bo.mls_provider().unwrap()).await.unwrap(); assert_eq!(bob_received_groups.len(), 2); let bo_groups = bo.find_groups(GroupQueryArgs::default()).unwrap(); @@ -1189,7 +1213,9 @@ pub(crate) mod tests { .await .unwrap(); - bo.sync_all_groups(bo_groups).await.unwrap(); + bo.sync_all_groups(bo_groups, &bo.mls_provider().unwrap()) + .await + .unwrap(); let bo_messages1 = bo_group1.find_messages(&MsgQueryArgs::default()).unwrap(); assert_eq!(bo_messages1.len(), 1); @@ -1226,7 +1252,7 @@ pub(crate) mod tests { // Initial sync (None): Bob should fetch both groups let bob_received_groups = bo - .sync_all_welcomes_and_groups(&bo.store().conn().unwrap(), None) + .sync_all_welcomes_and_groups(&bo.mls_provider().unwrap(), None) .await .unwrap(); assert_eq!(bob_received_groups, 2); @@ -1261,7 +1287,7 @@ pub(crate) mod tests { // Sync with `Unknown`: Bob should not fetch new messages let bob_received_groups_unknown = bo - .sync_all_welcomes_and_groups(&bo.store().conn().unwrap(), Some(ConsentState::Allowed)) + .sync_all_welcomes_and_groups(&bo.mls_provider().unwrap(), Some(ConsentState::Allowed)) .await .unwrap(); assert_eq!(bob_received_groups_unknown, 0); @@ -1294,7 +1320,7 @@ pub(crate) mod tests { // Sync with `None`: Bob should fetch all messages let bob_received_groups_all = bo - .sync_all_welcomes_and_groups(&bo.store().conn().unwrap(), Some(ConsentState::Unknown)) + .sync_all_welcomes_and_groups(&bo.mls_provider().unwrap(), Some(ConsentState::Unknown)) .await .unwrap(); assert_eq!(bob_received_groups_all, 2); @@ -1355,7 +1381,7 @@ pub(crate) mod tests { assert_eq!(amal_group.members().await.unwrap().len(), 1); tracing::info!("Syncing bolas welcomes"); // See if Bola can see that they were added to the group - bola.sync_welcomes(&bola.store().conn().unwrap()) + bola.sync_welcomes(&bola.mls_provider().unwrap()) .await .unwrap(); let bola_groups = bola.find_groups(Default::default()).unwrap(); @@ -1376,7 +1402,7 @@ pub(crate) mod tests { .add_members_by_inbox_id(&[bola.inbox_id()]) .await .unwrap(); - bola.sync_welcomes(&bola.store().conn().unwrap()) + bola.sync_welcomes(&bola.mls_provider().unwrap()) .await .unwrap(); @@ -1426,12 +1452,13 @@ pub(crate) mod tests { async fn get_key_package_init_key< ApiClient: XmtpApi, Verifier: SmartContractSignatureVerifier, + Id: AsRef<[u8]>, >( client: &Client, - installation_id: &[u8], + installation_id: Id, ) -> Vec { let kps = client - .get_key_packages_for_installation_ids(vec![installation_id.to_vec()]) + .get_key_packages_for_installation_ids(vec![installation_id.as_ref().to_vec()]) .await .unwrap(); let kp = kps.first().unwrap(); @@ -1468,18 +1495,18 @@ pub(crate) mod tests { .await .unwrap(); - bo.sync_welcomes(&bo.store().conn().unwrap()).await.unwrap(); + bo.sync_welcomes(&bo.mls_provider().unwrap()).await.unwrap(); let bo_new_key = get_key_package_init_key(&bo, bo.installation_public_key()).await; // Bo's key should have changed assert_ne!(bo_original_init_key, bo_new_key); - bo.sync_welcomes(&bo.store().conn().unwrap()).await.unwrap(); + bo.sync_welcomes(&bo.mls_provider().unwrap()).await.unwrap(); let bo_new_key_2 = get_key_package_init_key(&bo, bo.installation_public_key()).await; // Bo's key should not have changed syncing the second time. assert_eq!(bo_new_key, bo_new_key_2); - alix.sync_welcomes(&alix.store().conn().unwrap()) + alix.sync_welcomes(&alix.mls_provider().unwrap()) .await .unwrap(); let alix_key_2 = get_key_package_init_key(&alix, alix.installation_public_key()).await; @@ -1493,7 +1520,7 @@ pub(crate) mod tests { ) .await .unwrap(); - bo.sync_welcomes(&bo.store().conn().unwrap()).await.unwrap(); + bo.sync_welcomes(&bo.mls_provider().unwrap()).await.unwrap(); // Bo should have two groups now let bo_groups = bo.find_groups(GroupQueryArgs::default()).unwrap(); diff --git a/xmtp_mls/src/groups/device_sync.rs b/xmtp_mls/src/groups/device_sync.rs index 89c86cb7a..c0af9ac84 100644 --- a/xmtp_mls/src/groups/device_sync.rs +++ b/xmtp_mls/src/groups/device_sync.rs @@ -401,7 +401,7 @@ where let content = DeviceSyncContent::Request(request.clone()); let content_bytes = serde_json::to_vec(&content)?; - let _message_id = sync_group.prepare_message(&content_bytes, provider.conn_ref(), { + let _message_id = sync_group.prepare_message(&content_bytes, provider, { let request = request.clone(); move |_time_ns| PlaintextEnvelope { content: Some(Content::V2(V2 { @@ -445,7 +445,6 @@ where provider: &XmtpOpenMlsProvider, contents: DeviceSyncReplyProto, ) -> Result<(), DeviceSyncError> { - let conn = provider.conn_ref(); // find the sync group let sync_group = self.get_sync_group(provider.conn_ref())?; @@ -457,7 +456,7 @@ where .await?; // add original sender to all groups on this device on the node - self.ensure_member_of_all_groups(conn, &msg.sender_inbox_id) + self.ensure_member_of_all_groups(provider, &msg.sender_inbox_id) .await?; // the reply message @@ -471,7 +470,7 @@ where (content_bytes, contents) }; - sync_group.prepare_message(&content_bytes, conn, |_time_ns| PlaintextEnvelope { + sync_group.prepare_message(&content_bytes, provider, |_time_ns| PlaintextEnvelope { content: Some(Content::V2(V2 { idempotency_key: new_request_id(), message_type: Some(MessageType::DeviceSyncReply(contents)), @@ -491,8 +490,10 @@ where let sync_group = self.get_sync_group(provider.conn_ref())?; sync_group.sync_with_conn(provider).await?; - let messages = sync_group - .find_messages(&MsgQueryArgs::default().kind(GroupMessageKind::Application))?; + let messages = provider.conn_ref().get_group_messages( + &sync_group.group_id, + &MsgQueryArgs::default().kind(GroupMessageKind::Application), + )?; for msg in messages.into_iter().rev() { let Ok(msg_content) = @@ -565,13 +566,14 @@ where self.insert_encrypted_syncables(provider, enc_payload, &enc_key.try_into()?) .await?; - self.sync_welcomes(provider.conn_ref()).await?; + self.sync_welcomes(provider).await?; let groups = conn.find_groups(GroupQueryArgs::default().conversation_type(ConversationType::Group))?; for crate::storage::group::StoredGroup { id, .. } in groups.into_iter() { - let group = self.group(id)?; - Box::pin(group.sync()).await?; + let group = self.group_with_conn(provider.conn_ref(), id)?; + group.maybe_update_installations(provider, None).await?; + Box::pin(group.sync_with_conn(provider)).await?; } Ok(()) @@ -579,14 +581,18 @@ where async fn ensure_member_of_all_groups( &self, - conn: &DbConnection, + provider: &XmtpOpenMlsProvider, inbox_id: &str, ) -> Result<(), GroupError> { + let conn = provider.conn_ref(); let groups = conn.find_groups(GroupQueryArgs::default().conversation_type(ConversationType::Group))?; for group in groups { - let group = self.group(group.id)?; - Box::pin(group.add_members_by_inbox_id(&[inbox_id.to_string()])).await?; + let group = self.group_with_conn(conn, group.id)?; + Box::pin( + group.add_members_by_inbox_id_with_provider(provider, &[inbox_id.to_string()]), + ) + .await?; } Ok(()) diff --git a/xmtp_mls/src/groups/device_sync/consent_sync.rs b/xmtp_mls/src/groups/device_sync/consent_sync.rs index a4053288b..4003322b8 100644 --- a/xmtp_mls/src/groups/device_sync/consent_sync.rs +++ b/xmtp_mls/src/groups/device_sync/consent_sync.rs @@ -19,15 +19,13 @@ where "Streaming consent update. {:?}", record ); - let conn = provider.conn_ref(); let sync_group = self.ensure_sync_group(provider).await?; - let update_proto: UserPreferenceUpdateProto = UserPreferenceUpdate::ConsentUpdate(record) .try_into() .map_err(|e| DeviceSyncError::Bincode(format!("{e:?}")))?; let content_bytes = serde_json::to_vec(&update_proto)?; - sync_group.prepare_message(&content_bytes, conn, |_time_ns| PlaintextEnvelope { + sync_group.prepare_message(&content_bytes, provider, |_time_ns| PlaintextEnvelope { content: Some(Content::V2(V2 { idempotency_key: new_request_id(), message_type: Some(MessageType::UserPreferenceUpdate(update_proto)), @@ -111,7 +109,7 @@ pub(crate) mod tests { let old_group_id = amal_a.get_sync_group(amal_a_conn).unwrap().group_id; tracing::info!("Old Group Id: {}", hex::encode(&old_group_id)); // Check for new welcomes to new groups in the first installation (should be welcomed to a new sync group from amal_b). - amal_a.sync_welcomes(amal_a_conn).await.unwrap(); + amal_a.sync_welcomes(&amal_a_provider).await.unwrap(); let new_group_id = amal_a.get_sync_group(amal_a_conn).unwrap().group_id; tracing::info!("New Group Id: {}", hex::encode(&new_group_id)); // group id should have changed to the new sync group created by the second installation diff --git a/xmtp_mls/src/groups/device_sync/message_sync.rs b/xmtp_mls/src/groups/device_sync/message_sync.rs index 056f0c3e7..66e63e261 100644 --- a/xmtp_mls/src/groups/device_sync/message_sync.rs +++ b/xmtp_mls/src/groups/device_sync/message_sync.rs @@ -106,7 +106,7 @@ pub(crate) mod tests { let old_group_id = amal_a.get_sync_group(amal_a_conn).unwrap().group_id; // Check for new welcomes to new groups in the first installation (should be welcomed to a new sync group from amal_b). amal_a - .sync_welcomes(amal_a_conn) + .sync_welcomes(&amal_a_provider) .await .expect("sync_welcomes"); let new_group_id = amal_a.get_sync_group(amal_a_conn).unwrap().group_id; @@ -205,7 +205,7 @@ pub(crate) mod tests { // Check for new welcomes to new groups in the first installation (should be welcomed to a new sync group from amal_b). amal_a - .sync_welcomes(amal_a_conn) + .sync_welcomes(&amal_a_provider) .await .expect("sync_welcomes"); let new_group_id = amal_a.get_sync_group(amal_a_conn).unwrap().group_id; @@ -262,7 +262,7 @@ pub(crate) mod tests { async fn test_externals_cant_join_sync_group() { let wallet = generate_local_wallet(); let amal = ClientBuilder::new_test_client_with_history(&wallet, HISTORY_SYNC_URL).await; - amal.sync_welcomes(&amal.store().conn().unwrap()) + amal.sync_welcomes(&amal.mls_provider().unwrap()) .await .expect("sync welcomes"); @@ -271,7 +271,7 @@ pub(crate) mod tests { ClientBuilder::new_test_client_with_history(&bo_wallet, HISTORY_SYNC_URL).await; bo_client - .sync_welcomes(&bo_client.store().conn().unwrap()) + .sync_welcomes(&bo_client.mls_provider().unwrap()) .await .expect("sync welcomes"); diff --git a/xmtp_mls/src/groups/intents.rs b/xmtp_mls/src/groups/intents.rs index 80f5eb167..b3faf11b4 100644 --- a/xmtp_mls/src/groups/intents.rs +++ b/xmtp_mls/src/groups/intents.rs @@ -33,6 +33,7 @@ use crate::{ }, types::Address, verified_key_package_v2::{KeyPackageVerificationError, VerifiedKeyPackageV2}, + XmtpOpenMlsProvider, }; use super::{ @@ -58,16 +59,17 @@ pub enum IntentError { impl MlsGroup { pub fn queue_intent( &self, + provider: &XmtpOpenMlsProvider, intent_kind: IntentKind, intent_data: Vec, ) -> Result { - self.context().store().transaction(|provider| { + self.context().store().transaction(provider, |provider| { let conn = provider.conn_ref(); self.queue_intent_with_conn(conn, intent_kind, intent_data) }) } - pub fn queue_intent_with_conn( + fn queue_intent_with_conn( &self, conn: &DbConnection, intent_kind: IntentKind, @@ -800,7 +802,7 @@ pub(crate) mod tests { // Client B sends a message to Client A let groups_b = client_b - .sync_welcomes(&client_b.store().conn().unwrap()) + .sync_welcomes(&client_b.mls_provider().unwrap()) .await .unwrap(); assert_eq!(groups_b.len(), 1); diff --git a/xmtp_mls/src/groups/mls_sync.rs b/xmtp_mls/src/groups/mls_sync.rs index 60a609cd4..91426988d 100644 --- a/xmtp_mls/src/groups/mls_sync.rs +++ b/xmtp_mls/src/groups/mls_sync.rs @@ -170,6 +170,7 @@ where let mls_provider = XmtpOpenMlsProvider::from(conn); tracing::info!( inbox_id = self.client.inbox_id(), + installation_id = %self.client.installation_id(), group_id = hex::encode(&self.group_id), current_epoch = self.load_mls_group(&mls_provider)?.epoch().as_u64(), "[{}] syncing group", @@ -177,6 +178,7 @@ where ); tracing::info!( inbox_id = self.client.inbox_id(), + installation_id = %self.client.installation_id(), group_id = hex::encode(&self.group_id), current_epoch = self.load_mls_group(&mls_provider)?.epoch().as_u64(), "current epoch for [{}] in sync() is Epoch: [{}]", @@ -363,7 +365,7 @@ where let group_epoch = openmls_group.epoch(); debug!( inbox_id = self.client.inbox_id(), - installation_id = hex::encode(self.client.installation_id()), + installation_id = %self.client.installation_id(), group_id = hex::encode(&self.group_id), current_epoch = openmls_group.epoch().as_u64(), msg_id, @@ -392,6 +394,7 @@ where if published_in_epoch_u64 != group_epoch_u64 { tracing::warn!( inbox_id = self.client.inbox_id(), + installation_id = %self.client.installation_id(), group_id = hex::encode(&self.group_id), current_epoch = openmls_group.epoch().as_u64(), msg_id, @@ -491,6 +494,7 @@ where tracing::info!( inbox_id = self.client.inbox_id(), + installation_id = %self.client.installation_id(), sender_inbox_id = sender_inbox_id, sender_installation_id = hex::encode(&sender_installation_id), group_id = hex::encode(&self.group_id), @@ -512,6 +516,8 @@ where tracing::info!( inbox_id = self.client.inbox_id(), sender_inbox_id = sender_inbox_id, + sender_installation_id = hex::encode(&sender_installation_id), + installation_id = %self.client.installation_id(), group_id = hex::encode(&self.group_id), current_epoch = openmls_group.epoch().as_u64(), msg_epoch, @@ -636,6 +642,7 @@ where tracing::info!( inbox_id = self.client.inbox_id(), sender_inbox_id = sender_inbox_id, + installation_id = %self.client.installation_id(), sender_installation_id = hex::encode(&sender_installation_id), group_id = hex::encode(&self.group_id), current_epoch = openmls_group.epoch().as_u64(), @@ -659,6 +666,7 @@ where tracing::info!( inbox_id = self.client.inbox_id(), sender_inbox_id = sender_inbox_id, + installation_id = %self.client.installation_id(), sender_installation_id = hex::encode(&sender_installation_id), group_id = hex::encode(&self.group_id), current_epoch = openmls_group.epoch().as_u64(), @@ -705,6 +713,7 @@ where .find_group_intent_by_payload_hash(sha256(envelope.data.as_slice())); tracing::info!( inbox_id = self.client.inbox_id(), + installation_id = %self.client.installation_id(), group_id = hex::encode(&self.group_id), current_epoch = openmls_group.epoch().as_u64(), msg_id = envelope.id, @@ -718,6 +727,7 @@ where let intent_id = intent.id; tracing::info!( inbox_id = self.client.inbox_id(), + installation_id = %self.client.installation_id(), group_id = hex::encode(&self.group_id), current_epoch = openmls_group.epoch().as_u64(), msg_id = envelope.id, @@ -752,6 +762,7 @@ where Ok(None) => { tracing::info!( inbox_id = self.client.inbox_id(), + installation_id = %self.client.installation_id(), group_id = hex::encode(&self.group_id), current_epoch = openmls_group.epoch().as_u64(), msg_id = envelope.id, @@ -769,9 +780,9 @@ where #[tracing::instrument(level = "trace", skip_all)] async fn consume_message( &self, + provider: &XmtpOpenMlsProvider, envelope: &GroupMessage, openmls_group: &mut OpenMlsGroup, - conn: &DbConnection, ) -> Result<(), GroupMessageProcessingError> { let msgv1 = match &envelope.version { Some(GroupMessageVersion::V1(value)) => value, @@ -784,12 +795,15 @@ where _ => EntityKind::Group, }; - let last_cursor = conn.get_last_cursor_for_id(&self.group_id, message_entity_kind)?; + let last_cursor = provider + .conn_ref() + .get_last_cursor_for_id(&self.group_id, message_entity_kind)?; tracing::info!("### last cursor --> [{:?}]", last_cursor); let should_skip_message = last_cursor > msgv1.id as i64; if should_skip_message { tracing::info!( inbox_id = "self.inbox_id()", + installation_id = %self.client.installation_id(), group_id = hex::encode(&self.group_id), "Message already processed: skipped msgId:[{}] entity kind:[{:?}] last cursor in db: [{}]", msgv1.id, @@ -798,19 +812,36 @@ where ); Err(GroupMessageProcessingError::AlreadyProcessed(msgv1.id)) } else { - self.client - .intents() - .process_for_id( - &msgv1.group_id, - EntityKind::Group, - msgv1.id, - |provider| async move { - self.process_message(openmls_group, &provider, msgv1, true) - .await?; - Ok::<(), GroupMessageProcessingError>(()) - }, - ) - .await?; + let cursor = &msgv1.id; + // Download all unread welcome messages and convert to groups. + // In a database transaction, increment the cursor for a given entity and + // apply the update after the provided `ProcessingFn` has completed successfully. + self.client.store().transaction_async(provider, |provider| async move { + let is_updated = + provider + .conn_ref() + .update_cursor(&msgv1.group_id, EntityKind::Group, *cursor as i64)?; + if !is_updated { + return Err(ProcessIntentError::AlreadyProcessed(*cursor).into()); + } + self.process_message(openmls_group, provider, msgv1, true).await?; + Ok::<_, GroupMessageProcessingError>(()) + }).await + .inspect(|_| { + tracing::info!( + "Transaction completed successfully: process for group [{}] envelope cursor[{}]", + hex::encode(&msgv1.group_id), + cursor + ); + }) + .inspect_err(|err| { + tracing::info!( + "Transaction failed: process for group [{}] envelope cursor [{}] error:[{}]", + hex::encode(&msgv1.group_id), + cursor, + err + ); + })?; Ok(()) } } @@ -828,7 +859,7 @@ where let result = retry_async!( Retry::default(), (async { - self.consume_message(&message, &mut openmls_group, provider.conn_ref()) + self.consume_message(provider, &message, &mut openmls_group) .await }) ); @@ -852,7 +883,13 @@ where if receive_errors.is_empty() { Ok(()) } else { - tracing::error!("Message processing errors: {:?}", receive_errors); + tracing::error!( + group_id = hex::encode(&self.group_id), + inbox_id = self.client.inbox_id(), + installation_id = hex::encode(self.client.installation_id()), + "Message processing errors: {:?}", + receive_errors + ); Err(GroupError::ReceiveErrors(receive_errors)) } } @@ -944,6 +981,7 @@ where intent.id, intent.kind = %intent.kind, inbox_id = self.client.inbox_id(), + installation_id = %self.client.installation_id(), group_id = hex::encode(&self.group_id), "intent {} has reached max publish attempts", intent.id); // TODO: Eventually clean up errored attempts @@ -974,7 +1012,7 @@ where )?; tracing::debug!( inbox_id = self.client.inbox_id(), - installation_id = hex::encode(self.client.installation_id()), + installation_id = %self.client.installation_id(), intent.id, intent.kind = %intent.kind, group_id = hex::encode(&self.group_id), @@ -992,7 +1030,7 @@ where intent.id, intent.kind = %intent.kind, inbox_id = self.client.inbox_id(), - installation_id = hex::encode(self.client.installation_id()), + installation_id = %self.client.installation_id(), group_id = hex::encode(&self.group_id), "[{}] published intent [{}] of type [{}]", self.client.inbox_id(), @@ -1007,7 +1045,7 @@ where Ok(None) => { tracing::info!( inbox_id = self.client.inbox_id(), - installation_id = hex::encode(self.client.installation_id()), + installation_id = %self.client.installation_id(), "Skipping intent because no publish data returned" ); let deleter: &dyn Delete = provider.conn_ref(); @@ -1148,7 +1186,7 @@ where if let Some(post_commit_data) = intent.post_commit_data { tracing::debug!( inbox_id = self.client.inbox_id(), - installation_id = hex::encode(self.client.installation_id()), + installation_id = %self.client.installation_id(), intent.id, intent.kind = %intent.kind, "taking post commit action" ); @@ -1216,13 +1254,13 @@ where debug!( inbox_id = self.client.inbox_id(), - installation_id = hex::encode(self.client.installation_id()), + installation_id = %self.client.installation_id(), "Adding missing installations {:?}", intent_data ); - let intent = self.queue_intent_with_conn( - provider.conn_ref(), + let intent = self.queue_intent( + provider, IntentKind::UpdateGroupMembership, intent_data.into(), )?; diff --git a/xmtp_mls/src/groups/mod.rs b/xmtp_mls/src/groups/mod.rs index ad9d92d34..f23bb8b6b 100644 --- a/xmtp_mls/src/groups/mod.rs +++ b/xmtp_mls/src/groups/mod.rs @@ -91,7 +91,7 @@ use crate::{ group::{ConversationType, GroupMembershipState, StoredGroup}, group_intent::IntentKind, group_message::{DeliveryStatus, GroupMessageKind, MsgQueryArgs, StoredGroupMessage}, - sql_key_store, + sql_key_store, StorageError, }, subscriptions::{LocalEventError, LocalEvents}, utils::{id::calculate_message_id, time::now_ns}, @@ -319,8 +319,8 @@ impl MlsGroup { /// Instantiate a new [`XmtpOpenMlsProvider`] pulling a connection from the database. /// prefer to use an already-instantiated mls provider if possible. - pub fn mls_provider(&self) -> Result { - Ok(self.context().mls_provider()?) + pub fn mls_provider(&self) -> Result { + self.context().mls_provider() } // Load the stored OpenMLS group from the OpenMLS provider's keystore @@ -338,15 +338,14 @@ impl MlsGroup { } // Create a new group and save it to the DB - pub fn create_and_insert( + pub(crate) fn create_and_insert( client: Arc, + provider: &XmtpOpenMlsProvider, membership_state: GroupMembershipState, permissions_policy_set: PolicySet, opts: GroupMetadataOptions, ) -> Result { let context = client.context(); - let conn = context.store().conn()?; - let provider = XmtpOpenMlsProvider::new(conn); let creator_inbox_id = context.inbox_id(); let protected_metadata = build_protected_metadata_extension(creator_inbox_id, ConversationType::Group)?; @@ -361,7 +360,7 @@ impl MlsGroup { )?; let mls_group = OpenMlsGroup::new( - &provider, + provider, &context.identity.installation_keys, &group_config, CredentialWithKey { @@ -388,14 +387,13 @@ impl MlsGroup { } // Create a new DM and save it to the DB - pub fn create_dm_and_insert( + pub(crate) fn create_dm_and_insert( + provider: &XmtpOpenMlsProvider, client: Arc, membership_state: GroupMembershipState, dm_target_inbox_id: InboxId, ) -> Result { let context = client.context(); - let conn = context.store().conn()?; - let provider = XmtpOpenMlsProvider::new(conn); let protected_metadata = build_dm_protected_metadata_extension(context.inbox_id(), dm_target_inbox_id.clone())?; let mutable_metadata = @@ -608,9 +606,8 @@ impl MlsGroup { self.maybe_update_installations(provider, update_interval_ns) .await?; - let message_id = self.prepare_message(message, provider.conn_ref(), |now| { - Self::into_envelope(message, now) - }); + let message_id = + self.prepare_message(message, provider, |now| Self::into_envelope(message, now)); self.sync_until_last_intent_resolved(provider).await?; @@ -648,9 +645,9 @@ impl MlsGroup { /// Send a message, optimistically returning the ID of the message before the result of a message publish. pub fn send_message_optimistic(&self, message: &[u8]) -> Result, GroupError> { - let conn = self.context().store().conn()?; + let provider = self.mls_provider()?; let message_id = - self.prepare_message(message, &conn, |now| Self::into_envelope(message, now))?; + self.prepare_message(message, &provider, |now| Self::into_envelope(message, now))?; Ok(message_id) } @@ -664,7 +661,7 @@ impl MlsGroup { fn prepare_message( &self, message: &[u8], - conn: &DbConnection, + provider: &XmtpOpenMlsProvider, envelope: F, ) -> Result, GroupError> where @@ -678,7 +675,7 @@ impl MlsGroup { .map_err(GroupError::EncodeError)?; let intent_data: Vec = SendMessageIntentData::new(encoded_envelope).into(); - self.queue_intent_with_conn(conn, IntentKind::SendMessage, intent_data)?; + self.queue_intent(provider, IntentKind::SendMessage, intent_data)?; // store this unpublished message locally before sending let message_id = calculate_message_id(&self.group_id, message, &now.to_string()); @@ -692,7 +689,7 @@ impl MlsGroup { sender_inbox_id: self.context().inbox_id().to_string(), delivery_status: DeliveryStatus::Unpublished, }; - group_message.store(conn)?; + group_message.store(provider.conn_ref())?; Ok(message_id) } @@ -730,8 +727,9 @@ impl MlsGroup { .api() .get_inbox_ids(account_addresses.clone()) .await?; + let provider = self.mls_provider()?; // get current number of users in group - let member_count = self.members().await?.len(); + let member_count = self.members_with_provider(&provider).await?.len(); if member_count + inbox_id_map.len() > MAX_GROUP_SIZE { return Err(GroupError::UserLimitExceeded); } @@ -745,8 +743,11 @@ impl MlsGroup { )); } - self.add_members_by_inbox_id(&inbox_id_map.into_values().collect::>()) - .await + self.add_members_by_inbox_id_with_provider( + &provider, + &inbox_id_map.into_values().collect::>(), + ) + .await } #[tracing::instrument(level = "trace", skip_all)] @@ -755,9 +756,19 @@ impl MlsGroup { inbox_ids: &[S], ) -> Result<(), GroupError> { let provider = self.client.mls_provider()?; + self.add_members_by_inbox_id_with_provider(&provider, inbox_ids) + .await + } + + #[tracing::instrument(level = "trace", skip_all)] + pub async fn add_members_by_inbox_id_with_provider>( + &self, + provider: &XmtpOpenMlsProvider, + inbox_ids: &[S], + ) -> Result<(), GroupError> { let ids = inbox_ids.iter().map(AsRef::as_ref).collect::>(); let intent_data = self - .get_membership_update_intent(&provider, ids.as_slice(), &[]) + .get_membership_update_intent(provider, ids.as_slice(), &[]) .await?; // TODO:nm this isn't the best test for whether the request is valid @@ -768,13 +779,13 @@ impl MlsGroup { return Ok(()); } - let intent = self.queue_intent_with_conn( - provider.conn_ref(), + let intent = self.queue_intent( + provider, IntentKind::UpdateGroupMembership, intent_data.into(), )?; - self.sync_until_intent_resolved(&provider, intent.id).await + self.sync_until_intent_resolved(provider, intent.id).await } /// Removes members from the group by their account addresses. @@ -817,8 +828,8 @@ impl MlsGroup { .get_membership_update_intent(&provider, &[], inbox_ids) .await?; - let intent = self.queue_intent_with_conn( - provider.conn_ref(), + let intent = self.queue_intent( + &provider, IntentKind::UpdateGroupMembership, intent_data.into(), )?; @@ -835,7 +846,7 @@ impl MlsGroup { } let intent_data: Vec = UpdateMetadataIntentData::new_update_group_name(group_name).into(); - let intent = self.queue_intent(IntentKind::MetadataUpdate, intent_data)?; + let intent = self.queue_intent(&provider, IntentKind::MetadataUpdate, intent_data)?; self.sync_until_intent_resolved(&provider, intent.id).await } @@ -864,7 +875,7 @@ impl MlsGroup { ) .into(); - let intent = self.queue_intent(IntentKind::UpdatePermission, intent_data)?; + let intent = self.queue_intent(&provider, IntentKind::UpdatePermission, intent_data)?; self.sync_until_intent_resolved(&provider, intent.id).await } @@ -894,7 +905,7 @@ impl MlsGroup { } let intent_data: Vec = UpdateMetadataIntentData::new_update_group_description(group_description).into(); - let intent = self.queue_intent(IntentKind::MetadataUpdate, intent_data)?; + let intent = self.queue_intent(&provider, IntentKind::MetadataUpdate, intent_data)?; self.sync_until_intent_resolved(&provider, intent.id).await } @@ -924,7 +935,7 @@ impl MlsGroup { let intent_data: Vec = UpdateMetadataIntentData::new_update_group_image_url_square(group_image_url_square) .into(); - let intent = self.queue_intent(IntentKind::MetadataUpdate, intent_data)?; + let intent = self.queue_intent(&provider, IntentKind::MetadataUpdate, intent_data)?; self.sync_until_intent_resolved(&provider, intent.id).await } @@ -956,7 +967,7 @@ impl MlsGroup { } let intent_data: Vec = UpdateMetadataIntentData::new_update_group_pinned_frame_url(pinned_frame_url).into(); - let intent = self.queue_intent(IntentKind::MetadataUpdate, intent_data)?; + let intent = self.queue_intent(&provider, IntentKind::MetadataUpdate, intent_data)?; self.sync_until_intent_resolved(&provider, intent.id).await } @@ -1039,7 +1050,7 @@ impl MlsGroup { }; let intent_data: Vec = UpdateAdminListIntentData::new(intent_action_type, inbox_id).into(); - let intent = self.queue_intent(IntentKind::UpdateAdminList, intent_data)?; + let intent = self.queue_intent(&provider, IntentKind::UpdateAdminList, intent_data)?; self.sync_until_intent_resolved(&provider, intent.id).await } @@ -1104,9 +1115,9 @@ impl MlsGroup { /// Update this installation's leaf key in the group by creating a key update commit pub async fn key_update(&self) -> Result<(), GroupError> { - let intent = self.queue_intent(IntentKind::KeyUpdate, vec![])?; - self.sync_until_intent_resolved(&self.client.mls_provider()?, intent.id) - .await + let provider = self.client.mls_provider()?; + let intent = self.queue_intent(&provider, IntentKind::KeyUpdate, vec![])?; + self.sync_until_intent_resolved(&provider, intent.id).await } /// Checks if the the current user is active in the group. @@ -1134,8 +1145,7 @@ impl MlsGroup { } pub fn permissions(&self) -> Result { - let conn = self.context().store().conn()?; - let provider = XmtpOpenMlsProvider::new(conn); + let provider = self.mls_provider()?; let mls_group = self.load_mls_group(&provider)?; Ok(extract_group_permissions(&mls_group)?) @@ -1627,7 +1637,7 @@ pub(crate) mod tests { async fn receive_group_invite(client: &FullXmtpClient) -> MlsGroup { client - .sync_welcomes(&client.store().conn().unwrap()) + .sync_welcomes(&client.mls_provider().unwrap()) .await .unwrap(); let mut groups = client.find_groups(GroupQueryArgs::default()).unwrap(); @@ -1775,7 +1785,7 @@ pub(crate) mod tests { // Get bola's version of the same group let bola_groups = bola - .sync_welcomes(&bola.store().conn().unwrap()) + .sync_welcomes(&bola.mls_provider().unwrap()) .await .unwrap(); let bola_group = bola_groups.first().unwrap(); @@ -1834,7 +1844,7 @@ pub(crate) mod tests { // Get bola's version of the same group let bola_groups = bola - .sync_welcomes(&bola.store().conn().unwrap()) + .sync_welcomes(&bola.mls_provider().unwrap()) .await .unwrap(); let bola_group = bola_groups.first().unwrap(); @@ -1944,7 +1954,7 @@ pub(crate) mod tests { force_add_member(&alix, &bo, &alix_group, &mut mls_group, &provider).await; // Bo should not be able to actually read this group - bo.sync_welcomes(&bo.store().conn().unwrap()).await.unwrap(); + bo.sync_welcomes(&bo.mls_provider().unwrap()).await.unwrap(); let groups = bo.find_groups(GroupQueryArgs::default()).unwrap(); assert_eq!(groups.len(), 0); assert_logged!("failed to create group from welcome", 1); @@ -2072,7 +2082,7 @@ pub(crate) mod tests { group.send_message(b"hello").await.expect("send message"); bola_client - .sync_welcomes(&bola_client.store().conn().unwrap()) + .sync_welcomes(&bola_client.mls_provider().unwrap()) .await .unwrap(); let bola_groups = bola_client.find_groups(GroupQueryArgs::default()).unwrap(); @@ -2429,7 +2439,7 @@ pub(crate) mod tests { .add_members_by_inbox_id(&[bola.inbox_id()]) .await .unwrap(); - bola.sync_welcomes(&bola.store().conn().unwrap()) + bola.sync_welcomes(&bola.mls_provider().unwrap()) .await .unwrap(); @@ -2600,7 +2610,7 @@ pub(crate) mod tests { .add_members(&[bola_wallet.get_address()]) .await .unwrap(); - bola.sync_welcomes(&bola.store().conn().unwrap()) + bola.sync_welcomes(&bola.mls_provider().unwrap()) .await .unwrap(); let bola_groups = bola.find_groups(GroupQueryArgs::default()).unwrap(); @@ -2682,7 +2692,7 @@ pub(crate) mod tests { .add_members(&[bola_wallet.get_address()]) .await .unwrap(); - bola.sync_welcomes(&bola.store().conn().unwrap()) + bola.sync_welcomes(&bola.mls_provider().unwrap()) .await .unwrap(); let bola_groups = bola.find_groups(GroupQueryArgs::default()).unwrap(); @@ -2700,7 +2710,7 @@ pub(crate) mod tests { assert!(super_admin_list.contains(&amal.inbox_id().to_string())); // Verify that bola can not add caro because they are not an admin - bola.sync_welcomes(&bola.store().conn().unwrap()) + bola.sync_welcomes(&bola.mls_provider().unwrap()) .await .unwrap(); let bola_groups = bola.find_groups(GroupQueryArgs::default()).unwrap(); @@ -2769,7 +2779,7 @@ pub(crate) mod tests { .contains(&bola.inbox_id().to_string())); // Verify that bola can not add charlie because they are not an admin - bola.sync_welcomes(&bola.store().conn().unwrap()) + bola.sync_welcomes(&bola.mls_provider().unwrap()) .await .unwrap(); let bola_groups = bola.find_groups(GroupQueryArgs::default()).unwrap(); @@ -2800,7 +2810,7 @@ pub(crate) mod tests { .add_members_by_inbox_id(&[bola.inbox_id()]) .await .unwrap(); - bola.sync_welcomes(&bola.store().conn().unwrap()) + bola.sync_welcomes(&bola.mls_provider().unwrap()) .await .unwrap(); let bola_groups = bola.find_groups(GroupQueryArgs::default()).unwrap(); @@ -2818,7 +2828,7 @@ pub(crate) mod tests { assert!(super_admin_list.contains(&amal.inbox_id().to_string())); // Verify that bola can not add caro as an admin because they are not a super admin - bola.sync_welcomes(&bola.store().conn().unwrap()) + bola.sync_welcomes(&bola.mls_provider().unwrap()) .await .unwrap(); let bola_groups = bola.find_groups(GroupQueryArgs::default()).unwrap(); @@ -3012,7 +3022,7 @@ pub(crate) mod tests { // Bola syncs groups - this will decrypt the Welcome, identify who added Bola // and then store that value on the group and insert into the database let bola_groups = bola - .sync_welcomes(&bola.store().conn().unwrap()) + .sync_welcomes(&bola.mls_provider().unwrap()) .await .unwrap(); @@ -3081,7 +3091,7 @@ pub(crate) mod tests { .unwrap(); // Step 3: Verify that Bola can update the group name, and amal sees the update - bola.sync_welcomes(&bola.store().conn().unwrap()) + bola.sync_welcomes(&bola.mls_provider().unwrap()) .await .unwrap(); let bola_groups = bola.find_groups(GroupQueryArgs::default()).unwrap(); @@ -3149,7 +3159,7 @@ pub(crate) mod tests { // Step 3: Bola attemps to add Caro, but fails because group is admin only let caro = ClientBuilder::new_test_client(&generate_local_wallet()).await; - bola.sync_welcomes(&bola.store().conn().unwrap()) + bola.sync_welcomes(&bola.mls_provider().unwrap()) .await .unwrap(); let bola_groups = bola.find_groups(GroupQueryArgs::default()).unwrap(); @@ -3294,7 +3304,7 @@ pub(crate) mod tests { // Amal creates a dm group targetting bola let amal_dm = amal - .create_dm_by_inbox_id(bola.inbox_id().to_string()) + .create_dm_by_inbox_id(&amal.mls_provider().unwrap(), bola.inbox_id().to_string()) .await .unwrap(); @@ -3312,7 +3322,7 @@ pub(crate) mod tests { assert_eq!(members.len(), 2); // Bola can message amal - let _ = bola.sync_welcomes(&bola.store().conn().unwrap()).await; + let _ = bola.sync_welcomes(&bola.mls_provider().unwrap()).await; let bola_groups = bola.find_groups(GroupQueryArgs::default()).unwrap(); let bola_dm: &MlsGroup<_> = bola_groups.first().unwrap(); @@ -3428,7 +3438,7 @@ pub(crate) mod tests { let alix_message = vec![1]; alix_group.send_message(&alix_message).await.unwrap(); bo_client - .sync_welcomes(&bo_client.store().conn().unwrap()) + .sync_welcomes(&bo_client.mls_provider().unwrap()) .await .unwrap(); let bo_groups = bo_client.find_groups(GroupQueryArgs::default()).unwrap(); @@ -3552,7 +3562,11 @@ pub(crate) mod tests { } group - .queue_intent(IntentKind::UpdateGroupMembership, intent_data.into()) + .queue_intent( + provider, + IntentKind::UpdateGroupMembership, + intent_data.into(), + ) .unwrap(); } @@ -3711,7 +3725,7 @@ pub(crate) mod tests { .await .unwrap(); - bola.sync_welcomes(&bola.store().conn().unwrap()) + bola.sync_welcomes(&bola.mls_provider().unwrap()) .await .unwrap(); let bola_groups = bola.find_groups(GroupQueryArgs::default()).unwrap(); @@ -3732,7 +3746,7 @@ pub(crate) mod tests { .await .unwrap(); - caro.sync_welcomes(&caro.store().conn().unwrap()) + caro.sync_welcomes(&caro.mls_provider().unwrap()) .await .unwrap(); let caro_groups = caro.find_groups(GroupQueryArgs::default()).unwrap(); @@ -3765,7 +3779,7 @@ pub(crate) mod tests { .await .unwrap(); - bo.sync_welcomes(&bo.store().conn().unwrap()).await.unwrap(); + bo.sync_welcomes(&bo.mls_provider().unwrap()).await.unwrap(); let bo_groups = bo.find_groups(GroupQueryArgs::default()).unwrap(); let bo_group = bo_groups.first().unwrap(); diff --git a/xmtp_mls/src/groups/scoped_client.rs b/xmtp_mls/src/groups/scoped_client.rs index 808fee0e0..557761f6e 100644 --- a/xmtp_mls/src/groups/scoped_client.rs +++ b/xmtp_mls/src/groups/scoped_client.rs @@ -3,9 +3,9 @@ use crate::{ api::ApiClientWrapper, client::{ClientError, XmtpMlsLocalContext}, identity_updates::{InstallationDiff, InstallationDiffError}, - intents::Intents, - storage::{DbConnection, EncryptedMessageStore}, + storage::{DbConnection, EncryptedMessageStore, StorageError}, subscriptions::LocalEvents, + types::InstallationId, verified_key_package_v2::VerifiedKeyPackageV2, xmtp_openmls_provider::XmtpOpenMlsProvider, Client, @@ -37,16 +37,14 @@ pub trait LocalScopedGroupClient: Send + Sync + Sized { self.context_ref().inbox_id() } - fn installation_id(&self) -> &[u8] { + fn installation_id(&self) -> InstallationId { self.context_ref().installation_public_key() } - fn mls_provider(&self) -> Result { + fn mls_provider(&self) -> Result { self.context_ref().mls_provider() } - fn intents(&self) -> &Arc; - fn context_ref(&self) -> &Arc; fn context(&self) -> Arc { @@ -105,16 +103,14 @@ pub trait ScopedGroupClient: Sized { self.context_ref().inbox_id() } - fn installation_id(&self) -> &[u8] { + fn installation_id(&self) -> InstallationId { self.context_ref().installation_public_key() } - fn mls_provider(&self) -> Result { + fn mls_provider(&self) -> Result { self.context_ref().mls_provider() } - fn intents(&self) -> &Arc; - fn context_ref(&self) -> &Arc; fn context(&self) -> Arc { @@ -173,10 +169,6 @@ where Client::::context(self) } - fn intents(&self) -> &Arc { - crate::Client::::intents(self) - } - fn history_sync_url(&self) -> &Option { &self.history_sync_url } @@ -264,10 +256,6 @@ where (**self).store() } - fn intents(&self) -> &Arc { - (**self).intents() - } - fn inbox_id(&self) -> InboxIdRef<'_> { (**self).inbox_id() } @@ -276,7 +264,7 @@ where (**self).context_ref() } - fn mls_provider(&self) -> Result { + fn mls_provider(&self) -> Result { (**self).mls_provider() } @@ -358,10 +346,6 @@ where (**self).history_sync_url() } - fn intents(&self) -> &Arc { - (**self).intents() - } - fn inbox_id(&self) -> InboxIdRef<'_> { (**self).inbox_id() } @@ -370,7 +354,7 @@ where (**self).context_ref() } - fn mls_provider(&self) -> Result { + fn mls_provider(&self) -> Result { (**self).mls_provider() } diff --git a/xmtp_mls/src/groups/subscriptions.rs b/xmtp_mls/src/groups/subscriptions.rs index 2caf9bec9..fbaaa20d6 100644 --- a/xmtp_mls/src/groups/subscriptions.rs +++ b/xmtp_mls/src/groups/subscriptions.rs @@ -14,6 +14,7 @@ use crate::storage::refresh_state::EntityKind; use crate::storage::StorageError; use crate::subscriptions::MessagesStreamInfo; use crate::subscriptions::SubscribeError; +use crate::XmtpOpenMlsProvider; use crate::{retry::Retry, retry_async}; use prost::Message; use xmtp_proto::xmtp::mls::api::v1::GroupMessage; @@ -22,6 +23,7 @@ impl MlsGroup { /// Internal stream processing function pub(crate) async fn process_stream_entry( &self, + provider: &XmtpOpenMlsProvider, envelope: GroupMessage, ) -> Result { let msgv1 = extract_message_v1(envelope)?; @@ -45,8 +47,8 @@ impl MlsGroup { let msgv1 = &msgv1; self.context() .store() - .transaction_async(|provider| async move { - let mut openmls_group = self.load_mls_group(&provider)?; + .transaction_async(provider, |provider| async move { + let mut openmls_group = self.load_mls_group(provider)?; // Attempt processing immediately, but fail if the message is not an Application Message // Returning an error should roll back the DB tx @@ -60,7 +62,7 @@ impl MlsGroup { openmls_group.epoch() ); - self.process_message(&mut openmls_group, &provider, msgv1, false) + self.process_message(&mut openmls_group, provider, msgv1, false) .await // NOTE: We want to make sure we retry an error in process_message .map_err(SubscribeError::ReceiveGroup) @@ -78,7 +80,7 @@ impl MlsGroup { ); // Swallow errors here, since another process may have successfully saved the message // to the DB - if let Err(err) = self.sync_with_conn(&self.client.mls_provider()?).await { + if let Err(err) = self.sync_with_conn(provider).await { tracing::warn!( inbox_id = self.client.inbox_id(), group_id = hex::encode(&self.group_id), @@ -108,10 +110,8 @@ impl MlsGroup { // Load the message from the DB to handle cases where it may have been already processed in // another thread - let new_message = self - .context() - .store() - .conn()? + let new_message = provider + .conn_ref() .get_group_message_by_timestamp(&self.group_id, created_ns as i64)? .ok_or(SubscribeError::GroupMessageNotFound)?; @@ -133,20 +133,21 @@ impl MlsGroup { /// Converts some `SubscribeError` variants to an Option, if they are inconsequential. pub async fn process_streamed_group_message( &self, + provider: &XmtpOpenMlsProvider, envelope_bytes: Vec, ) -> Result { let envelope = GroupMessage::decode(envelope_bytes.as_slice())?; - self.process_stream_entry(envelope).await + self.process_stream_entry(provider, envelope).await } - pub async fn stream( - &self, + pub async fn stream<'a>( + &'a self, ) -> Result< - impl Stream> + use<'_, ScopedClient>, + impl Stream> + use<'a, ScopedClient>, ClientError, > where - ::ApiClient: XmtpMlsStreams + 'static, + ::ApiClient: XmtpMlsStreams + 'a, { let group_list = HashMap::from([( self.group_id.clone(), @@ -180,14 +181,15 @@ impl MlsGroup { } /// Stream messages from groups in `group_id_to_info` +// TODO: Note when to use a None provider #[tracing::instrument(level = "debug", skip_all)] -pub(crate) async fn stream_messages( - client: &ScopedClient, +pub(crate) async fn stream_messages<'a, ScopedClient>( + client: &'a ScopedClient, group_id_to_info: Arc, MessagesStreamInfo>>, -) -> Result> + '_, ClientError> +) -> Result> + 'a, ClientError> where ScopedClient: ScopedGroupClient, - ::ApiClient: XmtpApi + XmtpMlsStreams + 'static, + ::ApiClient: XmtpApi + XmtpMlsStreams + 'a, { let filters: Vec = group_id_to_info .iter() @@ -200,6 +202,7 @@ where .then(move |res| { let group_id_to_info = group_id_to_info.clone(); async move { + let provider = client.mls_provider()?; let envelope = res.map_err(GroupError::from)?; let group_id = extract_group_id(&envelope)?; tracing::info!( @@ -214,7 +217,8 @@ where "Received message for a non-subscribed group".to_string(), ))?; let mls_group = MlsGroup::new(client, group_id, stream_info.convo_created_at_ns); - mls_group.process_stream_entry(envelope).await + + mls_group.process_stream_entry(&provider, envelope).await } }) .inspect(|e| { @@ -296,8 +300,9 @@ pub(crate) mod tests { let message = messages.first().unwrap(); let mut message_bytes: Vec = Vec::new(); message.encode(&mut message_bytes).unwrap(); + let provider = amal.mls_provider().unwrap(); let message_again = amal_group - .process_streamed_group_message(message_bytes) + .process_streamed_group_message(&provider, message_bytes) .await; if let Ok(message) = message_again { @@ -327,7 +332,7 @@ pub(crate) mod tests { // Get bola's version of the same group let bola_groups = bola - .sync_welcomes(&bola.store().conn().unwrap()) + .sync_welcomes(&bola.mls_provider().unwrap()) .await .unwrap(); let bola_group = Arc::new(bola_groups.first().unwrap().clone()); diff --git a/xmtp_mls/src/identity.rs b/xmtp_mls/src/identity.rs index 0b73a784d..d80ebf852 100644 --- a/xmtp_mls/src/identity.rs +++ b/xmtp_mls/src/identity.rs @@ -5,7 +5,6 @@ use crate::retry::RetryableError; use crate::storage::db_connection::DbConnection; use crate::storage::identity::StoredIdentity; use crate::storage::sql_key_store::{SqlKeyStore, SqlKeyStoreError, KEY_PACKAGE_REFERENCES}; -use crate::storage::EncryptedMessageStore; use crate::{ api::{ApiClientWrapper, WrappedApiError}, configuration::{CIPHERSUITE, GROUP_MEMBERSHIP_EXTENSION_ID, MUTABLE_METADATA_EXTENSION_ID}, @@ -111,14 +110,12 @@ impl IdentityStrategy { pub(crate) async fn initialize_identity( self, api_client: &ApiClientWrapper, - store: &EncryptedMessageStore, + provider: &XmtpOpenMlsProvider, scw_signature_verifier: impl SmartContractSignatureVerifier, ) -> Result { use IdentityStrategy::*; info!("Initializing identity"); - let conn = store.conn()?; - let provider = XmtpOpenMlsProvider::new(conn); let stored_identity: Option = provider .conn_ref() .fetch(&())? @@ -150,7 +147,7 @@ impl IdentityStrategy { nonce, legacy_signed_private_key, api_client, - &provider, + provider, scw_signature_verifier, ) .await diff --git a/xmtp_mls/src/intents.rs b/xmtp_mls/src/intents.rs index 7f54daa6d..6664152cf 100644 --- a/xmtp_mls/src/intents.rs +++ b/xmtp_mls/src/intents.rs @@ -8,13 +8,7 @@ //! Intents are written to local storage (SQLite), before being published to the delivery service via gRPC. An //! intent is fully resolved (success or failure) once it -use crate::{ - client::XmtpMlsLocalContext, - retry::RetryableError, - storage::{refresh_state::EntityKind, EncryptedMessageStore}, - xmtp_openmls_provider::XmtpOpenMlsProvider, -}; -use std::{future::Future, sync::Arc}; +use crate::retry::RetryableError; use thiserror::Error; #[derive(Debug, Error)] @@ -36,61 +30,3 @@ impl RetryableError for ProcessIntentError { } } } - -/// Intents holding the context of this Client -pub struct Intents { - pub(crate) context: Arc, -} - -impl Intents { - pub(crate) fn store(&self) -> &EncryptedMessageStore { - self.context.store() - } - - /// Download all unread welcome messages and convert to groups. - /// In a database transaction, increment the cursor for a given entity and - /// apply the update after the provided `ProcessingFn` has completed successfully. - pub(crate) async fn process_for_id( - &self, - entity_id: &[u8], - entity_kind: EntityKind, - cursor: u64, - process_envelope: ProcessingFn, - ) -> Result - where - Fut: Future>, - ProcessingFn: FnOnce(XmtpOpenMlsProvider) -> Fut, - ErrorType: From - + From - + From - + std::fmt::Display, - { - self.store() - .transaction_async(|provider| async move { - let is_updated = - provider - .conn_ref() - .update_cursor(entity_id, entity_kind, cursor as i64)?; - if !is_updated { - return Err(ProcessIntentError::AlreadyProcessed(cursor).into()); - } - process_envelope(provider).await - }) - .await - .inspect(|_| { - tracing::info!( - "Transaction completed successfully: process for entity [{:?}] envelope cursor[{}]", - entity_id, - cursor - ); - }) - .inspect_err(|err| { - tracing::info!( - "Transaction failed: process for entity [{:?}] envelope cursor[{}] error:[{}]", - entity_id, - cursor, - err - ); - }) - } -} diff --git a/xmtp_mls/src/storage/encrypted_store/db_connection.rs b/xmtp_mls/src/storage/encrypted_store/db_connection.rs index e2ef9a970..d0ef3942a 100644 --- a/xmtp_mls/src/storage/encrypted_store/db_connection.rs +++ b/xmtp_mls/src/storage/encrypted_store/db_connection.rs @@ -51,6 +51,8 @@ where self.inner.lock() } + /// Internal-only API to get the underlying `diesel::Connection` reference + /// without a scope pub(super) fn inner_ref(&self) -> Arc> { self.inner.clone() } diff --git a/xmtp_mls/src/storage/encrypted_store/mod.rs b/xmtp_mls/src/storage/encrypted_store/mod.rs index 58ff1eff8..9646a7611 100644 --- a/xmtp_mls/src/storage/encrypted_store/mod.rs +++ b/xmtp_mls/src/storage/encrypted_store/mod.rs @@ -190,6 +190,13 @@ pub mod private { Ok::<_, StorageError>(()) } + pub fn mls_provider( + &self, + ) -> Result::Connection>, StorageError> { + let conn = self.conn()?; + Ok(crate::xmtp_openmls_provider::XmtpOpenMlsProviderPrivate::new(conn)) + } + /// Pulls a new connection from the store pub fn conn( &self, @@ -198,6 +205,7 @@ pub mod private { } /// Start a new database transaction with the OpenMLS Provider from XMTP + /// with the provided connection /// # Arguments /// `fun`: Scoped closure providing a MLSProvider to carry out the transaction /// @@ -210,22 +218,25 @@ pub mod private { /// provider.conn().db_operation()?; /// }) /// ``` - pub fn transaction(&self, fun: F) -> Result + pub fn transaction( + &self, + provider: &XmtpOpenMlsProviderPrivate<::Connection>, + fun: F, + ) -> Result where F: FnOnce(&XmtpOpenMlsProviderPrivate<::Connection>) -> Result, E: From + From, { tracing::debug!("Transaction beginning"); - let connection = self.db.conn()?; { + let connection = provider.conn_ref(); let mut connection = connection.inner_mut_ref(); ::TransactionManager::begin_transaction(&mut *connection)?; } - let provider = XmtpOpenMlsProviderPrivate::new(connection); let conn = provider.conn_ref(); - match fun(&provider) { + match fun(provider) { Ok(value) => { conn.raw_query(|conn| { ::TransactionManager::commit_transaction(&mut *conn) @@ -260,27 +271,29 @@ pub mod private { /// provider.conn().db_operation()?; /// }).await /// ``` - pub async fn transaction_async(&self, fun: F) -> Result + pub async fn transaction_async<'a, T, F, E, Fut>( + &self, + provider: &'a XmtpOpenMlsProviderPrivate<::Connection>, + fun: F, + ) -> Result where - F: FnOnce(XmtpOpenMlsProviderPrivate<::Connection>) -> Fut, + F: FnOnce(&'a XmtpOpenMlsProviderPrivate<::Connection>) -> Fut, Fut: futures::Future>, E: From + From, { tracing::debug!("Transaction async beginning"); - let db_connection = self.db.conn()?; { - let mut connection = db_connection.inner_mut_ref(); + let connection = provider.conn_ref(); + let mut connection = connection.inner_mut_ref(); ::TransactionManager::begin_transaction(&mut *connection)?; } - let local_connection = db_connection.inner_ref(); - let provider = XmtpOpenMlsProviderPrivate::new(db_connection); - // the other connection is dropped in the closure // ensuring we have only one strong reference let result = fun(provider).await; + let local_connection = provider.conn_ref().inner_ref(); if Arc::strong_count(&local_connection) > 1 { tracing::warn!( - "More than 1 strong connection references still exist during transaction" + "More than 1 strong connection references still exist during async transaction" ); } @@ -467,7 +480,7 @@ pub(crate) mod tests { identity::StoredIdentity, }, utils::test::{rand_vec, tmp_path}, - Fetch, Store, StreamHandle as _, + Fetch, Store, StreamHandle as _, XmtpOpenMlsProvider, }; /// Test harness that loads an Ephemeral store. @@ -651,11 +664,11 @@ pub(crate) mod tests { .unwrap(); let barrier = Arc::new(Barrier::new(2)); - + let provider = XmtpOpenMlsProvider::new(store.conn().unwrap()); let store_pointer = store.clone(); let barrier_pointer = barrier.clone(); let handle = std::thread::spawn(move || { - store_pointer.transaction(|provider| { + store_pointer.transaction(&provider, |provider| { let conn1 = provider.conn_ref(); StoredIdentity::new("correct".to_string(), rand_vec(), rand_vec()) .store(conn1) @@ -669,20 +682,22 @@ pub(crate) mod tests { }); let store_pointer = store.clone(); + let provider = XmtpOpenMlsProvider::new(store.conn().unwrap()); let handle2 = std::thread::spawn(move || { barrier.wait(); - let result = store_pointer.transaction(|provider| -> Result<(), anyhow::Error> { - let connection = provider.conn_ref(); - let group = StoredGroup::new( - b"should not exist".to_vec(), - 0, - GroupMembershipState::Allowed, - "goodbye".to_string(), - None, - ); - group.store(connection)?; - Ok(()) - }); + let result = + store_pointer.transaction(&provider, |provider| -> Result<(), anyhow::Error> { + let connection = provider.conn_ref(); + let group = StoredGroup::new( + b"should not exist".to_vec(), + 0, + GroupMembershipState::Allowed, + "goodbye".to_string(), + None, + ); + group.store(connection)?; + Ok(()) + }); barrier.wait(); result }); @@ -718,10 +733,10 @@ pub(crate) mod tests { .unwrap(); let store_pointer = store.clone(); - + let provider = XmtpOpenMlsProvider::new(store_pointer.conn().unwrap()); let handle = crate::spawn(None, async move { store_pointer - .transaction_async(|provider| async move { + .transaction_async(&provider, |provider| async move { let conn1 = provider.conn_ref(); StoredIdentity::new("crab".to_string(), rand_vec(), rand_vec()) .store(conn1) diff --git a/xmtp_mls/src/storage/encrypted_store/refresh_state.rs b/xmtp_mls/src/storage/encrypted_store/refresh_state.rs index 34efa6220..f5cf0ba33 100644 --- a/xmtp_mls/src/storage/encrypted_store/refresh_state.rs +++ b/xmtp_mls/src/storage/encrypted_store/refresh_state.rs @@ -90,13 +90,13 @@ impl DbConnection { } } - pub fn update_cursor( + pub fn update_cursor>( &self, - entity_id: &[u8], + entity_id: Id, entity_kind: EntityKind, cursor: i64, ) -> Result { - let state: Option = self.get_refresh_state(entity_id, entity_kind)?; + let state: Option = self.get_refresh_state(&entity_id, entity_kind)?; match state { Some(state) => { use super::schema::refresh_state::dsl; @@ -110,7 +110,7 @@ impl DbConnection { } None => Err(StorageError::NotFound(format!( "state for entity ID {} with kind {:?}", - hex::encode(entity_id), + hex::encode(entity_id.as_ref()), entity_kind ))), } diff --git a/xmtp_mls/src/subscriptions.rs b/xmtp_mls/src/subscriptions.rs index 9a89fb014..b14a9291c 100644 --- a/xmtp_mls/src/subscriptions.rs +++ b/xmtp_mls/src/subscriptions.rs @@ -12,7 +12,10 @@ use xmtp_proto::{api_client::XmtpMlsStreams, xmtp::mls::api::v1::WelcomeMessage} use crate::{ client::{extract_welcome_message, ClientError}, - groups::{mls_sync::GroupMessageProcessingError, subscriptions, GroupError, MlsGroup}, + groups::{ + group_metadata::GroupMetadata, mls_sync::GroupMessageProcessingError, + scoped_client::ScopedGroupClient as _, subscriptions, GroupError, MlsGroup, + }, preferences::UserPreferenceUpdate, retry::{Retry, RetryableError}, retry_async, retryable, @@ -22,7 +25,7 @@ use crate::{ group_message::StoredGroupMessage, StorageError, }, - Client, XmtpApi, + Client, XmtpApi, XmtpOpenMlsProvider, }; use thiserror::Error; @@ -223,6 +226,7 @@ where { async fn process_streamed_welcome( &self, + provider: &XmtpOpenMlsProvider, welcome: WelcomeMessage, ) -> Result, ClientError> { let welcome_v1 = extract_welcome_message(welcome)?; @@ -236,10 +240,10 @@ where let welcome_v1 = &welcome_v1; self.context .store() - .transaction_async(|provider| async move { + .transaction_async(provider, |provider| async move { MlsGroup::create_from_encrypted_welcome( Arc::new(self.clone()), - &provider, + provider, welcome_v1.hpke_public_key.as_slice(), &welcome_v1.data, welcome_v1.id as i64, @@ -251,7 +255,7 @@ where ); if let Some(err) = creation_result.as_ref().err() { - let conn = self.context.store().conn()?; + let conn = provider.conn_ref(); let result = conn.find_group_by_welcome_id(welcome_v1.id as i64); match result { Ok(Some(group)) => { @@ -276,71 +280,81 @@ where &self, envelope_bytes: Vec, ) -> Result, ClientError> { + let provider = self.mls_provider()?; let envelope = WelcomeMessage::decode(envelope_bytes.as_slice()) .map_err(|e| ClientError::Generic(e.to_string()))?; - let welcome = self.process_streamed_welcome(envelope).await?; + let welcome = self.process_streamed_welcome(&provider, envelope).await?; Ok(welcome) } #[tracing::instrument(level = "debug", skip_all)] - pub async fn stream_conversations( - &self, + pub async fn stream_conversations<'a>( + &'a self, conversation_type: Option, - ) -> Result, SubscribeError>> + '_, ClientError> + ) -> Result, SubscribeError>> + 'a, ClientError> where ApiClient: XmtpMlsStreams, { - let event_queue = tokio_stream::wrappers::BroadcastStream::new( - self.local_events.subscribe(), - ) - .filter_map(|event| async { - crate::optify!(event, "Missed messages due to event queue lag") - .and_then(LocalEvents::group_filter) - .map(Result::Ok) - }); - - // Helper function for filtering Dm groups - let filter_group = move |group: Result, ClientError>| { - let conversation_type = &conversation_type; - // take care of any possible errors - let result = || -> Result<_, _> { - let group = group?; - let provider = group.client.context().mls_provider()?; - let metadata = group.metadata(&provider)?; - Ok((metadata, group)) - }; - let filtered = result().map(|(metadata, group)| { - conversation_type - .map_or(true, |ct| ct == metadata.conversation_type) - .then_some(group) - }); - futures::future::ready(filtered.transpose()) - }; - let installation_key = self.installation_public_key(); let id_cursor = 0; tracing::info!(inbox_id = self.inbox_id(), "Setting up conversation stream"); let subscription = self .api_client - .subscribe_welcome_messages(installation_key.into(), Some(id_cursor)) - .await?; + .subscribe_welcome_messages(installation_key.as_ref(), Some(id_cursor)) + .await? + .map(WelcomeOrGroup::::Welcome); + + let event_queue = + tokio_stream::wrappers::BroadcastStream::new(self.local_events.subscribe()) + .filter_map(|event| async { + crate::optify!(event, "Missed messages due to event queue lag") + .and_then(LocalEvents::group_filter) + .map(Result::Ok) + }) + .map(WelcomeOrGroup::::Group); + + let stream = futures::stream::select(event_queue, subscription); + let stream = stream.filter_map(move |group_or_welcome| async move { + tracing::info!( + inbox_id = self.inbox_id(), + installation_id = %self.installation_id(), + "Received conversation streaming payload" + ); + let filtered = self.process_streamed_convo(group_or_welcome).await; + let filtered = filtered.map(|(metadata, group)| { + conversation_type + .map_or(true, |ct| ct == metadata.conversation_type) + .then_some(group) + }); + filtered.transpose() + }); - let stream = subscription - .map(|welcome| async { - tracing::info!( - inbox_id = self.inbox_id(), - "Received conversation streaming payload" - ); - self.process_streamed_welcome(welcome?).await - }) - .filter_map(|v| async { Some(v.await) }); + Ok(stream) + } - Ok(futures::stream::select(stream, event_queue).filter_map(filter_group)) + async fn process_streamed_convo( + &self, + welcome_or_group: WelcomeOrGroup, + ) -> Result<(GroupMetadata, MlsGroup>), SubscribeError> { + let provider = self.mls_provider()?; + let group = match welcome_or_group { + WelcomeOrGroup::Welcome(welcome) => { + self.process_streamed_welcome(&provider, welcome?).await? + } + WelcomeOrGroup::Group(group) => group?, + }; + let metadata = group.metadata(provider)?; + Ok((metadata, group)) } } +enum WelcomeOrGroup { + Group(Result>, SubscribeError>), + Welcome(Result), +} + impl Client where ApiClient: XmtpApi + XmtpMlsStreams + Send + Sync + 'static, @@ -377,17 +391,19 @@ where conversation_type = ?conversation_type, "stream all messages" ); - - let conn = self.store().conn()?; - self.sync_welcomes(&conn).await?; - - let mut group_id_to_info = self - .store() - .conn()? - .find_groups(GroupQueryArgs::default().maybe_conversation_type(conversation_type))? - .into_iter() - .map(Into::into) - .collect::, MessagesStreamInfo>>(); + let mut group_id_to_info = async { + let provider = self.mls_provider()?; + self.sync_welcomes(&provider).await?; + + let group_id_to_info = provider + .conn_ref() + .find_groups(GroupQueryArgs::default().maybe_conversation_type(conversation_type))? + .into_iter() + .map(Into::into) + .collect::, MessagesStreamInfo>>(); + Ok::<_, ClientError>(group_id_to_info) + } + .await?; let stream = async_stream::stream! { let messages_stream = subscriptions::stream_messages( @@ -586,7 +602,7 @@ pub(crate) mod tests { .await .unwrap(); let bob_group = bob - .sync_welcomes(&bob.store().conn().unwrap()) + .sync_welcomes(&bob.mls_provider().unwrap()) .await .unwrap(); let bob_group = bob_group.first().unwrap(); @@ -895,7 +911,7 @@ pub(crate) mod tests { } // Verify syncing welcomes while streaming causes no issues - alix.sync_welcomes(&alix.store().conn().unwrap()) + alix.sync_welcomes(&alix.mls_provider().unwrap()) .await .unwrap(); let find_groups_results = alix.find_groups(GroupQueryArgs::default()).unwrap(); @@ -930,7 +946,7 @@ pub(crate) mod tests { }, ); - alix.create_dm_by_inbox_id(bo.inbox_id().to_string()) + alix.create_dm_by_inbox_id(&alix.mls_provider().unwrap(), bo.inbox_id().to_string()) .await .unwrap(); @@ -980,7 +996,7 @@ pub(crate) mod tests { let result = notify.wait_for_delivery().await; assert!(result.is_err(), "Stream unexpectedly received a Group"); - alix.create_dm_by_inbox_id(bo.inbox_id().to_string()) + alix.create_dm_by_inbox_id(&alix.mls_provider().unwrap(), bo.inbox_id().to_string()) .await .unwrap(); notify.wait_for_delivery().await.unwrap(); @@ -1003,7 +1019,7 @@ pub(crate) mod tests { notify_pointer.notify_one(); }); - alix.create_dm_by_inbox_id(bo.inbox_id().to_string()) + alix.create_dm_by_inbox_id(&alix.mls_provider().unwrap(), bo.inbox_id().to_string()) .await .unwrap(); notify.wait_for_delivery().await.unwrap(); @@ -1013,7 +1029,7 @@ pub(crate) mod tests { } let dm = bo - .create_dm_by_inbox_id(alix.inbox_id().to_string()) + .create_dm_by_inbox_id(&bo.mls_provider().unwrap(), alix.inbox_id().to_string()) .await .unwrap(); dm.add_members_by_inbox_id(&[alix.inbox_id()]) @@ -1057,7 +1073,7 @@ pub(crate) mod tests { .unwrap(); let alix_dm = alix - .create_dm_by_inbox_id(bo.inbox_id().to_string()) + .create_dm_by_inbox_id(&alix.mls_provider().unwrap(), bo.inbox_id().to_string()) .await .unwrap(); diff --git a/xmtp_mls/src/types.rs b/xmtp_mls/src/types.rs index 0a73a89b1..5a97a0ca3 100644 --- a/xmtp_mls/src/types.rs +++ b/xmtp_mls/src/types.rs @@ -1,2 +1,86 @@ pub type Address = String; -pub type InstallationId = String; + +use std::fmt; + +#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] +pub struct InstallationId([u8; 32]); + +impl fmt::Display for InstallationId { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", hex::encode(self.0)) + } +} + +impl std::ops::Deref for InstallationId { + type Target = [u8; 32]; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl AsRef<[u8]> for InstallationId { + fn as_ref(&self) -> &[u8] { + &self.0 + } +} + +impl From for Vec { + fn from(value: InstallationId) -> Self { + value.0.to_vec() + } +} + +impl From<[u8; 32]> for InstallationId { + fn from(value: [u8; 32]) -> Self { + InstallationId(value) + } +} + +impl PartialEq> for InstallationId { + fn eq(&self, other: &Vec) -> bool { + self.0.eq(&other[..]) + } +} + +impl PartialEq for Vec { + fn eq(&self, other: &InstallationId) -> bool { + other.0.eq(&self[..]) + } +} + +impl PartialEq<&Vec> for InstallationId { + fn eq(&self, other: &&Vec) -> bool { + self.0.eq(&other[..]) + } +} + +impl PartialEq for &Vec { + fn eq(&self, other: &InstallationId) -> bool { + other.0.eq(&self[..]) + } +} + +impl PartialEq<[u8]> for InstallationId { + fn eq(&self, other: &[u8]) -> bool { + self.0.eq(other) + } +} + +impl PartialEq for [u8] { + fn eq(&self, other: &InstallationId) -> bool { + other.0.eq(self) + } +} + +impl PartialEq<[u8; 32]> for InstallationId { + fn eq(&self, other: &[u8; 32]) -> bool { + self.0.eq(other) + } +} + +impl PartialEq for [u8; 32] { + fn eq(&self, other: &InstallationId) -> bool { + other.0.eq(&self[..]) + } +} diff --git a/xmtp_mls/src/xmtp_openmls_provider.rs b/xmtp_mls/src/xmtp_openmls_provider.rs index 77dd51494..a5597ee31 100644 --- a/xmtp_mls/src/xmtp_openmls_provider.rs +++ b/xmtp_mls/src/xmtp_openmls_provider.rs @@ -19,7 +19,11 @@ impl XmtpOpenMlsProviderPrivate { } } - pub(crate) fn conn_ref(&self) -> &DbConnectionPrivate { + pub fn new_crypto() -> RustCrypto { + RustCrypto::default() + } + + pub fn conn_ref(&self) -> &DbConnectionPrivate { self.key_store.conn_ref() } } From ca2715754abaefefb0585cb276ff87f65bbd55bb Mon Sep 17 00:00:00 2001 From: Dakota Brink <779390+codabrink@users.noreply.github.com> Date: Mon, 9 Dec 2024 16:56:35 -0500 Subject: [PATCH 38/46] Bump wasm-bindgen, cargo update (#1395) * bump wasm-bindgen, cargo update * upate sqlite repo --- Cargo.lock | 572 +++++++++++++++++++++++++++-------------------------- Cargo.toml | 6 +- 2 files changed, 297 insertions(+), 281 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 07e02c708..513ee426e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -149,9 +149,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.93" +version = "1.0.94" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c95c10ba0b00a02636238b814946408b1322d5ac4760326e6fb8ec956d85775" +checksum = "c1fd03a028ef38ba2276dce7e33fcd6369c158a1bca17946c4b1b701891c1ff7" [[package]] name = "arrayref" @@ -197,7 +197,7 @@ dependencies = [ "proc-macro2", "quote", "serde", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -257,7 +257,7 @@ checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -268,7 +268,7 @@ checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -296,7 +296,7 @@ checksum = "3c87f3f15e7794432337fc718554eaa4dc8f04c9677a950ffe366f20a162ae42" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -315,7 +315,7 @@ dependencies = [ "axum-core", "bytes", "futures-util", - "http 1.1.0", + "http 1.2.0", "http-body 1.0.1", "http-body-util", "itoa", @@ -326,7 +326,7 @@ dependencies = [ "pin-project-lite", "rustversion", "serde", - "sync_wrapper 1.0.1", + "sync_wrapper 1.0.2", "tower 0.5.1", "tower-layer", "tower-service", @@ -341,13 +341,13 @@ dependencies = [ "async-trait", "bytes", "futures-util", - "http 1.1.0", + "http 1.2.0", "http-body 1.0.1", "http-body-util", "mime", "pin-project-lite", "rustversion", - "sync_wrapper 1.0.1", + "sync_wrapper 1.0.2", "tower-layer", "tower-service", ] @@ -444,7 +444,7 @@ dependencies = [ "regex", "rustc-hash", "shlex", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -578,9 +578,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.8.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ac0150caa2ae65ca5bd83f25c7de183dea78d4d366469f148435e2acfbad0da" +checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b" dependencies = [ "serde", ] @@ -617,9 +617,9 @@ dependencies = [ [[package]] name = "cargo-platform" -version = "0.1.8" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24b1f0365a6c6bb4020cd05806fd0d33c44d38046b8bd7f0e40814b9763cabfc" +checksum = "e35af189006b9c0f00a064685c727031e3ed2d8020f7ba284d78cc2671bd36ea" dependencies = [ "serde", ] @@ -660,9 +660,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cc" -version = "1.2.1" +version = "1.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd9de9f2205d5ef3fd67e685b0df337994ddd4495e2a28d185500d0e1edfea47" +checksum = "27f657647bcff5394bf56c7317665bbf790a137a50eaaa5c6bfbb9e27a518f2d" dependencies = [ "jobserver", "libc", @@ -710,9 +710,9 @@ dependencies = [ [[package]] name = "chrono" -version = "0.4.38" +version = "0.4.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" +checksum = "7e36cc9d416881d2e24f9a963be5fb1cd90966419ac844274161d10488b3e825" dependencies = [ "android-tzdata", "iana-time-zone", @@ -773,9 +773,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.21" +version = "4.5.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb3b4b9e5a7c7514dfa52869339ee98b3156b0bfb4e8a77c4ff4babb64b1604f" +checksum = "3135e7ec2ef7b10c6ed8950f0f792ed96ee093fa088608f1c76e569722700c84" dependencies = [ "clap_builder", "clap_derive", @@ -783,9 +783,9 @@ dependencies = [ [[package]] name = "clap-verbosity-flag" -version = "3.0.0" +version = "3.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42dcf89bb9d98abb02e9a4a8ef1cce429e547a803460a8245c399860985d5281" +checksum = "54381ae56ad222eea3f529c692879e9c65e07945ae48d3dc4d1cb18dbec8cf44" dependencies = [ "clap", "log", @@ -793,9 +793,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.21" +version = "4.5.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b17a95aa67cc7b5ebd32aa5370189aa0d79069ef1c64ce893bd30fb24bff20ec" +checksum = "30582fc632330df2bd26877bde0c1f4470d57c582bbc070376afcd04d8cb4838" dependencies = [ "anstream", "anstyle", @@ -812,14 +812,14 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] name = "clap_lex" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afb84c814227b90d6895e01398aee0d8033c00e7466aca416fb6a8e0eb19d8a7" +checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" [[package]] name = "coins-bip32" @@ -941,9 +941,9 @@ dependencies = [ [[package]] name = "const-hex" -version = "1.13.1" +version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0121754e84117e65f9d90648ee6aa4882a6e63110307ab73967a4c5e7e69e586" +checksum = "4b0485bab839b018a8f1723fc5391819fea5f8f0f32288ef8a735fd096b6160c" dependencies = [ "cfg-if", "cpufeatures", @@ -960,18 +960,18 @@ checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" [[package]] name = "const_format" -version = "0.2.33" +version = "0.2.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50c655d81ff1114fb0dcdea9225ea9f0cc712a6f8d189378e82bdf62a473a64b" +checksum = "126f97965c8ad46d6d9163268ff28432e8f6a1196a55578867832e3049df63dd" dependencies = [ "const_format_proc_macros", ] [[package]] name = "const_format_proc_macros" -version = "0.2.33" +version = "0.2.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eff1a44b93f47b1bac19a27932f5c591e43d1ba357ee4f61526c8a25603f0eb1" +checksum = "1d57c2eccfb16dbac1f4e61e206105db5820c9d26c3c472bc17c774259ef7744" dependencies = [ "proc-macro2", "quote", @@ -1003,6 +1003,16 @@ dependencies = [ "libc", ] +[[package]] +name = "core-foundation" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b55271e5c8c478ad3f38ad24ef34923091e0548492a266d19b3c0b4d82574c63" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "core-foundation-sys" version = "0.8.7" @@ -1011,9 +1021,9 @@ checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] name = "cpufeatures" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ca741a962e1b0bff6d724a1a0958b686406e853bb14061f218562e1896f95e6" +checksum = "16b80225097f2e5ae4e7179dd2266824648f3e2f49d9134d584b76389d31c4c3" dependencies = [ "libc", ] @@ -1152,12 +1162,12 @@ dependencies = [ [[package]] name = "ctor" -version = "0.2.8" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edb49164822f3ee45b17acd4a208cfc1251410cf0cad9a833234c9890774dd9f" +checksum = "32a2785755761f3ddc1492979ce1e48d2c00d09311c39e4466429188f3dd6501" dependencies = [ "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -1193,7 +1203,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -1217,7 +1227,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -1228,7 +1238,7 @@ checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" dependencies = [ "darling_core", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -1284,13 +1294,13 @@ checksum = "cb7330aeadfbe296029522e6c40f315320aba36fc43a5b3632f3795348f3bd22" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] name = "diesel" version = "2.2.4" -source = "git+https://github.com/diesel-rs/diesel?branch=master#5a2940eeaa935c0cc0a7fc57ffe012f3aaa80f43" +source = "git+https://github.com/diesel-rs/diesel?branch=master#b3cca0b44faf7679f307a19bcb08bf51f090c4a1" dependencies = [ "diesel_derives", "downcast-rs", @@ -1302,7 +1312,7 @@ dependencies = [ [[package]] name = "diesel-wasm-sqlite" version = "0.0.1" -source = "git+https://github.com/xmtp/diesel-wasm-sqlite?branch=main#1eb449b79ed50e00042efb0bc9ca0a9f302ba7ef" +source = "git+https://github.com/xmtp/sqlite-web-rs?branch=main#7f0f938aa4d49ed7bfe5624d086e7f6583805419" dependencies = [ "diesel", "diesel_derives", @@ -1310,7 +1320,7 @@ dependencies = [ "serde", "serde-wasm-bindgen", "talc", - "thiserror 1.0.69", + "thiserror 2.0.6", "tokio", "tracing", "wasm-bindgen", @@ -1320,19 +1330,19 @@ dependencies = [ [[package]] name = "diesel_derives" version = "2.2.0" -source = "git+https://github.com/diesel-rs/diesel?branch=master#5a2940eeaa935c0cc0a7fc57ffe012f3aaa80f43" +source = "git+https://github.com/diesel-rs/diesel?branch=master#b3cca0b44faf7679f307a19bcb08bf51f090c4a1" dependencies = [ "diesel_table_macro_syntax", "dsl_auto_type", "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] name = "diesel_migrations" version = "2.2.0" -source = "git+https://github.com/diesel-rs/diesel?branch=master#5a2940eeaa935c0cc0a7fc57ffe012f3aaa80f43" +source = "git+https://github.com/diesel-rs/diesel?branch=master#b3cca0b44faf7679f307a19bcb08bf51f090c4a1" dependencies = [ "diesel", "migrations_internals", @@ -1342,9 +1352,9 @@ dependencies = [ [[package]] name = "diesel_table_macro_syntax" version = "0.2.0" -source = "git+https://github.com/diesel-rs/diesel?branch=master#5a2940eeaa935c0cc0a7fc57ffe012f3aaa80f43" +source = "git+https://github.com/diesel-rs/diesel?branch=master#b3cca0b44faf7679f307a19bcb08bf51f090c4a1" dependencies = [ - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -1427,7 +1437,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -1445,14 +1455,14 @@ checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2" [[package]] name = "dsl_auto_type" version = "0.1.0" -source = "git+https://github.com/diesel-rs/diesel?branch=master#5a2940eeaa935c0cc0a7fc57ffe012f3aaa80f43" +source = "git+https://github.com/diesel-rs/diesel?branch=master#b3cca0b44faf7679f307a19bcb08bf51f090c4a1" dependencies = [ "darling", "either", "heck", "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -1617,12 +1627,12 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "errno" -version = "0.3.9" +version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" +checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" dependencies = [ "libc", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -1761,7 +1771,7 @@ dependencies = [ "reqwest 0.11.27", "serde", "serde_json", - "syn 2.0.87", + "syn 2.0.90", "toml 0.8.19", "walkdir", ] @@ -1779,7 +1789,7 @@ dependencies = [ "proc-macro2", "quote", "serde_json", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -1805,7 +1815,7 @@ dependencies = [ "serde", "serde_json", "strum", - "syn 2.0.87", + "syn 2.0.90", "tempfile", "thiserror 1.0.69", "tiny-keccak", @@ -1955,9 +1965,9 @@ dependencies = [ [[package]] name = "fastrand" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "486f806e73c5707928240ddc295403b1b93c96a02038563881c4a2fd84b81ac4" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" [[package]] name = "fdlimit" @@ -2171,7 +2181,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -2351,7 +2361,7 @@ dependencies = [ "futures-sink", "futures-util", "http 0.2.12", - "indexmap 2.6.0", + "indexmap 2.7.0", "slab", "tokio", "tokio-util", @@ -2360,17 +2370,17 @@ dependencies = [ [[package]] name = "h2" -version = "0.4.6" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "524e8ac6999421f49a846c2d4411f337e53497d8ec55d67753beffa43c5d9205" +checksum = "ccae279728d634d083c00f6099cb58f01cc99c145b84b8be2f6c74618d79922e" dependencies = [ "atomic-waker", "bytes", "fnv", "futures-core", "futures-sink", - "http 1.1.0", - "indexmap 2.6.0", + "http 1.2.0", + "indexmap 2.7.0", "slab", "tokio", "tokio-util", @@ -2395,9 +2405,9 @@ checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" [[package]] name = "hashbrown" -version = "0.15.1" +version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a9bfc1af68b1726ea47d3d5109de126281def866b33970e10fbab11b5dafab3" +checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" [[package]] name = "hashers" @@ -2557,9 +2567,9 @@ dependencies = [ [[package]] name = "http" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" +checksum = "f16ca2af56261c99fba8bac40a10251ce8188205a4c448fbb745a2e4daa76fea" dependencies = [ "bytes", "fnv", @@ -2584,7 +2594,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" dependencies = [ "bytes", - "http 1.1.0", + "http 1.2.0", ] [[package]] @@ -2595,7 +2605,7 @@ checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" dependencies = [ "bytes", "futures-util", - "http 1.1.0", + "http 1.2.0", "http-body 1.0.1", "pin-project-lite", ] @@ -2638,15 +2648,15 @@ dependencies = [ [[package]] name = "hyper" -version = "1.5.0" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbbff0a806a4728c99295b254c8838933b5b082d75e3cb70c8dab21fdfbcfa9a" +checksum = "97818827ef4f364230e16705d4706e2897df2bb60617d6ca15d598025a3c481f" dependencies = [ "bytes", "futures-channel", "futures-util", - "h2 0.4.6", - "http 1.1.0", + "h2 0.4.7", + "http 1.2.0", "http-body 1.0.1", "httparse", "httpdate", @@ -2678,13 +2688,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08afdbb5c31130e3034af566421053ab03787c640246a446327f550d11bcb333" dependencies = [ "futures-util", - "http 1.1.0", - "hyper 1.5.0", + "http 1.2.0", + "hyper 1.5.1", "hyper-util", - "rustls 0.23.18", + "rustls 0.23.19", "rustls-pki-types", "tokio", - "tokio-rustls 0.26.0", + "tokio-rustls 0.26.1", "tower-service", ] @@ -2694,7 +2704,7 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b90d566bffbce6a75bd8b09a05aa8c2cb1fabb6cb348f8840c9e4c90a0d83b0" dependencies = [ - "hyper 1.5.0", + "hyper 1.5.1", "hyper-util", "pin-project-lite", "tokio", @@ -2722,7 +2732,7 @@ checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" dependencies = [ "bytes", "http-body-util", - "hyper 1.5.0", + "hyper 1.5.1", "hyper-util", "native-tls", "tokio", @@ -2739,9 +2749,9 @@ dependencies = [ "bytes", "futures-channel", "futures-util", - "http 1.1.0", + "http 1.2.0", "http-body 1.0.1", - "hyper 1.5.0", + "hyper 1.5.1", "pin-project-lite", "socket2", "tokio", @@ -2887,7 +2897,7 @@ checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -2946,13 +2956,13 @@ dependencies = [ [[package]] name = "impl-trait-for-tuples" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11d7a9f6330b71fea57921c9b61c47ee6e84f72d394754eff6163ae67e7395eb" +checksum = "a0eb5a3343abf848c0984fe4604b2b105da9539376e24fc0a3b0007411ae4fd9" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.90", ] [[package]] @@ -2973,12 +2983,12 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.6.0" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" +checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f" dependencies = [ "equivalent", - "hashbrown 0.15.1", + "hashbrown 0.15.2", ] [[package]] @@ -3076,9 +3086,9 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.11" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" +checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" [[package]] name = "jni-sys" @@ -3097,9 +3107,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.74" +version = "0.3.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a865e038f7f6ed956f788f0d7d60c541fff74c7bd74272c5d4cf15c63743e705" +checksum = "6717b6b5b077764fb5966237269cb3c64edddde4b14ce42647430a78ced9e7b7" dependencies = [ "once_cell", "wasm-bindgen", @@ -3194,9 +3204,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.164" +version = "0.2.168" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "433bfe06b8c75da9b2e3fbea6e5329ff87748f0b144ef75306e674c3f6f7c13f" +checksum = "5aaeb2981e0606ca11d79718f8bb01164f1d6ed75080182d3abf017e6d244b6d" [[package]] name = "libgit2-sys" @@ -3212,9 +3222,9 @@ dependencies = [ [[package]] name = "libloading" -version = "0.8.5" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4" +checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34" dependencies = [ "cfg-if", "windows-targets 0.52.6", @@ -3326,9 +3336,9 @@ dependencies = [ [[package]] name = "litemap" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "643cb0b8d4fcc284004d5fd0d67ccf61dfffadb7f75e1e71bc420f4688a3a704" +checksum = "4ee93343901ab17bd981295f2cf0026d4ad018c7c31ba84549a4ddbb47a45104" [[package]] name = "lock_api" @@ -3389,7 +3399,7 @@ dependencies = [ [[package]] name = "migrations_internals" version = "2.2.0" -source = "git+https://github.com/diesel-rs/diesel?branch=master#5a2940eeaa935c0cc0a7fc57ffe012f3aaa80f43" +source = "git+https://github.com/diesel-rs/diesel?branch=master#b3cca0b44faf7679f307a19bcb08bf51f090c4a1" dependencies = [ "serde", "toml 0.8.19", @@ -3398,7 +3408,7 @@ dependencies = [ [[package]] name = "migrations_macros" version = "2.2.0" -source = "git+https://github.com/diesel-rs/diesel?branch=master#5a2940eeaa935c0cc0a7fc57ffe012f3aaa80f43" +source = "git+https://github.com/diesel-rs/diesel?branch=master#b3cca0b44faf7679f307a19bcb08bf51f090c4a1" dependencies = [ "migrations_internals", "proc-macro2", @@ -3423,13 +3433,13 @@ dependencies = [ [[package]] name = "mini-internal" -version = "0.1.40" +version = "0.1.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3cd9f9bbedc1b92683a9847b8db12f3203cf32af6a11db085fa007708dc9555" +checksum = "07b7f1340a7f0d2f89755aac4096f1c55352bfcb95cb8f351d6fcefa18df474f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -3450,9 +3460,9 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "miniserde" -version = "0.1.40" +version = "0.1.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9b650e926368ad21aaabe6055341d1874df696178f47d70b6d9a691f616274e" +checksum = "625208b7bc90255fe6d99338041880bf48a3049166f46fbefbd4e9b0478c0b66" dependencies = [ "itoa", "mini-internal", @@ -3479,11 +3489,10 @@ dependencies = [ [[package]] name = "mio" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec" +checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" dependencies = [ - "hermit-abi 0.3.9", "libc", "wasi", "windows-sys 0.52.0", @@ -3501,7 +3510,7 @@ dependencies = [ "openmls", "openmls_rust_crypto", "rand", - "thiserror 2.0.3", + "thiserror 2.0.6", "tokio", "tonic", "tracing", @@ -3537,7 +3546,7 @@ dependencies = [ "cfg-if", "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -3550,10 +3559,10 @@ dependencies = [ "bytes", "colored", "futures-util", - "http 1.1.0", + "http 1.2.0", "http-body 1.0.1", "http-body-util", - "hyper 1.5.0", + "hyper 1.5.1", "hyper-util", "log", "rand", @@ -3610,23 +3619,23 @@ checksum = "e1c0f5d67ee408a4685b61f5ab7e58605c8ae3f2b4189f0127d804ff13d5560a" [[package]] name = "napi-derive" -version = "2.16.12" +version = "2.16.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17435f7a00bfdab20b0c27d9c56f58f6499e418252253081bfff448099da31d1" +checksum = "7cbe2585d8ac223f7d34f13701434b9d5f4eb9c332cccce8dee57ea18ab8ab0c" dependencies = [ "cfg-if", "convert_case", "napi-derive-backend", "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] name = "napi-derive-backend" -version = "1.0.74" +version = "1.0.75" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "967c485e00f0bf3b1bdbe510a38a4606919cf1d34d9a37ad41f25a81aa077abe" +checksum = "1639aaa9eeb76e91c6ae66da8ce3e89e921cd3885e99ec85f4abacae72fc91bf" dependencies = [ "convert_case", "once_cell", @@ -3634,7 +3643,7 @@ dependencies = [ "quote", "regex", "semver", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -3658,7 +3667,7 @@ dependencies = [ "openssl-probe", "openssl-sys", "schannel", - "security-framework", + "security-framework 2.11.1", "security-framework-sys", "tempfile", ] @@ -3761,7 +3770,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -3927,7 +3936,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -4020,29 +4029,28 @@ dependencies = [ [[package]] name = "parity-scale-codec" -version = "3.7.0" +version = "3.6.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8be4817d39f3272f69c59fe05d0535ae6456c2dc2fa1ba02910296c7e0a5c590" +checksum = "306800abfa29c7f16596b5970a588435e3d5b3149683d00c12b699cc19f895ee" dependencies = [ "arrayvec", "bitvec", "byte-slice-cast", "impl-trait-for-tuples", "parity-scale-codec-derive", - "rustversion", "serde", ] [[package]] name = "parity-scale-codec-derive" -version = "3.7.0" +version = "3.6.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8781a75c6205af67215f382092b6e0a4ff3734798523e69073d4bcd294ec767b" +checksum = "d830939c76d294956402033aee57a6da7b438f2294eb94864c37b0569053a42c" dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.87", + "syn 1.0.109", ] [[package]] @@ -4206,7 +4214,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" dependencies = [ "fixedbitset", - "indexmap 2.6.0", + "indexmap 2.7.0", ] [[package]] @@ -4249,7 +4257,7 @@ dependencies = [ "phf_shared 0.11.2", "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -4287,7 +4295,7 @@ checksum = "3c0f5fad0874fc7abcd4d750e76917eaebbecaa2c20bde22e1dbeeba8beb758c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -4387,9 +4395,9 @@ dependencies = [ [[package]] name = "portable-atomic" -version = "1.9.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc9c68a3f6da06753e9335d63e27f6b9754dd1920d941135b7ea8224f141adb2" +checksum = "280dc24453071f1b63954171985a0b0d30058d287960968b9b2aca264c8d4ee6" [[package]] name = "powerfmt" @@ -4445,7 +4453,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "64d1ec885c64d0457d564db4ec299b2dae3f9c02808b8ad9c3a089c591b18033" dependencies = [ "proc-macro2", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -4482,9 +4490,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.89" +version = "1.0.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f139b0662de085916d1fb67d2b4169d1addddda1919e696f3252b740b629986e" +checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" dependencies = [ "unicode-ident", ] @@ -4507,9 +4515,9 @@ dependencies = [ [[package]] name = "prost" -version = "0.13.3" +version = "0.13.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b0487d90e047de87f984913713b85c601c05609aad5b0df4b4573fbf69aa13f" +checksum = "2c0fef6c4230e4ccf618a35c59d7ede15dea37de8427500f50aff708806e42ec" dependencies = [ "bytes", "prost-derive", @@ -4517,11 +4525,10 @@ dependencies = [ [[package]] name = "prost-build" -version = "0.13.3" +version = "0.13.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c1318b19085f08681016926435853bbf7858f9c082d0999b80550ff5d9abe15" +checksum = "d0f3e5beed80eb580c68e2c600937ac2c4eedabdfd5ef1e5b7ea4f3fba84497b" dependencies = [ - "bytes", "heck", "itertools 0.13.0", "log", @@ -4532,28 +4539,28 @@ dependencies = [ "prost", "prost-types", "regex", - "syn 2.0.87", + "syn 2.0.90", "tempfile", ] [[package]] name = "prost-derive" -version = "0.13.3" +version = "0.13.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9552f850d5f0964a4e4d0bf306459ac29323ddfbae05e35a7c0d35cb0803cc5" +checksum = "157c5a9d7ea5c2ed2d9fb8f495b64759f7816c7eaea54ba3978f0d63000162e3" dependencies = [ "anyhow", "itertools 0.13.0", "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] name = "prost-types" -version = "0.13.3" +version = "0.13.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4759aa0d3a6232fb8dbdb97b61de2c20047c68aca932c7ed76da9d788508d670" +checksum = "cc2f1e56baa61e93533aebc21af4d2134b70f66275e0fcdf3cbe43d77ff7e8fc" dependencies = [ "prost", ] @@ -4780,11 +4787,11 @@ dependencies = [ "encoding_rs", "futures-core", "futures-util", - "h2 0.4.6", - "http 1.1.0", + "h2 0.4.7", + "http 1.2.0", "http-body 1.0.1", "http-body-util", - "hyper 1.5.0", + "hyper 1.5.1", "hyper-rustls 0.27.3", "hyper-tls 0.6.0", "hyper-util", @@ -4800,7 +4807,7 @@ dependencies = [ "serde", "serde_json", "serde_urlencoded", - "sync_wrapper 1.0.1", + "sync_wrapper 1.0.2", "system-configuration 0.6.1", "tokio", "tokio-native-tls", @@ -4925,15 +4932,15 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.41" +version = "0.38.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7f649912bc1495e167a6edee79151c84b1bad49748cb4f1f1167f459f6224f6" +checksum = "f93dc38ecbab2eb790ff964bb77fa94faf256fd3e73285fd7ba0903b76bedb85" dependencies = [ "bitflags 2.6.0", "errno", "libc", "linux-raw-sys", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -4950,9 +4957,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.18" +version = "0.23.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c9cc1d47e243d655ace55ed38201c19ae02c148ae56412ab8750e8f0166ab7f" +checksum = "934b404430bb06b3fae2cba809eb45a1ab1aecd64491213d7c3301b88393f8d1" dependencies = [ "log", "once_cell", @@ -4965,15 +4972,14 @@ dependencies = [ [[package]] name = "rustls-native-certs" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcaf18a4f2be7326cd874a5fa579fae794320a0f388d365dca7e480e55f83f8a" +checksum = "7fcff2dd52b58a8d98a70243663a0d234c4e2b79235637849d15913394a247d3" dependencies = [ "openssl-probe", - "rustls-pemfile 2.2.0", "rustls-pki-types", "schannel", - "security-framework", + "security-framework 3.0.1", ] [[package]] @@ -5053,9 +5059,9 @@ dependencies = [ [[package]] name = "scale-info" -version = "2.11.5" +version = "2.11.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1aa7ffc1c0ef49b0452c6e2986abf2b07743320641ffd5fc63d552458e3b779b" +checksum = "346a3b32eba2640d17a9cb5927056b08f3de90f65b72fe09402c2ad07d684d0b" dependencies = [ "cfg-if", "derive_more", @@ -5065,21 +5071,21 @@ dependencies = [ [[package]] name = "scale-info-derive" -version = "2.11.5" +version = "2.11.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46385cc24172cf615450267463f937c10072516359b3ff1cb24228a4a08bf951" +checksum = "c6630024bf739e2179b91fb424b28898baf819414262c5d376677dbff1fe7ebf" dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] name = "schannel" -version = "0.1.26" +version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01227be5826fa0690321a2ba6c5cd57a19cf3f6a09e76973b58e61de6ab9d1c1" +checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d" dependencies = [ "windows-sys 0.59.0", ] @@ -5122,7 +5128,7 @@ checksum = "7f81c2fde025af7e69b1d1420531c8a8811ca898919db177141a85313b1cb932" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -5182,7 +5188,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" dependencies = [ "bitflags 2.6.0", - "core-foundation", + "core-foundation 0.9.4", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1415a607e92bec364ea2cf9264646dcce0f91e6d65281bd6f2819cca3bf39c8" +dependencies = [ + "bitflags 2.6.0", + "core-foundation 0.10.0", "core-foundation-sys", "libc", "security-framework-sys", @@ -5247,7 +5266,7 @@ checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -5409,9 +5428,9 @@ checksum = "b7c388c1b5e93756d0c740965c41e8822f866621d41acbdf6336a6a168f8840c" [[package]] name = "socket2" -version = "0.5.7" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" +checksum = "c970269d99b64e60ec3bd6ad27270092a5394c4e309314b18ae3fe575695fbe8" dependencies = [ "libc", "windows-sys 0.52.0", @@ -5449,7 +5468,7 @@ checksum = "658f2ca5276b92c3dfd65fa88316b4e032ace68f88d7570b43967784c0bac5ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -5540,7 +5559,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -5582,9 +5601,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.87" +version = "2.0.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25aa4ce346d03a6dcd68dd8b4010bcb74e54e62c90c573f394c46eae99aba32d" +checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31" dependencies = [ "proc-macro2", "quote", @@ -5599,9 +5618,9 @@ checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" [[package]] name = "sync_wrapper" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394" +checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" dependencies = [ "futures-core", ] @@ -5614,7 +5633,7 @@ checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -5624,7 +5643,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" dependencies = [ "bitflags 1.3.2", - "core-foundation", + "core-foundation 0.9.4", "system-configuration-sys 0.5.0", ] @@ -5635,7 +5654,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" dependencies = [ "bitflags 2.6.0", - "core-foundation", + "core-foundation 0.9.4", "system-configuration-sys 0.6.0", ] @@ -5724,11 +5743,11 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.3" +version = "2.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c006c85c7651b3cf2ada4584faa36773bd07bac24acfb39f3c431b36d7e667aa" +checksum = "8fec2a1820ebd077e2b90c4df007bebf344cd394098a13c563957d0afc83ea47" dependencies = [ - "thiserror-impl 2.0.3", + "thiserror-impl 2.0.6", ] [[package]] @@ -5739,18 +5758,18 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] name = "thiserror-impl" -version = "2.0.3" +version = "2.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f077553d607adc1caf65430528a576c757a71ed73944b66ebb58ef2bbd243568" +checksum = "d65750cab40f4ff1929fb1ba509e9914eb756131cef4210da8d5d700d26f6312" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -5765,9 +5784,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.36" +version = "0.3.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" +checksum = "35e7868883861bd0e56d9ac6efcaaca0d6d5d82a2a7ec8209ff492c07cf37b21" dependencies = [ "deranged", "itoa", @@ -5788,9 +5807,9 @@ checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" [[package]] name = "time-macros" -version = "0.2.18" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf" +checksum = "2834e6017e3e5e4b9834939793b282bc03b37a3336245fa820e35e233e2a85de" dependencies = [ "num-conv", "time-core", @@ -5869,14 +5888,14 @@ checksum = "8d9ef545650e79f30233c0003bcc2504d7efac6dad25fca40744de773fe2049c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] name = "tokio" -version = "1.41.1" +version = "1.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22cfb5bee7a6a52939ca9224d6ac897bb669134078daa8735560897f69de4d33" +checksum = "5cec9b21b0450273377fc97bd4c33a8acffc8c996c987a7c5b319a0083707551" dependencies = [ "backtrace", "bytes", @@ -5899,7 +5918,7 @@ checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -5924,20 +5943,19 @@ dependencies = [ [[package]] name = "tokio-rustls" -version = "0.26.0" +version = "0.26.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4" +checksum = "5f6d0975eaace0cf0fcadee4e4aaa5da15b5c079146f2cffb67c113be122bf37" dependencies = [ - "rustls 0.23.18", - "rustls-pki-types", + "rustls 0.23.19", "tokio", ] [[package]] name = "tokio-stream" -version = "0.1.16" +version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f4e6ce100d0eb49a2734f8c0812bcd324cf357d21810932c5df6b96ef2b86f1" +checksum = "eca58d7bba4a75707817a2c44174253f9236b2d5fbd055602e9d5c07c139a047" dependencies = [ "futures-core", "pin-project-lite", @@ -5976,9 +5994,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.12" +version = "0.7.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61e7c3654c13bcd040d4a03abee2c75b1d14a37b423cf5a813ceae1cc903ec6a" +checksum = "d7fcaa8d55a2bdd6b83ace262b016eca0d79ee02818c5c1bcdf0305114081078" dependencies = [ "bytes", "futures-core", @@ -6023,7 +6041,7 @@ version = "0.22.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" dependencies = [ - "indexmap 2.6.0", + "indexmap 2.7.0", "serde", "serde_spanned", "toml_datetime", @@ -6041,11 +6059,11 @@ dependencies = [ "axum", "base64 0.22.1", "bytes", - "h2 0.4.6", - "http 1.1.0", + "h2 0.4.7", + "http 1.2.0", "http-body 1.0.1", "http-body-util", - "hyper 1.5.0", + "hyper 1.5.1", "hyper-timeout", "hyper-util", "percent-encoding", @@ -6055,13 +6073,13 @@ dependencies = [ "rustls-pemfile 2.2.0", "socket2", "tokio", - "tokio-rustls 0.26.0", + "tokio-rustls 0.26.1", "tokio-stream", "tower 0.4.13", "tower-layer", "tower-service", "tracing", - "webpki-roots 0.26.6", + "webpki-roots 0.26.7", ] [[package]] @@ -6112,9 +6130,9 @@ checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" [[package]] name = "tracing" -version = "0.1.40" +version = "0.1.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" dependencies = [ "log", "pin-project-lite", @@ -6136,20 +6154,20 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.27" +version = "0.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" +checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] name = "tracing-core" -version = "0.1.32" +version = "0.1.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" dependencies = [ "once_cell", "valuable", @@ -6157,9 +6175,9 @@ dependencies = [ [[package]] name = "tracing-error" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d686ec1c0f384b1277f097b2f279a2ecc11afe8c133c1aabf036a27cb4cd206e" +checksum = "8b1581020d7a273442f5b45074a6a57d5757ad0a47dac0e9f0bd57b81936f3db" dependencies = [ "tracing", "tracing-subscriber", @@ -6215,9 +6233,9 @@ dependencies = [ [[package]] name = "tracing-serde" -version = "0.1.3" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc6b213177105856957181934e4920de57730fc69bf42c37ee5bb664d406d9e1" +checksum = "704b1aeb7be0d0a84fc9828cae51dab5970fee5088f83d1dd7ee6f6246fc6ff1" dependencies = [ "serde", "tracing-core", @@ -6227,9 +6245,9 @@ dependencies = [ [[package]] name = "tracing-subscriber" -version = "0.3.18" +version = "0.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" +checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008" dependencies = [ "chrono", "matchers", @@ -6281,7 +6299,7 @@ checksum = "70977707304198400eb4835a78f6a9f928bf41bba420deb8fdb175cd965d77a7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -6320,7 +6338,7 @@ dependencies = [ "byteorder", "bytes", "data-encoding", - "http 1.1.0", + "http 1.2.0", "httparse", "log", "rand", @@ -6362,9 +6380,9 @@ checksum = "7e51b68083f157f853b6379db119d1c1be0e6e4dec98101079dec41f6f5cf6df" [[package]] name = "unicode-ident" -version = "1.0.13" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" +checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" [[package]] name = "unicode-segmentation" @@ -6446,7 +6464,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "802d2051a700e3ec894c79f80d2705b69d85844dafbbe5d1a92776f8f48b563a" dependencies = [ "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -6477,7 +6495,7 @@ dependencies = [ "proc-macro2", "quote", "serde", - "syn 2.0.87", + "syn 2.0.90", "toml 0.5.11", "uniffi_meta", ] @@ -6709,9 +6727,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.97" +version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d15e63b4482863c109d70a7b8706c1e364eb6ea449b201a76c5b89cedcec2d5c" +checksum = "a474f6281d1d70c17ae7aa6a613c87fce69a127e2624002df63dcb39d6cf6396" dependencies = [ "cfg-if", "once_cell", @@ -6720,24 +6738,23 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.97" +version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d36ef12e3aaca16ddd3f67922bc63e48e953f126de60bd33ccc0101ef9998cd" +checksum = "5f89bb38646b4f81674e8f5c3fb81b562be1fd936d84320f3264486418519c79" dependencies = [ "bumpalo", "log", - "once_cell", "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.47" +version = "0.4.49" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9dfaf8f50e5f293737ee323940c7d8b08a66a95a419223d9f41610ca08b0833d" +checksum = "38176d9b44ea84e9184eff0bc34cc167ed044f816accfe5922e54d84cf48eca2" dependencies = [ "cfg-if", "js-sys", @@ -6748,9 +6765,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.97" +version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "705440e08b42d3e4b36de7d66c944be628d579796b8090bfa3471478a2260051" +checksum = "2cc6181fd9a7492eef6fef1f33961e3695e4579b9872a6f7c83aee556666d4fe" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -6758,32 +6775,31 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.97" +version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98c9ae5a76e46f4deecd0f0255cc223cfa18dc9b261213b8aa0c7b36f61b3f1d" +checksum = "30d7a95b763d3c45903ed6c81f156801839e5ee968bb07e534c44df0fcd330c2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.97" +version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ee99da9c5ba11bd675621338ef6fa52296b76b83305e9b6e5c77d4c286d6d49" +checksum = "943aab3fdaaa029a6e0271b35ea10b72b943135afe9bffca82384098ad0e06a6" [[package]] name = "wasm-bindgen-test" -version = "0.3.47" +version = "0.3.49" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d919bb60ebcecb9160afee6c71b43a58a4f0517a2de0054cd050d02cec08201" +checksum = "c61d44563646eb934577f2772656c7ad5e9c90fac78aa8013d776fcdaf24625d" dependencies = [ "js-sys", "minicov", - "once_cell", "scoped-tls", "wasm-bindgen", "wasm-bindgen-futures", @@ -6792,13 +6808,13 @@ dependencies = [ [[package]] name = "wasm-bindgen-test-macro" -version = "0.3.47" +version = "0.3.49" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "222ebde6ea87fbfa6bdd2e9f1fd8a91d60aee5db68792632176c4e16a74fc7d8" +checksum = "54171416ce73aa0b9c377b51cc3cb542becee1cd678204812e8392e5b0e4a031" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -6831,9 +6847,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.74" +version = "0.3.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a98bc3c33f0fe7e59ad7cd041b89034fa82a7c2d4365ca538dda6cdaf513863c" +checksum = "04dd7223427d52553d3702c004d3b2fe07c148165faa56313cb00211e31c12bc" dependencies = [ "js-sys", "wasm-bindgen", @@ -6857,9 +6873,9 @@ checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" [[package]] name = "webpki-roots" -version = "0.26.6" +version = "0.26.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "841c67bff177718f1d4dfefde8d8f0e78f9b6589319ba88312f567fc5841a958" +checksum = "5d642ff16b7e79272ae451b7322067cdc17cadf68c23264be9d94a32319efe7e" dependencies = [ "rustls-pki-types", ] @@ -7188,7 +7204,7 @@ dependencies = [ "redb", "speedy", "tempfile", - "thiserror 2.0.3", + "thiserror 2.0.6", "tokio", "tracing", "tracing-appender", @@ -7248,7 +7264,7 @@ dependencies = [ "reqwest 0.12.9", "serde", "serde_json", - "thiserror 2.0.3", + "thiserror 2.0.6", "tokio", "tracing", "wasm-bindgen-test", @@ -7270,7 +7286,7 @@ dependencies = [ "prost", "serde", "serde_json", - "thiserror 2.0.3", + "thiserror 2.0.6", "timeago", "tokio", "tracing", @@ -7304,7 +7320,7 @@ dependencies = [ "serde", "sha2 0.10.8", "sha3", - "thiserror 2.0.3", + "thiserror 2.0.6", "tls_codec", "tracing", "wasm-bindgen-futures", @@ -7333,7 +7349,7 @@ dependencies = [ "serde", "serde_json", "sha2 0.10.8", - "thiserror 2.0.3", + "thiserror 2.0.6", "tokio", "tracing", "url", @@ -7386,7 +7402,7 @@ dependencies = [ "serde", "serde_json", "tempfile", - "thiserror 2.0.3", + "thiserror 2.0.6", "tls_codec", "tokio", "tokio-stream", @@ -7464,7 +7480,7 @@ dependencies = [ "paranoid-android", "parking_lot 0.12.3", "rand", - "thiserror 2.0.3", + "thiserror 2.0.6", "tokio", "tracing", "tracing-oslog", @@ -7519,9 +7535,9 @@ checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" [[package]] name = "yoke" -version = "0.7.4" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c5b1314b079b0930c31e3af543d8ee1757b1951ae1e1565ec704403a7240ca5" +checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" dependencies = [ "serde", "stable_deref_trait", @@ -7531,13 +7547,13 @@ dependencies = [ [[package]] name = "yoke-derive" -version = "0.7.4" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28cc31741b18cb6f1d5ff12f5b7523e3d6eb0852bbbad19d73905511d9849b95" +checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", "synstructure", ] @@ -7559,27 +7575,27 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] name = "zerofrom" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91ec111ce797d0e0784a1116d0ddcdbea84322cd79e5d5ad173daeba4f93ab55" +checksum = "cff3ee08c995dee1859d998dea82f7374f2826091dd9cd47def953cae446cd2e" dependencies = [ "zerofrom-derive", ] [[package]] name = "zerofrom-derive" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ea7b4a3637ea8669cedf0f1fd5c286a17f3de97b8dd5a70a6c167a1730e63a5" +checksum = "595eed982f7d355beb85837f651fa22e90b3c044842dc7f2c2842c086f295808" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", "synstructure", ] @@ -7600,7 +7616,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -7622,7 +7638,7 @@ checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 41a238589..2408f730c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -89,9 +89,9 @@ tracing = { version = "0.1", features = ["log"] } tracing-subscriber = { version = "0.3", default-features = false } trait-variant = "0.1.2" url = "2.5.0" -wasm-bindgen = "=0.2.97" +wasm-bindgen = "=0.2.99" wasm-bindgen-futures = "0.4" -wasm-bindgen-test = "0.3.47" +wasm-bindgen-test = "0.3.49" web-sys = "0.3" zeroize = "1.8" @@ -142,6 +142,6 @@ opt-level = "s" # (cfg-specific patche support does not exist) [patch.crates-io] diesel = { git = "https://github.com/diesel-rs/diesel", branch = "master" } -diesel-wasm-sqlite = { git = "https://github.com/xmtp/diesel-wasm-sqlite", branch = "main" } +diesel-wasm-sqlite = { git = "https://github.com/xmtp/sqlite-web-rs", branch = "main" } diesel_derives = { git = "https://github.com/diesel-rs/diesel", branch = "master" } diesel_migrations = { git = "https://github.com/diesel-rs/diesel", branch = "master" } From 0d7674eb3ac9a80222c472fcadc562d04c9623be Mon Sep 17 00:00:00 2001 From: Dakota Brink <779390+codabrink@users.noreply.github.com> Date: Tue, 10 Dec 2024 12:29:21 -0500 Subject: [PATCH 39/46] Provide HMAC Keys (#1394) * hkdf wip * calculate the kdf * hash the message, provide the hmac * missing files * lint * provide on the ffi * needless bit flipping * test fix * lint * lint * bump version * test it * move down * typo * update hmac algo * lint * move the salt const --- Cargo.lock | 3 + Cargo.toml | 1 + bindings_ffi/src/mls.rs | 34 ++++++ xmtp_mls/Cargo.toml | 3 + .../down.sql | 2 + .../up.sql | 2 + xmtp_mls/src/api/mls.rs | 27 ++--- xmtp_mls/src/client.rs | 6 +- xmtp_mls/src/configuration.rs | 1 + xmtp_mls/src/groups/device_sync.rs | 3 +- .../src/groups/device_sync/consent_sync.rs | 2 +- .../device_sync/preference_sync.rs} | 0 xmtp_mls/src/groups/mls_sync.rs | 103 ++++++++++++++++-- xmtp_mls/src/groups/mod.rs | 13 ++- xmtp_mls/src/lib.rs | 1 - .../src/storage/encrypted_store/schema.rs | 2 +- .../encrypted_store/user_preferences.rs | 45 +++++--- xmtp_mls/src/subscriptions.rs | 6 +- xmtp_mls/src/utils/mod.rs | 22 +++- xmtp_v2/Cargo.toml | 6 +- 20 files changed, 226 insertions(+), 56 deletions(-) create mode 100644 xmtp_mls/migrations/2024-12-06-212729_make_hmac_required/down.sql create mode 100644 xmtp_mls/migrations/2024-12-06-212729_make_hmac_required/up.sql rename xmtp_mls/src/{preferences.rs => groups/device_sync/preference_sync.rs} (100%) diff --git a/Cargo.lock b/Cargo.lock index 513ee426e..17a96844d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7384,6 +7384,8 @@ dependencies = [ "getrandom", "gloo-timers 0.3.0", "hex", + "hkdf", + "hmac 0.12.1", "indicatif", "libsqlite3-sys", "mockall", @@ -7401,6 +7403,7 @@ dependencies = [ "reqwest 0.12.9", "serde", "serde_json", + "sha2 0.10.8", "tempfile", "thiserror 2.0.6", "tls_codec", diff --git a/Cargo.toml b/Cargo.toml index 2408f730c..0226f5a35 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -39,6 +39,7 @@ futures = "0.3.30" futures-core = "0.3.30" getrandom = { version = "0.2", default-features = false } hex = "0.4.3" +hkdf = "0.12.3" openmls = { git = "https://github.com/xmtp/openmls", rev = "043b347cb18d528647df36f500725ab57c41c7db", default-features = false } openmls_basic_credential = { git = "https://github.com/xmtp/openmls", rev = "043b347cb18d528647df36f500725ab57c41c7db" } openmls_rust_crypto = { git = "https://github.com/xmtp/openmls", rev = "043b347cb18d528647df36f500725ab57c41c7db" } diff --git a/bindings_ffi/src/mls.rs b/bindings_ffi/src/mls.rs index f5014e982..6a8955bec 100644 --- a/bindings_ffi/src/mls.rs +++ b/bindings_ffi/src/mls.rs @@ -16,6 +16,7 @@ use xmtp_id::{ InboxId, }; use xmtp_mls::groups::scoped_client::LocalScopedGroupClient; +use xmtp_mls::groups::HmacKey; use xmtp_mls::storage::group::ConversationType; use xmtp_mls::storage::group_message::MsgQueryArgs; use xmtp_mls::storage::group_message::SortDirection; @@ -527,6 +528,33 @@ impl FfiXmtpClient { scw_verifier: self.inner_client.scw_verifier().clone().clone(), })) } + + pub fn get_hmac_keys(&self) -> Result, GenericError> { + let inner = self.inner_client.as_ref(); + let conversations = inner.find_groups(GroupQueryArgs::default())?; + + let mut keys = vec![]; + for conversation in conversations { + let mut k = conversation + .hmac_keys(-1..=1)? + .into_iter() + .map(Into::into) + .collect::>(); + + keys.append(&mut k); + } + + Ok(keys) + } +} + +impl From for FfiHmacKey { + fn from(value: HmacKey) -> Self { + Self { + epoch: value.epoch, + key: value.key.to_vec(), + } + } } #[derive(uniffi::Record)] @@ -537,6 +565,12 @@ pub struct FfiInboxState { pub account_addresses: Vec, } +#[derive(uniffi::Record)] +pub struct FfiHmacKey { + key: Vec, + epoch: i64, +} + #[derive(uniffi::Record)] pub struct FfiInstallation { pub id: Vec, diff --git a/xmtp_mls/Cargo.toml b/xmtp_mls/Cargo.toml index 1d10929c6..c1f8b4c72 100644 --- a/xmtp_mls/Cargo.toml +++ b/xmtp_mls/Cargo.toml @@ -51,6 +51,7 @@ bincode.workspace = true diesel_migrations.workspace = true futures.workspace = true hex.workspace = true +hkdf.workspace = true openmls_rust_crypto = { workspace = true } openmls_traits = { workspace = true } parking_lot.workspace = true @@ -59,6 +60,7 @@ rand = { workspace = true } reqwest = { version = "0.12.4", features = ["stream"] } serde = { workspace = true } serde_json.workspace = true +sha2.workspace = true thiserror = { workspace = true } tls_codec = { workspace = true } tokio-stream = { version = "0.1", default-features = false, features = [ @@ -90,6 +92,7 @@ criterion = { version = "0.5", features = [ "html_reports", "async_tokio", ], optional = true } +hmac = "0.12.1" indicatif = { version = "0.17", optional = true } mockall = { version = "0.13.1", optional = true } once_cell = { version = "1.19", optional = true } diff --git a/xmtp_mls/migrations/2024-12-06-212729_make_hmac_required/down.sql b/xmtp_mls/migrations/2024-12-06-212729_make_hmac_required/down.sql new file mode 100644 index 000000000..409db041b --- /dev/null +++ b/xmtp_mls/migrations/2024-12-06-212729_make_hmac_required/down.sql @@ -0,0 +1,2 @@ +ALTER TABLE user_preferences DROP COLUMN hmac_key; +ALTER TABLE user_preferences ADD COLUMN hmac_key BLOB; diff --git a/xmtp_mls/migrations/2024-12-06-212729_make_hmac_required/up.sql b/xmtp_mls/migrations/2024-12-06-212729_make_hmac_required/up.sql new file mode 100644 index 000000000..584d0f375 --- /dev/null +++ b/xmtp_mls/migrations/2024-12-06-212729_make_hmac_required/up.sql @@ -0,0 +1,2 @@ +ALTER TABLE user_preferences DROP COLUMN hmac_key; +ALTER TABLE user_preferences ADD COLUMN hmac_key BLOB NOT NULL; diff --git a/xmtp_mls/src/api/mls.rs b/xmtp_mls/src/api/mls.rs index 33a42a577..a319f7737 100644 --- a/xmtp_mls/src/api/mls.rs +++ b/xmtp_mls/src/api/mls.rs @@ -4,13 +4,12 @@ use super::ApiClientWrapper; use crate::{retry_async, XmtpApi}; use xmtp_proto::api_client::XmtpMlsStreams; use xmtp_proto::xmtp::mls::api::v1::{ - group_message_input::{Version as GroupMessageInputVersion, V1 as GroupMessageInputV1}, subscribe_group_messages_request::Filter as GroupFilterProto, - subscribe_welcome_messages_request::Filter as WelcomeFilterProto, - FetchKeyPackagesRequest, GroupMessage, GroupMessageInput, KeyPackageUpload, PagingInfo, - QueryGroupMessagesRequest, QueryWelcomeMessagesRequest, SendGroupMessagesRequest, - SendWelcomeMessagesRequest, SortDirection, SubscribeGroupMessagesRequest, - SubscribeWelcomeMessagesRequest, UploadKeyPackageRequest, WelcomeMessage, WelcomeMessageInput, + subscribe_welcome_messages_request::Filter as WelcomeFilterProto, FetchKeyPackagesRequest, + GroupMessage, GroupMessageInput, KeyPackageUpload, PagingInfo, QueryGroupMessagesRequest, + QueryWelcomeMessagesRequest, SendGroupMessagesRequest, SendWelcomeMessagesRequest, + SortDirection, SubscribeGroupMessagesRequest, SubscribeWelcomeMessagesRequest, + UploadKeyPackageRequest, WelcomeMessage, WelcomeMessageInput, }; use xmtp_proto::{Error as ApiError, ErrorKind}; @@ -250,28 +249,22 @@ where } #[tracing::instrument(level = "trace", skip_all)] - pub async fn send_group_messages(&self, group_messages: Vec<&[u8]>) -> Result<(), ApiError> { + pub async fn send_group_messages( + &self, + group_messages: Vec, + ) -> Result<(), ApiError> { tracing::debug!( inbox_id = self.inbox_id, "sending [{}] group messages", group_messages.len() ); - let to_send: Vec = group_messages - .iter() - .map(|msg| GroupMessageInput { - version: Some(GroupMessageInputVersion::V1(GroupMessageInputV1 { - data: msg.to_vec(), - sender_hmac: vec![], - })), - }) - .collect(); retry_async!( self.retry_strategy, (async { self.api_client .send_group_messages(SendGroupMessagesRequest { - messages: to_send.clone(), + messages: group_messages.clone(), }) .await }) diff --git a/xmtp_mls/src/client.rs b/xmtp_mls/src/client.rs index 81751d5a8..819356dc4 100644 --- a/xmtp_mls/src/client.rs +++ b/xmtp_mls/src/client.rs @@ -32,12 +32,14 @@ use xmtp_proto::xmtp::mls::api::v1::{ use crate::{ api::ApiClientWrapper, - groups::{group_permissions::PolicySet, GroupError, GroupMetadataOptions, MlsGroup}, + groups::{ + device_sync::preference_sync::UserPreferenceUpdate, group_permissions::PolicySet, + GroupError, GroupMetadataOptions, MlsGroup, + }, identity::{parse_credential, Identity, IdentityError}, identity_updates::{load_identity_updates, IdentityUpdateError}, intents::ProcessIntentError, mutex_registry::MutexRegistry, - preferences::UserPreferenceUpdate, retry::Retry, retry_async, retryable, storage::{ diff --git a/xmtp_mls/src/configuration.rs b/xmtp_mls/src/configuration.rs index 9b36d7045..d8fa3ea65 100644 --- a/xmtp_mls/src/configuration.rs +++ b/xmtp_mls/src/configuration.rs @@ -57,3 +57,4 @@ pub const DEFAULT_GROUP_PINNED_FRAME_URL: &str = ""; // If a metadata field name starts with this character, // and it does not have a policy set, it is a super admin only field pub const SUPER_ADMIN_METADATA_PREFIX: &str = "_"; +pub(crate) const HMAC_SALT: &[u8] = b"libXMTP HKDF salt!"; diff --git a/xmtp_mls/src/groups/device_sync.rs b/xmtp_mls/src/groups/device_sync.rs index c0af9ac84..3f9536371 100644 --- a/xmtp_mls/src/groups/device_sync.rs +++ b/xmtp_mls/src/groups/device_sync.rs @@ -1,6 +1,5 @@ use super::{GroupError, MlsGroup}; use crate::configuration::NS_IN_HOUR; -use crate::preferences::UserPreferenceUpdate; use crate::retry::{Retry, RetryableError}; use crate::storage::group::{ConversationType, GroupQueryArgs}; use crate::storage::group_message::MsgQueryArgs; @@ -25,6 +24,7 @@ use aes_gcm::{ Aes256Gcm, }; use futures::{Stream, StreamExt}; +use preference_sync::UserPreferenceUpdate; use rand::{ distributions::{Alphanumeric, DistString}, Rng, RngCore, @@ -50,6 +50,7 @@ use xmtp_proto::xmtp::mls::message_contents::{ pub mod consent_sync; pub mod message_sync; +pub mod preference_sync; pub const ENC_KEY_SIZE: usize = 32; // 256-bit key pub const NONCE_SIZE: usize = 12; // 96-bit nonce diff --git a/xmtp_mls/src/groups/device_sync/consent_sync.rs b/xmtp_mls/src/groups/device_sync/consent_sync.rs index 4003322b8..d327923fe 100644 --- a/xmtp_mls/src/groups/device_sync/consent_sync.rs +++ b/xmtp_mls/src/groups/device_sync/consent_sync.rs @@ -1,5 +1,5 @@ use super::*; -use crate::{preferences::UserPreferenceUpdate, Client, XmtpApi}; +use crate::{Client, XmtpApi}; use xmtp_id::scw_verifier::SmartContractSignatureVerifier; use xmtp_proto::xmtp::mls::message_contents::UserPreferenceUpdate as UserPreferenceUpdateProto; diff --git a/xmtp_mls/src/preferences.rs b/xmtp_mls/src/groups/device_sync/preference_sync.rs similarity index 100% rename from xmtp_mls/src/preferences.rs rename to xmtp_mls/src/groups/device_sync/preference_sync.rs diff --git a/xmtp_mls/src/groups/mls_sync.rs b/xmtp_mls/src/groups/mls_sync.rs index 91426988d..d1131d40c 100644 --- a/xmtp_mls/src/groups/mls_sync.rs +++ b/xmtp_mls/src/groups/mls_sync.rs @@ -6,12 +6,12 @@ use super::{ UpdateAdminListIntentData, UpdateGroupMembershipIntentData, UpdatePermissionIntentData, }, validated_commit::{extract_group_membership, CommitValidationError}, - GroupError, IntentError, MlsGroup, ScopedGroupClient, + GroupError, HmacKey, IntentError, MlsGroup, ScopedGroupClient, }; use crate::{ codecs::{group_updated::GroupUpdatedCodec, ContentCodec}, configuration::{ - GRPC_DATA_LIMIT, MAX_GROUP_SIZE, MAX_INTENT_PUBLISH_ATTEMPTS, MAX_PAST_EPOCHS, + GRPC_DATA_LIMIT, HMAC_SALT, MAX_GROUP_SIZE, MAX_INTENT_PUBLISH_ATTEMPTS, MAX_PAST_EPOCHS, SYNC_UPDATE_INSTALLATIONS_INTERVAL_NS, }, groups::{intents::UpdateMetadataIntentData, validated_commit::ValidatedCommit}, @@ -28,14 +28,18 @@ use crate::{ refresh_state::EntityKind, serialization::{db_deserialize, db_serialize}, sql_key_store, + user_preferences::StoredUserPreferences, + StorageError, }, subscriptions::LocalEvents, - utils::{hash::sha256, id::calculate_message_id}, + utils::{hash::sha256, id::calculate_message_id, time::hmac_epoch}, xmtp_openmls_provider::XmtpOpenMlsProvider, Delete, Fetch, StoreOrIgnore, }; use crate::{groups::device_sync::DeviceSyncContent, subscriptions::SyncMessage}; use futures::future::try_join_all; +use hkdf::Hkdf; +use hmac::{Hmac, Mac}; use openmls::{ credentials::BasicCredential, extensions::Extensions, @@ -53,19 +57,22 @@ use openmls::{framing::WireFormat, prelude::BasicCredentialError}; use openmls_traits::{signatures::Signer, OpenMlsProvider}; use prost::bytes::Bytes; use prost::Message; +use sha2::Sha256; use std::{ collections::{HashMap, HashSet}, mem::{discriminant, Discriminant}, + ops::RangeInclusive, }; use thiserror::Error; use xmtp_id::{InboxId, InboxIdRef}; use xmtp_proto::xmtp::mls::{ api::v1::{ group_message::{Version as GroupMessageVersion, V1 as GroupMessageV1}, + group_message_input::{Version as GroupMessageInputVersion, V1 as GroupMessageInputV1}, welcome_message_input::{ Version as WelcomeMessageInputVersion, V1 as WelcomeMessageInputV1, }, - GroupMessage, WelcomeMessageInput, + GroupMessage, GroupMessageInput, WelcomeMessageInput, }, message_contents::{ plaintext_envelope::{v2::MessageType, Content, V1, V2}, @@ -1021,10 +1028,8 @@ where intent.id ); - self.client - .api() - .send_group_messages(vec![payload_slice]) - .await?; + let messages = self.prepare_group_messages(vec![payload_slice])?; + self.client.api().send_group_messages(messages).await?; tracing::info!( intent.id, @@ -1387,6 +1392,62 @@ where try_join_all(futures).await?; Ok(()) } + + /// Provides hmac keys for a range of epochs around current epoch + /// `group.hmac_keys(-1..=1)`` will provide 3 keys consisting of last epoch, current epoch, and next epoch + /// `group.hmac_keys(0..=0) will provide 1 key, consisting of only the current epoch + #[tracing::instrument(level = "trace", skip_all)] + pub fn hmac_keys( + &self, + epoch_delta_range: RangeInclusive, + ) -> Result, StorageError> { + let conn = self.client.store().conn()?; + let mut ikm = StoredUserPreferences::load(&conn)?.hmac_key; + ikm.extend(&self.group_id); + let hkdf = Hkdf::::new(Some(HMAC_SALT), &ikm[..]); + + let mut result = vec![]; + let current_epoch = hmac_epoch(); + for delta in epoch_delta_range { + let mut key = [0; 42]; + let epoch = current_epoch + delta; + hkdf.expand(&epoch.to_le_bytes(), &mut key) + .expect("Length is correct"); + + result.push(HmacKey { key, epoch }); + } + + Ok(result) + } + + #[tracing::instrument(level = "trace", skip_all)] + pub(super) fn prepare_group_messages( + &self, + payloads: Vec<&[u8]>, + ) -> Result, GroupError> { + let hmac_key = self + .hmac_keys(0..=0)? + .pop() + .expect("Range of count 1 was provided."); + let sender_hmac = + Hmac::::new_from_slice(&hmac_key.key).expect("HMAC can take key of any size"); + + let mut result = vec![]; + for payload in payloads { + let mut sender_hmac = sender_hmac.clone(); + sender_hmac.update(payload); + let sender_hmac = sender_hmac.finalize(); + + result.push(GroupMessageInput { + version: Some(GroupMessageInputVersion::V1(GroupMessageInputV1 { + data: payload.to_vec(), + sender_hmac: sender_hmac.into_bytes().to_vec(), + })), + }); + } + + Ok(result) + } } // Extracts the message sender, but does not do any validation to ensure that the @@ -1569,4 +1630,30 @@ pub(crate) mod tests { } future::join_all(futures).await; } + + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), tokio::test(flavor = "multi_thread"))] + async fn hmac_keys_work_as_expected() { + let wallet = generate_local_wallet(); + let amal = Arc::new(ClientBuilder::new_test_client(&wallet).await); + let amal_group: Arc> = + Arc::new(amal.create_group(None, Default::default()).unwrap()); + + let hmac_keys = amal_group.hmac_keys(-1..=1).unwrap(); + let current_hmac_key = amal_group.hmac_keys(0..=0).unwrap().pop().unwrap(); + assert_eq!(hmac_keys.len(), 3); + assert_eq!(hmac_keys[1].key, current_hmac_key.key); + assert_eq!(hmac_keys[1].epoch, current_hmac_key.epoch); + + // Make sure the keys are different + assert_ne!(hmac_keys[0].key, hmac_keys[1].key); + assert_ne!(hmac_keys[0].key, hmac_keys[2].key); + assert_ne!(hmac_keys[1].key, hmac_keys[2].key); + + // Make sure the epochs align + let current_epoch = hmac_epoch(); + assert_eq!(hmac_keys[0].epoch, current_epoch - 1); + assert_eq!(hmac_keys[1].epoch, current_epoch); + assert_eq!(hmac_keys[2].epoch, current_epoch + 1); + } } diff --git a/xmtp_mls/src/groups/mod.rs b/xmtp_mls/src/groups/mod.rs index f23bb8b6b..360245fd1 100644 --- a/xmtp_mls/src/groups/mod.rs +++ b/xmtp_mls/src/groups/mod.rs @@ -11,6 +11,7 @@ pub(super) mod mls_sync; pub(super) mod subscriptions; pub mod validated_commit; +use device_sync::preference_sync::UserPreferenceUpdate; use intents::SendMessageIntentData; use mls_sync::GroupMessageProcessingError; use openmls::{ @@ -83,7 +84,6 @@ use crate::{ identity::{parse_credential, IdentityError}, identity_updates::{load_identity_updates, InstallationDiffError}, intents::ProcessIntentError, - preferences::UserPreferenceUpdate, retry::RetryableError, storage::{ consent_record::{ConsentState, ConsentType, StoredConsentRecord}, @@ -285,6 +285,12 @@ impl Clone for MlsGroup { } } +pub struct HmacKey { + pub key: [u8; 42], + // # of 30 day periods since unix epoch + pub epoch: i64, +} + #[derive(Debug, Clone, PartialEq)] pub enum UpdateAdminListType { Add, @@ -1686,9 +1692,12 @@ pub(crate) mod tests { }], serialized_welcome, ); + let messages = sender_group + .prepare_group_messages(vec![serialized_commit.as_slice()]) + .unwrap(); sender_client .api_client - .send_group_messages(vec![serialized_commit.as_slice()]) + .send_group_messages(messages) .await .unwrap(); sender_group diff --git a/xmtp_mls/src/lib.rs b/xmtp_mls/src/lib.rs index cf0a08702..fb21ba10b 100644 --- a/xmtp_mls/src/lib.rs +++ b/xmtp_mls/src/lib.rs @@ -12,7 +12,6 @@ pub mod identity; pub mod identity_updates; mod intents; mod mutex_registry; -mod preferences; pub mod retry; pub mod storage; mod stream_handles; diff --git a/xmtp_mls/src/storage/encrypted_store/schema.rs b/xmtp_mls/src/storage/encrypted_store/schema.rs index 2c1f722fa..14ede47e5 100644 --- a/xmtp_mls/src/storage/encrypted_store/schema.rs +++ b/xmtp_mls/src/storage/encrypted_store/schema.rs @@ -110,7 +110,7 @@ diesel::table! { diesel::table! { user_preferences (id) { id -> Nullable, - hmac_key -> Nullable, + hmac_key -> Binary, } } diff --git a/xmtp_mls/src/storage/encrypted_store/user_preferences.rs b/xmtp_mls/src/storage/encrypted_store/user_preferences.rs index 0810a415b..9d59bc299 100644 --- a/xmtp_mls/src/storage/encrypted_store/user_preferences.rs +++ b/xmtp_mls/src/storage/encrypted_store/user_preferences.rs @@ -5,16 +5,27 @@ use super::{ DbConnection, }; use diesel::prelude::*; +use rand::{rngs::OsRng, RngCore}; -#[derive(Identifiable, Insertable, Queryable, Debug, Clone, PartialEq, Eq, Default)] +#[derive(Identifiable, Insertable, Queryable, Debug, Clone, PartialEq, Eq)] #[diesel(table_name = user_preferences)] #[diesel(primary_key(id))] pub struct StoredUserPreferences { /// Primary key - latest key is the "current" preference pub id: Option, /// Randomly generated hmac key root - pub hmac_key: Option>, + pub hmac_key: Vec, } + +impl Default for StoredUserPreferences { + fn default() -> Self { + let mut hmac_key = vec![0; 32]; + OsRng.fill_bytes(&mut hmac_key); + + Self { id: None, hmac_key } + } +} + impl_store!(StoredUserPreferences, user_preferences); impl StoredUserPreferences { @@ -22,13 +33,25 @@ impl StoredUserPreferences { let query = dsl::user_preferences.order(dsl::id.desc()).limit(1); let mut result = conn.raw_query(|conn| query.load::(conn))?; - Ok(result.pop().unwrap_or_default()) + let result = match result.pop() { + Some(result) => result, + None => { + // Create a default and store it. + let result = Self::default(); + // TODO: emit an hmac key update event here. + result.store(conn)?; + result + } + }; + + Ok(result) } pub fn set_hmac_key(conn: &DbConnection, hmac_key: Vec) -> Result<(), StorageError> { let mut preferences = Self::load(conn)?; + // Have the id increment preferences.id = None; - preferences.hmac_key = Some(hmac_key); + preferences.hmac_key = hmac_key; preferences.store(conn)?; @@ -38,7 +61,7 @@ impl StoredUserPreferences { #[cfg(test)] mod tests { - use crate::{storage::encrypted_store::tests::with_connection, Store}; + use crate::storage::encrypted_store::tests::with_connection; #[cfg(target_arch = "wasm32")] wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_dedicated_worker); @@ -46,14 +69,10 @@ mod tests { #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] - async fn test_insert_and_upate_preferences() { + async fn test_insert_and_update_preferences() { with_connection(|conn| { - // loads a default - let pref = StoredUserPreferences::load(conn).unwrap(); - assert_eq!(pref, StoredUserPreferences::default()); - assert_eq!(pref.id, None); - // save that default - pref.store(conn).unwrap(); + // loads and stores a default + let _pref = StoredUserPreferences::load(conn).unwrap(); // set an hmac key let hmac_key = vec![1, 2, 1, 2, 1, 2, 1, 2, 1, 2]; @@ -61,7 +80,7 @@ mod tests { // load preferences from db let pref = StoredUserPreferences::load(conn).unwrap(); - assert_eq!(pref.hmac_key, Some(hmac_key)); + assert_eq!(pref.hmac_key, hmac_key); assert_eq!(pref.id, Some(2)); // check that there are two preferences stored diff --git a/xmtp_mls/src/subscriptions.rs b/xmtp_mls/src/subscriptions.rs index b14a9291c..d90bab05f 100644 --- a/xmtp_mls/src/subscriptions.rs +++ b/xmtp_mls/src/subscriptions.rs @@ -13,10 +13,10 @@ use xmtp_proto::{api_client::XmtpMlsStreams, xmtp::mls::api::v1::WelcomeMessage} use crate::{ client::{extract_welcome_message, ClientError}, groups::{ - group_metadata::GroupMetadata, mls_sync::GroupMessageProcessingError, - scoped_client::ScopedGroupClient as _, subscriptions, GroupError, MlsGroup, + device_sync::preference_sync::UserPreferenceUpdate, group_metadata::GroupMetadata, + mls_sync::GroupMessageProcessingError, scoped_client::ScopedGroupClient as _, + subscriptions, GroupError, MlsGroup, }, - preferences::UserPreferenceUpdate, retry::{Retry, RetryableError}, retry_async, retryable, storage::{ diff --git a/xmtp_mls/src/utils/mod.rs b/xmtp_mls/src/utils/mod.rs index 19872e390..a81bba777 100644 --- a/xmtp_mls/src/utils/mod.rs +++ b/xmtp_mls/src/utils/mod.rs @@ -8,16 +8,30 @@ pub mod hash { } pub mod time { + use std::time::Duration; + use wasm_timer::{SystemTime, UNIX_EPOCH}; pub const NS_IN_SEC: i64 = 1_000_000_000; + const SECS_IN_30_DAYS: i64 = 60 * 60 * 24 * 30; + + fn duration_since_epoch() -> Duration { + SystemTime::now() + .duration_since(UNIX_EPOCH) + .expect("Time went backwards") + } pub fn now_ns() -> i64 { - let now = SystemTime::now(); + duration_since_epoch().as_nanos() as i64 + } - now.duration_since(UNIX_EPOCH) - .expect("Time went backwards") - .as_nanos() as i64 + pub fn now_secs() -> i64 { + duration_since_epoch().as_secs() as i64 + } + + /// Current hmac epoch. HMAC keys change every 30 days + pub fn hmac_epoch() -> i64 { + now_secs() / SECS_IN_30_DAYS } } diff --git a/xmtp_v2/Cargo.toml b/xmtp_v2/Cargo.toml index b1fcf7e7a..5917affcd 100644 --- a/xmtp_v2/Cargo.toml +++ b/xmtp_v2/Cargo.toml @@ -1,19 +1,19 @@ [package] edition = "2021" +license.workspace = true name = "xmtp_v2" rust-version = "1.64" version.workspace = true -license.workspace = true [dependencies] aes-gcm = "0.10.1" ecdsa = "0.15.1" generic-array = "0.14.6" hex = { workspace = true } -hkdf = "0.12.3" +hkdf.workspace = true k256 = { version = "0.12.0", features = ["ecdh"] } rand = { workspace = true } -sha2 = "0.10.6" +sha2.workspace = true sha3 = "0.10.6" [target.'cfg(target_arch = "wasm32")'.dependencies] From 481fad74ff60bc1f9e3f5d45266ff66849943474 Mon Sep 17 00:00:00 2001 From: Dakota Brink <779390+codabrink@users.noreply.github.com> Date: Tue, 10 Dec 2024 12:38:26 -0500 Subject: [PATCH 40/46] Dry up the streaming code, add a couple of sanity checks to tests, un-ignore test (#1398) * update the stream tests a bit * add a dm and a message * dry the code * cleanup --- bindings_ffi/src/mls.rs | 58 +++++++++++++++++++++-------------- xmtp_mls/src/subscriptions.rs | 23 ++++++-------- 2 files changed, 45 insertions(+), 36 deletions(-) diff --git a/bindings_ffi/src/mls.rs b/bindings_ffi/src/mls.rs index 6a8955bec..22f56f725 100644 --- a/bindings_ffi/src/mls.rs +++ b/bindings_ffi/src/mls.rs @@ -1036,41 +1036,33 @@ impl FfiConversations { &self, message_callback: Arc, ) -> FfiStreamCloser { - let handle = RustXmtpClient::stream_all_messages_with_callback( - self.inner_client.clone(), - Some(ConversationType::Group), - move |msg| match msg { - Ok(m) => message_callback.on_message(m.into()), - Err(e) => message_callback.on_error(e.into()), - }, - ); - - FfiStreamCloser::new(handle) + self.stream_messages(message_callback, Some(FfiConversationType::Group)) + .await } pub async fn stream_all_dm_messages( &self, message_callback: Arc, ) -> FfiStreamCloser { - let handle = RustXmtpClient::stream_all_messages_with_callback( - self.inner_client.clone(), - Some(ConversationType::Dm), - move |msg| match msg { - Ok(m) => message_callback.on_message(m.into()), - Err(e) => message_callback.on_error(e.into()), - }, - ); - - FfiStreamCloser::new(handle) + self.stream_messages(message_callback, Some(FfiConversationType::Dm)) + .await } pub async fn stream_all_messages( &self, message_callback: Arc, + ) -> FfiStreamCloser { + self.stream_messages(message_callback, None).await + } + + async fn stream_messages( + &self, + message_callback: Arc, + conversation_type: Option, ) -> FfiStreamCloser { let handle = RustXmtpClient::stream_all_messages_with_callback( self.inner_client.clone(), - None, + conversation_type.map(Into::into), move |msg| match msg { Ok(m) => message_callback.on_message(m.into()), Err(e) => message_callback.on_error(e.into()), @@ -1093,6 +1085,16 @@ impl FfiConversations { } } +impl From for ConversationType { + fn from(value: FfiConversationType) -> Self { + match value { + FfiConversationType::Dm => ConversationType::Dm, + FfiConversationType::Group => ConversationType::Group, + FfiConversationType::Sync => ConversationType::Sync, + } + } +} + #[derive(uniffi::Object)] pub struct FfiConversation { inner: MlsGroup, @@ -2512,7 +2514,6 @@ mod tests { // Looks like this test might be a separate issue #[tokio::test(flavor = "multi_thread", worker_threads = 5)] - #[ignore] async fn test_can_stream_group_messages_for_updates() { let alix = new_test_client().await; let bo = new_test_client().await; @@ -2554,6 +2555,17 @@ mod tests { .unwrap(); message_callbacks.wait_for_delivery(None).await.unwrap(); + alix_group.send(b"Hello there".to_vec()).await.unwrap(); + message_callbacks.wait_for_delivery(None).await.unwrap(); + + let dm = bo + .conversations() + .create_dm(alix.account_address.clone()) + .await + .unwrap(); + dm.send(b"Hello again".to_vec()).await.unwrap(); + message_callbacks.wait_for_delivery(None).await.unwrap(); + // Uncomment the following lines to add more group name updates bo_group .update_group_name("Old Name3".to_string()) @@ -2561,7 +2573,7 @@ mod tests { .unwrap(); message_callbacks.wait_for_delivery(None).await.unwrap(); - assert_eq!(message_callbacks.message_count(), 3); + assert_eq!(message_callbacks.message_count(), 6); stream_messages.end_and_wait().await.unwrap(); diff --git a/xmtp_mls/src/subscriptions.rs b/xmtp_mls/src/subscriptions.rs index d90bab05f..94b93c537 100644 --- a/xmtp_mls/src/subscriptions.rs +++ b/xmtp_mls/src/subscriptions.rs @@ -546,6 +546,7 @@ pub(crate) mod tests { Arc, }; use xmtp_cryptography::utils::generate_local_wallet; + use xmtp_id::InboxOwner; #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] #[cfg_attr(not(target_arch = "wasm32"), tokio::test(flavor = "current_thread"))] @@ -702,7 +703,8 @@ pub(crate) mod tests { async fn test_stream_all_messages_changing_group_list() { let alix = Arc::new(ClientBuilder::new_test_client(&generate_local_wallet()).await); let bo = ClientBuilder::new_test_client(&generate_local_wallet()).await; - let caro = Arc::new(ClientBuilder::new_test_client(&generate_local_wallet()).await); + let caro_wallet = generate_local_wallet(); + let caro = Arc::new(ClientBuilder::new_test_client(&caro_wallet).await); let alix_group = alix .create_group(None, GroupMetadataOptions::default()) @@ -726,27 +728,21 @@ pub(crate) mod tests { ); handle.wait_for_ready().await; - alix_group.send_message("first".as_bytes()).await.unwrap(); + alix_group.send_message(b"first").await.unwrap(); delivery .wait_for_delivery() .await .expect("timed out waiting for `first`"); - let bo_group = bo - .create_group(None, GroupMetadataOptions::default()) - .unwrap(); - bo_group - .add_members_by_inbox_id(&[caro.inbox_id()]) - .await - .unwrap(); + let bo_group = bo.create_dm(caro_wallet.get_address()).await.unwrap(); - bo_group.send_message("second".as_bytes()).await.unwrap(); + bo_group.send_message(b"second").await.unwrap(); delivery .wait_for_delivery() .await .expect("timed out waiting for `second`"); - alix_group.send_message("third".as_bytes()).await.unwrap(); + alix_group.send_message(b"third").await.unwrap(); delivery .wait_for_delivery() .await @@ -760,13 +756,13 @@ pub(crate) mod tests { .await .unwrap(); - alix_group.send_message("fourth".as_bytes()).await.unwrap(); + alix_group.send_message(b"fourth").await.unwrap(); delivery .wait_for_delivery() .await .expect("timed out waiting for `fourth`"); - alix_group_2.send_message("fifth".as_bytes()).await.unwrap(); + alix_group_2.send_message(b"fifth").await.unwrap(); delivery .wait_for_delivery() .await @@ -789,6 +785,7 @@ pub(crate) mod tests { crate::sleep(core::time::Duration::from_millis(100)).await; let messages = messages.lock(); + assert_eq!(messages.len(), 5); } From 9579cf37b2e9cf1fca4551710044d753dbc03c4a Mon Sep 17 00:00:00 2001 From: Cameron Voell <1103838+cameronvoell@users.noreply.github.com> Date: Wed, 11 Dec 2024 13:43:49 -0800 Subject: [PATCH 41/46] Adds tests showing authn abilities lost after wallet is associated to another inbox_id (#1406) * adds tests showing authentication abilities lost after wallet is associated to another inbox_id * fix lint warnings --------- Co-authored-by: cameronvoell --- bindings_ffi/src/mls.rs | 226 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 226 insertions(+) diff --git a/bindings_ffi/src/mls.rs b/bindings_ffi/src/mls.rs index 22f56f725..b3a3b74b3 100644 --- a/bindings_ffi/src/mls.rs +++ b/bindings_ffi/src/mls.rs @@ -4460,4 +4460,230 @@ mod tests { "Hello in group" ); } + + #[tokio::test(flavor = "multi_thread", worker_threads = 5)] + async fn test_can_not_create_new_inbox_id_with_already_associated_wallet() { + // Step 1: Generate wallet A + let wallet_a = generate_local_wallet(); + + // Step 2: Use wallet A to create a new client with a new inbox id derived from wallet A + let wallet_a_inbox_id = generate_inbox_id(&wallet_a.get_address(), &1).unwrap(); + let client_a = create_client( + xmtp_api_grpc::LOCALHOST_ADDRESS.to_string(), + false, + Some(tmp_path()), + Some(xmtp_mls::storage::EncryptedMessageStore::generate_enc_key().into()), + &wallet_a_inbox_id, + wallet_a.get_address(), + 1, + None, + Some(HISTORY_SYNC_URL.to_string()), + ) + .await + .unwrap(); + let ffi_inbox_owner = LocalWalletInboxOwner::with_wallet(wallet_a.clone()); + register_client(&ffi_inbox_owner, &client_a).await; + + // Step 3: Generate wallet B + let wallet_b = generate_local_wallet(); + + // Step 4: Associate wallet B to inbox A + let add_wallet_signature_request = client_a + .add_wallet(&wallet_b.get_address()) + .await + .expect("could not add wallet"); + add_wallet_signature_request + .add_wallet_signature(&wallet_b) + .await; + client_a + .apply_signature_request(add_wallet_signature_request) + .await + .unwrap(); + + // Verify that we can now use wallet B to create a new client that has inbox_id == client_a.inbox_id + let nonce = 1; + let inbox_id = client_a.inbox_id(); + + let client_b = create_client( + xmtp_api_grpc::LOCALHOST_ADDRESS.to_string(), + false, + Some(tmp_path()), + Some(xmtp_mls::storage::EncryptedMessageStore::generate_enc_key().into()), + &inbox_id, + wallet_b.get_address(), + nonce, + None, + Some(HISTORY_SYNC_URL.to_string()), + ) + .await + .unwrap(); + let ffi_inbox_owner = LocalWalletInboxOwner::with_wallet(wallet_b.clone()); + register_client(&ffi_inbox_owner, &client_b).await; + + assert!(client_b.inbox_id() == client_a.inbox_id()); + + // Verify both clients can receive messages for inbox_id == client_a.inbox_id + let bo = new_test_client().await; + + // Alix creates DM with Bo + let bo_dm = bo + .conversations() + .create_dm(wallet_a.get_address().clone()) + .await + .unwrap(); + + bo_dm.send("Hello in DM".as_bytes().to_vec()).await.unwrap(); + + // Verify that client_a and client_b received the dm message to wallet a address + client_a + .conversations() + .sync_all_conversations(None) + .await + .unwrap(); + client_b + .conversations() + .sync_all_conversations(None) + .await + .unwrap(); + + let alix_dm_messages = client_a + .conversations() + .list(FfiListConversationsOptions::default()) + .await + .unwrap()[0] + .find_messages(FfiListMessagesOptions::default()) + .unwrap(); + let bo_dm_messages = client_b + .conversations() + .list(FfiListConversationsOptions::default()) + .await + .unwrap()[0] + .find_messages(FfiListMessagesOptions::default()) + .unwrap(); + assert_eq!(alix_dm_messages[0].content, "Hello in DM".as_bytes()); + assert_eq!(bo_dm_messages[0].content, "Hello in DM".as_bytes()); + + let client_b_inbox_id = generate_inbox_id(&wallet_b.get_address(), &nonce).unwrap(); + let client_b_new_result = create_client( + xmtp_api_grpc::LOCALHOST_ADDRESS.to_string(), + false, + Some(tmp_path()), + Some(xmtp_mls::storage::EncryptedMessageStore::generate_enc_key().into()), + &client_b_inbox_id, + wallet_b.get_address(), + nonce, + None, + Some(HISTORY_SYNC_URL.to_string()), + ) + .await; + + // Client creation for b now fails since wallet b is already associated with inbox a + match client_b_new_result { + Err(err) => { + println!("Error returned: {:?}", err); + assert_eq!( + err.to_string(), + "Client builder error: error creating new identity: Inbox ID mismatch" + .to_string() + ); + } + Ok(_) => panic!("Expected an error, but got Ok"), + } + } + + #[tokio::test(flavor = "multi_thread", worker_threads = 5)] + async fn test_wallet_b_cannot_create_new_client_for_inbox_b_after_association() { + // Step 1: Wallet A creates a new client with inbox_id A + let wallet_a = generate_local_wallet(); + let wallet_a_inbox_id = generate_inbox_id(&wallet_a.get_address(), &1).unwrap(); + let client_a = create_client( + xmtp_api_grpc::LOCALHOST_ADDRESS.to_string(), + false, + Some(tmp_path()), + Some(xmtp_mls::storage::EncryptedMessageStore::generate_enc_key().into()), + &wallet_a_inbox_id, + wallet_a.get_address(), + 1, + None, + Some(HISTORY_SYNC_URL.to_string()), + ) + .await + .unwrap(); + let ffi_inbox_owner_a = LocalWalletInboxOwner::with_wallet(wallet_a.clone()); + register_client(&ffi_inbox_owner_a, &client_a).await; + + // Step 2: Wallet B creates a new client with inbox_id B + let wallet_b = generate_local_wallet(); + let wallet_b_inbox_id = generate_inbox_id(&wallet_b.get_address(), &1).unwrap(); + let client_b1 = create_client( + xmtp_api_grpc::LOCALHOST_ADDRESS.to_string(), + false, + Some(tmp_path()), + Some(xmtp_mls::storage::EncryptedMessageStore::generate_enc_key().into()), + &wallet_b_inbox_id, + wallet_b.get_address(), + 1, + None, + Some(HISTORY_SYNC_URL.to_string()), + ) + .await + .unwrap(); + let ffi_inbox_owner_b1 = LocalWalletInboxOwner::with_wallet(wallet_b.clone()); + register_client(&ffi_inbox_owner_b1, &client_b1).await; + + // Step 3: Wallet B creates a second client for inbox_id B + let _client_b2 = create_client( + xmtp_api_grpc::LOCALHOST_ADDRESS.to_string(), + false, + Some(tmp_path()), + Some(xmtp_mls::storage::EncryptedMessageStore::generate_enc_key().into()), + &wallet_b_inbox_id, + wallet_b.get_address(), + 1, + None, + Some(HISTORY_SYNC_URL.to_string()), + ) + .await + .unwrap(); + + // Step 4: Client A adds association to wallet B + let add_wallet_signature_request = client_a + .add_wallet(&wallet_b.get_address()) + .await + .expect("could not add wallet"); + add_wallet_signature_request + .add_wallet_signature(&wallet_b) + .await; + client_a + .apply_signature_request(add_wallet_signature_request) + .await + .unwrap(); + + // Step 5: Wallet B tries to create another new client for inbox_id B, but it fails + let client_b3 = create_client( + xmtp_api_grpc::LOCALHOST_ADDRESS.to_string(), + false, + Some(tmp_path()), + Some(xmtp_mls::storage::EncryptedMessageStore::generate_enc_key().into()), + &wallet_b_inbox_id, + wallet_b.get_address(), + 1, + None, + Some(HISTORY_SYNC_URL.to_string()), + ) + .await; + + // Client creation for b now fails since wallet b is already associated with inbox a + match client_b3 { + Err(err) => { + println!("Error returned: {:?}", err); + assert_eq!( + err.to_string(), + "Client builder error: error creating new identity: Inbox ID mismatch" + .to_string() + ); + } + Ok(_) => panic!("Expected an error, but got Ok"), + } + } } From 4da3f363d14000eb43f7cb881ca9ce7ea0910696 Mon Sep 17 00:00:00 2001 From: Cameron Voell <1103838+cameronvoell@users.noreply.github.com> Date: Wed, 11 Dec 2024 15:18:45 -0800 Subject: [PATCH 42/46] Move content types to new crate (#1401) * feat: adding new xmtp_content_types crate * move content types to new crate * fix wasm bindings build --------- Co-authored-by: cameronvoell --- Cargo.lock | 13 +++++++++++++ Cargo.toml | 2 ++ examples/cli/Cargo.toml | 1 + examples/cli/cli-client.rs | 2 +- examples/cli/serializable.rs | 8 ++------ xmtp_content_types/Cargo.toml | 16 ++++++++++++++++ .../src}/group_updated.rs | 2 +- .../mod.rs => xmtp_content_types/src/lib.rs | 9 ++++++++- .../src}/membership_change.rs | 2 +- xmtp_content_types/src/test_utils.rs | 15 +++++++++++++++ .../codecs => xmtp_content_types/src}/text.rs | 2 +- xmtp_mls/Cargo.toml | 1 + xmtp_mls/src/groups/mls_sync.rs | 4 ++-- xmtp_mls/src/groups/mod.rs | 2 +- xmtp_mls/src/lib.rs | 1 - 15 files changed, 65 insertions(+), 15 deletions(-) create mode 100644 xmtp_content_types/Cargo.toml rename {xmtp_mls/src/codecs => xmtp_content_types/src}/group_updated.rs (98%) rename xmtp_mls/src/codecs/mod.rs => xmtp_content_types/src/lib.rs (82%) rename {xmtp_mls/src/codecs => xmtp_content_types/src}/membership_change.rs (98%) create mode 100644 xmtp_content_types/src/test_utils.rs rename {xmtp_mls/src/codecs => xmtp_content_types/src}/text.rs (97%) diff --git a/Cargo.lock b/Cargo.lock index 17a96844d..96b598356 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7294,12 +7294,24 @@ dependencies = [ "valuable", "valuable-serde", "xmtp_api_grpc", + "xmtp_content_types", "xmtp_cryptography", "xmtp_id", "xmtp_mls", "xmtp_proto", ] +[[package]] +name = "xmtp_content_types" +version = "0.1.0" +dependencies = [ + "prost", + "rand", + "thiserror 2.0.6", + "tonic", + "xmtp_proto", +] + [[package]] name = "xmtp_cryptography" version = "0.1.0" @@ -7422,6 +7434,7 @@ dependencies = [ "web-time", "xmtp_api_grpc", "xmtp_api_http", + "xmtp_content_types", "xmtp_cryptography", "xmtp_id", "xmtp_proto", diff --git a/Cargo.toml b/Cargo.toml index 0226f5a35..c72428bfd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,6 +15,7 @@ members = [ "bindings_ffi", "xtask", "xmtp_debug", + "xmtp_content_types", ] # Make the feature resolver explicit. @@ -102,6 +103,7 @@ xmtp_cryptography = { path = "xmtp_cryptography" } xmtp_id = { path = "xmtp_id" } xmtp_mls = { path = "xmtp_mls" } xmtp_proto = { path = "xmtp_proto" } +xmtp_content_types = { path = "xmtp_content_types" } [profile.dev] # Disabling debug info speeds up builds a bunch, diff --git a/examples/cli/Cargo.toml b/examples/cli/Cargo.toml index 9d837d9a1..830931bce 100644 --- a/examples/cli/Cargo.toml +++ b/examples/cli/Cargo.toml @@ -39,6 +39,7 @@ valuable = { version = "0.1", features = ["derive"] } valuable-serde = "0.1" xmtp_api_grpc = { path = "../../xmtp_api_grpc" } xmtp_cryptography = { path = "../../xmtp_cryptography" } +xmtp_content_types = { path = "../../xmtp_content_types" } xmtp_id = { path = "../../xmtp_id" } xmtp_mls = { path = "../../xmtp_mls" } xmtp_proto = { path = "../../xmtp_proto", features = ["proto_full"] } diff --git a/examples/cli/cli-client.rs b/examples/cli/cli-client.rs index a9513bec5..ec285b1d9 100755 --- a/examples/cli/cli-client.rs +++ b/examples/cli/cli-client.rs @@ -32,6 +32,7 @@ use tracing_subscriber::{ use valuable::Valuable; use xmtp_api_grpc::grpc_api_helper::Client as ClientV3; use xmtp_api_grpc::replication_client::ClientV4; +use xmtp_content_types::{text::TextCodec, ContentCodec}; use xmtp_cryptography::{ signature::{RecoverableSignature, SignatureError}, utils::rng, @@ -47,7 +48,6 @@ use xmtp_mls::XmtpApi; use xmtp_mls::{ builder::ClientBuilderError, client::ClientError, - codecs::{text::TextCodec, ContentCodec}, groups::{device_sync::MessageHistoryUrls, GroupMetadataOptions}, identity::IdentityStrategy, storage::{ diff --git a/examples/cli/serializable.rs b/examples/cli/serializable.rs index cbc3190a6..c6ee793ce 100644 --- a/examples/cli/serializable.rs +++ b/examples/cli/serializable.rs @@ -1,12 +1,8 @@ use prost::Message; use serde::Serialize; use valuable::Valuable; -use xmtp_mls::{ - codecs::{text::TextCodec, ContentCodec}, - groups::MlsGroup, - storage::group_message::StoredGroupMessage, - XmtpApi, -}; +use xmtp_content_types::{text::TextCodec, ContentCodec}; +use xmtp_mls::{groups::MlsGroup, storage::group_message::StoredGroupMessage, XmtpApi}; use xmtp_proto::xmtp::mls::message_contents::EncodedContent; #[derive(Serialize, Debug, Valuable)] diff --git a/xmtp_content_types/Cargo.toml b/xmtp_content_types/Cargo.toml new file mode 100644 index 000000000..4d0a2b2ee --- /dev/null +++ b/xmtp_content_types/Cargo.toml @@ -0,0 +1,16 @@ +[package] +edition = "2021" +name = "xmtp_content_types" +version.workspace = true +license.workspace = true + +[dependencies] +thiserror = { workspace = true } +prost = { workspace = true, features = ["prost-derive"] } +rand = { workspace = true } + +# XMTP/Local +xmtp_proto = { workspace = true, features = ["convert"] } + +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +tonic = { version = "0.12", features = ["transport"] } diff --git a/xmtp_mls/src/codecs/group_updated.rs b/xmtp_content_types/src/group_updated.rs similarity index 98% rename from xmtp_mls/src/codecs/group_updated.rs rename to xmtp_content_types/src/group_updated.rs index 09ebea595..7aa797ee0 100644 --- a/xmtp_mls/src/codecs/group_updated.rs +++ b/xmtp_content_types/src/group_updated.rs @@ -52,7 +52,7 @@ pub(crate) mod tests { use xmtp_proto::xmtp::mls::message_contents::{group_updated::Inbox, GroupUpdated}; - use crate::utils::test::rand_string; + use crate::test_utils::rand_string; use super::*; diff --git a/xmtp_mls/src/codecs/mod.rs b/xmtp_content_types/src/lib.rs similarity index 82% rename from xmtp_mls/src/codecs/mod.rs rename to xmtp_content_types/src/lib.rs index dc44e7cf4..b882891a1 100644 --- a/xmtp_mls/src/codecs/mod.rs +++ b/xmtp_content_types/src/lib.rs @@ -1,11 +1,18 @@ pub mod group_updated; pub mod membership_change; +#[cfg(test)] +mod test_utils; pub mod text; use thiserror::Error; - use xmtp_proto::xmtp::mls::message_contents::{ContentTypeId, EncodedContent}; +pub enum ContentType { + GroupMembershipChange, + GroupUpdated, + Text, +} + #[derive(Debug, Error)] pub enum CodecError { #[error("encode error {0}")] diff --git a/xmtp_mls/src/codecs/membership_change.rs b/xmtp_content_types/src/membership_change.rs similarity index 98% rename from xmtp_mls/src/codecs/membership_change.rs rename to xmtp_content_types/src/membership_change.rs index e64f50df6..b83483806 100644 --- a/xmtp_mls/src/codecs/membership_change.rs +++ b/xmtp_content_types/src/membership_change.rs @@ -54,7 +54,7 @@ pub(crate) mod tests { use xmtp_proto::xmtp::mls::message_contents::MembershipChange; - use crate::utils::test::{rand_string, rand_vec}; + use crate::test_utils::{rand_string, rand_vec}; use super::*; diff --git a/xmtp_content_types/src/test_utils.rs b/xmtp_content_types/src/test_utils.rs new file mode 100644 index 000000000..dead0c7e6 --- /dev/null +++ b/xmtp_content_types/src/test_utils.rs @@ -0,0 +1,15 @@ +#[cfg(test)] +use rand::{ + distributions::{Alphanumeric, DistString}, + Rng, +}; + +#[cfg(test)] +pub(crate) fn rand_string() -> String { + Alphanumeric.sample_string(&mut rand::thread_rng(), 24) +} + +#[cfg(test)] +pub(crate) fn rand_vec() -> Vec { + rand::thread_rng().gen::<[u8; 24]>().to_vec() +} diff --git a/xmtp_mls/src/codecs/text.rs b/xmtp_content_types/src/text.rs similarity index 97% rename from xmtp_mls/src/codecs/text.rs rename to xmtp_content_types/src/text.rs index d016f1513..124fb7831 100644 --- a/xmtp_mls/src/codecs/text.rs +++ b/xmtp_content_types/src/text.rs @@ -58,7 +58,7 @@ pub(crate) mod tests { #[cfg(target_arch = "wasm32")] wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_dedicated_worker); - use crate::codecs::{text::TextCodec, ContentCodec}; + use crate::{text::TextCodec, ContentCodec}; #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] #[cfg_attr(not(target_arch = "wasm32"), test)] diff --git a/xmtp_mls/Cargo.toml b/xmtp_mls/Cargo.toml index c1f8b4c72..e9d16676d 100644 --- a/xmtp_mls/Cargo.toml +++ b/xmtp_mls/Cargo.toml @@ -73,6 +73,7 @@ web-time.workspace = true zeroize.workspace = true # XMTP/Local +xmtp_content_types = { path = "../xmtp_content_types" } xmtp_cryptography = { workspace = true } xmtp_id = { path = "../xmtp_id" } xmtp_proto = { workspace = true, features = ["convert"] } diff --git a/xmtp_mls/src/groups/mls_sync.rs b/xmtp_mls/src/groups/mls_sync.rs index d1131d40c..a613551f8 100644 --- a/xmtp_mls/src/groups/mls_sync.rs +++ b/xmtp_mls/src/groups/mls_sync.rs @@ -9,7 +9,6 @@ use super::{ GroupError, HmacKey, IntentError, MlsGroup, ScopedGroupClient, }; use crate::{ - codecs::{group_updated::GroupUpdatedCodec, ContentCodec}, configuration::{ GRPC_DATA_LIMIT, HMAC_SALT, MAX_GROUP_SIZE, MAX_INTENT_PUBLISH_ATTEMPTS, MAX_PAST_EPOCHS, SYNC_UPDATE_INSTALLATIONS_INTERVAL_NS, @@ -64,6 +63,7 @@ use std::{ ops::RangeInclusive, }; use thiserror::Error; +use xmtp_content_types::{group_updated::GroupUpdatedCodec, CodecError, ContentCodec}; use xmtp_id::{InboxId, InboxIdRef}; use xmtp_proto::xmtp::mls::{ api::v1::{ @@ -122,7 +122,7 @@ pub enum GroupMessageProcessingError { #[error(transparent)] Intent(#[from] IntentError), #[error(transparent)] - Codec(#[from] crate::codecs::CodecError), + Codec(#[from] CodecError), #[error("wrong credential type")] WrongCredentialType(#[from] BasicCredentialError), #[error(transparent)] diff --git a/xmtp_mls/src/groups/mod.rs b/xmtp_mls/src/groups/mod.rs index 360245fd1..c8e19e933 100644 --- a/xmtp_mls/src/groups/mod.rs +++ b/xmtp_mls/src/groups/mod.rs @@ -1609,6 +1609,7 @@ pub(crate) mod tests { use openmls::prelude::Member; use prost::Message; use std::sync::Arc; + use xmtp_content_types::{group_updated::GroupUpdatedCodec, ContentCodec}; use xmtp_cryptography::utils::generate_local_wallet; use xmtp_proto::xmtp::mls::api::v1::group_message::Version; use xmtp_proto::xmtp::mls::message_contents::EncodedContent; @@ -1616,7 +1617,6 @@ pub(crate) mod tests { use crate::{ assert_err, builder::ClientBuilder, - codecs::{group_updated::GroupUpdatedCodec, ContentCodec}, groups::{ build_dm_protected_metadata_extension, build_mutable_metadata_extension_default, build_protected_metadata_extension, diff --git a/xmtp_mls/src/lib.rs b/xmtp_mls/src/lib.rs index fb21ba10b..71d2ede3f 100644 --- a/xmtp_mls/src/lib.rs +++ b/xmtp_mls/src/lib.rs @@ -4,7 +4,6 @@ pub mod api; pub mod builder; pub mod client; -pub mod codecs; pub mod configuration; pub mod groups; mod hpke; From cf64bae0f68d80024c3f6564a03f474fc22c70a6 Mon Sep 17 00:00:00 2001 From: Andrew Plaza Date: Thu, 12 Dec 2024 10:04:17 -0500 Subject: [PATCH 43/46] re-add webpki to native (#1407) --- xmtp_api_grpc/Cargo.toml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/xmtp_api_grpc/Cargo.toml b/xmtp_api_grpc/Cargo.toml index 7c4ebee2c..b69a0d0c4 100644 --- a/xmtp_api_grpc/Cargo.toml +++ b/xmtp_api_grpc/Cargo.toml @@ -17,13 +17,17 @@ xmtp_proto = { path = "../xmtp_proto", features = ["proto_full"] } xmtp_v2 = { path = "../xmtp_v2" } zeroize.workspace = true +# Anything but iOS and Android will use either webpki or native. +# If native certs are not found, it will fallback to webpki [target.'cfg(not(any(target_os = "android", target_os = "ios")))'.dependencies] tonic = { workspace = true, features = [ "default", "tls", "tls-native-roots", + "tls-webpki-roots" ] } +# Force Android + iOS to use webki [target.'cfg(any(target_os = "android", target_os = "ios"))'.dependencies] tonic = { workspace = true, features = [ "default", From 600a8e272cc082dcc7a1aeb5fbdb3584b46bacf4 Mon Sep 17 00:00:00 2001 From: Andrew Plaza Date: Thu, 12 Dec 2024 11:38:09 -0500 Subject: [PATCH 44/46] common crate, expose more tests in wasm, db test utils (#1366) * common crate for wasm shims * feedback --- .github/workflows/test-webassembly.yml | 4 +- Cargo.lock | 51 +++-- Cargo.toml | 2 + bindings_ffi/Cargo.toml | 1 + bindings_ffi/src/mls.rs | 23 +-- bindings_node/Cargo.toml | 1 + bindings_node/src/inbox_id.rs | 2 +- bindings_wasm/Cargo.toml | 1 + bindings_wasm/src/inbox_id.rs | 2 +- common/Cargo.toml | 38 ++++ common/src/lib.rs | 47 +++++ common/src/macros.rs | 24 +++ {xmtp_mls => common}/src/retry.rs | 21 +- common/src/test.rs | 183 ++++++++++++++++++ common/src/test/macros.rs | 49 +++++ .../utils => common/src}/test/traced_test.rs | 39 +++- common/src/time.rs | 99 ++++++++++ dev/wasm | 12 -- examples/cli/Cargo.toml | 1 + examples/cli/cli-client.rs | 2 +- mls_validation_service/Cargo.toml | 1 + mls_validation_service/src/handlers.rs | 5 +- xmtp_api_http/src/util.rs | 1 - xmtp_content_types/Cargo.toml | 4 + xmtp_content_types/src/group_updated.rs | 10 +- xmtp_content_types/src/lib.rs | 2 - xmtp_content_types/src/membership_change.rs | 10 +- xmtp_content_types/src/test_utils.rs | 15 -- xmtp_id/Cargo.toml | 8 +- xmtp_id/src/associations/builder.rs | 3 +- xmtp_id/src/associations/member.rs | 7 +- xmtp_id/src/associations/mod.rs | 131 ++++++------- xmtp_id/src/associations/serialization.rs | 16 +- xmtp_id/src/associations/signature.rs | 5 +- xmtp_id/src/associations/state.rs | 6 +- xmtp_id/src/associations/test_utils.rs | 23 --- xmtp_id/src/associations/unverified.rs | 7 +- .../src/associations/verified_signature.rs | 10 +- xmtp_id/src/utils/mod.rs | 11 -- xmtp_mls/Cargo.toml | 6 +- xmtp_mls/benches/crypto.rs | 1 - xmtp_mls/src/api/identity.rs | 13 +- xmtp_mls/src/api/mls.rs | 3 +- xmtp_mls/src/api/mod.rs | 6 +- xmtp_mls/src/api/test_utils.rs | 55 ------ xmtp_mls/src/builder.rs | 17 +- xmtp_mls/src/client.rs | 13 +- xmtp_mls/src/groups/device_sync.rs | 35 ++-- .../src/groups/device_sync/consent_sync.rs | 63 +++--- .../src/groups/device_sync/message_sync.rs | 96 +++------ .../src/groups/device_sync/preference_sync.rs | 7 +- xmtp_mls/src/groups/group_permissions.rs | 24 ++- xmtp_mls/src/groups/intents.rs | 2 +- xmtp_mls/src/groups/mls_sync.rs | 11 +- xmtp_mls/src/groups/mod.rs | 139 +++++-------- xmtp_mls/src/groups/scoped_client.rs | 2 +- xmtp_mls/src/groups/subscriptions.rs | 30 +-- xmtp_mls/src/groups/validated_commit.rs | 3 +- xmtp_mls/src/hpke.rs | 3 +- xmtp_mls/src/identity.rs | 12 +- xmtp_mls/src/identity_updates.rs | 16 +- xmtp_mls/src/intents.rs | 2 +- xmtp_mls/src/lib.rs | 138 +------------ xmtp_mls/src/storage/encrypted_store/group.rs | 13 +- .../storage/encrypted_store/group_intent.rs | 46 ++--- .../storage/encrypted_store/group_message.rs | 33 ++-- .../src/storage/encrypted_store/identity.rs | 7 +- .../encrypted_store/identity_update.rs | 14 +- .../encrypted_store/key_package_history.rs | 14 +- xmtp_mls/src/storage/encrypted_store/mod.rs | 41 ++-- .../encrypted_store/sqlcipher_connection.rs | 3 +- xmtp_mls/src/storage/encrypted_store/wasm.rs | 6 +- xmtp_mls/src/storage/errors.rs | 42 ++-- xmtp_mls/src/storage/mod.rs | 92 +++++++++ xmtp_mls/src/storage/sql_key_store.rs | 4 +- xmtp_mls/src/stream_handles.rs | 52 ++++- xmtp_mls/src/subscriptions.rs | 63 +++--- xmtp_mls/src/utils/mod.rs | 52 +---- xmtp_mls/src/utils/test/mod.rs | 118 ++--------- xmtp_proto/Cargo.toml | 12 +- xmtp_proto/src/api_client.rs | 6 - xmtp_proto/src/error.rs | 7 + 82 files changed, 1161 insertions(+), 1038 deletions(-) create mode 100644 common/Cargo.toml create mode 100644 common/src/lib.rs create mode 100644 common/src/macros.rs rename {xmtp_mls => common}/src/retry.rs (94%) create mode 100644 common/src/test.rs create mode 100644 common/src/test/macros.rs rename {xmtp_mls/src/utils => common/src}/test/traced_test.rs (72%) create mode 100644 common/src/time.rs delete mode 100755 dev/wasm delete mode 100644 xmtp_content_types/src/test_utils.rs diff --git a/.github/workflows/test-webassembly.yml b/.github/workflows/test-webassembly.yml index c77c0a7c1..24cabc60d 100644 --- a/.github/workflows/test-webassembly.yml +++ b/.github/workflows/test-webassembly.yml @@ -16,7 +16,7 @@ on: - "rust-toolchain" env: CARGO_TERM_COLOR: always - WASM_BINDGEN_TEST_TIMEOUT: 120 + WASM_BINDGEN_TEST_TIMEOUT: 180 WASM_BINDGEN_TEST_ONLY_WEB: 1 WASM_BINDGEN_SPLIT_LINKED_MODULES: 1 jobs: @@ -35,7 +35,7 @@ jobs: - name: Start Docker containers run: dev/up - name: Build WebAssembly Packages - run: cargo build --tests --release --target wasm32-unknown-unknown -p xmtp_id -p xmtp_mls -p xmtp_api_http -p xmtp_cryptography + run: cargo build --tests --release --target wasm32-unknown-unknown -p xmtp_id -p xmtp_mls -p xmtp_api_http -p xmtp_cryptography -p xmtp_common - name: test with chrome run: | cargo test --release --target wasm32-unknown-unknown -p xmtp_mls -p xmtp_id -p xmtp_api_http -p xmtp_cryptography -- \ diff --git a/Cargo.lock b/Cargo.lock index 96b598356..7cf24af0f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -461,6 +461,7 @@ dependencies = [ "tracing", "tracing-subscriber", "xmtp_api_grpc", + "xmtp_common", "xmtp_cryptography", "xmtp_id", "xmtp_mls", @@ -485,6 +486,7 @@ dependencies = [ "wasm-bindgen-futures", "wasm-bindgen-test", "xmtp_api_http", + "xmtp_common", "xmtp_cryptography", "xmtp_id", "xmtp_mls", @@ -3517,6 +3519,7 @@ dependencies = [ "tracing-subscriber", "vergen", "warp", + "xmtp_common", "xmtp_cryptography", "xmtp_id", "xmtp_mls", @@ -6830,21 +6833,6 @@ dependencies = [ "web-sys", ] -[[package]] -name = "wasm-timer" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be0ecb0db480561e9a7642b5d3e4187c128914e58aa84330b9493e3eb68c5e7f" -dependencies = [ - "futures", - "js-sys", - "parking_lot 0.11.2", - "pin-utils", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", -] - [[package]] name = "web-sys" version = "0.3.76" @@ -7294,6 +7282,7 @@ dependencies = [ "valuable", "valuable-serde", "xmtp_api_grpc", + "xmtp_common", "xmtp_content_types", "xmtp_cryptography", "xmtp_id", @@ -7301,6 +7290,29 @@ dependencies = [ "xmtp_proto", ] +[[package]] +name = "xmtp_common" +version = "0.1.0" +dependencies = [ + "console_error_panic_hook", + "futures", + "getrandom", + "gloo-timers 0.3.0", + "js-sys", + "parking_lot 0.12.3", + "rand", + "thiserror 2.0.6", + "tokio", + "tracing", + "tracing-subscriber", + "tracing-wasm", + "wasm-bindgen-futures", + "wasm-bindgen-test", + "web-sys", + "web-time", + "xmtp_cryptography", +] + [[package]] name = "xmtp_content_types" version = "0.1.0" @@ -7309,6 +7321,7 @@ dependencies = [ "rand", "thiserror 2.0.6", "tonic", + "xmtp_common", "xmtp_proto", ] @@ -7366,7 +7379,8 @@ dependencies = [ "tracing", "url", "wasm-bindgen-test", - "wasm-timer", + "web-time", + "xmtp_common", "xmtp_cryptography", "xmtp_proto", "xmtp_v2", @@ -7429,11 +7443,10 @@ dependencies = [ "trait-variant", "wasm-bindgen-futures", "wasm-bindgen-test", - "wasm-timer", "web-sys", - "web-time", "xmtp_api_grpc", "xmtp_api_http", + "xmtp_common", "xmtp_content_types", "xmtp_cryptography", "xmtp_id", @@ -7457,6 +7470,7 @@ dependencies = [ "tonic", "tracing", "wasm-bindgen-test", + "xmtp_common", ] [[package]] @@ -7504,6 +7518,7 @@ dependencies = [ "uniffi", "uuid 1.11.0", "xmtp_api_grpc", + "xmtp_common", "xmtp_cryptography", "xmtp_id", "xmtp_mls", diff --git a/Cargo.toml b/Cargo.toml index c72428bfd..0dde776cf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,6 +16,7 @@ members = [ "xtask", "xmtp_debug", "xmtp_content_types", + "common" ] # Make the feature resolver explicit. @@ -104,6 +105,7 @@ xmtp_id = { path = "xmtp_id" } xmtp_mls = { path = "xmtp_mls" } xmtp_proto = { path = "xmtp_proto" } xmtp_content_types = { path = "xmtp_content_types" } +xmtp_common = { path = "common" } [profile.dev] # Disabling debug info speeds up builds a bunch, diff --git a/bindings_ffi/Cargo.toml b/bindings_ffi/Cargo.toml index 938ab78b8..7e44b3498 100644 --- a/bindings_ffi/Cargo.toml +++ b/bindings_ffi/Cargo.toml @@ -22,6 +22,7 @@ xmtp_mls = { path = "../xmtp_mls" } xmtp_proto = { path = "../xmtp_proto", features = ["proto_full"] } xmtp_user_preferences = { path = "../xmtp_user_preferences" } xmtp_v2 = { path = "../xmtp_v2" } +xmtp_common.workspace = true [target.'cfg(target_os = "android")'.dependencies] paranoid-android = "0.2" diff --git a/bindings_ffi/src/mls.rs b/bindings_ffi/src/mls.rs index b3a3b74b3..a9ae8232b 100644 --- a/bindings_ffi/src/mls.rs +++ b/bindings_ffi/src/mls.rs @@ -4,6 +4,7 @@ use crate::{FfiSubscribeError, GenericError}; use std::{collections::HashMap, convert::TryInto, sync::Arc}; use tokio::sync::Mutex; use xmtp_api_grpc::grpc_api_helper::Client as TonicApiClient; +use xmtp_common::retry::Retry; use xmtp_id::associations::verify_signed_with_public_context; use xmtp_id::scw_verifier::RemoteSignatureVerifier; use xmtp_id::{ @@ -37,7 +38,6 @@ use xmtp_mls::{ GroupMetadataOptions, MlsGroup, PreconfiguredPolicies, UpdateAdminListType, }, identity::IdentityStrategy, - retry::Retry, storage::{ consent_record::{ConsentState, ConsentType, StoredConsentRecord}, group::GroupQueryArgs, @@ -1827,9 +1827,7 @@ mod tests { FfiPermissionPolicySet, FfiPermissionUpdateType, FfiSubscribeError, }; use ethers::utils::hex; - use rand::distributions::{Alphanumeric, DistString}; use std::{ - env, sync::{ atomic::{AtomicU32, Ordering}, Arc, Mutex, @@ -1837,13 +1835,14 @@ mod tests { time::{Duration, Instant}, }; use tokio::{sync::Notify, time::error::Elapsed}; + use xmtp_common::tmp_path; + use xmtp_common::{wait_for_eq, wait_for_ok}; use xmtp_cryptography::{signature::RecoverableSignature, utils::rng}; use xmtp_id::associations::{ generate_inbox_id, unverified::{UnverifiedRecoverableEcdsaSignature, UnverifiedSignature}, }; use xmtp_mls::{ - api::test_utils::{wait_for_eq, wait_for_ok}, groups::{scoped_client::LocalScopedGroupClient, GroupError}, storage::EncryptionKey, InboxOwner, @@ -1974,15 +1973,6 @@ mod tests { } } - pub fn rand_string() -> String { - Alphanumeric.sample_string(&mut rand::thread_rng(), 24) - } - - pub fn tmp_path() -> String { - let db_name = rand_string(); - format!("{}/{}.db3", env::temp_dir().to_str().unwrap(), db_name) - } - fn static_enc_key() -> EncryptionKey { [2u8; 32] } @@ -4160,7 +4150,9 @@ mod tests { let _ = wait_for_ok(|| async { alix_a.inner_client.get_sync_group(&alix_a_conn) }).await; let alix_b = new_test_client_with_wallet_and_history(wallet).await; - wait_for_eq(|| async { alix_b.inner_client.identity().is_ready() }, true).await; + wait_for_eq(|| async { alix_b.inner_client.identity().is_ready() }, true) + .await + .unwrap(); let bo = new_test_client_with_history().await; @@ -4179,7 +4171,8 @@ mod tests { }, 2, ) - .await; + .await + .unwrap(); // check that they have the same sync group let sync_group_a = wait_for_ok(|| async { alix_a.conversations().get_sync_group() }) diff --git a/bindings_node/Cargo.toml b/bindings_node/Cargo.toml index aa1038961..81729585c 100644 --- a/bindings_node/Cargo.toml +++ b/bindings_node/Cargo.toml @@ -30,6 +30,7 @@ xmtp_cryptography = { path = "../xmtp_cryptography" } xmtp_id = { path = "../xmtp_id" } xmtp_mls = { path = "../xmtp_mls" } xmtp_proto = { path = "../xmtp_proto", features = ["proto_full"] } +xmtp_common.workspace = true [build-dependencies] napi-build = "2.0.1" diff --git a/bindings_node/src/inbox_id.rs b/bindings_node/src/inbox_id.rs index b9a4d34a9..5b91cb9ea 100644 --- a/bindings_node/src/inbox_id.rs +++ b/bindings_node/src/inbox_id.rs @@ -4,10 +4,10 @@ use napi::bindgen_prelude::Uint8Array; use napi_derive::napi; use std::sync::Arc; use xmtp_api_grpc::grpc_api_helper::Client as TonicApiClient; +use xmtp_common::retry::Retry; use xmtp_id::associations::generate_inbox_id as xmtp_id_generate_inbox_id; use xmtp_id::associations::MemberIdentifier; use xmtp_mls::api::ApiClientWrapper; -use xmtp_mls::retry::Retry; #[napi] pub async fn get_inbox_id_for_address( diff --git a/bindings_wasm/Cargo.toml b/bindings_wasm/Cargo.toml index 65f79084b..20e988091 100644 --- a/bindings_wasm/Cargo.toml +++ b/bindings_wasm/Cargo.toml @@ -19,6 +19,7 @@ xmtp_api_http = { path = "../xmtp_api_http" } xmtp_cryptography = { path = "../xmtp_cryptography" } xmtp_id = { path = "../xmtp_id" } xmtp_mls = { path = "../xmtp_mls", features = ["test-utils", "http-api"] } +xmtp_common.workspace = true xmtp_proto = { path = "../xmtp_proto", features = ["proto_full"] } tracing-web = "0.1" tracing.workspace = true diff --git a/bindings_wasm/src/inbox_id.rs b/bindings_wasm/src/inbox_id.rs index 1aec357c4..d0b046f3d 100644 --- a/bindings_wasm/src/inbox_id.rs +++ b/bindings_wasm/src/inbox_id.rs @@ -1,8 +1,8 @@ use wasm_bindgen::prelude::{wasm_bindgen, JsError}; use xmtp_api_http::XmtpHttpApiClient; +use xmtp_common::retry::Retry; use xmtp_id::associations::generate_inbox_id as xmtp_id_generate_inbox_id; use xmtp_mls::api::ApiClientWrapper; -use xmtp_mls::retry::Retry; #[wasm_bindgen(js_name = getInboxIdForAddress)] pub async fn get_inbox_id_for_address( diff --git a/common/Cargo.toml b/common/Cargo.toml new file mode 100644 index 000000000..76b836916 --- /dev/null +++ b/common/Cargo.toml @@ -0,0 +1,38 @@ +[package] +name = "xmtp_common" +edition = "2021" +version.workspace = true +license.workspace = true + +[dependencies] +web-time.workspace = true +tracing.workspace = true +tokio = { workspace = true, features = ["time"] } +rand = "0.8" +futures.workspace = true +xmtp_cryptography.workspace = true + +parking_lot = { workspace = true, optional = true } +tracing-subscriber = { workspace = true, features = ["fmt", "env-filter", "ansi", "json"], optional = true } + +[target.'cfg(target_arch = "wasm32")'.dependencies] +getrandom = { workspace = true, features = ["js"] } +gloo-timers = { workspace = true, features = ["futures"] } +tracing-wasm = { version = "0.2", optional = true } +console_error_panic_hook = { version = "0.1", optional = true } +js-sys.workspace = true +web-sys = { workspace = true, features = ["Window"] } +wasm-bindgen-futures.workspace = true + +[dev-dependencies] +thiserror.workspace = true + +[target.'cfg(target_arch = "wasm32")'.dev-dependencies] +tokio = { workspace = true, features = ["time", "macros", "rt", "sync"]} +wasm-bindgen-test.workspace = true + +[target.'cfg(not(target_arch = "wasm32"))'.dev-dependencies] +tokio = { workspace = true, features = ["time", "macros", "rt-multi-thread", "sync"]} + +[features] +test-utils = ["dep:parking_lot", "dep:tracing-subscriber", "dep:tracing-wasm", "dep:console_error_panic_hook"] diff --git a/common/src/lib.rs b/common/src/lib.rs new file mode 100644 index 000000000..a198962ad --- /dev/null +++ b/common/src/lib.rs @@ -0,0 +1,47 @@ +//! Common types shared among all XMTP Crates + +mod macros; + +#[cfg(feature = "test-utils")] +mod test; +#[cfg(feature = "test-utils")] +pub use test::*; + +pub mod retry; +pub use retry::*; + +/// Global Marker trait for WebAssembly +#[cfg(target_arch = "wasm32")] +pub trait Wasm {} +#[cfg(target_arch = "wasm32")] +impl Wasm for T {} + +pub mod time; + +use rand::{ + distributions::{Alphanumeric, DistString}, + RngCore, +}; +use xmtp_cryptography::utils as crypto_utils; + +pub fn rand_string() -> String { + Alphanumeric.sample_string(&mut crypto_utils::rng(), N) +} + +pub fn rand_array() -> [u8; N] { + let mut buffer = [0u8; N]; + crypto_utils::rng().fill_bytes(&mut buffer); + buffer +} + +/// Yield back control to the async runtime +#[cfg(not(target_arch = "wasm32"))] +pub async fn yield_() { + tokio::task::yield_now().await +} + +/// Yield back control to the async runtime +#[cfg(target_arch = "wasm32")] +pub async fn yield_() { + time::sleep(crate::time::Duration::from_millis(1)).await; +} diff --git a/common/src/macros.rs b/common/src/macros.rs new file mode 100644 index 000000000..9ebf42790 --- /dev/null +++ b/common/src/macros.rs @@ -0,0 +1,24 @@ +/// Turn the `Result` into an `Option`, logging the error with `tracing::error` and +/// returning `None` if the value matches on Result::Err(). +/// Optionally pass a message as the second argument. +#[macro_export] +macro_rules! optify { + ( $e: expr ) => { + match $e { + Ok(v) => Some(v), + Err(e) => { + tracing::error!("{}", e); + None + } + } + }; + ( $e: expr, $msg: tt ) => { + match $e { + Ok(v) => Some(v), + Err(e) => { + tracing::error!("{}: {:?}", $msg, e); + None + } + } + }; +} diff --git a/xmtp_mls/src/retry.rs b/common/src/retry.rs similarity index 94% rename from xmtp_mls/src/retry.rs rename to common/src/retry.rs index 6e5aca993..3088d1dc6 100644 --- a/xmtp_mls/src/retry.rs +++ b/common/src/retry.rs @@ -18,9 +18,11 @@ use rand::Rng; +pub struct NotSpecialized; + /// Specifies which errors are retryable. /// All Errors are not retryable by-default. -pub trait RetryableError: std::error::Error { +pub trait RetryableError: std::error::Error { fn is_retryable(&self) -> bool; } @@ -76,7 +78,7 @@ pub struct RetryBuilder { /// /// # Example /// ``` -/// use xmtp_mls::retry::RetryBuilder; +/// use xmtp_common::retry::RetryBuilder; /// /// RetryBuilder::default() /// .retries(5) @@ -121,7 +123,7 @@ impl Retry { /// Retry but for an async context /// ``` -/// use xmtp_mls::{retry_async, retry::{RetryableError, Retry}}; +/// use xmtp_common::{retry_async, retry::{RetryableError, Retry}}; /// use thiserror::Error; /// use tokio::sync::mpsc; /// @@ -183,7 +185,7 @@ macro_rules! retry_async { e.to_string() ); attempts += 1; - $crate::sleep($retry.duration(attempts)).await; + $crate::time::sleep($retry.duration(attempts)).await; } else { tracing::info!("error is not retryable. {:?}:{}", e, e); break Err(e); @@ -207,13 +209,6 @@ macro_rules! retryable { }}; } -// network errors should generally be retryable, unless there's a bug in our code -impl RetryableError for xmtp_proto::Error { - fn is_retryable(&self) -> bool { - true - } -} - #[cfg(test)] pub(crate) mod tests { #[cfg(target_arch = "wasm32")] @@ -313,7 +308,7 @@ pub(crate) mod tests { return Ok(()); } // do some work - crate::sleep(core::time::Duration::from_nanos(100)).await; + crate::time::sleep(core::time::Duration::from_nanos(100)).await; Err(SomeError::ARetryableError) } @@ -339,7 +334,7 @@ pub(crate) mod tests { } *data += 1; // do some work - crate::sleep(core::time::Duration::from_nanos(100)).await; + crate::time::sleep(core::time::Duration::from_nanos(100)).await; Err(SomeError::ARetryableError) } diff --git a/common/src/test.rs b/common/src/test.rs new file mode 100644 index 000000000..c11c692cb --- /dev/null +++ b/common/src/test.rs @@ -0,0 +1,183 @@ +//! Common Test Utilites +use rand::{ + distributions::{Alphanumeric, DistString}, + seq::IteratorRandom, + Rng, +}; +use std::{future::Future, sync::OnceLock}; +use xmtp_cryptography::utils as crypto_utils; + +#[cfg(not(target_arch = "wasm32"))] +pub mod traced_test; +#[cfg(not(target_arch = "wasm32"))] +pub use traced_test::TestWriter; + +use crate::time::Expired; + +mod macros; + +static INIT: OnceLock<()> = OnceLock::new(); + +/// A simple test logger that defaults to the INFO level +#[cfg(not(all(target_family = "wasm", target_os = "unknown")))] +pub fn logger() { + use tracing_subscriber::{ + fmt::{self, format}, + layer::SubscriberExt, + util::SubscriberInitExt, + EnvFilter, Layer, + }; + + INIT.get_or_init(|| { + let structured = std::env::var("STRUCTURED"); + let is_structured = matches!(structured, Ok(s) if s == "true" || s == "1"); + + let filter = || { + EnvFilter::builder() + .with_default_directive(tracing::metadata::LevelFilter::INFO.into()) + .from_env_lossy() + }; + + tracing_subscriber::registry() + // structured JSON logger only if STRUCTURED=true + .with(is_structured.then(|| { + tracing_subscriber::fmt::layer() + .json() + .flatten_event(true) + .with_level(true) + .with_filter(filter()) + })) + // default logger + .with((!is_structured).then(|| { + fmt::layer() + .compact() + .fmt_fields({ + format::debug_fn(move |writer, field, value| { + if field.name() == "message" { + write!(writer, "{:?}", value)?; + } + Ok(()) + }) + }) + .with_filter(filter()) + })) + .init(); + }); +} + +/// A simple test logger that defaults to the INFO level +#[cfg(all(target_family = "wasm", target_os = "unknown"))] +pub fn logger() { + use tracing_subscriber::layer::SubscriberExt; + use tracing_subscriber::util::SubscriberInitExt; + use tracing_subscriber::EnvFilter; + + INIT.get_or_init(|| { + let filter = EnvFilter::builder() + .with_default_directive(tracing::metadata::LevelFilter::DEBUG.into()) + .from_env_lossy(); + + tracing_subscriber::registry() + .with(tracing_wasm::WASMLayer::default()) + .with(filter) + .init(); + + console_error_panic_hook::set_once(); + }); +} + +pub fn rand_hexstring() -> String { + let mut rng = crypto_utils::rng(); + let hex_chars = "0123456789abcdef"; + let v: String = (0..40) + .map(|_| hex_chars.chars().choose(&mut rng).unwrap()) + .collect(); + + format!("0x{}", v) +} + +pub fn rand_account_address() -> String { + Alphanumeric.sample_string(&mut crypto_utils::rng(), 42) +} + +pub fn rand_vec() -> Vec { + crate::rand_array::().to_vec() +} + +pub fn rand_u64() -> u64 { + crypto_utils::rng().gen() +} + +#[cfg(not(target_arch = "wasm32"))] +pub fn tmp_path() -> String { + let db_name = crate::rand_string::<24>(); + format!("{}/{}.db3", std::env::temp_dir().to_str().unwrap(), db_name) +} + +#[cfg(target_arch = "wasm32")] +pub fn tmp_path() -> String { + let db_name = crate::rand_string::<24>(); + format!("{}/{}.db3", "test_db", db_name) +} + +pub fn rand_time() -> i64 { + let mut rng = rand::thread_rng(); + rng.gen_range(0..1_000_000_000) +} + +pub async fn wait_for_some(f: F) -> Option +where + F: Fn() -> Fut, + Fut: Future>, +{ + crate::time::timeout(crate::time::Duration::from_secs(20), async { + loop { + if let Some(r) = f().await { + return r; + } else { + crate::yield_().await; + } + } + }) + .await + .ok() +} + +pub async fn wait_for_ok(f: F) -> Result +where + F: Fn() -> Fut, + Fut: Future>, +{ + crate::time::timeout(crate::time::Duration::from_secs(20), async { + loop { + if let Ok(r) = f().await { + return r; + } else { + crate::yield_().await; + } + } + }) + .await +} + +pub async fn wait_for_eq(f: F, expected: T) -> Result<(), Expired> +where + F: Fn() -> Fut, + Fut: Future, + T: std::fmt::Debug + PartialEq, +{ + let result = crate::time::timeout(crate::time::Duration::from_secs(20), async { + loop { + let result = f().await; + if expected == result { + return result; + } else { + crate::yield_().await; + } + } + }) + .await?; + + assert_eq!(expected, result); + Ok(()) +} diff --git a/common/src/test/macros.rs b/common/src/test/macros.rs new file mode 100644 index 000000000..e07087d78 --- /dev/null +++ b/common/src/test/macros.rs @@ -0,0 +1,49 @@ +/// wrapper over assert!(matches!()) for Errors +/// assert_err!(fun(), StorageError::Explosion) +/// +/// or the message variant, +/// assert_err!(fun(), StorageError::Explosion, "the storage did not explode"); +#[macro_export] +macro_rules! assert_err { + ( $x:expr , $y:pat $(,)? ) => { + assert!(matches!($x, Err($y))) + }; + + ( $x:expr, $y:pat $(,)?, $($msg:tt)+) => {{ + assert!(matches!($x, Err($y)), $($msg)+) + }} + } + +/// wrapper over assert! macros for Ok's +/// +/// Make sure something is Ok(_) without caring about return value. +/// assert_ok!(fun()); +/// +/// Against an expected value, e.g Ok(true) +/// assert_ok!(fun(), true); +/// +/// or the message variant, +/// assert_ok!(fun(), Ok(_), "the storage is not ok"); +#[macro_export] +macro_rules! assert_ok { + + ( $e:expr ) => { + assert_ok!($e,) + }; + + ( $e:expr, ) => {{ + use std::result::Result::*; + match $e { + Ok(v) => v, + Err(e) => panic!("assertion failed: Err({:?})", e), + } + }}; + + ( $x:expr , $y:expr $(,)? ) => { + assert_eq!($x, Ok($y.into())); + }; + + ( $x:expr, $y:expr $(,)?, $($msg:tt)+) => {{ + assert_eq!($x, Ok($y.into()), $($msg)+); + }} + } diff --git a/xmtp_mls/src/utils/test/traced_test.rs b/common/src/test/traced_test.rs similarity index 72% rename from xmtp_mls/src/utils/test/traced_test.rs rename to common/src/test/traced_test.rs index fea217199..eb208d220 100644 --- a/xmtp_mls/src/utils/test/traced_test.rs +++ b/common/src/test/traced_test.rs @@ -1,3 +1,4 @@ +/// Tests that can assert on tracing logs in a tokio threaded context use std::{io, sync::Arc}; use parking_lot::Mutex; @@ -58,8 +59,9 @@ impl fmt::MakeWriter<'_> for TestWriter { self.clone() } } - +/* /// Only works with current-thread +#[inline] pub fn traced_test(f: impl Fn() -> Fut) where Fut: futures::Future, @@ -88,6 +90,39 @@ where buf.clear(); }); } +*/ + +#[macro_export] +macro_rules! traced_test { + ( $f:expr ) => {{ + use tracing_subscriber::fmt; + use $crate::traced_test::TestWriter; + + $crate::traced_test::LOG_BUFFER.with(|buf| { + let rt = tokio::runtime::Builder::new_current_thread() + .thread_name("tracing-test") + .enable_time() + .enable_io() + .build() + .unwrap(); + buf.clear(); + + let subscriber = fmt::Subscriber::builder() + .with_env_filter(format!("{}=debug", env!("CARGO_PKG_NAME"))) + .with_writer(buf.clone()) + .with_level(true) + .with_ansi(false) + .finish(); + + let dispatch = tracing::Dispatch::new(subscriber); + tracing::dispatcher::with_default(&dispatch, || { + rt.block_on($f); + }); + + buf.clear(); + }); + }}; +} /// macro that can assert logs in tests. /// Note: tests that use this must be used in `traced_test` function @@ -95,7 +130,7 @@ where #[macro_export] macro_rules! assert_logged { ( $search:expr , $occurrences:expr ) => { - $crate::utils::test::traced_test::LOG_BUFFER.with(|buf| { + $crate::traced_test::LOG_BUFFER.with(|buf| { let lines = { buf.flush(); buf.as_string() diff --git a/common/src/time.rs b/common/src/time.rs new file mode 100644 index 000000000..8b411a826 --- /dev/null +++ b/common/src/time.rs @@ -0,0 +1,99 @@ +//! Time primitives for native and WebAssembly + +use std::fmt; + +#[derive(Debug)] +pub struct Expired; + +impl std::error::Error for Expired { + fn description(&self) -> &str { + "Timer duration expired" + } +} + +#[cfg(not(target_arch = "wasm32"))] +impl From for Expired { + fn from(_: tokio::time::error::Elapsed) -> Expired { + Expired + } +} + +impl fmt::Display for Expired { + fn fmt(&self, f: &mut fmt::Formatter) -> std::fmt::Result { + write!(f, "timer duration expired") + } +} + +#[cfg(not(all(target_family = "wasm", target_os = "unknown")))] +pub use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH}; +#[cfg(all(target_family = "wasm", target_os = "unknown"))] +pub use web_time::{Duration, Instant, SystemTime, UNIX_EPOCH}; + +fn duration_since_epoch() -> Duration { + SystemTime::now() + .duration_since(UNIX_EPOCH) + .expect("Time went backwards") +} + +pub fn now_ns() -> i64 { + duration_since_epoch().as_nanos() as i64 +} + +pub fn now_secs() -> i64 { + duration_since_epoch().as_secs() as i64 +} + +#[cfg(target_arch = "wasm32")] +pub async fn timeout(duration: Duration, future: F) -> Result +where + F: std::future::IntoFuture, +{ + use futures::future::Either::*; + let timeout = gloo_timers::future::TimeoutFuture::new(duration.as_millis() as u32); + let future = future.into_future(); + futures::pin_mut!(future); + match futures::future::select(timeout, future).await { + Left(_) => Err(Expired), + Right((value, _)) => Ok(value), + } +} + +#[cfg(not(target_arch = "wasm32"))] +pub async fn timeout(duration: Duration, future: F) -> Result +where + F: std::future::IntoFuture, +{ + tokio::time::timeout(duration, future) + .await + .map_err(Into::into) +} + +// WASM Shims +#[cfg(target_arch = "wasm32")] +#[doc(hidden)] +pub async fn sleep(duration: Duration) { + use js_sys::wasm_bindgen::JsCast; + use js_sys::wasm_bindgen::UnwrapThrowExt; + use web_sys::WorkerGlobalScope; + + let mut cb = |resolve: js_sys::Function, _reject: js_sys::Function| { + let worker = js_sys::global() + .dyn_into::() + .expect("xmtp_mls should always act in worker in browser"); + + worker + .set_timeout_with_callback_and_timeout_and_arguments_0( + &resolve, + duration.as_millis() as i32, + ) + .expect("Failed to call set_timeout"); + }; + let p = js_sys::Promise::new(&mut cb); + wasm_bindgen_futures::JsFuture::from(p).await.unwrap_throw(); +} + +#[cfg(not(target_arch = "wasm32"))] +#[doc(hidden)] +pub async fn sleep(duration: Duration) { + tokio::time::sleep(duration).await +} diff --git a/dev/wasm b/dev/wasm deleted file mode 100755 index 717bdf8b4..000000000 --- a/dev/wasm +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/bash -set -eou pipefail - -if [[ "${OSTYPE}" == "darwin"* ]]; then - if ! wasm-pack --version &>/dev/null; then cargo install wasm-pack; fi -fi - -pushd bindings_wasm/ > /dev/null - -wasm-pack build --target nodejs --out-dir pkg # pkg is the default - -popd > /dev/null diff --git a/examples/cli/Cargo.toml b/examples/cli/Cargo.toml index 830931bce..cff9a9200 100644 --- a/examples/cli/Cargo.toml +++ b/examples/cli/Cargo.toml @@ -43,3 +43,4 @@ xmtp_content_types = { path = "../../xmtp_content_types" } xmtp_id = { path = "../../xmtp_id" } xmtp_mls = { path = "../../xmtp_mls" } xmtp_proto = { path = "../../xmtp_proto", features = ["proto_full"] } +xmtp_common.workspace = true diff --git a/examples/cli/cli-client.rs b/examples/cli/cli-client.rs index ec285b1d9..a30060380 100755 --- a/examples/cli/cli-client.rs +++ b/examples/cli/cli-client.rs @@ -32,6 +32,7 @@ use tracing_subscriber::{ use valuable::Valuable; use xmtp_api_grpc::grpc_api_helper::Client as ClientV3; use xmtp_api_grpc::replication_client::ClientV4; +use xmtp_common::time::now_ns; use xmtp_content_types::{text::TextCodec, ContentCodec}; use xmtp_cryptography::{ signature::{RecoverableSignature, SignatureError}, @@ -54,7 +55,6 @@ use xmtp_mls::{ group_message::StoredGroupMessage, EncryptedMessageStore, EncryptionKey, StorageError, StorageOption, }, - utils::time::now_ns, InboxOwner, }; use xmtp_proto::xmtp::mls::message_contents::DeviceSyncKind; diff --git a/mls_validation_service/Cargo.toml b/mls_validation_service/Cargo.toml index fd6e37edd..e5aa6dbb7 100644 --- a/mls_validation_service/Cargo.toml +++ b/mls_validation_service/Cargo.toml @@ -36,6 +36,7 @@ ethers.workspace = true rand = { workspace = true } xmtp_id = { workspace = true, features = ["test-utils"] } xmtp_mls = { workspace = true, features = ["test-utils"] } +xmtp_common = { workspace = true, features = ["test-utils"]} [features] test-utils = ["xmtp_id/test-utils"] diff --git a/mls_validation_service/src/handlers.rs b/mls_validation_service/src/handlers.rs index ef96904dd..abf159685 100644 --- a/mls_validation_service/src/handlers.rs +++ b/mls_validation_service/src/handlers.rs @@ -328,11 +328,12 @@ mod tests { prelude::{tls_codec::Serialize, Credential as OpenMlsCredential, CredentialWithKey}, }; use openmls_rust_crypto::OpenMlsRustCrypto; + use xmtp_common::{rand_string, rand_u64}; use xmtp_cryptography::XmtpInstallationCredential; use xmtp_id::{ associations::{ generate_inbox_id, - test_utils::{rand_string, rand_u64, MockSmartContractSignatureVerifier}, + test_utils::MockSmartContractSignatureVerifier, unverified::{UnverifiedAction, UnverifiedIdentityUpdate}, }, is_smart_contract, @@ -399,7 +400,7 @@ mod tests { #[tokio::test] #[should_panic] async fn test_get_association_state() { - let account_address = rand_string(); + let account_address = rand_string::<24>(); let nonce = rand_u64(); let inbox_id = generate_inbox_id(&account_address, &nonce).unwrap(); let update = UnverifiedIdentityUpdate::new_test( diff --git a/xmtp_api_http/src/util.rs b/xmtp_api_http/src/util.rs index 55e4ff3fa..8a839fc56 100644 --- a/xmtp_api_http/src/util.rs +++ b/xmtp_api_http/src/util.rs @@ -76,7 +76,6 @@ pub fn create_grpc_stream_inner< http_client: reqwest::Client, ) -> impl Stream> { async_stream::stream! { - tracing::info!("Spawning grpc http stream"); let request = http_client .post(endpoint) .json(&request) diff --git a/xmtp_content_types/Cargo.toml b/xmtp_content_types/Cargo.toml index 4d0a2b2ee..2b7c506d1 100644 --- a/xmtp_content_types/Cargo.toml +++ b/xmtp_content_types/Cargo.toml @@ -11,6 +11,10 @@ rand = { workspace = true } # XMTP/Local xmtp_proto = { workspace = true, features = ["convert"] } +xmtp_common = { workspace = true } + +[dev-dependencies] +xmtp_common = { workspace = true, features = ['test-utils'] } [target.'cfg(not(target_arch = "wasm32"))'.dependencies] tonic = { version = "0.12", features = ["transport"] } diff --git a/xmtp_content_types/src/group_updated.rs b/xmtp_content_types/src/group_updated.rs index 7aa797ee0..2ab08917a 100644 --- a/xmtp_content_types/src/group_updated.rs +++ b/xmtp_content_types/src/group_updated.rs @@ -50,20 +50,18 @@ pub(crate) mod tests { #[cfg(target_arch = "wasm32")] wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_dedicated_worker); - use xmtp_proto::xmtp::mls::message_contents::{group_updated::Inbox, GroupUpdated}; - - use crate::test_utils::rand_string; - use super::*; + use xmtp_common::rand_string; + use xmtp_proto::xmtp::mls::message_contents::{group_updated::Inbox, GroupUpdated}; #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] #[cfg_attr(not(target_arch = "wasm32"), test)] fn test_encode_decode() { let new_member = Inbox { - inbox_id: rand_string(), + inbox_id: rand_string::<24>(), }; let data = GroupUpdated { - initiated_by_inbox_id: rand_string(), + initiated_by_inbox_id: rand_string::<24>(), added_inboxes: vec![new_member.clone()], removed_inboxes: vec![], metadata_field_changes: vec![], diff --git a/xmtp_content_types/src/lib.rs b/xmtp_content_types/src/lib.rs index b882891a1..04a7a3fb9 100644 --- a/xmtp_content_types/src/lib.rs +++ b/xmtp_content_types/src/lib.rs @@ -1,7 +1,5 @@ pub mod group_updated; pub mod membership_change; -#[cfg(test)] -mod test_utils; pub mod text; use thiserror::Error; diff --git a/xmtp_content_types/src/membership_change.rs b/xmtp_content_types/src/membership_change.rs index b83483806..14401bbb8 100644 --- a/xmtp_content_types/src/membership_change.rs +++ b/xmtp_content_types/src/membership_change.rs @@ -52,18 +52,16 @@ pub(crate) mod tests { #[cfg(target_arch = "wasm32")] wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_dedicated_worker); - use xmtp_proto::xmtp::mls::message_contents::MembershipChange; - - use crate::test_utils::{rand_string, rand_vec}; - use super::*; + use xmtp_common::{rand_string, rand_vec}; + use xmtp_proto::xmtp::mls::message_contents::MembershipChange; #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] #[cfg_attr(not(target_arch = "wasm32"), test)] fn test_encode_decode() { let new_member = MembershipChange { - installation_ids: vec![rand_vec()], - account_address: rand_string(), + installation_ids: vec![rand_vec::<24>()], + account_address: rand_string::<24>(), initiated_by_account_address: "".to_string(), }; let data = GroupMembershipChanges { diff --git a/xmtp_content_types/src/test_utils.rs b/xmtp_content_types/src/test_utils.rs deleted file mode 100644 index dead0c7e6..000000000 --- a/xmtp_content_types/src/test_utils.rs +++ /dev/null @@ -1,15 +0,0 @@ -#[cfg(test)] -use rand::{ - distributions::{Alphanumeric, DistString}, - Rng, -}; - -#[cfg(test)] -pub(crate) fn rand_string() -> String { - Alphanumeric.sample_string(&mut rand::thread_rng(), 24) -} - -#[cfg(test)] -pub(crate) fn rand_vec() -> Vec { - rand::thread_rng().gen::<[u8; 24]>().to_vec() -} diff --git a/xmtp_id/Cargo.toml b/xmtp_id/Cargo.toml index 3488b23d3..2b6d44c91 100644 --- a/xmtp_id/Cargo.toml +++ b/xmtp_id/Cargo.toml @@ -27,8 +27,9 @@ tokio = { workspace = true, features = ["macros"] } tracing.workspace = true xmtp_cryptography.workspace = true xmtp_proto = { workspace = true, features = ["proto_full"] } -wasm-timer.workspace = true +web-time.workspace = true ethers = { workspace = true, features = ["rustls"] } +xmtp_common.workspace = true [target.'cfg(target_arch = "wasm32")'.dependencies] openmls = { workspace = true, features = ["js"] } @@ -40,10 +41,11 @@ openmls.workspace = true [dev-dependencies] xmtp_v2 = { path = "../xmtp_v2" } ed25519-dalek = { workspace = true, features = ["digest", "rand_core"] } +xmtp_common = { workspace = true, features = ["test-utils"] } +wasm-bindgen-test.workspace = true [target.'cfg(target_arch = "wasm32")'.dev-dependencies] -wasm-bindgen-test.workspace = true gloo-timers.workspace = true [features] -test-utils = [] +test-utils = ["xmtp_common/test-utils"] diff --git a/xmtp_id/src/associations/builder.rs b/xmtp_id/src/associations/builder.rs index 43c0d166a..5426cd8b7 100644 --- a/xmtp_id/src/associations/builder.rs +++ b/xmtp_id/src/associations/builder.rs @@ -4,8 +4,9 @@ use std::collections::HashMap; -use crate::{scw_verifier::SmartContractSignatureVerifier, utils::now_ns}; +use crate::scw_verifier::SmartContractSignatureVerifier; use thiserror::Error; +use xmtp_common::time::now_ns; use super::{ unsigned_actions::{ diff --git a/xmtp_id/src/associations/member.rs b/xmtp_id/src/associations/member.rs index 40b162e73..f23e19101 100644 --- a/xmtp_id/src/associations/member.rs +++ b/xmtp_id/src/associations/member.rs @@ -165,15 +165,12 @@ pub(crate) mod tests { #[cfg(target_arch = "wasm32")] wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_dedicated_worker); - use crate::associations::test_utils; - use super::*; - - use test_utils::rand_string; + use xmtp_common::rand_hexstring; impl Default for MemberIdentifier { fn default() -> Self { - MemberIdentifier::Address(rand_string()) + MemberIdentifier::Address(rand_hexstring()) } } diff --git a/xmtp_id/src/associations/mod.rs b/xmtp_id/src/associations/mod.rs index 7cd29ba17..ca6e6e7d3 100644 --- a/xmtp_id/src/associations/mod.rs +++ b/xmtp_id/src/associations/mod.rs @@ -42,11 +42,11 @@ pub fn get_state>( #[cfg(any(test, feature = "test-utils"))] pub mod test_defaults { use self::{ - test_utils::{rand_string, rand_u64, rand_vec}, unverified::{UnverifiedAction, UnverifiedIdentityUpdate}, verified_signature::VerifiedSignature, }; use super::*; + use xmtp_common::{rand_hexstring, rand_u64, rand_vec}; impl IdentityUpdate { pub fn new_test(actions: Vec, inbox_id: String) -> Self { @@ -62,19 +62,19 @@ pub mod test_defaults { impl Default for AddAssociation { fn default() -> Self { - let existing_member = rand_string(); - let new_member = rand_vec(); + let existing_member = rand_hexstring(); + let new_member = rand_vec::<32>(); Self { existing_member_signature: VerifiedSignature::new( existing_member.into(), SignatureKind::Erc191, - rand_vec(), + rand_vec::<32>(), None, ), new_member_signature: VerifiedSignature::new( new_member.clone().into(), SignatureKind::InstallationKey, - rand_vec(), + rand_vec::<32>(), None, ), new_member_identifier: new_member.into(), @@ -85,14 +85,14 @@ pub mod test_defaults { // Default will create an inbox with a ERC-191 signature impl Default for CreateInbox { fn default() -> Self { - let signer = rand_string(); + let signer = rand_hexstring(); Self { nonce: rand_u64(), account_address: signer.clone(), initial_address_signature: VerifiedSignature::new( signer.into(), SignatureKind::Erc191, - rand_vec(), + rand_vec::<32>(), None, ), } @@ -101,15 +101,15 @@ pub mod test_defaults { impl Default for RevokeAssociation { fn default() -> Self { - let signer = rand_string(); + let signer = rand_hexstring(); Self { recovery_address_signature: VerifiedSignature::new( signer.into(), SignatureKind::Erc191, - rand_vec(), + rand_vec::<32>(), None, ), - revoked_member: rand_string().into(), + revoked_member: rand_hexstring().into(), } } } @@ -119,10 +119,11 @@ pub mod test_defaults { pub(crate) mod tests { #[cfg(target_arch = "wasm32")] wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_dedicated_worker); + use wasm_bindgen_test::wasm_bindgen_test; - use self::test_utils::{rand_string, rand_vec}; use super::*; use crate::associations::verified_signature::VerifiedSignature; + use xmtp_common::{rand_hexstring, rand_vec}; pub fn new_test_inbox() -> AssociationState { let create_request = CreateInbox::default(); @@ -144,7 +145,7 @@ pub(crate) mod tests { existing_member_signature: VerifiedSignature::new( initial_wallet_address.clone(), SignatureKind::Erc191, - rand_vec(), + rand_vec::<32>(), None, ), ..Default::default() @@ -157,7 +158,7 @@ pub(crate) mod tests { .unwrap() } - #[test] + #[wasm_bindgen_test(unsupported = test)] fn test_create_inbox() { let create_request = CreateInbox::default(); let inbox_id = @@ -172,11 +173,11 @@ pub(crate) mod tests { assert!(existing_entity.identifier.eq(&account_address.into())); } - #[test] + #[wasm_bindgen_test(unsupported = test)] fn create_and_add_separately() { let initial_state = new_test_inbox(); let inbox_id = initial_state.inbox_id().to_string(); - let new_installation_identifier: MemberIdentifier = rand_vec().into(); + let new_installation_identifier: MemberIdentifier = rand_vec::<32>().into(); let first_member: MemberIdentifier = initial_state.recovery_address().clone().into(); let update = Action::AddAssociation(AddAssociation { @@ -184,13 +185,13 @@ pub(crate) mod tests { new_member_signature: VerifiedSignature::new( new_installation_identifier.clone(), SignatureKind::InstallationKey, - rand_vec(), + rand_vec::<32>(), None, ), existing_member_signature: VerifiedSignature::new( first_member.clone(), SignatureKind::Erc191, - rand_vec(), + rand_vec::<32>(), None, ), }); @@ -206,24 +207,24 @@ pub(crate) mod tests { assert_eq!(new_member.added_by_entity, Some(first_member)); } - #[test] + #[wasm_bindgen_test(unsupported = test)] fn create_and_add_together() { let create_action = CreateInbox::default(); let account_address = create_action.account_address.clone(); let inbox_id = generate_inbox_id(&account_address, &create_action.nonce).unwrap(); - let new_member_identifier: MemberIdentifier = rand_vec().into(); + let new_member_identifier: MemberIdentifier = rand_vec::<32>().into(); let add_action = AddAssociation { existing_member_signature: VerifiedSignature::new( account_address.clone().into(), SignatureKind::Erc191, - rand_vec(), + rand_vec::<32>(), None, ), // Add an installation ID new_member_signature: VerifiedSignature::new( new_member_identifier.clone(), SignatureKind::InstallationKey, - rand_vec(), + rand_vec::<32>(), None, ), new_member_identifier: new_member_identifier.clone(), @@ -243,9 +244,9 @@ pub(crate) mod tests { ); } - #[test] + #[wasm_bindgen_test(unsupported = test)] fn create_from_legacy_key() { - let member_identifier: MemberIdentifier = rand_string().into(); + let member_identifier: MemberIdentifier = rand_hexstring().into(); let create_action = CreateInbox { nonce: 0, account_address: member_identifier.to_string(), @@ -282,7 +283,7 @@ pub(crate) mod tests { assert!(matches!(update_result, Err(AssociationError::Replay))); } - #[test] + #[wasm_bindgen_test(unsupported = test)] fn add_wallet_from_installation_key() { let initial_state = new_test_inbox_with_installation(); let inbox_id = initial_state.inbox_id().to_string(); @@ -293,19 +294,19 @@ pub(crate) mod tests { .unwrap() .identifier; - let new_wallet_address: MemberIdentifier = rand_string().into(); + let new_wallet_address: MemberIdentifier = rand_hexstring().into(); let add_association = Action::AddAssociation(AddAssociation { new_member_identifier: new_wallet_address.clone(), new_member_signature: VerifiedSignature::new( new_wallet_address.clone(), SignatureKind::Erc191, - rand_vec(), + rand_vec::<32>(), None, ), existing_member_signature: VerifiedSignature::new( installation_id.clone(), SignatureKind::InstallationKey, - rand_vec(), + rand_vec::<32>(), None, ), }); @@ -318,13 +319,13 @@ pub(crate) mod tests { assert_eq!(new_state.members().len(), 3); } - #[test] + #[wasm_bindgen_test(unsupported = test)] fn reject_invalid_signature_on_create() { // Creates a signature with the wrong signer let bad_signature = VerifiedSignature::new( - rand_string().into(), + rand_hexstring().into(), SignatureKind::Erc191, - rand_vec(), + rand_vec::<32>(), None, ); let action = CreateInbox { @@ -334,7 +335,7 @@ pub(crate) mod tests { let state_result = get_state(vec![IdentityUpdate::new_test( vec![Action::CreateInbox(action)], - rand_string(), + rand_hexstring(), )]); assert!(state_result.is_err()); @@ -344,15 +345,15 @@ pub(crate) mod tests { )); } - #[test] + #[wasm_bindgen_test(unsupported = test)] fn reject_invalid_signature_on_update() { let initial_state = new_test_inbox(); let inbox_id = initial_state.inbox_id().to_string(); // Signature is from a random address let bad_signature = VerifiedSignature::new( - rand_string().into(), + rand_hexstring().into(), SignatureKind::Erc191, - rand_vec(), + rand_vec::<32>(), None, ); @@ -376,7 +377,7 @@ pub(crate) mod tests { existing_member_signature: VerifiedSignature::new( initial_state.recovery_address().clone().into(), SignatureKind::Erc191, - rand_vec(), + rand_vec::<32>(), None, ), ..Default::default() @@ -392,7 +393,7 @@ pub(crate) mod tests { )); } - #[test] + #[wasm_bindgen_test(unsupported = test)] fn reject_if_signer_not_existing_member() { let create_inbox = CreateInbox::default(); let inbox_id = @@ -402,9 +403,9 @@ pub(crate) mod tests { let update = Action::AddAssociation(AddAssociation { // Existing member signature is coming from a random wallet existing_member_signature: VerifiedSignature::new( - rand_string().into(), + rand_hexstring().into(), SignatureKind::Erc191, - rand_vec(), + rand_vec::<32>(), None, ), ..Default::default() @@ -420,26 +421,26 @@ pub(crate) mod tests { )); } - #[test] + #[wasm_bindgen_test(unsupported = test)] fn reject_if_installation_adding_installation() { let existing_state = new_test_inbox_with_installation(); let inbox_id = existing_state.inbox_id().to_string(); let existing_installations = existing_state.members_by_kind(MemberKind::Installation); let existing_installation = existing_installations.first().unwrap(); - let new_installation_id: MemberIdentifier = rand_vec().into(); + let new_installation_id: MemberIdentifier = rand_vec::<32>().into(); let update = Action::AddAssociation(AddAssociation { existing_member_signature: VerifiedSignature::new( existing_installation.identifier.clone(), SignatureKind::InstallationKey, - rand_vec(), + rand_vec::<32>(), None, ), new_member_identifier: new_installation_id.clone(), new_member_signature: VerifiedSignature::new( new_installation_id.clone(), SignatureKind::InstallationKey, - rand_vec(), + rand_vec::<32>(), None, ), }); @@ -457,7 +458,7 @@ pub(crate) mod tests { )); } - #[test] + #[wasm_bindgen_test(unsupported = test)] fn revoke() { let initial_state = new_test_inbox_with_installation(); let inbox_id = initial_state.inbox_id().to_string(); @@ -471,7 +472,7 @@ pub(crate) mod tests { recovery_address_signature: VerifiedSignature::new( initial_state.recovery_address().clone().into(), SignatureKind::Erc191, - rand_vec(), + rand_vec::<32>(), None, ), revoked_member: installation_id.clone(), @@ -485,7 +486,7 @@ pub(crate) mod tests { assert!(new_state.get(&installation_id).is_none()); } - #[test] + #[wasm_bindgen_test(unsupported = test)] fn revoke_children() { let initial_state = new_test_inbox_with_installation(); let inbox_id = initial_state.inbox_id().to_string(); @@ -500,7 +501,7 @@ pub(crate) mod tests { existing_member_signature: VerifiedSignature::new( wallet_address.clone(), SignatureKind::Erc191, - rand_vec(), + rand_vec::<32>(), None, ), ..Default::default() @@ -517,7 +518,7 @@ pub(crate) mod tests { recovery_address_signature: VerifiedSignature::new( wallet_address.clone(), SignatureKind::Erc191, - rand_vec(), + rand_vec::<32>(), None, ), revoked_member: wallet_address.clone(), @@ -532,7 +533,7 @@ pub(crate) mod tests { assert_eq!(new_state.members().len(), 0); } - #[test] + #[wasm_bindgen_test(unsupported = test)] fn revoke_and_re_add() { let initial_state = new_test_inbox(); let wallet_address = initial_state @@ -544,19 +545,19 @@ pub(crate) mod tests { let inbox_id = initial_state.inbox_id().to_string(); - let second_wallet_address: MemberIdentifier = rand_string().into(); + let second_wallet_address: MemberIdentifier = rand_hexstring().into(); let add_second_wallet = Action::AddAssociation(AddAssociation { new_member_identifier: second_wallet_address.clone(), new_member_signature: VerifiedSignature::new( second_wallet_address.clone(), SignatureKind::Erc191, - rand_vec(), + rand_vec::<32>(), None, ), existing_member_signature: VerifiedSignature::new( wallet_address.clone(), SignatureKind::Erc191, - rand_vec(), + rand_vec::<32>(), None, ), }); @@ -565,7 +566,7 @@ pub(crate) mod tests { recovery_address_signature: VerifiedSignature::new( wallet_address.clone(), SignatureKind::Erc191, - rand_vec(), + rand_vec::<32>(), None, ), revoked_member: second_wallet_address.clone(), @@ -586,13 +587,13 @@ pub(crate) mod tests { new_member_signature: VerifiedSignature::new( second_wallet_address.clone(), SignatureKind::Erc191, - rand_vec(), + rand_vec::<32>(), None, ), existing_member_signature: VerifiedSignature::new( wallet_address, SignatureKind::Erc191, - rand_vec(), + rand_vec::<32>(), None, ), }); @@ -605,19 +606,19 @@ pub(crate) mod tests { assert_eq!(state_after_re_add.members().len(), 2); } - #[test] + #[wasm_bindgen_test(unsupported = test)] fn change_recovery_address() { let initial_state = new_test_inbox_with_installation(); let inbox_id = initial_state.inbox_id().to_string(); let initial_recovery_address: MemberIdentifier = initial_state.recovery_address().clone().into(); - let new_recovery_address = rand_string(); + let new_recovery_address = rand_hexstring(); let update_recovery = Action::ChangeRecoveryAddress(ChangeRecoveryAddress { new_recovery_address: new_recovery_address.clone(), recovery_address_signature: VerifiedSignature::new( initial_state.recovery_address().clone().into(), SignatureKind::Erc191, - rand_vec(), + rand_vec::<32>(), None, ), }); @@ -633,7 +634,7 @@ pub(crate) mod tests { recovery_address_signature: VerifiedSignature::new( initial_recovery_address.clone(), SignatureKind::Erc191, - rand_vec(), + rand_vec::<32>(), None, ), revoked_member: initial_recovery_address.clone(), @@ -650,14 +651,14 @@ pub(crate) mod tests { )); } - #[test] + #[wasm_bindgen_test(unsupported = test)] fn scw_signature_binding() { let initial_chain_id: u64 = 1; - let signer = rand_string(); + let signer = rand_hexstring(); let initial_address_signature = VerifiedSignature::new( signer.clone().into(), SignatureKind::Erc1271, - rand_vec(), + rand_vec::<32>(), Some(initial_chain_id), ); let action = CreateInbox { @@ -675,13 +676,13 @@ pub(crate) mod tests { let inbox_id = initial_state.inbox_id(); let new_chain_id: u64 = 2; - let new_member: MemberIdentifier = rand_vec().into(); + let new_member: MemberIdentifier = rand_vec::<32>().into(); // A signature from the same account address but on a different chain ID let existing_member_sig = VerifiedSignature::new( signer.clone().into(), SignatureKind::Erc1271, - rand_vec(), + rand_vec::<32>(), Some(new_chain_id), ); @@ -691,7 +692,7 @@ pub(crate) mod tests { new_member_signature: VerifiedSignature::new( new_member.clone(), SignatureKind::InstallationKey, - rand_vec(), + rand_vec::<32>(), None, ), new_member_identifier: new_member.clone(), @@ -702,7 +703,7 @@ pub(crate) mod tests { }), Action::ChangeRecoveryAddress(ChangeRecoveryAddress { recovery_address_signature: existing_member_sig.clone(), - new_recovery_address: rand_string(), + new_recovery_address: rand_hexstring(), }), ]; diff --git a/xmtp_id/src/associations/serialization.rs b/xmtp_id/src/associations/serialization.rs index 15c5ca2b5..41e76a0d7 100644 --- a/xmtp_id/src/associations/serialization.rs +++ b/xmtp_id/src/associations/serialization.rs @@ -581,21 +581,19 @@ pub(crate) mod tests { #[cfg(target_arch = "wasm32")] wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_dedicated_worker); - use crate::associations::{ - hashes::generate_inbox_id, - test_utils::{rand_string, rand_u64, rand_vec}, - }; + use crate::associations::hashes::generate_inbox_id; + use xmtp_common::{rand_hexstring, rand_u64, rand_vec}; use super::*; #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] #[cfg_attr(not(target_arch = "wasm32"), test)] fn test_round_trip_unverified() { - let account_address = rand_string(); + let account_address = rand_hexstring(); let nonce = rand_u64(); let inbox_id = generate_inbox_id(&account_address, &nonce).unwrap(); let client_timestamp_ns = rand_u64(); - let signature_bytes = rand_vec(); + let signature_bytes = rand_vec::<32>(); let identity_update = UnverifiedIdentityUpdate::new( inbox_id, @@ -616,7 +614,7 @@ pub(crate) mod tests { 4, 5, 6, ]), unsigned_action: UnsignedAddAssociation { - new_member_identifier: rand_string().into(), + new_member_identifier: rand_hexstring().into(), }, }), UnverifiedAction::ChangeRecoveryAddress(UnverifiedChangeRecoveryAddress { @@ -624,7 +622,7 @@ pub(crate) mod tests { 7, 8, 9, ]), unsigned_action: UnsignedChangeRecoveryAddress { - new_recovery_address: rand_string(), + new_recovery_address: rand_hexstring(), }, }), UnverifiedAction::RevokeAssociation(UnverifiedRevokeAssociation { @@ -632,7 +630,7 @@ pub(crate) mod tests { 10, 11, 12, ]), unsigned_action: UnsignedRevokeAssociation { - revoked_member: rand_string().into(), + revoked_member: rand_hexstring().into(), }, }), ], diff --git a/xmtp_id/src/associations/signature.rs b/xmtp_id/src/associations/signature.rs index 863e0044e..90eb98a4d 100644 --- a/xmtp_id/src/associations/signature.rs +++ b/xmtp_id/src/associations/signature.rs @@ -296,8 +296,9 @@ mod tests { use ethers::core::k256::{ecdsa::Signature as K256Signature, elliptic_curve::scalar::IsHigh}; use ethers::signers::{LocalWallet, Signer}; use rand::thread_rng; + use wasm_bindgen_test::wasm_bindgen_test; - #[tokio::test] + #[wasm_bindgen_test(unsupported = tokio::test)] async fn test_to_lower_s() { // Create a test wallet let wallet = LocalWallet::new(&mut thread_rng()); @@ -334,7 +335,7 @@ mod tests { assert!(!is_high, "Normalized signature should have low-s value"); } - #[test] + #[wasm_bindgen_test(unsupported = test)] fn test_invalid_signature() { // Test with invalid signature bytes let invalid_sig = vec![0u8; 65]; diff --git a/xmtp_id/src/associations/state.rs b/xmtp_id/src/associations/state.rs index a9339be88..d26569e1b 100644 --- a/xmtp_id/src/associations/state.rs +++ b/xmtp_id/src/associations/state.rs @@ -204,14 +204,14 @@ pub(crate) mod tests { #[cfg(target_arch = "wasm32")] wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_dedicated_worker); - use crate::associations::test_utils::rand_string; + use xmtp_common::rand_hexstring; use super::*; #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] #[cfg_attr(not(target_arch = "wasm32"), test)] fn can_add_remove() { - let starting_state = AssociationState::new(rand_string(), 0, None).unwrap(); + let starting_state = AssociationState::new(rand_hexstring(), 0, None).unwrap(); let new_entity = Member::default(); let with_add = starting_state.add(new_entity.clone()); assert!(with_add.get(&new_entity.identifier).is_some()); @@ -221,7 +221,7 @@ pub(crate) mod tests { #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] #[cfg_attr(not(target_arch = "wasm32"), test)] fn can_diff() { - let starting_state = AssociationState::new(rand_string(), 0, None).unwrap(); + let starting_state = AssociationState::new(rand_hexstring(), 0, None).unwrap(); let entity_1 = Member::default(); let entity_2 = Member::default(); let entity_3 = Member::default(); diff --git a/xmtp_id/src/associations/test_utils.rs b/xmtp_id/src/associations/test_utils.rs index 4ab83734d..2f0db1704 100644 --- a/xmtp_id/src/associations/test_utils.rs +++ b/xmtp_id/src/associations/test_utils.rs @@ -11,32 +11,9 @@ use ethers::{ signers::{LocalWallet, Signer}, types::Bytes, }; -use rand::Rng; use xmtp_cryptography::basic_credential::XmtpInstallationCredential; use xmtp_cryptography::CredentialSign; -pub fn rand_string() -> String { - let hex_chars = "0123456789abcdef"; - let v: String = (0..40) - .map(|_| { - let idx = rand::thread_rng().gen_range(0..hex_chars.len()); - hex_chars.chars().nth(idx).unwrap() - }) - .collect(); - - format!("0x{}", v) -} - -pub fn rand_u64() -> u64 { - rand::thread_rng().gen() -} - -pub fn rand_vec() -> Vec { - let mut buf = [0u8; 32]; - rand::thread_rng().fill(&mut buf[..]); - buf.to_vec() -} - #[derive(Debug, Clone)] pub struct MockSmartContractSignatureVerifier { is_valid_signature: bool, diff --git a/xmtp_id/src/associations/unverified.rs b/xmtp_id/src/associations/unverified.rs index a1ac2c849..64f198e0e 100644 --- a/xmtp_id/src/associations/unverified.rs +++ b/xmtp_id/src/associations/unverified.rs @@ -409,9 +409,8 @@ mod tests { #[cfg(target_arch = "wasm32")] wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_dedicated_worker); - use crate::associations::{ - generate_inbox_id, test_utils::rand_string, unsigned_actions::UnsignedCreateInbox, - }; + use crate::associations::{generate_inbox_id, unsigned_actions::UnsignedCreateInbox}; + use xmtp_common::rand_hexstring; use super::{ UnverifiedAction, UnverifiedCreateInbox, UnverifiedIdentityUpdate, @@ -421,7 +420,7 @@ mod tests { #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] #[cfg_attr(not(target_arch = "wasm32"), test)] fn create_identity_update() { - let account_address = rand_string(); + let account_address = rand_hexstring(); let nonce = 1; let update = UnverifiedIdentityUpdate { inbox_id: generate_inbox_id(account_address.as_str(), &nonce).unwrap(), diff --git a/xmtp_id/src/associations/verified_signature.rs b/xmtp_id/src/associations/verified_signature.rs index 3b30dc6e0..255fc3972 100644 --- a/xmtp_id/src/associations/verified_signature.rs +++ b/xmtp_id/src/associations/verified_signature.rs @@ -175,15 +175,15 @@ mod tests { use super::*; use crate::{ associations::{ - sign_with_legacy_key, - test_utils::{rand_string, MockSmartContractSignatureVerifier}, - verified_signature::VerifiedSignature, - InstallationKeyContext, MemberIdentifier, SignatureKind, + sign_with_legacy_key, test_utils::MockSmartContractSignatureVerifier, + verified_signature::VerifiedSignature, InstallationKeyContext, MemberIdentifier, + SignatureKind, }, InboxOwner, }; use ethers::signers::{LocalWallet, Signer}; use prost::Message; + use xmtp_common::rand_hexstring; use xmtp_cryptography::{CredentialSign, XmtpInstallationCredential}; use xmtp_proto::xmtp::message_contents::{ signature::Union as SignatureUnion, signed_private_key, @@ -367,7 +367,7 @@ mod tests { async fn test_smart_contract_wallet() { let mock_verifier = MockSmartContractSignatureVerifier::new(true); let chain_id: u64 = 24; - let account_address = rand_string(); + let account_address = rand_hexstring(); let account_id = AccountId::new(format!("eip155:{chain_id}"), account_address.clone()); let signature_text = "test_smart_contract_wallet_signature"; let signature_bytes = &[1, 2, 3]; diff --git a/xmtp_id/src/utils/mod.rs b/xmtp_id/src/utils/mod.rs index 0acaf32ef..ec59e09c8 100644 --- a/xmtp_id/src/utils/mod.rs +++ b/xmtp_id/src/utils/mod.rs @@ -1,13 +1,2 @@ -use wasm_timer::{SystemTime, UNIX_EPOCH}; #[cfg(any(test, feature = "test-utils"))] pub mod test; - -pub const NS_IN_SEC: i64 = 1_000_000_000; - -pub fn now_ns() -> i64 { - let now = SystemTime::now(); - - now.duration_since(UNIX_EPOCH) - .expect("Time went backwards") - .as_nanos() as i64 -} diff --git a/xmtp_mls/Cargo.toml b/xmtp_mls/Cargo.toml index e9d16676d..ef9d49670 100644 --- a/xmtp_mls/Cargo.toml +++ b/xmtp_mls/Cargo.toml @@ -40,6 +40,7 @@ test-utils = [ "xmtp_api_grpc/test-utils", "dep:const_format", "mockall", + "xmtp_common/test-utils" ] update-schema = ["toml"] @@ -68,9 +69,8 @@ tokio-stream = { version = "0.1", default-features = false, features = [ ] } tracing.workspace = true trait-variant.workspace = true -wasm-timer.workspace = true -web-time.workspace = true zeroize.workspace = true +xmtp_common.workspace = true # XMTP/Local xmtp_content_types = { path = "../xmtp_content_types" } @@ -149,6 +149,8 @@ mockall = "0.13.1" openmls_basic_credential.workspace = true xmtp_id = { path = "../xmtp_id", features = ["test-utils"] } xmtp_proto = { workspace = true, features = ["test-utils"] } +xmtp_common = { workspace = true, features = ["test-utils"]} +wasm-bindgen-test.workspace = true [target.'cfg(not(target_arch = "wasm32"))'.dev-dependencies] ctor.workspace = true diff --git a/xmtp_mls/benches/crypto.rs b/xmtp_mls/benches/crypto.rs index 17306e01b..c4f338ba7 100644 --- a/xmtp_mls/benches/crypto.rs +++ b/xmtp_mls/benches/crypto.rs @@ -46,7 +46,6 @@ fn bench_encrypt_welcome(c: &mut Criterion) { let keypair = crypto .derive_hpke_keypair(CIPHERSUITE.hpke_config(), ikm.as_slice()) .unwrap(); - let mut payload = vec![0; size]; OsRng.fill_bytes(payload.as_mut_slice()); (payload, keypair.public) diff --git a/xmtp_mls/src/api/identity.rs b/xmtp_mls/src/api/identity.rs index 02e6be91c..f2ef21a75 100644 --- a/xmtp_mls/src/api/identity.rs +++ b/xmtp_mls/src/api/identity.rs @@ -151,8 +151,9 @@ pub(crate) mod tests { use super::super::test_utils::*; use super::GetIdentityUpdatesV2Filter; - use crate::{api::ApiClientWrapper, retry::Retry}; - use xmtp_id::associations::{test_utils::rand_string, unverified::UnverifiedIdentityUpdate}; + use crate::api::ApiClientWrapper; + use xmtp_common::{rand_hexstring, Retry}; + use xmtp_id::associations::unverified::UnverifiedIdentityUpdate; use xmtp_proto::xmtp::identity::api::v1::{ get_identity_updates_response::{ IdentityUpdateLog, Response as GetIdentityUpdatesResponseItem, @@ -173,7 +174,7 @@ pub(crate) mod tests { #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] async fn publish_identity_update() { let mut mock_api = MockApiClient::new(); - let inbox_id = rand_string(); + let inbox_id = rand_hexstring(); let identity_update = create_identity_update(inbox_id.clone()); mock_api @@ -191,7 +192,7 @@ pub(crate) mod tests { #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] async fn get_identity_update_v2() { let mut mock_api = MockApiClient::new(); - let inbox_id = rand_string(); + let inbox_id = rand_hexstring(); let inbox_id_clone = inbox_id.clone(); let inbox_id_clone_2 = inbox_id.clone(); mock_api @@ -238,10 +239,10 @@ pub(crate) mod tests { #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] async fn get_inbox_ids() { let mut mock_api = MockApiClient::new(); - let inbox_id = rand_string(); + let inbox_id = rand_hexstring(); let inbox_id_clone = inbox_id.clone(); let inbox_id_clone_2 = inbox_id.clone(); - let address = rand_string(); + let address = rand_hexstring(); let address_clone = address.clone(); let address_clone_2 = address.clone(); diff --git a/xmtp_mls/src/api/mls.rs b/xmtp_mls/src/api/mls.rs index a319f7737..3994cd8fa 100644 --- a/xmtp_mls/src/api/mls.rs +++ b/xmtp_mls/src/api/mls.rs @@ -1,7 +1,8 @@ use std::collections::HashMap; use super::ApiClientWrapper; -use crate::{retry_async, XmtpApi}; +use crate::XmtpApi; +use xmtp_common::retry_async; use xmtp_proto::api_client::XmtpMlsStreams; use xmtp_proto::xmtp::mls::api::v1::{ subscribe_group_messages_request::Filter as GroupFilterProto, diff --git a/xmtp_mls/src/api/mod.rs b/xmtp_mls/src/api/mod.rs index 8cd71039d..e9515058d 100644 --- a/xmtp_mls/src/api/mod.rs +++ b/xmtp_mls/src/api/mod.rs @@ -5,11 +5,9 @@ pub mod test_utils; use std::sync::Arc; -use crate::{ - retry::{Retry, RetryableError}, - XmtpApi, -}; +use crate::XmtpApi; use thiserror::Error; +use xmtp_common::{Retry, RetryableError}; use xmtp_id::{associations::DeserializationError as AssociationDeserializationError, InboxId}; use xmtp_proto::Error as ApiError; diff --git a/xmtp_mls/src/api/test_utils.rs b/xmtp_mls/src/api/test_utils.rs index 087877624..829166507 100644 --- a/xmtp_mls/src/api/test_utils.rs +++ b/xmtp_mls/src/api/test_utils.rs @@ -1,6 +1,3 @@ -use std::{future::Future, time::Duration}; -use web_time::Instant; - use mockall::mock; use xmtp_proto::{ api_client::{ClientWithMetadata, XmtpIdentityClient, XmtpMlsClient, XmtpMlsStreams}, @@ -179,55 +176,3 @@ mod wasm { } } } - -pub async fn wait_for_some(f: F) -> Option -where - F: Fn() -> Fut, - Fut: Future>, -{ - let start = Instant::now(); - while start.elapsed() < Duration::from_secs(3) { - let result = f().await; - if result.is_some() { - return result; - } - crate::sleep(Duration::from_millis(100)).await; - } - None -} - -pub async fn wait_for_ok(f: F) -> Result -where - F: Fn() -> Fut, - Fut: Future>, -{ - let start = Instant::now(); - let mut result = f().await; - while start.elapsed() < Duration::from_secs(3) { - if result.is_ok() { - return result; - } - crate::sleep(Duration::from_millis(100)).await; - result = f().await; - } - result -} - -pub async fn wait_for_eq(f: F, expected: T) -where - F: Fn() -> Fut, - Fut: Future, - T: std::fmt::Debug + PartialEq, -{ - let start = Instant::now(); - let mut result = f().await; - while start.elapsed() < Duration::from_secs(3) { - if result == expected { - break; - } - crate::sleep(Duration::from_millis(100)).await; - result = f().await; - } - - assert_eq!(expected, result); -} diff --git a/xmtp_mls/src/builder.rs b/xmtp_mls/src/builder.rs index 997a92ce8..f8411744e 100644 --- a/xmtp_mls/src/builder.rs +++ b/xmtp_mls/src/builder.rs @@ -11,10 +11,10 @@ use crate::{ client::Client, identity::{Identity, IdentityStrategy}, identity_updates::load_identity_updates, - retry::Retry, storage::EncryptedMessageStore, StorageError, XmtpApi, XmtpOpenMlsProvider, }; +use xmtp_common::Retry; #[derive(Error, Debug)] pub enum ClientBuilderError { @@ -230,24 +230,22 @@ pub(crate) mod tests { use crate::api::ApiClientWrapper; use crate::builder::ClientBuilderError; use crate::identity::IdentityError; - use crate::retry::Retry; use crate::utils::test::TestClient; use crate::XmtpApi; - use crate::{ - api::test_utils::*, identity::Identity, storage::identity::StoredIdentity, - utils::test::rand_vec, Store, - }; + use crate::{api::test_utils::*, identity::Identity, storage::identity::StoredIdentity, Store}; + use xmtp_common::{rand_vec, tmp_path, Retry}; use openmls::credentials::{Credential, CredentialType}; use prost::Message; + use xmtp_common::rand_u64; use xmtp_cryptography::utils::{generate_local_wallet, rng}; use xmtp_cryptography::XmtpInstallationCredential; + use xmtp_id::associations::generate_inbox_id; use xmtp_id::associations::test_utils::MockSmartContractSignatureVerifier; use xmtp_id::associations::unverified::{ UnverifiedRecoverableEcdsaSignature, UnverifiedSignature, }; use xmtp_id::associations::ValidatedLegacySignedPublicKey; - use xmtp_id::associations::{generate_inbox_id, test_utils::rand_u64}; use xmtp_id::scw_verifier::SmartContractSignatureVerifier; use xmtp_proto::api_client::XmtpTestClient; use xmtp_proto::xmtp::identity::api::v1::{ @@ -263,7 +261,6 @@ pub(crate) mod tests { use super::{ClientBuilder, IdentityStrategy}; use crate::{ storage::{EncryptedMessageStore, StorageOption}, - utils::test::tmp_path, Client, InboxOwner, }; @@ -627,7 +624,7 @@ pub(crate) mod tests { let stored: StoredIdentity = (&Identity { inbox_id: inbox_id.clone(), installation_keys: XmtpInstallationCredential::new(), - credential: Credential::new(CredentialType::Basic, rand_vec()), + credential: Credential::new(CredentialType::Basic, rand_vec::<24>()), signature_request: None, is_ready: AtomicBool::new(true), }) @@ -664,7 +661,7 @@ pub(crate) mod tests { let stored: StoredIdentity = (&Identity { inbox_id: stored_inbox_id.clone(), installation_keys: Default::default(), - credential: Credential::new(CredentialType::Basic, rand_vec()), + credential: Credential::new(CredentialType::Basic, rand_vec::<24>()), signature_request: None, is_ready: AtomicBool::new(true), }) diff --git a/xmtp_mls/src/client.rs b/xmtp_mls/src/client.rs index 819356dc4..e293188a7 100644 --- a/xmtp_mls/src/client.rs +++ b/xmtp_mls/src/client.rs @@ -40,8 +40,6 @@ use crate::{ identity_updates::{load_identity_updates, IdentityUpdateError}, intents::ProcessIntentError, mutex_registry::MutexRegistry, - retry::Retry, - retry_async, retryable, storage::{ consent_record::{ConsentState, ConsentType, StoredConsentRecord}, db_connection::DbConnection, @@ -57,6 +55,7 @@ use crate::{ xmtp_openmls_provider::XmtpOpenMlsProvider, Fetch, Store, XmtpApi, }; +use xmtp_common::{retry_async, retryable, Retry}; /// Enum representing the network the Client is connected to #[derive(Clone, Copy, Default, Debug)] @@ -112,7 +111,7 @@ impl From for ClientError { } } -impl crate::retry::RetryableError for ClientError { +impl xmtp_common::RetryableError for ClientError { fn is_retryable(&self) -> bool { match self { ClientError::Group(group_error) => retryable!(group_error), @@ -441,9 +440,9 @@ where .into_iter() .map(UserPreferenceUpdate::ConsentUpdate) .collect(); - self.local_events - .send(LocalEvents::OutgoingPreferenceUpdates(records)) - .map_err(|e| ClientError::Generic(e.to_string()))?; + let _ = self + .local_events + .send(LocalEvents::OutgoingPreferenceUpdates(records)); } Ok(()) @@ -689,7 +688,7 @@ where .await?; self.apply_signature_request(signature_request).await?; - + self.identity().set_ready(); Ok(()) } diff --git a/xmtp_mls/src/groups/device_sync.rs b/xmtp_mls/src/groups/device_sync.rs index 3f9536371..5e5a840a7 100644 --- a/xmtp_mls/src/groups/device_sync.rs +++ b/xmtp_mls/src/groups/device_sync.rs @@ -1,11 +1,9 @@ use super::{GroupError, MlsGroup}; use crate::configuration::NS_IN_HOUR; -use crate::retry::{Retry, RetryableError}; use crate::storage::group::{ConversationType, GroupQueryArgs}; use crate::storage::group_message::MsgQueryArgs; use crate::storage::DbConnection; use crate::subscriptions::{LocalEvents, StreamMessages, SubscribeError, SyncMessage}; -use crate::utils::time::now_ns; use crate::xmtp_openmls_provider::XmtpOpenMlsProvider; use crate::{ client::ClientError, @@ -15,9 +13,8 @@ use crate::{ group_message::{GroupMessageKind, StoredGroupMessage}, StorageError, }, - Client, + Client, Store, }; -use crate::{retry_async, Store}; use aes_gcm::aead::generic_array::GenericArray; use aes_gcm::{ aead::{Aead, KeyInit}, @@ -25,16 +22,14 @@ use aes_gcm::{ }; use futures::{Stream, StreamExt}; use preference_sync::UserPreferenceUpdate; -use rand::{ - distributions::{Alphanumeric, DistString}, - Rng, RngCore, -}; +use rand::{Rng, RngCore}; use serde::{Deserialize, Serialize}; use std::pin::Pin; -use std::time::Duration; use thiserror::Error; use tokio::sync::OnceCell; use tracing::{instrument, warn}; +use xmtp_common::time::{now_ns, Duration}; +use xmtp_common::{retry_async, Retry, RetryableError}; use xmtp_cryptography::utils as crypto_utils; use xmtp_id::scw_verifier::SmartContractSignatureVerifier; use xmtp_proto::api_client::trait_impls::XmtpApi; @@ -154,9 +149,9 @@ where V: SmartContractSignatureVerifier + 'static, { async fn run(&mut self) -> Result<(), DeviceSyncError> { - // Wait for the identity to be ready before doing anything + // Wait for the identity to be ready & verified before doing anything while !self.client.identity().is_ready() { - crate::sleep(Duration::from_millis(200)).await; + xmtp_common::yield_().await } self.sync_init().await?; @@ -332,17 +327,22 @@ where let inbox_id = self.client.inbox_id().to_string(); let installation_id = hex::encode(self.client.installation_public_key()); while let Err(err) = self.run().await { + tracing::info!("Running worker.."); match err { DeviceSyncError::Client(ClientError::Storage( StorageError::PoolNeedsConnection, )) => { - tracing::warn!("Pool disconnected. task will restart on reconnect"); + tracing::warn!( + inbox_id, + installation_id, + "Pool disconnected. task will restart on reconnect" + ); break; } _ => { tracing::error!(inbox_id, installation_id, "sync worker error {err}"); // Wait 2 seconds before restarting. - crate::sleep(Duration::from_secs(2)).await; + xmtp_common::time::sleep(Duration::from_secs(2)).await; } } } @@ -615,7 +615,7 @@ where tracing::info!( inbox_id = self.inbox_id(), installation_id = hex::encode(self.installation_public_key()), - "Using upload url {upload_url}" + "Using upload url {upload_url}", ); let response = reqwest::Client::new() @@ -858,14 +858,11 @@ impl TryFrom for DeviceSyncKeyType { } pub(super) fn new_request_id() -> String { - Alphanumeric.sample_string(&mut rand::thread_rng(), ENC_KEY_SIZE) + xmtp_common::rand_string::() } pub(super) fn generate_nonce() -> [u8; NONCE_SIZE] { - let mut nonce = [0u8; NONCE_SIZE]; - let mut rng = crypto_utils::rng(); - rng.fill_bytes(&mut nonce); - nonce + xmtp_common::rand_array::() } pub(super) fn new_pin() -> String { diff --git a/xmtp_mls/src/groups/device_sync/consent_sync.rs b/xmtp_mls/src/groups/device_sync/consent_sync.rs index d327923fe..965fdb770 100644 --- a/xmtp_mls/src/groups/device_sync/consent_sync.rs +++ b/xmtp_mls/src/groups/device_sync/consent_sync.rs @@ -50,33 +50,41 @@ where } } -#[cfg(all(not(target_arch = "wasm32"), test))] +#[cfg(test)] pub(crate) mod tests { + #[cfg(target_arch = "wasm32")] + wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_dedicated_worker); + use wasm_bindgen_test::wasm_bindgen_test; + const HISTORY_SERVER_HOST: &str = "localhost"; const HISTORY_SERVER_PORT: u16 = 5558; - use std::time::{Duration, Instant}; + use xmtp_common::{ + assert_ok, + time::{Duration, Instant}, + }; use super::*; use crate::{ - assert_ok, builder::ClientBuilder, - groups::scoped_client::LocalScopedGroupClient, + groups::scoped_client::ScopedGroupClient, storage::consent_record::{ConsentState, ConsentType}, utils::test::wait_for_min_intents, }; use xmtp_cryptography::utils::generate_local_wallet; use xmtp_id::InboxOwner; - #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + #[wasm_bindgen_test(unsupported = tokio::test(flavor = "multi_thread", worker_threads = 1))] + #[cfg_attr(target_family = "wasm", ignore)] async fn test_consent_sync() { + xmtp_common::logger(); let history_sync_url = format!("http://{}:{}", HISTORY_SERVER_HOST, HISTORY_SERVER_PORT); - let wallet = generate_local_wallet(); let amal_a = ClientBuilder::new_test_client_with_history(&wallet, &history_sync_url).await; let amal_a_provider = amal_a.mls_provider().unwrap(); let amal_a_conn = amal_a_provider.conn_ref(); + wait_for_min_intents(amal_a_conn, 3).await; // create an alix installation and consent with alix let alix_wallet = generate_local_wallet(); @@ -93,12 +101,12 @@ pub(crate) mod tests { // Create a second installation for amal with sync. let amal_b = ClientBuilder::new_test_client_with_history(&wallet, &history_sync_url).await; + let amal_b_provider = amal_b.mls_provider().unwrap(); let amal_b_conn = amal_b_provider.conn_ref(); let consent_records_b = amal_b.syncable_consent_records(amal_b_conn).unwrap(); assert_eq!(consent_records_b.len(), 0); - - // make sure amal's worker has time to sync + // make sure amal's workers have time to sync // 3 Intents: // 1.) UpdateGroupMembership Intent for new sync group // 2.) Device Sync Request @@ -120,30 +128,25 @@ pub(crate) mod tests { // Have amal_a receive the message (and auto-process) let amal_a_sync_group = amal_a.get_sync_group(amal_a_conn).unwrap(); assert_ok!(amal_a_sync_group.sync_with_conn(&amal_a_provider).await); - - // Wait for up to 3 seconds for the reply on amal_b (usually is almost instant) - let start = Instant::now(); - let mut reply = None; - while reply.is_none() { - reply = amal_b + xmtp_common::wait_for_some(|| async { + amal_b .get_latest_sync_reply(&amal_b_provider, DeviceSyncKind::Consent) .await - .unwrap(); - if start.elapsed() > Duration::from_secs(3) { - panic!("Did not receive sync reply."); - } - } - - // Wait up to 3 seconds for sync to process (typically is almost instant) - let mut consent_b = 0; - let start = Instant::now(); - while consent_b != consent_a { - consent_b = amal_b.syncable_consent_records(amal_b_conn).unwrap().len(); - - if start.elapsed() > Duration::from_secs(3) { - panic!("Consent sync did not work. Consent: {consent_b}/{consent_a}"); - } - } + .unwrap() + }) + .await + .unwrap(); + + // Wait up to 20 seconds for sync to process (typically is almost instant) + xmtp_common::wait_for_eq( + || { + let consent_b = amal_b.syncable_consent_records(amal_b_conn).unwrap().len(); + futures::future::ready(consent_b != consent_a) + }, + true, + ) + .await + .unwrap(); // Test consent streaming let amal_b_sync_group = amal_b.get_sync_group(amal_b_conn).unwrap(); diff --git a/xmtp_mls/src/groups/device_sync/message_sync.rs b/xmtp_mls/src/groups/device_sync/message_sync.rs index 66e63e261..053dea448 100644 --- a/xmtp_mls/src/groups/device_sync/message_sync.rs +++ b/xmtp_mls/src/groups/device_sync/message_sync.rs @@ -42,24 +42,25 @@ where } } -#[cfg(all(not(target_arch = "wasm32"), test))] +#[cfg(test)] pub(crate) mod tests { #[cfg(target_arch = "wasm32")] wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_dedicated_worker); + use wasm_bindgen_test::wasm_bindgen_test; use super::*; + use crate::{ - api::test_utils::wait_for_some, - assert_ok, builder::ClientBuilder, groups::GroupMetadataOptions, utils::test::{wait_for_min_intents, HISTORY_SYNC_URL}, }; - use std::time::{Duration, Instant}; + use xmtp_common::{assert_ok, wait_for_some}; use xmtp_cryptography::utils::generate_local_wallet; use xmtp_id::InboxOwner; - #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + #[wasm_bindgen_test(unsupported = tokio::test(flavor = "multi_thread", worker_threads = 1))] + #[cfg_attr(target_family = "wasm", ignore)] async fn test_message_history_sync() { let wallet = generate_local_wallet(); let amal_a = ClientBuilder::new_test_client_with_history(&wallet, HISTORY_SYNC_URL).await; @@ -123,35 +124,30 @@ pub(crate) mod tests { let amal_a_sync_group = amal_a.get_sync_group(amal_a_conn).unwrap(); assert_ok!(amal_a_sync_group.sync_with_conn(&amal_a_provider).await); - // Wait for up to 3 seconds for the reply on amal_b (usually is almost instant) - let start = Instant::now(); - let mut reply = None; - while reply.is_none() { - reply = amal_b + xmtp_common::wait_for_some(|| async { + amal_b .get_latest_sync_reply(&amal_b_provider, DeviceSyncKind::MessageHistory) .await - .unwrap(); - if start.elapsed() > Duration::from_secs(3) { - panic!("Did not receive sync reply."); - } - } - - // Wait up to 3 seconds for sync to process (typically is almost instant) - let [mut groups_a, mut groups_b, mut messages_a, mut messages_b] = [0; 4]; - let start = Instant::now(); - while groups_a != groups_b || messages_a != messages_b { - groups_a = amal_a.syncable_groups(amal_a_conn).unwrap().len(); - groups_b = amal_b.syncable_groups(amal_b_conn).unwrap().len(); - messages_a = amal_a.syncable_messages(amal_a_conn).unwrap().len(); - messages_b = amal_b.syncable_messages(amal_b_conn).unwrap().len(); - - if start.elapsed() > Duration::from_secs(3) { - panic!("Message sync did not work. Groups: {groups_a}/{groups_b} | Messages: {messages_a}/{messages_b}"); - } - } + .unwrap() + }) + .await + .unwrap(); + + xmtp_common::wait_for_eq( + || { + let groups_a = amal_a.syncable_groups(amal_a_conn).unwrap().len(); + let groups_b = amal_b.syncable_groups(amal_b_conn).unwrap().len(); + let messages_a = amal_a.syncable_messages(amal_a_conn).unwrap().len(); + let messages_b = amal_b.syncable_messages(amal_b_conn).unwrap().len(); + futures::future::ready(groups_a != groups_b || messages_a != messages_b) + }, + true, + ) + .await + .unwrap(); } - #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + #[wasm_bindgen_test(unsupported = tokio::test(flavor = "multi_thread", worker_threads = 1))] async fn test_sync_continues_during_db_disconnect() { let wallet = generate_local_wallet(); let amal_a = ClientBuilder::new_test_client_with_history(&wallet, HISTORY_SYNC_URL).await; @@ -213,35 +209,7 @@ pub(crate) mod tests { assert_ne!(old_group_id, new_group_id); } - #[tokio::test(flavor = "multi_thread", worker_threads = 1)] - async fn disconnect_does_not_effect_init() { - let wallet = generate_local_wallet(); - let amal_a = ClientBuilder::new_test_client_with_history(&wallet, HISTORY_SYNC_URL).await; - - let amal_a_provider = amal_a.mls_provider().unwrap(); - let amal_a_conn = amal_a_provider.conn_ref(); - - //release db conn right after creating client, not giving the worker time to do initial - //sync - amal_a.release_db_connection().unwrap(); - - let sync_group = amal_a.get_sync_group(amal_a_conn); - crate::assert_err!(sync_group, GroupError::GroupNotFound); - - amal_a.reconnect_db().unwrap(); - - // make sure amal's worker has time to sync - // 3 Intents: - // 1.) Sync Group Creation - // 2.) Device Sync Request - // 3.) MessageHistory Sync Request - wait_for_min_intents(amal_a_conn, 3).await; - tracing::info!("Waiting for intents published"); - let sync_group = amal_a.get_sync_group(amal_a_conn); - assert!(sync_group.is_ok()); - } - - #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + #[wasm_bindgen_test(unsupported = tokio::test(flavor = "multi_thread", worker_threads = 1))] async fn test_prepare_groups_to_sync() { let wallet = generate_local_wallet(); let amal_a = ClientBuilder::new_test_client(&wallet).await; @@ -258,7 +226,7 @@ pub(crate) mod tests { assert_eq!(result.len(), 2); } - #[tokio::test] + #[wasm_bindgen_test(unsupported = tokio::test(flavor = "multi_thread", worker_threads = 1))] async fn test_externals_cant_join_sync_group() { let wallet = generate_local_wallet(); let amal = ClientBuilder::new_test_client_with_history(&wallet, HISTORY_SYNC_URL).await; @@ -295,20 +263,20 @@ pub(crate) mod tests { assert!(result.is_err()); } - #[test] + #[wasm_bindgen_test(unsupported = test)] fn test_new_pin() { let pin = new_pin(); assert!(pin.chars().all(|c| c.is_numeric())); assert_eq!(pin.len(), 4); } - #[test] + #[wasm_bindgen_test(unsupported = test)] fn test_new_request_id() { let request_id = new_request_id(); assert_eq!(request_id.len(), ENC_KEY_SIZE); } - #[test] + #[wasm_bindgen_test(unsupported = test)] fn test_new_key() { let sig_key = DeviceSyncKeyType::new_aes_256_gcm_key(); let enc_key = DeviceSyncKeyType::new_aes_256_gcm_key(); @@ -318,7 +286,7 @@ pub(crate) mod tests { assert_ne!(sig_key, enc_key); } - #[test] + #[wasm_bindgen_test(unsupported = test)] fn test_generate_nonce() { let nonce_1 = generate_nonce(); let nonce_2 = generate_nonce(); diff --git a/xmtp_mls/src/groups/device_sync/preference_sync.rs b/xmtp_mls/src/groups/device_sync/preference_sync.rs index fa9c48628..f677eee4e 100644 --- a/xmtp_mls/src/groups/device_sync/preference_sync.rs +++ b/xmtp_mls/src/groups/device_sync/preference_sync.rs @@ -32,9 +32,9 @@ impl TryInto for UserPreferenceUpdate { #[cfg(test)] mod tests { - use crate::storage::consent_record::{ConsentState, ConsentType}; - use super::*; + use crate::storage::consent_record::{ConsentState, ConsentType}; + use wasm_bindgen_test::wasm_bindgen_test; #[derive(Serialize, Deserialize, Clone)] #[repr(i32)] @@ -42,8 +42,7 @@ mod tests { ConsentUpdate(StoredConsentRecord) = 1, } - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] - #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] + #[wasm_bindgen_test(unsupported = tokio::test(flavor = "multi_thread", worker_threads = 1))] async fn test_can_deserialize_between_versions() { let consent_record = StoredConsentRecord { entity: "hello there".to_string(), diff --git a/xmtp_mls/src/groups/group_permissions.rs b/xmtp_mls/src/groups/group_permissions.rs index 62aedf158..1a1b04594 100644 --- a/xmtp_mls/src/groups/group_permissions.rs +++ b/xmtp_mls/src/groups/group_permissions.rs @@ -1275,19 +1275,17 @@ pub(crate) mod tests { #[cfg(target_arch = "wasm32")] wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_dedicated_worker); - use crate::{ - groups::{ - group_metadata::DmMembers, group_mutable_metadata::MetadataField, - validated_commit::MutableMetadataChanges, - }, - utils::test::{rand_string, rand_vec}, + use crate::groups::{ + group_metadata::DmMembers, group_mutable_metadata::MetadataField, + validated_commit::MutableMetadataChanges, }; + use xmtp_common::{rand_string, rand_vec}; use super::*; fn build_change(inbox_id: Option, is_admin: bool, is_super_admin: bool) -> Inbox { Inbox { - inbox_id: inbox_id.unwrap_or(rand_string()), + inbox_id: inbox_id.unwrap_or(rand_string::<24>()), is_creator: is_super_admin, is_super_admin, is_admin, @@ -1302,8 +1300,8 @@ pub(crate) mod tests { is_super_admin: bool, ) -> CommitParticipant { CommitParticipant { - inbox_id: inbox_id.unwrap_or(rand_string()), - installation_id: installation_id.unwrap_or_else(rand_vec), + inbox_id: inbox_id.unwrap_or(rand_string::<24>()), + installation_id: installation_id.unwrap_or_else(rand_vec::<24>), is_creator: is_super_admin, is_admin, is_super_admin, @@ -1344,7 +1342,13 @@ pub(crate) mod tests { let field_changes = metadata_fields_changed .unwrap_or_default() .into_iter() - .map(|field| MetadataFieldChange::new(field, Some(rand_string()), Some(rand_string()))) + .map(|field| { + MetadataFieldChange::new( + field, + Some(rand_string::<24>()), + Some(rand_string::<24>()), + ) + }) .collect(); let dm_members = if let Some(dm_target_inbox_id) = dm_target_inbox_id { diff --git a/xmtp_mls/src/groups/intents.rs b/xmtp_mls/src/groups/intents.rs index b3faf11b4..d756f204a 100644 --- a/xmtp_mls/src/groups/intents.rs +++ b/xmtp_mls/src/groups/intents.rs @@ -95,7 +95,7 @@ impl MlsGroup { fn maybe_insert_key_update_intent(&self, conn: &DbConnection) -> Result<(), GroupError> { let last_rotated_at_ns = conn.get_rotated_at_ns(self.group_id.clone())?; - let now_ns = crate::utils::time::now_ns(); + let now_ns = xmtp_common::time::now_ns(); let elapsed_ns = now_ns - last_rotated_at_ns; if elapsed_ns > GROUP_KEY_ROTATION_INTERVAL_NS { self.queue_intent_with_conn(conn, IntentKind::KeyUpdate, vec![])?; diff --git a/xmtp_mls/src/groups/mls_sync.rs b/xmtp_mls/src/groups/mls_sync.rs index a613551f8..954041dde 100644 --- a/xmtp_mls/src/groups/mls_sync.rs +++ b/xmtp_mls/src/groups/mls_sync.rs @@ -13,13 +13,12 @@ use crate::{ GRPC_DATA_LIMIT, HMAC_SALT, MAX_GROUP_SIZE, MAX_INTENT_PUBLISH_ATTEMPTS, MAX_PAST_EPOCHS, SYNC_UPDATE_INSTALLATIONS_INTERVAL_NS, }, + groups::device_sync::DeviceSyncContent, groups::{intents::UpdateMetadataIntentData, validated_commit::ValidatedCommit}, hpke::{encrypt_welcome, HpkeError}, identity::{parse_credential, IdentityError}, identity_updates::load_identity_updates, intents::ProcessIntentError, - retry::{Retry, RetryableError}, - retry_async, storage::{ db_connection::DbConnection, group_intent::{IntentKind, IntentState, StoredGroupIntent, ID}, @@ -31,11 +30,11 @@ use crate::{ StorageError, }, subscriptions::LocalEvents, + subscriptions::SyncMessage, utils::{hash::sha256, id::calculate_message_id, time::hmac_epoch}, xmtp_openmls_provider::XmtpOpenMlsProvider, Delete, Fetch, StoreOrIgnore, }; -use crate::{groups::device_sync::DeviceSyncContent, subscriptions::SyncMessage}; use futures::future::try_join_all; use hkdf::Hkdf; use hmac::{Hmac, Mac}; @@ -63,6 +62,8 @@ use std::{ ops::RangeInclusive, }; use thiserror::Error; +use tracing::debug; +use xmtp_common::{retry_async, Retry, RetryableError}; use xmtp_content_types::{group_updated::GroupUpdatedCodec, CodecError, ContentCodec}; use xmtp_id::{InboxId, InboxIdRef}; use xmtp_proto::xmtp::mls::{ @@ -131,7 +132,7 @@ pub enum GroupMessageProcessingError { AssociationDeserialization(#[from] xmtp_id::associations::DeserializationError), } -impl crate::retry::RetryableError for GroupMessageProcessingError { +impl RetryableError for GroupMessageProcessingError { fn is_retryable(&self) -> bool { match self { Self::Diesel(err) => err.is_retryable(), @@ -1221,7 +1222,7 @@ where None => SYNC_UPDATE_INSTALLATIONS_INTERVAL_NS, }; - let now_ns = crate::utils::time::now_ns(); + let now_ns = xmtp_common::time::now_ns(); let last_ns = provider .conn_ref() .get_installations_time_checked(self.group_id.clone())?; diff --git a/xmtp_mls/src/groups/mod.rs b/xmtp_mls/src/groups/mod.rs index c8e19e933..9213c38ef 100644 --- a/xmtp_mls/src/groups/mod.rs +++ b/xmtp_mls/src/groups/mod.rs @@ -59,6 +59,7 @@ use self::{ validated_commit::CommitValidationError, }; use std::{collections::HashSet, sync::Arc}; +use xmtp_common::time::now_ns; use xmtp_cryptography::signature::{sanitize_evm_addresses, AddressValidationError}; use xmtp_id::{InboxId, InboxIdRef}; use xmtp_proto::xmtp::mls::{ @@ -84,7 +85,6 @@ use crate::{ identity::{parse_credential, IdentityError}, identity_updates::{load_identity_updates, InstallationDiffError}, intents::ProcessIntentError, - retry::RetryableError, storage::{ consent_record::{ConsentState, ConsentType, StoredConsentRecord}, db_connection::DbConnection, @@ -94,10 +94,11 @@ use crate::{ sql_key_store, StorageError, }, subscriptions::{LocalEventError, LocalEvents}, - utils::{id::calculate_message_id, time::now_ns}, + utils::id::calculate_message_id, xmtp_openmls_provider::XmtpOpenMlsProvider, Store, }; +use xmtp_common::retry::RetryableError; #[derive(Debug, Error)] pub enum GroupError { @@ -1609,13 +1610,14 @@ pub(crate) mod tests { use openmls::prelude::Member; use prost::Message; use std::sync::Arc; + use wasm_bindgen_test::wasm_bindgen_test; + use xmtp_common::assert_err; use xmtp_content_types::{group_updated::GroupUpdatedCodec, ContentCodec}; use xmtp_cryptography::utils::generate_local_wallet; use xmtp_proto::xmtp::mls::api::v1::group_message::Version; use xmtp_proto::xmtp::mls::message_contents::EncodedContent; use crate::{ - assert_err, builder::ClientBuilder, groups::{ build_dm_protected_metadata_extension, build_mutable_metadata_extension_default, @@ -1706,8 +1708,7 @@ pub(crate) mod tests { .unwrap(); } - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] - #[cfg_attr(not(target_arch = "wasm32"), tokio::test(flavor = "current_thread"))] + #[wasm_bindgen_test(unsupported = tokio::test(flavor = "current_thread"))] async fn test_send_message() { let wallet = generate_local_wallet(); let client = ClientBuilder::new_test_client(&wallet).await; @@ -1724,8 +1725,7 @@ pub(crate) mod tests { assert_eq!(messages.len(), 2); } - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] - #[cfg_attr(not(target_arch = "wasm32"), tokio::test(flavor = "current_thread"))] + #[wasm_bindgen_test(unsupported = tokio::test(flavor = "current_thread"))] async fn test_receive_self_message() { let wallet = generate_local_wallet(); let client = ClientBuilder::new_test_client(&wallet).await; @@ -1778,8 +1778,7 @@ pub(crate) mod tests { } // Test members function from non group creator - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] - #[cfg_attr(not(target_arch = "wasm32"), tokio::test(flavor = "current_thread"))] + #[wasm_bindgen_test(unsupported = tokio::test(flavor = "current_thread"))] async fn test_members_func_from_non_creator() { let amal = ClientBuilder::new_test_client(&generate_local_wallet()).await; let bola = ClientBuilder::new_test_client(&generate_local_wallet()).await; @@ -1835,8 +1834,7 @@ pub(crate) mod tests { // Amal and Bola will both try and add Charlie from the same epoch. // The group should resolve to a consistent state - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] - #[cfg_attr(not(target_arch = "wasm32"), tokio::test(flavor = "current_thread"))] + #[wasm_bindgen_test(unsupported = tokio::test(flavor = "current_thread"))] async fn test_add_member_conflict() { let amal = ClientBuilder::new_test_client(&generate_local_wallet()).await; let bola = ClientBuilder::new_test_client(&generate_local_wallet()).await; @@ -1935,8 +1933,9 @@ pub(crate) mod tests { #[cfg(not(target_arch = "wasm32"))] fn test_create_from_welcome_validation() { use crate::groups::{build_group_membership_extension, group_membership::GroupMembership}; - use crate::{assert_logged, utils::test::traced_test}; - traced_test(|| async { + use xmtp_common::assert_logged; + xmtp_common::traced_test!(async { + tracing::info!("TEST"); let alix = ClientBuilder::new_test_client(&generate_local_wallet()).await; let bo = ClientBuilder::new_test_client(&generate_local_wallet()).await; @@ -1970,8 +1969,7 @@ pub(crate) mod tests { }); } - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] - #[cfg_attr(not(target_arch = "wasm32"), tokio::test(flavor = "current_thread"))] + #[wasm_bindgen_test(unsupported = tokio::test(flavor = "current_thread"))] async fn test_add_inbox() { let client = ClientBuilder::new_test_client(&generate_local_wallet()).await; let client_2 = ClientBuilder::new_test_client(&generate_local_wallet()).await; @@ -1995,8 +1993,7 @@ pub(crate) mod tests { assert_eq!(messages.len(), 1); } - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] - #[cfg_attr(not(target_arch = "wasm32"), tokio::test(flavor = "current_thread"))] + #[wasm_bindgen_test(unsupported = tokio::test(flavor = "current_thread"))] async fn test_add_invalid_member() { let client = ClientBuilder::new_test_client(&generate_local_wallet()).await; let group = client @@ -2008,8 +2005,7 @@ pub(crate) mod tests { assert!(result.is_err()); } - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] - #[cfg_attr(not(target_arch = "wasm32"), tokio::test(flavor = "current_thread"))] + #[wasm_bindgen_test(unsupported = tokio::test(flavor = "current_thread"))] async fn test_add_unregistered_member() { let amal = ClientBuilder::new_test_client(&generate_local_wallet()).await; let unconnected_wallet_address = generate_local_wallet().get_address(); @@ -2021,8 +2017,7 @@ pub(crate) mod tests { assert!(result.is_err()); } - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] - #[cfg_attr(not(target_arch = "wasm32"), tokio::test(flavor = "current_thread"))] + #[wasm_bindgen_test(unsupported = tokio::test(flavor = "current_thread"))] async fn test_remove_inbox() { let client_1 = ClientBuilder::new_test_client(&generate_local_wallet()).await; // Add another client onto the network @@ -2060,8 +2055,7 @@ pub(crate) mod tests { assert_eq!(messages.len(), 2); } - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] - #[cfg_attr(not(target_arch = "wasm32"), tokio::test(flavor = "current_thread"))] + #[wasm_bindgen_test(unsupported = tokio::test(flavor = "current_thread"))] async fn test_key_update() { let client = ClientBuilder::new_test_client(&generate_local_wallet()).await; let bola_client = ClientBuilder::new_test_client(&generate_local_wallet()).await; @@ -2101,8 +2095,7 @@ pub(crate) mod tests { assert_eq!(bola_messages.len(), 1); } - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] - #[cfg_attr(not(target_arch = "wasm32"), tokio::test(flavor = "current_thread"))] + #[wasm_bindgen_test(unsupported = tokio::test(flavor = "current_thread"))] async fn test_post_commit() { let client = ClientBuilder::new_test_client(&generate_local_wallet()).await; let client_2 = ClientBuilder::new_test_client(&generate_local_wallet()).await; @@ -2125,8 +2118,7 @@ pub(crate) mod tests { assert_eq!(welcome_messages.len(), 1); } - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] - #[cfg_attr(not(target_arch = "wasm32"), tokio::test(flavor = "current_thread"))] + #[wasm_bindgen_test(unsupported = tokio::test(flavor = "current_thread"))] async fn test_remove_by_account_address() { let amal = ClientBuilder::new_test_client(&generate_local_wallet()).await; let bola_wallet = &generate_local_wallet(); @@ -2174,8 +2166,7 @@ pub(crate) mod tests { .unwrap()) } - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] - #[cfg_attr(not(target_arch = "wasm32"), tokio::test(flavor = "current_thread"))] + #[wasm_bindgen_test(unsupported = tokio::test(flavor = "current_thread"))] async fn test_removed_members_cannot_send_message_to_others() { let amal = ClientBuilder::new_test_client(&generate_local_wallet()).await; let bola_wallet = &generate_local_wallet(); @@ -2236,8 +2227,7 @@ pub(crate) mod tests { assert!(amal_messages.is_empty()); } - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] - #[cfg_attr(not(target_arch = "wasm32"), tokio::test(flavor = "current_thread"))] + #[wasm_bindgen_test(unsupported = tokio::test(flavor = "current_thread"))] async fn test_add_missing_installations() { // Setup for test let amal_wallet = generate_local_wallet(); @@ -2270,11 +2260,7 @@ pub(crate) mod tests { assert_eq!(num_members, 3); } - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] - #[cfg_attr( - not(target_arch = "wasm32"), - tokio::test(flavor = "multi_thread", worker_threads = 10) - )] + #[wasm_bindgen_test(unsupported = tokio::test(flavor = "multi_thread", worker_threads = 10))] async fn test_self_resolve_epoch_mismatch() { let amal = ClientBuilder::new_test_client(&generate_local_wallet()).await; let bola = ClientBuilder::new_test_client(&generate_local_wallet()).await; @@ -2324,8 +2310,7 @@ pub(crate) mod tests { assert!(expected_latest_message.eq(&dave_latest_message.decrypted_message_bytes)); } - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] - #[cfg_attr(not(target_arch = "wasm32"), tokio::test(flavor = "current_thread"))] + #[wasm_bindgen_test(unsupported = tokio::test(flavor = "current_thread"))] async fn test_group_permissions() { let amal = ClientBuilder::new_test_client(&generate_local_wallet()).await; let bola = ClientBuilder::new_test_client(&generate_local_wallet()).await; @@ -2351,8 +2336,7 @@ pub(crate) mod tests { .is_err(),); } - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] - #[cfg_attr(not(target_arch = "wasm32"), tokio::test(flavor = "current_thread"))] + #[wasm_bindgen_test(unsupported = tokio::test(flavor = "current_thread"))] async fn test_group_options() { let amal = ClientBuilder::new_test_client(&generate_local_wallet()).await; @@ -2394,8 +2378,7 @@ pub(crate) mod tests { assert_eq!(amal_group_pinned_frame_url, "pinned frame"); } - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] - #[cfg_attr(not(target_arch = "wasm32"), tokio::test(flavor = "current_thread"))] + #[wasm_bindgen_test(unsupported = tokio::test(flavor = "current_thread"))] #[ignore] async fn test_max_limit_add() { let amal = ClientBuilder::new_test_client(&generate_local_wallet()).await; @@ -2420,8 +2403,7 @@ pub(crate) mod tests { .is_err(),); } - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] - #[cfg_attr(not(target_arch = "wasm32"), tokio::test(flavor = "current_thread"))] + #[wasm_bindgen_test(unsupported = tokio::test(flavor = "current_thread"))] async fn test_group_mutable_data() { let amal = ClientBuilder::new_test_client(&generate_local_wallet()).await; let bola = ClientBuilder::new_test_client(&generate_local_wallet()).await; @@ -2513,8 +2495,7 @@ pub(crate) mod tests { assert_eq!(bola_group_name, "New Group Name 1"); } - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] - #[cfg_attr(not(target_arch = "wasm32"), tokio::test(flavor = "current_thread"))] + #[wasm_bindgen_test(unsupported = tokio::test(flavor = "current_thread"))] async fn test_update_group_image_url_square() { let amal = ClientBuilder::new_test_client(&generate_local_wallet()).await; @@ -2552,8 +2533,7 @@ pub(crate) mod tests { assert_eq!(amal_group_image_url, "a url"); } - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] - #[cfg_attr(not(target_arch = "wasm32"), tokio::test(flavor = "current_thread"))] + #[wasm_bindgen_test(unsupported = tokio::test(flavor = "current_thread"))] async fn test_update_group_pinned_frame_url() { let amal = ClientBuilder::new_test_client(&generate_local_wallet()).await; @@ -2591,8 +2571,7 @@ pub(crate) mod tests { assert_eq!(amal_group_pinned_frame_url, "a frame url"); } - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] - #[cfg_attr(not(target_arch = "wasm32"), tokio::test(flavor = "current_thread"))] + #[wasm_bindgen_test(unsupported = tokio::test(flavor = "current_thread"))] async fn test_group_mutable_data_group_permissions() { let amal = ClientBuilder::new_test_client(&generate_local_wallet()).await; let bola_wallet = generate_local_wallet(); @@ -2681,8 +2660,7 @@ pub(crate) mod tests { assert_eq!(amal_group_name, "New Group Name 2"); } - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] - #[cfg_attr(not(target_arch = "wasm32"), tokio::test(flavor = "current_thread"))] + #[wasm_bindgen_test(unsupported = tokio::test(flavor = "current_thread"))] async fn test_group_admin_list_update() { let amal = ClientBuilder::new_test_client(&generate_local_wallet()).await; let bola_wallet = generate_local_wallet(); @@ -2801,8 +2779,7 @@ pub(crate) mod tests { .expect_err("expected err"); } - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] - #[cfg_attr(not(target_arch = "wasm32"), tokio::test(flavor = "current_thread"))] + #[wasm_bindgen_test(unsupported = tokio::test(flavor = "current_thread"))] async fn test_group_super_admin_list_update() { let amal = ClientBuilder::new_test_client(&generate_local_wallet()).await; let bola = ClientBuilder::new_test_client(&generate_local_wallet()).await; @@ -2912,8 +2889,7 @@ pub(crate) mod tests { .expect_err("expected err"); } - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] - #[cfg_attr(not(target_arch = "wasm32"), tokio::test(flavor = "current_thread"))] + #[wasm_bindgen_test(unsupported = tokio::test(flavor = "current_thread"))] async fn test_group_members_permission_level_update() { let amal = ClientBuilder::new_test_client(&generate_local_wallet()).await; let bola = ClientBuilder::new_test_client(&generate_local_wallet()).await; @@ -3010,8 +2986,7 @@ pub(crate) mod tests { assert_eq!(count_member, 0, "no members have no admin status"); } - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] - #[cfg_attr(not(target_arch = "wasm32"), tokio::test(flavor = "current_thread"))] + #[wasm_bindgen_test(unsupported = tokio::test(flavor = "current_thread"))] async fn test_staged_welcome() { // Create Clients let amal = ClientBuilder::new_test_client(&generate_local_wallet()).await; @@ -3054,8 +3029,7 @@ pub(crate) mod tests { ); } - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] - #[cfg_attr(not(target_arch = "wasm32"), tokio::test(flavor = "current_thread"))] + #[wasm_bindgen_test(unsupported = tokio::test(flavor = "current_thread"))] async fn test_can_read_group_creator_inbox_id() { let amal = ClientBuilder::new_test_client(&generate_local_wallet()).await; let policy_set = Some(PreconfiguredPolicies::AllMembers.to_policy_set()); @@ -3081,8 +3055,7 @@ pub(crate) mod tests { assert_eq!(protected_metadata.creator_inbox_id, amal.inbox_id()); } - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] - #[cfg_attr(not(target_arch = "wasm32"), tokio::test(flavor = "current_thread"))] + #[wasm_bindgen_test(unsupported = tokio::test(flavor = "current_thread"))] async fn test_can_update_gce_after_failed_commit() { // Step 1: Amal creates a group let amal = ClientBuilder::new_test_client(&generate_local_wallet()).await; @@ -3150,8 +3123,7 @@ pub(crate) mod tests { assert_eq!(bola_group_name, "Name Update 2"); } - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] - #[cfg_attr(not(target_arch = "wasm32"), tokio::test(flavor = "current_thread"))] + #[wasm_bindgen_test(unsupported = tokio::test(flavor = "current_thread"))] async fn test_can_update_permissions_after_group_creation() { let amal = ClientBuilder::new_test_client(&generate_local_wallet()).await; let policy_set = Some(PreconfiguredPolicies::AdminsOnly.to_policy_set()); @@ -3216,8 +3188,7 @@ pub(crate) mod tests { assert_eq!(members.len(), 3); } - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] - #[cfg_attr(not(target_arch = "wasm32"), tokio::test(flavor = "multi_thread"))] + #[wasm_bindgen_test(unsupported = tokio::test(flavor = "current_thread"))] async fn test_optimistic_send() { let amal = Arc::new(ClientBuilder::new_test_client(&generate_local_wallet()).await); let bola_wallet = generate_local_wallet(); @@ -3304,8 +3275,7 @@ pub(crate) mod tests { ); } - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] - #[cfg_attr(not(target_arch = "wasm32"), tokio::test(flavor = "multi_thread"))] + #[wasm_bindgen_test(unsupported = tokio::test(flavor = "current_thread"))] async fn test_dm_creation() { let amal = ClientBuilder::new_test_client(&generate_local_wallet()).await; let bola = ClientBuilder::new_test_client(&generate_local_wallet()).await; @@ -3372,8 +3342,7 @@ pub(crate) mod tests { assert!(!is_bola_super_admin); } - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] - #[cfg_attr(not(target_arch = "wasm32"), tokio::test(flavor = "multi_thread"))] + #[wasm_bindgen_test(unsupported = tokio::test(flavor = "current_thread"))] async fn process_messages_abort_on_retryable_error() { let alix = ClientBuilder::new_test_client(&generate_local_wallet()).await; let bo = ClientBuilder::new_test_client(&generate_local_wallet()).await; @@ -3427,8 +3396,7 @@ pub(crate) mod tests { } } - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] - #[cfg_attr(not(target_arch = "wasm32"), tokio::test(flavor = "multi_thread"))] + #[wasm_bindgen_test(unsupported = tokio::test(flavor = "current_thread"))] async fn skip_already_processed_messages() { let alix = ClientBuilder::new_test_client(&generate_local_wallet()).await; @@ -3480,11 +3448,7 @@ pub(crate) mod tests { } } - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] - #[cfg_attr( - not(target_arch = "wasm32"), - tokio::test(flavor = "multi_thread", worker_threads = 5) - )] + #[wasm_bindgen_test(unsupported = tokio::test(flavor = "multi_thread", worker_threads = 5))] async fn test_parallel_syncs() { let wallet = generate_local_wallet(); let alix1 = Arc::new(ClientBuilder::new_test_client(&wallet).await); @@ -3586,11 +3550,7 @@ pub(crate) mod tests { * We need to be safe even in situations where there are multiple * intents that do the same thing, leading to conflicts */ - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] - #[cfg_attr( - not(target_arch = "wasm32"), - tokio::test(flavor = "multi_thread", worker_threads = 5) - )] + #[wasm_bindgen_test(unsupported = tokio::test(flavor = "multi_thread", worker_threads = 5))] async fn add_missing_installs_reentrancy() { let wallet = generate_local_wallet(); let alix1 = ClientBuilder::new_test_client(&wallet).await; @@ -3667,11 +3627,7 @@ pub(crate) mod tests { .any(|m| m.decrypted_message_bytes == "hi from alix1".as_bytes())); } - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] - #[cfg_attr( - not(target_arch = "wasm32"), - tokio::test(flavor = "multi_thread", worker_threads = 5) - )] + #[wasm_bindgen_test(unsupported = tokio::test(flavor = "multi_thread", worker_threads = 5))] async fn respect_allow_epoch_increment() { let wallet = generate_local_wallet(); let client = ClientBuilder::new_test_client(&wallet).await; @@ -3711,8 +3667,7 @@ pub(crate) mod tests { ); } - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] - #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] + #[wasm_bindgen_test(unsupported = tokio::test)] async fn test_get_and_set_consent() { let alix = ClientBuilder::new_test_client(&generate_local_wallet()).await; let bola = ClientBuilder::new_test_client(&generate_local_wallet()).await; @@ -3771,8 +3726,7 @@ pub(crate) mod tests { assert_eq!(caro_group.consent_state().unwrap(), ConsentState::Allowed); } - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] - #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] + #[wasm_bindgen_test(unsupported = tokio::test)] // TODO(rich): Generalize the test once fixed - test messages that are 0, 1, 2, 3, 4, 5 epochs behind async fn test_max_past_epochs() { // Create group with two members @@ -3831,8 +3785,7 @@ pub(crate) mod tests { assert_eq!(alix_messages.len(), 3); // Fails here, 2 != 3 } - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] - #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] + #[wasm_bindgen_test(unsupported = tokio::test)] async fn test_validate_dm_group() { let client = ClientBuilder::new_test_client(&generate_local_wallet()).await; let added_by_inbox = "added_by_inbox_id"; diff --git a/xmtp_mls/src/groups/scoped_client.rs b/xmtp_mls/src/groups/scoped_client.rs index 557761f6e..e745114a1 100644 --- a/xmtp_mls/src/groups/scoped_client.rs +++ b/xmtp_mls/src/groups/scoped_client.rs @@ -17,7 +17,7 @@ use xmtp_id::{ }; use xmtp_proto::{api_client::trait_impls::XmtpApi, xmtp::mls::api::v1::GroupMessage}; -#[cfg_attr(not(target_arch = "wasm32"), trait_variant::make(ScopedGroupClient: Send ))] +#[cfg_attr(not(target_arch = "wasm32"), trait_variant::make(ScopedGroupClient: Send))] #[cfg(not(target_arch = "wasm32"))] #[allow(unused)] pub trait LocalScopedGroupClient: Send + Sync + Sized { diff --git a/xmtp_mls/src/groups/subscriptions.rs b/xmtp_mls/src/groups/subscriptions.rs index fbaaa20d6..eb354fe3c 100644 --- a/xmtp_mls/src/groups/subscriptions.rs +++ b/xmtp_mls/src/groups/subscriptions.rs @@ -15,8 +15,8 @@ use crate::storage::StorageError; use crate::subscriptions::MessagesStreamInfo; use crate::subscriptions::SubscribeError; use crate::XmtpOpenMlsProvider; -use crate::{retry::Retry, retry_async}; use prost::Message; +use xmtp_common::{retry_async, Retry}; use xmtp_proto::xmtp::mls::api::v1::GroupMessage; impl MlsGroup { @@ -263,6 +263,8 @@ pub(crate) mod tests { #[cfg(target_arch = "wasm32")] wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_dedicated_worker); + use wasm_bindgen_test::wasm_bindgen_test; + use super::*; use tokio_stream::wrappers::UnboundedReceiverStream; use xmtp_cryptography::utils::generate_local_wallet; @@ -273,11 +275,7 @@ pub(crate) mod tests { }; use futures::StreamExt; - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] - #[cfg_attr( - not(target_arch = "wasm32"), - tokio::test(flavor = "multi_thread", worker_threads = 1) - )] + #[wasm_bindgen_test(unsupported = tokio::test(flavor = "multi_thread", worker_threads = 10))] async fn test_decode_group_message_bytes() { let amal = ClientBuilder::new_test_client(&generate_local_wallet()).await; let bola = ClientBuilder::new_test_client(&generate_local_wallet()).await; @@ -312,11 +310,7 @@ pub(crate) mod tests { } } - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] - #[cfg_attr( - not(target_arch = "wasm32"), - tokio::test(flavor = "multi_thread", worker_threads = 10) - )] + #[wasm_bindgen_test(unsupported = tokio::test(flavor = "multi_thread", worker_threads = 10))] async fn test_subscribe_messages() { let amal = ClientBuilder::new_test_client(&generate_local_wallet()).await; let bola = Arc::new(ClientBuilder::new_test_client(&generate_local_wallet()).await); @@ -369,11 +363,7 @@ pub(crate) mod tests { assert_eq!(second_val.decrypted_message_bytes, "goodbye".as_bytes()); } - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] - #[cfg_attr( - not(target_arch = "wasm32"), - tokio::test(flavor = "multi_thread", worker_threads = 10) - )] + #[wasm_bindgen_test(unsupported = tokio::test(flavor = "multi_thread", worker_threads = 10))] async fn test_subscribe_multiple() { let amal = Arc::new(ClientBuilder::new_test_client(&generate_local_wallet()).await); let group = Arc::new( @@ -411,11 +401,7 @@ pub(crate) mod tests { } } - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] - #[cfg_attr( - not(target_arch = "wasm32"), - tokio::test(flavor = "multi_thread", worker_threads = 5) - )] + #[wasm_bindgen_test(unsupported = tokio::test(flavor = "multi_thread", worker_threads = 10))] async fn test_subscribe_membership_changes() { let amal = Arc::new(ClientBuilder::new_test_client(&generate_local_wallet()).await); let bola = ClientBuilder::new_test_client(&generate_local_wallet()).await; @@ -443,7 +429,7 @@ pub(crate) mod tests { // just to make sure stream is started let _ = start_rx.await; // Adding in a sleep, since the HTTP API client may acknowledge requests before they are ready - crate::sleep(core::time::Duration::from_millis(100)).await; + xmtp_common::time::sleep(core::time::Duration::from_millis(100)).await; amal_group .add_members_by_inbox_id(&[bola.inbox_id()]) diff --git a/xmtp_mls/src/groups/validated_commit.rs b/xmtp_mls/src/groups/validated_commit.rs index 45cb5cc75..f13557236 100644 --- a/xmtp_mls/src/groups/validated_commit.rs +++ b/xmtp_mls/src/groups/validated_commit.rs @@ -24,10 +24,9 @@ use xmtp_proto::xmtp::{ use crate::{ configuration::GROUP_MEMBERSHIP_EXTENSION_ID, identity_updates::{InstallationDiff, InstallationDiffError}, - retry::RetryableError, - retryable, storage::db_connection::DbConnection, }; +use xmtp_common::{retry::RetryableError, retryable}; use super::{ group_membership::{GroupMembership, MembershipDiff}, diff --git a/xmtp_mls/src/hpke.rs b/xmtp_mls/src/hpke.rs index 19906a351..cf664043a 100644 --- a/xmtp_mls/src/hpke.rs +++ b/xmtp_mls/src/hpke.rs @@ -1,7 +1,5 @@ use crate::{ configuration::{CIPHERSUITE, WELCOME_HPKE_LABEL}, - retry::RetryableError, - retryable, storage::sql_key_store::{SqlKeyStoreError, KEY_PACKAGE_REFERENCES}, xmtp_openmls_provider::XmtpOpenMlsProvider, }; @@ -17,6 +15,7 @@ use openmls_rust_crypto::RustCrypto; use openmls_traits::OpenMlsProvider; use openmls_traits::{storage::StorageProvider, types::HpkeCiphertext}; use thiserror::Error; +use xmtp_common::{retryable, RetryableError}; #[derive(Debug, Error)] pub enum HpkeError { diff --git a/xmtp_mls/src/identity.rs b/xmtp_mls/src/identity.rs index d80ebf852..10a05344a 100644 --- a/xmtp_mls/src/identity.rs +++ b/xmtp_mls/src/identity.rs @@ -1,7 +1,6 @@ use std::sync::atomic::{AtomicBool, Ordering}; use crate::configuration::GROUP_PERMISSIONS_EXTENSION_ID; -use crate::retry::RetryableError; use crate::storage::db_connection::DbConnection; use crate::storage::identity::StoredIdentity; use crate::storage::sql_key_store::{SqlKeyStore, SqlKeyStoreError, KEY_PACKAGE_REFERENCES}; @@ -10,9 +9,8 @@ use crate::{ configuration::{CIPHERSUITE, GROUP_MEMBERSHIP_EXTENSION_ID, MUTABLE_METADATA_EXTENSION_ID}, storage::StorageError, xmtp_openmls_provider::XmtpOpenMlsProvider, - XmtpApi, + Fetch, Store, XmtpApi, }; -use crate::{retryable, Fetch, Store}; use openmls::prelude::hash_ref::HashReference; use openmls::{ credentials::{errors::BasicCredentialError, BasicCredential, CredentialWithKey}, @@ -30,6 +28,7 @@ use prost::Message; use thiserror::Error; use tracing::debug; use tracing::info; +use xmtp_common::{retryable, RetryableError}; use xmtp_cryptography::{CredentialSign, XmtpInstallationCredential}; use xmtp_id::associations::unverified::UnverifiedSignature; use xmtp_id::associations::{AssociationError, InstallationKeyContext, PublicContext}; @@ -423,11 +422,14 @@ impl Identity { conn.get_latest_sequence_id_for_inbox(self.inbox_id.as_str()) } - #[allow(dead_code)] pub fn is_ready(&self) -> bool { self.is_ready.load(Ordering::SeqCst) } + pub(crate) fn set_ready(&self) { + self.is_ready.store(true, Ordering::SeqCst) + } + pub fn signature_request(&self) -> Option { self.signature_request.clone() } @@ -524,8 +526,6 @@ impl Identity { } self.rotate_key_package(provider, api_client).await?; - self.is_ready.store(true, Ordering::SeqCst); - Ok(StoredIdentity::try_from(self)?.store(provider.conn_ref())?) } diff --git a/xmtp_mls/src/identity_updates.rs b/xmtp_mls/src/identity_updates.rs index e4a6cef10..822c00bac 100644 --- a/xmtp_mls/src/identity_updates.rs +++ b/xmtp_mls/src/identity_updates.rs @@ -1,11 +1,8 @@ -use crate::{ - retry::{Retry, RetryableError}, - retry_async, retryable, - storage::association_state::StoredAssociationState, -}; +use crate::storage::association_state::StoredAssociationState; use futures::future::try_join_all; use std::collections::{HashMap, HashSet}; use thiserror::Error; +use xmtp_common::{retry_async, retryable, Retry, RetryableError}; use xmtp_cryptography::CredentialSign; use xmtp_id::{ associations::{ @@ -593,9 +590,10 @@ pub(crate) mod tests { builder::ClientBuilder, groups::group_membership::GroupMembership, storage::{db_connection::DbConnection, identity_update::StoredIdentityUpdate}, - utils::test::{rand_vec, FullXmtpClient}, + utils::test::FullXmtpClient, Client, XmtpApi, }; + use xmtp_common::rand_vec; use super::{is_member_of_association_state, load_identity_updates}; @@ -620,7 +618,7 @@ pub(crate) mod tests { fn insert_identity_update(conn: &DbConnection, inbox_id: &str, sequence_id: i64) { let identity_update = - StoredIdentityUpdate::new(inbox_id.to_string(), sequence_id, 0, rand_vec()); + StoredIdentityUpdate::new(inbox_id.to_string(), sequence_id, 0, rand_vec::<24>()); conn.insert_or_ignore_identity_updates(&[identity_update]) .expect("insert should succeed"); @@ -730,8 +728,8 @@ pub(crate) mod tests { #[cfg_attr(not(target_arch = "wasm32"), test)] #[cfg(not(target_arch = "wasm32"))] fn cache_association_state() { - use crate::{assert_logged, utils::test::traced_test}; - traced_test(|| async { + use xmtp_common::assert_logged; + xmtp_common::traced_test!(async { let wallet = generate_local_wallet(); let wallet_2 = generate_local_wallet(); let wallet_address = wallet.get_address(); diff --git a/xmtp_mls/src/intents.rs b/xmtp_mls/src/intents.rs index 6664152cf..87adbc539 100644 --- a/xmtp_mls/src/intents.rs +++ b/xmtp_mls/src/intents.rs @@ -8,8 +8,8 @@ //! Intents are written to local storage (SQLite), before being published to the delivery service via gRPC. An //! intent is fully resolved (success or failure) once it -use crate::retry::RetryableError; use thiserror::Error; +use xmtp_common::RetryableError; #[derive(Debug, Error)] pub enum ProcessIntentError { diff --git a/xmtp_mls/src/lib.rs b/xmtp_mls/src/lib.rs index 71d2ede3f..d287fd676 100644 --- a/xmtp_mls/src/lib.rs +++ b/xmtp_mls/src/lib.rs @@ -11,7 +11,6 @@ pub mod identity; pub mod identity_updates; mod intents; mod mutex_registry; -pub mod retry; pub mod storage; mod stream_handles; pub mod subscriptions; @@ -27,15 +26,6 @@ pub use xmtp_openmls_provider::XmtpOpenMlsProvider; pub use xmtp_id::InboxOwner; pub use xmtp_proto::api_client::trait_impls::*; -#[macro_use] -extern crate tracing; - -/// Global Marker trait for WebAssembly -#[cfg(target_arch = "wasm32")] -pub trait Wasm {} -#[cfg(target_arch = "wasm32")] -impl Wasm for T {} - /// Inserts a model to the underlying data store, erroring if it already exists pub trait Store { fn store(&self, into: &StorageConnection) -> Result<(), StorageError>; @@ -78,138 +68,12 @@ pub use stream_handles::{ spawn, AbortHandle, GenericStreamHandle, StreamHandle, StreamHandleError, }; -#[cfg(target_arch = "wasm32")] -#[doc(hidden)] -pub async fn sleep(duration: core::time::Duration) { - gloo_timers::future::TimeoutFuture::new(duration.as_millis() as u32).await; -} - -#[cfg(not(target_arch = "wasm32"))] -#[doc(hidden)] -pub async fn sleep(duration: core::time::Duration) { - tokio::time::sleep(duration).await -} - -/// Turn the `Result` into an `Option`, logging the error with `tracing::error` and -/// returning `None` if the value matches on Result::Err(). -/// Optionally pass a message as the second argument. -#[macro_export] -macro_rules! optify { - ( $e: expr ) => { - match $e { - Ok(v) => Some(v), - Err(e) => { - tracing::error!("{}", e); - None - } - } - }; - ( $e: expr, $msg: tt ) => { - match $e { - Ok(v) => Some(v), - Err(e) => { - tracing::error!("{}: {:?}", $msg, e); - None - } - } - }; -} - #[cfg(test)] pub(crate) mod tests { // Execute once before any tests are run #[cfg_attr(not(target_arch = "wasm32"), ctor::ctor)] #[cfg(not(target_arch = "wasm32"))] fn _setup() { - use tracing_subscriber::{ - fmt::{self, format}, - layer::SubscriberExt, - util::SubscriberInitExt, - EnvFilter, Layer, - }; - - let structured = std::env::var("STRUCTURED"); - let is_structured = matches!(structured, Ok(s) if s == "true" || s == "1"); - - let filter = || { - EnvFilter::builder() - .with_default_directive(tracing::metadata::LevelFilter::INFO.into()) - .from_env_lossy() - }; - - tracing_subscriber::registry() - // structured JSON logger - .with(is_structured.then(|| { - tracing_subscriber::fmt::layer() - .json() - .flatten_event(true) - .with_level(true) - .with_filter(filter()) - })) - // default logger - .with((!is_structured).then(|| { - fmt::layer() - .compact() - .fmt_fields({ - format::debug_fn(move |writer, field, value| { - if field.name() == "message" { - write!(writer, "{:?}", value)?; - } - Ok(()) - }) - }) - .with_filter(filter()) - })) - .init(); - } - - /// wrapper over assert!(matches!()) for Errors - /// assert_err!(fun(), StorageError::Explosion) - /// - /// or the message variant, - /// assert_err!(fun(), StorageError::Explosion, "the storage did not explode"); - #[macro_export] - macro_rules! assert_err { - ( $x:expr , $y:pat $(,)? ) => { - assert!(matches!($x, Err($y))) - }; - - ( $x:expr, $y:pat $(,)?, $($msg:tt)+) => {{ - assert!(matches!($x, Err($y)), $($msg)+) - }} - } - - /// wrapper over assert! macros for Ok's - /// - /// Make sure something is Ok(_) without caring about return value. - /// assert_ok!(fun()); - /// - /// Against an expected value, e.g Ok(true) - /// assert_ok!(fun(), true); - /// - /// or the message variant, - /// assert_ok!(fun(), Ok(_), "the storage is not ok"); - #[macro_export] - macro_rules! assert_ok { - - ( $e:expr ) => { - assert_ok!($e,) - }; - - ( $e:expr, ) => {{ - use std::result::Result::*; - match $e { - Ok(v) => v, - Err(e) => panic!("assertion failed: Err({:?})", e), - } - }}; - - ( $x:expr , $y:expr $(,)? ) => { - assert_eq!($x, Ok($y.into())); - }; - - ( $x:expr, $y:expr $(,)?, $($msg:tt)+) => {{ - assert_eq!($x, Ok($y.into()), $($msg)+); - }} + xmtp_common::logger() } } diff --git a/xmtp_mls/src/storage/encrypted_store/group.rs b/xmtp_mls/src/storage/encrypted_store/group.rs index 63906099e..010eab713 100644 --- a/xmtp_mls/src/storage/encrypted_store/group.rs +++ b/xmtp_mls/src/storage/encrypted_store/group.rs @@ -388,7 +388,7 @@ impl DbConnection { /// Updates the 'last time checked' we checked for new installations. pub fn update_rotated_at_ns(&self, group_id: Vec) -> Result<(), StorageError> { self.raw_query(|conn| { - let now = crate::utils::time::now_ns(); + let now = xmtp_common::time::now_ns(); diesel::update(dsl::groups.find(&group_id)) .set(dsl::rotated_at_ns.eq(now)) .execute(conn) @@ -416,7 +416,7 @@ impl DbConnection { /// Updates the 'last time checked' we checked for new installations. pub fn update_installations_time_checked(&self, group_id: Vec) -> Result<(), StorageError> { self.raw_query(|conn| { - let now = crate::utils::time::now_ns(); + let now = xmtp_common::time::now_ns(); diesel::update(dsl::groups.find(&group_id)) .set(dsl::installations_last_checked.eq(now)) .execute(conn) @@ -548,18 +548,17 @@ pub(crate) mod tests { use super::*; use crate::{ - assert_ok, storage::{ consent_record::{ConsentType, StoredConsentRecord}, encrypted_store::{schema::groups::dsl::groups, tests::with_connection}, }, - utils::{test::rand_vec, time::now_ns}, Fetch, Store, }; + use xmtp_common::{assert_ok, rand_vec, time::now_ns}; /// Generate a test group pub fn generate_group(state: Option) -> StoredGroup { - let id = rand_vec(); + let id = rand_vec::<24>(); let created_at_ns = now_ns(); let membership_state = state.unwrap_or(GroupMembershipState::Allowed); StoredGroup::new( @@ -586,7 +585,7 @@ pub(crate) mod tests { /// Generate a test dm group pub fn generate_dm(state: Option) -> StoredGroup { - let id = rand_vec(); + let id = rand_vec::<24>(); let created_at_ns = now_ns(); let membership_state = state.unwrap_or(GroupMembershipState::Allowed); let dm_inbox_id = Some("placeholder_inbox_id".to_string()); @@ -774,7 +773,7 @@ pub(crate) mod tests { #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] async fn test_new_sync_group() { with_connection(|conn| { - let id = rand_vec(); + let id = rand_vec::<24>(); let created_at_ns = now_ns(); let membership_state = GroupMembershipState::Allowed; diff --git a/xmtp_mls/src/storage/encrypted_store/group_intent.rs b/xmtp_mls/src/storage/encrypted_store/group_intent.rs index a45a818c3..2cc872a3c 100644 --- a/xmtp_mls/src/storage/encrypted_store/group_intent.rs +++ b/xmtp_mls/src/storage/encrypted_store/group_intent.rs @@ -400,9 +400,9 @@ pub(crate) mod tests { group::{GroupMembershipState, StoredGroup}, tests::with_connection, }, - utils::test::rand_vec, Fetch, Store, }; + use xmtp_common::rand_vec; fn insert_group(conn: &DbConnection, group_id: Vec) { let group = StoredGroup::new( @@ -445,8 +445,8 @@ pub(crate) mod tests { #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] async fn test_store_and_fetch() { - let group_id = rand_vec(); - let data = rand_vec(); + let group_id = rand_vec::<24>(); + let data = rand_vec::<24>(); let kind = IntentKind::UpdateGroupMembership; let state = IntentState::ToPublish; @@ -479,25 +479,25 @@ pub(crate) mod tests { #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] async fn test_query() { - let group_id = rand_vec(); + let group_id = rand_vec::<24>(); let test_intents: Vec = vec![ NewGroupIntent::new_test( IntentKind::UpdateGroupMembership, group_id.clone(), - rand_vec(), + rand_vec::<24>(), IntentState::ToPublish, ), NewGroupIntent::new_test( IntentKind::KeyUpdate, group_id.clone(), - rand_vec(), + rand_vec::<24>(), IntentState::Published, ), NewGroupIntent::new_test( IntentKind::KeyUpdate, group_id.clone(), - rand_vec(), + rand_vec::<24>(), IntentState::Committed, ), ]; @@ -559,7 +559,7 @@ pub(crate) mod tests { #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] async fn find_by_payload_hash() { - let group_id = rand_vec(); + let group_id = rand_vec::<24>(); with_connection(|conn| { insert_group(conn, group_id.clone()); @@ -568,7 +568,7 @@ pub(crate) mod tests { NewGroupIntent::new( IntentKind::UpdateGroupMembership, group_id.clone(), - rand_vec(), + rand_vec::<24>(), ) .store(conn) .unwrap(); @@ -577,8 +577,8 @@ pub(crate) mod tests { let intent = find_first_intent(conn, group_id.clone()); // Set the payload hash - let payload_hash = rand_vec(); - let post_commit_data = rand_vec(); + let payload_hash = rand_vec::<24>(); + let post_commit_data = rand_vec::<24>(); conn.set_group_intent_published( intent.id, payload_hash.clone(), @@ -602,7 +602,7 @@ pub(crate) mod tests { #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] async fn test_happy_path_state_transitions() { - let group_id = rand_vec(); + let group_id = rand_vec::<24>(); with_connection(|conn| { insert_group(conn, group_id.clone()); @@ -611,7 +611,7 @@ pub(crate) mod tests { NewGroupIntent::new( IntentKind::UpdateGroupMembership, group_id.clone(), - rand_vec(), + rand_vec::<24>(), ) .store(conn) .unwrap(); @@ -619,8 +619,8 @@ pub(crate) mod tests { let mut intent = find_first_intent(conn, group_id.clone()); // Set to published - let payload_hash = rand_vec(); - let post_commit_data = rand_vec(); + let payload_hash = rand_vec::<24>(); + let post_commit_data = rand_vec::<24>(); conn.set_group_intent_published( intent.id, payload_hash.clone(), @@ -648,7 +648,7 @@ pub(crate) mod tests { #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] async fn test_republish_state_transition() { - let group_id = rand_vec(); + let group_id = rand_vec::<24>(); with_connection(|conn| { insert_group(conn, group_id.clone()); @@ -657,7 +657,7 @@ pub(crate) mod tests { NewGroupIntent::new( IntentKind::UpdateGroupMembership, group_id.clone(), - rand_vec(), + rand_vec::<24>(), ) .store(conn) .unwrap(); @@ -665,8 +665,8 @@ pub(crate) mod tests { let mut intent = find_first_intent(conn, group_id.clone()); // Set to published - let payload_hash = rand_vec(); - let post_commit_data = rand_vec(); + let payload_hash = rand_vec::<24>(); + let post_commit_data = rand_vec::<24>(); conn.set_group_intent_published( intent.id, payload_hash.clone(), @@ -693,7 +693,7 @@ pub(crate) mod tests { #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] async fn test_invalid_state_transition() { - let group_id = rand_vec(); + let group_id = rand_vec::<24>(); with_connection(|conn| { insert_group(conn, group_id.clone()); @@ -702,7 +702,7 @@ pub(crate) mod tests { NewGroupIntent::new( IntentKind::UpdateGroupMembership, group_id.clone(), - rand_vec(), + rand_vec::<24>(), ) .store(conn) .unwrap(); @@ -729,13 +729,13 @@ pub(crate) mod tests { #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] async fn test_increment_publish_attempts() { - let group_id = rand_vec(); + let group_id = rand_vec::<24>(); with_connection(|conn| { insert_group(conn, group_id.clone()); NewGroupIntent::new( IntentKind::UpdateGroupMembership, group_id.clone(), - rand_vec(), + rand_vec::<24>(), ) .store(conn) .unwrap(); diff --git a/xmtp_mls/src/storage/encrypted_store/group_message.rs b/xmtp_mls/src/storage/encrypted_store/group_message.rs index 7976a030c..743800d79 100644 --- a/xmtp_mls/src/storage/encrypted_store/group_message.rs +++ b/xmtp_mls/src/storage/encrypted_store/group_message.rs @@ -284,11 +284,11 @@ pub(crate) mod tests { use super::*; use crate::{ - assert_err, assert_ok, storage::encrypted_store::{group::tests::generate_group, tests::with_connection}, - utils::test::{rand_time, rand_vec}, Store, }; + use wasm_bindgen_test::wasm_bindgen_test; + use xmtp_common::{assert_err, assert_ok, rand_time, rand_vec}; fn generate_message( kind: Option, @@ -296,19 +296,18 @@ pub(crate) mod tests { sent_at_ns: Option, ) -> StoredGroupMessage { StoredGroupMessage { - id: rand_vec(), - group_id: group_id.map(<[u8]>::to_vec).unwrap_or(rand_vec()), - decrypted_message_bytes: rand_vec(), + id: rand_vec::<24>(), + group_id: group_id.map(<[u8]>::to_vec).unwrap_or(rand_vec::<24>()), + decrypted_message_bytes: rand_vec::<24>(), sent_at_ns: sent_at_ns.unwrap_or(rand_time()), - sender_installation_id: rand_vec(), + sender_installation_id: rand_vec::<24>(), sender_inbox_id: "0x0".to_string(), kind: kind.unwrap_or(GroupMessageKind::Application), delivery_status: DeliveryStatus::Unpublished, } } - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] - #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] + #[wasm_bindgen_test(unsupported = tokio::test)] async fn it_does_not_error_on_empty_messages() { with_connection(|conn| { let id = vec![0x0]; @@ -317,8 +316,7 @@ pub(crate) mod tests { .await } - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] - #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] + #[wasm_bindgen_test(unsupported = tokio::test)] async fn it_gets_messages() { with_connection(|conn| { let group = generate_group(None); @@ -334,8 +332,7 @@ pub(crate) mod tests { .await } - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] - #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] + #[wasm_bindgen_test(unsupported = tokio::test)] async fn it_cannot_insert_message_without_group() { use diesel::result::{DatabaseErrorKind::ForeignKeyViolation, Error::DatabaseError}; @@ -349,8 +346,7 @@ pub(crate) mod tests { .await } - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] - #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] + #[wasm_bindgen_test(unsupported = tokio::test)] async fn it_gets_many_messages() { use crate::storage::encrypted_store::schema::group_messages::dsl; @@ -385,8 +381,7 @@ pub(crate) mod tests { .await } - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] - #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] + #[wasm_bindgen_test(unsupported = tokio::test)] async fn it_gets_messages_by_time() { with_connection(|conn| { let group = generate_group(None); @@ -423,8 +418,7 @@ pub(crate) mod tests { .await } - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] - #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] + #[wasm_bindgen_test(unsupported = tokio::test)] async fn it_gets_messages_by_kind() { with_connection(|conn| { let group = generate_group(None); @@ -471,8 +465,7 @@ pub(crate) mod tests { .await } - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] - #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] + #[wasm_bindgen_test(unsupported = tokio::test)] async fn it_orders_messages_by_sent() { with_connection(|conn| { let group = generate_group(None); diff --git a/xmtp_mls/src/storage/encrypted_store/identity.rs b/xmtp_mls/src/storage/encrypted_store/identity.rs index 4051036c5..f6f973b8f 100644 --- a/xmtp_mls/src/storage/encrypted_store/identity.rs +++ b/xmtp_mls/src/storage/encrypted_store/identity.rs @@ -71,7 +71,8 @@ pub(crate) mod tests { super::{EncryptedMessageStore, StorageOption}, StoredIdentity, }; - use crate::{utils::test::rand_vec, Store}; + use crate::Store; + use xmtp_common::rand_vec; #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] @@ -84,12 +85,12 @@ pub(crate) mod tests { .unwrap(); let conn = &store.conn().unwrap(); - StoredIdentity::new("".to_string(), rand_vec(), rand_vec()) + StoredIdentity::new("".to_string(), rand_vec::<24>(), rand_vec::<24>()) .store(conn) .unwrap(); let duplicate_insertion = - StoredIdentity::new("".to_string(), rand_vec(), rand_vec()).store(conn); + StoredIdentity::new("".to_string(), rand_vec::<24>(), rand_vec::<24>()).store(conn); assert!(duplicate_insertion.is_err()); } } diff --git a/xmtp_mls/src/storage/encrypted_store/identity_update.rs b/xmtp_mls/src/storage/encrypted_store/identity_update.rs index 74eb878d3..1c5c6b564 100644 --- a/xmtp_mls/src/storage/encrypted_store/identity_update.rs +++ b/xmtp_mls/src/storage/encrypted_store/identity_update.rs @@ -134,16 +134,18 @@ pub(crate) mod tests { #[cfg(target_arch = "wasm32")] wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_dedicated_worker); - use crate::{ - storage::encrypted_store::tests::with_connection, - utils::test::{rand_time, rand_vec}, - Store, - }; + use crate::{storage::encrypted_store::tests::with_connection, Store}; + use xmtp_common::{rand_time, rand_vec}; use super::*; fn build_update(inbox_id: &str, sequence_id: i64) -> StoredIdentityUpdate { - StoredIdentityUpdate::new(inbox_id.to_string(), sequence_id, rand_time(), rand_vec()) + StoredIdentityUpdate::new( + inbox_id.to_string(), + sequence_id, + rand_time(), + rand_vec::<24>(), + ) } #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] diff --git a/xmtp_mls/src/storage/encrypted_store/key_package_history.rs b/xmtp_mls/src/storage/encrypted_store/key_package_history.rs index 7947abb0a..9e43243c0 100644 --- a/xmtp_mls/src/storage/encrypted_store/key_package_history.rs +++ b/xmtp_mls/src/storage/encrypted_store/key_package_history.rs @@ -1,7 +1,8 @@ use diesel::prelude::*; use super::{db_connection::DbConnection, schema::key_package_history, StorageError}; -use crate::{impl_store_or_ignore, utils::time::now_ns, StoreOrIgnore}; +use crate::{impl_store_or_ignore, StoreOrIgnore}; +use xmtp_common::time::now_ns; #[derive(Insertable, Debug, Clone)] #[diesel(table_name = key_package_history)] @@ -78,7 +79,8 @@ impl DbConnection { #[cfg(test)] mod tests { - use crate::{storage::encrypted_store::tests::with_connection, utils::test::rand_vec}; + use crate::storage::encrypted_store::tests::with_connection; + use xmtp_common::rand_vec; #[cfg(target_arch = "wasm32")] wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_dedicated_worker); @@ -86,7 +88,7 @@ mod tests { #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] async fn test_store_key_package_history_entry() { with_connection(|conn| { - let hash_ref = rand_vec(); + let hash_ref = rand_vec::<24>(); let new_entry = conn .store_key_package_history_entry(hash_ref.clone()) .unwrap(); @@ -100,9 +102,9 @@ mod tests { #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] async fn test_store_multiple() { with_connection(|conn| { - let hash_ref1 = rand_vec(); - let hash_ref2 = rand_vec(); - let hash_ref3 = rand_vec(); + let hash_ref1 = rand_vec::<24>(); + let hash_ref2 = rand_vec::<24>(); + let hash_ref3 = rand_vec::<24>(); conn.store_key_package_history_entry(hash_ref1.clone()) .unwrap(); diff --git a/xmtp_mls/src/storage/encrypted_store/mod.rs b/xmtp_mls/src/storage/encrypted_store/mod.rs index 9646a7611..c7172dd5b 100644 --- a/xmtp_mls/src/storage/encrypted_store/mod.rs +++ b/xmtp_mls/src/storage/encrypted_store/mod.rs @@ -472,6 +472,7 @@ where pub(crate) mod tests { #[cfg(target_arch = "wasm32")] wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_dedicated_worker); + use wasm_bindgen_test::wasm_bindgen_test; use super::*; use crate::{ @@ -479,9 +480,9 @@ pub(crate) mod tests { group::{GroupMembershipState, StoredGroup}, identity::StoredIdentity, }, - utils::test::{rand_vec, tmp_path}, Fetch, Store, StreamHandle as _, XmtpOpenMlsProvider, }; + use xmtp_common::{rand_vec, tmp_path}; /// Test harness that loads an Ephemeral store. pub async fn with_connection(fun: F) -> R @@ -510,8 +511,7 @@ pub(crate) mod tests { } } - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] - #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] + #[wasm_bindgen_test(unsupported = tokio::test)] async fn ephemeral_store() { let store = EncryptedMessageStore::new( StorageOption::Ephemeral, @@ -522,7 +522,7 @@ pub(crate) mod tests { let conn = &store.conn().unwrap(); let inbox_id = "inbox_id"; - StoredIdentity::new(inbox_id.to_string(), rand_vec(), rand_vec()) + StoredIdentity::new(inbox_id.to_string(), rand_vec::<24>(), rand_vec::<24>()) .store(conn) .unwrap(); @@ -530,8 +530,7 @@ pub(crate) mod tests { assert_eq!(fetched_identity.inbox_id, inbox_id); } - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] - #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] + #[wasm_bindgen_test(unsupported = tokio::test)] async fn persistent_store() { let db_path = tmp_path(); { @@ -544,7 +543,7 @@ pub(crate) mod tests { let conn = &store.conn().unwrap(); let inbox_id = "inbox_id"; - StoredIdentity::new(inbox_id.to_string(), rand_vec(), rand_vec()) + StoredIdentity::new(inbox_id.to_string(), rand_vec::<24>(), rand_vec::<24>()) .store(conn) .unwrap(); @@ -553,10 +552,8 @@ pub(crate) mod tests { } EncryptedMessageStore::remove_db_files(db_path) } - - // #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] - #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] #[cfg(not(target_arch = "wasm32"))] + #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] async fn releases_db_lock() { let db_path = tmp_path(); { @@ -569,7 +566,7 @@ pub(crate) mod tests { let conn = &store.conn().unwrap(); let inbox_id = "inbox_id"; - StoredIdentity::new(inbox_id.to_string(), rand_vec(), rand_vec()) + StoredIdentity::new(inbox_id.to_string(), rand_vec::<24>(), rand_vec::<24>()) .store(conn) .unwrap(); @@ -588,8 +585,7 @@ pub(crate) mod tests { EncryptedMessageStore::remove_db_files(db_path) } - #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] - #[cfg(not(target_arch = "wasm32"))] + #[tokio::test] async fn mismatched_encryption_key() { let mut enc_key = [1u8; 32]; @@ -601,9 +597,13 @@ pub(crate) mod tests { .await .unwrap(); - StoredIdentity::new("dummy_address".to_string(), rand_vec(), rand_vec()) - .store(&store.conn().unwrap()) - .unwrap(); + StoredIdentity::new( + "dummy_address".to_string(), + rand_vec::<24>(), + rand_vec::<24>(), + ) + .store(&store.conn().unwrap()) + .unwrap(); } // Drop it enc_key[3] = 145; // Alter the enc_key @@ -618,8 +618,7 @@ pub(crate) mod tests { EncryptedMessageStore::remove_db_files(db_path) } - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] - #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] + #[wasm_bindgen_test(unsupported = tokio::test)] async fn encrypted_db_with_multiple_connections() { let db_path = tmp_path(); { @@ -632,7 +631,7 @@ pub(crate) mod tests { let conn1 = &store.conn().unwrap(); let inbox_id = "inbox_id"; - StoredIdentity::new(inbox_id.to_string(), rand_vec(), rand_vec()) + StoredIdentity::new(inbox_id.to_string(), rand_vec::<24>(), rand_vec::<24>()) .store(conn1) .unwrap(); @@ -670,7 +669,7 @@ pub(crate) mod tests { let handle = std::thread::spawn(move || { store_pointer.transaction(&provider, |provider| { let conn1 = provider.conn_ref(); - StoredIdentity::new("correct".to_string(), rand_vec(), rand_vec()) + StoredIdentity::new("correct".to_string(), rand_vec::<24>(), rand_vec::<24>()) .store(conn1) .unwrap(); // wait for second transaction to start @@ -738,7 +737,7 @@ pub(crate) mod tests { store_pointer .transaction_async(&provider, |provider| async move { let conn1 = provider.conn_ref(); - StoredIdentity::new("crab".to_string(), rand_vec(), rand_vec()) + StoredIdentity::new("crab".to_string(), rand_vec::<24>(), rand_vec::<24>()) .store(conn1) .unwrap(); diff --git a/xmtp_mls/src/storage/encrypted_store/sqlcipher_connection.rs b/xmtp_mls/src/storage/encrypted_store/sqlcipher_connection.rs index 25dfb379f..fe9350b26 100644 --- a/xmtp_mls/src/storage/encrypted_store/sqlcipher_connection.rs +++ b/xmtp_mls/src/storage/encrypted_store/sqlcipher_connection.rs @@ -304,9 +304,10 @@ fn pragma_plaintext_header() -> impl Display { #[cfg(test)] mod tests { - use crate::{storage::EncryptedMessageStore, utils::test::tmp_path}; + use crate::storage::EncryptedMessageStore; use diesel_migrations::MigrationHarness; use std::fs::File; + use xmtp_common::tmp_path; use super::*; const SQLITE3_PLAINTEXT_HEADER: &str = "SQLite format 3\0"; diff --git a/xmtp_mls/src/storage/encrypted_store/wasm.rs b/xmtp_mls/src/storage/encrypted_store/wasm.rs index 2d551c8a9..7cbc05fc0 100644 --- a/xmtp_mls/src/storage/encrypted_store/wasm.rs +++ b/xmtp_mls/src/storage/encrypted_store/wasm.rs @@ -50,13 +50,11 @@ impl XmtpDb for WasmDb { Ok(()) } - #[allow(unreachable_code)] fn release_connection(&self) -> Result<(), StorageError> { - unimplemented!(); + Ok(()) } - #[allow(unreachable_code)] fn reconnect(&self) -> Result<(), StorageError> { - unimplemented!(); + Ok(()) } } diff --git a/xmtp_mls/src/storage/errors.rs b/xmtp_mls/src/storage/errors.rs index f109b0248..de25850ab 100644 --- a/xmtp_mls/src/storage/errors.rs +++ b/xmtp_mls/src/storage/errors.rs @@ -3,9 +3,11 @@ use std::sync::PoisonError; use diesel::result::DatabaseErrorKind; use thiserror::Error; -use crate::{groups::intents::IntentError, retry::RetryableError, retryable}; - use super::sql_key_store; +use crate::groups::intents::IntentError; +use xmtp_common::{retryable, RetryableError}; + +pub struct Mls; #[derive(Debug, Error)] pub enum StorageError { @@ -66,7 +68,7 @@ impl From> for StorageError { } } -impl RetryableError for diesel::result::Error { +impl RetryableError for diesel::result::Error { fn is_retryable(&self) -> bool { use diesel::result::Error::*; use DatabaseErrorKind::*; @@ -101,7 +103,7 @@ impl RetryableError for StorageError { } // OpenMLS KeyStore errors -impl RetryableError for openmls::group::AddMembersError { +impl RetryableError for openmls::group::AddMembersError { fn is_retryable(&self) -> bool { match self { Self::CreateCommitError(commit) => retryable!(commit), @@ -112,7 +114,7 @@ impl RetryableError for openmls::group::AddMembersError { +impl RetryableError for openmls::group::CreateCommitError { fn is_retryable(&self) -> bool { match self { Self::KeyStoreError(storage) => retryable!(storage), @@ -122,7 +124,9 @@ impl RetryableError for openmls::group::CreateCommitError { +impl RetryableError + for openmls::treesync::LeafNodeUpdateError +{ fn is_retryable(&self) -> bool { match self { Self::Storage(storage) => retryable!(storage), @@ -131,13 +135,13 @@ impl RetryableError for openmls::treesync::LeafNodeUpdateError for openmls::key_packages::errors::KeyPackageNewError { fn is_retryable(&self) -> bool { matches!(self, Self::StorageError) } } -impl RetryableError for openmls::group::RemoveMembersError { +impl RetryableError for openmls::group::RemoveMembersError { fn is_retryable(&self) -> bool { match self { Self::CreateCommitError(commit) => retryable!(commit), @@ -148,7 +152,7 @@ impl RetryableError for openmls::group::RemoveMembersError { +impl RetryableError for openmls::group::NewGroupError { fn is_retryable(&self) -> bool { match self { Self::StorageError(storage) => retryable!(storage), @@ -157,7 +161,7 @@ impl RetryableError for openmls::group::NewGroupError for openmls::group::UpdateGroupMembershipError { fn is_retryable(&self) -> bool { @@ -170,13 +174,13 @@ impl RetryableError } } -impl RetryableError for openmls::prelude::MlsGroupStateError { +impl RetryableError for openmls::prelude::MlsGroupStateError { fn is_retryable(&self) -> bool { false } } -impl RetryableError +impl RetryableError for openmls::prelude::CreateGroupContextExtProposalError { fn is_retryable(&self) -> bool { @@ -188,7 +192,7 @@ impl RetryableError } } -impl RetryableError for openmls::group::SelfUpdateError { +impl RetryableError for openmls::group::SelfUpdateError { fn is_retryable(&self) -> bool { match self { Self::CreateCommitError(commit) => retryable!(commit), @@ -199,7 +203,7 @@ impl RetryableError for openmls::group::SelfUpdateError for openmls::prelude::CreationFromExternalError { fn is_retryable(&self) -> bool { @@ -210,7 +214,7 @@ impl RetryableError } } -impl RetryableError for openmls::prelude::WelcomeError { +impl RetryableError for openmls::prelude::WelcomeError { fn is_retryable(&self) -> bool { match self { Self::PublicGroupError(creation_err) => retryable!(creation_err), @@ -220,7 +224,7 @@ impl RetryableError for openmls::prelude::WelcomeError { +impl RetryableError for openmls::group::MergeCommitError { fn is_retryable(&self) -> bool { match self { Self::StorageError(storage) => retryable!(storage), @@ -229,7 +233,9 @@ impl RetryableError for openmls::group::MergeCommitError { +impl RetryableError + for openmls::group::MergePendingCommitError +{ fn is_retryable(&self) -> bool { match self { Self::MlsGroupStateError(err) => retryable!(err), @@ -238,7 +244,7 @@ impl RetryableError for openmls::group::MergePendingCommitError for openmls::prelude::ProcessMessageError { fn is_retryable(&self) -> bool { match self { Self::GroupStateError(err) => retryable!(err), diff --git a/xmtp_mls/src/storage/mod.rs b/xmtp_mls/src/storage/mod.rs index c1ecc7ed6..d3c525897 100644 --- a/xmtp_mls/src/storage/mod.rs +++ b/xmtp_mls/src/storage/mod.rs @@ -13,3 +13,95 @@ pub async fn init_sqlite() { } #[cfg(not(target_arch = "wasm32"))] pub async fn init_sqlite() {} + +#[cfg(any(test, feature = "test-utils"))] +pub mod test_util { + #![allow(clippy::unwrap_used)] + use super::*; + use diesel::{connection::LoadConnection, deserialize::FromSqlRow, sql_query, RunQueryDsl}; + impl DbConnection { + /// Create a new table and register triggers for tracking column updates + pub fn register_triggers(&self) { + tracing::info!("Registering triggers"); + let queries = vec![ + r#" + CREATE TABLE test_metadata ( + intents_created INT DEFAULT 0, + intents_published INT DEFAULT 0, + intents_deleted INT DEFAULT 0, + rowid integer PRIMARY KEY CHECK (rowid = 1) -- There can only be one meta + ); + "#, + r#"CREATE TRIGGER intents_created_tracking AFTER INSERT on group_intents + BEGIN + UPDATE test_metadata SET intents_created = intents_created + 1; + END;"#, + r#"CREATE TRIGGER intents_published_tracking AFTER UPDATE OF state ON group_intents + FOR EACH ROW + WHEN NEW.state = 2 AND OLD.state !=2 + BEGIN + UPDATE test_metadata SET intents_published = intents_published + 1; + END;"#, + r#"CREATE TRIGGER intents_deleted_tracking AFTER DELETE ON group_intents + FOR EACH ROW + BEGIN + UPDATE test_metadata SET intents_deleted = intents_deleted + 1; + END;"#, + r#"INSERT INTO test_metadata ( + intents_created, + intents_deleted, + intents_published + ) VALUES (0, 0,0);"#, + ]; + + for query in queries { + let query = diesel::sql_query(query); + let _ = self.raw_query(|conn| query.execute(conn)).unwrap(); + } + } + + pub fn intents_published(&self) -> i32 { + self.raw_query(|conn| { + let mut row = conn + .load(sql_query( + "SELECT intents_published FROM test_metadata WHERE rowid = 1", + )) + .unwrap(); + let row = row.next().unwrap().unwrap(); + Ok::<_, StorageError>( + >::build_from_row(&row) + .unwrap(), + ) + }) + .unwrap() + } + + pub fn intents_deleted(&self) -> i32 { + self.raw_query(|conn| { + let mut row = conn + .load(sql_query("SELECT intents_deleted FROM test_metadata")) + .unwrap(); + let row = row.next().unwrap().unwrap(); + Ok::<_, StorageError>( + >::build_from_row(&row) + .unwrap(), + ) + }) + .unwrap() + } + + pub fn intents_created(&self) -> i32 { + self.raw_query(|conn| { + let mut row = conn + .load(sql_query("SELECT intents_created FROM test_metadata")) + .unwrap(); + let row = row.next().unwrap().unwrap(); + Ok::<_, StorageError>( + >::build_from_row(&row) + .unwrap(), + ) + }) + .unwrap() + } + } +} diff --git a/xmtp_mls/src/storage/sql_key_store.rs b/xmtp_mls/src/storage/sql_key_store.rs index ae9d2d797..1ad7aa674 100644 --- a/xmtp_mls/src/storage/sql_key_store.rs +++ b/xmtp_mls/src/storage/sql_key_store.rs @@ -1,4 +1,4 @@ -use crate::{retry::RetryableError, retryable}; +use xmtp_common::{retryable, RetryableError}; use super::encrypted_store::db_connection::DbConnectionPrivate; use bincode; @@ -1041,9 +1041,9 @@ pub(crate) mod tests { use crate::{ configuration::CIPHERSUITE, storage::{sql_key_store::SqlKeyStoreError, EncryptedMessageStore, StorageOption}, - utils::test::tmp_path, xmtp_openmls_provider::XmtpOpenMlsProvider, }; + use xmtp_common::tmp_path; #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] diff --git a/xmtp_mls/src/stream_handles.rs b/xmtp_mls/src/stream_handles.rs index 869b3dbc7..a42af78e0 100644 --- a/xmtp_mls/src/stream_handles.rs +++ b/xmtp_mls/src/stream_handles.rs @@ -1,6 +1,6 @@ //! Consistent Stream behavior between WebAssembly and Native utilizing `tokio::task::spawn` in native and //! `wasm_bindgen_futures::spawn` for web. -use futures::{Future, FutureExt}; +use futures::FutureExt; #[cfg(target_arch = "wasm32")] pub type GenericStreamHandle = dyn StreamHandle; @@ -72,6 +72,12 @@ pub use wasm::*; #[cfg(target_arch = "wasm32")] mod wasm { + use std::{ + future::Future, + pin::Pin, + task::{Context, Poll}, + }; + use futures::future::Either; use super::*; @@ -150,32 +156,62 @@ mod wasm { F::Output: 'static, { let (res_tx, res_rx) = tokio::sync::oneshot::channel(); - let (closer_tx, mut closer_rx) = tokio::sync::mpsc::channel::<()>(1); + let (closer_tx, closer_rx) = tokio::sync::mpsc::channel::<()>(1); + let closer_handle = CloserHandle::new(closer_rx); let handle = WasmStreamHandle { result: res_rx, closer: closer_tx, ready, }; - + tracing::info!("Spawning local task on web executor"); wasm_bindgen_futures::spawn_local(async move { - let recv = closer_rx.recv(); - futures::pin_mut!(recv); + futures::pin_mut!(closer_handle); futures::pin_mut!(future); - let value = match futures::future::select(recv, future).await { - Either::Left((_, _)) => Err(StreamHandleError::StreamClosed), - Either::Right((v, _)) => Ok(v), + let value = match futures::future::select(closer_handle, future).await { + Either::Left((_, _)) => { + tracing::warn!("stream closed"); + Err(StreamHandleError::StreamClosed) + } + Either::Right((v, _)) => { + tracing::debug!("Future ended with value"); + Ok(v) + } }; let _ = res_tx.send(value); + tracing::info!("spawned local future closing"); }); handle } + + struct CloserHandle(tokio::sync::mpsc::Receiver<()>); + + impl CloserHandle { + fn new(receiver: tokio::sync::mpsc::Receiver<()>) -> Self { + Self(receiver) + } + } + + impl Future for CloserHandle { + type Output = (); + + fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + match self.0.poll_recv(cx) { + Poll::Pending => Poll::Pending, + Poll::Ready(Some(_)) => Poll::Ready(()), + // if the channel is closed, the task has detached and must + // be kept alive for the duration for the program + Poll::Ready(None) => Poll::Pending, + } + } + } } #[cfg(not(target_arch = "wasm32"))] mod native { use super::*; + use std::future::Future; use tokio::task::JoinHandle; pub struct TokioStreamHandle { diff --git a/xmtp_mls/src/subscriptions.rs b/xmtp_mls/src/subscriptions.rs index 94b93c537..d285050c2 100644 --- a/xmtp_mls/src/subscriptions.rs +++ b/xmtp_mls/src/subscriptions.rs @@ -17,8 +17,6 @@ use crate::{ mls_sync::GroupMessageProcessingError, scoped_client::ScopedGroupClient as _, subscriptions, GroupError, MlsGroup, }, - retry::{Retry, RetryableError}, - retry_async, retryable, storage::{ consent_record::StoredConsentRecord, group::{ConversationType, GroupQueryArgs, StoredGroup}, @@ -28,6 +26,7 @@ use crate::{ Client, XmtpApi, XmtpOpenMlsProvider, }; use thiserror::Error; +use xmtp_common::{retry_async, retryable, Retry, RetryableError}; #[derive(Debug, Error)] pub enum LocalEventError { @@ -130,7 +129,7 @@ where #[instrument(level = "trace", skip_all)] fn stream_sync_messages(self) -> impl Stream, SubscribeError>> { BroadcastStream::new(self).filter_map(|event| async { - crate::optify!(event, "Missed message due to event queue lag") + xmtp_common::optify!(event, "Missed message due to event queue lag") .and_then(LocalEvents::sync_filter) .map(Result::Ok) }) @@ -140,7 +139,7 @@ where self, ) -> impl Stream, SubscribeError>> { BroadcastStream::new(self).filter_map(|event| async { - crate::optify!(event, "Missed message due to event queue lag") + xmtp_common::optify!(event, "Missed message due to event queue lag") .and_then(LocalEvents::consent_filter) .map(Result::Ok) }) @@ -309,7 +308,7 @@ where let event_queue = tokio_stream::wrappers::BroadcastStream::new(self.local_events.subscribe()) .filter_map(|event| async { - crate::optify!(event, "Missed messages due to event queue lag") + xmtp_common::optify!(event, "Missed messages due to event queue lag") .and_then(LocalEvents::group_filter) .map(Result::Ok) }) @@ -545,11 +544,11 @@ pub(crate) mod tests { atomic::{AtomicU64, Ordering}, Arc, }; + use wasm_bindgen_test::wasm_bindgen_test; use xmtp_cryptography::utils::generate_local_wallet; use xmtp_id::InboxOwner; - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] - #[cfg_attr(not(target_arch = "wasm32"), tokio::test(flavor = "current_thread"))] + #[wasm_bindgen_test(unsupported = tokio::test(flavor = "multi_thread", worker_threads = 10))] async fn test_stream_welcomes() { let alice = Arc::new(ClientBuilder::new_test_client(&generate_local_wallet()).await); let bob = Arc::new(ClientBuilder::new_test_client(&generate_local_wallet()).await); @@ -584,12 +583,9 @@ pub(crate) mod tests { assert_eq!(bob_received_groups.group_id, group_id); } - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] - #[cfg_attr( - not(target_arch = "wasm32"), - tokio::test(flavor = "multi_thread", worker_threads = 10) - )] + #[wasm_bindgen_test(unsupported = tokio::test(flavor = "multi_thread", worker_threads = 10))] async fn test_stream_messages() { + xmtp_common::logger(); let alice = Arc::new(ClientBuilder::new_test_client(&generate_local_wallet()).await); let bob = ClientBuilder::new_test_client(&generate_local_wallet()).await; @@ -597,7 +593,6 @@ pub(crate) mod tests { .create_group(None, GroupMetadataOptions::default()) .unwrap(); - // let mut bob_stream = bob.stream_conversations().await.unwrap()warning: unused implementer of `futures::Future` that must be used; alice_group .add_members_by_inbox_id(&[bob.inbox_id()]) .await @@ -619,26 +614,25 @@ pub(crate) mod tests { notify_ptr.notify_one(); } }); - let mut stream = tokio_stream::wrappers::UnboundedReceiverStream::new(rx); + let stream = tokio_stream::wrappers::UnboundedReceiverStream::new(rx); + // let stream = alice_group.stream().await.unwrap(); + futures::pin_mut!(stream); bob_group.send_message(b"hello").await.unwrap(); - notify.wait_for_delivery().await.unwrap(); + tracing::debug!("Bob Sent Message!, waiting for delivery"); + // notify.wait_for_delivery().await.unwrap(); let message = stream.next().await.unwrap().unwrap(); assert_eq!(message.decrypted_message_bytes, b"hello"); bob_group.send_message(b"hello2").await.unwrap(); - notify.wait_for_delivery().await.unwrap(); + // notify.wait_for_delivery().await.unwrap(); let message = stream.next().await.unwrap().unwrap(); assert_eq!(message.decrypted_message_bytes, b"hello2"); // assert_eq!(bob_received_groups.group_id, alice_bob_group.group_id); } - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] - #[cfg_attr( - not(target_arch = "wasm32"), - tokio::test(flavor = "multi_thread", worker_threads = 10) - )] + #[wasm_bindgen_test(unsupported = tokio::test(flavor = "multi_thread", worker_threads = 10))] async fn test_stream_all_messages_unchanging_group_list() { let alix = ClientBuilder::new_test_client(&generate_local_wallet()).await; let bo = ClientBuilder::new_test_client(&generate_local_wallet()).await; @@ -659,7 +653,7 @@ pub(crate) mod tests { .add_members_by_inbox_id(&[caro.inbox_id()]) .await .unwrap(); - crate::sleep(core::time::Duration::from_millis(100)).await; + xmtp_common::time::sleep(core::time::Duration::from_millis(100)).await; let messages: Arc>> = Arc::new(Mutex::new(Vec::new())); let messages_clone = messages.clone(); @@ -695,11 +689,7 @@ pub(crate) mod tests { assert_eq!(messages[3].decrypted_message_bytes, b"fourth"); } - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] - #[cfg_attr( - not(target_arch = "wasm32"), - tokio::test(flavor = "multi_thread", worker_threads = 10) - )] + #[wasm_bindgen_test(unsupported = tokio::test(flavor = "multi_thread", worker_threads = 10))] async fn test_stream_all_messages_changing_group_list() { let alix = Arc::new(ClientBuilder::new_test_client(&generate_local_wallet()).await); let bo = ClientBuilder::new_test_client(&generate_local_wallet()).await; @@ -782,7 +772,7 @@ pub(crate) mod tests { .send_message("should not show up".as_bytes()) .await .unwrap(); - crate::sleep(core::time::Duration::from_millis(100)).await; + xmtp_common::time::sleep(core::time::Duration::from_millis(100)).await; let messages = messages.lock(); @@ -790,11 +780,7 @@ pub(crate) mod tests { } #[ignore] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] - #[cfg_attr( - not(target_arch = "wasm32"), - tokio::test(flavor = "multi_thread", worker_threads = 10) - )] + #[wasm_bindgen_test(unsupported = tokio::test(flavor = "multi_thread"))] async fn test_stream_all_messages_does_not_lose_messages() { let alix = Arc::new(ClientBuilder::new_test_client(&generate_local_wallet()).await); let caro = Arc::new(ClientBuilder::new_test_client(&generate_local_wallet()).await); @@ -827,7 +813,7 @@ pub(crate) mod tests { crate::spawn(None, async move { for _ in 0..50 { alix_group_pointer.send_message(b"spam").await.unwrap(); - crate::sleep(core::time::Duration::from_micros(200)).await; + xmtp_common::time::sleep(core::time::Duration::from_micros(200)).await; } }); @@ -859,8 +845,7 @@ pub(crate) mod tests { } } - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] - #[cfg_attr(not(target_arch = "wasm32"), tokio::test(flavor = "multi_thread"))] + #[wasm_bindgen_test(unsupported = tokio::test(flavor = "multi_thread"))] async fn test_self_group_creation() { let alix = Arc::new(ClientBuilder::new_test_client(&generate_local_wallet()).await); let bo = Arc::new(ClientBuilder::new_test_client(&generate_local_wallet()).await); @@ -921,8 +906,7 @@ pub(crate) mod tests { closer.end(); } - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] - #[cfg_attr(not(target_arch = "wasm32"), tokio::test(flavor = "multi_thread"))] + #[wasm_bindgen_test(unsupported = tokio::test(flavor = "multi_thread"))] async fn test_dm_streaming() { let alix = Arc::new(ClientBuilder::new_test_client(&generate_local_wallet()).await); let bo = Arc::new(ClientBuilder::new_test_client(&generate_local_wallet()).await); @@ -1055,8 +1039,7 @@ pub(crate) mod tests { closer.end(); } - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] - #[cfg_attr(not(target_arch = "wasm32"), tokio::test(flavor = "multi_thread"))] + #[wasm_bindgen_test(unsupported = tokio::test(flavor = "multi_thread"))] async fn test_dm_stream_all_messages() { let alix = Arc::new(ClientBuilder::new_test_client(&generate_local_wallet()).await); let bo = Arc::new(ClientBuilder::new_test_client(&generate_local_wallet()).await); diff --git a/xmtp_mls/src/utils/mod.rs b/xmtp_mls/src/utils/mod.rs index a81bba777..357410b65 100644 --- a/xmtp_mls/src/utils/mod.rs +++ b/xmtp_mls/src/utils/mod.rs @@ -8,30 +8,11 @@ pub mod hash { } pub mod time { - use std::time::Duration; - - use wasm_timer::{SystemTime, UNIX_EPOCH}; - - pub const NS_IN_SEC: i64 = 1_000_000_000; const SECS_IN_30_DAYS: i64 = 60 * 60 * 24 * 30; - fn duration_since_epoch() -> Duration { - SystemTime::now() - .duration_since(UNIX_EPOCH) - .expect("Time went backwards") - } - - pub fn now_ns() -> i64 { - duration_since_epoch().as_nanos() as i64 - } - - pub fn now_secs() -> i64 { - duration_since_epoch().as_secs() as i64 - } - /// Current hmac epoch. HMAC keys change every 30 days pub fn hmac_epoch() -> i64 { - now_secs() / SECS_IN_30_DAYS + xmtp_common::time::now_secs() / SECS_IN_30_DAYS } } @@ -56,34 +37,3 @@ pub mod id { hex::encode(group_id) } } - -#[cfg(any( - all(target_arch = "wasm32", feature = "test-utils"), - all(test, target_arch = "wasm32") -))] -pub mod wasm { - use tokio::sync::OnceCell; - static INIT: OnceCell<()> = OnceCell::const_new(); - - /// can be used to debug wasm tests - /// normal tracing logs are output to the browser console - pub async fn init() { - use web_sys::console; - - INIT.get_or_init(|| async { - console::log_1(&"INIT".into()); - let config = tracing_wasm::WASMLayerConfigBuilder::default() - .set_console_config(tracing_wasm::ConsoleConfig::ReportWithoutConsoleColor) - .build(); - tracing_wasm::set_as_global_default_with_config(config); - console_error_panic_hook::set_once(); - diesel_wasm_sqlite::init_sqlite().await; - }) - .await; - } -} - -#[cfg(not(target_arch = "wasm32"))] -pub mod wasm { - pub async fn init() {} -} diff --git a/xmtp_mls/src/utils/test/mod.rs b/xmtp_mls/src/utils/test/mod.rs index 7067f0537..ff44452b2 100755 --- a/xmtp_mls/src/utils/test/mod.rs +++ b/xmtp_mls/src/utils/test/mod.rs @@ -1,19 +1,7 @@ #![allow(clippy::unwrap_used)] -use crate::storage::DbConnection; -use crate::{ - builder::ClientBuilder, - identity::IdentityStrategy, - storage::{EncryptedMessageStore, StorageOption}, - types::Address, - Client, InboxOwner, XmtpApi, -}; -use rand::{ - distributions::{Alphanumeric, DistString}, - Rng, RngCore, -}; use std::sync::Arc; -use tokio::{sync::Notify, time::error::Elapsed}; +use tokio::sync::Notify; use xmtp_id::{ associations::{ generate_inbox_id, @@ -24,10 +12,12 @@ use xmtp_id::{ }; use xmtp_proto::api_client::XmtpTestClient; -#[cfg(not(target_arch = "wasm32"))] -pub mod traced_test; -#[cfg(not(target_arch = "wasm32"))] -pub use traced_test::traced_test; +use crate::{ + builder::ClientBuilder, + identity::IdentityStrategy, + storage::{DbConnection, EncryptedMessageStore, StorageOption}, + Client, InboxOwner, XmtpApi, +}; pub type FullXmtpClient = Client; @@ -45,40 +35,9 @@ use xmtp_api_http::XmtpHttpApiClient; #[cfg(any(feature = "http-api", target_arch = "wasm32"))] pub type TestClient = XmtpHttpApiClient; -pub fn rand_string() -> String { - Alphanumeric.sample_string(&mut rand::thread_rng(), 24) -} - -pub fn rand_account_address() -> Address { - Alphanumeric.sample_string(&mut rand::thread_rng(), 42) -} - -pub fn rand_vec() -> Vec { - rand::thread_rng().gen::<[u8; 24]>().to_vec() -} - -#[cfg(not(target_arch = "wasm32"))] -pub fn tmp_path() -> String { - let db_name = rand_string(); - format!("{}/{}.db3", std::env::temp_dir().to_str().unwrap(), db_name) -} - -#[cfg(target_arch = "wasm32")] -pub fn tmp_path() -> String { - let db_name = rand_string(); - format!("{}/{}.db3", "test_db", db_name) -} - -pub fn rand_time() -> i64 { - let mut rng = rand::thread_rng(); - rng.gen_range(0..1_000_000_000) -} - impl EncryptedMessageStore { pub fn generate_enc_key() -> [u8; 32] { - let mut key = [0u8; 32]; - xmtp_cryptography::utils::rng().fill_bytes(&mut key[..]); - key + xmtp_common::rand_array::<32>() } #[cfg(not(target_arch = "wasm32"))] @@ -97,8 +56,7 @@ impl EncryptedMessageStore { impl ClientBuilder { pub async fn temp_store(self) -> Self { - let tmpdb = tmp_path(); - tracing::info!("Opening Database at [{}]", tmpdb); + let tmpdb = xmtp_common::tmp_path(); self.store( EncryptedMessageStore::new( StorageOption::Persistent(tmpdb), @@ -197,7 +155,8 @@ where .build() .await .unwrap(); - + let conn = client.store().conn().unwrap(); + conn.register_triggers(); register_client(&client, owner).await; client @@ -232,7 +191,8 @@ where } let client = builder.build_with_verifier().await.unwrap(); - + let conn = client.store().conn().unwrap(); + conn.register_triggers(); register_client(&client, owner).await; client @@ -254,8 +214,8 @@ impl Delivery { } } - pub async fn wait_for_delivery(&self) -> Result<(), Elapsed> { - tokio::time::timeout(self.timeout, async { self.notify.notified().await }).await + pub async fn wait_for_delivery(&self) -> Result<(), xmtp_common::time::Expired> { + xmtp_common::time::timeout(self.timeout, async { self.notify.notified().await }).await } pub fn notify_one(&self) { @@ -295,50 +255,12 @@ pub async fn register_client( client.register_identity(signature_request).await.unwrap(); } -/// waits for all intents to finish -/// TODO: Should wrap with a timeout -pub async fn wait_for_all_intents_published(conn: &DbConnection) { - use crate::storage::group_intent::IntentState; - use crate::storage::group_intent::StoredGroupIntent; - use crate::storage::schema::group_intents::dsl; - use diesel::{ExpressionMethods, QueryDsl, RunQueryDsl}; - - let mut query = dsl::group_intents.into_boxed(); - let states = vec![IntentState::ToPublish]; - query = query.filter(dsl::state.eq_any(states)); - query = query.order(dsl::id.asc()); - - let intents = conn - .raw_query(|conn| query.load::(conn)) - .unwrap(); - - tracing::info!("{} intents left", intents.len()); - if intents.is_empty() { - tokio::time::sleep(std::time::Duration::from_secs(1)).await; - Box::pin(wait_for_all_intents_published(conn)).await - } -} - -/// wait for a minimum amount of intent +/// wait for a minimum amount of intents to be published /// TODO: Should wrap with a timeout pub async fn wait_for_min_intents(conn: &DbConnection, n: usize) { - use crate::storage::group_intent::IntentState; - use crate::storage::group_intent::StoredGroupIntent; - use crate::storage::schema::group_intents::dsl; - use diesel::{ExpressionMethods, QueryDsl, RunQueryDsl}; - - let mut query = dsl::group_intents.into_boxed(); - let states = vec![IntentState::Published]; - query = query.filter(dsl::state.eq_any(states)); - query = query.order(dsl::id.asc()); - - let intents = conn - .raw_query(|conn| query.load::(conn)) - .unwrap(); - - tracing::info!("{} intents left", intents.len()); - if intents.len() < n { - tokio::time::sleep(std::time::Duration::from_millis(200)).await; - Box::pin(wait_for_min_intents(conn, n - intents.len())).await + let mut published = conn.intents_published() as usize; + while published < n { + xmtp_common::yield_().await; + published = conn.intents_published() as usize; } } diff --git a/xmtp_proto/Cargo.toml b/xmtp_proto/Cargo.toml index d4bb67c97..9e5ddf30f 100644 --- a/xmtp_proto/Cargo.toml +++ b/xmtp_proto/Cargo.toml @@ -6,7 +6,6 @@ license.workspace = true [dependencies] futures = { workspace = true } -openmls = { workspace = true, optional = true } pbjson-types.workspace = true pbjson.workspace = true prost = { workspace = true, features = ["prost-derive"] } @@ -15,17 +14,22 @@ async-trait = "0.1" hex.workspace = true openmls_rust_crypto = { workspace = true, optional = true } tracing.workspace = true +xmtp_common.workspace = true [target.'cfg(not(target_arch = "wasm32"))'.dependencies] -tonic = { workspace = true } +tonic = { workspace = true, features = ["codegen", "server", "channel", "prost"] } +openmls = { workspace = true } + +[target.'cfg(target_arch = "wasm32")'.dependencies] +openmls = { workspace = true, features = ["js"] } [target.'cfg(target_arch = "wasm32")'.dev-dependencies] wasm-bindgen-test.workspace = true [features] -convert = ["openmls", "openmls_rust_crypto", "proto_full"] +convert = ["openmls_rust_crypto", "proto_full"] default = [] -test-utils = [] +test-utils = ["xmtp_common/test-utils"] # @@protoc_deletion_point(features) # This section is automatically generated by protoc-gen-prost-crate. diff --git a/xmtp_proto/src/api_client.rs b/xmtp_proto/src/api_client.rs index 03afb8df3..75cd72fbb 100644 --- a/xmtp_proto/src/api_client.rs +++ b/xmtp_proto/src/api_client.rs @@ -128,12 +128,6 @@ where } } -/// Global Marker trait for WebAssembly -#[cfg(target_arch = "wasm32")] -pub trait Wasm {} -#[cfg(target_arch = "wasm32")] -impl Wasm for T {} - // Wasm futures don't have `Send` or `Sync` bounds. #[cfg_attr(not(target_arch = "wasm32"), async_trait::async_trait)] #[cfg_attr(target_arch = "wasm32", async_trait::async_trait(?Send))] diff --git a/xmtp_proto/src/error.rs b/xmtp_proto/src/error.rs index d8109b9b8..8a574c785 100644 --- a/xmtp_proto/src/error.rs +++ b/xmtp_proto/src/error.rs @@ -35,6 +35,13 @@ pub struct Error { source: Option, } +// network errors should generally be retryable, unless there's a bug in our code +impl xmtp_common::RetryableError for Error { + fn is_retryable(&self) -> bool { + true + } +} + impl Error { pub fn new(kind: ErrorKind) -> Self { Self { kind, source: None } From bd03cd775865fde7f80194442ad08cb5f541d1f0 Mon Sep 17 00:00:00 2001 From: Dakota Brink <779390+codabrink@users.noreply.github.com> Date: Thu, 12 Dec 2024 23:30:23 -0500 Subject: [PATCH 45/46] Sync All Preference Updates Across Devices (#1400) * Sync preference in batches * a bit of cleanup * update than handling of the incoming mls sync msg * comments * wip * rely on mls for ordering * move the group_id to the info field during hkdf as suggested * lint * Constrain params to only what they need to be * lint * Store and emit hmac key updates * fix wasm * worker handle * fix user preferences * fix tests * cleanup * test fix * cleanup * gate the worker handle behind test utils * lint * lint * cleanup * try this * add test-utils flag * cleanup * revert * revert * test fix * xmtp_common exists now --- bindings_wasm/Cargo.toml | 11 +- .../down.sql | 6 + .../up.sql | 6 + xmtp_mls/src/client.rs | 11 + xmtp_mls/src/groups/device_sync.rs | 129 +- .../src/groups/device_sync/consent_sync.rs | 64 +- .../src/groups/device_sync/preference_sync.rs | 137 +- xmtp_mls/src/groups/mls_sync.rs | 48 +- .../src/storage/encrypted_store/schema.rs | 4 +- .../encrypted_store/user_preferences.rs | 129 +- .../src/gen/xmtp.mls.message_contents.rs | 1689 +++++++++-------- .../gen/xmtp.mls.message_contents.serde.rs | 7 +- 12 files changed, 1222 insertions(+), 1019 deletions(-) create mode 100644 xmtp_mls/migrations/2024-12-11-183736_recreate_user_preferences_with_primary_key/down.sql create mode 100644 xmtp_mls/migrations/2024-12-11-183736_recreate_user_preferences_with_primary_key/up.sql diff --git a/bindings_wasm/Cargo.toml b/bindings_wasm/Cargo.toml index 20e988091..0457f7a96 100644 --- a/bindings_wasm/Cargo.toml +++ b/bindings_wasm/Cargo.toml @@ -7,25 +7,24 @@ version.workspace = true crate-type = ["cdylib", "rlib"] [dependencies] +console_error_panic_hook.workspace = true hex.workspace = true js-sys.workspace = true prost.workspace = true serde-wasm-bindgen = "0.6.5" serde.workspace = true tokio.workspace = true +tracing-subscriber = { workspace = true, features = ["env-filter", "json"] } +tracing-web = "0.1" +tracing.workspace = true wasm-bindgen-futures.workspace = true wasm-bindgen.workspace = true xmtp_api_http = { path = "../xmtp_api_http" } +xmtp_common.workspace = true xmtp_cryptography = { path = "../xmtp_cryptography" } xmtp_id = { path = "../xmtp_id" } xmtp_mls = { path = "../xmtp_mls", features = ["test-utils", "http-api"] } -xmtp_common.workspace = true xmtp_proto = { path = "../xmtp_proto", features = ["proto_full"] } -tracing-web = "0.1" -tracing.workspace = true -tracing-subscriber = { workspace = true, features = ["env-filter", "json"] } -console_error_panic_hook.workspace = true [dev-dependencies] wasm-bindgen-test.workspace = true -xmtp_mls = { path = "../xmtp_mls", features = ["test-utils", "http-api"] } diff --git a/xmtp_mls/migrations/2024-12-11-183736_recreate_user_preferences_with_primary_key/down.sql b/xmtp_mls/migrations/2024-12-11-183736_recreate_user_preferences_with_primary_key/down.sql new file mode 100644 index 000000000..9cf18dcce --- /dev/null +++ b/xmtp_mls/migrations/2024-12-11-183736_recreate_user_preferences_with_primary_key/down.sql @@ -0,0 +1,6 @@ +DROP TABLE user_preferences; + +CREATE TABLE user_preferences( + id INTEGER PRIMARY KEY ASC, + hmac_key BLOB NOT NULL +); diff --git a/xmtp_mls/migrations/2024-12-11-183736_recreate_user_preferences_with_primary_key/up.sql b/xmtp_mls/migrations/2024-12-11-183736_recreate_user_preferences_with_primary_key/up.sql new file mode 100644 index 000000000..910b462a7 --- /dev/null +++ b/xmtp_mls/migrations/2024-12-11-183736_recreate_user_preferences_with_primary_key/up.sql @@ -0,0 +1,6 @@ +DROP TABLE user_preferences; + +CREATE TABLE user_preferences( + id INTEGER PRIMARY KEY ASC NOT NULL, + hmac_key BLOB +); diff --git a/xmtp_mls/src/client.rs b/xmtp_mls/src/client.rs index e293188a7..6db9747da 100644 --- a/xmtp_mls/src/client.rs +++ b/xmtp_mls/src/client.rs @@ -30,6 +30,9 @@ use xmtp_proto::xmtp::mls::api::v1::{ GroupMessage, WelcomeMessage, }; +#[cfg(any(test, feature = "test-utils"))] +use crate::groups::device_sync::WorkerHandle; + use crate::{ api::ApiClientWrapper, groups::{ @@ -144,6 +147,9 @@ pub struct Client> { pub(crate) local_events: broadcast::Sender>, /// The method of verifying smart contract wallet signatures for this Client pub(crate) scw_verifier: Arc, + + #[cfg(any(test, feature = "test-utils"))] + pub(crate) sync_worker_handle: Arc>>>, } // most of these things are `Arc`'s @@ -155,6 +161,9 @@ impl Clone for Client { history_sync_url: self.history_sync_url.clone(), local_events: self.local_events.clone(), scw_verifier: self.scw_verifier.clone(), + + #[cfg(any(test, feature = "test-utils"))] + sync_worker_handle: self.sync_worker_handle.clone(), } } } @@ -240,6 +249,8 @@ where context, history_sync_url, local_events: tx, + #[cfg(any(test, feature = "test-utils"))] + sync_worker_handle: Arc::new(parking_lot::Mutex::default()), scw_verifier: scw_verifier.into(), } } diff --git a/xmtp_mls/src/groups/device_sync.rs b/xmtp_mls/src/groups/device_sync.rs index 5e5a840a7..65f233256 100644 --- a/xmtp_mls/src/groups/device_sync.rs +++ b/xmtp_mls/src/groups/device_sync.rs @@ -24,9 +24,14 @@ use futures::{Stream, StreamExt}; use preference_sync::UserPreferenceUpdate; use rand::{Rng, RngCore}; use serde::{Deserialize, Serialize}; +use std::future::Future; use std::pin::Pin; +use std::sync::atomic::{AtomicUsize, Ordering}; +use std::sync::Arc; use thiserror::Error; -use tokio::sync::OnceCell; +use tokio::sync::{Notify, OnceCell}; +use tokio::time::error::Elapsed; +use tokio::time::timeout; use tracing::{instrument, warn}; use xmtp_common::time::{now_ns, Duration}; use xmtp_common::{retry_async, Retry, RetryableError}; @@ -104,8 +109,8 @@ pub enum DeviceSyncError { SyncPayloadTooOld, #[error(transparent)] Subscribe(#[from] SubscribeError), - #[error("Unable to serialize: {0}")] - Bincode(String), + #[error(transparent)] + Bincode(#[from] bincode::Error), } impl RetryableError for DeviceSyncError { @@ -114,6 +119,17 @@ impl RetryableError for DeviceSyncError { } } +#[cfg(any(test, feature = "test-utils"))] +impl Client { + pub fn sync_worker_handle(&self) -> Option> { + self.sync_worker_handle.lock().clone() + } + + pub(crate) fn set_sync_worker_handle(&self, handle: Arc) { + *self.sync_worker_handle.lock() = Some(handle); + } +} + impl Client where ApiClient: XmtpApi + Send + Sync + 'static, @@ -128,7 +144,10 @@ where "starting sync worker" ); - SyncWorker::new(client).spawn_worker(); + let worker = SyncWorker::new(client); + #[cfg(any(test, feature = "test-utils"))] + self.set_sync_worker_handle(worker.handle.clone()); + worker.spawn_worker(); } } @@ -141,6 +160,57 @@ pub struct SyncWorker { >, init: OnceCell<()>, retry: Retry, + + // Number of events processed + #[cfg(any(test, feature = "test-utils"))] + handle: Arc, +} + +#[cfg(any(test, feature = "test-utils"))] +pub struct WorkerHandle { + processed: AtomicUsize, + notify: Notify, +} + +#[cfg(any(test, feature = "test-utils"))] +impl WorkerHandle { + pub async fn wait_for_new_events(&self, mut count: usize) -> Result<(), Elapsed> { + timeout(Duration::from_secs(3), async { + while count > 0 { + self.notify.notified().await; + count -= 1; + } + }) + .await?; + + Ok(()) + } + + pub async fn wait_for_processed_count(&self, expected: usize) -> Result<(), Elapsed> { + timeout(Duration::from_secs(3), async { + while self.processed.load(Ordering::SeqCst) < expected { + self.notify.notified().await; + } + }) + .await?; + + Ok(()) + } + + pub async fn block_for_num_events(&self, num_events: usize, op: Fut) -> Result<(), Elapsed> + where + Fut: Future, + { + let processed_count = self.processed_count(); + op.await; + self.wait_for_processed_count(processed_count + num_events) + .await?; + Ok(()) + } + + pub fn processed_count(&self) -> usize { + self.processed.load(Ordering::SeqCst) + } } impl SyncWorker @@ -168,33 +238,22 @@ where self.on_request(message_id, &provider).await? } }, - LocalEvents::OutgoingPreferenceUpdates(consent_records) => { - let provider = self.client.mls_provider()?; - for record in consent_records { - let UserPreferenceUpdate::ConsentUpdate(consent_record) = record else { - continue; - }; - - self.client - .send_consent_update(&provider, consent_record) - .await?; - } + LocalEvents::OutgoingPreferenceUpdates(preference_updates) => { + tracing::error!("Outgoing preference update {preference_updates:?}"); + UserPreferenceUpdate::sync_across_devices(preference_updates, &self.client) + .await?; } - LocalEvents::IncomingPreferenceUpdate(updates) => { - let provider = self.client.mls_provider()?; - let consent_records = updates - .into_iter() - .filter_map(|pu| match pu { - UserPreferenceUpdate::ConsentUpdate(cr) => Some(cr), - _ => None, - }) - .collect::>(); - provider - .conn_ref() - .insert_or_replace_consent_records(&consent_records)?; + LocalEvents::IncomingPreferenceUpdate(_) => { + tracing::error!("Incoming preference update"); } _ => {} } + + #[cfg(any(test, feature = "test-utils"))] + { + self.handle.processed.fetch_add(1, Ordering::SeqCst); + self.handle.notify.notify_waiters(); + } } Ok(()) } @@ -319,6 +378,12 @@ where stream, init: OnceCell::new(), retry, + + #[cfg(any(test, feature = "test-utils"))] + handle: Arc::new(WorkerHandle { + processed: AtomicUsize::new(0), + notify: Notify::new(), + }), } } @@ -404,10 +469,10 @@ where let _message_id = sync_group.prepare_message(&content_bytes, provider, { let request = request.clone(); - move |_time_ns| PlaintextEnvelope { + move |now| PlaintextEnvelope { content: Some(Content::V2(V2 { message_type: Some(MessageType::DeviceSyncRequest(request)), - idempotency_key: new_request_id(), + idempotency_key: now.to_string(), })), } })?; @@ -471,14 +536,14 @@ where (content_bytes, contents) }; - sync_group.prepare_message(&content_bytes, provider, |_time_ns| PlaintextEnvelope { + sync_group.prepare_message(&content_bytes, provider, |now| PlaintextEnvelope { content: Some(Content::V2(V2 { - idempotency_key: new_request_id(), message_type: Some(MessageType::DeviceSyncReply(contents)), + idempotency_key: now.to_string(), })), })?; - sync_group.sync_until_last_intent_resolved(provider).await?; + sync_group.publish_intents(provider).await?; Ok(()) } diff --git a/xmtp_mls/src/groups/device_sync/consent_sync.rs b/xmtp_mls/src/groups/device_sync/consent_sync.rs index 965fdb770..ea3d5587d 100644 --- a/xmtp_mls/src/groups/device_sync/consent_sync.rs +++ b/xmtp_mls/src/groups/device_sync/consent_sync.rs @@ -1,42 +1,12 @@ use super::*; use crate::{Client, XmtpApi}; use xmtp_id::scw_verifier::SmartContractSignatureVerifier; -use xmtp_proto::xmtp::mls::message_contents::UserPreferenceUpdate as UserPreferenceUpdateProto; impl Client where ApiClient: XmtpApi, V: SmartContractSignatureVerifier, { - pub(crate) async fn send_consent_update( - &self, - provider: &XmtpOpenMlsProvider, - record: StoredConsentRecord, - ) -> Result<(), DeviceSyncError> { - tracing::info!( - inbox_id = self.inbox_id(), - installation_id = hex::encode(self.installation_public_key()), - "Streaming consent update. {:?}", - record - ); - - let sync_group = self.ensure_sync_group(provider).await?; - let update_proto: UserPreferenceUpdateProto = UserPreferenceUpdate::ConsentUpdate(record) - .try_into() - .map_err(|e| DeviceSyncError::Bincode(format!("{e:?}")))?; - let content_bytes = serde_json::to_vec(&update_proto)?; - sync_group.prepare_message(&content_bytes, provider, |_time_ns| PlaintextEnvelope { - content: Some(Content::V2(V2 { - idempotency_key: new_request_id(), - message_type: Some(MessageType::UserPreferenceUpdate(update_proto)), - })), - })?; - - sync_group.sync_until_last_intent_resolved(provider).await?; - - Ok(()) - } - pub(super) fn syncable_consent_records( &self, conn: &DbConnection, @@ -59,17 +29,15 @@ pub(crate) mod tests { const HISTORY_SERVER_HOST: &str = "localhost"; const HISTORY_SERVER_PORT: u16 = 5558; - use xmtp_common::{ - assert_ok, - time::{Duration, Instant}, - }; - use super::*; use crate::{ builder::ClientBuilder, groups::scoped_client::ScopedGroupClient, storage::consent_record::{ConsentState, ConsentType}, - utils::test::wait_for_min_intents, + }; + use xmtp_common::{ + assert_ok, + time::{Duration, Instant}, }; use xmtp_cryptography::utils::generate_local_wallet; use xmtp_id::InboxOwner; @@ -81,10 +49,9 @@ pub(crate) mod tests { let history_sync_url = format!("http://{}:{}", HISTORY_SERVER_HOST, HISTORY_SERVER_PORT); let wallet = generate_local_wallet(); let amal_a = ClientBuilder::new_test_client_with_history(&wallet, &history_sync_url).await; - let amal_a_provider = amal_a.mls_provider().unwrap(); let amal_a_conn = amal_a_provider.conn_ref(); - wait_for_min_intents(amal_a_conn, 3).await; + let amal_a_worker = amal_a.sync_worker_handle().unwrap(); // create an alix installation and consent with alix let alix_wallet = generate_local_wallet(); @@ -104,6 +71,8 @@ pub(crate) mod tests { let amal_b_provider = amal_b.mls_provider().unwrap(); let amal_b_conn = amal_b_provider.conn_ref(); + let amal_b_worker = amal_b.sync_worker_handle().unwrap(); + let consent_records_b = amal_b.syncable_consent_records(amal_b_conn).unwrap(); assert_eq!(consent_records_b.len(), 0); // make sure amal's workers have time to sync @@ -111,31 +80,34 @@ pub(crate) mod tests { // 1.) UpdateGroupMembership Intent for new sync group // 2.) Device Sync Request // 3.) MessageHistory Sync Request - tracing::info!("Waiting for intents published"); - wait_for_min_intents(amal_b_conn, 3).await; + amal_b_worker.wait_for_new_events(1).await.unwrap(); let old_group_id = amal_a.get_sync_group(amal_a_conn).unwrap().group_id; - tracing::info!("Old Group Id: {}", hex::encode(&old_group_id)); // Check for new welcomes to new groups in the first installation (should be welcomed to a new sync group from amal_b). amal_a.sync_welcomes(&amal_a_provider).await.unwrap(); let new_group_id = amal_a.get_sync_group(amal_a_conn).unwrap().group_id; - tracing::info!("New Group Id: {}", hex::encode(&new_group_id)); // group id should have changed to the new sync group created by the second installation assert_ne!(old_group_id, new_group_id); let consent_a = amal_a.syncable_consent_records(amal_a_conn).unwrap().len(); // Have amal_a receive the message (and auto-process) - let amal_a_sync_group = amal_a.get_sync_group(amal_a_conn).unwrap(); - assert_ok!(amal_a_sync_group.sync_with_conn(&amal_a_provider).await); + + amal_a_worker + .block_for_num_events(1, async { + let amal_a_sync_group = amal_a.get_sync_group(amal_a_conn).unwrap(); + assert_ok!(amal_a_sync_group.sync_with_conn(&amal_a_provider).await); + }) + .await + .unwrap(); + xmtp_common::wait_for_some(|| async { amal_b .get_latest_sync_reply(&amal_b_provider, DeviceSyncKind::Consent) .await .unwrap() }) - .await - .unwrap(); + .await; // Wait up to 20 seconds for sync to process (typically is almost instant) xmtp_common::wait_for_eq( diff --git a/xmtp_mls/src/groups/device_sync/preference_sync.rs b/xmtp_mls/src/groups/device_sync/preference_sync.rs index f677eee4e..c1de9bebf 100644 --- a/xmtp_mls/src/groups/device_sync/preference_sync.rs +++ b/xmtp_mls/src/groups/device_sync/preference_sync.rs @@ -1,39 +1,101 @@ +use super::*; +use crate::{ + storage::{consent_record::StoredConsentRecord, user_preferences::StoredUserPreferences}, + Client, +}; use serde::{Deserialize, Serialize}; -use xmtp_id::associations::DeserializationError; -use xmtp_proto::xmtp::mls::message_contents::UserPreferenceUpdate as UserPreferenceUpdateProto; +use xmtp_proto::{ + api_client::trait_impls::XmtpApi, + xmtp::mls::message_contents::UserPreferenceUpdate as UserPreferenceUpdateProto, +}; -use crate::storage::consent_record::StoredConsentRecord; - -#[derive(Serialize, Deserialize, Clone)] +#[derive(Serialize, Deserialize, Clone, Debug)] #[repr(i32)] pub enum UserPreferenceUpdate { ConsentUpdate(StoredConsentRecord) = 1, HmacKeyUpdate { key: Vec } = 2, } -impl TryFrom for UserPreferenceUpdate { - type Error = DeserializationError; - fn try_from(value: UserPreferenceUpdateProto) -> Result { - let update = - bincode::deserialize(&value.content).map_err(|_| DeserializationError::Bincode)?; +impl UserPreferenceUpdate { + /// Send a preference update through the sync group for other devices to consume + pub(crate) async fn sync_across_devices( + updates: Vec, + client: &Client, + ) -> Result<(), DeviceSyncError> { + let provider = client.mls_provider()?; + let sync_group = client.ensure_sync_group(&provider).await?; + + let updates = updates + .iter() + .map(bincode::serialize) + .collect::, _>>()?; + let update_proto = UserPreferenceUpdateProto { content: updates }; + let content_bytes = serde_json::to_vec(&update_proto)?; + sync_group.prepare_message(&content_bytes, &provider, |now| PlaintextEnvelope { + content: Some(Content::V2(V2 { + message_type: Some(MessageType::UserPreferenceUpdate(update_proto)), + idempotency_key: now.to_string(), + })), + })?; + + sync_group.publish_intents(&provider).await?; - Ok(update) + Ok(()) } -} -impl TryInto for UserPreferenceUpdate { - type Error = bincode::Error; + /// Process and insert incoming preference updates over the sync group + pub(crate) fn process_incoming_preference_update( + update_proto: UserPreferenceUpdateProto, + provider: &XmtpOpenMlsProvider, + ) -> Result, StorageError> { + let conn = provider.conn_ref(); + + let proto_content = update_proto.content; - fn try_into(self) -> Result { - let content = bincode::serialize(&self)?; - Ok(UserPreferenceUpdateProto { content }) + let mut updates = Vec::with_capacity(proto_content.len()); + let mut consent_updates = vec![]; + + for update in proto_content { + if let Ok(update) = bincode::deserialize::(&update) { + updates.push(update.clone()); + match update { + UserPreferenceUpdate::ConsentUpdate(consent_record) => { + consent_updates.push(consent_record); + } + UserPreferenceUpdate::HmacKeyUpdate { key } => { + StoredUserPreferences { + hmac_key: Some(key), + ..StoredUserPreferences::load(conn)? + } + .store(conn)?; + } + } + } else { + // Don't fail on errors since this may come from a newer version of the lib + // that has new update types. + tracing::warn!( + "Failed to deserialize preference update. Is this libxmtp version outdated?" + ); + } + } + + // Insert all of the consent records at once. + if !consent_updates.is_empty() { + conn.insert_or_replace_consent_records(&consent_updates)?; + } + + Ok(updates) } } #[cfg(test)] mod tests { use super::*; - use crate::storage::consent_record::{ConsentState, ConsentType}; + use crate::{ + builder::ClientBuilder, + storage::consent_record::{ConsentState, ConsentType}, + }; + use crypto_utils::generate_local_wallet; use wasm_bindgen_test::wasm_bindgen_test; #[derive(Serialize, Deserialize, Clone)] @@ -43,6 +105,7 @@ mod tests { } #[wasm_bindgen_test(unsupported = tokio::test(flavor = "multi_thread", worker_threads = 1))] + #[cfg_attr(target_family = "wasm", ignore)] async fn test_can_deserialize_between_versions() { let consent_record = StoredConsentRecord { entity: "hello there".to_string(), @@ -58,4 +121,42 @@ mod tests { let OldUserPreferenceUpdate::ConsentUpdate(update) = old_update; assert_eq!(update.state, ConsentState::Allowed); } + + #[wasm_bindgen_test(unsupported = tokio::test(flavor = "multi_thread", worker_threads = 1))] + #[cfg_attr(target_family = "wasm", ignore)] + async fn test_hmac_sync() { + let wallet = generate_local_wallet(); + let amal_a = + ClientBuilder::new_test_client_with_history(&wallet, "http://localhost:5558").await; + let amal_a_provider = amal_a.mls_provider().unwrap(); + let amal_a_conn = amal_a_provider.conn_ref(); + let amal_a_worker = amal_a.sync_worker_handle().unwrap(); + + let amal_b = + ClientBuilder::new_test_client_with_history(&wallet, "http://localhost:5558").await; + let amal_b_provider = amal_b.mls_provider().unwrap(); + let amal_b_conn = amal_b_provider.conn_ref(); + let amal_b_worker = amal_b.sync_worker_handle().unwrap(); + + // wait for the new sync group + amal_a_worker.wait_for_processed_count(1).await.unwrap(); + amal_b_worker.wait_for_processed_count(1).await.unwrap(); + + amal_a.sync_welcomes(&amal_a_provider).await.unwrap(); + + let sync_group_a = amal_a.get_sync_group(amal_a_conn).unwrap(); + let sync_group_b = amal_b.get_sync_group(amal_b_conn).unwrap(); + assert_eq!(sync_group_a.group_id, sync_group_b.group_id); + + sync_group_a.sync_with_conn(&amal_a_provider).await.unwrap(); + sync_group_b.sync_with_conn(&amal_a_provider).await.unwrap(); + + // Wait for a to process the new hmac key + amal_a_worker.wait_for_processed_count(2).await.unwrap(); + + let pref_a = StoredUserPreferences::load(amal_a_conn).unwrap(); + let pref_b = StoredUserPreferences::load(amal_b_conn).unwrap(); + + assert_eq!(pref_a.hmac_key, pref_b.hmac_key); + } } diff --git a/xmtp_mls/src/groups/mls_sync.rs b/xmtp_mls/src/groups/mls_sync.rs index 954041dde..6a642bc41 100644 --- a/xmtp_mls/src/groups/mls_sync.rs +++ b/xmtp_mls/src/groups/mls_sync.rs @@ -14,7 +14,10 @@ use crate::{ SYNC_UPDATE_INSTALLATIONS_INTERVAL_NS, }, groups::device_sync::DeviceSyncContent, - groups::{intents::UpdateMetadataIntentData, validated_commit::ValidatedCommit}, + groups::{ + device_sync::preference_sync::UserPreferenceUpdate, intents::UpdateMetadataIntentData, + validated_commit::ValidatedCommit, + }, hpke::{encrypt_welcome, HpkeError}, identity::{parse_credential, IdentityError}, identity_updates::load_identity_updates, @@ -621,16 +624,18 @@ where )); } Some(MessageType::UserPreferenceUpdate(update)) => { - // Ignore errors since this may come from a newer version of the lib - // that has new update types. - if let Ok(update) = update.try_into() { - let _ = self - .client - .local_events() - .send(LocalEvents::IncomingPreferenceUpdate(vec![update])); - } else { - tracing::warn!("Failed to deserialize preference update. Is this libxmtp version old?"); - } + // This function inserts the updates appropriately, + // and returns a copy of what was inserted + let updates = + UserPreferenceUpdate::process_incoming_preference_update( + update, provider, + )?; + + // Broadcast those updates for integrators to be notified of changes + let _ = self + .client + .local_events() + .send(LocalEvents::IncomingPreferenceUpdate(updates)); } _ => { return Err(GroupMessageProcessingError::InvalidPayload); @@ -1403,17 +1408,28 @@ where epoch_delta_range: RangeInclusive, ) -> Result, StorageError> { let conn = self.client.store().conn()?; - let mut ikm = StoredUserPreferences::load(&conn)?.hmac_key; + + let preferences = StoredUserPreferences::load(&conn)?; + let mut ikm = match preferences.hmac_key { + Some(ikm) => ikm, + None => { + let local_events = self.client.local_events(); + StoredUserPreferences::new_hmac_key(&conn, local_events)? + } + }; ikm.extend(&self.group_id); - let hkdf = Hkdf::::new(Some(HMAC_SALT), &ikm[..]); + let hkdf = Hkdf::::new(Some(HMAC_SALT), &ikm); let mut result = vec![]; let current_epoch = hmac_epoch(); for delta in epoch_delta_range { - let mut key = [0; 42]; let epoch = current_epoch + delta; - hkdf.expand(&epoch.to_le_bytes(), &mut key) - .expect("Length is correct"); + + let mut info = self.group_id.clone(); + info.extend(&epoch.to_le_bytes()); + + let mut key = [0; 42]; + hkdf.expand(&info, &mut key).expect("Length is correct"); result.push(HmacKey { key, epoch }); } diff --git a/xmtp_mls/src/storage/encrypted_store/schema.rs b/xmtp_mls/src/storage/encrypted_store/schema.rs index 14ede47e5..c82818161 100644 --- a/xmtp_mls/src/storage/encrypted_store/schema.rs +++ b/xmtp_mls/src/storage/encrypted_store/schema.rs @@ -109,8 +109,8 @@ diesel::table! { diesel::table! { user_preferences (id) { - id -> Nullable, - hmac_key -> Binary, + id -> Integer, + hmac_key -> Nullable, } } diff --git a/xmtp_mls/src/storage/encrypted_store/user_preferences.rs b/xmtp_mls/src/storage/encrypted_store/user_preferences.rs index 9d59bc299..98170d52f 100644 --- a/xmtp_mls/src/storage/encrypted_store/user_preferences.rs +++ b/xmtp_mls/src/storage/encrypted_store/user_preferences.rs @@ -1,4 +1,7 @@ -use crate::{impl_store, storage::StorageError, Store}; +use crate::{ + groups::device_sync::preference_sync::UserPreferenceUpdate, storage::StorageError, + subscriptions::LocalEvents, Store, +}; use super::{ schema::user_preferences::{self, dsl}, @@ -6,62 +9,85 @@ use super::{ }; use diesel::prelude::*; use rand::{rngs::OsRng, RngCore}; +use tokio::sync::broadcast::Sender; -#[derive(Identifiable, Insertable, Queryable, Debug, Clone, PartialEq, Eq)] +#[derive(Identifiable, Queryable, AsChangeset, Debug, Clone, PartialEq, Eq, Default)] #[diesel(table_name = user_preferences)] #[diesel(primary_key(id))] pub struct StoredUserPreferences { /// Primary key - latest key is the "current" preference - pub id: Option, + pub id: i32, /// Randomly generated hmac key root - pub hmac_key: Vec, + pub hmac_key: Option>, } -impl Default for StoredUserPreferences { - fn default() -> Self { - let mut hmac_key = vec![0; 32]; - OsRng.fill_bytes(&mut hmac_key); +#[derive(Insertable)] +#[diesel(table_name = user_preferences)] +pub struct NewStoredUserPreferences<'a> { + hmac_key: Option<&'a Vec>, +} - Self { id: None, hmac_key } +impl<'a> From<&'a StoredUserPreferences> for NewStoredUserPreferences<'a> { + fn from(value: &'a StoredUserPreferences) -> Self { + Self { + hmac_key: value.hmac_key.as_ref(), + } } } -impl_store!(StoredUserPreferences, user_preferences); +impl Store for StoredUserPreferences { + fn store(&self, conn: &DbConnection) -> Result<(), StorageError> { + conn.raw_query(|conn| { + diesel::update(dsl::user_preferences) + .set(self) + .execute(conn) + })?; + + Ok(()) + } +} impl StoredUserPreferences { pub fn load(conn: &DbConnection) -> Result { let query = dsl::user_preferences.order(dsl::id.desc()).limit(1); let mut result = conn.raw_query(|conn| query.load::(conn))?; - let result = match result.pop() { - Some(result) => result, - None => { - // Create a default and store it. - let result = Self::default(); - // TODO: emit an hmac key update event here. - result.store(conn)?; - result - } - }; - - Ok(result) + Ok(result.pop().unwrap_or_default()) } - pub fn set_hmac_key(conn: &DbConnection, hmac_key: Vec) -> Result<(), StorageError> { + pub fn new_hmac_key( + conn: &DbConnection, + local_events: &Sender>, + ) -> Result, StorageError> { let mut preferences = Self::load(conn)?; - // Have the id increment - preferences.id = None; - preferences.hmac_key = hmac_key; - preferences.store(conn)?; - - Ok(()) + let mut hmac_key = vec![0; 32]; + OsRng.fill_bytes(&mut hmac_key); + preferences.hmac_key = Some(hmac_key.clone()); + + // Sync the new key to other devices + let _ = local_events.send(LocalEvents::OutgoingPreferenceUpdates(vec![ + UserPreferenceUpdate::HmacKeyUpdate { + key: hmac_key.clone(), + }, + ])); + + let to_insert: NewStoredUserPreferences = (&preferences).into(); + conn.raw_query(|conn| { + diesel::insert_into(dsl::user_preferences) + .values(to_insert) + .execute(conn) + })?; + + Ok(hmac_key) } } #[cfg(test)] mod tests { - use crate::storage::encrypted_store::tests::with_connection; + use xmtp_cryptography::utils::generate_local_wallet; + + use crate::builder::ClientBuilder; #[cfg(target_arch = "wasm32")] wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_dedicated_worker); @@ -70,26 +96,27 @@ mod tests { #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] async fn test_insert_and_update_preferences() { - with_connection(|conn| { - // loads and stores a default - let _pref = StoredUserPreferences::load(conn).unwrap(); - - // set an hmac key - let hmac_key = vec![1, 2, 1, 2, 1, 2, 1, 2, 1, 2]; - StoredUserPreferences::set_hmac_key(conn, hmac_key.clone()).unwrap(); - - // load preferences from db - let pref = StoredUserPreferences::load(conn).unwrap(); - assert_eq!(pref.hmac_key, hmac_key); - assert_eq!(pref.id, Some(2)); - - // check that there are two preferences stored - let query = dsl::user_preferences.order(dsl::id.desc()); - let result = conn - .raw_query(|conn| query.load::(conn)) - .unwrap(); - assert_eq!(result.len(), 2); - }) - .await; + let wallet = generate_local_wallet(); + let client = ClientBuilder::new_test_client(&wallet).await; + + let conn = client.store().conn().unwrap(); + + // loads and stores a default + let pref = StoredUserPreferences::load(&conn).unwrap(); + // by default, there is no key + assert!(pref.hmac_key.is_none()); + + // set an hmac key + let hmac_key = StoredUserPreferences::new_hmac_key(&conn, &client.local_events).unwrap(); + let pref = StoredUserPreferences::load(&conn).unwrap(); + // Make sure it saved + assert_eq!(hmac_key, pref.hmac_key.unwrap()); + + // check that there are two preferences stored + let query = dsl::user_preferences.order(dsl::id.desc()); + let result = conn + .raw_query(|conn| query.load::(conn)) + .unwrap(); + assert_eq!(result.len(), 1); } } diff --git a/xmtp_proto/src/gen/xmtp.mls.message_contents.rs b/xmtp_proto/src/gen/xmtp.mls.message_contents.rs index dad2c1b77..6cdc4be11 100644 --- a/xmtp_proto/src/gen/xmtp.mls.message_contents.rs +++ b/xmtp_proto/src/gen/xmtp.mls.message_contents.rs @@ -158,8 +158,8 @@ pub mod device_sync_key_type { #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct UserPreferenceUpdate { - #[prost(bytes="vec", tag="1")] - pub content: ::prost::alloc::vec::Vec, + #[prost(bytes="vec", repeated, tag="1")] + pub content: ::prost::alloc::vec::Vec<::prost::alloc::vec::Vec>, } /// Recognized compression algorithms /// protolint:disable ENUM_FIELD_NAMES_ZERO_VALUE_END_WITH @@ -616,7 +616,7 @@ pub mod group_updated { } /// Encoded file descriptor set for the `xmtp.mls.message_contents` package pub const FILE_DESCRIPTOR_SET: &[u8] = &[ - 0x0a, 0xac, 0x34, 0x0a, 0x22, 0x6d, 0x6c, 0x73, 0x2f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x0a, 0xba, 0x34, 0x0a, 0x22, 0x6d, 0x6c, 0x73, 0x2f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x19, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, @@ -724,7 +724,7 @@ pub const FILE_DESCRIPTOR_SET: &[u8] = &[ 0x48, 0x00, 0x52, 0x09, 0x61, 0x65, 0x73, 0x32, 0x35, 0x36, 0x47, 0x63, 0x6d, 0x42, 0x05, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x22, 0x30, 0x0a, 0x14, 0x55, 0x73, 0x65, 0x72, 0x50, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x18, 0x0a, 0x07, - 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x63, + 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2a, 0x3c, 0x0a, 0x0b, 0x43, 0x6f, 0x6d, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x17, 0x0a, 0x13, 0x43, 0x4f, 0x4d, 0x50, 0x52, 0x45, 0x53, 0x53, 0x49, 0x4f, 0x4e, 0x5f, 0x44, 0x45, 0x46, 0x4c, 0x41, 0x54, 0x45, 0x10, 0x00, 0x12, 0x14, @@ -751,7 +751,7 @@ pub const FILE_DESCRIPTOR_SET: &[u8] = &[ 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x1a, 0x58, 0x6d, 0x74, 0x70, 0x3a, 0x3a, 0x4d, 0x6c, 0x73, 0x3a, 0x3a, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, - 0x4a, 0xb4, 0x23, 0x0a, 0x06, 0x12, 0x04, 0x02, 0x00, 0x78, 0x01, 0x0a, 0x7c, 0x0a, 0x01, 0x0c, + 0x4a, 0xc2, 0x23, 0x0a, 0x06, 0x12, 0x04, 0x02, 0x00, 0x78, 0x01, 0x0a, 0x7c, 0x0a, 0x01, 0x0c, 0x12, 0x03, 0x02, 0x00, 0x12, 0x1a, 0x72, 0x20, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x20, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x75, 0x72, 0x65, 0x73, 0x0a, 0x20, 0x43, 0x6f, 0x70, @@ -1031,106 +1031,29 @@ pub const FILE_DESCRIPTOR_SET: &[u8] = &[ 0x05, 0x01, 0x02, 0x02, 0x01, 0x12, 0x03, 0x73, 0x02, 0x1a, 0x0a, 0x0c, 0x0a, 0x05, 0x05, 0x01, 0x02, 0x02, 0x02, 0x12, 0x03, 0x73, 0x1d, 0x1e, 0x0a, 0x0a, 0x0a, 0x02, 0x04, 0x06, 0x12, 0x04, 0x76, 0x00, 0x78, 0x01, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x06, 0x01, 0x12, 0x03, 0x76, 0x08, 0x1c, - 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x06, 0x02, 0x00, 0x12, 0x03, 0x77, 0x02, 0x14, 0x0a, 0x0c, 0x0a, - 0x05, 0x04, 0x06, 0x02, 0x00, 0x05, 0x12, 0x03, 0x77, 0x02, 0x07, 0x0a, 0x0c, 0x0a, 0x05, 0x04, - 0x06, 0x02, 0x00, 0x01, 0x12, 0x03, 0x77, 0x08, 0x0f, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x06, 0x02, - 0x00, 0x03, 0x12, 0x03, 0x77, 0x12, 0x13, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, 0x0a, - 0x90, 0x06, 0x0a, 0x2b, 0x6d, 0x6c, 0x73, 0x2f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, - 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2f, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x5f, 0x6d, - 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, - 0x19, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x22, 0xa0, 0x01, 0x0a, 0x0f, 0x47, - 0x72, 0x6f, 0x75, 0x70, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x12, 0x51, - 0x0a, 0x07, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, - 0x37, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x47, 0x72, 0x6f, 0x75, - 0x70, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x2e, 0x4d, 0x65, 0x6d, 0x62, - 0x65, 0x72, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, - 0x73, 0x1a, 0x3a, 0x0a, 0x0c, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x45, 0x6e, 0x74, 0x72, - 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, - 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x04, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x42, 0xe9, 0x01, - 0x0a, 0x1d, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x42, - 0x14, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, - 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x30, 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, 0x6d, 0x6c, 0x73, 0x2f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0xa2, 0x02, 0x03, 0x58, 0x4d, 0x4d, 0xaa, - 0x02, 0x18, 0x58, 0x6d, 0x74, 0x70, 0x2e, 0x4d, 0x6c, 0x73, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0xca, 0x02, 0x18, 0x58, 0x6d, 0x74, - 0x70, 0x5c, 0x4d, 0x6c, 0x73, 0x5c, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, - 0x74, 0x65, 0x6e, 0x74, 0x73, 0xe2, 0x02, 0x24, 0x58, 0x6d, 0x74, 0x70, 0x5c, 0x4d, 0x6c, 0x73, - 0x5c, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, - 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x1a, 0x58, - 0x6d, 0x74, 0x70, 0x3a, 0x3a, 0x4d, 0x6c, 0x73, 0x3a, 0x3a, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x4a, 0xae, 0x02, 0x0a, 0x06, 0x12, 0x04, - 0x01, 0x00, 0x0c, 0x01, 0x0a, 0x1c, 0x0a, 0x01, 0x0c, 0x12, 0x03, 0x01, 0x00, 0x12, 0x1a, 0x12, - 0x20, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x20, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, - 0x70, 0x0a, 0x0a, 0x08, 0x0a, 0x01, 0x02, 0x12, 0x03, 0x03, 0x00, 0x22, 0x0a, 0x08, 0x0a, 0x01, - 0x08, 0x12, 0x03, 0x05, 0x00, 0x47, 0x0a, 0x09, 0x0a, 0x02, 0x08, 0x0b, 0x12, 0x03, 0x05, 0x00, - 0x47, 0x0a, 0xa3, 0x01, 0x0a, 0x02, 0x04, 0x00, 0x12, 0x04, 0x0a, 0x00, 0x0c, 0x01, 0x1a, 0x96, - 0x01, 0x20, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x73, 0x20, 0x61, 0x20, 0x6d, 0x61, 0x70, - 0x70, 0x69, 0x6e, 0x67, 0x20, 0x6f, 0x66, 0x20, 0x60, 0x69, 0x6e, 0x62, 0x6f, 0x78, 0x5f, 0x69, - 0x64, 0x60, 0x20, 0x2d, 0x3e, 0x20, 0x60, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x5f, - 0x69, 0x64, 0x60, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x61, 0x6c, 0x6c, 0x20, 0x6d, 0x65, 0x6d, 0x62, - 0x65, 0x72, 0x73, 0x20, 0x6f, 0x66, 0x20, 0x61, 0x20, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x2e, 0x0a, - 0x20, 0x44, 0x65, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x20, 0x74, 0x6f, 0x20, 0x62, 0x65, 0x20, - 0x73, 0x74, 0x6f, 0x72, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x67, 0x72, - 0x6f, 0x75, 0x70, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x20, 0x65, 0x78, 0x74, 0x65, - 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x4d, 0x4c, 0x53, - 0x20, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x0a, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x00, 0x01, 0x12, 0x03, - 0x0a, 0x08, 0x17, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x00, 0x02, 0x00, 0x12, 0x03, 0x0b, 0x02, 0x22, - 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x00, 0x06, 0x12, 0x03, 0x0b, 0x02, 0x15, 0x0a, 0x0c, - 0x0a, 0x05, 0x04, 0x00, 0x02, 0x00, 0x01, 0x12, 0x03, 0x0b, 0x16, 0x1d, 0x0a, 0x0c, 0x0a, 0x05, - 0x04, 0x00, 0x02, 0x00, 0x03, 0x12, 0x03, 0x0b, 0x20, 0x21, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x33, 0x0a, 0xe5, 0x0e, 0x0a, 0x29, 0x6d, 0x6c, 0x73, 0x2f, 0x6d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2f, 0x67, 0x72, 0x6f, 0x75, - 0x70, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x12, 0x19, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x22, 0xa6, 0x02, 0x0a, 0x0f, - 0x47, 0x72, 0x6f, 0x75, 0x70, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x56, 0x31, 0x12, - 0x58, 0x0a, 0x11, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, - 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2b, 0x2e, 0x78, 0x6d, 0x74, - 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, - 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x43, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x10, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x12, 0x36, 0x0a, 0x17, 0x63, 0x72, 0x65, - 0x61, 0x74, 0x6f, 0x72, 0x5f, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x61, 0x64, 0x64, - 0x72, 0x65, 0x73, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x15, 0x63, 0x72, 0x65, 0x61, - 0x74, 0x6f, 0x72, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, - 0x73, 0x12, 0x28, 0x0a, 0x10, 0x63, 0x72, 0x65, 0x61, 0x74, 0x6f, 0x72, 0x5f, 0x69, 0x6e, 0x62, - 0x6f, 0x78, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x63, 0x72, 0x65, - 0x61, 0x74, 0x6f, 0x72, 0x49, 0x6e, 0x62, 0x6f, 0x78, 0x49, 0x64, 0x12, 0x48, 0x0a, 0x0a, 0x64, - 0x6d, 0x5f, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x24, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x44, 0x6d, 0x4d, 0x65, - 0x6d, 0x62, 0x65, 0x72, 0x73, 0x48, 0x00, 0x52, 0x09, 0x64, 0x6d, 0x4d, 0x65, 0x6d, 0x62, 0x65, - 0x72, 0x73, 0x88, 0x01, 0x01, 0x42, 0x0d, 0x0a, 0x0b, 0x5f, 0x64, 0x6d, 0x5f, 0x6d, 0x65, 0x6d, - 0x62, 0x65, 0x72, 0x73, 0x22, 0x22, 0x0a, 0x05, 0x49, 0x6e, 0x62, 0x6f, 0x78, 0x12, 0x19, 0x0a, - 0x08, 0x69, 0x6e, 0x62, 0x6f, 0x78, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x07, 0x69, 0x6e, 0x62, 0x6f, 0x78, 0x49, 0x64, 0x22, 0x97, 0x01, 0x0a, 0x09, 0x44, 0x6d, 0x4d, - 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x12, 0x44, 0x0a, 0x0d, 0x64, 0x6d, 0x5f, 0x6d, 0x65, 0x6d, - 0x62, 0x65, 0x72, 0x5f, 0x6f, 0x6e, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, + 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x06, 0x02, 0x00, 0x12, 0x03, 0x77, 0x02, 0x1d, 0x0a, 0x0c, 0x0a, + 0x05, 0x04, 0x06, 0x02, 0x00, 0x04, 0x12, 0x03, 0x77, 0x02, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, + 0x06, 0x02, 0x00, 0x05, 0x12, 0x03, 0x77, 0x0b, 0x10, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x06, 0x02, + 0x00, 0x01, 0x12, 0x03, 0x77, 0x11, 0x18, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x06, 0x02, 0x00, 0x03, + 0x12, 0x03, 0x77, 0x1b, 0x1c, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, 0x0a, 0x90, 0x06, + 0x0a, 0x2b, 0x6d, 0x6c, 0x73, 0x2f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, + 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2f, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x5f, 0x6d, 0x65, 0x6d, + 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x19, 0x78, + 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, + 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x22, 0xa0, 0x01, 0x0a, 0x0f, 0x47, 0x72, 0x6f, + 0x75, 0x70, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x12, 0x51, 0x0a, 0x07, + 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x37, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x49, 0x6e, 0x62, 0x6f, 0x78, 0x52, - 0x0b, 0x64, 0x6d, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x4f, 0x6e, 0x65, 0x12, 0x44, 0x0a, 0x0d, - 0x64, 0x6d, 0x5f, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x5f, 0x74, 0x77, 0x6f, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, - 0x49, 0x6e, 0x62, 0x6f, 0x78, 0x52, 0x0b, 0x64, 0x6d, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x54, - 0x77, 0x6f, 0x2a, 0x88, 0x01, 0x0a, 0x10, 0x43, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x12, 0x21, 0x0a, 0x1d, 0x43, 0x4f, 0x4e, 0x56, 0x45, - 0x52, 0x53, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x53, - 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x1b, 0x0a, 0x17, 0x43, 0x4f, - 0x4e, 0x56, 0x45, 0x52, 0x53, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, - 0x47, 0x52, 0x4f, 0x55, 0x50, 0x10, 0x01, 0x12, 0x18, 0x0a, 0x14, 0x43, 0x4f, 0x4e, 0x56, 0x45, - 0x52, 0x53, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x44, 0x4d, 0x10, - 0x02, 0x12, 0x1a, 0x0a, 0x16, 0x43, 0x4f, 0x4e, 0x56, 0x45, 0x52, 0x53, 0x41, 0x54, 0x49, 0x4f, - 0x4e, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x53, 0x59, 0x4e, 0x43, 0x10, 0x03, 0x42, 0xe7, 0x01, - 0x0a, 0x1d, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x42, - 0x12, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x50, 0x72, + 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x4d, + 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x2e, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, + 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x1a, + 0x3a, 0x0a, 0x0c, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, + 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, + 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, + 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x42, 0xe9, 0x01, 0x0a, 0x1d, + 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x42, 0x14, 0x47, + 0x72, 0x6f, 0x75, 0x70, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x30, 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, 0x6d, 0x6c, 0x73, 0x2f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, @@ -1142,625 +1065,73 @@ pub const FILE_DESCRIPTOR_SET: &[u8] = &[ 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x1a, 0x58, 0x6d, 0x74, 0x70, 0x3a, 0x3a, 0x4d, 0x6c, 0x73, 0x3a, 0x3a, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x43, - 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x4a, 0xb8, 0x07, 0x0a, 0x06, 0x12, 0x04, 0x01, 0x00, - 0x23, 0x01, 0x0a, 0x24, 0x0a, 0x01, 0x0c, 0x12, 0x03, 0x01, 0x00, 0x12, 0x1a, 0x1a, 0x20, 0x47, - 0x72, 0x6f, 0x75, 0x70, 0x20, 0x69, 0x6d, 0x6d, 0x75, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x6d, - 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x0a, 0x0a, 0x08, 0x0a, 0x01, 0x02, 0x12, 0x03, 0x03, - 0x00, 0x22, 0x0a, 0x08, 0x0a, 0x01, 0x08, 0x12, 0x03, 0x05, 0x00, 0x47, 0x0a, 0x09, 0x0a, 0x02, - 0x08, 0x0b, 0x12, 0x03, 0x05, 0x00, 0x47, 0x0a, 0x2f, 0x0a, 0x02, 0x04, 0x00, 0x12, 0x04, 0x09, - 0x00, 0x10, 0x01, 0x1a, 0x23, 0x20, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x20, 0x6d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x20, 0x6d, - 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x0a, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x00, 0x01, 0x12, - 0x03, 0x09, 0x08, 0x17, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x00, 0x02, 0x00, 0x12, 0x03, 0x0a, 0x02, - 0x29, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x00, 0x06, 0x12, 0x03, 0x0a, 0x02, 0x12, 0x0a, - 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x00, 0x01, 0x12, 0x03, 0x0a, 0x13, 0x24, 0x0a, 0x0c, 0x0a, - 0x05, 0x04, 0x00, 0x02, 0x00, 0x03, 0x12, 0x03, 0x0a, 0x27, 0x28, 0x0a, 0x28, 0x0a, 0x04, 0x04, - 0x00, 0x02, 0x01, 0x12, 0x03, 0x0c, 0x02, 0x25, 0x1a, 0x1b, 0x20, 0x54, 0x68, 0x69, 0x73, 0x20, - 0x77, 0x69, 0x6c, 0x6c, 0x20, 0x62, 0x65, 0x20, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x20, - 0x73, 0x6f, 0x6f, 0x6e, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x01, 0x05, 0x12, 0x03, - 0x0c, 0x02, 0x08, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x01, 0x01, 0x12, 0x03, 0x0c, 0x09, - 0x20, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x01, 0x03, 0x12, 0x03, 0x0c, 0x23, 0x24, 0x0a, - 0x0b, 0x0a, 0x04, 0x04, 0x00, 0x02, 0x02, 0x12, 0x03, 0x0d, 0x02, 0x1e, 0x0a, 0x0c, 0x0a, 0x05, - 0x04, 0x00, 0x02, 0x02, 0x05, 0x12, 0x03, 0x0d, 0x02, 0x08, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, - 0x02, 0x02, 0x01, 0x12, 0x03, 0x0d, 0x09, 0x19, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x02, - 0x03, 0x12, 0x03, 0x0d, 0x1c, 0x1d, 0x0a, 0x3e, 0x0a, 0x04, 0x04, 0x00, 0x02, 0x03, 0x12, 0x03, - 0x0f, 0x02, 0x24, 0x1a, 0x31, 0x20, 0x53, 0x68, 0x6f, 0x75, 0x6c, 0x64, 0x20, 0x6f, 0x6e, 0x6c, - 0x79, 0x20, 0x62, 0x65, 0x20, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x20, 0x66, 0x6f, 0x72, - 0x20, 0x43, 0x4f, 0x4e, 0x56, 0x45, 0x52, 0x53, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x54, 0x59, - 0x50, 0x45, 0x5f, 0x44, 0x4d, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x03, 0x04, 0x12, - 0x03, 0x0f, 0x02, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x03, 0x06, 0x12, 0x03, 0x0f, - 0x0b, 0x14, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x03, 0x01, 0x12, 0x03, 0x0f, 0x15, 0x1f, - 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x03, 0x03, 0x12, 0x03, 0x0f, 0x22, 0x23, 0x0a, 0x2e, - 0x0a, 0x02, 0x05, 0x00, 0x12, 0x04, 0x13, 0x00, 0x18, 0x01, 0x1a, 0x22, 0x20, 0x44, 0x65, 0x66, - 0x69, 0x6e, 0x65, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x79, 0x70, 0x65, 0x20, 0x6f, 0x66, - 0x20, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x0a, 0x0a, 0x0a, - 0x0a, 0x03, 0x05, 0x00, 0x01, 0x12, 0x03, 0x13, 0x05, 0x15, 0x0a, 0x0b, 0x0a, 0x04, 0x05, 0x00, - 0x02, 0x00, 0x12, 0x03, 0x14, 0x02, 0x24, 0x0a, 0x0c, 0x0a, 0x05, 0x05, 0x00, 0x02, 0x00, 0x01, - 0x12, 0x03, 0x14, 0x02, 0x1f, 0x0a, 0x0c, 0x0a, 0x05, 0x05, 0x00, 0x02, 0x00, 0x02, 0x12, 0x03, - 0x14, 0x22, 0x23, 0x0a, 0x0b, 0x0a, 0x04, 0x05, 0x00, 0x02, 0x01, 0x12, 0x03, 0x15, 0x02, 0x1e, - 0x0a, 0x0c, 0x0a, 0x05, 0x05, 0x00, 0x02, 0x01, 0x01, 0x12, 0x03, 0x15, 0x02, 0x19, 0x0a, 0x0c, - 0x0a, 0x05, 0x05, 0x00, 0x02, 0x01, 0x02, 0x12, 0x03, 0x15, 0x1c, 0x1d, 0x0a, 0x0b, 0x0a, 0x04, - 0x05, 0x00, 0x02, 0x02, 0x12, 0x03, 0x16, 0x02, 0x1b, 0x0a, 0x0c, 0x0a, 0x05, 0x05, 0x00, 0x02, - 0x02, 0x01, 0x12, 0x03, 0x16, 0x02, 0x16, 0x0a, 0x0c, 0x0a, 0x05, 0x05, 0x00, 0x02, 0x02, 0x02, - 0x12, 0x03, 0x16, 0x19, 0x1a, 0x0a, 0x0b, 0x0a, 0x04, 0x05, 0x00, 0x02, 0x03, 0x12, 0x03, 0x17, - 0x02, 0x1d, 0x0a, 0x0c, 0x0a, 0x05, 0x05, 0x00, 0x02, 0x03, 0x01, 0x12, 0x03, 0x17, 0x02, 0x18, - 0x0a, 0x0c, 0x0a, 0x05, 0x05, 0x00, 0x02, 0x03, 0x02, 0x12, 0x03, 0x17, 0x1b, 0x1c, 0x0a, 0x28, - 0x0a, 0x02, 0x04, 0x01, 0x12, 0x04, 0x1b, 0x00, 0x1d, 0x01, 0x1a, 0x1c, 0x20, 0x57, 0x72, 0x61, - 0x70, 0x70, 0x65, 0x72, 0x20, 0x61, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x20, 0x61, 0x6e, 0x20, 0x49, - 0x6e, 0x62, 0x6f, 0x78, 0x20, 0x49, 0x64, 0x0a, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x01, 0x01, 0x12, - 0x03, 0x1b, 0x08, 0x0d, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x01, 0x02, 0x00, 0x12, 0x03, 0x1c, 0x02, - 0x16, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x00, 0x05, 0x12, 0x03, 0x1c, 0x02, 0x08, 0x0a, - 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x00, 0x01, 0x12, 0x03, 0x1c, 0x09, 0x11, 0x0a, 0x0c, 0x0a, - 0x05, 0x04, 0x01, 0x02, 0x00, 0x03, 0x12, 0x03, 0x1c, 0x14, 0x15, 0x0a, 0x2b, 0x0a, 0x02, 0x04, - 0x02, 0x12, 0x04, 0x20, 0x00, 0x23, 0x01, 0x1a, 0x1f, 0x20, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x69, - 0x6e, 0x67, 0x20, 0x64, 0x6f, 0x65, 0x73, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x6d, 0x61, 0x74, 0x74, - 0x65, 0x72, 0x20, 0x68, 0x65, 0x72, 0x65, 0x0a, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x02, 0x01, 0x12, - 0x03, 0x20, 0x08, 0x11, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x02, 0x02, 0x00, 0x12, 0x03, 0x21, 0x02, - 0x1a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x00, 0x06, 0x12, 0x03, 0x21, 0x02, 0x07, 0x0a, - 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x00, 0x01, 0x12, 0x03, 0x21, 0x08, 0x15, 0x0a, 0x0c, 0x0a, - 0x05, 0x04, 0x02, 0x02, 0x00, 0x03, 0x12, 0x03, 0x21, 0x18, 0x19, 0x0a, 0x0b, 0x0a, 0x04, 0x04, - 0x02, 0x02, 0x01, 0x12, 0x03, 0x22, 0x02, 0x1a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x01, - 0x06, 0x12, 0x03, 0x22, 0x02, 0x07, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x01, 0x01, 0x12, - 0x03, 0x22, 0x08, 0x15, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x01, 0x03, 0x12, 0x03, 0x22, - 0x18, 0x19, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, 0x0a, 0x92, 0x0a, 0x0a, 0x31, 0x6d, - 0x6c, 0x73, 0x2f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, - 0x6e, 0x74, 0x73, 0x2f, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x5f, 0x6d, 0x75, 0x74, 0x61, 0x62, 0x6c, - 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x12, 0x19, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x22, 0xcb, 0x02, 0x0a, 0x16, - 0x47, 0x72, 0x6f, 0x75, 0x70, 0x4d, 0x75, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x4d, 0x65, 0x74, 0x61, - 0x64, 0x61, 0x74, 0x61, 0x56, 0x31, 0x12, 0x61, 0x0a, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, - 0x75, 0x74, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x41, 0x2e, 0x78, 0x6d, 0x74, - 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, - 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x4d, 0x75, 0x74, 0x61, - 0x62, 0x6c, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x56, 0x31, 0x2e, 0x41, 0x74, - 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0a, 0x61, - 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x12, 0x41, 0x0a, 0x0a, 0x61, 0x64, 0x6d, - 0x69, 0x6e, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, + 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x4a, 0xae, 0x02, 0x0a, 0x06, 0x12, 0x04, 0x01, 0x00, + 0x0c, 0x01, 0x0a, 0x1c, 0x0a, 0x01, 0x0c, 0x12, 0x03, 0x01, 0x00, 0x12, 0x1a, 0x12, 0x20, 0x47, + 0x72, 0x6f, 0x75, 0x70, 0x20, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x0a, + 0x0a, 0x08, 0x0a, 0x01, 0x02, 0x12, 0x03, 0x03, 0x00, 0x22, 0x0a, 0x08, 0x0a, 0x01, 0x08, 0x12, + 0x03, 0x05, 0x00, 0x47, 0x0a, 0x09, 0x0a, 0x02, 0x08, 0x0b, 0x12, 0x03, 0x05, 0x00, 0x47, 0x0a, + 0xa3, 0x01, 0x0a, 0x02, 0x04, 0x00, 0x12, 0x04, 0x0a, 0x00, 0x0c, 0x01, 0x1a, 0x96, 0x01, 0x20, + 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x73, 0x20, 0x61, 0x20, 0x6d, 0x61, 0x70, 0x70, 0x69, + 0x6e, 0x67, 0x20, 0x6f, 0x66, 0x20, 0x60, 0x69, 0x6e, 0x62, 0x6f, 0x78, 0x5f, 0x69, 0x64, 0x60, + 0x20, 0x2d, 0x3e, 0x20, 0x60, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, + 0x60, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x61, 0x6c, 0x6c, 0x20, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, + 0x73, 0x20, 0x6f, 0x66, 0x20, 0x61, 0x20, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x2e, 0x0a, 0x20, 0x44, + 0x65, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x20, 0x74, 0x6f, 0x20, 0x62, 0x65, 0x20, 0x73, 0x74, + 0x6f, 0x72, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x67, 0x72, 0x6f, 0x75, + 0x70, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x20, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, + 0x69, 0x6f, 0x6e, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x4d, 0x4c, 0x53, 0x20, 0x67, + 0x72, 0x6f, 0x75, 0x70, 0x0a, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x00, 0x01, 0x12, 0x03, 0x0a, 0x08, + 0x17, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x00, 0x02, 0x00, 0x12, 0x03, 0x0b, 0x02, 0x22, 0x0a, 0x0c, + 0x0a, 0x05, 0x04, 0x00, 0x02, 0x00, 0x06, 0x12, 0x03, 0x0b, 0x02, 0x15, 0x0a, 0x0c, 0x0a, 0x05, + 0x04, 0x00, 0x02, 0x00, 0x01, 0x12, 0x03, 0x0b, 0x16, 0x1d, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, + 0x02, 0x00, 0x03, 0x12, 0x03, 0x0b, 0x20, 0x21, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x0a, 0xe5, 0x0e, 0x0a, 0x29, 0x6d, 0x6c, 0x73, 0x2f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2f, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x5f, + 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x19, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x49, 0x6e, 0x62, 0x6f, 0x78, 0x65, - 0x73, 0x52, 0x09, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x4c, 0x0a, 0x10, - 0x73, 0x75, 0x70, 0x65, 0x72, 0x5f, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x5f, 0x6c, 0x69, 0x73, 0x74, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, - 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, - 0x74, 0x73, 0x2e, 0x49, 0x6e, 0x62, 0x6f, 0x78, 0x65, 0x73, 0x52, 0x0e, 0x73, 0x75, 0x70, 0x65, - 0x72, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x4c, 0x69, 0x73, 0x74, 0x1a, 0x3d, 0x0a, 0x0f, 0x41, 0x74, - 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, - 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, - 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, - 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x26, 0x0a, 0x07, 0x49, 0x6e, 0x62, - 0x6f, 0x78, 0x65, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x69, 0x6e, 0x62, 0x6f, 0x78, 0x5f, 0x69, 0x64, - 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x69, 0x6e, 0x62, 0x6f, 0x78, 0x49, 0x64, - 0x73, 0x42, 0xee, 0x01, 0x0a, 0x1d, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, - 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, - 0x6e, 0x74, 0x73, 0x42, 0x19, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x4d, 0x75, 0x74, 0x61, 0x62, 0x6c, - 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, - 0x5a, 0x30, 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, 0x6d, 0x6c, - 0x73, 0x2f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, - 0x74, 0x73, 0xa2, 0x02, 0x03, 0x58, 0x4d, 0x4d, 0xaa, 0x02, 0x18, 0x58, 0x6d, 0x74, 0x70, 0x2e, - 0x4d, 0x6c, 0x73, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, - 0x6e, 0x74, 0x73, 0xca, 0x02, 0x18, 0x58, 0x6d, 0x74, 0x70, 0x5c, 0x4d, 0x6c, 0x73, 0x5c, 0x4d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0xe2, 0x02, - 0x24, 0x58, 0x6d, 0x74, 0x70, 0x5c, 0x4d, 0x6c, 0x73, 0x5c, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, - 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x1a, 0x58, 0x6d, 0x74, 0x70, 0x3a, 0x3a, 0x4d, 0x6c, - 0x73, 0x3a, 0x3a, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, - 0x74, 0x73, 0x4a, 0xd2, 0x04, 0x0a, 0x06, 0x12, 0x04, 0x01, 0x00, 0x16, 0x01, 0x0a, 0x22, 0x0a, - 0x01, 0x0c, 0x12, 0x03, 0x01, 0x00, 0x12, 0x1a, 0x18, 0x20, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x20, - 0x6d, 0x75, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, - 0x0a, 0x0a, 0x08, 0x0a, 0x01, 0x02, 0x12, 0x03, 0x03, 0x00, 0x22, 0x0a, 0x08, 0x0a, 0x01, 0x08, - 0x12, 0x03, 0x05, 0x00, 0x47, 0x0a, 0x09, 0x0a, 0x02, 0x08, 0x0b, 0x12, 0x03, 0x05, 0x00, 0x47, - 0x0a, 0x30, 0x0a, 0x02, 0x04, 0x00, 0x12, 0x04, 0x0a, 0x00, 0x11, 0x01, 0x1a, 0x24, 0x20, 0x4d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x67, 0x72, 0x6f, 0x75, 0x70, - 0x20, 0x6d, 0x75, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, - 0x61, 0x0a, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x00, 0x01, 0x12, 0x03, 0x0a, 0x08, 0x1e, 0x0a, 0x4a, - 0x0a, 0x04, 0x04, 0x00, 0x02, 0x00, 0x12, 0x03, 0x0c, 0x02, 0x25, 0x1a, 0x3d, 0x20, 0x4d, 0x61, - 0x70, 0x20, 0x74, 0x6f, 0x20, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x20, 0x76, 0x61, 0x72, 0x69, 0x6f, - 0x75, 0x73, 0x20, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x20, 0x61, 0x74, 0x74, 0x72, - 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x20, 0x28, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x20, 0x6e, 0x61, - 0x6d, 0x65, 0x2c, 0x20, 0x65, 0x74, 0x63, 0x2e, 0x29, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, - 0x02, 0x00, 0x06, 0x12, 0x03, 0x0c, 0x02, 0x15, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x00, - 0x01, 0x12, 0x03, 0x0c, 0x16, 0x20, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x00, 0x03, 0x12, - 0x03, 0x0c, 0x23, 0x24, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x00, 0x02, 0x01, 0x12, 0x03, 0x0d, 0x02, - 0x19, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x01, 0x06, 0x12, 0x03, 0x0d, 0x02, 0x09, 0x0a, - 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x01, 0x01, 0x12, 0x03, 0x0d, 0x0a, 0x14, 0x0a, 0x0c, 0x0a, - 0x05, 0x04, 0x00, 0x02, 0x01, 0x03, 0x12, 0x03, 0x0d, 0x17, 0x18, 0x0a, 0x64, 0x0a, 0x04, 0x04, - 0x00, 0x02, 0x02, 0x12, 0x03, 0x10, 0x02, 0x1f, 0x1a, 0x57, 0x20, 0x43, 0x72, 0x65, 0x61, 0x74, - 0x6f, 0x72, 0x20, 0x73, 0x74, 0x61, 0x72, 0x74, 0x73, 0x20, 0x61, 0x73, 0x20, 0x6f, 0x6e, 0x6c, - 0x79, 0x20, 0x73, 0x75, 0x70, 0x65, 0x72, 0x5f, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x0a, 0x20, 0x4f, - 0x6e, 0x6c, 0x79, 0x20, 0x73, 0x75, 0x70, 0x65, 0x72, 0x5f, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x20, - 0x63, 0x61, 0x6e, 0x20, 0x61, 0x64, 0x64, 0x2f, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x20, 0x6f, - 0x74, 0x68, 0x65, 0x72, 0x20, 0x73, 0x75, 0x70, 0x65, 0x72, 0x5f, 0x61, 0x64, 0x6d, 0x69, 0x6e, - 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x02, 0x06, 0x12, 0x03, 0x10, 0x02, 0x09, 0x0a, - 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x02, 0x01, 0x12, 0x03, 0x10, 0x0a, 0x1a, 0x0a, 0x0c, 0x0a, - 0x05, 0x04, 0x00, 0x02, 0x02, 0x03, 0x12, 0x03, 0x10, 0x1d, 0x1e, 0x0a, 0x39, 0x0a, 0x02, 0x04, - 0x01, 0x12, 0x04, 0x14, 0x00, 0x16, 0x01, 0x1a, 0x2d, 0x20, 0x57, 0x72, 0x61, 0x70, 0x70, 0x65, - 0x72, 0x20, 0x61, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x20, 0x61, 0x20, 0x6c, 0x69, 0x73, 0x74, 0x20, - 0x6f, 0x66, 0x20, 0x72, 0x65, 0x70, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x49, 0x6e, 0x62, 0x6f, - 0x78, 0x20, 0x49, 0x64, 0x73, 0x0a, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x01, 0x01, 0x12, 0x03, 0x14, - 0x08, 0x0f, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x01, 0x02, 0x00, 0x12, 0x03, 0x15, 0x02, 0x20, 0x0a, - 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x00, 0x04, 0x12, 0x03, 0x15, 0x02, 0x0a, 0x0a, 0x0c, 0x0a, - 0x05, 0x04, 0x01, 0x02, 0x00, 0x05, 0x12, 0x03, 0x15, 0x0b, 0x11, 0x0a, 0x0c, 0x0a, 0x05, 0x04, - 0x01, 0x02, 0x00, 0x01, 0x12, 0x03, 0x15, 0x12, 0x1b, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, - 0x00, 0x03, 0x12, 0x03, 0x15, 0x1e, 0x1f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, 0x0a, - 0xfb, 0x31, 0x0a, 0x2c, 0x6d, 0x6c, 0x73, 0x2f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, - 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2f, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x5f, 0x70, - 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x12, 0x19, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x22, 0x5d, 0x0a, 0x19, 0x47, - 0x72, 0x6f, 0x75, 0x70, 0x4d, 0x75, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x50, 0x65, 0x72, 0x6d, 0x69, - 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x56, 0x31, 0x12, 0x40, 0x0a, 0x08, 0x70, 0x6f, 0x6c, 0x69, - 0x63, 0x69, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x78, 0x6d, 0x74, - 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, - 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x53, 0x65, 0x74, - 0x52, 0x08, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x22, 0xdf, 0x05, 0x0a, 0x09, 0x50, - 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x53, 0x65, 0x74, 0x12, 0x57, 0x0a, 0x11, 0x61, 0x64, 0x64, 0x5f, - 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x5f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, - 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, - 0x52, 0x0f, 0x61, 0x64, 0x64, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x50, 0x6f, 0x6c, 0x69, 0x63, - 0x79, 0x12, 0x5d, 0x0a, 0x14, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x5f, 0x6d, 0x65, 0x6d, 0x62, - 0x65, 0x72, 0x5f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x2b, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x4d, 0x65, 0x6d, 0x62, - 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x12, 0x72, 0x65, - 0x6d, 0x6f, 0x76, 0x65, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, - 0x12, 0x74, 0x0a, 0x16, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, - 0x61, 0x74, 0x61, 0x5f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, - 0x32, 0x3e, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x50, 0x6f, 0x6c, - 0x69, 0x63, 0x79, 0x53, 0x65, 0x74, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4d, 0x65, 0x74, - 0x61, 0x64, 0x61, 0x74, 0x61, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x45, 0x6e, 0x74, 0x72, 0x79, - 0x52, 0x14, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, - 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x5c, 0x0a, 0x10, 0x61, 0x64, 0x64, 0x5f, 0x61, 0x64, - 0x6d, 0x69, 0x6e, 0x5f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x32, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x50, 0x65, 0x72, - 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, 0x6f, - 0x6c, 0x69, 0x63, 0x79, 0x52, 0x0e, 0x61, 0x64, 0x64, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x50, 0x6f, - 0x6c, 0x69, 0x63, 0x79, 0x12, 0x62, 0x0a, 0x13, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x5f, 0x61, - 0x64, 0x6d, 0x69, 0x6e, 0x5f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x32, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x50, 0x65, - 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, - 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x11, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x41, 0x64, 0x6d, - 0x69, 0x6e, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x6e, 0x0a, 0x19, 0x75, 0x70, 0x64, 0x61, - 0x74, 0x65, 0x5f, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x5f, 0x70, - 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x32, 0x2e, 0x78, 0x6d, - 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, - 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, - 0x6f, 0x6e, 0x73, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, - 0x17, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, - 0x6e, 0x73, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x1a, 0x72, 0x0a, 0x19, 0x55, 0x70, 0x64, 0x61, - 0x74, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, - 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x3f, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, - 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, - 0x74, 0x73, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x50, 0x6f, 0x6c, 0x69, 0x63, - 0x79, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x8a, 0x05, 0x0a, - 0x10, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x50, 0x6f, 0x6c, 0x69, 0x63, - 0x79, 0x12, 0x4c, 0x0a, 0x04, 0x62, 0x61, 0x73, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, - 0x36, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x4d, 0x65, 0x6d, 0x62, - 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x42, 0x61, 0x73, - 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x48, 0x00, 0x52, 0x04, 0x62, 0x61, 0x73, 0x65, 0x12, - 0x5f, 0x0a, 0x0d, 0x61, 0x6e, 0x64, 0x5f, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x38, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, - 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, - 0x74, 0x73, 0x2e, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x50, 0x6f, 0x6c, - 0x69, 0x63, 0x79, 0x2e, 0x41, 0x6e, 0x64, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, - 0x48, 0x00, 0x52, 0x0c, 0x61, 0x6e, 0x64, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, - 0x12, 0x5f, 0x0a, 0x0d, 0x61, 0x6e, 0x79, 0x5f, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, - 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x38, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, - 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, - 0x6e, 0x74, 0x73, 0x2e, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x50, 0x6f, - 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x41, 0x6e, 0x79, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, - 0x6e, 0x48, 0x00, 0x52, 0x0c, 0x61, 0x6e, 0x79, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, - 0x6e, 0x1a, 0x57, 0x0a, 0x0c, 0x41, 0x6e, 0x64, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, - 0x6e, 0x12, 0x47, 0x0a, 0x08, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x18, 0x01, 0x20, - 0x03, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, - 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, - 0x52, 0x08, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x1a, 0x57, 0x0a, 0x0c, 0x41, 0x6e, - 0x79, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x47, 0x0a, 0x08, 0x70, 0x6f, - 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x78, - 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, - 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, - 0x68, 0x69, 0x70, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x08, 0x70, 0x6f, 0x6c, 0x69, 0x63, - 0x69, 0x65, 0x73, 0x22, 0xab, 0x01, 0x0a, 0x0a, 0x42, 0x61, 0x73, 0x65, 0x50, 0x6f, 0x6c, 0x69, - 0x63, 0x79, 0x12, 0x1b, 0x0a, 0x17, 0x42, 0x41, 0x53, 0x45, 0x5f, 0x50, 0x4f, 0x4c, 0x49, 0x43, - 0x59, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, - 0x15, 0x0a, 0x11, 0x42, 0x41, 0x53, 0x45, 0x5f, 0x50, 0x4f, 0x4c, 0x49, 0x43, 0x59, 0x5f, 0x41, - 0x4c, 0x4c, 0x4f, 0x57, 0x10, 0x01, 0x12, 0x14, 0x0a, 0x10, 0x42, 0x41, 0x53, 0x45, 0x5f, 0x50, - 0x4f, 0x4c, 0x49, 0x43, 0x59, 0x5f, 0x44, 0x45, 0x4e, 0x59, 0x10, 0x02, 0x12, 0x2d, 0x0a, 0x29, - 0x42, 0x41, 0x53, 0x45, 0x5f, 0x50, 0x4f, 0x4c, 0x49, 0x43, 0x59, 0x5f, 0x41, 0x4c, 0x4c, 0x4f, - 0x57, 0x5f, 0x49, 0x46, 0x5f, 0x41, 0x44, 0x4d, 0x49, 0x4e, 0x5f, 0x4f, 0x52, 0x5f, 0x53, 0x55, - 0x50, 0x45, 0x52, 0x5f, 0x41, 0x44, 0x4d, 0x49, 0x4e, 0x10, 0x03, 0x12, 0x24, 0x0a, 0x20, 0x42, - 0x41, 0x53, 0x45, 0x5f, 0x50, 0x4f, 0x4c, 0x49, 0x43, 0x59, 0x5f, 0x41, 0x4c, 0x4c, 0x4f, 0x57, - 0x5f, 0x49, 0x46, 0x5f, 0x53, 0x55, 0x50, 0x45, 0x52, 0x5f, 0x41, 0x44, 0x4d, 0x49, 0x4e, 0x10, - 0x04, 0x42, 0x06, 0x0a, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x22, 0xac, 0x05, 0x0a, 0x0e, 0x4d, 0x65, - 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x52, 0x0a, 0x04, - 0x62, 0x61, 0x73, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x3c, 0x2e, 0x78, 0x6d, 0x74, - 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, - 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x50, - 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x42, 0x61, - 0x73, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x48, 0x00, 0x52, 0x04, 0x62, 0x61, 0x73, 0x65, - 0x12, 0x5d, 0x0a, 0x0d, 0x61, 0x6e, 0x64, 0x5f, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, - 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x36, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, - 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, - 0x6e, 0x74, 0x73, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x50, 0x6f, 0x6c, 0x69, - 0x63, 0x79, 0x2e, 0x41, 0x6e, 0x64, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x48, - 0x00, 0x52, 0x0c, 0x61, 0x6e, 0x64, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, - 0x5d, 0x0a, 0x0d, 0x61, 0x6e, 0x79, 0x5f, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x36, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, - 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, - 0x74, 0x73, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x50, 0x6f, 0x6c, 0x69, 0x63, - 0x79, 0x2e, 0x41, 0x6e, 0x79, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x00, - 0x52, 0x0c, 0x61, 0x6e, 0x79, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x1a, 0x55, - 0x0a, 0x0c, 0x41, 0x6e, 0x64, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x45, - 0x0a, 0x08, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, - 0x32, 0x29, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x4d, 0x65, 0x74, - 0x61, 0x64, 0x61, 0x74, 0x61, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x08, 0x70, 0x6f, 0x6c, - 0x69, 0x63, 0x69, 0x65, 0x73, 0x1a, 0x55, 0x0a, 0x0c, 0x41, 0x6e, 0x79, 0x43, 0x6f, 0x6e, 0x64, - 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x45, 0x0a, 0x08, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, - 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, - 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, - 0x6e, 0x74, 0x73, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x50, 0x6f, 0x6c, 0x69, - 0x63, 0x79, 0x52, 0x08, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x22, 0xd1, 0x01, 0x0a, - 0x12, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x42, 0x61, 0x73, 0x65, 0x50, 0x6f, 0x6c, - 0x69, 0x63, 0x79, 0x12, 0x24, 0x0a, 0x20, 0x4d, 0x45, 0x54, 0x41, 0x44, 0x41, 0x54, 0x41, 0x5f, - 0x42, 0x41, 0x53, 0x45, 0x5f, 0x50, 0x4f, 0x4c, 0x49, 0x43, 0x59, 0x5f, 0x55, 0x4e, 0x53, 0x50, - 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x1e, 0x0a, 0x1a, 0x4d, 0x45, 0x54, - 0x41, 0x44, 0x41, 0x54, 0x41, 0x5f, 0x42, 0x41, 0x53, 0x45, 0x5f, 0x50, 0x4f, 0x4c, 0x49, 0x43, - 0x59, 0x5f, 0x41, 0x4c, 0x4c, 0x4f, 0x57, 0x10, 0x01, 0x12, 0x1d, 0x0a, 0x19, 0x4d, 0x45, 0x54, - 0x41, 0x44, 0x41, 0x54, 0x41, 0x5f, 0x42, 0x41, 0x53, 0x45, 0x5f, 0x50, 0x4f, 0x4c, 0x49, 0x43, - 0x59, 0x5f, 0x44, 0x45, 0x4e, 0x59, 0x10, 0x02, 0x12, 0x27, 0x0a, 0x23, 0x4d, 0x45, 0x54, 0x41, - 0x44, 0x41, 0x54, 0x41, 0x5f, 0x42, 0x41, 0x53, 0x45, 0x5f, 0x50, 0x4f, 0x4c, 0x49, 0x43, 0x59, - 0x5f, 0x41, 0x4c, 0x4c, 0x4f, 0x57, 0x5f, 0x49, 0x46, 0x5f, 0x41, 0x44, 0x4d, 0x49, 0x4e, 0x10, - 0x03, 0x12, 0x2d, 0x0a, 0x29, 0x4d, 0x45, 0x54, 0x41, 0x44, 0x41, 0x54, 0x41, 0x5f, 0x42, 0x41, - 0x53, 0x45, 0x5f, 0x50, 0x4f, 0x4c, 0x49, 0x43, 0x59, 0x5f, 0x41, 0x4c, 0x4c, 0x4f, 0x57, 0x5f, - 0x49, 0x46, 0x5f, 0x53, 0x55, 0x50, 0x45, 0x52, 0x5f, 0x41, 0x44, 0x4d, 0x49, 0x4e, 0x10, 0x04, - 0x42, 0x06, 0x0a, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x22, 0xd4, 0x05, 0x0a, 0x17, 0x50, 0x65, 0x72, - 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, 0x6f, - 0x6c, 0x69, 0x63, 0x79, 0x12, 0x5e, 0x0a, 0x04, 0x62, 0x61, 0x73, 0x65, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x0e, 0x32, 0x48, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x50, - 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, - 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, - 0x6e, 0x73, 0x42, 0x61, 0x73, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x48, 0x00, 0x52, 0x04, - 0x62, 0x61, 0x73, 0x65, 0x12, 0x66, 0x0a, 0x0d, 0x61, 0x6e, 0x64, 0x5f, 0x63, 0x6f, 0x6e, 0x64, - 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3f, 0x2e, 0x78, 0x6d, - 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, - 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, - 0x6f, 0x6e, 0x73, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, - 0x41, 0x6e, 0x64, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x0c, - 0x61, 0x6e, 0x64, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x66, 0x0a, 0x0d, - 0x61, 0x6e, 0x79, 0x5f, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x3f, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, - 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x55, 0x70, 0x64, 0x61, 0x74, - 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x41, 0x6e, 0x79, 0x43, 0x6f, 0x6e, 0x64, 0x69, - 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x0c, 0x61, 0x6e, 0x79, 0x43, 0x6f, 0x6e, 0x64, 0x69, - 0x74, 0x69, 0x6f, 0x6e, 0x1a, 0x5e, 0x0a, 0x0c, 0x41, 0x6e, 0x64, 0x43, 0x6f, 0x6e, 0x64, 0x69, - 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x4e, 0x0a, 0x08, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, - 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x32, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, - 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, - 0x74, 0x73, 0x2e, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x55, 0x70, - 0x64, 0x61, 0x74, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x08, 0x70, 0x6f, 0x6c, 0x69, - 0x63, 0x69, 0x65, 0x73, 0x1a, 0x5e, 0x0a, 0x0c, 0x41, 0x6e, 0x79, 0x43, 0x6f, 0x6e, 0x64, 0x69, - 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x4e, 0x0a, 0x08, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, - 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x32, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, - 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, - 0x74, 0x73, 0x2e, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x55, 0x70, - 0x64, 0x61, 0x74, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x08, 0x70, 0x6f, 0x6c, 0x69, - 0x63, 0x69, 0x65, 0x73, 0x22, 0xc0, 0x01, 0x0a, 0x15, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, - 0x69, 0x6f, 0x6e, 0x73, 0x42, 0x61, 0x73, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x27, - 0x0a, 0x23, 0x50, 0x45, 0x52, 0x4d, 0x49, 0x53, 0x53, 0x49, 0x4f, 0x4e, 0x53, 0x5f, 0x42, 0x41, - 0x53, 0x45, 0x5f, 0x50, 0x4f, 0x4c, 0x49, 0x43, 0x59, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, - 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x20, 0x0a, 0x1c, 0x50, 0x45, 0x52, 0x4d, 0x49, - 0x53, 0x53, 0x49, 0x4f, 0x4e, 0x53, 0x5f, 0x42, 0x41, 0x53, 0x45, 0x5f, 0x50, 0x4f, 0x4c, 0x49, - 0x43, 0x59, 0x5f, 0x44, 0x45, 0x4e, 0x59, 0x10, 0x01, 0x12, 0x2a, 0x0a, 0x26, 0x50, 0x45, 0x52, - 0x4d, 0x49, 0x53, 0x53, 0x49, 0x4f, 0x4e, 0x53, 0x5f, 0x42, 0x41, 0x53, 0x45, 0x5f, 0x50, 0x4f, - 0x4c, 0x49, 0x43, 0x59, 0x5f, 0x41, 0x4c, 0x4c, 0x4f, 0x57, 0x5f, 0x49, 0x46, 0x5f, 0x41, 0x44, - 0x4d, 0x49, 0x4e, 0x10, 0x02, 0x12, 0x30, 0x0a, 0x2c, 0x50, 0x45, 0x52, 0x4d, 0x49, 0x53, 0x53, - 0x49, 0x4f, 0x4e, 0x53, 0x5f, 0x42, 0x41, 0x53, 0x45, 0x5f, 0x50, 0x4f, 0x4c, 0x49, 0x43, 0x59, - 0x5f, 0x41, 0x4c, 0x4c, 0x4f, 0x57, 0x5f, 0x49, 0x46, 0x5f, 0x53, 0x55, 0x50, 0x45, 0x52, 0x5f, - 0x41, 0x44, 0x4d, 0x49, 0x4e, 0x10, 0x03, 0x42, 0x06, 0x0a, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x42, - 0xea, 0x01, 0x0a, 0x1d, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, - 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, - 0x73, 0x42, 0x15, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, - 0x6f, 0x6e, 0x73, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x30, 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, 0x6d, 0x6c, 0x73, 0x2f, 0x6d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0xa2, 0x02, 0x03, 0x58, - 0x4d, 0x4d, 0xaa, 0x02, 0x18, 0x58, 0x6d, 0x74, 0x70, 0x2e, 0x4d, 0x6c, 0x73, 0x2e, 0x4d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0xca, 0x02, 0x18, - 0x58, 0x6d, 0x74, 0x70, 0x5c, 0x4d, 0x6c, 0x73, 0x5c, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0xe2, 0x02, 0x24, 0x58, 0x6d, 0x74, 0x70, 0x5c, - 0x4d, 0x6c, 0x73, 0x5c, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, - 0x6e, 0x74, 0x73, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, - 0x02, 0x1a, 0x58, 0x6d, 0x74, 0x70, 0x3a, 0x3a, 0x4d, 0x6c, 0x73, 0x3a, 0x3a, 0x4d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x4a, 0xe6, 0x18, 0x0a, - 0x06, 0x12, 0x04, 0x01, 0x00, 0x68, 0x01, 0x0a, 0x2e, 0x0a, 0x01, 0x0c, 0x12, 0x03, 0x01, 0x00, - 0x12, 0x1a, 0x24, 0x20, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x20, 0x6d, 0x75, 0x74, 0x61, 0x62, 0x6c, - 0x65, 0x20, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x6d, 0x65, - 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x0a, 0x0a, 0x08, 0x0a, 0x01, 0x02, 0x12, 0x03, 0x03, 0x00, - 0x22, 0x0a, 0x08, 0x0a, 0x01, 0x08, 0x12, 0x03, 0x05, 0x00, 0x47, 0x0a, 0x09, 0x0a, 0x02, 0x08, - 0x0b, 0x12, 0x03, 0x05, 0x00, 0x47, 0x0a, 0x30, 0x0a, 0x02, 0x04, 0x00, 0x12, 0x04, 0x09, 0x00, - 0x0b, 0x01, 0x1a, 0x24, 0x20, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x20, 0x66, 0x6f, 0x72, - 0x20, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x20, 0x6d, 0x75, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x6d, - 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x0a, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x00, 0x01, 0x12, - 0x03, 0x09, 0x08, 0x21, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x00, 0x02, 0x00, 0x12, 0x03, 0x0a, 0x02, - 0x19, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x00, 0x06, 0x12, 0x03, 0x0a, 0x02, 0x0b, 0x0a, - 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x00, 0x01, 0x12, 0x03, 0x0a, 0x0c, 0x14, 0x0a, 0x0c, 0x0a, - 0x05, 0x04, 0x00, 0x02, 0x00, 0x03, 0x12, 0x03, 0x0a, 0x17, 0x18, 0x0a, 0x37, 0x0a, 0x02, 0x04, - 0x01, 0x12, 0x04, 0x0e, 0x00, 0x15, 0x01, 0x1a, 0x2b, 0x20, 0x54, 0x68, 0x65, 0x20, 0x73, 0x65, - 0x74, 0x20, 0x6f, 0x66, 0x20, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x20, 0x74, 0x68, - 0x61, 0x74, 0x20, 0x67, 0x6f, 0x76, 0x65, 0x72, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x67, 0x72, - 0x6f, 0x75, 0x70, 0x0a, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x01, 0x01, 0x12, 0x03, 0x0e, 0x08, 0x11, - 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x01, 0x02, 0x00, 0x12, 0x03, 0x0f, 0x02, 0x29, 0x0a, 0x0c, 0x0a, - 0x05, 0x04, 0x01, 0x02, 0x00, 0x06, 0x12, 0x03, 0x0f, 0x02, 0x12, 0x0a, 0x0c, 0x0a, 0x05, 0x04, - 0x01, 0x02, 0x00, 0x01, 0x12, 0x03, 0x0f, 0x13, 0x24, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, - 0x00, 0x03, 0x12, 0x03, 0x0f, 0x27, 0x28, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x01, 0x02, 0x01, 0x12, - 0x03, 0x10, 0x02, 0x2c, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x01, 0x06, 0x12, 0x03, 0x10, - 0x02, 0x12, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x01, 0x01, 0x12, 0x03, 0x10, 0x13, 0x27, - 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x01, 0x03, 0x12, 0x03, 0x10, 0x2a, 0x2b, 0x0a, 0x0b, - 0x0a, 0x04, 0x04, 0x01, 0x02, 0x02, 0x12, 0x03, 0x11, 0x02, 0x39, 0x0a, 0x0c, 0x0a, 0x05, 0x04, - 0x01, 0x02, 0x02, 0x06, 0x12, 0x03, 0x11, 0x02, 0x1d, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, - 0x02, 0x01, 0x12, 0x03, 0x11, 0x1e, 0x34, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x02, 0x03, - 0x12, 0x03, 0x11, 0x37, 0x38, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x01, 0x02, 0x03, 0x12, 0x03, 0x12, - 0x02, 0x2f, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x03, 0x06, 0x12, 0x03, 0x12, 0x02, 0x19, - 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x03, 0x01, 0x12, 0x03, 0x12, 0x1a, 0x2a, 0x0a, 0x0c, - 0x0a, 0x05, 0x04, 0x01, 0x02, 0x03, 0x03, 0x12, 0x03, 0x12, 0x2d, 0x2e, 0x0a, 0x0b, 0x0a, 0x04, - 0x04, 0x01, 0x02, 0x04, 0x12, 0x03, 0x13, 0x02, 0x32, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, - 0x04, 0x06, 0x12, 0x03, 0x13, 0x02, 0x19, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x04, 0x01, - 0x12, 0x03, 0x13, 0x1a, 0x2d, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x04, 0x03, 0x12, 0x03, - 0x13, 0x30, 0x31, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x01, 0x02, 0x05, 0x12, 0x03, 0x14, 0x02, 0x38, - 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x05, 0x06, 0x12, 0x03, 0x14, 0x02, 0x19, 0x0a, 0x0c, - 0x0a, 0x05, 0x04, 0x01, 0x02, 0x05, 0x01, 0x12, 0x03, 0x14, 0x1a, 0x33, 0x0a, 0x0c, 0x0a, 0x05, - 0x04, 0x01, 0x02, 0x05, 0x03, 0x12, 0x03, 0x14, 0x36, 0x37, 0x0a, 0x4c, 0x0a, 0x02, 0x04, 0x02, - 0x12, 0x04, 0x18, 0x00, 0x31, 0x01, 0x1a, 0x40, 0x20, 0x41, 0x20, 0x70, 0x6f, 0x6c, 0x69, 0x63, - 0x79, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x67, 0x6f, 0x76, 0x65, 0x72, 0x6e, 0x73, 0x20, 0x61, - 0x64, 0x64, 0x69, 0x6e, 0x67, 0x2f, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x69, 0x6e, 0x67, 0x20, 0x6d, - 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x20, 0x6f, 0x72, 0x20, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, - 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x0a, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x02, 0x01, 0x12, - 0x03, 0x18, 0x08, 0x18, 0x0a, 0x1b, 0x0a, 0x04, 0x04, 0x02, 0x04, 0x00, 0x12, 0x04, 0x1a, 0x02, - 0x20, 0x03, 0x1a, 0x0d, 0x20, 0x42, 0x61, 0x73, 0x65, 0x20, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, - 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x04, 0x00, 0x01, 0x12, 0x03, 0x1a, 0x07, 0x11, 0x0a, - 0x0d, 0x0a, 0x06, 0x04, 0x02, 0x04, 0x00, 0x02, 0x00, 0x12, 0x03, 0x1b, 0x04, 0x20, 0x0a, 0x0e, - 0x0a, 0x07, 0x04, 0x02, 0x04, 0x00, 0x02, 0x00, 0x01, 0x12, 0x03, 0x1b, 0x04, 0x1b, 0x0a, 0x0e, - 0x0a, 0x07, 0x04, 0x02, 0x04, 0x00, 0x02, 0x00, 0x02, 0x12, 0x03, 0x1b, 0x1e, 0x1f, 0x0a, 0x0d, - 0x0a, 0x06, 0x04, 0x02, 0x04, 0x00, 0x02, 0x01, 0x12, 0x03, 0x1c, 0x04, 0x1a, 0x0a, 0x0e, 0x0a, - 0x07, 0x04, 0x02, 0x04, 0x00, 0x02, 0x01, 0x01, 0x12, 0x03, 0x1c, 0x04, 0x15, 0x0a, 0x0e, 0x0a, - 0x07, 0x04, 0x02, 0x04, 0x00, 0x02, 0x01, 0x02, 0x12, 0x03, 0x1c, 0x18, 0x19, 0x0a, 0x0d, 0x0a, - 0x06, 0x04, 0x02, 0x04, 0x00, 0x02, 0x02, 0x12, 0x03, 0x1d, 0x04, 0x19, 0x0a, 0x0e, 0x0a, 0x07, - 0x04, 0x02, 0x04, 0x00, 0x02, 0x02, 0x01, 0x12, 0x03, 0x1d, 0x04, 0x14, 0x0a, 0x0e, 0x0a, 0x07, - 0x04, 0x02, 0x04, 0x00, 0x02, 0x02, 0x02, 0x12, 0x03, 0x1d, 0x17, 0x18, 0x0a, 0x0d, 0x0a, 0x06, - 0x04, 0x02, 0x04, 0x00, 0x02, 0x03, 0x12, 0x03, 0x1e, 0x04, 0x32, 0x0a, 0x0e, 0x0a, 0x07, 0x04, - 0x02, 0x04, 0x00, 0x02, 0x03, 0x01, 0x12, 0x03, 0x1e, 0x04, 0x2d, 0x0a, 0x0e, 0x0a, 0x07, 0x04, - 0x02, 0x04, 0x00, 0x02, 0x03, 0x02, 0x12, 0x03, 0x1e, 0x30, 0x31, 0x0a, 0x0d, 0x0a, 0x06, 0x04, - 0x02, 0x04, 0x00, 0x02, 0x04, 0x12, 0x03, 0x1f, 0x04, 0x29, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, - 0x04, 0x00, 0x02, 0x04, 0x01, 0x12, 0x03, 0x1f, 0x04, 0x24, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, - 0x04, 0x00, 0x02, 0x04, 0x02, 0x12, 0x03, 0x1f, 0x27, 0x28, 0x0a, 0x44, 0x0a, 0x04, 0x04, 0x02, - 0x03, 0x00, 0x12, 0x04, 0x23, 0x02, 0x25, 0x03, 0x1a, 0x36, 0x20, 0x43, 0x6f, 0x6d, 0x62, 0x69, - 0x6e, 0x65, 0x20, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x20, 0x70, 0x6f, 0x6c, 0x69, - 0x63, 0x69, 0x65, 0x73, 0x2e, 0x20, 0x41, 0x6c, 0x6c, 0x20, 0x6d, 0x75, 0x73, 0x74, 0x20, 0x65, - 0x76, 0x61, 0x6c, 0x75, 0x61, 0x74, 0x65, 0x20, 0x74, 0x6f, 0x20, 0x74, 0x72, 0x75, 0x65, 0x0a, - 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x03, 0x00, 0x01, 0x12, 0x03, 0x23, 0x0a, 0x16, 0x0a, 0x0d, - 0x0a, 0x06, 0x04, 0x02, 0x03, 0x00, 0x02, 0x00, 0x12, 0x03, 0x24, 0x04, 0x2b, 0x0a, 0x0e, 0x0a, - 0x07, 0x04, 0x02, 0x03, 0x00, 0x02, 0x00, 0x04, 0x12, 0x03, 0x24, 0x04, 0x0c, 0x0a, 0x0e, 0x0a, - 0x07, 0x04, 0x02, 0x03, 0x00, 0x02, 0x00, 0x06, 0x12, 0x03, 0x24, 0x0d, 0x1d, 0x0a, 0x0e, 0x0a, - 0x07, 0x04, 0x02, 0x03, 0x00, 0x02, 0x00, 0x01, 0x12, 0x03, 0x24, 0x1e, 0x26, 0x0a, 0x0e, 0x0a, - 0x07, 0x04, 0x02, 0x03, 0x00, 0x02, 0x00, 0x03, 0x12, 0x03, 0x24, 0x29, 0x2a, 0x0a, 0x44, 0x0a, - 0x04, 0x04, 0x02, 0x03, 0x01, 0x12, 0x04, 0x28, 0x02, 0x2a, 0x03, 0x1a, 0x36, 0x20, 0x43, 0x6f, - 0x6d, 0x62, 0x69, 0x6e, 0x65, 0x20, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x20, 0x70, - 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x2e, 0x20, 0x41, 0x6e, 0x79, 0x20, 0x6d, 0x75, 0x73, - 0x74, 0x20, 0x65, 0x76, 0x61, 0x6c, 0x75, 0x61, 0x74, 0x65, 0x20, 0x74, 0x6f, 0x20, 0x74, 0x72, - 0x75, 0x65, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x03, 0x01, 0x01, 0x12, 0x03, 0x28, 0x0a, - 0x16, 0x0a, 0x0d, 0x0a, 0x06, 0x04, 0x02, 0x03, 0x01, 0x02, 0x00, 0x12, 0x03, 0x29, 0x04, 0x2b, - 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, 0x01, 0x02, 0x00, 0x04, 0x12, 0x03, 0x29, 0x04, 0x0c, - 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, 0x01, 0x02, 0x00, 0x06, 0x12, 0x03, 0x29, 0x0d, 0x1d, - 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, 0x01, 0x02, 0x00, 0x01, 0x12, 0x03, 0x29, 0x1e, 0x26, - 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, 0x01, 0x02, 0x00, 0x03, 0x12, 0x03, 0x29, 0x29, 0x2a, - 0x0a, 0x0c, 0x0a, 0x04, 0x04, 0x02, 0x08, 0x00, 0x12, 0x04, 0x2c, 0x02, 0x30, 0x03, 0x0a, 0x0c, - 0x0a, 0x05, 0x04, 0x02, 0x08, 0x00, 0x01, 0x12, 0x03, 0x2c, 0x08, 0x0c, 0x0a, 0x0b, 0x0a, 0x04, - 0x04, 0x02, 0x02, 0x00, 0x12, 0x03, 0x2d, 0x04, 0x18, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, - 0x00, 0x06, 0x12, 0x03, 0x2d, 0x04, 0x0e, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x00, 0x01, - 0x12, 0x03, 0x2d, 0x0f, 0x13, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x00, 0x03, 0x12, 0x03, - 0x2d, 0x16, 0x17, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x02, 0x02, 0x01, 0x12, 0x03, 0x2e, 0x04, 0x23, - 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x01, 0x06, 0x12, 0x03, 0x2e, 0x04, 0x10, 0x0a, 0x0c, - 0x0a, 0x05, 0x04, 0x02, 0x02, 0x01, 0x01, 0x12, 0x03, 0x2e, 0x11, 0x1e, 0x0a, 0x0c, 0x0a, 0x05, - 0x04, 0x02, 0x02, 0x01, 0x03, 0x12, 0x03, 0x2e, 0x21, 0x22, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x02, - 0x02, 0x02, 0x12, 0x03, 0x2f, 0x04, 0x23, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x02, 0x06, - 0x12, 0x03, 0x2f, 0x04, 0x10, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x02, 0x01, 0x12, 0x03, - 0x2f, 0x11, 0x1e, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x02, 0x03, 0x12, 0x03, 0x2f, 0x21, - 0x22, 0x0a, 0x35, 0x0a, 0x02, 0x04, 0x03, 0x12, 0x04, 0x34, 0x00, 0x4d, 0x01, 0x1a, 0x29, 0x20, - 0x41, 0x20, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x67, 0x6f, - 0x76, 0x65, 0x72, 0x6e, 0x73, 0x20, 0x75, 0x70, 0x64, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x20, 0x6d, - 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x0a, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x03, 0x01, 0x12, - 0x03, 0x34, 0x08, 0x16, 0x0a, 0x1b, 0x0a, 0x04, 0x04, 0x03, 0x04, 0x00, 0x12, 0x04, 0x36, 0x02, - 0x3c, 0x03, 0x1a, 0x0d, 0x20, 0x42, 0x61, 0x73, 0x65, 0x20, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, - 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x04, 0x00, 0x01, 0x12, 0x03, 0x36, 0x07, 0x19, 0x0a, - 0x0d, 0x0a, 0x06, 0x04, 0x03, 0x04, 0x00, 0x02, 0x00, 0x12, 0x03, 0x37, 0x04, 0x29, 0x0a, 0x0e, - 0x0a, 0x07, 0x04, 0x03, 0x04, 0x00, 0x02, 0x00, 0x01, 0x12, 0x03, 0x37, 0x04, 0x24, 0x0a, 0x0e, - 0x0a, 0x07, 0x04, 0x03, 0x04, 0x00, 0x02, 0x00, 0x02, 0x12, 0x03, 0x37, 0x27, 0x28, 0x0a, 0x0d, - 0x0a, 0x06, 0x04, 0x03, 0x04, 0x00, 0x02, 0x01, 0x12, 0x03, 0x38, 0x04, 0x23, 0x0a, 0x0e, 0x0a, - 0x07, 0x04, 0x03, 0x04, 0x00, 0x02, 0x01, 0x01, 0x12, 0x03, 0x38, 0x04, 0x1e, 0x0a, 0x0e, 0x0a, - 0x07, 0x04, 0x03, 0x04, 0x00, 0x02, 0x01, 0x02, 0x12, 0x03, 0x38, 0x21, 0x22, 0x0a, 0x0d, 0x0a, - 0x06, 0x04, 0x03, 0x04, 0x00, 0x02, 0x02, 0x12, 0x03, 0x39, 0x04, 0x22, 0x0a, 0x0e, 0x0a, 0x07, - 0x04, 0x03, 0x04, 0x00, 0x02, 0x02, 0x01, 0x12, 0x03, 0x39, 0x04, 0x1d, 0x0a, 0x0e, 0x0a, 0x07, - 0x04, 0x03, 0x04, 0x00, 0x02, 0x02, 0x02, 0x12, 0x03, 0x39, 0x20, 0x21, 0x0a, 0x0d, 0x0a, 0x06, - 0x04, 0x03, 0x04, 0x00, 0x02, 0x03, 0x12, 0x03, 0x3a, 0x04, 0x2c, 0x0a, 0x0e, 0x0a, 0x07, 0x04, - 0x03, 0x04, 0x00, 0x02, 0x03, 0x01, 0x12, 0x03, 0x3a, 0x04, 0x27, 0x0a, 0x0e, 0x0a, 0x07, 0x04, - 0x03, 0x04, 0x00, 0x02, 0x03, 0x02, 0x12, 0x03, 0x3a, 0x2a, 0x2b, 0x0a, 0x0d, 0x0a, 0x06, 0x04, - 0x03, 0x04, 0x00, 0x02, 0x04, 0x12, 0x03, 0x3b, 0x04, 0x32, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x03, - 0x04, 0x00, 0x02, 0x04, 0x01, 0x12, 0x03, 0x3b, 0x04, 0x2d, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x03, - 0x04, 0x00, 0x02, 0x04, 0x02, 0x12, 0x03, 0x3b, 0x30, 0x31, 0x0a, 0x44, 0x0a, 0x04, 0x04, 0x03, - 0x03, 0x00, 0x12, 0x04, 0x3f, 0x02, 0x41, 0x03, 0x1a, 0x36, 0x20, 0x43, 0x6f, 0x6d, 0x62, 0x69, - 0x6e, 0x65, 0x20, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x20, 0x70, 0x6f, 0x6c, 0x69, - 0x63, 0x69, 0x65, 0x73, 0x2e, 0x20, 0x41, 0x6c, 0x6c, 0x20, 0x6d, 0x75, 0x73, 0x74, 0x20, 0x65, - 0x76, 0x61, 0x6c, 0x75, 0x61, 0x74, 0x65, 0x20, 0x74, 0x6f, 0x20, 0x74, 0x72, 0x75, 0x65, 0x0a, - 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x03, 0x00, 0x01, 0x12, 0x03, 0x3f, 0x0a, 0x16, 0x0a, 0x0d, - 0x0a, 0x06, 0x04, 0x03, 0x03, 0x00, 0x02, 0x00, 0x12, 0x03, 0x40, 0x04, 0x29, 0x0a, 0x0e, 0x0a, - 0x07, 0x04, 0x03, 0x03, 0x00, 0x02, 0x00, 0x04, 0x12, 0x03, 0x40, 0x04, 0x0c, 0x0a, 0x0e, 0x0a, - 0x07, 0x04, 0x03, 0x03, 0x00, 0x02, 0x00, 0x06, 0x12, 0x03, 0x40, 0x0d, 0x1b, 0x0a, 0x0e, 0x0a, - 0x07, 0x04, 0x03, 0x03, 0x00, 0x02, 0x00, 0x01, 0x12, 0x03, 0x40, 0x1c, 0x24, 0x0a, 0x0e, 0x0a, - 0x07, 0x04, 0x03, 0x03, 0x00, 0x02, 0x00, 0x03, 0x12, 0x03, 0x40, 0x27, 0x28, 0x0a, 0x44, 0x0a, - 0x04, 0x04, 0x03, 0x03, 0x01, 0x12, 0x04, 0x44, 0x02, 0x46, 0x03, 0x1a, 0x36, 0x20, 0x43, 0x6f, - 0x6d, 0x62, 0x69, 0x6e, 0x65, 0x20, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x20, 0x70, - 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x2e, 0x20, 0x41, 0x6e, 0x79, 0x20, 0x6d, 0x75, 0x73, - 0x74, 0x20, 0x65, 0x76, 0x61, 0x6c, 0x75, 0x61, 0x74, 0x65, 0x20, 0x74, 0x6f, 0x20, 0x74, 0x72, - 0x75, 0x65, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x03, 0x01, 0x01, 0x12, 0x03, 0x44, 0x0a, - 0x16, 0x0a, 0x0d, 0x0a, 0x06, 0x04, 0x03, 0x03, 0x01, 0x02, 0x00, 0x12, 0x03, 0x45, 0x04, 0x29, - 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x03, 0x03, 0x01, 0x02, 0x00, 0x04, 0x12, 0x03, 0x45, 0x04, 0x0c, - 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x03, 0x03, 0x01, 0x02, 0x00, 0x06, 0x12, 0x03, 0x45, 0x0d, 0x1b, - 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x03, 0x03, 0x01, 0x02, 0x00, 0x01, 0x12, 0x03, 0x45, 0x1c, 0x24, - 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x03, 0x03, 0x01, 0x02, 0x00, 0x03, 0x12, 0x03, 0x45, 0x27, 0x28, - 0x0a, 0x0c, 0x0a, 0x04, 0x04, 0x03, 0x08, 0x00, 0x12, 0x04, 0x48, 0x02, 0x4c, 0x03, 0x0a, 0x0c, - 0x0a, 0x05, 0x04, 0x03, 0x08, 0x00, 0x01, 0x12, 0x03, 0x48, 0x08, 0x0c, 0x0a, 0x0b, 0x0a, 0x04, - 0x04, 0x03, 0x02, 0x00, 0x12, 0x03, 0x49, 0x04, 0x20, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, - 0x00, 0x06, 0x12, 0x03, 0x49, 0x04, 0x16, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, 0x00, 0x01, - 0x12, 0x03, 0x49, 0x17, 0x1b, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, 0x00, 0x03, 0x12, 0x03, - 0x49, 0x1e, 0x1f, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x03, 0x02, 0x01, 0x12, 0x03, 0x4a, 0x04, 0x23, - 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, 0x01, 0x06, 0x12, 0x03, 0x4a, 0x04, 0x10, 0x0a, 0x0c, - 0x0a, 0x05, 0x04, 0x03, 0x02, 0x01, 0x01, 0x12, 0x03, 0x4a, 0x11, 0x1e, 0x0a, 0x0c, 0x0a, 0x05, - 0x04, 0x03, 0x02, 0x01, 0x03, 0x12, 0x03, 0x4a, 0x21, 0x22, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x03, - 0x02, 0x02, 0x12, 0x03, 0x4b, 0x04, 0x23, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, 0x02, 0x06, - 0x12, 0x03, 0x4b, 0x04, 0x10, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, 0x02, 0x01, 0x12, 0x03, - 0x4b, 0x11, 0x1e, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, 0x02, 0x03, 0x12, 0x03, 0x4b, 0x21, - 0x22, 0x0a, 0x38, 0x0a, 0x02, 0x04, 0x04, 0x12, 0x04, 0x50, 0x00, 0x68, 0x01, 0x1a, 0x2c, 0x20, - 0x41, 0x20, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x67, 0x6f, - 0x76, 0x65, 0x72, 0x6e, 0x73, 0x20, 0x75, 0x70, 0x64, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x20, 0x70, - 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x0a, 0x0a, 0x0a, 0x0a, 0x03, 0x04, - 0x04, 0x01, 0x12, 0x03, 0x50, 0x08, 0x1f, 0x0a, 0x1b, 0x0a, 0x04, 0x04, 0x04, 0x04, 0x00, 0x12, - 0x04, 0x52, 0x02, 0x57, 0x03, 0x1a, 0x0d, 0x20, 0x42, 0x61, 0x73, 0x65, 0x20, 0x70, 0x6f, 0x6c, - 0x69, 0x63, 0x79, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x04, 0x00, 0x01, 0x12, 0x03, 0x52, - 0x07, 0x1c, 0x0a, 0x0d, 0x0a, 0x06, 0x04, 0x04, 0x04, 0x00, 0x02, 0x00, 0x12, 0x03, 0x53, 0x04, - 0x2c, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x04, 0x04, 0x00, 0x02, 0x00, 0x01, 0x12, 0x03, 0x53, 0x04, - 0x27, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x04, 0x04, 0x00, 0x02, 0x00, 0x02, 0x12, 0x03, 0x53, 0x2a, - 0x2b, 0x0a, 0x0d, 0x0a, 0x06, 0x04, 0x04, 0x04, 0x00, 0x02, 0x01, 0x12, 0x03, 0x54, 0x04, 0x25, - 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x04, 0x04, 0x00, 0x02, 0x01, 0x01, 0x12, 0x03, 0x54, 0x04, 0x20, - 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x04, 0x04, 0x00, 0x02, 0x01, 0x02, 0x12, 0x03, 0x54, 0x23, 0x24, - 0x0a, 0x0d, 0x0a, 0x06, 0x04, 0x04, 0x04, 0x00, 0x02, 0x02, 0x12, 0x03, 0x55, 0x04, 0x2f, 0x0a, - 0x0e, 0x0a, 0x07, 0x04, 0x04, 0x04, 0x00, 0x02, 0x02, 0x01, 0x12, 0x03, 0x55, 0x04, 0x2a, 0x0a, - 0x0e, 0x0a, 0x07, 0x04, 0x04, 0x04, 0x00, 0x02, 0x02, 0x02, 0x12, 0x03, 0x55, 0x2d, 0x2e, 0x0a, - 0x0d, 0x0a, 0x06, 0x04, 0x04, 0x04, 0x00, 0x02, 0x03, 0x12, 0x03, 0x56, 0x04, 0x35, 0x0a, 0x0e, - 0x0a, 0x07, 0x04, 0x04, 0x04, 0x00, 0x02, 0x03, 0x01, 0x12, 0x03, 0x56, 0x04, 0x30, 0x0a, 0x0e, - 0x0a, 0x07, 0x04, 0x04, 0x04, 0x00, 0x02, 0x03, 0x02, 0x12, 0x03, 0x56, 0x33, 0x34, 0x0a, 0x44, - 0x0a, 0x04, 0x04, 0x04, 0x03, 0x00, 0x12, 0x04, 0x5a, 0x02, 0x5c, 0x03, 0x1a, 0x36, 0x20, 0x43, - 0x6f, 0x6d, 0x62, 0x69, 0x6e, 0x65, 0x20, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x20, - 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x2e, 0x20, 0x41, 0x6c, 0x6c, 0x20, 0x6d, 0x75, - 0x73, 0x74, 0x20, 0x65, 0x76, 0x61, 0x6c, 0x75, 0x61, 0x74, 0x65, 0x20, 0x74, 0x6f, 0x20, 0x74, - 0x72, 0x75, 0x65, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x03, 0x00, 0x01, 0x12, 0x03, 0x5a, - 0x0a, 0x16, 0x0a, 0x0d, 0x0a, 0x06, 0x04, 0x04, 0x03, 0x00, 0x02, 0x00, 0x12, 0x03, 0x5b, 0x04, - 0x32, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x04, 0x03, 0x00, 0x02, 0x00, 0x04, 0x12, 0x03, 0x5b, 0x04, - 0x0c, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x04, 0x03, 0x00, 0x02, 0x00, 0x06, 0x12, 0x03, 0x5b, 0x0d, - 0x24, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x04, 0x03, 0x00, 0x02, 0x00, 0x01, 0x12, 0x03, 0x5b, 0x25, - 0x2d, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x04, 0x03, 0x00, 0x02, 0x00, 0x03, 0x12, 0x03, 0x5b, 0x30, - 0x31, 0x0a, 0x44, 0x0a, 0x04, 0x04, 0x04, 0x03, 0x01, 0x12, 0x04, 0x5f, 0x02, 0x61, 0x03, 0x1a, - 0x36, 0x20, 0x43, 0x6f, 0x6d, 0x62, 0x69, 0x6e, 0x65, 0x20, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, - 0x6c, 0x65, 0x20, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x2e, 0x20, 0x41, 0x6e, 0x79, - 0x20, 0x6d, 0x75, 0x73, 0x74, 0x20, 0x65, 0x76, 0x61, 0x6c, 0x75, 0x61, 0x74, 0x65, 0x20, 0x74, - 0x6f, 0x20, 0x74, 0x72, 0x75, 0x65, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x03, 0x01, 0x01, - 0x12, 0x03, 0x5f, 0x0a, 0x16, 0x0a, 0x0d, 0x0a, 0x06, 0x04, 0x04, 0x03, 0x01, 0x02, 0x00, 0x12, - 0x03, 0x60, 0x04, 0x32, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x04, 0x03, 0x01, 0x02, 0x00, 0x04, 0x12, - 0x03, 0x60, 0x04, 0x0c, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x04, 0x03, 0x01, 0x02, 0x00, 0x06, 0x12, - 0x03, 0x60, 0x0d, 0x24, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x04, 0x03, 0x01, 0x02, 0x00, 0x01, 0x12, - 0x03, 0x60, 0x25, 0x2d, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x04, 0x03, 0x01, 0x02, 0x00, 0x03, 0x12, - 0x03, 0x60, 0x30, 0x31, 0x0a, 0x0c, 0x0a, 0x04, 0x04, 0x04, 0x08, 0x00, 0x12, 0x04, 0x63, 0x02, - 0x67, 0x03, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x08, 0x00, 0x01, 0x12, 0x03, 0x63, 0x08, 0x0c, - 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x04, 0x02, 0x00, 0x12, 0x03, 0x64, 0x04, 0x23, 0x0a, 0x0c, 0x0a, - 0x05, 0x04, 0x04, 0x02, 0x00, 0x06, 0x12, 0x03, 0x64, 0x04, 0x19, 0x0a, 0x0c, 0x0a, 0x05, 0x04, - 0x04, 0x02, 0x00, 0x01, 0x12, 0x03, 0x64, 0x1a, 0x1e, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x02, - 0x00, 0x03, 0x12, 0x03, 0x64, 0x21, 0x22, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x04, 0x02, 0x01, 0x12, - 0x03, 0x65, 0x04, 0x23, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x02, 0x01, 0x06, 0x12, 0x03, 0x65, - 0x04, 0x10, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x02, 0x01, 0x01, 0x12, 0x03, 0x65, 0x11, 0x1e, - 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x02, 0x01, 0x03, 0x12, 0x03, 0x65, 0x21, 0x22, 0x0a, 0x0b, - 0x0a, 0x04, 0x04, 0x04, 0x02, 0x02, 0x12, 0x03, 0x66, 0x04, 0x23, 0x0a, 0x0c, 0x0a, 0x05, 0x04, - 0x04, 0x02, 0x02, 0x06, 0x12, 0x03, 0x66, 0x04, 0x10, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x02, - 0x02, 0x01, 0x12, 0x03, 0x66, 0x11, 0x1e, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x02, 0x02, 0x03, - 0x12, 0x03, 0x66, 0x21, 0x22, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, 0x0a, 0xb8, 0x1a, - 0x0a, 0x2e, 0x6d, 0x6c, 0x73, 0x2f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, - 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x63, 0x72, 0x69, 0x70, - 0x74, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x12, 0x19, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x22, 0xa7, 0x01, 0x0a, 0x10, - 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, - 0x12, 0x29, 0x0a, 0x10, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x5f, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x0f, 0x69, 0x6e, 0x73, 0x74, - 0x61, 0x6c, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x73, 0x12, 0x27, 0x0a, 0x0f, 0x61, - 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x41, 0x64, 0x64, - 0x72, 0x65, 0x73, 0x73, 0x12, 0x3f, 0x0a, 0x1c, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x74, 0x65, - 0x64, 0x5f, 0x62, 0x79, 0x5f, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x61, 0x64, 0x64, - 0x72, 0x65, 0x73, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x19, 0x69, 0x6e, 0x69, 0x74, - 0x69, 0x61, 0x74, 0x65, 0x64, 0x42, 0x79, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x41, 0x64, - 0x64, 0x72, 0x65, 0x73, 0x73, 0x22, 0x80, 0x03, 0x0a, 0x16, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x4d, - 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x73, - 0x12, 0x50, 0x0a, 0x0d, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x5f, 0x61, 0x64, 0x64, 0x65, - 0x64, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, - 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, - 0x6e, 0x74, 0x73, 0x2e, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x43, 0x68, - 0x61, 0x6e, 0x67, 0x65, 0x52, 0x0c, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x41, 0x64, 0x64, - 0x65, 0x64, 0x12, 0x54, 0x0a, 0x0f, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x5f, 0x72, 0x65, - 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x78, 0x6d, - 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, - 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, - 0x69, 0x70, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x0e, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, - 0x73, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x12, 0x5c, 0x0a, 0x13, 0x69, 0x6e, 0x73, 0x74, - 0x61, 0x6c, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x5f, 0x61, 0x64, 0x64, 0x65, 0x64, 0x18, - 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, - 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, - 0x73, 0x2e, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x43, 0x68, 0x61, 0x6e, - 0x67, 0x65, 0x52, 0x12, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x73, 0x41, 0x64, 0x64, 0x65, 0x64, 0x12, 0x60, 0x0a, 0x15, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, - 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x5f, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x18, - 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, - 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, - 0x73, 0x2e, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x43, 0x68, 0x61, 0x6e, - 0x67, 0x65, 0x52, 0x14, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x73, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x22, 0x9b, 0x04, 0x0a, 0x0c, 0x47, 0x72, 0x6f, - 0x75, 0x70, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x12, 0x31, 0x0a, 0x15, 0x69, 0x6e, 0x69, - 0x74, 0x69, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x62, 0x79, 0x5f, 0x69, 0x6e, 0x62, 0x6f, 0x78, 0x5f, - 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x12, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x61, - 0x74, 0x65, 0x64, 0x42, 0x79, 0x49, 0x6e, 0x62, 0x6f, 0x78, 0x49, 0x64, 0x12, 0x52, 0x0a, 0x0d, - 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x69, 0x6e, 0x62, 0x6f, 0x78, 0x65, 0x73, 0x18, 0x02, 0x20, - 0x03, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, - 0x47, 0x72, 0x6f, 0x75, 0x70, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x2e, 0x49, 0x6e, 0x62, - 0x6f, 0x78, 0x52, 0x0c, 0x61, 0x64, 0x64, 0x65, 0x64, 0x49, 0x6e, 0x62, 0x6f, 0x78, 0x65, 0x73, - 0x12, 0x56, 0x0a, 0x0f, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x5f, 0x69, 0x6e, 0x62, 0x6f, - 0x78, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x78, 0x6d, 0x74, 0x70, - 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, - 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x55, 0x70, 0x64, 0x61, 0x74, - 0x65, 0x64, 0x2e, 0x49, 0x6e, 0x62, 0x6f, 0x78, 0x52, 0x0e, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, - 0x64, 0x49, 0x6e, 0x62, 0x6f, 0x78, 0x65, 0x73, 0x12, 0x71, 0x0a, 0x16, 0x6d, 0x65, 0x74, 0x61, - 0x64, 0x61, 0x74, 0x61, 0x5f, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x67, - 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x3b, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, + 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x22, 0xa6, 0x02, 0x0a, 0x0f, 0x47, 0x72, + 0x6f, 0x75, 0x70, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x56, 0x31, 0x12, 0x58, 0x0a, + 0x11, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x74, 0x79, + 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2b, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, - 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, - 0x64, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x43, - 0x68, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x14, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x46, - 0x69, 0x65, 0x6c, 0x64, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x1a, 0x22, 0x0a, 0x05, 0x49, - 0x6e, 0x62, 0x6f, 0x78, 0x12, 0x19, 0x0a, 0x08, 0x69, 0x6e, 0x62, 0x6f, 0x78, 0x5f, 0x69, 0x64, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x69, 0x6e, 0x62, 0x6f, 0x78, 0x49, 0x64, 0x1a, - 0x94, 0x01, 0x0a, 0x13, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x46, 0x69, 0x65, 0x6c, - 0x64, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x66, 0x69, 0x65, 0x6c, 0x64, - 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x66, 0x69, 0x65, - 0x6c, 0x64, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x09, 0x6f, 0x6c, 0x64, 0x5f, 0x76, 0x61, - 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x08, 0x6f, 0x6c, 0x64, - 0x56, 0x61, 0x6c, 0x75, 0x65, 0x88, 0x01, 0x01, 0x12, 0x20, 0x0a, 0x09, 0x6e, 0x65, 0x77, 0x5f, - 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x48, 0x01, 0x52, 0x08, 0x6e, - 0x65, 0x77, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x88, 0x01, 0x01, 0x42, 0x0c, 0x0a, 0x0a, 0x5f, 0x6f, - 0x6c, 0x64, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x42, 0x0c, 0x0a, 0x0a, 0x5f, 0x6e, 0x65, 0x77, - 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x42, 0xec, 0x01, 0x0a, 0x1d, 0x63, 0x6f, 0x6d, 0x2e, 0x78, - 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, - 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x42, 0x17, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x63, - 0x72, 0x69, 0x70, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x50, 0x72, 0x6f, 0x74, + 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x43, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x10, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x12, 0x36, 0x0a, 0x17, 0x63, 0x72, 0x65, 0x61, 0x74, + 0x6f, 0x72, 0x5f, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, + 0x73, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x15, 0x63, 0x72, 0x65, 0x61, 0x74, 0x6f, + 0x72, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, + 0x28, 0x0a, 0x10, 0x63, 0x72, 0x65, 0x61, 0x74, 0x6f, 0x72, 0x5f, 0x69, 0x6e, 0x62, 0x6f, 0x78, + 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x63, 0x72, 0x65, 0x61, 0x74, + 0x6f, 0x72, 0x49, 0x6e, 0x62, 0x6f, 0x78, 0x49, 0x64, 0x12, 0x48, 0x0a, 0x0a, 0x64, 0x6d, 0x5f, + 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, + 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x44, 0x6d, 0x4d, 0x65, 0x6d, 0x62, + 0x65, 0x72, 0x73, 0x48, 0x00, 0x52, 0x09, 0x64, 0x6d, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, + 0x88, 0x01, 0x01, 0x42, 0x0d, 0x0a, 0x0b, 0x5f, 0x64, 0x6d, 0x5f, 0x6d, 0x65, 0x6d, 0x62, 0x65, + 0x72, 0x73, 0x22, 0x22, 0x0a, 0x05, 0x49, 0x6e, 0x62, 0x6f, 0x78, 0x12, 0x19, 0x0a, 0x08, 0x69, + 0x6e, 0x62, 0x6f, 0x78, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x69, + 0x6e, 0x62, 0x6f, 0x78, 0x49, 0x64, 0x22, 0x97, 0x01, 0x0a, 0x09, 0x44, 0x6d, 0x4d, 0x65, 0x6d, + 0x62, 0x65, 0x72, 0x73, 0x12, 0x44, 0x0a, 0x0d, 0x64, 0x6d, 0x5f, 0x6d, 0x65, 0x6d, 0x62, 0x65, + 0x72, 0x5f, 0x6f, 0x6e, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x78, 0x6d, + 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, + 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x49, 0x6e, 0x62, 0x6f, 0x78, 0x52, 0x0b, 0x64, + 0x6d, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x4f, 0x6e, 0x65, 0x12, 0x44, 0x0a, 0x0d, 0x64, 0x6d, + 0x5f, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x5f, 0x74, 0x77, 0x6f, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x20, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x49, 0x6e, + 0x62, 0x6f, 0x78, 0x52, 0x0b, 0x64, 0x6d, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x54, 0x77, 0x6f, + 0x2a, 0x88, 0x01, 0x0a, 0x10, 0x43, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x54, 0x79, 0x70, 0x65, 0x12, 0x21, 0x0a, 0x1d, 0x43, 0x4f, 0x4e, 0x56, 0x45, 0x52, 0x53, + 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, + 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x1b, 0x0a, 0x17, 0x43, 0x4f, 0x4e, 0x56, + 0x45, 0x52, 0x53, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x47, 0x52, + 0x4f, 0x55, 0x50, 0x10, 0x01, 0x12, 0x18, 0x0a, 0x14, 0x43, 0x4f, 0x4e, 0x56, 0x45, 0x52, 0x53, + 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x44, 0x4d, 0x10, 0x02, 0x12, + 0x1a, 0x0a, 0x16, 0x43, 0x4f, 0x4e, 0x56, 0x45, 0x52, 0x53, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, + 0x54, 0x59, 0x50, 0x45, 0x5f, 0x53, 0x59, 0x4e, 0x43, 0x10, 0x03, 0x42, 0xe7, 0x01, 0x0a, 0x1d, + 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x42, 0x12, 0x47, + 0x72, 0x6f, 0x75, 0x70, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x30, 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, 0x6d, 0x6c, 0x73, 0x2f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, @@ -1772,130 +1143,760 @@ pub const FILE_DESCRIPTOR_SET: &[u8] = &[ 0x73, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x1a, 0x58, 0x6d, 0x74, 0x70, 0x3a, 0x3a, 0x4d, 0x6c, 0x73, 0x3a, 0x3a, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, - 0x74, 0x65, 0x6e, 0x74, 0x73, 0x4a, 0xa8, 0x0f, 0x0a, 0x06, 0x12, 0x04, 0x01, 0x00, 0x38, 0x01, - 0x0a, 0x2f, 0x0a, 0x01, 0x0c, 0x12, 0x03, 0x01, 0x00, 0x12, 0x1a, 0x25, 0x20, 0x4d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x20, 0x65, 0x6e, 0x63, - 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x75, 0x72, 0x65, 0x73, - 0x0a, 0x0a, 0x08, 0x0a, 0x01, 0x02, 0x12, 0x03, 0x03, 0x00, 0x22, 0x0a, 0x08, 0x0a, 0x01, 0x08, - 0x12, 0x03, 0x05, 0x00, 0x47, 0x0a, 0x09, 0x0a, 0x02, 0x08, 0x0b, 0x12, 0x03, 0x05, 0x00, 0x47, - 0x0a, 0x3a, 0x0a, 0x02, 0x04, 0x00, 0x12, 0x04, 0x09, 0x00, 0x0d, 0x01, 0x1a, 0x2e, 0x20, 0x41, - 0x20, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x20, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x20, 0x61, 0x6e, - 0x64, 0x20, 0x61, 0x66, 0x66, 0x65, 0x63, 0x74, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x73, 0x74, 0x61, - 0x6c, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x49, 0x44, 0x73, 0x0a, 0x0a, 0x0a, 0x0a, 0x03, - 0x04, 0x00, 0x01, 0x12, 0x03, 0x09, 0x08, 0x18, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x00, 0x02, 0x00, - 0x12, 0x03, 0x0a, 0x02, 0x26, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x00, 0x04, 0x12, 0x03, - 0x0a, 0x02, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x00, 0x05, 0x12, 0x03, 0x0a, 0x0b, - 0x10, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x00, 0x01, 0x12, 0x03, 0x0a, 0x11, 0x21, 0x0a, - 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x00, 0x03, 0x12, 0x03, 0x0a, 0x24, 0x25, 0x0a, 0x0b, 0x0a, - 0x04, 0x04, 0x00, 0x02, 0x01, 0x12, 0x03, 0x0b, 0x02, 0x1d, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, - 0x02, 0x01, 0x05, 0x12, 0x03, 0x0b, 0x02, 0x08, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x01, - 0x01, 0x12, 0x03, 0x0b, 0x09, 0x18, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x01, 0x03, 0x12, - 0x03, 0x0b, 0x1b, 0x1c, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x00, 0x02, 0x02, 0x12, 0x03, 0x0c, 0x02, - 0x2a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x02, 0x05, 0x12, 0x03, 0x0c, 0x02, 0x08, 0x0a, - 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x02, 0x01, 0x12, 0x03, 0x0c, 0x09, 0x25, 0x0a, 0x0c, 0x0a, - 0x05, 0x04, 0x00, 0x02, 0x02, 0x03, 0x12, 0x03, 0x0c, 0x28, 0x29, 0x0a, 0x64, 0x0a, 0x02, 0x04, - 0x01, 0x12, 0x04, 0x10, 0x00, 0x1d, 0x01, 0x1a, 0x23, 0x20, 0x54, 0x68, 0x65, 0x20, 0x67, 0x72, - 0x6f, 0x75, 0x70, 0x20, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x20, 0x63, - 0x68, 0x61, 0x6e, 0x67, 0x65, 0x20, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x0a, 0x22, 0x33, 0x20, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x6c, 0x69, 0x6e, 0x74, 0x3a, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, - 0x20, 0x52, 0x45, 0x50, 0x45, 0x41, 0x54, 0x45, 0x44, 0x5f, 0x46, 0x49, 0x45, 0x4c, 0x44, 0x5f, - 0x4e, 0x41, 0x4d, 0x45, 0x53, 0x5f, 0x50, 0x4c, 0x55, 0x52, 0x41, 0x4c, 0x49, 0x5a, 0x45, 0x44, - 0x0a, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x01, 0x01, 0x12, 0x03, 0x10, 0x08, 0x1e, 0x0a, 0x39, 0x0a, - 0x04, 0x04, 0x01, 0x02, 0x00, 0x12, 0x03, 0x14, 0x02, 0x2e, 0x1a, 0x2c, 0x20, 0x4d, 0x65, 0x6d, - 0x62, 0x65, 0x72, 0x73, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x68, 0x61, 0x76, 0x65, 0x20, 0x62, - 0x65, 0x65, 0x6e, 0x20, 0x61, 0x64, 0x64, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, - 0x20, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x00, - 0x04, 0x12, 0x03, 0x14, 0x02, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x00, 0x06, 0x12, - 0x03, 0x14, 0x0b, 0x1b, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x00, 0x01, 0x12, 0x03, 0x14, - 0x1c, 0x29, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x00, 0x03, 0x12, 0x03, 0x14, 0x2c, 0x2d, - 0x0a, 0x3b, 0x0a, 0x04, 0x04, 0x01, 0x02, 0x01, 0x12, 0x03, 0x16, 0x02, 0x30, 0x1a, 0x2e, 0x20, - 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x68, 0x61, 0x76, - 0x65, 0x20, 0x62, 0x65, 0x65, 0x6e, 0x20, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x20, 0x69, - 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x0a, 0x0a, 0x0c, 0x0a, - 0x05, 0x04, 0x01, 0x02, 0x01, 0x04, 0x12, 0x03, 0x16, 0x02, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, - 0x01, 0x02, 0x01, 0x06, 0x12, 0x03, 0x16, 0x0b, 0x1b, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, - 0x01, 0x01, 0x12, 0x03, 0x16, 0x1c, 0x2b, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x01, 0x03, - 0x12, 0x03, 0x16, 0x2e, 0x2f, 0x0a, 0x52, 0x0a, 0x04, 0x04, 0x01, 0x02, 0x02, 0x12, 0x03, 0x18, - 0x02, 0x34, 0x1a, 0x45, 0x20, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x73, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x68, 0x61, 0x76, 0x65, 0x20, 0x62, 0x65, 0x65, + 0x74, 0x65, 0x6e, 0x74, 0x73, 0x4a, 0xb8, 0x07, 0x0a, 0x06, 0x12, 0x04, 0x01, 0x00, 0x23, 0x01, + 0x0a, 0x24, 0x0a, 0x01, 0x0c, 0x12, 0x03, 0x01, 0x00, 0x12, 0x1a, 0x1a, 0x20, 0x47, 0x72, 0x6f, + 0x75, 0x70, 0x20, 0x69, 0x6d, 0x6d, 0x75, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x6d, 0x65, 0x74, + 0x61, 0x64, 0x61, 0x74, 0x61, 0x0a, 0x0a, 0x08, 0x0a, 0x01, 0x02, 0x12, 0x03, 0x03, 0x00, 0x22, + 0x0a, 0x08, 0x0a, 0x01, 0x08, 0x12, 0x03, 0x05, 0x00, 0x47, 0x0a, 0x09, 0x0a, 0x02, 0x08, 0x0b, + 0x12, 0x03, 0x05, 0x00, 0x47, 0x0a, 0x2f, 0x0a, 0x02, 0x04, 0x00, 0x12, 0x04, 0x09, 0x00, 0x10, + 0x01, 0x1a, 0x23, 0x20, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x20, 0x6d, 0x65, 0x74, + 0x61, 0x64, 0x61, 0x74, 0x61, 0x0a, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x00, 0x01, 0x12, 0x03, 0x09, + 0x08, 0x17, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x00, 0x02, 0x00, 0x12, 0x03, 0x0a, 0x02, 0x29, 0x0a, + 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x00, 0x06, 0x12, 0x03, 0x0a, 0x02, 0x12, 0x0a, 0x0c, 0x0a, + 0x05, 0x04, 0x00, 0x02, 0x00, 0x01, 0x12, 0x03, 0x0a, 0x13, 0x24, 0x0a, 0x0c, 0x0a, 0x05, 0x04, + 0x00, 0x02, 0x00, 0x03, 0x12, 0x03, 0x0a, 0x27, 0x28, 0x0a, 0x28, 0x0a, 0x04, 0x04, 0x00, 0x02, + 0x01, 0x12, 0x03, 0x0c, 0x02, 0x25, 0x1a, 0x1b, 0x20, 0x54, 0x68, 0x69, 0x73, 0x20, 0x77, 0x69, + 0x6c, 0x6c, 0x20, 0x62, 0x65, 0x20, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x20, 0x73, 0x6f, + 0x6f, 0x6e, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x01, 0x05, 0x12, 0x03, 0x0c, 0x02, + 0x08, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x01, 0x01, 0x12, 0x03, 0x0c, 0x09, 0x20, 0x0a, + 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x01, 0x03, 0x12, 0x03, 0x0c, 0x23, 0x24, 0x0a, 0x0b, 0x0a, + 0x04, 0x04, 0x00, 0x02, 0x02, 0x12, 0x03, 0x0d, 0x02, 0x1e, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, + 0x02, 0x02, 0x05, 0x12, 0x03, 0x0d, 0x02, 0x08, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x02, + 0x01, 0x12, 0x03, 0x0d, 0x09, 0x19, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x02, 0x03, 0x12, + 0x03, 0x0d, 0x1c, 0x1d, 0x0a, 0x3e, 0x0a, 0x04, 0x04, 0x00, 0x02, 0x03, 0x12, 0x03, 0x0f, 0x02, + 0x24, 0x1a, 0x31, 0x20, 0x53, 0x68, 0x6f, 0x75, 0x6c, 0x64, 0x20, 0x6f, 0x6e, 0x6c, 0x79, 0x20, + 0x62, 0x65, 0x20, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x43, + 0x4f, 0x4e, 0x56, 0x45, 0x52, 0x53, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x54, 0x59, 0x50, 0x45, + 0x5f, 0x44, 0x4d, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x03, 0x04, 0x12, 0x03, 0x0f, + 0x02, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x03, 0x06, 0x12, 0x03, 0x0f, 0x0b, 0x14, + 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x03, 0x01, 0x12, 0x03, 0x0f, 0x15, 0x1f, 0x0a, 0x0c, + 0x0a, 0x05, 0x04, 0x00, 0x02, 0x03, 0x03, 0x12, 0x03, 0x0f, 0x22, 0x23, 0x0a, 0x2e, 0x0a, 0x02, + 0x05, 0x00, 0x12, 0x04, 0x13, 0x00, 0x18, 0x01, 0x1a, 0x22, 0x20, 0x44, 0x65, 0x66, 0x69, 0x6e, + 0x65, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x79, 0x70, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x63, + 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x0a, 0x0a, 0x0a, 0x0a, 0x03, + 0x05, 0x00, 0x01, 0x12, 0x03, 0x13, 0x05, 0x15, 0x0a, 0x0b, 0x0a, 0x04, 0x05, 0x00, 0x02, 0x00, + 0x12, 0x03, 0x14, 0x02, 0x24, 0x0a, 0x0c, 0x0a, 0x05, 0x05, 0x00, 0x02, 0x00, 0x01, 0x12, 0x03, + 0x14, 0x02, 0x1f, 0x0a, 0x0c, 0x0a, 0x05, 0x05, 0x00, 0x02, 0x00, 0x02, 0x12, 0x03, 0x14, 0x22, + 0x23, 0x0a, 0x0b, 0x0a, 0x04, 0x05, 0x00, 0x02, 0x01, 0x12, 0x03, 0x15, 0x02, 0x1e, 0x0a, 0x0c, + 0x0a, 0x05, 0x05, 0x00, 0x02, 0x01, 0x01, 0x12, 0x03, 0x15, 0x02, 0x19, 0x0a, 0x0c, 0x0a, 0x05, + 0x05, 0x00, 0x02, 0x01, 0x02, 0x12, 0x03, 0x15, 0x1c, 0x1d, 0x0a, 0x0b, 0x0a, 0x04, 0x05, 0x00, + 0x02, 0x02, 0x12, 0x03, 0x16, 0x02, 0x1b, 0x0a, 0x0c, 0x0a, 0x05, 0x05, 0x00, 0x02, 0x02, 0x01, + 0x12, 0x03, 0x16, 0x02, 0x16, 0x0a, 0x0c, 0x0a, 0x05, 0x05, 0x00, 0x02, 0x02, 0x02, 0x12, 0x03, + 0x16, 0x19, 0x1a, 0x0a, 0x0b, 0x0a, 0x04, 0x05, 0x00, 0x02, 0x03, 0x12, 0x03, 0x17, 0x02, 0x1d, + 0x0a, 0x0c, 0x0a, 0x05, 0x05, 0x00, 0x02, 0x03, 0x01, 0x12, 0x03, 0x17, 0x02, 0x18, 0x0a, 0x0c, + 0x0a, 0x05, 0x05, 0x00, 0x02, 0x03, 0x02, 0x12, 0x03, 0x17, 0x1b, 0x1c, 0x0a, 0x28, 0x0a, 0x02, + 0x04, 0x01, 0x12, 0x04, 0x1b, 0x00, 0x1d, 0x01, 0x1a, 0x1c, 0x20, 0x57, 0x72, 0x61, 0x70, 0x70, + 0x65, 0x72, 0x20, 0x61, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x20, 0x61, 0x6e, 0x20, 0x49, 0x6e, 0x62, + 0x6f, 0x78, 0x20, 0x49, 0x64, 0x0a, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x01, 0x01, 0x12, 0x03, 0x1b, + 0x08, 0x0d, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x01, 0x02, 0x00, 0x12, 0x03, 0x1c, 0x02, 0x16, 0x0a, + 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x00, 0x05, 0x12, 0x03, 0x1c, 0x02, 0x08, 0x0a, 0x0c, 0x0a, + 0x05, 0x04, 0x01, 0x02, 0x00, 0x01, 0x12, 0x03, 0x1c, 0x09, 0x11, 0x0a, 0x0c, 0x0a, 0x05, 0x04, + 0x01, 0x02, 0x00, 0x03, 0x12, 0x03, 0x1c, 0x14, 0x15, 0x0a, 0x2b, 0x0a, 0x02, 0x04, 0x02, 0x12, + 0x04, 0x20, 0x00, 0x23, 0x01, 0x1a, 0x1f, 0x20, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x69, 0x6e, 0x67, + 0x20, 0x64, 0x6f, 0x65, 0x73, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x6d, 0x61, 0x74, 0x74, 0x65, 0x72, + 0x20, 0x68, 0x65, 0x72, 0x65, 0x0a, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x02, 0x01, 0x12, 0x03, 0x20, + 0x08, 0x11, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x02, 0x02, 0x00, 0x12, 0x03, 0x21, 0x02, 0x1a, 0x0a, + 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x00, 0x06, 0x12, 0x03, 0x21, 0x02, 0x07, 0x0a, 0x0c, 0x0a, + 0x05, 0x04, 0x02, 0x02, 0x00, 0x01, 0x12, 0x03, 0x21, 0x08, 0x15, 0x0a, 0x0c, 0x0a, 0x05, 0x04, + 0x02, 0x02, 0x00, 0x03, 0x12, 0x03, 0x21, 0x18, 0x19, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x02, 0x02, + 0x01, 0x12, 0x03, 0x22, 0x02, 0x1a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x01, 0x06, 0x12, + 0x03, 0x22, 0x02, 0x07, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x01, 0x01, 0x12, 0x03, 0x22, + 0x08, 0x15, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x01, 0x03, 0x12, 0x03, 0x22, 0x18, 0x19, + 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, 0x0a, 0x92, 0x0a, 0x0a, 0x31, 0x6d, 0x6c, 0x73, + 0x2f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, + 0x73, 0x2f, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x5f, 0x6d, 0x75, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5f, + 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x19, + 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x22, 0xcb, 0x02, 0x0a, 0x16, 0x47, 0x72, + 0x6f, 0x75, 0x70, 0x4d, 0x75, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, + 0x74, 0x61, 0x56, 0x31, 0x12, 0x61, 0x0a, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, + 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x41, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, + 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, + 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x4d, 0x75, 0x74, 0x61, 0x62, 0x6c, + 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x56, 0x31, 0x2e, 0x41, 0x74, 0x74, 0x72, + 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0a, 0x61, 0x74, 0x74, + 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x12, 0x41, 0x0a, 0x0a, 0x61, 0x64, 0x6d, 0x69, 0x6e, + 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x78, 0x6d, + 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, + 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x49, 0x6e, 0x62, 0x6f, 0x78, 0x65, 0x73, 0x52, + 0x09, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x4c, 0x0a, 0x10, 0x73, 0x75, + 0x70, 0x65, 0x72, 0x5f, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, + 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, + 0x2e, 0x49, 0x6e, 0x62, 0x6f, 0x78, 0x65, 0x73, 0x52, 0x0e, 0x73, 0x75, 0x70, 0x65, 0x72, 0x41, + 0x64, 0x6d, 0x69, 0x6e, 0x4c, 0x69, 0x73, 0x74, 0x1a, 0x3d, 0x0a, 0x0f, 0x41, 0x74, 0x74, 0x72, + 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, + 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, + 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, + 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x26, 0x0a, 0x07, 0x49, 0x6e, 0x62, 0x6f, 0x78, + 0x65, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x69, 0x6e, 0x62, 0x6f, 0x78, 0x5f, 0x69, 0x64, 0x73, 0x18, + 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x69, 0x6e, 0x62, 0x6f, 0x78, 0x49, 0x64, 0x73, 0x42, + 0xee, 0x01, 0x0a, 0x1d, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, + 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, + 0x73, 0x42, 0x19, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x4d, 0x75, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x4d, + 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x30, + 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, 0x6d, 0x6c, 0x73, 0x2f, + 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, + 0xa2, 0x02, 0x03, 0x58, 0x4d, 0x4d, 0xaa, 0x02, 0x18, 0x58, 0x6d, 0x74, 0x70, 0x2e, 0x4d, 0x6c, + 0x73, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, + 0x73, 0xca, 0x02, 0x18, 0x58, 0x6d, 0x74, 0x70, 0x5c, 0x4d, 0x6c, 0x73, 0x5c, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0xe2, 0x02, 0x24, 0x58, + 0x6d, 0x74, 0x70, 0x5c, 0x4d, 0x6c, 0x73, 0x5c, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x43, + 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, + 0x61, 0x74, 0x61, 0xea, 0x02, 0x1a, 0x58, 0x6d, 0x74, 0x70, 0x3a, 0x3a, 0x4d, 0x6c, 0x73, 0x3a, + 0x3a, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, + 0x4a, 0xd2, 0x04, 0x0a, 0x06, 0x12, 0x04, 0x01, 0x00, 0x16, 0x01, 0x0a, 0x22, 0x0a, 0x01, 0x0c, + 0x12, 0x03, 0x01, 0x00, 0x12, 0x1a, 0x18, 0x20, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x20, 0x6d, 0x75, + 0x74, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x0a, 0x0a, + 0x08, 0x0a, 0x01, 0x02, 0x12, 0x03, 0x03, 0x00, 0x22, 0x0a, 0x08, 0x0a, 0x01, 0x08, 0x12, 0x03, + 0x05, 0x00, 0x47, 0x0a, 0x09, 0x0a, 0x02, 0x08, 0x0b, 0x12, 0x03, 0x05, 0x00, 0x47, 0x0a, 0x30, + 0x0a, 0x02, 0x04, 0x00, 0x12, 0x04, 0x0a, 0x00, 0x11, 0x01, 0x1a, 0x24, 0x20, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x20, 0x6d, + 0x75, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x0a, + 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x00, 0x01, 0x12, 0x03, 0x0a, 0x08, 0x1e, 0x0a, 0x4a, 0x0a, 0x04, + 0x04, 0x00, 0x02, 0x00, 0x12, 0x03, 0x0c, 0x02, 0x25, 0x1a, 0x3d, 0x20, 0x4d, 0x61, 0x70, 0x20, + 0x74, 0x6f, 0x20, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x20, 0x76, 0x61, 0x72, 0x69, 0x6f, 0x75, 0x73, + 0x20, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x20, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, + 0x75, 0x74, 0x65, 0x73, 0x20, 0x28, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x20, 0x6e, 0x61, 0x6d, 0x65, + 0x2c, 0x20, 0x65, 0x74, 0x63, 0x2e, 0x29, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x00, + 0x06, 0x12, 0x03, 0x0c, 0x02, 0x15, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x00, 0x01, 0x12, + 0x03, 0x0c, 0x16, 0x20, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x00, 0x03, 0x12, 0x03, 0x0c, + 0x23, 0x24, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x00, 0x02, 0x01, 0x12, 0x03, 0x0d, 0x02, 0x19, 0x0a, + 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x01, 0x06, 0x12, 0x03, 0x0d, 0x02, 0x09, 0x0a, 0x0c, 0x0a, + 0x05, 0x04, 0x00, 0x02, 0x01, 0x01, 0x12, 0x03, 0x0d, 0x0a, 0x14, 0x0a, 0x0c, 0x0a, 0x05, 0x04, + 0x00, 0x02, 0x01, 0x03, 0x12, 0x03, 0x0d, 0x17, 0x18, 0x0a, 0x64, 0x0a, 0x04, 0x04, 0x00, 0x02, + 0x02, 0x12, 0x03, 0x10, 0x02, 0x1f, 0x1a, 0x57, 0x20, 0x43, 0x72, 0x65, 0x61, 0x74, 0x6f, 0x72, + 0x20, 0x73, 0x74, 0x61, 0x72, 0x74, 0x73, 0x20, 0x61, 0x73, 0x20, 0x6f, 0x6e, 0x6c, 0x79, 0x20, + 0x73, 0x75, 0x70, 0x65, 0x72, 0x5f, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x0a, 0x20, 0x4f, 0x6e, 0x6c, + 0x79, 0x20, 0x73, 0x75, 0x70, 0x65, 0x72, 0x5f, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x20, 0x63, 0x61, + 0x6e, 0x20, 0x61, 0x64, 0x64, 0x2f, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x20, 0x6f, 0x74, 0x68, + 0x65, 0x72, 0x20, 0x73, 0x75, 0x70, 0x65, 0x72, 0x5f, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x0a, 0x0a, + 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x02, 0x06, 0x12, 0x03, 0x10, 0x02, 0x09, 0x0a, 0x0c, 0x0a, + 0x05, 0x04, 0x00, 0x02, 0x02, 0x01, 0x12, 0x03, 0x10, 0x0a, 0x1a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, + 0x00, 0x02, 0x02, 0x03, 0x12, 0x03, 0x10, 0x1d, 0x1e, 0x0a, 0x39, 0x0a, 0x02, 0x04, 0x01, 0x12, + 0x04, 0x14, 0x00, 0x16, 0x01, 0x1a, 0x2d, 0x20, 0x57, 0x72, 0x61, 0x70, 0x70, 0x65, 0x72, 0x20, + 0x61, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x20, 0x61, 0x20, 0x6c, 0x69, 0x73, 0x74, 0x20, 0x6f, 0x66, + 0x20, 0x72, 0x65, 0x70, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x49, 0x6e, 0x62, 0x6f, 0x78, 0x20, + 0x49, 0x64, 0x73, 0x0a, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x01, 0x01, 0x12, 0x03, 0x14, 0x08, 0x0f, + 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x01, 0x02, 0x00, 0x12, 0x03, 0x15, 0x02, 0x20, 0x0a, 0x0c, 0x0a, + 0x05, 0x04, 0x01, 0x02, 0x00, 0x04, 0x12, 0x03, 0x15, 0x02, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, + 0x01, 0x02, 0x00, 0x05, 0x12, 0x03, 0x15, 0x0b, 0x11, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, + 0x00, 0x01, 0x12, 0x03, 0x15, 0x12, 0x1b, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x00, 0x03, + 0x12, 0x03, 0x15, 0x1e, 0x1f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, 0x0a, 0xfb, 0x31, + 0x0a, 0x2c, 0x6d, 0x6c, 0x73, 0x2f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, + 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2f, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x5f, 0x70, 0x65, 0x72, + 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x19, + 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x22, 0x5d, 0x0a, 0x19, 0x47, 0x72, 0x6f, + 0x75, 0x70, 0x4d, 0x75, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, + 0x69, 0x6f, 0x6e, 0x73, 0x56, 0x31, 0x12, 0x40, 0x0a, 0x08, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x69, + 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, + 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, + 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x53, 0x65, 0x74, 0x52, 0x08, + 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x22, 0xdf, 0x05, 0x0a, 0x09, 0x50, 0x6f, 0x6c, + 0x69, 0x63, 0x79, 0x53, 0x65, 0x74, 0x12, 0x57, 0x0a, 0x11, 0x61, 0x64, 0x64, 0x5f, 0x6d, 0x65, + 0x6d, 0x62, 0x65, 0x72, 0x5f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x2b, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x4d, 0x65, + 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x0f, + 0x61, 0x64, 0x64, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, + 0x5d, 0x0a, 0x14, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x5f, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, + 0x5f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, + 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, + 0x73, 0x68, 0x69, 0x70, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x12, 0x72, 0x65, 0x6d, 0x6f, + 0x76, 0x65, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x74, + 0x0a, 0x16, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, + 0x61, 0x5f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x3e, + 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x50, 0x6f, 0x6c, 0x69, 0x63, + 0x79, 0x53, 0x65, 0x74, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, + 0x61, 0x74, 0x61, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x14, + 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x50, 0x6f, + 0x6c, 0x69, 0x63, 0x79, 0x12, 0x5c, 0x0a, 0x10, 0x61, 0x64, 0x64, 0x5f, 0x61, 0x64, 0x6d, 0x69, + 0x6e, 0x5f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x32, + 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x50, 0x65, 0x72, 0x6d, 0x69, + 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, 0x6f, 0x6c, 0x69, + 0x63, 0x79, 0x52, 0x0e, 0x61, 0x64, 0x64, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x50, 0x6f, 0x6c, 0x69, + 0x63, 0x79, 0x12, 0x62, 0x0a, 0x13, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x5f, 0x61, 0x64, 0x6d, + 0x69, 0x6e, 0x5f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x32, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x50, 0x65, 0x72, 0x6d, + 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, 0x6f, 0x6c, + 0x69, 0x63, 0x79, 0x52, 0x11, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x41, 0x64, 0x6d, 0x69, 0x6e, + 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x6e, 0x0a, 0x19, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, + 0x5f, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x5f, 0x70, 0x6f, 0x6c, + 0x69, 0x63, 0x79, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x32, 0x2e, 0x78, 0x6d, 0x74, 0x70, + 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, + 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, + 0x73, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x17, 0x75, + 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, + 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x1a, 0x72, 0x0a, 0x19, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, + 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x45, 0x6e, + 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x3f, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, + 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, + 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, + 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x8a, 0x05, 0x0a, 0x10, 0x4d, + 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, + 0x4c, 0x0a, 0x04, 0x62, 0x61, 0x73, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x36, 0x2e, + 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, + 0x73, 0x68, 0x69, 0x70, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x42, 0x61, 0x73, 0x65, 0x50, + 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x48, 0x00, 0x52, 0x04, 0x62, 0x61, 0x73, 0x65, 0x12, 0x5f, 0x0a, + 0x0d, 0x61, 0x6e, 0x64, 0x5f, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x38, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, + 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, + 0x2e, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x50, 0x6f, 0x6c, 0x69, 0x63, + 0x79, 0x2e, 0x41, 0x6e, 0x64, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x00, + 0x52, 0x0c, 0x61, 0x6e, 0x64, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x5f, + 0x0a, 0x0d, 0x61, 0x6e, 0x79, 0x5f, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x38, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, + 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, + 0x73, 0x2e, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x50, 0x6f, 0x6c, 0x69, + 0x63, 0x79, 0x2e, 0x41, 0x6e, 0x79, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x48, + 0x00, 0x52, 0x0c, 0x61, 0x6e, 0x79, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x1a, + 0x57, 0x0a, 0x0c, 0x41, 0x6e, 0x64, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, + 0x47, 0x0a, 0x08, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x2b, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x4d, 0x65, + 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x08, + 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x1a, 0x57, 0x0a, 0x0c, 0x41, 0x6e, 0x79, 0x43, + 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x47, 0x0a, 0x08, 0x70, 0x6f, 0x6c, 0x69, + 0x63, 0x69, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x78, 0x6d, 0x74, + 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, + 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, + 0x70, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x08, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, + 0x73, 0x22, 0xab, 0x01, 0x0a, 0x0a, 0x42, 0x61, 0x73, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, + 0x12, 0x1b, 0x0a, 0x17, 0x42, 0x41, 0x53, 0x45, 0x5f, 0x50, 0x4f, 0x4c, 0x49, 0x43, 0x59, 0x5f, + 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x15, 0x0a, + 0x11, 0x42, 0x41, 0x53, 0x45, 0x5f, 0x50, 0x4f, 0x4c, 0x49, 0x43, 0x59, 0x5f, 0x41, 0x4c, 0x4c, + 0x4f, 0x57, 0x10, 0x01, 0x12, 0x14, 0x0a, 0x10, 0x42, 0x41, 0x53, 0x45, 0x5f, 0x50, 0x4f, 0x4c, + 0x49, 0x43, 0x59, 0x5f, 0x44, 0x45, 0x4e, 0x59, 0x10, 0x02, 0x12, 0x2d, 0x0a, 0x29, 0x42, 0x41, + 0x53, 0x45, 0x5f, 0x50, 0x4f, 0x4c, 0x49, 0x43, 0x59, 0x5f, 0x41, 0x4c, 0x4c, 0x4f, 0x57, 0x5f, + 0x49, 0x46, 0x5f, 0x41, 0x44, 0x4d, 0x49, 0x4e, 0x5f, 0x4f, 0x52, 0x5f, 0x53, 0x55, 0x50, 0x45, + 0x52, 0x5f, 0x41, 0x44, 0x4d, 0x49, 0x4e, 0x10, 0x03, 0x12, 0x24, 0x0a, 0x20, 0x42, 0x41, 0x53, + 0x45, 0x5f, 0x50, 0x4f, 0x4c, 0x49, 0x43, 0x59, 0x5f, 0x41, 0x4c, 0x4c, 0x4f, 0x57, 0x5f, 0x49, + 0x46, 0x5f, 0x53, 0x55, 0x50, 0x45, 0x52, 0x5f, 0x41, 0x44, 0x4d, 0x49, 0x4e, 0x10, 0x04, 0x42, + 0x06, 0x0a, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x22, 0xac, 0x05, 0x0a, 0x0e, 0x4d, 0x65, 0x74, 0x61, + 0x64, 0x61, 0x74, 0x61, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x52, 0x0a, 0x04, 0x62, 0x61, + 0x73, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x3c, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, + 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, + 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x50, 0x6f, 0x6c, + 0x69, 0x63, 0x79, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x42, 0x61, 0x73, 0x65, + 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x48, 0x00, 0x52, 0x04, 0x62, 0x61, 0x73, 0x65, 0x12, 0x5d, + 0x0a, 0x0d, 0x61, 0x6e, 0x64, 0x5f, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x36, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, + 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, + 0x73, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, + 0x2e, 0x41, 0x6e, 0x64, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, + 0x0c, 0x61, 0x6e, 0x64, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x5d, 0x0a, + 0x0d, 0x61, 0x6e, 0x79, 0x5f, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x36, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, + 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, + 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, + 0x41, 0x6e, 0x79, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x0c, + 0x61, 0x6e, 0x79, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x1a, 0x55, 0x0a, 0x0c, + 0x41, 0x6e, 0x64, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x45, 0x0a, 0x08, + 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x29, + 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, + 0x61, 0x74, 0x61, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x08, 0x70, 0x6f, 0x6c, 0x69, 0x63, + 0x69, 0x65, 0x73, 0x1a, 0x55, 0x0a, 0x0c, 0x41, 0x6e, 0x79, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, + 0x69, 0x6f, 0x6e, 0x12, 0x45, 0x0a, 0x08, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x18, + 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, + 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, + 0x73, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, + 0x52, 0x08, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x22, 0xd1, 0x01, 0x0a, 0x12, 0x4d, + 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x42, 0x61, 0x73, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, + 0x79, 0x12, 0x24, 0x0a, 0x20, 0x4d, 0x45, 0x54, 0x41, 0x44, 0x41, 0x54, 0x41, 0x5f, 0x42, 0x41, + 0x53, 0x45, 0x5f, 0x50, 0x4f, 0x4c, 0x49, 0x43, 0x59, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, + 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x1e, 0x0a, 0x1a, 0x4d, 0x45, 0x54, 0x41, 0x44, + 0x41, 0x54, 0x41, 0x5f, 0x42, 0x41, 0x53, 0x45, 0x5f, 0x50, 0x4f, 0x4c, 0x49, 0x43, 0x59, 0x5f, + 0x41, 0x4c, 0x4c, 0x4f, 0x57, 0x10, 0x01, 0x12, 0x1d, 0x0a, 0x19, 0x4d, 0x45, 0x54, 0x41, 0x44, + 0x41, 0x54, 0x41, 0x5f, 0x42, 0x41, 0x53, 0x45, 0x5f, 0x50, 0x4f, 0x4c, 0x49, 0x43, 0x59, 0x5f, + 0x44, 0x45, 0x4e, 0x59, 0x10, 0x02, 0x12, 0x27, 0x0a, 0x23, 0x4d, 0x45, 0x54, 0x41, 0x44, 0x41, + 0x54, 0x41, 0x5f, 0x42, 0x41, 0x53, 0x45, 0x5f, 0x50, 0x4f, 0x4c, 0x49, 0x43, 0x59, 0x5f, 0x41, + 0x4c, 0x4c, 0x4f, 0x57, 0x5f, 0x49, 0x46, 0x5f, 0x41, 0x44, 0x4d, 0x49, 0x4e, 0x10, 0x03, 0x12, + 0x2d, 0x0a, 0x29, 0x4d, 0x45, 0x54, 0x41, 0x44, 0x41, 0x54, 0x41, 0x5f, 0x42, 0x41, 0x53, 0x45, + 0x5f, 0x50, 0x4f, 0x4c, 0x49, 0x43, 0x59, 0x5f, 0x41, 0x4c, 0x4c, 0x4f, 0x57, 0x5f, 0x49, 0x46, + 0x5f, 0x53, 0x55, 0x50, 0x45, 0x52, 0x5f, 0x41, 0x44, 0x4d, 0x49, 0x4e, 0x10, 0x04, 0x42, 0x06, + 0x0a, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x22, 0xd4, 0x05, 0x0a, 0x17, 0x50, 0x65, 0x72, 0x6d, 0x69, + 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, 0x6f, 0x6c, 0x69, + 0x63, 0x79, 0x12, 0x5e, 0x0a, 0x04, 0x62, 0x61, 0x73, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, + 0x32, 0x48, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x50, 0x65, 0x72, + 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, 0x6f, + 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, + 0x42, 0x61, 0x73, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x48, 0x00, 0x52, 0x04, 0x62, 0x61, + 0x73, 0x65, 0x12, 0x66, 0x0a, 0x0d, 0x61, 0x6e, 0x64, 0x5f, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, + 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3f, 0x2e, 0x78, 0x6d, 0x74, 0x70, + 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, + 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, + 0x73, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x41, 0x6e, + 0x64, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x0c, 0x61, 0x6e, + 0x64, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x66, 0x0a, 0x0d, 0x61, 0x6e, + 0x79, 0x5f, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x3f, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x50, 0x65, + 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, + 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x41, 0x6e, 0x79, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, + 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x0c, 0x61, 0x6e, 0x79, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, + 0x6f, 0x6e, 0x1a, 0x5e, 0x0a, 0x0c, 0x41, 0x6e, 0x64, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, + 0x6f, 0x6e, 0x12, 0x4e, 0x0a, 0x08, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x18, 0x01, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x32, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, + 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, + 0x2e, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x55, 0x70, 0x64, 0x61, + 0x74, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x08, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x69, + 0x65, 0x73, 0x1a, 0x5e, 0x0a, 0x0c, 0x41, 0x6e, 0x79, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, + 0x6f, 0x6e, 0x12, 0x4e, 0x0a, 0x08, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x18, 0x01, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x32, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, + 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, + 0x2e, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x55, 0x70, 0x64, 0x61, + 0x74, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x08, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x69, + 0x65, 0x73, 0x22, 0xc0, 0x01, 0x0a, 0x15, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, + 0x6e, 0x73, 0x42, 0x61, 0x73, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x27, 0x0a, 0x23, + 0x50, 0x45, 0x52, 0x4d, 0x49, 0x53, 0x53, 0x49, 0x4f, 0x4e, 0x53, 0x5f, 0x42, 0x41, 0x53, 0x45, + 0x5f, 0x50, 0x4f, 0x4c, 0x49, 0x43, 0x59, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, + 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x20, 0x0a, 0x1c, 0x50, 0x45, 0x52, 0x4d, 0x49, 0x53, 0x53, + 0x49, 0x4f, 0x4e, 0x53, 0x5f, 0x42, 0x41, 0x53, 0x45, 0x5f, 0x50, 0x4f, 0x4c, 0x49, 0x43, 0x59, + 0x5f, 0x44, 0x45, 0x4e, 0x59, 0x10, 0x01, 0x12, 0x2a, 0x0a, 0x26, 0x50, 0x45, 0x52, 0x4d, 0x49, + 0x53, 0x53, 0x49, 0x4f, 0x4e, 0x53, 0x5f, 0x42, 0x41, 0x53, 0x45, 0x5f, 0x50, 0x4f, 0x4c, 0x49, + 0x43, 0x59, 0x5f, 0x41, 0x4c, 0x4c, 0x4f, 0x57, 0x5f, 0x49, 0x46, 0x5f, 0x41, 0x44, 0x4d, 0x49, + 0x4e, 0x10, 0x02, 0x12, 0x30, 0x0a, 0x2c, 0x50, 0x45, 0x52, 0x4d, 0x49, 0x53, 0x53, 0x49, 0x4f, + 0x4e, 0x53, 0x5f, 0x42, 0x41, 0x53, 0x45, 0x5f, 0x50, 0x4f, 0x4c, 0x49, 0x43, 0x59, 0x5f, 0x41, + 0x4c, 0x4c, 0x4f, 0x57, 0x5f, 0x49, 0x46, 0x5f, 0x53, 0x55, 0x50, 0x45, 0x52, 0x5f, 0x41, 0x44, + 0x4d, 0x49, 0x4e, 0x10, 0x03, 0x42, 0x06, 0x0a, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x42, 0xea, 0x01, + 0x0a, 0x1d, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x42, + 0x15, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, + 0x73, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x30, 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, 0x6d, 0x6c, 0x73, 0x2f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0xa2, 0x02, 0x03, 0x58, 0x4d, 0x4d, + 0xaa, 0x02, 0x18, 0x58, 0x6d, 0x74, 0x70, 0x2e, 0x4d, 0x6c, 0x73, 0x2e, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0xca, 0x02, 0x18, 0x58, 0x6d, + 0x74, 0x70, 0x5c, 0x4d, 0x6c, 0x73, 0x5c, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x43, 0x6f, + 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0xe2, 0x02, 0x24, 0x58, 0x6d, 0x74, 0x70, 0x5c, 0x4d, 0x6c, + 0x73, 0x5c, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, + 0x73, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x1a, + 0x58, 0x6d, 0x74, 0x70, 0x3a, 0x3a, 0x4d, 0x6c, 0x73, 0x3a, 0x3a, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x4a, 0xe6, 0x18, 0x0a, 0x06, 0x12, + 0x04, 0x01, 0x00, 0x68, 0x01, 0x0a, 0x2e, 0x0a, 0x01, 0x0c, 0x12, 0x03, 0x01, 0x00, 0x12, 0x1a, + 0x24, 0x20, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x20, 0x6d, 0x75, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x20, + 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x6d, 0x65, 0x74, 0x61, + 0x64, 0x61, 0x74, 0x61, 0x0a, 0x0a, 0x08, 0x0a, 0x01, 0x02, 0x12, 0x03, 0x03, 0x00, 0x22, 0x0a, + 0x08, 0x0a, 0x01, 0x08, 0x12, 0x03, 0x05, 0x00, 0x47, 0x0a, 0x09, 0x0a, 0x02, 0x08, 0x0b, 0x12, + 0x03, 0x05, 0x00, 0x47, 0x0a, 0x30, 0x0a, 0x02, 0x04, 0x00, 0x12, 0x04, 0x09, 0x00, 0x0b, 0x01, + 0x1a, 0x24, 0x20, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x67, + 0x72, 0x6f, 0x75, 0x70, 0x20, 0x6d, 0x75, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x6d, 0x65, 0x74, + 0x61, 0x64, 0x61, 0x74, 0x61, 0x0a, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x00, 0x01, 0x12, 0x03, 0x09, + 0x08, 0x21, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x00, 0x02, 0x00, 0x12, 0x03, 0x0a, 0x02, 0x19, 0x0a, + 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x00, 0x06, 0x12, 0x03, 0x0a, 0x02, 0x0b, 0x0a, 0x0c, 0x0a, + 0x05, 0x04, 0x00, 0x02, 0x00, 0x01, 0x12, 0x03, 0x0a, 0x0c, 0x14, 0x0a, 0x0c, 0x0a, 0x05, 0x04, + 0x00, 0x02, 0x00, 0x03, 0x12, 0x03, 0x0a, 0x17, 0x18, 0x0a, 0x37, 0x0a, 0x02, 0x04, 0x01, 0x12, + 0x04, 0x0e, 0x00, 0x15, 0x01, 0x1a, 0x2b, 0x20, 0x54, 0x68, 0x65, 0x20, 0x73, 0x65, 0x74, 0x20, + 0x6f, 0x66, 0x20, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x20, 0x74, 0x68, 0x61, 0x74, + 0x20, 0x67, 0x6f, 0x76, 0x65, 0x72, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x67, 0x72, 0x6f, 0x75, + 0x70, 0x0a, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x01, 0x01, 0x12, 0x03, 0x0e, 0x08, 0x11, 0x0a, 0x0b, + 0x0a, 0x04, 0x04, 0x01, 0x02, 0x00, 0x12, 0x03, 0x0f, 0x02, 0x29, 0x0a, 0x0c, 0x0a, 0x05, 0x04, + 0x01, 0x02, 0x00, 0x06, 0x12, 0x03, 0x0f, 0x02, 0x12, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, + 0x00, 0x01, 0x12, 0x03, 0x0f, 0x13, 0x24, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x00, 0x03, + 0x12, 0x03, 0x0f, 0x27, 0x28, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x01, 0x02, 0x01, 0x12, 0x03, 0x10, + 0x02, 0x2c, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x01, 0x06, 0x12, 0x03, 0x10, 0x02, 0x12, + 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x01, 0x01, 0x12, 0x03, 0x10, 0x13, 0x27, 0x0a, 0x0c, + 0x0a, 0x05, 0x04, 0x01, 0x02, 0x01, 0x03, 0x12, 0x03, 0x10, 0x2a, 0x2b, 0x0a, 0x0b, 0x0a, 0x04, + 0x04, 0x01, 0x02, 0x02, 0x12, 0x03, 0x11, 0x02, 0x39, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, + 0x02, 0x06, 0x12, 0x03, 0x11, 0x02, 0x1d, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x02, 0x01, + 0x12, 0x03, 0x11, 0x1e, 0x34, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x02, 0x03, 0x12, 0x03, + 0x11, 0x37, 0x38, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x01, 0x02, 0x03, 0x12, 0x03, 0x12, 0x02, 0x2f, + 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x03, 0x06, 0x12, 0x03, 0x12, 0x02, 0x19, 0x0a, 0x0c, + 0x0a, 0x05, 0x04, 0x01, 0x02, 0x03, 0x01, 0x12, 0x03, 0x12, 0x1a, 0x2a, 0x0a, 0x0c, 0x0a, 0x05, + 0x04, 0x01, 0x02, 0x03, 0x03, 0x12, 0x03, 0x12, 0x2d, 0x2e, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x01, + 0x02, 0x04, 0x12, 0x03, 0x13, 0x02, 0x32, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x04, 0x06, + 0x12, 0x03, 0x13, 0x02, 0x19, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x04, 0x01, 0x12, 0x03, + 0x13, 0x1a, 0x2d, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x04, 0x03, 0x12, 0x03, 0x13, 0x30, + 0x31, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x01, 0x02, 0x05, 0x12, 0x03, 0x14, 0x02, 0x38, 0x0a, 0x0c, + 0x0a, 0x05, 0x04, 0x01, 0x02, 0x05, 0x06, 0x12, 0x03, 0x14, 0x02, 0x19, 0x0a, 0x0c, 0x0a, 0x05, + 0x04, 0x01, 0x02, 0x05, 0x01, 0x12, 0x03, 0x14, 0x1a, 0x33, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, + 0x02, 0x05, 0x03, 0x12, 0x03, 0x14, 0x36, 0x37, 0x0a, 0x4c, 0x0a, 0x02, 0x04, 0x02, 0x12, 0x04, + 0x18, 0x00, 0x31, 0x01, 0x1a, 0x40, 0x20, 0x41, 0x20, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x20, + 0x74, 0x68, 0x61, 0x74, 0x20, 0x67, 0x6f, 0x76, 0x65, 0x72, 0x6e, 0x73, 0x20, 0x61, 0x64, 0x64, + 0x69, 0x6e, 0x67, 0x2f, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x69, 0x6e, 0x67, 0x20, 0x6d, 0x65, 0x6d, + 0x62, 0x65, 0x72, 0x73, 0x20, 0x6f, 0x72, 0x20, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x0a, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x02, 0x01, 0x12, 0x03, 0x18, + 0x08, 0x18, 0x0a, 0x1b, 0x0a, 0x04, 0x04, 0x02, 0x04, 0x00, 0x12, 0x04, 0x1a, 0x02, 0x20, 0x03, + 0x1a, 0x0d, 0x20, 0x42, 0x61, 0x73, 0x65, 0x20, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x0a, 0x0a, + 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x04, 0x00, 0x01, 0x12, 0x03, 0x1a, 0x07, 0x11, 0x0a, 0x0d, 0x0a, + 0x06, 0x04, 0x02, 0x04, 0x00, 0x02, 0x00, 0x12, 0x03, 0x1b, 0x04, 0x20, 0x0a, 0x0e, 0x0a, 0x07, + 0x04, 0x02, 0x04, 0x00, 0x02, 0x00, 0x01, 0x12, 0x03, 0x1b, 0x04, 0x1b, 0x0a, 0x0e, 0x0a, 0x07, + 0x04, 0x02, 0x04, 0x00, 0x02, 0x00, 0x02, 0x12, 0x03, 0x1b, 0x1e, 0x1f, 0x0a, 0x0d, 0x0a, 0x06, + 0x04, 0x02, 0x04, 0x00, 0x02, 0x01, 0x12, 0x03, 0x1c, 0x04, 0x1a, 0x0a, 0x0e, 0x0a, 0x07, 0x04, + 0x02, 0x04, 0x00, 0x02, 0x01, 0x01, 0x12, 0x03, 0x1c, 0x04, 0x15, 0x0a, 0x0e, 0x0a, 0x07, 0x04, + 0x02, 0x04, 0x00, 0x02, 0x01, 0x02, 0x12, 0x03, 0x1c, 0x18, 0x19, 0x0a, 0x0d, 0x0a, 0x06, 0x04, + 0x02, 0x04, 0x00, 0x02, 0x02, 0x12, 0x03, 0x1d, 0x04, 0x19, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, + 0x04, 0x00, 0x02, 0x02, 0x01, 0x12, 0x03, 0x1d, 0x04, 0x14, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, + 0x04, 0x00, 0x02, 0x02, 0x02, 0x12, 0x03, 0x1d, 0x17, 0x18, 0x0a, 0x0d, 0x0a, 0x06, 0x04, 0x02, + 0x04, 0x00, 0x02, 0x03, 0x12, 0x03, 0x1e, 0x04, 0x32, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x04, + 0x00, 0x02, 0x03, 0x01, 0x12, 0x03, 0x1e, 0x04, 0x2d, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x04, + 0x00, 0x02, 0x03, 0x02, 0x12, 0x03, 0x1e, 0x30, 0x31, 0x0a, 0x0d, 0x0a, 0x06, 0x04, 0x02, 0x04, + 0x00, 0x02, 0x04, 0x12, 0x03, 0x1f, 0x04, 0x29, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x04, 0x00, + 0x02, 0x04, 0x01, 0x12, 0x03, 0x1f, 0x04, 0x24, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x04, 0x00, + 0x02, 0x04, 0x02, 0x12, 0x03, 0x1f, 0x27, 0x28, 0x0a, 0x44, 0x0a, 0x04, 0x04, 0x02, 0x03, 0x00, + 0x12, 0x04, 0x23, 0x02, 0x25, 0x03, 0x1a, 0x36, 0x20, 0x43, 0x6f, 0x6d, 0x62, 0x69, 0x6e, 0x65, + 0x20, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x20, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x69, + 0x65, 0x73, 0x2e, 0x20, 0x41, 0x6c, 0x6c, 0x20, 0x6d, 0x75, 0x73, 0x74, 0x20, 0x65, 0x76, 0x61, + 0x6c, 0x75, 0x61, 0x74, 0x65, 0x20, 0x74, 0x6f, 0x20, 0x74, 0x72, 0x75, 0x65, 0x0a, 0x0a, 0x0c, + 0x0a, 0x05, 0x04, 0x02, 0x03, 0x00, 0x01, 0x12, 0x03, 0x23, 0x0a, 0x16, 0x0a, 0x0d, 0x0a, 0x06, + 0x04, 0x02, 0x03, 0x00, 0x02, 0x00, 0x12, 0x03, 0x24, 0x04, 0x2b, 0x0a, 0x0e, 0x0a, 0x07, 0x04, + 0x02, 0x03, 0x00, 0x02, 0x00, 0x04, 0x12, 0x03, 0x24, 0x04, 0x0c, 0x0a, 0x0e, 0x0a, 0x07, 0x04, + 0x02, 0x03, 0x00, 0x02, 0x00, 0x06, 0x12, 0x03, 0x24, 0x0d, 0x1d, 0x0a, 0x0e, 0x0a, 0x07, 0x04, + 0x02, 0x03, 0x00, 0x02, 0x00, 0x01, 0x12, 0x03, 0x24, 0x1e, 0x26, 0x0a, 0x0e, 0x0a, 0x07, 0x04, + 0x02, 0x03, 0x00, 0x02, 0x00, 0x03, 0x12, 0x03, 0x24, 0x29, 0x2a, 0x0a, 0x44, 0x0a, 0x04, 0x04, + 0x02, 0x03, 0x01, 0x12, 0x04, 0x28, 0x02, 0x2a, 0x03, 0x1a, 0x36, 0x20, 0x43, 0x6f, 0x6d, 0x62, + 0x69, 0x6e, 0x65, 0x20, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x20, 0x70, 0x6f, 0x6c, + 0x69, 0x63, 0x69, 0x65, 0x73, 0x2e, 0x20, 0x41, 0x6e, 0x79, 0x20, 0x6d, 0x75, 0x73, 0x74, 0x20, + 0x65, 0x76, 0x61, 0x6c, 0x75, 0x61, 0x74, 0x65, 0x20, 0x74, 0x6f, 0x20, 0x74, 0x72, 0x75, 0x65, + 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x03, 0x01, 0x01, 0x12, 0x03, 0x28, 0x0a, 0x16, 0x0a, + 0x0d, 0x0a, 0x06, 0x04, 0x02, 0x03, 0x01, 0x02, 0x00, 0x12, 0x03, 0x29, 0x04, 0x2b, 0x0a, 0x0e, + 0x0a, 0x07, 0x04, 0x02, 0x03, 0x01, 0x02, 0x00, 0x04, 0x12, 0x03, 0x29, 0x04, 0x0c, 0x0a, 0x0e, + 0x0a, 0x07, 0x04, 0x02, 0x03, 0x01, 0x02, 0x00, 0x06, 0x12, 0x03, 0x29, 0x0d, 0x1d, 0x0a, 0x0e, + 0x0a, 0x07, 0x04, 0x02, 0x03, 0x01, 0x02, 0x00, 0x01, 0x12, 0x03, 0x29, 0x1e, 0x26, 0x0a, 0x0e, + 0x0a, 0x07, 0x04, 0x02, 0x03, 0x01, 0x02, 0x00, 0x03, 0x12, 0x03, 0x29, 0x29, 0x2a, 0x0a, 0x0c, + 0x0a, 0x04, 0x04, 0x02, 0x08, 0x00, 0x12, 0x04, 0x2c, 0x02, 0x30, 0x03, 0x0a, 0x0c, 0x0a, 0x05, + 0x04, 0x02, 0x08, 0x00, 0x01, 0x12, 0x03, 0x2c, 0x08, 0x0c, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x02, + 0x02, 0x00, 0x12, 0x03, 0x2d, 0x04, 0x18, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x00, 0x06, + 0x12, 0x03, 0x2d, 0x04, 0x0e, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x00, 0x01, 0x12, 0x03, + 0x2d, 0x0f, 0x13, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x00, 0x03, 0x12, 0x03, 0x2d, 0x16, + 0x17, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x02, 0x02, 0x01, 0x12, 0x03, 0x2e, 0x04, 0x23, 0x0a, 0x0c, + 0x0a, 0x05, 0x04, 0x02, 0x02, 0x01, 0x06, 0x12, 0x03, 0x2e, 0x04, 0x10, 0x0a, 0x0c, 0x0a, 0x05, + 0x04, 0x02, 0x02, 0x01, 0x01, 0x12, 0x03, 0x2e, 0x11, 0x1e, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, + 0x02, 0x01, 0x03, 0x12, 0x03, 0x2e, 0x21, 0x22, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x02, 0x02, 0x02, + 0x12, 0x03, 0x2f, 0x04, 0x23, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x02, 0x06, 0x12, 0x03, + 0x2f, 0x04, 0x10, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x02, 0x01, 0x12, 0x03, 0x2f, 0x11, + 0x1e, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x02, 0x03, 0x12, 0x03, 0x2f, 0x21, 0x22, 0x0a, + 0x35, 0x0a, 0x02, 0x04, 0x03, 0x12, 0x04, 0x34, 0x00, 0x4d, 0x01, 0x1a, 0x29, 0x20, 0x41, 0x20, + 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x67, 0x6f, 0x76, 0x65, + 0x72, 0x6e, 0x73, 0x20, 0x75, 0x70, 0x64, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x20, 0x6d, 0x65, 0x74, + 0x61, 0x64, 0x61, 0x74, 0x61, 0x0a, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x03, 0x01, 0x12, 0x03, 0x34, + 0x08, 0x16, 0x0a, 0x1b, 0x0a, 0x04, 0x04, 0x03, 0x04, 0x00, 0x12, 0x04, 0x36, 0x02, 0x3c, 0x03, + 0x1a, 0x0d, 0x20, 0x42, 0x61, 0x73, 0x65, 0x20, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x0a, 0x0a, + 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x04, 0x00, 0x01, 0x12, 0x03, 0x36, 0x07, 0x19, 0x0a, 0x0d, 0x0a, + 0x06, 0x04, 0x03, 0x04, 0x00, 0x02, 0x00, 0x12, 0x03, 0x37, 0x04, 0x29, 0x0a, 0x0e, 0x0a, 0x07, + 0x04, 0x03, 0x04, 0x00, 0x02, 0x00, 0x01, 0x12, 0x03, 0x37, 0x04, 0x24, 0x0a, 0x0e, 0x0a, 0x07, + 0x04, 0x03, 0x04, 0x00, 0x02, 0x00, 0x02, 0x12, 0x03, 0x37, 0x27, 0x28, 0x0a, 0x0d, 0x0a, 0x06, + 0x04, 0x03, 0x04, 0x00, 0x02, 0x01, 0x12, 0x03, 0x38, 0x04, 0x23, 0x0a, 0x0e, 0x0a, 0x07, 0x04, + 0x03, 0x04, 0x00, 0x02, 0x01, 0x01, 0x12, 0x03, 0x38, 0x04, 0x1e, 0x0a, 0x0e, 0x0a, 0x07, 0x04, + 0x03, 0x04, 0x00, 0x02, 0x01, 0x02, 0x12, 0x03, 0x38, 0x21, 0x22, 0x0a, 0x0d, 0x0a, 0x06, 0x04, + 0x03, 0x04, 0x00, 0x02, 0x02, 0x12, 0x03, 0x39, 0x04, 0x22, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x03, + 0x04, 0x00, 0x02, 0x02, 0x01, 0x12, 0x03, 0x39, 0x04, 0x1d, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x03, + 0x04, 0x00, 0x02, 0x02, 0x02, 0x12, 0x03, 0x39, 0x20, 0x21, 0x0a, 0x0d, 0x0a, 0x06, 0x04, 0x03, + 0x04, 0x00, 0x02, 0x03, 0x12, 0x03, 0x3a, 0x04, 0x2c, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x03, 0x04, + 0x00, 0x02, 0x03, 0x01, 0x12, 0x03, 0x3a, 0x04, 0x27, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x03, 0x04, + 0x00, 0x02, 0x03, 0x02, 0x12, 0x03, 0x3a, 0x2a, 0x2b, 0x0a, 0x0d, 0x0a, 0x06, 0x04, 0x03, 0x04, + 0x00, 0x02, 0x04, 0x12, 0x03, 0x3b, 0x04, 0x32, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x03, 0x04, 0x00, + 0x02, 0x04, 0x01, 0x12, 0x03, 0x3b, 0x04, 0x2d, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x03, 0x04, 0x00, + 0x02, 0x04, 0x02, 0x12, 0x03, 0x3b, 0x30, 0x31, 0x0a, 0x44, 0x0a, 0x04, 0x04, 0x03, 0x03, 0x00, + 0x12, 0x04, 0x3f, 0x02, 0x41, 0x03, 0x1a, 0x36, 0x20, 0x43, 0x6f, 0x6d, 0x62, 0x69, 0x6e, 0x65, + 0x20, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x20, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x69, + 0x65, 0x73, 0x2e, 0x20, 0x41, 0x6c, 0x6c, 0x20, 0x6d, 0x75, 0x73, 0x74, 0x20, 0x65, 0x76, 0x61, + 0x6c, 0x75, 0x61, 0x74, 0x65, 0x20, 0x74, 0x6f, 0x20, 0x74, 0x72, 0x75, 0x65, 0x0a, 0x0a, 0x0c, + 0x0a, 0x05, 0x04, 0x03, 0x03, 0x00, 0x01, 0x12, 0x03, 0x3f, 0x0a, 0x16, 0x0a, 0x0d, 0x0a, 0x06, + 0x04, 0x03, 0x03, 0x00, 0x02, 0x00, 0x12, 0x03, 0x40, 0x04, 0x29, 0x0a, 0x0e, 0x0a, 0x07, 0x04, + 0x03, 0x03, 0x00, 0x02, 0x00, 0x04, 0x12, 0x03, 0x40, 0x04, 0x0c, 0x0a, 0x0e, 0x0a, 0x07, 0x04, + 0x03, 0x03, 0x00, 0x02, 0x00, 0x06, 0x12, 0x03, 0x40, 0x0d, 0x1b, 0x0a, 0x0e, 0x0a, 0x07, 0x04, + 0x03, 0x03, 0x00, 0x02, 0x00, 0x01, 0x12, 0x03, 0x40, 0x1c, 0x24, 0x0a, 0x0e, 0x0a, 0x07, 0x04, + 0x03, 0x03, 0x00, 0x02, 0x00, 0x03, 0x12, 0x03, 0x40, 0x27, 0x28, 0x0a, 0x44, 0x0a, 0x04, 0x04, + 0x03, 0x03, 0x01, 0x12, 0x04, 0x44, 0x02, 0x46, 0x03, 0x1a, 0x36, 0x20, 0x43, 0x6f, 0x6d, 0x62, + 0x69, 0x6e, 0x65, 0x20, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x20, 0x70, 0x6f, 0x6c, + 0x69, 0x63, 0x69, 0x65, 0x73, 0x2e, 0x20, 0x41, 0x6e, 0x79, 0x20, 0x6d, 0x75, 0x73, 0x74, 0x20, + 0x65, 0x76, 0x61, 0x6c, 0x75, 0x61, 0x74, 0x65, 0x20, 0x74, 0x6f, 0x20, 0x74, 0x72, 0x75, 0x65, + 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x03, 0x01, 0x01, 0x12, 0x03, 0x44, 0x0a, 0x16, 0x0a, + 0x0d, 0x0a, 0x06, 0x04, 0x03, 0x03, 0x01, 0x02, 0x00, 0x12, 0x03, 0x45, 0x04, 0x29, 0x0a, 0x0e, + 0x0a, 0x07, 0x04, 0x03, 0x03, 0x01, 0x02, 0x00, 0x04, 0x12, 0x03, 0x45, 0x04, 0x0c, 0x0a, 0x0e, + 0x0a, 0x07, 0x04, 0x03, 0x03, 0x01, 0x02, 0x00, 0x06, 0x12, 0x03, 0x45, 0x0d, 0x1b, 0x0a, 0x0e, + 0x0a, 0x07, 0x04, 0x03, 0x03, 0x01, 0x02, 0x00, 0x01, 0x12, 0x03, 0x45, 0x1c, 0x24, 0x0a, 0x0e, + 0x0a, 0x07, 0x04, 0x03, 0x03, 0x01, 0x02, 0x00, 0x03, 0x12, 0x03, 0x45, 0x27, 0x28, 0x0a, 0x0c, + 0x0a, 0x04, 0x04, 0x03, 0x08, 0x00, 0x12, 0x04, 0x48, 0x02, 0x4c, 0x03, 0x0a, 0x0c, 0x0a, 0x05, + 0x04, 0x03, 0x08, 0x00, 0x01, 0x12, 0x03, 0x48, 0x08, 0x0c, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x03, + 0x02, 0x00, 0x12, 0x03, 0x49, 0x04, 0x20, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, 0x00, 0x06, + 0x12, 0x03, 0x49, 0x04, 0x16, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, 0x00, 0x01, 0x12, 0x03, + 0x49, 0x17, 0x1b, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, 0x00, 0x03, 0x12, 0x03, 0x49, 0x1e, + 0x1f, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x03, 0x02, 0x01, 0x12, 0x03, 0x4a, 0x04, 0x23, 0x0a, 0x0c, + 0x0a, 0x05, 0x04, 0x03, 0x02, 0x01, 0x06, 0x12, 0x03, 0x4a, 0x04, 0x10, 0x0a, 0x0c, 0x0a, 0x05, + 0x04, 0x03, 0x02, 0x01, 0x01, 0x12, 0x03, 0x4a, 0x11, 0x1e, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, + 0x02, 0x01, 0x03, 0x12, 0x03, 0x4a, 0x21, 0x22, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x03, 0x02, 0x02, + 0x12, 0x03, 0x4b, 0x04, 0x23, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, 0x02, 0x06, 0x12, 0x03, + 0x4b, 0x04, 0x10, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, 0x02, 0x01, 0x12, 0x03, 0x4b, 0x11, + 0x1e, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, 0x02, 0x03, 0x12, 0x03, 0x4b, 0x21, 0x22, 0x0a, + 0x38, 0x0a, 0x02, 0x04, 0x04, 0x12, 0x04, 0x50, 0x00, 0x68, 0x01, 0x1a, 0x2c, 0x20, 0x41, 0x20, + 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x67, 0x6f, 0x76, 0x65, + 0x72, 0x6e, 0x73, 0x20, 0x75, 0x70, 0x64, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x20, 0x70, 0x65, 0x72, + 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x0a, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x04, 0x01, + 0x12, 0x03, 0x50, 0x08, 0x1f, 0x0a, 0x1b, 0x0a, 0x04, 0x04, 0x04, 0x04, 0x00, 0x12, 0x04, 0x52, + 0x02, 0x57, 0x03, 0x1a, 0x0d, 0x20, 0x42, 0x61, 0x73, 0x65, 0x20, 0x70, 0x6f, 0x6c, 0x69, 0x63, + 0x79, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x04, 0x00, 0x01, 0x12, 0x03, 0x52, 0x07, 0x1c, + 0x0a, 0x0d, 0x0a, 0x06, 0x04, 0x04, 0x04, 0x00, 0x02, 0x00, 0x12, 0x03, 0x53, 0x04, 0x2c, 0x0a, + 0x0e, 0x0a, 0x07, 0x04, 0x04, 0x04, 0x00, 0x02, 0x00, 0x01, 0x12, 0x03, 0x53, 0x04, 0x27, 0x0a, + 0x0e, 0x0a, 0x07, 0x04, 0x04, 0x04, 0x00, 0x02, 0x00, 0x02, 0x12, 0x03, 0x53, 0x2a, 0x2b, 0x0a, + 0x0d, 0x0a, 0x06, 0x04, 0x04, 0x04, 0x00, 0x02, 0x01, 0x12, 0x03, 0x54, 0x04, 0x25, 0x0a, 0x0e, + 0x0a, 0x07, 0x04, 0x04, 0x04, 0x00, 0x02, 0x01, 0x01, 0x12, 0x03, 0x54, 0x04, 0x20, 0x0a, 0x0e, + 0x0a, 0x07, 0x04, 0x04, 0x04, 0x00, 0x02, 0x01, 0x02, 0x12, 0x03, 0x54, 0x23, 0x24, 0x0a, 0x0d, + 0x0a, 0x06, 0x04, 0x04, 0x04, 0x00, 0x02, 0x02, 0x12, 0x03, 0x55, 0x04, 0x2f, 0x0a, 0x0e, 0x0a, + 0x07, 0x04, 0x04, 0x04, 0x00, 0x02, 0x02, 0x01, 0x12, 0x03, 0x55, 0x04, 0x2a, 0x0a, 0x0e, 0x0a, + 0x07, 0x04, 0x04, 0x04, 0x00, 0x02, 0x02, 0x02, 0x12, 0x03, 0x55, 0x2d, 0x2e, 0x0a, 0x0d, 0x0a, + 0x06, 0x04, 0x04, 0x04, 0x00, 0x02, 0x03, 0x12, 0x03, 0x56, 0x04, 0x35, 0x0a, 0x0e, 0x0a, 0x07, + 0x04, 0x04, 0x04, 0x00, 0x02, 0x03, 0x01, 0x12, 0x03, 0x56, 0x04, 0x30, 0x0a, 0x0e, 0x0a, 0x07, + 0x04, 0x04, 0x04, 0x00, 0x02, 0x03, 0x02, 0x12, 0x03, 0x56, 0x33, 0x34, 0x0a, 0x44, 0x0a, 0x04, + 0x04, 0x04, 0x03, 0x00, 0x12, 0x04, 0x5a, 0x02, 0x5c, 0x03, 0x1a, 0x36, 0x20, 0x43, 0x6f, 0x6d, + 0x62, 0x69, 0x6e, 0x65, 0x20, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x20, 0x70, 0x6f, + 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x2e, 0x20, 0x41, 0x6c, 0x6c, 0x20, 0x6d, 0x75, 0x73, 0x74, + 0x20, 0x65, 0x76, 0x61, 0x6c, 0x75, 0x61, 0x74, 0x65, 0x20, 0x74, 0x6f, 0x20, 0x74, 0x72, 0x75, + 0x65, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x03, 0x00, 0x01, 0x12, 0x03, 0x5a, 0x0a, 0x16, + 0x0a, 0x0d, 0x0a, 0x06, 0x04, 0x04, 0x03, 0x00, 0x02, 0x00, 0x12, 0x03, 0x5b, 0x04, 0x32, 0x0a, + 0x0e, 0x0a, 0x07, 0x04, 0x04, 0x03, 0x00, 0x02, 0x00, 0x04, 0x12, 0x03, 0x5b, 0x04, 0x0c, 0x0a, + 0x0e, 0x0a, 0x07, 0x04, 0x04, 0x03, 0x00, 0x02, 0x00, 0x06, 0x12, 0x03, 0x5b, 0x0d, 0x24, 0x0a, + 0x0e, 0x0a, 0x07, 0x04, 0x04, 0x03, 0x00, 0x02, 0x00, 0x01, 0x12, 0x03, 0x5b, 0x25, 0x2d, 0x0a, + 0x0e, 0x0a, 0x07, 0x04, 0x04, 0x03, 0x00, 0x02, 0x00, 0x03, 0x12, 0x03, 0x5b, 0x30, 0x31, 0x0a, + 0x44, 0x0a, 0x04, 0x04, 0x04, 0x03, 0x01, 0x12, 0x04, 0x5f, 0x02, 0x61, 0x03, 0x1a, 0x36, 0x20, + 0x43, 0x6f, 0x6d, 0x62, 0x69, 0x6e, 0x65, 0x20, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, + 0x20, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x2e, 0x20, 0x41, 0x6e, 0x79, 0x20, 0x6d, + 0x75, 0x73, 0x74, 0x20, 0x65, 0x76, 0x61, 0x6c, 0x75, 0x61, 0x74, 0x65, 0x20, 0x74, 0x6f, 0x20, + 0x74, 0x72, 0x75, 0x65, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x03, 0x01, 0x01, 0x12, 0x03, + 0x5f, 0x0a, 0x16, 0x0a, 0x0d, 0x0a, 0x06, 0x04, 0x04, 0x03, 0x01, 0x02, 0x00, 0x12, 0x03, 0x60, + 0x04, 0x32, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x04, 0x03, 0x01, 0x02, 0x00, 0x04, 0x12, 0x03, 0x60, + 0x04, 0x0c, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x04, 0x03, 0x01, 0x02, 0x00, 0x06, 0x12, 0x03, 0x60, + 0x0d, 0x24, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x04, 0x03, 0x01, 0x02, 0x00, 0x01, 0x12, 0x03, 0x60, + 0x25, 0x2d, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x04, 0x03, 0x01, 0x02, 0x00, 0x03, 0x12, 0x03, 0x60, + 0x30, 0x31, 0x0a, 0x0c, 0x0a, 0x04, 0x04, 0x04, 0x08, 0x00, 0x12, 0x04, 0x63, 0x02, 0x67, 0x03, + 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x08, 0x00, 0x01, 0x12, 0x03, 0x63, 0x08, 0x0c, 0x0a, 0x0b, + 0x0a, 0x04, 0x04, 0x04, 0x02, 0x00, 0x12, 0x03, 0x64, 0x04, 0x23, 0x0a, 0x0c, 0x0a, 0x05, 0x04, + 0x04, 0x02, 0x00, 0x06, 0x12, 0x03, 0x64, 0x04, 0x19, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x02, + 0x00, 0x01, 0x12, 0x03, 0x64, 0x1a, 0x1e, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x02, 0x00, 0x03, + 0x12, 0x03, 0x64, 0x21, 0x22, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x04, 0x02, 0x01, 0x12, 0x03, 0x65, + 0x04, 0x23, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x02, 0x01, 0x06, 0x12, 0x03, 0x65, 0x04, 0x10, + 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x02, 0x01, 0x01, 0x12, 0x03, 0x65, 0x11, 0x1e, 0x0a, 0x0c, + 0x0a, 0x05, 0x04, 0x04, 0x02, 0x01, 0x03, 0x12, 0x03, 0x65, 0x21, 0x22, 0x0a, 0x0b, 0x0a, 0x04, + 0x04, 0x04, 0x02, 0x02, 0x12, 0x03, 0x66, 0x04, 0x23, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x02, + 0x02, 0x06, 0x12, 0x03, 0x66, 0x04, 0x10, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x02, 0x02, 0x01, + 0x12, 0x03, 0x66, 0x11, 0x1e, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x02, 0x02, 0x03, 0x12, 0x03, + 0x66, 0x21, 0x22, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, 0x0a, 0xb8, 0x1a, 0x0a, 0x2e, + 0x6d, 0x6c, 0x73, 0x2f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, + 0x65, 0x6e, 0x74, 0x73, 0x2f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x5f, + 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x19, + 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x22, 0xa7, 0x01, 0x0a, 0x10, 0x4d, 0x65, + 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x29, + 0x0a, 0x10, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, + 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x0f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, + 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x73, 0x12, 0x27, 0x0a, 0x0f, 0x61, 0x63, 0x63, + 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0e, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, + 0x73, 0x73, 0x12, 0x3f, 0x0a, 0x1c, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x74, 0x65, 0x64, 0x5f, + 0x62, 0x79, 0x5f, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, + 0x73, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x19, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x61, + 0x74, 0x65, 0x64, 0x42, 0x79, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x41, 0x64, 0x64, 0x72, + 0x65, 0x73, 0x73, 0x22, 0x80, 0x03, 0x0a, 0x16, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x4d, 0x65, 0x6d, + 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x12, 0x50, + 0x0a, 0x0d, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x5f, 0x61, 0x64, 0x64, 0x65, 0x64, 0x18, + 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, + 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, + 0x73, 0x2e, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x43, 0x68, 0x61, 0x6e, + 0x67, 0x65, 0x52, 0x0c, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x41, 0x64, 0x64, 0x65, 0x64, + 0x12, 0x54, 0x0a, 0x0f, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x5f, 0x72, 0x65, 0x6d, 0x6f, + 0x76, 0x65, 0x64, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x78, 0x6d, 0x74, 0x70, + 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, + 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, + 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x0e, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x52, + 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x12, 0x5c, 0x0a, 0x13, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, + 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x5f, 0x61, 0x64, 0x64, 0x65, 0x64, 0x18, 0x03, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, + 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, + 0x52, 0x12, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x41, + 0x64, 0x64, 0x65, 0x64, 0x12, 0x60, 0x0a, 0x15, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x5f, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x18, 0x04, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, + 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, + 0x52, 0x14, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, + 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x22, 0x9b, 0x04, 0x0a, 0x0c, 0x47, 0x72, 0x6f, 0x75, 0x70, + 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x12, 0x31, 0x0a, 0x15, 0x69, 0x6e, 0x69, 0x74, 0x69, + 0x61, 0x74, 0x65, 0x64, 0x5f, 0x62, 0x79, 0x5f, 0x69, 0x6e, 0x62, 0x6f, 0x78, 0x5f, 0x69, 0x64, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x12, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x74, 0x65, + 0x64, 0x42, 0x79, 0x49, 0x6e, 0x62, 0x6f, 0x78, 0x49, 0x64, 0x12, 0x52, 0x0a, 0x0d, 0x61, 0x64, + 0x64, 0x65, 0x64, 0x5f, 0x69, 0x6e, 0x62, 0x6f, 0x78, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x2d, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x47, 0x72, + 0x6f, 0x75, 0x70, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x2e, 0x49, 0x6e, 0x62, 0x6f, 0x78, + 0x52, 0x0c, 0x61, 0x64, 0x64, 0x65, 0x64, 0x49, 0x6e, 0x62, 0x6f, 0x78, 0x65, 0x73, 0x12, 0x56, + 0x0a, 0x0f, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x5f, 0x69, 0x6e, 0x62, 0x6f, 0x78, 0x65, + 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, + 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, + 0x6e, 0x74, 0x73, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, + 0x2e, 0x49, 0x6e, 0x62, 0x6f, 0x78, 0x52, 0x0e, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x49, + 0x6e, 0x62, 0x6f, 0x78, 0x65, 0x73, 0x12, 0x71, 0x0a, 0x16, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, + 0x74, 0x61, 0x5f, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x73, + 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x3b, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, + 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, + 0x74, 0x73, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x2e, + 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x43, 0x68, 0x61, + 0x6e, 0x67, 0x65, 0x52, 0x14, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x46, 0x69, 0x65, + 0x6c, 0x64, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x1a, 0x22, 0x0a, 0x05, 0x49, 0x6e, 0x62, + 0x6f, 0x78, 0x12, 0x19, 0x0a, 0x08, 0x69, 0x6e, 0x62, 0x6f, 0x78, 0x5f, 0x69, 0x64, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x69, 0x6e, 0x62, 0x6f, 0x78, 0x49, 0x64, 0x1a, 0x94, 0x01, + 0x0a, 0x13, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x43, + 0x68, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x5f, 0x6e, + 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x66, 0x69, 0x65, 0x6c, 0x64, + 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x09, 0x6f, 0x6c, 0x64, 0x5f, 0x76, 0x61, 0x6c, 0x75, + 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x08, 0x6f, 0x6c, 0x64, 0x56, 0x61, + 0x6c, 0x75, 0x65, 0x88, 0x01, 0x01, 0x12, 0x20, 0x0a, 0x09, 0x6e, 0x65, 0x77, 0x5f, 0x76, 0x61, + 0x6c, 0x75, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x48, 0x01, 0x52, 0x08, 0x6e, 0x65, 0x77, + 0x56, 0x61, 0x6c, 0x75, 0x65, 0x88, 0x01, 0x01, 0x42, 0x0c, 0x0a, 0x0a, 0x5f, 0x6f, 0x6c, 0x64, + 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x42, 0x0c, 0x0a, 0x0a, 0x5f, 0x6e, 0x65, 0x77, 0x5f, 0x76, + 0x61, 0x6c, 0x75, 0x65, 0x42, 0xec, 0x01, 0x0a, 0x1d, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x6d, 0x74, + 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, + 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x42, 0x17, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x63, 0x72, 0x69, + 0x70, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, + 0x01, 0x5a, 0x30, 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, 0x6d, + 0x6c, 0x73, 0x2f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, + 0x6e, 0x74, 0x73, 0xa2, 0x02, 0x03, 0x58, 0x4d, 0x4d, 0xaa, 0x02, 0x18, 0x58, 0x6d, 0x74, 0x70, + 0x2e, 0x4d, 0x6c, 0x73, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x74, + 0x65, 0x6e, 0x74, 0x73, 0xca, 0x02, 0x18, 0x58, 0x6d, 0x74, 0x70, 0x5c, 0x4d, 0x6c, 0x73, 0x5c, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0xe2, + 0x02, 0x24, 0x58, 0x6d, 0x74, 0x70, 0x5c, 0x4d, 0x6c, 0x73, 0x5c, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, + 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x1a, 0x58, 0x6d, 0x74, 0x70, 0x3a, 0x3a, 0x4d, + 0x6c, 0x73, 0x3a, 0x3a, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, + 0x6e, 0x74, 0x73, 0x4a, 0xa8, 0x0f, 0x0a, 0x06, 0x12, 0x04, 0x01, 0x00, 0x38, 0x01, 0x0a, 0x2f, + 0x0a, 0x01, 0x0c, 0x12, 0x03, 0x01, 0x00, 0x12, 0x1a, 0x25, 0x20, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x20, 0x65, 0x6e, 0x63, 0x6f, 0x64, + 0x69, 0x6e, 0x67, 0x20, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x75, 0x72, 0x65, 0x73, 0x0a, 0x0a, + 0x08, 0x0a, 0x01, 0x02, 0x12, 0x03, 0x03, 0x00, 0x22, 0x0a, 0x08, 0x0a, 0x01, 0x08, 0x12, 0x03, + 0x05, 0x00, 0x47, 0x0a, 0x09, 0x0a, 0x02, 0x08, 0x0b, 0x12, 0x03, 0x05, 0x00, 0x47, 0x0a, 0x3a, + 0x0a, 0x02, 0x04, 0x00, 0x12, 0x04, 0x09, 0x00, 0x0d, 0x01, 0x1a, 0x2e, 0x20, 0x41, 0x20, 0x67, + 0x72, 0x6f, 0x75, 0x70, 0x20, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x20, 0x61, 0x6e, 0x64, 0x20, + 0x61, 0x66, 0x66, 0x65, 0x63, 0x74, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x49, 0x44, 0x73, 0x0a, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x00, + 0x01, 0x12, 0x03, 0x09, 0x08, 0x18, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x00, 0x02, 0x00, 0x12, 0x03, + 0x0a, 0x02, 0x26, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x00, 0x04, 0x12, 0x03, 0x0a, 0x02, + 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x00, 0x05, 0x12, 0x03, 0x0a, 0x0b, 0x10, 0x0a, + 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x00, 0x01, 0x12, 0x03, 0x0a, 0x11, 0x21, 0x0a, 0x0c, 0x0a, + 0x05, 0x04, 0x00, 0x02, 0x00, 0x03, 0x12, 0x03, 0x0a, 0x24, 0x25, 0x0a, 0x0b, 0x0a, 0x04, 0x04, + 0x00, 0x02, 0x01, 0x12, 0x03, 0x0b, 0x02, 0x1d, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x01, + 0x05, 0x12, 0x03, 0x0b, 0x02, 0x08, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x01, 0x01, 0x12, + 0x03, 0x0b, 0x09, 0x18, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x01, 0x03, 0x12, 0x03, 0x0b, + 0x1b, 0x1c, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x00, 0x02, 0x02, 0x12, 0x03, 0x0c, 0x02, 0x2a, 0x0a, + 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x02, 0x05, 0x12, 0x03, 0x0c, 0x02, 0x08, 0x0a, 0x0c, 0x0a, + 0x05, 0x04, 0x00, 0x02, 0x02, 0x01, 0x12, 0x03, 0x0c, 0x09, 0x25, 0x0a, 0x0c, 0x0a, 0x05, 0x04, + 0x00, 0x02, 0x02, 0x03, 0x12, 0x03, 0x0c, 0x28, 0x29, 0x0a, 0x64, 0x0a, 0x02, 0x04, 0x01, 0x12, + 0x04, 0x10, 0x00, 0x1d, 0x01, 0x1a, 0x23, 0x20, 0x54, 0x68, 0x65, 0x20, 0x67, 0x72, 0x6f, 0x75, + 0x70, 0x20, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x20, 0x63, 0x68, 0x61, + 0x6e, 0x67, 0x65, 0x20, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x0a, 0x22, 0x33, 0x20, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x6c, 0x69, 0x6e, 0x74, 0x3a, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x52, + 0x45, 0x50, 0x45, 0x41, 0x54, 0x45, 0x44, 0x5f, 0x46, 0x49, 0x45, 0x4c, 0x44, 0x5f, 0x4e, 0x41, + 0x4d, 0x45, 0x53, 0x5f, 0x50, 0x4c, 0x55, 0x52, 0x41, 0x4c, 0x49, 0x5a, 0x45, 0x44, 0x0a, 0x0a, + 0x0a, 0x0a, 0x03, 0x04, 0x01, 0x01, 0x12, 0x03, 0x10, 0x08, 0x1e, 0x0a, 0x39, 0x0a, 0x04, 0x04, + 0x01, 0x02, 0x00, 0x12, 0x03, 0x14, 0x02, 0x2e, 0x1a, 0x2c, 0x20, 0x4d, 0x65, 0x6d, 0x62, 0x65, + 0x72, 0x73, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x68, 0x61, 0x76, 0x65, 0x20, 0x62, 0x65, 0x65, 0x6e, 0x20, 0x61, 0x64, 0x64, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, - 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x2c, 0x20, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x65, 0x64, 0x20, 0x62, - 0x79, 0x20, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, - 0x02, 0x04, 0x12, 0x03, 0x18, 0x02, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x02, 0x06, - 0x12, 0x03, 0x18, 0x0b, 0x1b, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x02, 0x01, 0x12, 0x03, - 0x18, 0x1c, 0x2f, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x02, 0x03, 0x12, 0x03, 0x18, 0x32, - 0x33, 0x0a, 0x45, 0x0a, 0x04, 0x04, 0x01, 0x02, 0x03, 0x12, 0x03, 0x1a, 0x02, 0x36, 0x1a, 0x38, - 0x20, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x72, - 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6f, - 0x6d, 0x6d, 0x69, 0x74, 0x2c, 0x20, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x65, 0x64, 0x20, 0x62, 0x79, - 0x20, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x03, - 0x04, 0x12, 0x03, 0x1a, 0x02, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x03, 0x06, 0x12, - 0x03, 0x1a, 0x0b, 0x1b, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x03, 0x01, 0x12, 0x03, 0x1a, - 0x1c, 0x31, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x03, 0x03, 0x12, 0x03, 0x1a, 0x34, 0x35, - 0x0a, 0x6b, 0x0a, 0x02, 0x04, 0x02, 0x12, 0x04, 0x21, 0x00, 0x38, 0x01, 0x1a, 0x5f, 0x20, 0x41, - 0x20, 0x73, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, - 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x20, 0x69, 0x6e, 0x20, 0x61, 0x20, 0x63, 0x6f, 0x6d, - 0x6d, 0x69, 0x74, 0x2e, 0x0a, 0x20, 0x49, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x73, 0x20, 0x61, - 0x64, 0x64, 0x65, 0x64, 0x2f, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x62, - 0x6f, 0x78, 0x65, 0x73, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x73, - 0x20, 0x74, 0x6f, 0x20, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x0a, 0x0a, 0x0a, 0x0a, - 0x03, 0x04, 0x02, 0x01, 0x12, 0x03, 0x21, 0x08, 0x14, 0x0a, 0x41, 0x0a, 0x04, 0x04, 0x02, 0x03, - 0x00, 0x12, 0x04, 0x23, 0x02, 0x25, 0x03, 0x1a, 0x33, 0x20, 0x41, 0x6e, 0x20, 0x69, 0x6e, 0x62, - 0x6f, 0x78, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x77, 0x61, 0x73, 0x20, 0x61, 0x64, 0x64, 0x65, - 0x64, 0x20, 0x6f, 0x72, 0x20, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x20, - 0x74, 0x68, 0x69, 0x73, 0x20, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, - 0x04, 0x02, 0x03, 0x00, 0x01, 0x12, 0x03, 0x23, 0x0a, 0x0f, 0x0a, 0x0d, 0x0a, 0x06, 0x04, 0x02, - 0x03, 0x00, 0x02, 0x00, 0x12, 0x03, 0x24, 0x04, 0x18, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, - 0x00, 0x02, 0x00, 0x05, 0x12, 0x03, 0x24, 0x04, 0x0a, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, - 0x00, 0x02, 0x00, 0x01, 0x12, 0x03, 0x24, 0x0b, 0x13, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, - 0x00, 0x02, 0x00, 0x03, 0x12, 0x03, 0x24, 0x16, 0x17, 0x0a, 0x3d, 0x0a, 0x04, 0x04, 0x02, 0x03, - 0x01, 0x12, 0x04, 0x28, 0x02, 0x2f, 0x03, 0x1a, 0x2f, 0x20, 0x41, 0x20, 0x73, 0x75, 0x6d, 0x6d, - 0x61, 0x72, 0x79, 0x20, 0x6f, 0x66, 0x20, 0x61, 0x20, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x20, - 0x74, 0x6f, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6d, 0x75, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x6d, - 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x03, 0x01, - 0x01, 0x12, 0x03, 0x28, 0x0a, 0x1d, 0x0a, 0x2b, 0x0a, 0x06, 0x04, 0x02, 0x03, 0x01, 0x02, 0x00, - 0x12, 0x03, 0x2a, 0x04, 0x1a, 0x1a, 0x1c, 0x20, 0x54, 0x68, 0x65, 0x20, 0x66, 0x69, 0x65, 0x6c, - 0x64, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x77, 0x61, 0x73, 0x20, 0x63, 0x68, 0x61, 0x6e, 0x67, - 0x65, 0x64, 0x0a, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, 0x01, 0x02, 0x00, 0x05, 0x12, 0x03, - 0x2a, 0x04, 0x0a, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, 0x01, 0x02, 0x00, 0x01, 0x12, 0x03, - 0x2a, 0x0b, 0x15, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, 0x01, 0x02, 0x00, 0x03, 0x12, 0x03, - 0x2a, 0x18, 0x19, 0x0a, 0x23, 0x0a, 0x06, 0x04, 0x02, 0x03, 0x01, 0x02, 0x01, 0x12, 0x03, 0x2c, - 0x04, 0x22, 0x1a, 0x14, 0x20, 0x54, 0x68, 0x65, 0x20, 0x70, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, - 0x73, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x0a, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, 0x01, - 0x02, 0x01, 0x04, 0x12, 0x03, 0x2c, 0x04, 0x0c, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, 0x01, - 0x02, 0x01, 0x05, 0x12, 0x03, 0x2c, 0x0d, 0x13, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, 0x01, - 0x02, 0x01, 0x01, 0x12, 0x03, 0x2c, 0x14, 0x1d, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, 0x01, - 0x02, 0x01, 0x03, 0x12, 0x03, 0x2c, 0x20, 0x21, 0x0a, 0x22, 0x0a, 0x06, 0x04, 0x02, 0x03, 0x01, - 0x02, 0x02, 0x12, 0x03, 0x2e, 0x04, 0x22, 0x1a, 0x13, 0x20, 0x54, 0x68, 0x65, 0x20, 0x75, 0x70, - 0x64, 0x61, 0x74, 0x65, 0x64, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x0a, 0x0a, 0x0e, 0x0a, 0x07, - 0x04, 0x02, 0x03, 0x01, 0x02, 0x02, 0x04, 0x12, 0x03, 0x2e, 0x04, 0x0c, 0x0a, 0x0e, 0x0a, 0x07, - 0x04, 0x02, 0x03, 0x01, 0x02, 0x02, 0x05, 0x12, 0x03, 0x2e, 0x0d, 0x13, 0x0a, 0x0e, 0x0a, 0x07, - 0x04, 0x02, 0x03, 0x01, 0x02, 0x02, 0x01, 0x12, 0x03, 0x2e, 0x14, 0x1d, 0x0a, 0x0e, 0x0a, 0x07, - 0x04, 0x02, 0x03, 0x01, 0x02, 0x02, 0x03, 0x12, 0x03, 0x2e, 0x20, 0x21, 0x0a, 0x0b, 0x0a, 0x04, - 0x04, 0x02, 0x02, 0x00, 0x12, 0x03, 0x31, 0x02, 0x23, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, - 0x00, 0x05, 0x12, 0x03, 0x31, 0x02, 0x08, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x00, 0x01, - 0x12, 0x03, 0x31, 0x09, 0x1e, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x00, 0x03, 0x12, 0x03, - 0x31, 0x21, 0x22, 0x0a, 0x2e, 0x0a, 0x04, 0x04, 0x02, 0x02, 0x01, 0x12, 0x03, 0x33, 0x02, 0x23, - 0x1a, 0x21, 0x20, 0x54, 0x68, 0x65, 0x20, 0x69, 0x6e, 0x62, 0x6f, 0x78, 0x65, 0x73, 0x20, 0x61, - 0x64, 0x64, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6f, 0x6d, 0x6d, - 0x69, 0x74, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x01, 0x04, 0x12, 0x03, 0x33, 0x02, - 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x01, 0x06, 0x12, 0x03, 0x33, 0x0b, 0x10, 0x0a, - 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x01, 0x01, 0x12, 0x03, 0x33, 0x11, 0x1e, 0x0a, 0x0c, 0x0a, - 0x05, 0x04, 0x02, 0x02, 0x01, 0x03, 0x12, 0x03, 0x33, 0x21, 0x22, 0x0a, 0x30, 0x0a, 0x04, 0x04, - 0x02, 0x02, 0x02, 0x12, 0x03, 0x35, 0x02, 0x25, 0x1a, 0x23, 0x20, 0x54, 0x68, 0x65, 0x20, 0x69, - 0x6e, 0x62, 0x6f, 0x78, 0x65, 0x73, 0x20, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x20, 0x69, - 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x0a, 0x0a, 0x0c, 0x0a, - 0x05, 0x04, 0x02, 0x02, 0x02, 0x04, 0x12, 0x03, 0x35, 0x02, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, - 0x02, 0x02, 0x02, 0x06, 0x12, 0x03, 0x35, 0x0b, 0x10, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, - 0x02, 0x01, 0x12, 0x03, 0x35, 0x11, 0x20, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x02, 0x03, - 0x12, 0x03, 0x35, 0x23, 0x24, 0x0a, 0x31, 0x0a, 0x04, 0x04, 0x02, 0x02, 0x03, 0x12, 0x03, 0x37, - 0x02, 0x3a, 0x1a, 0x24, 0x20, 0x54, 0x68, 0x65, 0x20, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, - 0x61, 0x20, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, - 0x20, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x03, - 0x04, 0x12, 0x03, 0x37, 0x02, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x03, 0x06, 0x12, - 0x03, 0x37, 0x0b, 0x1e, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x03, 0x01, 0x12, 0x03, 0x37, - 0x1f, 0x35, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x03, 0x03, 0x12, 0x03, 0x37, 0x38, 0x39, - 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x00, 0x04, 0x12, + 0x03, 0x14, 0x02, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x00, 0x06, 0x12, 0x03, 0x14, + 0x0b, 0x1b, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x00, 0x01, 0x12, 0x03, 0x14, 0x1c, 0x29, + 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x00, 0x03, 0x12, 0x03, 0x14, 0x2c, 0x2d, 0x0a, 0x3b, + 0x0a, 0x04, 0x04, 0x01, 0x02, 0x01, 0x12, 0x03, 0x16, 0x02, 0x30, 0x1a, 0x2e, 0x20, 0x4d, 0x65, + 0x6d, 0x62, 0x65, 0x72, 0x73, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x68, 0x61, 0x76, 0x65, 0x20, + 0x62, 0x65, 0x65, 0x6e, 0x20, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, + 0x01, 0x02, 0x01, 0x04, 0x12, 0x03, 0x16, 0x02, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, + 0x01, 0x06, 0x12, 0x03, 0x16, 0x0b, 0x1b, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x01, 0x01, + 0x12, 0x03, 0x16, 0x1c, 0x2b, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x01, 0x03, 0x12, 0x03, + 0x16, 0x2e, 0x2f, 0x0a, 0x52, 0x0a, 0x04, 0x04, 0x01, 0x02, 0x02, 0x12, 0x03, 0x18, 0x02, 0x34, + 0x1a, 0x45, 0x20, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, + 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x68, 0x61, 0x76, 0x65, 0x20, 0x62, 0x65, 0x65, 0x6e, 0x20, + 0x61, 0x64, 0x64, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6f, 0x6d, + 0x6d, 0x69, 0x74, 0x2c, 0x20, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x65, 0x64, 0x20, 0x62, 0x79, 0x20, + 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x02, 0x04, + 0x12, 0x03, 0x18, 0x02, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x02, 0x06, 0x12, 0x03, + 0x18, 0x0b, 0x1b, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x02, 0x01, 0x12, 0x03, 0x18, 0x1c, + 0x2f, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x02, 0x03, 0x12, 0x03, 0x18, 0x32, 0x33, 0x0a, + 0x45, 0x0a, 0x04, 0x04, 0x01, 0x02, 0x03, 0x12, 0x03, 0x1a, 0x02, 0x36, 0x1a, 0x38, 0x20, 0x49, + 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x72, 0x65, 0x6d, + 0x6f, 0x76, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6f, 0x6d, 0x6d, + 0x69, 0x74, 0x2c, 0x20, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x65, 0x64, 0x20, 0x62, 0x79, 0x20, 0x6d, + 0x65, 0x6d, 0x62, 0x65, 0x72, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x03, 0x04, 0x12, + 0x03, 0x1a, 0x02, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x03, 0x06, 0x12, 0x03, 0x1a, + 0x0b, 0x1b, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x03, 0x01, 0x12, 0x03, 0x1a, 0x1c, 0x31, + 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x03, 0x03, 0x12, 0x03, 0x1a, 0x34, 0x35, 0x0a, 0x6b, + 0x0a, 0x02, 0x04, 0x02, 0x12, 0x04, 0x21, 0x00, 0x38, 0x01, 0x1a, 0x5f, 0x20, 0x41, 0x20, 0x73, + 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x68, + 0x61, 0x6e, 0x67, 0x65, 0x73, 0x20, 0x69, 0x6e, 0x20, 0x61, 0x20, 0x63, 0x6f, 0x6d, 0x6d, 0x69, + 0x74, 0x2e, 0x0a, 0x20, 0x49, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x73, 0x20, 0x61, 0x64, 0x64, + 0x65, 0x64, 0x2f, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x62, 0x6f, 0x78, + 0x65, 0x73, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x20, 0x74, + 0x6f, 0x20, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x0a, 0x0a, 0x0a, 0x0a, 0x03, 0x04, + 0x02, 0x01, 0x12, 0x03, 0x21, 0x08, 0x14, 0x0a, 0x41, 0x0a, 0x04, 0x04, 0x02, 0x03, 0x00, 0x12, + 0x04, 0x23, 0x02, 0x25, 0x03, 0x1a, 0x33, 0x20, 0x41, 0x6e, 0x20, 0x69, 0x6e, 0x62, 0x6f, 0x78, + 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x77, 0x61, 0x73, 0x20, 0x61, 0x64, 0x64, 0x65, 0x64, 0x20, + 0x6f, 0x72, 0x20, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, + 0x69, 0x73, 0x20, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, + 0x03, 0x00, 0x01, 0x12, 0x03, 0x23, 0x0a, 0x0f, 0x0a, 0x0d, 0x0a, 0x06, 0x04, 0x02, 0x03, 0x00, + 0x02, 0x00, 0x12, 0x03, 0x24, 0x04, 0x18, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, 0x00, 0x02, + 0x00, 0x05, 0x12, 0x03, 0x24, 0x04, 0x0a, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, 0x00, 0x02, + 0x00, 0x01, 0x12, 0x03, 0x24, 0x0b, 0x13, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, 0x00, 0x02, + 0x00, 0x03, 0x12, 0x03, 0x24, 0x16, 0x17, 0x0a, 0x3d, 0x0a, 0x04, 0x04, 0x02, 0x03, 0x01, 0x12, + 0x04, 0x28, 0x02, 0x2f, 0x03, 0x1a, 0x2f, 0x20, 0x41, 0x20, 0x73, 0x75, 0x6d, 0x6d, 0x61, 0x72, + 0x79, 0x20, 0x6f, 0x66, 0x20, 0x61, 0x20, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x20, 0x74, 0x6f, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x6d, 0x75, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x6d, 0x65, 0x74, + 0x61, 0x64, 0x61, 0x74, 0x61, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x03, 0x01, 0x01, 0x12, + 0x03, 0x28, 0x0a, 0x1d, 0x0a, 0x2b, 0x0a, 0x06, 0x04, 0x02, 0x03, 0x01, 0x02, 0x00, 0x12, 0x03, + 0x2a, 0x04, 0x1a, 0x1a, 0x1c, 0x20, 0x54, 0x68, 0x65, 0x20, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x20, + 0x74, 0x68, 0x61, 0x74, 0x20, 0x77, 0x61, 0x73, 0x20, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, + 0x0a, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, 0x01, 0x02, 0x00, 0x05, 0x12, 0x03, 0x2a, 0x04, + 0x0a, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, 0x01, 0x02, 0x00, 0x01, 0x12, 0x03, 0x2a, 0x0b, + 0x15, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, 0x01, 0x02, 0x00, 0x03, 0x12, 0x03, 0x2a, 0x18, + 0x19, 0x0a, 0x23, 0x0a, 0x06, 0x04, 0x02, 0x03, 0x01, 0x02, 0x01, 0x12, 0x03, 0x2c, 0x04, 0x22, + 0x1a, 0x14, 0x20, 0x54, 0x68, 0x65, 0x20, 0x70, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x20, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x0a, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, 0x01, 0x02, 0x01, + 0x04, 0x12, 0x03, 0x2c, 0x04, 0x0c, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, 0x01, 0x02, 0x01, + 0x05, 0x12, 0x03, 0x2c, 0x0d, 0x13, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, 0x01, 0x02, 0x01, + 0x01, 0x12, 0x03, 0x2c, 0x14, 0x1d, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, 0x01, 0x02, 0x01, + 0x03, 0x12, 0x03, 0x2c, 0x20, 0x21, 0x0a, 0x22, 0x0a, 0x06, 0x04, 0x02, 0x03, 0x01, 0x02, 0x02, + 0x12, 0x03, 0x2e, 0x04, 0x22, 0x1a, 0x13, 0x20, 0x54, 0x68, 0x65, 0x20, 0x75, 0x70, 0x64, 0x61, + 0x74, 0x65, 0x64, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x0a, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, + 0x03, 0x01, 0x02, 0x02, 0x04, 0x12, 0x03, 0x2e, 0x04, 0x0c, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, + 0x03, 0x01, 0x02, 0x02, 0x05, 0x12, 0x03, 0x2e, 0x0d, 0x13, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, + 0x03, 0x01, 0x02, 0x02, 0x01, 0x12, 0x03, 0x2e, 0x14, 0x1d, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, + 0x03, 0x01, 0x02, 0x02, 0x03, 0x12, 0x03, 0x2e, 0x20, 0x21, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x02, + 0x02, 0x00, 0x12, 0x03, 0x31, 0x02, 0x23, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x00, 0x05, + 0x12, 0x03, 0x31, 0x02, 0x08, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x00, 0x01, 0x12, 0x03, + 0x31, 0x09, 0x1e, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x00, 0x03, 0x12, 0x03, 0x31, 0x21, + 0x22, 0x0a, 0x2e, 0x0a, 0x04, 0x04, 0x02, 0x02, 0x01, 0x12, 0x03, 0x33, 0x02, 0x23, 0x1a, 0x21, + 0x20, 0x54, 0x68, 0x65, 0x20, 0x69, 0x6e, 0x62, 0x6f, 0x78, 0x65, 0x73, 0x20, 0x61, 0x64, 0x64, + 0x65, 0x64, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, + 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x01, 0x04, 0x12, 0x03, 0x33, 0x02, 0x0a, 0x0a, + 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x01, 0x06, 0x12, 0x03, 0x33, 0x0b, 0x10, 0x0a, 0x0c, 0x0a, + 0x05, 0x04, 0x02, 0x02, 0x01, 0x01, 0x12, 0x03, 0x33, 0x11, 0x1e, 0x0a, 0x0c, 0x0a, 0x05, 0x04, + 0x02, 0x02, 0x01, 0x03, 0x12, 0x03, 0x33, 0x21, 0x22, 0x0a, 0x30, 0x0a, 0x04, 0x04, 0x02, 0x02, + 0x02, 0x12, 0x03, 0x35, 0x02, 0x25, 0x1a, 0x23, 0x20, 0x54, 0x68, 0x65, 0x20, 0x69, 0x6e, 0x62, + 0x6f, 0x78, 0x65, 0x73, 0x20, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, + 0x02, 0x02, 0x02, 0x04, 0x12, 0x03, 0x35, 0x02, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, + 0x02, 0x06, 0x12, 0x03, 0x35, 0x0b, 0x10, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x02, 0x01, + 0x12, 0x03, 0x35, 0x11, 0x20, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x02, 0x03, 0x12, 0x03, + 0x35, 0x23, 0x24, 0x0a, 0x31, 0x0a, 0x04, 0x04, 0x02, 0x02, 0x03, 0x12, 0x03, 0x37, 0x02, 0x3a, + 0x1a, 0x24, 0x20, 0x54, 0x68, 0x65, 0x20, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x20, + 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, + 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x03, 0x04, 0x12, + 0x03, 0x37, 0x02, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x03, 0x06, 0x12, 0x03, 0x37, + 0x0b, 0x1e, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x03, 0x01, 0x12, 0x03, 0x37, 0x1f, 0x35, + 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x03, 0x03, 0x12, 0x03, 0x37, 0x38, 0x39, 0x62, 0x06, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, ]; include!("xmtp.mls.message_contents.serde.rs"); // @@protoc_insertion_point(module) \ No newline at end of file diff --git a/xmtp_proto/src/gen/xmtp.mls.message_contents.serde.rs b/xmtp_proto/src/gen/xmtp.mls.message_contents.serde.rs index cfda67548..a7f5af0e8 100644 --- a/xmtp_proto/src/gen/xmtp.mls.message_contents.serde.rs +++ b/xmtp_proto/src/gen/xmtp.mls.message_contents.serde.rs @@ -4068,9 +4068,7 @@ impl serde::Serialize for UserPreferenceUpdate { } let mut struct_ser = serializer.serialize_struct("xmtp.mls.message_contents.UserPreferenceUpdate", len)?; if !self.content.is_empty() { - #[allow(clippy::needless_borrow)] - #[allow(clippy::needless_borrows_for_generic_args)] - struct_ser.serialize_field("content", pbjson::private::base64::encode(&self.content).as_str())?; + struct_ser.serialize_field("content", &self.content.iter().map(pbjson::private::base64::encode).collect::>())?; } struct_ser.end() } @@ -4137,7 +4135,8 @@ impl<'de> serde::Deserialize<'de> for UserPreferenceUpdate { return Err(serde::de::Error::duplicate_field("content")); } content__ = - Some(map_.next_value::<::pbjson::private::BytesDeserialize<_>>()?.0) + Some(map_.next_value::>>()? + .into_iter().map(|x| x.0).collect()) ; } } From 7c7dbdbfc59bd792321b61845660117ec851341a Mon Sep 17 00:00:00 2001 From: Dakota Brink <779390+codabrink@users.noreply.github.com> Date: Fri, 13 Dec 2024 11:11:41 -0500 Subject: [PATCH 46/46] proto lint (#1411) --- .../src/groups/device_sync/preference_sync.rs | 4 +- .../src/gen/xmtp.mls.message_contents.rs | 2278 ++++++++--------- .../gen/xmtp.mls.message_contents.serde.rs | 24 +- 3 files changed, 1153 insertions(+), 1153 deletions(-) diff --git a/xmtp_mls/src/groups/device_sync/preference_sync.rs b/xmtp_mls/src/groups/device_sync/preference_sync.rs index c1de9bebf..9f23374b1 100644 --- a/xmtp_mls/src/groups/device_sync/preference_sync.rs +++ b/xmtp_mls/src/groups/device_sync/preference_sync.rs @@ -29,7 +29,7 @@ impl UserPreferenceUpdate { .iter() .map(bincode::serialize) .collect::, _>>()?; - let update_proto = UserPreferenceUpdateProto { content: updates }; + let update_proto = UserPreferenceUpdateProto { contents: updates }; let content_bytes = serde_json::to_vec(&update_proto)?; sync_group.prepare_message(&content_bytes, &provider, |now| PlaintextEnvelope { content: Some(Content::V2(V2 { @@ -50,7 +50,7 @@ impl UserPreferenceUpdate { ) -> Result, StorageError> { let conn = provider.conn_ref(); - let proto_content = update_proto.content; + let proto_content = update_proto.contents; let mut updates = Vec::with_capacity(proto_content.len()); let mut consent_updates = vec![]; diff --git a/xmtp_proto/src/gen/xmtp.mls.message_contents.rs b/xmtp_proto/src/gen/xmtp.mls.message_contents.rs index 6cdc4be11..1193804ab 100644 --- a/xmtp_proto/src/gen/xmtp.mls.message_contents.rs +++ b/xmtp_proto/src/gen/xmtp.mls.message_contents.rs @@ -159,7 +159,7 @@ pub mod device_sync_key_type { #[derive(Clone, PartialEq, ::prost::Message)] pub struct UserPreferenceUpdate { #[prost(bytes="vec", repeated, tag="1")] - pub content: ::prost::alloc::vec::Vec<::prost::alloc::vec::Vec>, + pub contents: ::prost::alloc::vec::Vec<::prost::alloc::vec::Vec>, } /// Recognized compression algorithms /// protolint:disable ENUM_FIELD_NAMES_ZERO_VALUE_END_WITH @@ -616,7 +616,7 @@ pub mod group_updated { } /// Encoded file descriptor set for the `xmtp.mls.message_contents` package pub const FILE_DESCRIPTOR_SET: &[u8] = &[ - 0x0a, 0xba, 0x34, 0x0a, 0x22, 0x6d, 0x6c, 0x73, 0x2f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x0a, 0xbc, 0x34, 0x0a, 0x22, 0x6d, 0x6c, 0x73, 0x2f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x19, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, @@ -722,175 +722,159 @@ pub const FILE_DESCRIPTOR_SET: &[u8] = &[ 0x53, 0x79, 0x6e, 0x63, 0x4b, 0x65, 0x79, 0x54, 0x79, 0x70, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x61, 0x65, 0x73, 0x5f, 0x32, 0x35, 0x36, 0x5f, 0x67, 0x63, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x00, 0x52, 0x09, 0x61, 0x65, 0x73, 0x32, 0x35, 0x36, 0x47, 0x63, 0x6d, 0x42, 0x05, 0x0a, - 0x03, 0x6b, 0x65, 0x79, 0x22, 0x30, 0x0a, 0x14, 0x55, 0x73, 0x65, 0x72, 0x50, 0x72, 0x65, 0x66, - 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x18, 0x0a, 0x07, - 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x07, 0x63, - 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2a, 0x3c, 0x0a, 0x0b, 0x43, 0x6f, 0x6d, 0x70, 0x72, 0x65, - 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x17, 0x0a, 0x13, 0x43, 0x4f, 0x4d, 0x50, 0x52, 0x45, 0x53, - 0x53, 0x49, 0x4f, 0x4e, 0x5f, 0x44, 0x45, 0x46, 0x4c, 0x41, 0x54, 0x45, 0x10, 0x00, 0x12, 0x14, - 0x0a, 0x10, 0x43, 0x4f, 0x4d, 0x50, 0x52, 0x45, 0x53, 0x53, 0x49, 0x4f, 0x4e, 0x5f, 0x47, 0x5a, - 0x49, 0x50, 0x10, 0x01, 0x2a, 0x76, 0x0a, 0x0e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x53, 0x79, - 0x6e, 0x63, 0x4b, 0x69, 0x6e, 0x64, 0x12, 0x20, 0x0a, 0x1c, 0x44, 0x45, 0x56, 0x49, 0x43, 0x45, - 0x5f, 0x53, 0x59, 0x4e, 0x43, 0x5f, 0x4b, 0x49, 0x4e, 0x44, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, - 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x24, 0x0a, 0x20, 0x44, 0x45, 0x56, 0x49, - 0x43, 0x45, 0x5f, 0x53, 0x59, 0x4e, 0x43, 0x5f, 0x4b, 0x49, 0x4e, 0x44, 0x5f, 0x4d, 0x45, 0x53, - 0x53, 0x41, 0x47, 0x45, 0x5f, 0x48, 0x49, 0x53, 0x54, 0x4f, 0x52, 0x59, 0x10, 0x01, 0x12, 0x1c, - 0x0a, 0x18, 0x44, 0x45, 0x56, 0x49, 0x43, 0x45, 0x5f, 0x53, 0x59, 0x4e, 0x43, 0x5f, 0x4b, 0x49, - 0x4e, 0x44, 0x5f, 0x43, 0x4f, 0x4e, 0x53, 0x45, 0x4e, 0x54, 0x10, 0x02, 0x42, 0xe1, 0x01, 0x0a, - 0x1d, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x42, 0x0c, - 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x30, - 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, 0x6d, 0x6c, 0x73, 0x2f, + 0x03, 0x6b, 0x65, 0x79, 0x22, 0x32, 0x0a, 0x14, 0x55, 0x73, 0x65, 0x72, 0x50, 0x72, 0x65, 0x66, + 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x1a, 0x0a, 0x08, + 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x08, + 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2a, 0x3c, 0x0a, 0x0b, 0x43, 0x6f, 0x6d, 0x70, + 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x17, 0x0a, 0x13, 0x43, 0x4f, 0x4d, 0x50, 0x52, + 0x45, 0x53, 0x53, 0x49, 0x4f, 0x4e, 0x5f, 0x44, 0x45, 0x46, 0x4c, 0x41, 0x54, 0x45, 0x10, 0x00, + 0x12, 0x14, 0x0a, 0x10, 0x43, 0x4f, 0x4d, 0x50, 0x52, 0x45, 0x53, 0x53, 0x49, 0x4f, 0x4e, 0x5f, + 0x47, 0x5a, 0x49, 0x50, 0x10, 0x01, 0x2a, 0x76, 0x0a, 0x0e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, + 0x53, 0x79, 0x6e, 0x63, 0x4b, 0x69, 0x6e, 0x64, 0x12, 0x20, 0x0a, 0x1c, 0x44, 0x45, 0x56, 0x49, + 0x43, 0x45, 0x5f, 0x53, 0x59, 0x4e, 0x43, 0x5f, 0x4b, 0x49, 0x4e, 0x44, 0x5f, 0x55, 0x4e, 0x53, + 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x24, 0x0a, 0x20, 0x44, 0x45, + 0x56, 0x49, 0x43, 0x45, 0x5f, 0x53, 0x59, 0x4e, 0x43, 0x5f, 0x4b, 0x49, 0x4e, 0x44, 0x5f, 0x4d, + 0x45, 0x53, 0x53, 0x41, 0x47, 0x45, 0x5f, 0x48, 0x49, 0x53, 0x54, 0x4f, 0x52, 0x59, 0x10, 0x01, + 0x12, 0x1c, 0x0a, 0x18, 0x44, 0x45, 0x56, 0x49, 0x43, 0x45, 0x5f, 0x53, 0x59, 0x4e, 0x43, 0x5f, + 0x4b, 0x49, 0x4e, 0x44, 0x5f, 0x43, 0x4f, 0x4e, 0x53, 0x45, 0x4e, 0x54, 0x10, 0x02, 0x42, 0xe1, + 0x01, 0x0a, 0x1d, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, - 0xa2, 0x02, 0x03, 0x58, 0x4d, 0x4d, 0xaa, 0x02, 0x18, 0x58, 0x6d, 0x74, 0x70, 0x2e, 0x4d, 0x6c, - 0x73, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, - 0x73, 0xca, 0x02, 0x18, 0x58, 0x6d, 0x74, 0x70, 0x5c, 0x4d, 0x6c, 0x73, 0x5c, 0x4d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0xe2, 0x02, 0x24, 0x58, - 0x6d, 0x74, 0x70, 0x5c, 0x4d, 0x6c, 0x73, 0x5c, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x43, - 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, - 0x61, 0x74, 0x61, 0xea, 0x02, 0x1a, 0x58, 0x6d, 0x74, 0x70, 0x3a, 0x3a, 0x4d, 0x6c, 0x73, 0x3a, - 0x3a, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, - 0x4a, 0xc2, 0x23, 0x0a, 0x06, 0x12, 0x04, 0x02, 0x00, 0x78, 0x01, 0x0a, 0x7c, 0x0a, 0x01, 0x0c, - 0x12, 0x03, 0x02, 0x00, 0x12, 0x1a, 0x72, 0x20, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x20, - 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x20, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, - 0x20, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x75, 0x72, 0x65, 0x73, 0x0a, 0x20, 0x43, 0x6f, 0x70, - 0x69, 0x65, 0x64, 0x20, 0x66, 0x72, 0x6f, 0x6d, 0x20, 0x56, 0x32, 0x20, 0x63, 0x6f, 0x64, 0x65, - 0x20, 0x73, 0x6f, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x77, 0x65, 0x20, 0x63, 0x61, 0x6e, 0x20, - 0x65, 0x76, 0x65, 0x6e, 0x74, 0x75, 0x61, 0x6c, 0x6c, 0x79, 0x20, 0x72, 0x65, 0x74, 0x69, 0x72, - 0x65, 0x20, 0x61, 0x6c, 0x6c, 0x20, 0x56, 0x32, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x0a, 0x0a, 0x08, 0x0a, 0x01, 0x02, 0x12, 0x03, - 0x04, 0x00, 0x22, 0x0a, 0x08, 0x0a, 0x01, 0x08, 0x12, 0x03, 0x06, 0x00, 0x47, 0x0a, 0x09, 0x0a, - 0x02, 0x08, 0x0b, 0x12, 0x03, 0x06, 0x00, 0x47, 0x0a, 0x58, 0x0a, 0x02, 0x04, 0x00, 0x12, 0x04, - 0x0a, 0x00, 0x0f, 0x01, 0x1a, 0x4c, 0x20, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x54, 0x79, - 0x70, 0x65, 0x49, 0x64, 0x20, 0x69, 0x73, 0x20, 0x75, 0x73, 0x65, 0x64, 0x20, 0x74, 0x6f, 0x20, - 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x79, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x79, 0x70, - 0x65, 0x20, 0x6f, 0x66, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x20, 0x73, 0x74, 0x6f, - 0x72, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x20, 0x61, 0x20, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x2e, 0x0a, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x00, 0x01, 0x12, 0x03, 0x0a, 0x08, 0x15, 0x0a, 0x34, - 0x0a, 0x04, 0x04, 0x00, 0x02, 0x00, 0x12, 0x03, 0x0b, 0x02, 0x1a, 0x22, 0x27, 0x20, 0x61, 0x75, - 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x67, 0x6f, 0x76, 0x65, 0x72, 0x6e, 0x69, 0x6e, - 0x67, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x20, 0x74, - 0x79, 0x70, 0x65, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x00, 0x05, 0x12, 0x03, 0x0b, - 0x02, 0x08, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x00, 0x01, 0x12, 0x03, 0x0b, 0x09, 0x15, - 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x00, 0x03, 0x12, 0x03, 0x0b, 0x18, 0x19, 0x0a, 0x1e, - 0x0a, 0x04, 0x04, 0x00, 0x02, 0x01, 0x12, 0x03, 0x0c, 0x02, 0x15, 0x22, 0x11, 0x20, 0x74, 0x79, - 0x70, 0x65, 0x20, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x0a, 0x0a, 0x0c, - 0x0a, 0x05, 0x04, 0x00, 0x02, 0x01, 0x05, 0x12, 0x03, 0x0c, 0x02, 0x08, 0x0a, 0x0c, 0x0a, 0x05, - 0x04, 0x00, 0x02, 0x01, 0x01, 0x12, 0x03, 0x0c, 0x09, 0x10, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, - 0x02, 0x01, 0x03, 0x12, 0x03, 0x0c, 0x13, 0x14, 0x0a, 0x28, 0x0a, 0x04, 0x04, 0x00, 0x02, 0x02, - 0x12, 0x03, 0x0d, 0x02, 0x1b, 0x22, 0x1b, 0x20, 0x6d, 0x61, 0x6a, 0x6f, 0x72, 0x20, 0x76, 0x65, - 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x79, 0x70, - 0x65, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x02, 0x05, 0x12, 0x03, 0x0d, 0x02, 0x08, - 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x02, 0x01, 0x12, 0x03, 0x0d, 0x09, 0x16, 0x0a, 0x0c, - 0x0a, 0x05, 0x04, 0x00, 0x02, 0x02, 0x03, 0x12, 0x03, 0x0d, 0x19, 0x1a, 0x0a, 0x28, 0x0a, 0x04, - 0x04, 0x00, 0x02, 0x03, 0x12, 0x03, 0x0e, 0x02, 0x1b, 0x22, 0x1b, 0x20, 0x6d, 0x69, 0x6e, 0x6f, - 0x72, 0x20, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, - 0x20, 0x74, 0x79, 0x70, 0x65, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x03, 0x05, 0x12, - 0x03, 0x0e, 0x02, 0x08, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x03, 0x01, 0x12, 0x03, 0x0e, - 0x09, 0x16, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x03, 0x03, 0x12, 0x03, 0x0e, 0x19, 0x1a, - 0x0a, 0x67, 0x0a, 0x02, 0x05, 0x00, 0x12, 0x04, 0x13, 0x00, 0x16, 0x01, 0x1a, 0x5b, 0x20, 0x52, - 0x65, 0x63, 0x6f, 0x67, 0x6e, 0x69, 0x7a, 0x65, 0x64, 0x20, 0x63, 0x6f, 0x6d, 0x70, 0x72, 0x65, - 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x61, 0x6c, 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x73, - 0x0a, 0x20, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x6c, 0x69, 0x6e, 0x74, 0x3a, 0x64, 0x69, 0x73, 0x61, - 0x62, 0x6c, 0x65, 0x20, 0x45, 0x4e, 0x55, 0x4d, 0x5f, 0x46, 0x49, 0x45, 0x4c, 0x44, 0x5f, 0x4e, - 0x41, 0x4d, 0x45, 0x53, 0x5f, 0x5a, 0x45, 0x52, 0x4f, 0x5f, 0x56, 0x41, 0x4c, 0x55, 0x45, 0x5f, - 0x45, 0x4e, 0x44, 0x5f, 0x57, 0x49, 0x54, 0x48, 0x0a, 0x0a, 0x0a, 0x0a, 0x03, 0x05, 0x00, 0x01, - 0x12, 0x03, 0x13, 0x05, 0x10, 0x0a, 0x0b, 0x0a, 0x04, 0x05, 0x00, 0x02, 0x00, 0x12, 0x03, 0x14, - 0x02, 0x1a, 0x0a, 0x0c, 0x0a, 0x05, 0x05, 0x00, 0x02, 0x00, 0x01, 0x12, 0x03, 0x14, 0x02, 0x15, - 0x0a, 0x0c, 0x0a, 0x05, 0x05, 0x00, 0x02, 0x00, 0x02, 0x12, 0x03, 0x14, 0x18, 0x19, 0x0a, 0x0b, - 0x0a, 0x04, 0x05, 0x00, 0x02, 0x01, 0x12, 0x03, 0x15, 0x02, 0x17, 0x0a, 0x0c, 0x0a, 0x05, 0x05, - 0x00, 0x02, 0x01, 0x01, 0x12, 0x03, 0x15, 0x02, 0x12, 0x0a, 0x0c, 0x0a, 0x05, 0x05, 0x00, 0x02, - 0x01, 0x02, 0x12, 0x03, 0x15, 0x15, 0x16, 0x0a, 0xa3, 0x01, 0x0a, 0x02, 0x04, 0x01, 0x12, 0x04, - 0x1b, 0x00, 0x29, 0x01, 0x1a, 0x96, 0x01, 0x20, 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x64, 0x43, - 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x20, 0x62, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x73, 0x20, 0x74, - 0x68, 0x65, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, - 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x20, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, - 0x79, 0x69, 0x6e, 0x67, 0x20, 0x69, 0x74, 0x73, 0x20, 0x74, 0x79, 0x70, 0x65, 0x0a, 0x20, 0x61, - 0x6e, 0x64, 0x20, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x20, 0x72, 0x65, - 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x63, 0x6f, 0x72, 0x72, 0x65, - 0x63, 0x74, 0x20, 0x64, 0x65, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x61, 0x6e, 0x64, 0x20, - 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6f, 0x66, 0x20, - 0x74, 0x68, 0x65, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x0a, 0x0a, 0x0a, 0x0a, - 0x03, 0x04, 0x01, 0x01, 0x12, 0x03, 0x1b, 0x08, 0x16, 0x0a, 0x65, 0x0a, 0x04, 0x04, 0x01, 0x02, - 0x00, 0x12, 0x03, 0x1e, 0x02, 0x19, 0x1a, 0x58, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, - 0x20, 0x74, 0x79, 0x70, 0x65, 0x20, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, - 0x20, 0x75, 0x73, 0x65, 0x64, 0x20, 0x74, 0x6f, 0x20, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x20, 0x74, - 0x68, 0x65, 0x20, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x0a, - 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6f, 0x72, 0x72, 0x65, 0x63, 0x74, 0x20, 0x64, 0x65, 0x63, - 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x72, 0x79, 0x0a, - 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x00, 0x06, 0x12, 0x03, 0x1e, 0x02, 0x0f, 0x0a, 0x0c, - 0x0a, 0x05, 0x04, 0x01, 0x02, 0x00, 0x01, 0x12, 0x03, 0x1e, 0x10, 0x14, 0x0a, 0x0c, 0x0a, 0x05, - 0x04, 0x01, 0x02, 0x00, 0x03, 0x12, 0x03, 0x1e, 0x17, 0x18, 0x0a, 0x54, 0x0a, 0x04, 0x04, 0x01, - 0x02, 0x01, 0x12, 0x03, 0x20, 0x02, 0x25, 0x1a, 0x47, 0x20, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, - 0x61, 0x6c, 0x20, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x70, 0x61, 0x72, 0x61, - 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x20, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x20, - 0x74, 0x6f, 0x20, 0x63, 0x6f, 0x72, 0x72, 0x65, 0x63, 0x74, 0x6c, 0x79, 0x20, 0x64, 0x65, 0x63, - 0x6f, 0x64, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x0a, - 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x01, 0x06, 0x12, 0x03, 0x20, 0x02, 0x15, 0x0a, 0x0c, - 0x0a, 0x05, 0x04, 0x01, 0x02, 0x01, 0x01, 0x12, 0x03, 0x20, 0x16, 0x20, 0x0a, 0x0c, 0x0a, 0x05, - 0x04, 0x01, 0x02, 0x01, 0x03, 0x12, 0x03, 0x20, 0x23, 0x24, 0x0a, 0x84, 0x01, 0x0a, 0x04, 0x04, - 0x01, 0x02, 0x02, 0x12, 0x03, 0x23, 0x02, 0x1f, 0x1a, 0x77, 0x20, 0x6f, 0x70, 0x74, 0x69, 0x6f, - 0x6e, 0x61, 0x6c, 0x20, 0x66, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x20, 0x64, 0x65, 0x73, - 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, - 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x63, 0x61, 0x6e, - 0x20, 0x62, 0x65, 0x20, 0x75, 0x73, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x20, 0x63, 0x61, 0x73, 0x65, - 0x0a, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x20, 0x63, 0x61, 0x6e, - 0x6e, 0x6f, 0x74, 0x20, 0x64, 0x65, 0x63, 0x6f, 0x64, 0x65, 0x20, 0x6f, 0x72, 0x20, 0x72, 0x65, - 0x6e, 0x64, 0x65, 0x72, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, - 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x02, 0x04, 0x12, 0x03, 0x23, 0x02, 0x0a, 0x0a, - 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x02, 0x05, 0x12, 0x03, 0x23, 0x0b, 0x11, 0x0a, 0x0c, 0x0a, - 0x05, 0x04, 0x01, 0x02, 0x02, 0x01, 0x12, 0x03, 0x23, 0x12, 0x1a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, - 0x01, 0x02, 0x02, 0x03, 0x12, 0x03, 0x23, 0x1d, 0x1e, 0x0a, 0x6e, 0x0a, 0x04, 0x04, 0x01, 0x02, - 0x03, 0x12, 0x03, 0x26, 0x02, 0x27, 0x1a, 0x61, 0x20, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x61, - 0x6c, 0x20, 0x63, 0x6f, 0x6d, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x3b, 0x20, 0x74, - 0x68, 0x65, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x20, 0x69, 0x6e, 0x64, 0x69, 0x63, 0x61, 0x74, - 0x65, 0x73, 0x20, 0x61, 0x6c, 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x20, 0x75, 0x73, 0x65, - 0x64, 0x20, 0x74, 0x6f, 0x0a, 0x20, 0x63, 0x6f, 0x6d, 0x70, 0x72, 0x65, 0x73, 0x73, 0x20, 0x74, - 0x68, 0x65, 0x20, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x64, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x65, - 0x6e, 0x74, 0x20, 0x62, 0x79, 0x74, 0x65, 0x73, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, - 0x03, 0x04, 0x12, 0x03, 0x26, 0x02, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x03, 0x06, - 0x12, 0x03, 0x26, 0x0b, 0x16, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x03, 0x01, 0x12, 0x03, - 0x26, 0x17, 0x22, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x03, 0x03, 0x12, 0x03, 0x26, 0x25, - 0x26, 0x0a, 0x25, 0x0a, 0x04, 0x04, 0x01, 0x02, 0x04, 0x12, 0x03, 0x28, 0x02, 0x14, 0x1a, 0x18, - 0x20, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x64, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, - 0x20, 0x69, 0x74, 0x73, 0x65, 0x6c, 0x66, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x04, - 0x05, 0x12, 0x03, 0x28, 0x02, 0x07, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x04, 0x01, 0x12, - 0x03, 0x28, 0x08, 0x0f, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x04, 0x03, 0x12, 0x03, 0x28, - 0x12, 0x13, 0x0a, 0x55, 0x0a, 0x02, 0x04, 0x02, 0x12, 0x04, 0x2c, 0x00, 0x4e, 0x01, 0x1a, 0x49, - 0x20, 0x41, 0x20, 0x50, 0x6c, 0x61, 0x69, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x45, 0x6e, 0x76, 0x65, - 0x6c, 0x6f, 0x70, 0x65, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6f, 0x75, 0x74, 0x65, - 0x72, 0x6d, 0x6f, 0x73, 0x74, 0x20, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x20, 0x74, 0x68, - 0x61, 0x74, 0x20, 0x67, 0x65, 0x74, 0x73, 0x20, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x65, - 0x64, 0x20, 0x62, 0x79, 0x20, 0x4d, 0x4c, 0x53, 0x0a, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x02, 0x01, - 0x12, 0x03, 0x2c, 0x08, 0x19, 0x0a, 0x33, 0x0a, 0x04, 0x04, 0x02, 0x03, 0x00, 0x12, 0x04, 0x2e, - 0x02, 0x34, 0x03, 0x1a, 0x25, 0x20, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x31, 0x20, - 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x65, 0x64, - 0x20, 0x65, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, - 0x03, 0x00, 0x01, 0x12, 0x03, 0x2e, 0x0a, 0x0c, 0x0a, 0x2e, 0x0a, 0x06, 0x04, 0x02, 0x03, 0x00, - 0x02, 0x00, 0x12, 0x03, 0x30, 0x04, 0x16, 0x1a, 0x1f, 0x20, 0x45, 0x78, 0x70, 0x65, 0x63, 0x74, - 0x65, 0x64, 0x20, 0x74, 0x6f, 0x20, 0x62, 0x65, 0x20, 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x64, - 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x0a, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, 0x00, - 0x02, 0x00, 0x05, 0x12, 0x03, 0x30, 0x04, 0x09, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, 0x00, - 0x02, 0x00, 0x01, 0x12, 0x03, 0x30, 0x0a, 0x11, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, 0x00, - 0x02, 0x00, 0x03, 0x12, 0x03, 0x30, 0x14, 0x15, 0x0a, 0x8c, 0x01, 0x0a, 0x06, 0x04, 0x02, 0x03, - 0x00, 0x02, 0x01, 0x12, 0x03, 0x33, 0x04, 0x1f, 0x1a, 0x7d, 0x20, 0x41, 0x20, 0x75, 0x6e, 0x69, - 0x71, 0x75, 0x65, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x63, - 0x61, 0x6e, 0x20, 0x62, 0x65, 0x20, 0x75, 0x73, 0x65, 0x64, 0x20, 0x74, 0x6f, 0x20, 0x65, 0x6e, - 0x73, 0x75, 0x72, 0x65, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x61, - 0x6d, 0x65, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x20, 0x63, 0x61, 0x6e, 0x0a, 0x20, - 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x65, 0x20, 0x64, 0x69, 0x66, 0x66, 0x65, 0x72, 0x65, 0x6e, - 0x74, 0x20, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x2e, 0x20, 0x4d, 0x61, 0x79, 0x20, 0x62, 0x65, - 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x20, 0x74, 0x69, 0x6d, 0x65, - 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x0a, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, 0x00, 0x02, - 0x01, 0x05, 0x12, 0x03, 0x33, 0x04, 0x0a, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, 0x00, 0x02, - 0x01, 0x01, 0x12, 0x03, 0x33, 0x0b, 0x1a, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, 0x00, 0x02, - 0x01, 0x03, 0x12, 0x03, 0x33, 0x1d, 0x1e, 0x0a, 0x33, 0x0a, 0x04, 0x04, 0x02, 0x03, 0x01, 0x12, - 0x04, 0x37, 0x02, 0x46, 0x03, 0x1a, 0x25, 0x20, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x20, - 0x32, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, + 0x42, 0x0c, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, + 0x5a, 0x30, 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, 0x6d, 0x6c, + 0x73, 0x2f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, + 0x74, 0x73, 0xa2, 0x02, 0x03, 0x58, 0x4d, 0x4d, 0xaa, 0x02, 0x18, 0x58, 0x6d, 0x74, 0x70, 0x2e, + 0x4d, 0x6c, 0x73, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, + 0x6e, 0x74, 0x73, 0xca, 0x02, 0x18, 0x58, 0x6d, 0x74, 0x70, 0x5c, 0x4d, 0x6c, 0x73, 0x5c, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0xe2, 0x02, + 0x24, 0x58, 0x6d, 0x74, 0x70, 0x5c, 0x4d, 0x6c, 0x73, 0x5c, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, + 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x1a, 0x58, 0x6d, 0x74, 0x70, 0x3a, 0x3a, 0x4d, 0x6c, + 0x73, 0x3a, 0x3a, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, + 0x74, 0x73, 0x4a, 0xc2, 0x23, 0x0a, 0x06, 0x12, 0x04, 0x02, 0x00, 0x78, 0x01, 0x0a, 0x7c, 0x0a, + 0x01, 0x0c, 0x12, 0x03, 0x02, 0x00, 0x12, 0x1a, 0x72, 0x20, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x20, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x69, + 0x6e, 0x67, 0x20, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x75, 0x72, 0x65, 0x73, 0x0a, 0x20, 0x43, + 0x6f, 0x70, 0x69, 0x65, 0x64, 0x20, 0x66, 0x72, 0x6f, 0x6d, 0x20, 0x56, 0x32, 0x20, 0x63, 0x6f, + 0x64, 0x65, 0x20, 0x73, 0x6f, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x77, 0x65, 0x20, 0x63, 0x61, + 0x6e, 0x20, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x75, 0x61, 0x6c, 0x6c, 0x79, 0x20, 0x72, 0x65, 0x74, + 0x69, 0x72, 0x65, 0x20, 0x61, 0x6c, 0x6c, 0x20, 0x56, 0x32, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x0a, 0x0a, 0x08, 0x0a, 0x01, 0x02, + 0x12, 0x03, 0x04, 0x00, 0x22, 0x0a, 0x08, 0x0a, 0x01, 0x08, 0x12, 0x03, 0x06, 0x00, 0x47, 0x0a, + 0x09, 0x0a, 0x02, 0x08, 0x0b, 0x12, 0x03, 0x06, 0x00, 0x47, 0x0a, 0x58, 0x0a, 0x02, 0x04, 0x00, + 0x12, 0x04, 0x0a, 0x00, 0x0f, 0x01, 0x1a, 0x4c, 0x20, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, + 0x54, 0x79, 0x70, 0x65, 0x49, 0x64, 0x20, 0x69, 0x73, 0x20, 0x75, 0x73, 0x65, 0x64, 0x20, 0x74, + 0x6f, 0x20, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x79, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, + 0x79, 0x70, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x20, 0x73, + 0x74, 0x6f, 0x72, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x20, 0x61, 0x20, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x2e, 0x0a, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x00, 0x01, 0x12, 0x03, 0x0a, 0x08, 0x15, + 0x0a, 0x34, 0x0a, 0x04, 0x04, 0x00, 0x02, 0x00, 0x12, 0x03, 0x0b, 0x02, 0x1a, 0x22, 0x27, 0x20, + 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x67, 0x6f, 0x76, 0x65, 0x72, 0x6e, + 0x69, 0x6e, 0x67, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, + 0x20, 0x74, 0x79, 0x70, 0x65, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x00, 0x05, 0x12, + 0x03, 0x0b, 0x02, 0x08, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x00, 0x01, 0x12, 0x03, 0x0b, + 0x09, 0x15, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x00, 0x03, 0x12, 0x03, 0x0b, 0x18, 0x19, + 0x0a, 0x1e, 0x0a, 0x04, 0x04, 0x00, 0x02, 0x01, 0x12, 0x03, 0x0c, 0x02, 0x15, 0x22, 0x11, 0x20, + 0x74, 0x79, 0x70, 0x65, 0x20, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x0a, + 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x01, 0x05, 0x12, 0x03, 0x0c, 0x02, 0x08, 0x0a, 0x0c, + 0x0a, 0x05, 0x04, 0x00, 0x02, 0x01, 0x01, 0x12, 0x03, 0x0c, 0x09, 0x10, 0x0a, 0x0c, 0x0a, 0x05, + 0x04, 0x00, 0x02, 0x01, 0x03, 0x12, 0x03, 0x0c, 0x13, 0x14, 0x0a, 0x28, 0x0a, 0x04, 0x04, 0x00, + 0x02, 0x02, 0x12, 0x03, 0x0d, 0x02, 0x1b, 0x22, 0x1b, 0x20, 0x6d, 0x61, 0x6a, 0x6f, 0x72, 0x20, + 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, + 0x79, 0x70, 0x65, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x02, 0x05, 0x12, 0x03, 0x0d, + 0x02, 0x08, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x02, 0x01, 0x12, 0x03, 0x0d, 0x09, 0x16, + 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x02, 0x03, 0x12, 0x03, 0x0d, 0x19, 0x1a, 0x0a, 0x28, + 0x0a, 0x04, 0x04, 0x00, 0x02, 0x03, 0x12, 0x03, 0x0e, 0x02, 0x1b, 0x22, 0x1b, 0x20, 0x6d, 0x69, + 0x6e, 0x6f, 0x72, 0x20, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x6f, 0x66, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x74, 0x79, 0x70, 0x65, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x03, + 0x05, 0x12, 0x03, 0x0e, 0x02, 0x08, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x03, 0x01, 0x12, + 0x03, 0x0e, 0x09, 0x16, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x03, 0x03, 0x12, 0x03, 0x0e, + 0x19, 0x1a, 0x0a, 0x67, 0x0a, 0x02, 0x05, 0x00, 0x12, 0x04, 0x13, 0x00, 0x16, 0x01, 0x1a, 0x5b, + 0x20, 0x52, 0x65, 0x63, 0x6f, 0x67, 0x6e, 0x69, 0x7a, 0x65, 0x64, 0x20, 0x63, 0x6f, 0x6d, 0x70, + 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x61, 0x6c, 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, + 0x6d, 0x73, 0x0a, 0x20, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x6c, 0x69, 0x6e, 0x74, 0x3a, 0x64, 0x69, + 0x73, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x45, 0x4e, 0x55, 0x4d, 0x5f, 0x46, 0x49, 0x45, 0x4c, 0x44, + 0x5f, 0x4e, 0x41, 0x4d, 0x45, 0x53, 0x5f, 0x5a, 0x45, 0x52, 0x4f, 0x5f, 0x56, 0x41, 0x4c, 0x55, + 0x45, 0x5f, 0x45, 0x4e, 0x44, 0x5f, 0x57, 0x49, 0x54, 0x48, 0x0a, 0x0a, 0x0a, 0x0a, 0x03, 0x05, + 0x00, 0x01, 0x12, 0x03, 0x13, 0x05, 0x10, 0x0a, 0x0b, 0x0a, 0x04, 0x05, 0x00, 0x02, 0x00, 0x12, + 0x03, 0x14, 0x02, 0x1a, 0x0a, 0x0c, 0x0a, 0x05, 0x05, 0x00, 0x02, 0x00, 0x01, 0x12, 0x03, 0x14, + 0x02, 0x15, 0x0a, 0x0c, 0x0a, 0x05, 0x05, 0x00, 0x02, 0x00, 0x02, 0x12, 0x03, 0x14, 0x18, 0x19, + 0x0a, 0x0b, 0x0a, 0x04, 0x05, 0x00, 0x02, 0x01, 0x12, 0x03, 0x15, 0x02, 0x17, 0x0a, 0x0c, 0x0a, + 0x05, 0x05, 0x00, 0x02, 0x01, 0x01, 0x12, 0x03, 0x15, 0x02, 0x12, 0x0a, 0x0c, 0x0a, 0x05, 0x05, + 0x00, 0x02, 0x01, 0x02, 0x12, 0x03, 0x15, 0x15, 0x16, 0x0a, 0xa3, 0x01, 0x0a, 0x02, 0x04, 0x01, + 0x12, 0x04, 0x1b, 0x00, 0x29, 0x01, 0x1a, 0x96, 0x01, 0x20, 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x65, + 0x64, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x20, 0x62, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x73, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x20, 0x77, 0x69, 0x74, + 0x68, 0x20, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x20, 0x69, 0x64, 0x65, 0x6e, 0x74, + 0x69, 0x66, 0x79, 0x69, 0x6e, 0x67, 0x20, 0x69, 0x74, 0x73, 0x20, 0x74, 0x79, 0x70, 0x65, 0x0a, + 0x20, 0x61, 0x6e, 0x64, 0x20, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x20, + 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x63, 0x6f, 0x72, + 0x72, 0x65, 0x63, 0x74, 0x20, 0x64, 0x65, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x61, 0x6e, + 0x64, 0x20, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6f, + 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x0a, 0x0a, + 0x0a, 0x0a, 0x03, 0x04, 0x01, 0x01, 0x12, 0x03, 0x1b, 0x08, 0x16, 0x0a, 0x65, 0x0a, 0x04, 0x04, + 0x01, 0x02, 0x00, 0x12, 0x03, 0x1e, 0x02, 0x19, 0x1a, 0x58, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x65, + 0x6e, 0x74, 0x20, 0x74, 0x79, 0x70, 0x65, 0x20, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, + 0x65, 0x72, 0x20, 0x75, 0x73, 0x65, 0x64, 0x20, 0x74, 0x6f, 0x20, 0x6d, 0x61, 0x74, 0x63, 0x68, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x20, 0x77, 0x69, 0x74, + 0x68, 0x0a, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6f, 0x72, 0x72, 0x65, 0x63, 0x74, 0x20, 0x64, + 0x65, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x72, + 0x79, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x00, 0x06, 0x12, 0x03, 0x1e, 0x02, 0x0f, + 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x00, 0x01, 0x12, 0x03, 0x1e, 0x10, 0x14, 0x0a, 0x0c, + 0x0a, 0x05, 0x04, 0x01, 0x02, 0x00, 0x03, 0x12, 0x03, 0x1e, 0x17, 0x18, 0x0a, 0x54, 0x0a, 0x04, + 0x04, 0x01, 0x02, 0x01, 0x12, 0x03, 0x20, 0x02, 0x25, 0x1a, 0x47, 0x20, 0x6f, 0x70, 0x74, 0x69, + 0x6f, 0x6e, 0x61, 0x6c, 0x20, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x70, 0x61, + 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x20, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, + 0x64, 0x20, 0x74, 0x6f, 0x20, 0x63, 0x6f, 0x72, 0x72, 0x65, 0x63, 0x74, 0x6c, 0x79, 0x20, 0x64, + 0x65, 0x63, 0x6f, 0x64, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, + 0x74, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x01, 0x06, 0x12, 0x03, 0x20, 0x02, 0x15, + 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x01, 0x01, 0x12, 0x03, 0x20, 0x16, 0x20, 0x0a, 0x0c, + 0x0a, 0x05, 0x04, 0x01, 0x02, 0x01, 0x03, 0x12, 0x03, 0x20, 0x23, 0x24, 0x0a, 0x84, 0x01, 0x0a, + 0x04, 0x04, 0x01, 0x02, 0x02, 0x12, 0x03, 0x23, 0x02, 0x1f, 0x1a, 0x77, 0x20, 0x6f, 0x70, 0x74, + 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x20, 0x66, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x20, 0x64, + 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x63, + 0x61, 0x6e, 0x20, 0x62, 0x65, 0x20, 0x75, 0x73, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x20, 0x63, 0x61, + 0x73, 0x65, 0x0a, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x20, 0x63, + 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x20, 0x64, 0x65, 0x63, 0x6f, 0x64, 0x65, 0x20, 0x6f, 0x72, 0x20, + 0x72, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x65, + 0x6e, 0x74, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x02, 0x04, 0x12, 0x03, 0x23, 0x02, + 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x02, 0x05, 0x12, 0x03, 0x23, 0x0b, 0x11, 0x0a, + 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x02, 0x01, 0x12, 0x03, 0x23, 0x12, 0x1a, 0x0a, 0x0c, 0x0a, + 0x05, 0x04, 0x01, 0x02, 0x02, 0x03, 0x12, 0x03, 0x23, 0x1d, 0x1e, 0x0a, 0x6e, 0x0a, 0x04, 0x04, + 0x01, 0x02, 0x03, 0x12, 0x03, 0x26, 0x02, 0x27, 0x1a, 0x61, 0x20, 0x6f, 0x70, 0x74, 0x69, 0x6f, + 0x6e, 0x61, 0x6c, 0x20, 0x63, 0x6f, 0x6d, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x3b, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x20, 0x69, 0x6e, 0x64, 0x69, 0x63, + 0x61, 0x74, 0x65, 0x73, 0x20, 0x61, 0x6c, 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x20, 0x75, + 0x73, 0x65, 0x64, 0x20, 0x74, 0x6f, 0x0a, 0x20, 0x63, 0x6f, 0x6d, 0x70, 0x72, 0x65, 0x73, 0x73, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x64, 0x20, 0x63, 0x6f, 0x6e, + 0x74, 0x65, 0x6e, 0x74, 0x20, 0x62, 0x79, 0x74, 0x65, 0x73, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, + 0x01, 0x02, 0x03, 0x04, 0x12, 0x03, 0x26, 0x02, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, + 0x03, 0x06, 0x12, 0x03, 0x26, 0x0b, 0x16, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x03, 0x01, + 0x12, 0x03, 0x26, 0x17, 0x22, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x03, 0x03, 0x12, 0x03, + 0x26, 0x25, 0x26, 0x0a, 0x25, 0x0a, 0x04, 0x04, 0x01, 0x02, 0x04, 0x12, 0x03, 0x28, 0x02, 0x14, + 0x1a, 0x18, 0x20, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x64, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x65, + 0x6e, 0x74, 0x20, 0x69, 0x74, 0x73, 0x65, 0x6c, 0x66, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, + 0x02, 0x04, 0x05, 0x12, 0x03, 0x28, 0x02, 0x07, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x04, + 0x01, 0x12, 0x03, 0x28, 0x08, 0x0f, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x04, 0x03, 0x12, + 0x03, 0x28, 0x12, 0x13, 0x0a, 0x55, 0x0a, 0x02, 0x04, 0x02, 0x12, 0x04, 0x2c, 0x00, 0x4e, 0x01, + 0x1a, 0x49, 0x20, 0x41, 0x20, 0x50, 0x6c, 0x61, 0x69, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x45, 0x6e, + 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6f, 0x75, + 0x74, 0x65, 0x72, 0x6d, 0x6f, 0x73, 0x74, 0x20, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x20, + 0x74, 0x68, 0x61, 0x74, 0x20, 0x67, 0x65, 0x74, 0x73, 0x20, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, + 0x74, 0x65, 0x64, 0x20, 0x62, 0x79, 0x20, 0x4d, 0x4c, 0x53, 0x0a, 0x0a, 0x0a, 0x0a, 0x03, 0x04, + 0x02, 0x01, 0x12, 0x03, 0x2c, 0x08, 0x19, 0x0a, 0x33, 0x0a, 0x04, 0x04, 0x02, 0x03, 0x00, 0x12, + 0x04, 0x2e, 0x02, 0x34, 0x03, 0x1a, 0x25, 0x20, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x20, + 0x31, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x65, 0x64, 0x20, 0x65, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, - 0x04, 0x02, 0x03, 0x01, 0x01, 0x12, 0x03, 0x37, 0x0a, 0x0c, 0x0a, 0x8c, 0x01, 0x0a, 0x06, 0x04, - 0x02, 0x03, 0x01, 0x02, 0x00, 0x12, 0x03, 0x3a, 0x04, 0x1f, 0x1a, 0x7d, 0x20, 0x41, 0x20, 0x75, + 0x04, 0x02, 0x03, 0x00, 0x01, 0x12, 0x03, 0x2e, 0x0a, 0x0c, 0x0a, 0x2e, 0x0a, 0x06, 0x04, 0x02, + 0x03, 0x00, 0x02, 0x00, 0x12, 0x03, 0x30, 0x04, 0x16, 0x1a, 0x1f, 0x20, 0x45, 0x78, 0x70, 0x65, + 0x63, 0x74, 0x65, 0x64, 0x20, 0x74, 0x6f, 0x20, 0x62, 0x65, 0x20, 0x45, 0x6e, 0x63, 0x6f, 0x64, + 0x65, 0x64, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x0a, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, + 0x03, 0x00, 0x02, 0x00, 0x05, 0x12, 0x03, 0x30, 0x04, 0x09, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, + 0x03, 0x00, 0x02, 0x00, 0x01, 0x12, 0x03, 0x30, 0x0a, 0x11, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, + 0x03, 0x00, 0x02, 0x00, 0x03, 0x12, 0x03, 0x30, 0x14, 0x15, 0x0a, 0x8c, 0x01, 0x0a, 0x06, 0x04, + 0x02, 0x03, 0x00, 0x02, 0x01, 0x12, 0x03, 0x33, 0x04, 0x1f, 0x1a, 0x7d, 0x20, 0x41, 0x20, 0x75, 0x6e, 0x69, 0x71, 0x75, 0x65, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x63, 0x61, 0x6e, 0x20, 0x62, 0x65, 0x20, 0x75, 0x73, 0x65, 0x64, 0x20, 0x74, 0x6f, 0x20, 0x65, 0x6e, 0x73, 0x75, 0x72, 0x65, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, @@ -899,161 +883,255 @@ pub const FILE_DESCRIPTOR_SET: &[u8] = &[ 0x65, 0x6e, 0x74, 0x20, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x2e, 0x20, 0x4d, 0x61, 0x79, 0x20, 0x62, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x20, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x0a, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, - 0x01, 0x02, 0x00, 0x05, 0x12, 0x03, 0x3a, 0x04, 0x0a, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, - 0x01, 0x02, 0x00, 0x01, 0x12, 0x03, 0x3a, 0x0b, 0x1a, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, - 0x01, 0x02, 0x00, 0x03, 0x12, 0x03, 0x3a, 0x1d, 0x1e, 0x0a, 0x0e, 0x0a, 0x06, 0x04, 0x02, 0x03, - 0x01, 0x08, 0x00, 0x12, 0x04, 0x3c, 0x04, 0x45, 0x05, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, - 0x01, 0x08, 0x00, 0x01, 0x12, 0x03, 0x3c, 0x0a, 0x16, 0x0a, 0x2e, 0x0a, 0x06, 0x04, 0x02, 0x03, - 0x01, 0x02, 0x01, 0x12, 0x03, 0x3e, 0x06, 0x18, 0x1a, 0x1f, 0x20, 0x45, 0x78, 0x70, 0x65, 0x63, - 0x74, 0x65, 0x64, 0x20, 0x74, 0x6f, 0x20, 0x62, 0x65, 0x20, 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x65, - 0x64, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x0a, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, - 0x01, 0x02, 0x01, 0x05, 0x12, 0x03, 0x3e, 0x06, 0x0b, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, - 0x01, 0x02, 0x01, 0x01, 0x12, 0x03, 0x3e, 0x0c, 0x13, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, - 0x01, 0x02, 0x01, 0x03, 0x12, 0x03, 0x3e, 0x16, 0x17, 0x0a, 0x42, 0x0a, 0x06, 0x04, 0x02, 0x03, - 0x01, 0x02, 0x02, 0x12, 0x03, 0x40, 0x06, 0x30, 0x1a, 0x33, 0x20, 0x49, 0x6e, 0x69, 0x74, 0x69, - 0x61, 0x74, 0x6f, 0x72, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x73, 0x20, 0x61, 0x20, 0x72, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x20, 0x74, 0x6f, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20, - 0x73, 0x79, 0x6e, 0x63, 0x20, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x0a, 0x0a, 0x0e, 0x0a, - 0x07, 0x04, 0x02, 0x03, 0x01, 0x02, 0x02, 0x06, 0x12, 0x03, 0x40, 0x06, 0x17, 0x0a, 0x0e, 0x0a, - 0x07, 0x04, 0x02, 0x03, 0x01, 0x02, 0x02, 0x01, 0x12, 0x03, 0x40, 0x18, 0x2b, 0x0a, 0x0e, 0x0a, - 0x07, 0x04, 0x02, 0x03, 0x01, 0x02, 0x02, 0x03, 0x12, 0x03, 0x40, 0x2e, 0x2f, 0x0a, 0x58, 0x0a, - 0x06, 0x04, 0x02, 0x03, 0x01, 0x02, 0x03, 0x12, 0x03, 0x42, 0x06, 0x2c, 0x1a, 0x49, 0x20, 0x53, - 0x6f, 0x6d, 0x65, 0x20, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x20, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, - 0x69, 0x7a, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x73, 0x20, 0x61, 0x20, 0x72, 0x65, 0x70, 0x6c, 0x79, 0x20, - 0x77, 0x69, 0x74, 0x68, 0x20, 0x61, 0x20, 0x6c, 0x69, 0x6e, 0x6b, 0x20, 0x74, 0x6f, 0x20, 0x70, - 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x0a, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, 0x01, 0x02, - 0x03, 0x06, 0x12, 0x03, 0x42, 0x06, 0x15, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, 0x01, 0x02, - 0x03, 0x01, 0x12, 0x03, 0x42, 0x16, 0x27, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, 0x01, 0x02, - 0x03, 0x03, 0x12, 0x03, 0x42, 0x2a, 0x2b, 0x0a, 0x34, 0x0a, 0x06, 0x04, 0x02, 0x03, 0x01, 0x02, - 0x04, 0x12, 0x03, 0x44, 0x06, 0x36, 0x1a, 0x25, 0x20, 0x41, 0x20, 0x73, 0x65, 0x72, 0x69, 0x61, - 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x20, 0x75, 0x73, 0x65, 0x72, 0x20, 0x70, 0x72, 0x65, 0x66, 0x65, - 0x72, 0x65, 0x6e, 0x63, 0x65, 0x20, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x0a, 0x0a, 0x0e, 0x0a, - 0x07, 0x04, 0x02, 0x03, 0x01, 0x02, 0x04, 0x06, 0x12, 0x03, 0x44, 0x06, 0x1a, 0x0a, 0x0e, 0x0a, - 0x07, 0x04, 0x02, 0x03, 0x01, 0x02, 0x04, 0x01, 0x12, 0x03, 0x44, 0x1b, 0x31, 0x0a, 0x0e, 0x0a, - 0x07, 0x04, 0x02, 0x03, 0x01, 0x02, 0x04, 0x03, 0x12, 0x03, 0x44, 0x34, 0x35, 0x0a, 0x66, 0x0a, - 0x04, 0x04, 0x02, 0x08, 0x00, 0x12, 0x04, 0x4a, 0x02, 0x4d, 0x03, 0x1a, 0x58, 0x20, 0x53, 0x65, - 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x20, 0x77, 0x68, 0x69, 0x63, 0x68, 0x20, 0x64, 0x65, 0x63, - 0x6c, 0x61, 0x72, 0x65, 0x73, 0x20, 0x77, 0x68, 0x69, 0x63, 0x68, 0x20, 0x76, 0x65, 0x72, 0x73, - 0x69, 0x6f, 0x6e, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x45, 0x6e, 0x63, 0x6f, 0x64, - 0x65, 0x64, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x20, 0x74, 0x68, 0x69, 0x73, 0x0a, 0x20, - 0x50, 0x6c, 0x61, 0x69, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x45, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, - 0x65, 0x20, 0x69, 0x73, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x08, 0x00, 0x01, 0x12, 0x03, - 0x4a, 0x08, 0x0f, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x02, 0x02, 0x00, 0x12, 0x03, 0x4b, 0x04, 0x0e, - 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x00, 0x06, 0x12, 0x03, 0x4b, 0x04, 0x06, 0x0a, 0x0c, - 0x0a, 0x05, 0x04, 0x02, 0x02, 0x00, 0x01, 0x12, 0x03, 0x4b, 0x07, 0x09, 0x0a, 0x0c, 0x0a, 0x05, - 0x04, 0x02, 0x02, 0x00, 0x03, 0x12, 0x03, 0x4b, 0x0c, 0x0d, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x02, - 0x02, 0x01, 0x12, 0x03, 0x4c, 0x04, 0x0e, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x01, 0x06, - 0x12, 0x03, 0x4c, 0x04, 0x06, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x01, 0x01, 0x12, 0x03, - 0x4c, 0x07, 0x09, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x01, 0x03, 0x12, 0x03, 0x4c, 0x0c, - 0x0d, 0x0a, 0x57, 0x0a, 0x02, 0x04, 0x03, 0x12, 0x04, 0x51, 0x00, 0x58, 0x01, 0x1a, 0x4b, 0x20, - 0x49, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x74, 0x6f, 0x72, 0x20, 0x6f, 0x72, 0x20, 0x6e, 0x65, 0x77, + 0x00, 0x02, 0x01, 0x05, 0x12, 0x03, 0x33, 0x04, 0x0a, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, + 0x00, 0x02, 0x01, 0x01, 0x12, 0x03, 0x33, 0x0b, 0x1a, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, + 0x00, 0x02, 0x01, 0x03, 0x12, 0x03, 0x33, 0x1d, 0x1e, 0x0a, 0x33, 0x0a, 0x04, 0x04, 0x02, 0x03, + 0x01, 0x12, 0x04, 0x37, 0x02, 0x46, 0x03, 0x1a, 0x25, 0x20, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, + 0x6e, 0x20, 0x32, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x65, 0x6e, 0x63, 0x72, 0x79, + 0x70, 0x74, 0x65, 0x64, 0x20, 0x65, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x0a, 0x0a, 0x0c, + 0x0a, 0x05, 0x04, 0x02, 0x03, 0x01, 0x01, 0x12, 0x03, 0x37, 0x0a, 0x0c, 0x0a, 0x8c, 0x01, 0x0a, + 0x06, 0x04, 0x02, 0x03, 0x01, 0x02, 0x00, 0x12, 0x03, 0x3a, 0x04, 0x1f, 0x1a, 0x7d, 0x20, 0x41, + 0x20, 0x75, 0x6e, 0x69, 0x71, 0x75, 0x65, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x20, 0x74, 0x68, + 0x61, 0x74, 0x20, 0x63, 0x61, 0x6e, 0x20, 0x62, 0x65, 0x20, 0x75, 0x73, 0x65, 0x64, 0x20, 0x74, + 0x6f, 0x20, 0x65, 0x6e, 0x73, 0x75, 0x72, 0x65, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x73, 0x61, 0x6d, 0x65, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x20, 0x63, + 0x61, 0x6e, 0x0a, 0x20, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x65, 0x20, 0x64, 0x69, 0x66, 0x66, + 0x65, 0x72, 0x65, 0x6e, 0x74, 0x20, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x2e, 0x20, 0x4d, 0x61, + 0x79, 0x20, 0x62, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x20, + 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x0a, 0x0a, 0x0e, 0x0a, 0x07, 0x04, + 0x02, 0x03, 0x01, 0x02, 0x00, 0x05, 0x12, 0x03, 0x3a, 0x04, 0x0a, 0x0a, 0x0e, 0x0a, 0x07, 0x04, + 0x02, 0x03, 0x01, 0x02, 0x00, 0x01, 0x12, 0x03, 0x3a, 0x0b, 0x1a, 0x0a, 0x0e, 0x0a, 0x07, 0x04, + 0x02, 0x03, 0x01, 0x02, 0x00, 0x03, 0x12, 0x03, 0x3a, 0x1d, 0x1e, 0x0a, 0x0e, 0x0a, 0x06, 0x04, + 0x02, 0x03, 0x01, 0x08, 0x00, 0x12, 0x04, 0x3c, 0x04, 0x45, 0x05, 0x0a, 0x0e, 0x0a, 0x07, 0x04, + 0x02, 0x03, 0x01, 0x08, 0x00, 0x01, 0x12, 0x03, 0x3c, 0x0a, 0x16, 0x0a, 0x2e, 0x0a, 0x06, 0x04, + 0x02, 0x03, 0x01, 0x02, 0x01, 0x12, 0x03, 0x3e, 0x06, 0x18, 0x1a, 0x1f, 0x20, 0x45, 0x78, 0x70, + 0x65, 0x63, 0x74, 0x65, 0x64, 0x20, 0x74, 0x6f, 0x20, 0x62, 0x65, 0x20, 0x45, 0x6e, 0x63, 0x6f, + 0x64, 0x65, 0x64, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x0a, 0x0a, 0x0e, 0x0a, 0x07, 0x04, + 0x02, 0x03, 0x01, 0x02, 0x01, 0x05, 0x12, 0x03, 0x3e, 0x06, 0x0b, 0x0a, 0x0e, 0x0a, 0x07, 0x04, + 0x02, 0x03, 0x01, 0x02, 0x01, 0x01, 0x12, 0x03, 0x3e, 0x0c, 0x13, 0x0a, 0x0e, 0x0a, 0x07, 0x04, + 0x02, 0x03, 0x01, 0x02, 0x01, 0x03, 0x12, 0x03, 0x3e, 0x16, 0x17, 0x0a, 0x42, 0x0a, 0x06, 0x04, + 0x02, 0x03, 0x01, 0x02, 0x02, 0x12, 0x03, 0x40, 0x06, 0x30, 0x1a, 0x33, 0x20, 0x49, 0x6e, 0x69, + 0x74, 0x69, 0x61, 0x74, 0x6f, 0x72, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x73, 0x20, 0x61, 0x20, 0x72, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x20, 0x74, 0x6f, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, + 0x65, 0x20, 0x73, 0x79, 0x6e, 0x63, 0x20, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x0a, 0x0a, + 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, 0x01, 0x02, 0x02, 0x06, 0x12, 0x03, 0x40, 0x06, 0x17, 0x0a, + 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, 0x01, 0x02, 0x02, 0x01, 0x12, 0x03, 0x40, 0x18, 0x2b, 0x0a, + 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, 0x01, 0x02, 0x02, 0x03, 0x12, 0x03, 0x40, 0x2e, 0x2f, 0x0a, + 0x58, 0x0a, 0x06, 0x04, 0x02, 0x03, 0x01, 0x02, 0x03, 0x12, 0x03, 0x42, 0x06, 0x2c, 0x1a, 0x49, + 0x20, 0x53, 0x6f, 0x6d, 0x65, 0x20, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x20, 0x61, 0x75, 0x74, 0x68, + 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x73, 0x20, 0x61, 0x20, 0x72, 0x65, 0x70, 0x6c, + 0x79, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x61, 0x20, 0x6c, 0x69, 0x6e, 0x6b, 0x20, 0x74, 0x6f, + 0x20, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x0a, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, + 0x01, 0x02, 0x03, 0x06, 0x12, 0x03, 0x42, 0x06, 0x15, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, + 0x01, 0x02, 0x03, 0x01, 0x12, 0x03, 0x42, 0x16, 0x27, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, + 0x01, 0x02, 0x03, 0x03, 0x12, 0x03, 0x42, 0x2a, 0x2b, 0x0a, 0x34, 0x0a, 0x06, 0x04, 0x02, 0x03, + 0x01, 0x02, 0x04, 0x12, 0x03, 0x44, 0x06, 0x36, 0x1a, 0x25, 0x20, 0x41, 0x20, 0x73, 0x65, 0x72, + 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x20, 0x75, 0x73, 0x65, 0x72, 0x20, 0x70, 0x72, 0x65, + 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x20, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x0a, 0x0a, + 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, 0x01, 0x02, 0x04, 0x06, 0x12, 0x03, 0x44, 0x06, 0x1a, 0x0a, + 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, 0x01, 0x02, 0x04, 0x01, 0x12, 0x03, 0x44, 0x1b, 0x31, 0x0a, + 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, 0x01, 0x02, 0x04, 0x03, 0x12, 0x03, 0x44, 0x34, 0x35, 0x0a, + 0x66, 0x0a, 0x04, 0x04, 0x02, 0x08, 0x00, 0x12, 0x04, 0x4a, 0x02, 0x4d, 0x03, 0x1a, 0x58, 0x20, + 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x20, 0x77, 0x68, 0x69, 0x63, 0x68, 0x20, 0x64, + 0x65, 0x63, 0x6c, 0x61, 0x72, 0x65, 0x73, 0x20, 0x77, 0x68, 0x69, 0x63, 0x68, 0x20, 0x76, 0x65, + 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x45, 0x6e, 0x63, + 0x6f, 0x64, 0x65, 0x64, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x20, 0x74, 0x68, 0x69, 0x73, + 0x0a, 0x20, 0x50, 0x6c, 0x61, 0x69, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x45, 0x6e, 0x76, 0x65, 0x6c, + 0x6f, 0x70, 0x65, 0x20, 0x69, 0x73, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x08, 0x00, 0x01, + 0x12, 0x03, 0x4a, 0x08, 0x0f, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x02, 0x02, 0x00, 0x12, 0x03, 0x4b, + 0x04, 0x0e, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x00, 0x06, 0x12, 0x03, 0x4b, 0x04, 0x06, + 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x00, 0x01, 0x12, 0x03, 0x4b, 0x07, 0x09, 0x0a, 0x0c, + 0x0a, 0x05, 0x04, 0x02, 0x02, 0x00, 0x03, 0x12, 0x03, 0x4b, 0x0c, 0x0d, 0x0a, 0x0b, 0x0a, 0x04, + 0x04, 0x02, 0x02, 0x01, 0x12, 0x03, 0x4c, 0x04, 0x0e, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, + 0x01, 0x06, 0x12, 0x03, 0x4c, 0x04, 0x06, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x01, 0x01, + 0x12, 0x03, 0x4c, 0x07, 0x09, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x01, 0x03, 0x12, 0x03, + 0x4c, 0x0c, 0x0d, 0x0a, 0x57, 0x0a, 0x02, 0x04, 0x03, 0x12, 0x04, 0x51, 0x00, 0x58, 0x01, 0x1a, + 0x4b, 0x20, 0x49, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x74, 0x6f, 0x72, 0x20, 0x6f, 0x72, 0x20, 0x6e, + 0x65, 0x77, 0x20, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, + 0x69, 0x64, 0x20, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x20, 0x61, 0x20, + 0x73, 0x79, 0x6e, 0x63, 0x20, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x20, 0x73, 0x65, 0x6e, + 0x64, 0x20, 0x61, 0x20, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x0a, 0x0a, 0x0a, 0x0a, 0x03, + 0x04, 0x03, 0x01, 0x12, 0x03, 0x51, 0x08, 0x19, 0x0a, 0x31, 0x0a, 0x04, 0x04, 0x03, 0x02, 0x00, + 0x12, 0x03, 0x53, 0x02, 0x18, 0x1a, 0x24, 0x20, 0x55, 0x6e, 0x69, 0x71, 0x75, 0x65, 0x20, 0x69, + 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x65, 0x61, + 0x63, 0x68, 0x20, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, + 0x03, 0x02, 0x00, 0x05, 0x12, 0x03, 0x53, 0x02, 0x08, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, + 0x00, 0x01, 0x12, 0x03, 0x53, 0x09, 0x13, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, 0x00, 0x03, + 0x12, 0x03, 0x53, 0x16, 0x17, 0x0a, 0x2d, 0x0a, 0x04, 0x04, 0x03, 0x02, 0x01, 0x12, 0x03, 0x55, + 0x02, 0x16, 0x1a, 0x20, 0x20, 0x45, 0x6e, 0x73, 0x75, 0x72, 0x65, 0x73, 0x20, 0x61, 0x20, 0x68, + 0x75, 0x6d, 0x61, 0x6e, 0x20, 0x69, 0x73, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6c, + 0x6f, 0x6f, 0x70, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, 0x01, 0x05, 0x12, 0x03, 0x55, + 0x02, 0x08, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, 0x01, 0x01, 0x12, 0x03, 0x55, 0x09, 0x11, + 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, 0x01, 0x03, 0x12, 0x03, 0x55, 0x14, 0x15, 0x0a, 0x1b, + 0x0a, 0x04, 0x04, 0x03, 0x02, 0x02, 0x12, 0x03, 0x57, 0x02, 0x1a, 0x1a, 0x0e, 0x20, 0x72, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x20, 0x6b, 0x69, 0x6e, 0x64, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, + 0x03, 0x02, 0x02, 0x06, 0x12, 0x03, 0x57, 0x02, 0x10, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, + 0x02, 0x01, 0x12, 0x03, 0x57, 0x11, 0x15, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, 0x02, 0x03, + 0x12, 0x03, 0x57, 0x18, 0x19, 0x0a, 0x5f, 0x0a, 0x02, 0x04, 0x04, 0x12, 0x04, 0x5b, 0x00, 0x66, + 0x01, 0x1a, 0x53, 0x20, 0x50, 0x72, 0x65, 0x2d, 0x65, 0x78, 0x69, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x20, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x69, 0x64, - 0x20, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x20, 0x61, 0x20, 0x73, 0x79, - 0x6e, 0x63, 0x20, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20, - 0x61, 0x20, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x0a, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x03, - 0x01, 0x12, 0x03, 0x51, 0x08, 0x19, 0x0a, 0x31, 0x0a, 0x04, 0x04, 0x03, 0x02, 0x00, 0x12, 0x03, - 0x53, 0x02, 0x18, 0x1a, 0x24, 0x20, 0x55, 0x6e, 0x69, 0x71, 0x75, 0x65, 0x20, 0x69, 0x64, 0x65, - 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x65, 0x61, 0x63, 0x68, - 0x20, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, - 0x00, 0x05, 0x12, 0x03, 0x53, 0x02, 0x08, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, 0x00, 0x01, - 0x12, 0x03, 0x53, 0x09, 0x13, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, 0x00, 0x03, 0x12, 0x03, - 0x53, 0x16, 0x17, 0x0a, 0x2d, 0x0a, 0x04, 0x04, 0x03, 0x02, 0x01, 0x12, 0x03, 0x55, 0x02, 0x16, - 0x1a, 0x20, 0x20, 0x45, 0x6e, 0x73, 0x75, 0x72, 0x65, 0x73, 0x20, 0x61, 0x20, 0x68, 0x75, 0x6d, - 0x61, 0x6e, 0x20, 0x69, 0x73, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6c, 0x6f, 0x6f, - 0x70, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, 0x01, 0x05, 0x12, 0x03, 0x55, 0x02, 0x08, - 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, 0x01, 0x01, 0x12, 0x03, 0x55, 0x09, 0x11, 0x0a, 0x0c, - 0x0a, 0x05, 0x04, 0x03, 0x02, 0x01, 0x03, 0x12, 0x03, 0x55, 0x14, 0x15, 0x0a, 0x1b, 0x0a, 0x04, - 0x04, 0x03, 0x02, 0x02, 0x12, 0x03, 0x57, 0x02, 0x1a, 0x1a, 0x0e, 0x20, 0x72, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x20, 0x6b, 0x69, 0x6e, 0x64, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, - 0x02, 0x06, 0x12, 0x03, 0x57, 0x02, 0x10, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, 0x02, 0x01, - 0x12, 0x03, 0x57, 0x11, 0x15, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, 0x02, 0x03, 0x12, 0x03, - 0x57, 0x18, 0x19, 0x0a, 0x5f, 0x0a, 0x02, 0x04, 0x04, 0x12, 0x04, 0x5b, 0x00, 0x66, 0x01, 0x1a, - 0x53, 0x20, 0x50, 0x72, 0x65, 0x2d, 0x65, 0x78, 0x69, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x20, 0x69, - 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x69, 0x64, 0x20, 0x63, - 0x61, 0x70, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x73, 0x75, 0x70, 0x70, 0x6c, 0x79, - 0x69, 0x6e, 0x67, 0x20, 0x61, 0x20, 0x73, 0x79, 0x6e, 0x63, 0x20, 0x70, 0x61, 0x79, 0x6c, 0x6f, - 0x61, 0x64, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x73, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x72, 0x65, - 0x70, 0x6c, 0x79, 0x0a, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x04, 0x01, 0x12, 0x03, 0x5b, 0x08, 0x17, - 0x0a, 0x4f, 0x0a, 0x04, 0x04, 0x04, 0x02, 0x00, 0x12, 0x03, 0x5d, 0x02, 0x18, 0x1a, 0x42, 0x20, - 0x4d, 0x75, 0x73, 0x74, 0x20, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x20, 0x61, 0x6e, 0x20, 0x65, 0x78, - 0x69, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x20, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x69, - 0x64, 0x20, 0x66, 0x72, 0x6f, 0x6d, 0x20, 0x61, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x20, 0x68, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x20, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x02, 0x00, 0x05, 0x12, 0x03, 0x5d, 0x02, 0x08, 0x0a, - 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x02, 0x00, 0x01, 0x12, 0x03, 0x5d, 0x09, 0x13, 0x0a, 0x0c, 0x0a, - 0x05, 0x04, 0x04, 0x02, 0x00, 0x03, 0x12, 0x03, 0x5d, 0x16, 0x17, 0x0a, 0x37, 0x0a, 0x04, 0x04, - 0x04, 0x02, 0x01, 0x12, 0x03, 0x5f, 0x02, 0x11, 0x1a, 0x2a, 0x20, 0x57, 0x68, 0x65, 0x72, 0x65, - 0x20, 0x74, 0x68, 0x65, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x20, 0x63, 0x61, - 0x6e, 0x20, 0x62, 0x65, 0x20, 0x72, 0x65, 0x74, 0x72, 0x69, 0x65, 0x76, 0x65, 0x64, 0x20, 0x66, - 0x72, 0x6f, 0x6d, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x02, 0x01, 0x05, 0x12, 0x03, 0x5f, - 0x02, 0x08, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x02, 0x01, 0x01, 0x12, 0x03, 0x5f, 0x09, 0x0c, - 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x02, 0x01, 0x03, 0x12, 0x03, 0x5f, 0x0f, 0x10, 0x0a, 0x5a, - 0x0a, 0x04, 0x04, 0x04, 0x02, 0x02, 0x12, 0x03, 0x61, 0x02, 0x27, 0x1a, 0x4d, 0x20, 0x47, 0x65, - 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x20, 0x27, 0x73, - 0x65, 0x63, 0x72, 0x65, 0x74, 0x27, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x74, 0x68, 0x65, 0x20, 0x41, - 0x45, 0x53, 0x20, 0x4b, 0x65, 0x79, 0x20, 0x75, 0x73, 0x65, 0x64, 0x20, 0x74, 0x6f, 0x20, 0x65, + 0x20, 0x63, 0x61, 0x70, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x73, 0x75, 0x70, 0x70, + 0x6c, 0x79, 0x69, 0x6e, 0x67, 0x20, 0x61, 0x20, 0x73, 0x79, 0x6e, 0x63, 0x20, 0x70, 0x61, 0x79, + 0x6c, 0x6f, 0x61, 0x64, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x73, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, + 0x72, 0x65, 0x70, 0x6c, 0x79, 0x0a, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x04, 0x01, 0x12, 0x03, 0x5b, + 0x08, 0x17, 0x0a, 0x4f, 0x0a, 0x04, 0x04, 0x04, 0x02, 0x00, 0x12, 0x03, 0x5d, 0x02, 0x18, 0x1a, + 0x42, 0x20, 0x4d, 0x75, 0x73, 0x74, 0x20, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x20, 0x61, 0x6e, 0x20, + 0x65, 0x78, 0x69, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x20, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x5f, 0x69, 0x64, 0x20, 0x66, 0x72, 0x6f, 0x6d, 0x20, 0x61, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x20, 0x68, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x20, 0x72, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x02, 0x00, 0x05, 0x12, 0x03, 0x5d, 0x02, + 0x08, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x02, 0x00, 0x01, 0x12, 0x03, 0x5d, 0x09, 0x13, 0x0a, + 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x02, 0x00, 0x03, 0x12, 0x03, 0x5d, 0x16, 0x17, 0x0a, 0x37, 0x0a, + 0x04, 0x04, 0x04, 0x02, 0x01, 0x12, 0x03, 0x5f, 0x02, 0x11, 0x1a, 0x2a, 0x20, 0x57, 0x68, 0x65, + 0x72, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x20, + 0x63, 0x61, 0x6e, 0x20, 0x62, 0x65, 0x20, 0x72, 0x65, 0x74, 0x72, 0x69, 0x65, 0x76, 0x65, 0x64, + 0x20, 0x66, 0x72, 0x6f, 0x6d, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x02, 0x01, 0x05, 0x12, + 0x03, 0x5f, 0x02, 0x08, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x02, 0x01, 0x01, 0x12, 0x03, 0x5f, + 0x09, 0x0c, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x02, 0x01, 0x03, 0x12, 0x03, 0x5f, 0x0f, 0x10, + 0x0a, 0x5a, 0x0a, 0x04, 0x04, 0x04, 0x02, 0x02, 0x12, 0x03, 0x61, 0x02, 0x27, 0x1a, 0x4d, 0x20, + 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x20, + 0x27, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x27, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x41, 0x45, 0x53, 0x20, 0x4b, 0x65, 0x79, 0x20, 0x75, 0x73, 0x65, 0x64, 0x20, 0x74, 0x6f, + 0x20, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x2d, 0x62, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, + 0x04, 0x04, 0x02, 0x02, 0x06, 0x12, 0x03, 0x61, 0x02, 0x13, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, + 0x02, 0x02, 0x01, 0x12, 0x03, 0x61, 0x14, 0x22, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x02, 0x02, + 0x03, 0x12, 0x03, 0x61, 0x25, 0x26, 0x0a, 0x3b, 0x0a, 0x04, 0x04, 0x04, 0x02, 0x03, 0x12, 0x03, + 0x63, 0x02, 0x1a, 0x1a, 0x2e, 0x20, 0x6e, 0x73, 0x20, 0x75, 0x6e, 0x69, 0x78, 0x20, 0x74, 0x69, + 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x20, 0x6f, 0x66, 0x20, 0x77, 0x68, 0x65, 0x6e, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x72, 0x65, 0x70, 0x6c, 0x79, 0x20, 0x77, 0x61, 0x73, 0x20, 0x73, 0x65, + 0x6e, 0x74, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x02, 0x03, 0x05, 0x12, 0x03, 0x63, 0x02, + 0x08, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x02, 0x03, 0x01, 0x12, 0x03, 0x63, 0x09, 0x15, 0x0a, + 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x02, 0x03, 0x03, 0x12, 0x03, 0x63, 0x18, 0x19, 0x0a, 0x1b, 0x0a, + 0x04, 0x04, 0x04, 0x02, 0x04, 0x12, 0x03, 0x65, 0x02, 0x1a, 0x1a, 0x0e, 0x20, 0x72, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x20, 0x6b, 0x69, 0x6e, 0x64, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, + 0x02, 0x04, 0x06, 0x12, 0x03, 0x65, 0x02, 0x10, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x02, 0x04, + 0x01, 0x12, 0x03, 0x65, 0x11, 0x15, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x02, 0x04, 0x03, 0x12, + 0x03, 0x65, 0x18, 0x19, 0x0a, 0x34, 0x0a, 0x02, 0x04, 0x05, 0x12, 0x04, 0x69, 0x00, 0x6d, 0x01, + 0x1a, 0x28, 0x20, 0x4b, 0x65, 0x79, 0x20, 0x75, 0x73, 0x65, 0x64, 0x20, 0x74, 0x6f, 0x20, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x2d, 0x62, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, - 0x02, 0x02, 0x06, 0x12, 0x03, 0x61, 0x02, 0x13, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x02, 0x02, - 0x01, 0x12, 0x03, 0x61, 0x14, 0x22, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x02, 0x02, 0x03, 0x12, - 0x03, 0x61, 0x25, 0x26, 0x0a, 0x3b, 0x0a, 0x04, 0x04, 0x04, 0x02, 0x03, 0x12, 0x03, 0x63, 0x02, - 0x1a, 0x1a, 0x2e, 0x20, 0x6e, 0x73, 0x20, 0x75, 0x6e, 0x69, 0x78, 0x20, 0x74, 0x69, 0x6d, 0x65, - 0x73, 0x74, 0x61, 0x6d, 0x70, 0x20, 0x6f, 0x66, 0x20, 0x77, 0x68, 0x65, 0x6e, 0x20, 0x74, 0x68, - 0x65, 0x20, 0x72, 0x65, 0x70, 0x6c, 0x79, 0x20, 0x77, 0x61, 0x73, 0x20, 0x73, 0x65, 0x6e, 0x74, - 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x02, 0x03, 0x05, 0x12, 0x03, 0x63, 0x02, 0x08, 0x0a, - 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x02, 0x03, 0x01, 0x12, 0x03, 0x63, 0x09, 0x15, 0x0a, 0x0c, 0x0a, - 0x05, 0x04, 0x04, 0x02, 0x03, 0x03, 0x12, 0x03, 0x63, 0x18, 0x19, 0x0a, 0x1b, 0x0a, 0x04, 0x04, - 0x04, 0x02, 0x04, 0x12, 0x03, 0x65, 0x02, 0x1a, 0x1a, 0x0e, 0x20, 0x72, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x20, 0x6b, 0x69, 0x6e, 0x64, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x02, 0x04, - 0x06, 0x12, 0x03, 0x65, 0x02, 0x10, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x02, 0x04, 0x01, 0x12, - 0x03, 0x65, 0x11, 0x15, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x02, 0x04, 0x03, 0x12, 0x03, 0x65, - 0x18, 0x19, 0x0a, 0x34, 0x0a, 0x02, 0x04, 0x05, 0x12, 0x04, 0x69, 0x00, 0x6d, 0x01, 0x1a, 0x28, - 0x20, 0x4b, 0x65, 0x79, 0x20, 0x75, 0x73, 0x65, 0x64, 0x20, 0x74, 0x6f, 0x20, 0x65, 0x6e, 0x63, - 0x72, 0x79, 0x70, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x2d, 0x62, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x0a, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x05, 0x01, 0x12, - 0x03, 0x69, 0x08, 0x19, 0x0a, 0x0c, 0x0a, 0x04, 0x04, 0x05, 0x08, 0x00, 0x12, 0x04, 0x6a, 0x02, - 0x6c, 0x03, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x05, 0x08, 0x00, 0x01, 0x12, 0x03, 0x6a, 0x08, 0x0b, - 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x05, 0x02, 0x00, 0x12, 0x03, 0x6b, 0x04, 0x1a, 0x0a, 0x0c, 0x0a, - 0x05, 0x04, 0x05, 0x02, 0x00, 0x05, 0x12, 0x03, 0x6b, 0x04, 0x09, 0x0a, 0x0c, 0x0a, 0x05, 0x04, - 0x05, 0x02, 0x00, 0x01, 0x12, 0x03, 0x6b, 0x0a, 0x15, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x05, 0x02, - 0x00, 0x03, 0x12, 0x03, 0x6b, 0x18, 0x19, 0x0a, 0x38, 0x0a, 0x02, 0x05, 0x01, 0x12, 0x04, 0x70, - 0x00, 0x74, 0x01, 0x1a, 0x2c, 0x20, 0x54, 0x68, 0x65, 0x20, 0x6b, 0x69, 0x6e, 0x64, 0x20, 0x6f, - 0x66, 0x20, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x20, 0x73, 0x79, 0x6e, 0x63, 0x20, 0x70, 0x61, - 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x20, 0x62, 0x65, 0x69, 0x6e, 0x67, 0x20, 0x73, 0x65, 0x6e, 0x74, - 0x0a, 0x0a, 0x0a, 0x0a, 0x03, 0x05, 0x01, 0x01, 0x12, 0x03, 0x70, 0x05, 0x13, 0x0a, 0x0b, 0x0a, - 0x04, 0x05, 0x01, 0x02, 0x00, 0x12, 0x03, 0x71, 0x02, 0x23, 0x0a, 0x0c, 0x0a, 0x05, 0x05, 0x01, - 0x02, 0x00, 0x01, 0x12, 0x03, 0x71, 0x02, 0x1e, 0x0a, 0x0c, 0x0a, 0x05, 0x05, 0x01, 0x02, 0x00, - 0x02, 0x12, 0x03, 0x71, 0x21, 0x22, 0x0a, 0x0b, 0x0a, 0x04, 0x05, 0x01, 0x02, 0x01, 0x12, 0x03, - 0x72, 0x02, 0x27, 0x0a, 0x0c, 0x0a, 0x05, 0x05, 0x01, 0x02, 0x01, 0x01, 0x12, 0x03, 0x72, 0x02, - 0x22, 0x0a, 0x0c, 0x0a, 0x05, 0x05, 0x01, 0x02, 0x01, 0x02, 0x12, 0x03, 0x72, 0x25, 0x26, 0x0a, - 0x0b, 0x0a, 0x04, 0x05, 0x01, 0x02, 0x02, 0x12, 0x03, 0x73, 0x02, 0x1f, 0x0a, 0x0c, 0x0a, 0x05, - 0x05, 0x01, 0x02, 0x02, 0x01, 0x12, 0x03, 0x73, 0x02, 0x1a, 0x0a, 0x0c, 0x0a, 0x05, 0x05, 0x01, - 0x02, 0x02, 0x02, 0x12, 0x03, 0x73, 0x1d, 0x1e, 0x0a, 0x0a, 0x0a, 0x02, 0x04, 0x06, 0x12, 0x04, - 0x76, 0x00, 0x78, 0x01, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x06, 0x01, 0x12, 0x03, 0x76, 0x08, 0x1c, - 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x06, 0x02, 0x00, 0x12, 0x03, 0x77, 0x02, 0x1d, 0x0a, 0x0c, 0x0a, - 0x05, 0x04, 0x06, 0x02, 0x00, 0x04, 0x12, 0x03, 0x77, 0x02, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, - 0x06, 0x02, 0x00, 0x05, 0x12, 0x03, 0x77, 0x0b, 0x10, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x06, 0x02, - 0x00, 0x01, 0x12, 0x03, 0x77, 0x11, 0x18, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x06, 0x02, 0x00, 0x03, - 0x12, 0x03, 0x77, 0x1b, 0x1c, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, 0x0a, 0x90, 0x06, - 0x0a, 0x2b, 0x6d, 0x6c, 0x73, 0x2f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, - 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2f, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x5f, 0x6d, 0x65, 0x6d, - 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x19, 0x78, - 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, - 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x22, 0xa0, 0x01, 0x0a, 0x0f, 0x47, 0x72, 0x6f, - 0x75, 0x70, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x12, 0x51, 0x0a, 0x07, - 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x37, 0x2e, + 0x67, 0x65, 0x2d, 0x62, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x0a, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x05, + 0x01, 0x12, 0x03, 0x69, 0x08, 0x19, 0x0a, 0x0c, 0x0a, 0x04, 0x04, 0x05, 0x08, 0x00, 0x12, 0x04, + 0x6a, 0x02, 0x6c, 0x03, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x05, 0x08, 0x00, 0x01, 0x12, 0x03, 0x6a, + 0x08, 0x0b, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x05, 0x02, 0x00, 0x12, 0x03, 0x6b, 0x04, 0x1a, 0x0a, + 0x0c, 0x0a, 0x05, 0x04, 0x05, 0x02, 0x00, 0x05, 0x12, 0x03, 0x6b, 0x04, 0x09, 0x0a, 0x0c, 0x0a, + 0x05, 0x04, 0x05, 0x02, 0x00, 0x01, 0x12, 0x03, 0x6b, 0x0a, 0x15, 0x0a, 0x0c, 0x0a, 0x05, 0x04, + 0x05, 0x02, 0x00, 0x03, 0x12, 0x03, 0x6b, 0x18, 0x19, 0x0a, 0x38, 0x0a, 0x02, 0x05, 0x01, 0x12, + 0x04, 0x70, 0x00, 0x74, 0x01, 0x1a, 0x2c, 0x20, 0x54, 0x68, 0x65, 0x20, 0x6b, 0x69, 0x6e, 0x64, + 0x20, 0x6f, 0x66, 0x20, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x20, 0x73, 0x79, 0x6e, 0x63, 0x20, + 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x20, 0x62, 0x65, 0x69, 0x6e, 0x67, 0x20, 0x73, 0x65, + 0x6e, 0x74, 0x0a, 0x0a, 0x0a, 0x0a, 0x03, 0x05, 0x01, 0x01, 0x12, 0x03, 0x70, 0x05, 0x13, 0x0a, + 0x0b, 0x0a, 0x04, 0x05, 0x01, 0x02, 0x00, 0x12, 0x03, 0x71, 0x02, 0x23, 0x0a, 0x0c, 0x0a, 0x05, + 0x05, 0x01, 0x02, 0x00, 0x01, 0x12, 0x03, 0x71, 0x02, 0x1e, 0x0a, 0x0c, 0x0a, 0x05, 0x05, 0x01, + 0x02, 0x00, 0x02, 0x12, 0x03, 0x71, 0x21, 0x22, 0x0a, 0x0b, 0x0a, 0x04, 0x05, 0x01, 0x02, 0x01, + 0x12, 0x03, 0x72, 0x02, 0x27, 0x0a, 0x0c, 0x0a, 0x05, 0x05, 0x01, 0x02, 0x01, 0x01, 0x12, 0x03, + 0x72, 0x02, 0x22, 0x0a, 0x0c, 0x0a, 0x05, 0x05, 0x01, 0x02, 0x01, 0x02, 0x12, 0x03, 0x72, 0x25, + 0x26, 0x0a, 0x0b, 0x0a, 0x04, 0x05, 0x01, 0x02, 0x02, 0x12, 0x03, 0x73, 0x02, 0x1f, 0x0a, 0x0c, + 0x0a, 0x05, 0x05, 0x01, 0x02, 0x02, 0x01, 0x12, 0x03, 0x73, 0x02, 0x1a, 0x0a, 0x0c, 0x0a, 0x05, + 0x05, 0x01, 0x02, 0x02, 0x02, 0x12, 0x03, 0x73, 0x1d, 0x1e, 0x0a, 0x0a, 0x0a, 0x02, 0x04, 0x06, + 0x12, 0x04, 0x76, 0x00, 0x78, 0x01, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x06, 0x01, 0x12, 0x03, 0x76, + 0x08, 0x1c, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x06, 0x02, 0x00, 0x12, 0x03, 0x77, 0x02, 0x1e, 0x0a, + 0x0c, 0x0a, 0x05, 0x04, 0x06, 0x02, 0x00, 0x04, 0x12, 0x03, 0x77, 0x02, 0x0a, 0x0a, 0x0c, 0x0a, + 0x05, 0x04, 0x06, 0x02, 0x00, 0x05, 0x12, 0x03, 0x77, 0x0b, 0x10, 0x0a, 0x0c, 0x0a, 0x05, 0x04, + 0x06, 0x02, 0x00, 0x01, 0x12, 0x03, 0x77, 0x11, 0x19, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x06, 0x02, + 0x00, 0x03, 0x12, 0x03, 0x77, 0x1c, 0x1d, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, 0x0a, + 0x90, 0x06, 0x0a, 0x2b, 0x6d, 0x6c, 0x73, 0x2f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, + 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2f, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x5f, 0x6d, + 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, + 0x19, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x22, 0xa0, 0x01, 0x0a, 0x0f, 0x47, + 0x72, 0x6f, 0x75, 0x70, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x12, 0x51, + 0x0a, 0x07, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x37, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x47, 0x72, 0x6f, 0x75, + 0x70, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x2e, 0x4d, 0x65, 0x6d, 0x62, + 0x65, 0x72, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, + 0x73, 0x1a, 0x3a, 0x0a, 0x0c, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x45, 0x6e, 0x74, 0x72, + 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, + 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x04, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x42, 0xe9, 0x01, + 0x0a, 0x1d, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x42, + 0x14, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, + 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x30, 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, 0x6d, 0x6c, 0x73, 0x2f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0xa2, 0x02, 0x03, 0x58, 0x4d, 0x4d, 0xaa, + 0x02, 0x18, 0x58, 0x6d, 0x74, 0x70, 0x2e, 0x4d, 0x6c, 0x73, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0xca, 0x02, 0x18, 0x58, 0x6d, 0x74, + 0x70, 0x5c, 0x4d, 0x6c, 0x73, 0x5c, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, + 0x74, 0x65, 0x6e, 0x74, 0x73, 0xe2, 0x02, 0x24, 0x58, 0x6d, 0x74, 0x70, 0x5c, 0x4d, 0x6c, 0x73, + 0x5c, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, + 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x1a, 0x58, + 0x6d, 0x74, 0x70, 0x3a, 0x3a, 0x4d, 0x6c, 0x73, 0x3a, 0x3a, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x4a, 0xae, 0x02, 0x0a, 0x06, 0x12, 0x04, + 0x01, 0x00, 0x0c, 0x01, 0x0a, 0x1c, 0x0a, 0x01, 0x0c, 0x12, 0x03, 0x01, 0x00, 0x12, 0x1a, 0x12, + 0x20, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x20, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, + 0x70, 0x0a, 0x0a, 0x08, 0x0a, 0x01, 0x02, 0x12, 0x03, 0x03, 0x00, 0x22, 0x0a, 0x08, 0x0a, 0x01, + 0x08, 0x12, 0x03, 0x05, 0x00, 0x47, 0x0a, 0x09, 0x0a, 0x02, 0x08, 0x0b, 0x12, 0x03, 0x05, 0x00, + 0x47, 0x0a, 0xa3, 0x01, 0x0a, 0x02, 0x04, 0x00, 0x12, 0x04, 0x0a, 0x00, 0x0c, 0x01, 0x1a, 0x96, + 0x01, 0x20, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x73, 0x20, 0x61, 0x20, 0x6d, 0x61, 0x70, + 0x70, 0x69, 0x6e, 0x67, 0x20, 0x6f, 0x66, 0x20, 0x60, 0x69, 0x6e, 0x62, 0x6f, 0x78, 0x5f, 0x69, + 0x64, 0x60, 0x20, 0x2d, 0x3e, 0x20, 0x60, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x5f, + 0x69, 0x64, 0x60, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x61, 0x6c, 0x6c, 0x20, 0x6d, 0x65, 0x6d, 0x62, + 0x65, 0x72, 0x73, 0x20, 0x6f, 0x66, 0x20, 0x61, 0x20, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x2e, 0x0a, + 0x20, 0x44, 0x65, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x20, 0x74, 0x6f, 0x20, 0x62, 0x65, 0x20, + 0x73, 0x74, 0x6f, 0x72, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x67, 0x72, + 0x6f, 0x75, 0x70, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x20, 0x65, 0x78, 0x74, 0x65, + 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x4d, 0x4c, 0x53, + 0x20, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x0a, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x00, 0x01, 0x12, 0x03, + 0x0a, 0x08, 0x17, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x00, 0x02, 0x00, 0x12, 0x03, 0x0b, 0x02, 0x22, + 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x00, 0x06, 0x12, 0x03, 0x0b, 0x02, 0x15, 0x0a, 0x0c, + 0x0a, 0x05, 0x04, 0x00, 0x02, 0x00, 0x01, 0x12, 0x03, 0x0b, 0x16, 0x1d, 0x0a, 0x0c, 0x0a, 0x05, + 0x04, 0x00, 0x02, 0x00, 0x03, 0x12, 0x03, 0x0b, 0x20, 0x21, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x33, 0x0a, 0xe5, 0x0e, 0x0a, 0x29, 0x6d, 0x6c, 0x73, 0x2f, 0x6d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2f, 0x67, 0x72, 0x6f, 0x75, + 0x70, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x12, 0x19, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x22, 0xa6, 0x02, 0x0a, 0x0f, + 0x47, 0x72, 0x6f, 0x75, 0x70, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x56, 0x31, 0x12, + 0x58, 0x0a, 0x11, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, + 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2b, 0x2e, 0x78, 0x6d, 0x74, + 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, + 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x43, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x10, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x12, 0x36, 0x0a, 0x17, 0x63, 0x72, 0x65, + 0x61, 0x74, 0x6f, 0x72, 0x5f, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x61, 0x64, 0x64, + 0x72, 0x65, 0x73, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x15, 0x63, 0x72, 0x65, 0x61, + 0x74, 0x6f, 0x72, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, + 0x73, 0x12, 0x28, 0x0a, 0x10, 0x63, 0x72, 0x65, 0x61, 0x74, 0x6f, 0x72, 0x5f, 0x69, 0x6e, 0x62, + 0x6f, 0x78, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x63, 0x72, 0x65, + 0x61, 0x74, 0x6f, 0x72, 0x49, 0x6e, 0x62, 0x6f, 0x78, 0x49, 0x64, 0x12, 0x48, 0x0a, 0x0a, 0x64, + 0x6d, 0x5f, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x24, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x44, 0x6d, 0x4d, 0x65, + 0x6d, 0x62, 0x65, 0x72, 0x73, 0x48, 0x00, 0x52, 0x09, 0x64, 0x6d, 0x4d, 0x65, 0x6d, 0x62, 0x65, + 0x72, 0x73, 0x88, 0x01, 0x01, 0x42, 0x0d, 0x0a, 0x0b, 0x5f, 0x64, 0x6d, 0x5f, 0x6d, 0x65, 0x6d, + 0x62, 0x65, 0x72, 0x73, 0x22, 0x22, 0x0a, 0x05, 0x49, 0x6e, 0x62, 0x6f, 0x78, 0x12, 0x19, 0x0a, + 0x08, 0x69, 0x6e, 0x62, 0x6f, 0x78, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x07, 0x69, 0x6e, 0x62, 0x6f, 0x78, 0x49, 0x64, 0x22, 0x97, 0x01, 0x0a, 0x09, 0x44, 0x6d, 0x4d, + 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x12, 0x44, 0x0a, 0x0d, 0x64, 0x6d, 0x5f, 0x6d, 0x65, 0x6d, + 0x62, 0x65, 0x72, 0x5f, 0x6f, 0x6e, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x4d, - 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x2e, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, - 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x1a, - 0x3a, 0x0a, 0x0c, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, - 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, - 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, - 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x42, 0xe9, 0x01, 0x0a, 0x1d, - 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x42, 0x14, 0x47, - 0x72, 0x6f, 0x75, 0x70, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x50, 0x72, + 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x49, 0x6e, 0x62, 0x6f, 0x78, 0x52, + 0x0b, 0x64, 0x6d, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x4f, 0x6e, 0x65, 0x12, 0x44, 0x0a, 0x0d, + 0x64, 0x6d, 0x5f, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x5f, 0x74, 0x77, 0x6f, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, + 0x49, 0x6e, 0x62, 0x6f, 0x78, 0x52, 0x0b, 0x64, 0x6d, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x54, + 0x77, 0x6f, 0x2a, 0x88, 0x01, 0x0a, 0x10, 0x43, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x12, 0x21, 0x0a, 0x1d, 0x43, 0x4f, 0x4e, 0x56, 0x45, + 0x52, 0x53, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x53, + 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x1b, 0x0a, 0x17, 0x43, 0x4f, + 0x4e, 0x56, 0x45, 0x52, 0x53, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, + 0x47, 0x52, 0x4f, 0x55, 0x50, 0x10, 0x01, 0x12, 0x18, 0x0a, 0x14, 0x43, 0x4f, 0x4e, 0x56, 0x45, + 0x52, 0x53, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x44, 0x4d, 0x10, + 0x02, 0x12, 0x1a, 0x0a, 0x16, 0x43, 0x4f, 0x4e, 0x56, 0x45, 0x52, 0x53, 0x41, 0x54, 0x49, 0x4f, + 0x4e, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x53, 0x59, 0x4e, 0x43, 0x10, 0x03, 0x42, 0xe7, 0x01, + 0x0a, 0x1d, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x42, + 0x12, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x30, 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, 0x6d, 0x6c, 0x73, 0x2f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, @@ -1065,73 +1143,625 @@ pub const FILE_DESCRIPTOR_SET: &[u8] = &[ 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x1a, 0x58, 0x6d, 0x74, 0x70, 0x3a, 0x3a, 0x4d, 0x6c, 0x73, 0x3a, 0x3a, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x43, - 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x4a, 0xae, 0x02, 0x0a, 0x06, 0x12, 0x04, 0x01, 0x00, - 0x0c, 0x01, 0x0a, 0x1c, 0x0a, 0x01, 0x0c, 0x12, 0x03, 0x01, 0x00, 0x12, 0x1a, 0x12, 0x20, 0x47, - 0x72, 0x6f, 0x75, 0x70, 0x20, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x0a, - 0x0a, 0x08, 0x0a, 0x01, 0x02, 0x12, 0x03, 0x03, 0x00, 0x22, 0x0a, 0x08, 0x0a, 0x01, 0x08, 0x12, - 0x03, 0x05, 0x00, 0x47, 0x0a, 0x09, 0x0a, 0x02, 0x08, 0x0b, 0x12, 0x03, 0x05, 0x00, 0x47, 0x0a, - 0xa3, 0x01, 0x0a, 0x02, 0x04, 0x00, 0x12, 0x04, 0x0a, 0x00, 0x0c, 0x01, 0x1a, 0x96, 0x01, 0x20, - 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x73, 0x20, 0x61, 0x20, 0x6d, 0x61, 0x70, 0x70, 0x69, - 0x6e, 0x67, 0x20, 0x6f, 0x66, 0x20, 0x60, 0x69, 0x6e, 0x62, 0x6f, 0x78, 0x5f, 0x69, 0x64, 0x60, - 0x20, 0x2d, 0x3e, 0x20, 0x60, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, - 0x60, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x61, 0x6c, 0x6c, 0x20, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, - 0x73, 0x20, 0x6f, 0x66, 0x20, 0x61, 0x20, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x2e, 0x0a, 0x20, 0x44, - 0x65, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x20, 0x74, 0x6f, 0x20, 0x62, 0x65, 0x20, 0x73, 0x74, - 0x6f, 0x72, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x67, 0x72, 0x6f, 0x75, - 0x70, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x20, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, - 0x69, 0x6f, 0x6e, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x4d, 0x4c, 0x53, 0x20, 0x67, - 0x72, 0x6f, 0x75, 0x70, 0x0a, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x00, 0x01, 0x12, 0x03, 0x0a, 0x08, - 0x17, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x00, 0x02, 0x00, 0x12, 0x03, 0x0b, 0x02, 0x22, 0x0a, 0x0c, - 0x0a, 0x05, 0x04, 0x00, 0x02, 0x00, 0x06, 0x12, 0x03, 0x0b, 0x02, 0x15, 0x0a, 0x0c, 0x0a, 0x05, - 0x04, 0x00, 0x02, 0x00, 0x01, 0x12, 0x03, 0x0b, 0x16, 0x1d, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, - 0x02, 0x00, 0x03, 0x12, 0x03, 0x0b, 0x20, 0x21, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, - 0x0a, 0xe5, 0x0e, 0x0a, 0x29, 0x6d, 0x6c, 0x73, 0x2f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2f, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x5f, - 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x19, - 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x22, 0xa6, 0x02, 0x0a, 0x0f, 0x47, 0x72, - 0x6f, 0x75, 0x70, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x56, 0x31, 0x12, 0x58, 0x0a, - 0x11, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x74, 0x79, - 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2b, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, - 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, - 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x43, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x10, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x12, 0x36, 0x0a, 0x17, 0x63, 0x72, 0x65, 0x61, 0x74, - 0x6f, 0x72, 0x5f, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, - 0x73, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x15, 0x63, 0x72, 0x65, 0x61, 0x74, 0x6f, - 0x72, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, - 0x28, 0x0a, 0x10, 0x63, 0x72, 0x65, 0x61, 0x74, 0x6f, 0x72, 0x5f, 0x69, 0x6e, 0x62, 0x6f, 0x78, - 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x63, 0x72, 0x65, 0x61, 0x74, - 0x6f, 0x72, 0x49, 0x6e, 0x62, 0x6f, 0x78, 0x49, 0x64, 0x12, 0x48, 0x0a, 0x0a, 0x64, 0x6d, 0x5f, - 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, + 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x4a, 0xb8, 0x07, 0x0a, 0x06, 0x12, 0x04, 0x01, 0x00, + 0x23, 0x01, 0x0a, 0x24, 0x0a, 0x01, 0x0c, 0x12, 0x03, 0x01, 0x00, 0x12, 0x1a, 0x1a, 0x20, 0x47, + 0x72, 0x6f, 0x75, 0x70, 0x20, 0x69, 0x6d, 0x6d, 0x75, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x6d, + 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x0a, 0x0a, 0x08, 0x0a, 0x01, 0x02, 0x12, 0x03, 0x03, + 0x00, 0x22, 0x0a, 0x08, 0x0a, 0x01, 0x08, 0x12, 0x03, 0x05, 0x00, 0x47, 0x0a, 0x09, 0x0a, 0x02, + 0x08, 0x0b, 0x12, 0x03, 0x05, 0x00, 0x47, 0x0a, 0x2f, 0x0a, 0x02, 0x04, 0x00, 0x12, 0x04, 0x09, + 0x00, 0x10, 0x01, 0x1a, 0x23, 0x20, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x20, 0x6d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x20, 0x6d, + 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x0a, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x00, 0x01, 0x12, + 0x03, 0x09, 0x08, 0x17, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x00, 0x02, 0x00, 0x12, 0x03, 0x0a, 0x02, + 0x29, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x00, 0x06, 0x12, 0x03, 0x0a, 0x02, 0x12, 0x0a, + 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x00, 0x01, 0x12, 0x03, 0x0a, 0x13, 0x24, 0x0a, 0x0c, 0x0a, + 0x05, 0x04, 0x00, 0x02, 0x00, 0x03, 0x12, 0x03, 0x0a, 0x27, 0x28, 0x0a, 0x28, 0x0a, 0x04, 0x04, + 0x00, 0x02, 0x01, 0x12, 0x03, 0x0c, 0x02, 0x25, 0x1a, 0x1b, 0x20, 0x54, 0x68, 0x69, 0x73, 0x20, + 0x77, 0x69, 0x6c, 0x6c, 0x20, 0x62, 0x65, 0x20, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x20, + 0x73, 0x6f, 0x6f, 0x6e, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x01, 0x05, 0x12, 0x03, + 0x0c, 0x02, 0x08, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x01, 0x01, 0x12, 0x03, 0x0c, 0x09, + 0x20, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x01, 0x03, 0x12, 0x03, 0x0c, 0x23, 0x24, 0x0a, + 0x0b, 0x0a, 0x04, 0x04, 0x00, 0x02, 0x02, 0x12, 0x03, 0x0d, 0x02, 0x1e, 0x0a, 0x0c, 0x0a, 0x05, + 0x04, 0x00, 0x02, 0x02, 0x05, 0x12, 0x03, 0x0d, 0x02, 0x08, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, + 0x02, 0x02, 0x01, 0x12, 0x03, 0x0d, 0x09, 0x19, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x02, + 0x03, 0x12, 0x03, 0x0d, 0x1c, 0x1d, 0x0a, 0x3e, 0x0a, 0x04, 0x04, 0x00, 0x02, 0x03, 0x12, 0x03, + 0x0f, 0x02, 0x24, 0x1a, 0x31, 0x20, 0x53, 0x68, 0x6f, 0x75, 0x6c, 0x64, 0x20, 0x6f, 0x6e, 0x6c, + 0x79, 0x20, 0x62, 0x65, 0x20, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x20, 0x66, 0x6f, 0x72, + 0x20, 0x43, 0x4f, 0x4e, 0x56, 0x45, 0x52, 0x53, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x54, 0x59, + 0x50, 0x45, 0x5f, 0x44, 0x4d, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x03, 0x04, 0x12, + 0x03, 0x0f, 0x02, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x03, 0x06, 0x12, 0x03, 0x0f, + 0x0b, 0x14, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x03, 0x01, 0x12, 0x03, 0x0f, 0x15, 0x1f, + 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x03, 0x03, 0x12, 0x03, 0x0f, 0x22, 0x23, 0x0a, 0x2e, + 0x0a, 0x02, 0x05, 0x00, 0x12, 0x04, 0x13, 0x00, 0x18, 0x01, 0x1a, 0x22, 0x20, 0x44, 0x65, 0x66, + 0x69, 0x6e, 0x65, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x79, 0x70, 0x65, 0x20, 0x6f, 0x66, + 0x20, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x0a, 0x0a, 0x0a, + 0x0a, 0x03, 0x05, 0x00, 0x01, 0x12, 0x03, 0x13, 0x05, 0x15, 0x0a, 0x0b, 0x0a, 0x04, 0x05, 0x00, + 0x02, 0x00, 0x12, 0x03, 0x14, 0x02, 0x24, 0x0a, 0x0c, 0x0a, 0x05, 0x05, 0x00, 0x02, 0x00, 0x01, + 0x12, 0x03, 0x14, 0x02, 0x1f, 0x0a, 0x0c, 0x0a, 0x05, 0x05, 0x00, 0x02, 0x00, 0x02, 0x12, 0x03, + 0x14, 0x22, 0x23, 0x0a, 0x0b, 0x0a, 0x04, 0x05, 0x00, 0x02, 0x01, 0x12, 0x03, 0x15, 0x02, 0x1e, + 0x0a, 0x0c, 0x0a, 0x05, 0x05, 0x00, 0x02, 0x01, 0x01, 0x12, 0x03, 0x15, 0x02, 0x19, 0x0a, 0x0c, + 0x0a, 0x05, 0x05, 0x00, 0x02, 0x01, 0x02, 0x12, 0x03, 0x15, 0x1c, 0x1d, 0x0a, 0x0b, 0x0a, 0x04, + 0x05, 0x00, 0x02, 0x02, 0x12, 0x03, 0x16, 0x02, 0x1b, 0x0a, 0x0c, 0x0a, 0x05, 0x05, 0x00, 0x02, + 0x02, 0x01, 0x12, 0x03, 0x16, 0x02, 0x16, 0x0a, 0x0c, 0x0a, 0x05, 0x05, 0x00, 0x02, 0x02, 0x02, + 0x12, 0x03, 0x16, 0x19, 0x1a, 0x0a, 0x0b, 0x0a, 0x04, 0x05, 0x00, 0x02, 0x03, 0x12, 0x03, 0x17, + 0x02, 0x1d, 0x0a, 0x0c, 0x0a, 0x05, 0x05, 0x00, 0x02, 0x03, 0x01, 0x12, 0x03, 0x17, 0x02, 0x18, + 0x0a, 0x0c, 0x0a, 0x05, 0x05, 0x00, 0x02, 0x03, 0x02, 0x12, 0x03, 0x17, 0x1b, 0x1c, 0x0a, 0x28, + 0x0a, 0x02, 0x04, 0x01, 0x12, 0x04, 0x1b, 0x00, 0x1d, 0x01, 0x1a, 0x1c, 0x20, 0x57, 0x72, 0x61, + 0x70, 0x70, 0x65, 0x72, 0x20, 0x61, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x20, 0x61, 0x6e, 0x20, 0x49, + 0x6e, 0x62, 0x6f, 0x78, 0x20, 0x49, 0x64, 0x0a, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x01, 0x01, 0x12, + 0x03, 0x1b, 0x08, 0x0d, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x01, 0x02, 0x00, 0x12, 0x03, 0x1c, 0x02, + 0x16, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x00, 0x05, 0x12, 0x03, 0x1c, 0x02, 0x08, 0x0a, + 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x00, 0x01, 0x12, 0x03, 0x1c, 0x09, 0x11, 0x0a, 0x0c, 0x0a, + 0x05, 0x04, 0x01, 0x02, 0x00, 0x03, 0x12, 0x03, 0x1c, 0x14, 0x15, 0x0a, 0x2b, 0x0a, 0x02, 0x04, + 0x02, 0x12, 0x04, 0x20, 0x00, 0x23, 0x01, 0x1a, 0x1f, 0x20, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x69, + 0x6e, 0x67, 0x20, 0x64, 0x6f, 0x65, 0x73, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x6d, 0x61, 0x74, 0x74, + 0x65, 0x72, 0x20, 0x68, 0x65, 0x72, 0x65, 0x0a, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x02, 0x01, 0x12, + 0x03, 0x20, 0x08, 0x11, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x02, 0x02, 0x00, 0x12, 0x03, 0x21, 0x02, + 0x1a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x00, 0x06, 0x12, 0x03, 0x21, 0x02, 0x07, 0x0a, + 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x00, 0x01, 0x12, 0x03, 0x21, 0x08, 0x15, 0x0a, 0x0c, 0x0a, + 0x05, 0x04, 0x02, 0x02, 0x00, 0x03, 0x12, 0x03, 0x21, 0x18, 0x19, 0x0a, 0x0b, 0x0a, 0x04, 0x04, + 0x02, 0x02, 0x01, 0x12, 0x03, 0x22, 0x02, 0x1a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x01, + 0x06, 0x12, 0x03, 0x22, 0x02, 0x07, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x01, 0x01, 0x12, + 0x03, 0x22, 0x08, 0x15, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x01, 0x03, 0x12, 0x03, 0x22, + 0x18, 0x19, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, 0x0a, 0x92, 0x0a, 0x0a, 0x31, 0x6d, + 0x6c, 0x73, 0x2f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, + 0x6e, 0x74, 0x73, 0x2f, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x5f, 0x6d, 0x75, 0x74, 0x61, 0x62, 0x6c, + 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x12, 0x19, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x22, 0xcb, 0x02, 0x0a, 0x16, + 0x47, 0x72, 0x6f, 0x75, 0x70, 0x4d, 0x75, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x4d, 0x65, 0x74, 0x61, + 0x64, 0x61, 0x74, 0x61, 0x56, 0x31, 0x12, 0x61, 0x0a, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, + 0x75, 0x74, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x41, 0x2e, 0x78, 0x6d, 0x74, + 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, + 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x4d, 0x75, 0x74, 0x61, + 0x62, 0x6c, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x56, 0x31, 0x2e, 0x41, 0x74, + 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0a, 0x61, + 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x12, 0x41, 0x0a, 0x0a, 0x61, 0x64, 0x6d, + 0x69, 0x6e, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x44, 0x6d, 0x4d, 0x65, 0x6d, 0x62, - 0x65, 0x72, 0x73, 0x48, 0x00, 0x52, 0x09, 0x64, 0x6d, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, - 0x88, 0x01, 0x01, 0x42, 0x0d, 0x0a, 0x0b, 0x5f, 0x64, 0x6d, 0x5f, 0x6d, 0x65, 0x6d, 0x62, 0x65, - 0x72, 0x73, 0x22, 0x22, 0x0a, 0x05, 0x49, 0x6e, 0x62, 0x6f, 0x78, 0x12, 0x19, 0x0a, 0x08, 0x69, - 0x6e, 0x62, 0x6f, 0x78, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x69, - 0x6e, 0x62, 0x6f, 0x78, 0x49, 0x64, 0x22, 0x97, 0x01, 0x0a, 0x09, 0x44, 0x6d, 0x4d, 0x65, 0x6d, - 0x62, 0x65, 0x72, 0x73, 0x12, 0x44, 0x0a, 0x0d, 0x64, 0x6d, 0x5f, 0x6d, 0x65, 0x6d, 0x62, 0x65, - 0x72, 0x5f, 0x6f, 0x6e, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x78, 0x6d, + 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x49, 0x6e, 0x62, 0x6f, 0x78, 0x65, + 0x73, 0x52, 0x09, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x4c, 0x0a, 0x10, + 0x73, 0x75, 0x70, 0x65, 0x72, 0x5f, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x5f, 0x6c, 0x69, 0x73, 0x74, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, + 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, + 0x74, 0x73, 0x2e, 0x49, 0x6e, 0x62, 0x6f, 0x78, 0x65, 0x73, 0x52, 0x0e, 0x73, 0x75, 0x70, 0x65, + 0x72, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x4c, 0x69, 0x73, 0x74, 0x1a, 0x3d, 0x0a, 0x0f, 0x41, 0x74, + 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, + 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, + 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x26, 0x0a, 0x07, 0x49, 0x6e, 0x62, + 0x6f, 0x78, 0x65, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x69, 0x6e, 0x62, 0x6f, 0x78, 0x5f, 0x69, 0x64, + 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x69, 0x6e, 0x62, 0x6f, 0x78, 0x49, 0x64, + 0x73, 0x42, 0xee, 0x01, 0x0a, 0x1d, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, + 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, + 0x6e, 0x74, 0x73, 0x42, 0x19, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x4d, 0x75, 0x74, 0x61, 0x62, 0x6c, + 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, + 0x5a, 0x30, 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, 0x6d, 0x6c, + 0x73, 0x2f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, + 0x74, 0x73, 0xa2, 0x02, 0x03, 0x58, 0x4d, 0x4d, 0xaa, 0x02, 0x18, 0x58, 0x6d, 0x74, 0x70, 0x2e, + 0x4d, 0x6c, 0x73, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, + 0x6e, 0x74, 0x73, 0xca, 0x02, 0x18, 0x58, 0x6d, 0x74, 0x70, 0x5c, 0x4d, 0x6c, 0x73, 0x5c, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0xe2, 0x02, + 0x24, 0x58, 0x6d, 0x74, 0x70, 0x5c, 0x4d, 0x6c, 0x73, 0x5c, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, + 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x1a, 0x58, 0x6d, 0x74, 0x70, 0x3a, 0x3a, 0x4d, 0x6c, + 0x73, 0x3a, 0x3a, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, + 0x74, 0x73, 0x4a, 0xd2, 0x04, 0x0a, 0x06, 0x12, 0x04, 0x01, 0x00, 0x16, 0x01, 0x0a, 0x22, 0x0a, + 0x01, 0x0c, 0x12, 0x03, 0x01, 0x00, 0x12, 0x1a, 0x18, 0x20, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x20, + 0x6d, 0x75, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, + 0x0a, 0x0a, 0x08, 0x0a, 0x01, 0x02, 0x12, 0x03, 0x03, 0x00, 0x22, 0x0a, 0x08, 0x0a, 0x01, 0x08, + 0x12, 0x03, 0x05, 0x00, 0x47, 0x0a, 0x09, 0x0a, 0x02, 0x08, 0x0b, 0x12, 0x03, 0x05, 0x00, 0x47, + 0x0a, 0x30, 0x0a, 0x02, 0x04, 0x00, 0x12, 0x04, 0x0a, 0x00, 0x11, 0x01, 0x1a, 0x24, 0x20, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x67, 0x72, 0x6f, 0x75, 0x70, + 0x20, 0x6d, 0x75, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, + 0x61, 0x0a, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x00, 0x01, 0x12, 0x03, 0x0a, 0x08, 0x1e, 0x0a, 0x4a, + 0x0a, 0x04, 0x04, 0x00, 0x02, 0x00, 0x12, 0x03, 0x0c, 0x02, 0x25, 0x1a, 0x3d, 0x20, 0x4d, 0x61, + 0x70, 0x20, 0x74, 0x6f, 0x20, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x20, 0x76, 0x61, 0x72, 0x69, 0x6f, + 0x75, 0x73, 0x20, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x20, 0x61, 0x74, 0x74, 0x72, + 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x20, 0x28, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x20, 0x6e, 0x61, + 0x6d, 0x65, 0x2c, 0x20, 0x65, 0x74, 0x63, 0x2e, 0x29, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, + 0x02, 0x00, 0x06, 0x12, 0x03, 0x0c, 0x02, 0x15, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x00, + 0x01, 0x12, 0x03, 0x0c, 0x16, 0x20, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x00, 0x03, 0x12, + 0x03, 0x0c, 0x23, 0x24, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x00, 0x02, 0x01, 0x12, 0x03, 0x0d, 0x02, + 0x19, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x01, 0x06, 0x12, 0x03, 0x0d, 0x02, 0x09, 0x0a, + 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x01, 0x01, 0x12, 0x03, 0x0d, 0x0a, 0x14, 0x0a, 0x0c, 0x0a, + 0x05, 0x04, 0x00, 0x02, 0x01, 0x03, 0x12, 0x03, 0x0d, 0x17, 0x18, 0x0a, 0x64, 0x0a, 0x04, 0x04, + 0x00, 0x02, 0x02, 0x12, 0x03, 0x10, 0x02, 0x1f, 0x1a, 0x57, 0x20, 0x43, 0x72, 0x65, 0x61, 0x74, + 0x6f, 0x72, 0x20, 0x73, 0x74, 0x61, 0x72, 0x74, 0x73, 0x20, 0x61, 0x73, 0x20, 0x6f, 0x6e, 0x6c, + 0x79, 0x20, 0x73, 0x75, 0x70, 0x65, 0x72, 0x5f, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x0a, 0x20, 0x4f, + 0x6e, 0x6c, 0x79, 0x20, 0x73, 0x75, 0x70, 0x65, 0x72, 0x5f, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x20, + 0x63, 0x61, 0x6e, 0x20, 0x61, 0x64, 0x64, 0x2f, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x20, 0x6f, + 0x74, 0x68, 0x65, 0x72, 0x20, 0x73, 0x75, 0x70, 0x65, 0x72, 0x5f, 0x61, 0x64, 0x6d, 0x69, 0x6e, + 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x02, 0x06, 0x12, 0x03, 0x10, 0x02, 0x09, 0x0a, + 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x02, 0x01, 0x12, 0x03, 0x10, 0x0a, 0x1a, 0x0a, 0x0c, 0x0a, + 0x05, 0x04, 0x00, 0x02, 0x02, 0x03, 0x12, 0x03, 0x10, 0x1d, 0x1e, 0x0a, 0x39, 0x0a, 0x02, 0x04, + 0x01, 0x12, 0x04, 0x14, 0x00, 0x16, 0x01, 0x1a, 0x2d, 0x20, 0x57, 0x72, 0x61, 0x70, 0x70, 0x65, + 0x72, 0x20, 0x61, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x20, 0x61, 0x20, 0x6c, 0x69, 0x73, 0x74, 0x20, + 0x6f, 0x66, 0x20, 0x72, 0x65, 0x70, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x49, 0x6e, 0x62, 0x6f, + 0x78, 0x20, 0x49, 0x64, 0x73, 0x0a, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x01, 0x01, 0x12, 0x03, 0x14, + 0x08, 0x0f, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x01, 0x02, 0x00, 0x12, 0x03, 0x15, 0x02, 0x20, 0x0a, + 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x00, 0x04, 0x12, 0x03, 0x15, 0x02, 0x0a, 0x0a, 0x0c, 0x0a, + 0x05, 0x04, 0x01, 0x02, 0x00, 0x05, 0x12, 0x03, 0x15, 0x0b, 0x11, 0x0a, 0x0c, 0x0a, 0x05, 0x04, + 0x01, 0x02, 0x00, 0x01, 0x12, 0x03, 0x15, 0x12, 0x1b, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, + 0x00, 0x03, 0x12, 0x03, 0x15, 0x1e, 0x1f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, 0x0a, + 0xfb, 0x31, 0x0a, 0x2c, 0x6d, 0x6c, 0x73, 0x2f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, + 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2f, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x5f, 0x70, + 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x12, 0x19, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x22, 0x5d, 0x0a, 0x19, 0x47, + 0x72, 0x6f, 0x75, 0x70, 0x4d, 0x75, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x50, 0x65, 0x72, 0x6d, 0x69, + 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x56, 0x31, 0x12, 0x40, 0x0a, 0x08, 0x70, 0x6f, 0x6c, 0x69, + 0x63, 0x69, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x78, 0x6d, 0x74, + 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, + 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x53, 0x65, 0x74, + 0x52, 0x08, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x22, 0xdf, 0x05, 0x0a, 0x09, 0x50, + 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x53, 0x65, 0x74, 0x12, 0x57, 0x0a, 0x11, 0x61, 0x64, 0x64, 0x5f, + 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x5f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, + 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, + 0x52, 0x0f, 0x61, 0x64, 0x64, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x50, 0x6f, 0x6c, 0x69, 0x63, + 0x79, 0x12, 0x5d, 0x0a, 0x14, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x5f, 0x6d, 0x65, 0x6d, 0x62, + 0x65, 0x72, 0x5f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x2b, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x4d, 0x65, 0x6d, 0x62, + 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x12, 0x72, 0x65, + 0x6d, 0x6f, 0x76, 0x65, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, + 0x12, 0x74, 0x0a, 0x16, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, + 0x61, 0x74, 0x61, 0x5f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x3e, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x50, 0x6f, 0x6c, + 0x69, 0x63, 0x79, 0x53, 0x65, 0x74, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4d, 0x65, 0x74, + 0x61, 0x64, 0x61, 0x74, 0x61, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x45, 0x6e, 0x74, 0x72, 0x79, + 0x52, 0x14, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, + 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x5c, 0x0a, 0x10, 0x61, 0x64, 0x64, 0x5f, 0x61, 0x64, + 0x6d, 0x69, 0x6e, 0x5f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x32, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x50, 0x65, 0x72, + 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, 0x6f, + 0x6c, 0x69, 0x63, 0x79, 0x52, 0x0e, 0x61, 0x64, 0x64, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x50, 0x6f, + 0x6c, 0x69, 0x63, 0x79, 0x12, 0x62, 0x0a, 0x13, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x5f, 0x61, + 0x64, 0x6d, 0x69, 0x6e, 0x5f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x32, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x50, 0x65, + 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, + 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x11, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x41, 0x64, 0x6d, + 0x69, 0x6e, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x6e, 0x0a, 0x19, 0x75, 0x70, 0x64, 0x61, + 0x74, 0x65, 0x5f, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x5f, 0x70, + 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x32, 0x2e, 0x78, 0x6d, + 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, + 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, + 0x6f, 0x6e, 0x73, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, + 0x17, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, + 0x6e, 0x73, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x1a, 0x72, 0x0a, 0x19, 0x55, 0x70, 0x64, 0x61, + 0x74, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, + 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x3f, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, + 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, + 0x74, 0x73, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x50, 0x6f, 0x6c, 0x69, 0x63, + 0x79, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x8a, 0x05, 0x0a, + 0x10, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x50, 0x6f, 0x6c, 0x69, 0x63, + 0x79, 0x12, 0x4c, 0x0a, 0x04, 0x62, 0x61, 0x73, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, + 0x36, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x4d, 0x65, 0x6d, 0x62, + 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x42, 0x61, 0x73, + 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x48, 0x00, 0x52, 0x04, 0x62, 0x61, 0x73, 0x65, 0x12, + 0x5f, 0x0a, 0x0d, 0x61, 0x6e, 0x64, 0x5f, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x38, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, + 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, + 0x74, 0x73, 0x2e, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x50, 0x6f, 0x6c, + 0x69, 0x63, 0x79, 0x2e, 0x41, 0x6e, 0x64, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, + 0x48, 0x00, 0x52, 0x0c, 0x61, 0x6e, 0x64, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, + 0x12, 0x5f, 0x0a, 0x0d, 0x61, 0x6e, 0x79, 0x5f, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, + 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x38, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, + 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, + 0x6e, 0x74, 0x73, 0x2e, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x50, 0x6f, + 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x41, 0x6e, 0x79, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, + 0x6e, 0x48, 0x00, 0x52, 0x0c, 0x61, 0x6e, 0x79, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, + 0x6e, 0x1a, 0x57, 0x0a, 0x0c, 0x41, 0x6e, 0x64, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, + 0x6e, 0x12, 0x47, 0x0a, 0x08, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x18, 0x01, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, + 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, + 0x52, 0x08, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x1a, 0x57, 0x0a, 0x0c, 0x41, 0x6e, + 0x79, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x47, 0x0a, 0x08, 0x70, 0x6f, + 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x78, + 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, + 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, + 0x68, 0x69, 0x70, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x08, 0x70, 0x6f, 0x6c, 0x69, 0x63, + 0x69, 0x65, 0x73, 0x22, 0xab, 0x01, 0x0a, 0x0a, 0x42, 0x61, 0x73, 0x65, 0x50, 0x6f, 0x6c, 0x69, + 0x63, 0x79, 0x12, 0x1b, 0x0a, 0x17, 0x42, 0x41, 0x53, 0x45, 0x5f, 0x50, 0x4f, 0x4c, 0x49, 0x43, + 0x59, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, + 0x15, 0x0a, 0x11, 0x42, 0x41, 0x53, 0x45, 0x5f, 0x50, 0x4f, 0x4c, 0x49, 0x43, 0x59, 0x5f, 0x41, + 0x4c, 0x4c, 0x4f, 0x57, 0x10, 0x01, 0x12, 0x14, 0x0a, 0x10, 0x42, 0x41, 0x53, 0x45, 0x5f, 0x50, + 0x4f, 0x4c, 0x49, 0x43, 0x59, 0x5f, 0x44, 0x45, 0x4e, 0x59, 0x10, 0x02, 0x12, 0x2d, 0x0a, 0x29, + 0x42, 0x41, 0x53, 0x45, 0x5f, 0x50, 0x4f, 0x4c, 0x49, 0x43, 0x59, 0x5f, 0x41, 0x4c, 0x4c, 0x4f, + 0x57, 0x5f, 0x49, 0x46, 0x5f, 0x41, 0x44, 0x4d, 0x49, 0x4e, 0x5f, 0x4f, 0x52, 0x5f, 0x53, 0x55, + 0x50, 0x45, 0x52, 0x5f, 0x41, 0x44, 0x4d, 0x49, 0x4e, 0x10, 0x03, 0x12, 0x24, 0x0a, 0x20, 0x42, + 0x41, 0x53, 0x45, 0x5f, 0x50, 0x4f, 0x4c, 0x49, 0x43, 0x59, 0x5f, 0x41, 0x4c, 0x4c, 0x4f, 0x57, + 0x5f, 0x49, 0x46, 0x5f, 0x53, 0x55, 0x50, 0x45, 0x52, 0x5f, 0x41, 0x44, 0x4d, 0x49, 0x4e, 0x10, + 0x04, 0x42, 0x06, 0x0a, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x22, 0xac, 0x05, 0x0a, 0x0e, 0x4d, 0x65, + 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x52, 0x0a, 0x04, + 0x62, 0x61, 0x73, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x3c, 0x2e, 0x78, 0x6d, 0x74, + 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, + 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x50, + 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x42, 0x61, + 0x73, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x48, 0x00, 0x52, 0x04, 0x62, 0x61, 0x73, 0x65, + 0x12, 0x5d, 0x0a, 0x0d, 0x61, 0x6e, 0x64, 0x5f, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, + 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x36, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, + 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, + 0x6e, 0x74, 0x73, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x50, 0x6f, 0x6c, 0x69, + 0x63, 0x79, 0x2e, 0x41, 0x6e, 0x64, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x48, + 0x00, 0x52, 0x0c, 0x61, 0x6e, 0x64, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, + 0x5d, 0x0a, 0x0d, 0x61, 0x6e, 0x79, 0x5f, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x36, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, + 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, + 0x74, 0x73, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x50, 0x6f, 0x6c, 0x69, 0x63, + 0x79, 0x2e, 0x41, 0x6e, 0x79, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x00, + 0x52, 0x0c, 0x61, 0x6e, 0x79, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x1a, 0x55, + 0x0a, 0x0c, 0x41, 0x6e, 0x64, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x45, + 0x0a, 0x08, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x29, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x4d, 0x65, 0x74, + 0x61, 0x64, 0x61, 0x74, 0x61, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x08, 0x70, 0x6f, 0x6c, + 0x69, 0x63, 0x69, 0x65, 0x73, 0x1a, 0x55, 0x0a, 0x0c, 0x41, 0x6e, 0x79, 0x43, 0x6f, 0x6e, 0x64, + 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x45, 0x0a, 0x08, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, + 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, + 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, + 0x6e, 0x74, 0x73, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x50, 0x6f, 0x6c, 0x69, + 0x63, 0x79, 0x52, 0x08, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x22, 0xd1, 0x01, 0x0a, + 0x12, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x42, 0x61, 0x73, 0x65, 0x50, 0x6f, 0x6c, + 0x69, 0x63, 0x79, 0x12, 0x24, 0x0a, 0x20, 0x4d, 0x45, 0x54, 0x41, 0x44, 0x41, 0x54, 0x41, 0x5f, + 0x42, 0x41, 0x53, 0x45, 0x5f, 0x50, 0x4f, 0x4c, 0x49, 0x43, 0x59, 0x5f, 0x55, 0x4e, 0x53, 0x50, + 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x1e, 0x0a, 0x1a, 0x4d, 0x45, 0x54, + 0x41, 0x44, 0x41, 0x54, 0x41, 0x5f, 0x42, 0x41, 0x53, 0x45, 0x5f, 0x50, 0x4f, 0x4c, 0x49, 0x43, + 0x59, 0x5f, 0x41, 0x4c, 0x4c, 0x4f, 0x57, 0x10, 0x01, 0x12, 0x1d, 0x0a, 0x19, 0x4d, 0x45, 0x54, + 0x41, 0x44, 0x41, 0x54, 0x41, 0x5f, 0x42, 0x41, 0x53, 0x45, 0x5f, 0x50, 0x4f, 0x4c, 0x49, 0x43, + 0x59, 0x5f, 0x44, 0x45, 0x4e, 0x59, 0x10, 0x02, 0x12, 0x27, 0x0a, 0x23, 0x4d, 0x45, 0x54, 0x41, + 0x44, 0x41, 0x54, 0x41, 0x5f, 0x42, 0x41, 0x53, 0x45, 0x5f, 0x50, 0x4f, 0x4c, 0x49, 0x43, 0x59, + 0x5f, 0x41, 0x4c, 0x4c, 0x4f, 0x57, 0x5f, 0x49, 0x46, 0x5f, 0x41, 0x44, 0x4d, 0x49, 0x4e, 0x10, + 0x03, 0x12, 0x2d, 0x0a, 0x29, 0x4d, 0x45, 0x54, 0x41, 0x44, 0x41, 0x54, 0x41, 0x5f, 0x42, 0x41, + 0x53, 0x45, 0x5f, 0x50, 0x4f, 0x4c, 0x49, 0x43, 0x59, 0x5f, 0x41, 0x4c, 0x4c, 0x4f, 0x57, 0x5f, + 0x49, 0x46, 0x5f, 0x53, 0x55, 0x50, 0x45, 0x52, 0x5f, 0x41, 0x44, 0x4d, 0x49, 0x4e, 0x10, 0x04, + 0x42, 0x06, 0x0a, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x22, 0xd4, 0x05, 0x0a, 0x17, 0x50, 0x65, 0x72, + 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, 0x6f, + 0x6c, 0x69, 0x63, 0x79, 0x12, 0x5e, 0x0a, 0x04, 0x62, 0x61, 0x73, 0x65, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0e, 0x32, 0x48, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x50, + 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, + 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, + 0x6e, 0x73, 0x42, 0x61, 0x73, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x48, 0x00, 0x52, 0x04, + 0x62, 0x61, 0x73, 0x65, 0x12, 0x66, 0x0a, 0x0d, 0x61, 0x6e, 0x64, 0x5f, 0x63, 0x6f, 0x6e, 0x64, + 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3f, 0x2e, 0x78, 0x6d, + 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, + 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, + 0x6f, 0x6e, 0x73, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, + 0x41, 0x6e, 0x64, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x0c, + 0x61, 0x6e, 0x64, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x66, 0x0a, 0x0d, + 0x61, 0x6e, 0x79, 0x5f, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x3f, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, + 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x55, 0x70, 0x64, 0x61, 0x74, + 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x41, 0x6e, 0x79, 0x43, 0x6f, 0x6e, 0x64, 0x69, + 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x0c, 0x61, 0x6e, 0x79, 0x43, 0x6f, 0x6e, 0x64, 0x69, + 0x74, 0x69, 0x6f, 0x6e, 0x1a, 0x5e, 0x0a, 0x0c, 0x41, 0x6e, 0x64, 0x43, 0x6f, 0x6e, 0x64, 0x69, + 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x4e, 0x0a, 0x08, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, + 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x32, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, + 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, + 0x74, 0x73, 0x2e, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x55, 0x70, + 0x64, 0x61, 0x74, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x08, 0x70, 0x6f, 0x6c, 0x69, + 0x63, 0x69, 0x65, 0x73, 0x1a, 0x5e, 0x0a, 0x0c, 0x41, 0x6e, 0x79, 0x43, 0x6f, 0x6e, 0x64, 0x69, + 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x4e, 0x0a, 0x08, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, + 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x32, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, + 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, + 0x74, 0x73, 0x2e, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x55, 0x70, + 0x64, 0x61, 0x74, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x08, 0x70, 0x6f, 0x6c, 0x69, + 0x63, 0x69, 0x65, 0x73, 0x22, 0xc0, 0x01, 0x0a, 0x15, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, + 0x69, 0x6f, 0x6e, 0x73, 0x42, 0x61, 0x73, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x27, + 0x0a, 0x23, 0x50, 0x45, 0x52, 0x4d, 0x49, 0x53, 0x53, 0x49, 0x4f, 0x4e, 0x53, 0x5f, 0x42, 0x41, + 0x53, 0x45, 0x5f, 0x50, 0x4f, 0x4c, 0x49, 0x43, 0x59, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, + 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x20, 0x0a, 0x1c, 0x50, 0x45, 0x52, 0x4d, 0x49, + 0x53, 0x53, 0x49, 0x4f, 0x4e, 0x53, 0x5f, 0x42, 0x41, 0x53, 0x45, 0x5f, 0x50, 0x4f, 0x4c, 0x49, + 0x43, 0x59, 0x5f, 0x44, 0x45, 0x4e, 0x59, 0x10, 0x01, 0x12, 0x2a, 0x0a, 0x26, 0x50, 0x45, 0x52, + 0x4d, 0x49, 0x53, 0x53, 0x49, 0x4f, 0x4e, 0x53, 0x5f, 0x42, 0x41, 0x53, 0x45, 0x5f, 0x50, 0x4f, + 0x4c, 0x49, 0x43, 0x59, 0x5f, 0x41, 0x4c, 0x4c, 0x4f, 0x57, 0x5f, 0x49, 0x46, 0x5f, 0x41, 0x44, + 0x4d, 0x49, 0x4e, 0x10, 0x02, 0x12, 0x30, 0x0a, 0x2c, 0x50, 0x45, 0x52, 0x4d, 0x49, 0x53, 0x53, + 0x49, 0x4f, 0x4e, 0x53, 0x5f, 0x42, 0x41, 0x53, 0x45, 0x5f, 0x50, 0x4f, 0x4c, 0x49, 0x43, 0x59, + 0x5f, 0x41, 0x4c, 0x4c, 0x4f, 0x57, 0x5f, 0x49, 0x46, 0x5f, 0x53, 0x55, 0x50, 0x45, 0x52, 0x5f, + 0x41, 0x44, 0x4d, 0x49, 0x4e, 0x10, 0x03, 0x42, 0x06, 0x0a, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x42, + 0xea, 0x01, 0x0a, 0x1d, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, + 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, + 0x73, 0x42, 0x15, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, + 0x6f, 0x6e, 0x73, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x30, 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, 0x6d, 0x6c, 0x73, 0x2f, 0x6d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0xa2, 0x02, 0x03, 0x58, + 0x4d, 0x4d, 0xaa, 0x02, 0x18, 0x58, 0x6d, 0x74, 0x70, 0x2e, 0x4d, 0x6c, 0x73, 0x2e, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0xca, 0x02, 0x18, + 0x58, 0x6d, 0x74, 0x70, 0x5c, 0x4d, 0x6c, 0x73, 0x5c, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0xe2, 0x02, 0x24, 0x58, 0x6d, 0x74, 0x70, 0x5c, + 0x4d, 0x6c, 0x73, 0x5c, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, + 0x6e, 0x74, 0x73, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, + 0x02, 0x1a, 0x58, 0x6d, 0x74, 0x70, 0x3a, 0x3a, 0x4d, 0x6c, 0x73, 0x3a, 0x3a, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x4a, 0xe6, 0x18, 0x0a, + 0x06, 0x12, 0x04, 0x01, 0x00, 0x68, 0x01, 0x0a, 0x2e, 0x0a, 0x01, 0x0c, 0x12, 0x03, 0x01, 0x00, + 0x12, 0x1a, 0x24, 0x20, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x20, 0x6d, 0x75, 0x74, 0x61, 0x62, 0x6c, + 0x65, 0x20, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x6d, 0x65, + 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x0a, 0x0a, 0x08, 0x0a, 0x01, 0x02, 0x12, 0x03, 0x03, 0x00, + 0x22, 0x0a, 0x08, 0x0a, 0x01, 0x08, 0x12, 0x03, 0x05, 0x00, 0x47, 0x0a, 0x09, 0x0a, 0x02, 0x08, + 0x0b, 0x12, 0x03, 0x05, 0x00, 0x47, 0x0a, 0x30, 0x0a, 0x02, 0x04, 0x00, 0x12, 0x04, 0x09, 0x00, + 0x0b, 0x01, 0x1a, 0x24, 0x20, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x20, 0x66, 0x6f, 0x72, + 0x20, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x20, 0x6d, 0x75, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x6d, + 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x0a, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x00, 0x01, 0x12, + 0x03, 0x09, 0x08, 0x21, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x00, 0x02, 0x00, 0x12, 0x03, 0x0a, 0x02, + 0x19, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x00, 0x06, 0x12, 0x03, 0x0a, 0x02, 0x0b, 0x0a, + 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x00, 0x01, 0x12, 0x03, 0x0a, 0x0c, 0x14, 0x0a, 0x0c, 0x0a, + 0x05, 0x04, 0x00, 0x02, 0x00, 0x03, 0x12, 0x03, 0x0a, 0x17, 0x18, 0x0a, 0x37, 0x0a, 0x02, 0x04, + 0x01, 0x12, 0x04, 0x0e, 0x00, 0x15, 0x01, 0x1a, 0x2b, 0x20, 0x54, 0x68, 0x65, 0x20, 0x73, 0x65, + 0x74, 0x20, 0x6f, 0x66, 0x20, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x20, 0x74, 0x68, + 0x61, 0x74, 0x20, 0x67, 0x6f, 0x76, 0x65, 0x72, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x67, 0x72, + 0x6f, 0x75, 0x70, 0x0a, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x01, 0x01, 0x12, 0x03, 0x0e, 0x08, 0x11, + 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x01, 0x02, 0x00, 0x12, 0x03, 0x0f, 0x02, 0x29, 0x0a, 0x0c, 0x0a, + 0x05, 0x04, 0x01, 0x02, 0x00, 0x06, 0x12, 0x03, 0x0f, 0x02, 0x12, 0x0a, 0x0c, 0x0a, 0x05, 0x04, + 0x01, 0x02, 0x00, 0x01, 0x12, 0x03, 0x0f, 0x13, 0x24, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, + 0x00, 0x03, 0x12, 0x03, 0x0f, 0x27, 0x28, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x01, 0x02, 0x01, 0x12, + 0x03, 0x10, 0x02, 0x2c, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x01, 0x06, 0x12, 0x03, 0x10, + 0x02, 0x12, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x01, 0x01, 0x12, 0x03, 0x10, 0x13, 0x27, + 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x01, 0x03, 0x12, 0x03, 0x10, 0x2a, 0x2b, 0x0a, 0x0b, + 0x0a, 0x04, 0x04, 0x01, 0x02, 0x02, 0x12, 0x03, 0x11, 0x02, 0x39, 0x0a, 0x0c, 0x0a, 0x05, 0x04, + 0x01, 0x02, 0x02, 0x06, 0x12, 0x03, 0x11, 0x02, 0x1d, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, + 0x02, 0x01, 0x12, 0x03, 0x11, 0x1e, 0x34, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x02, 0x03, + 0x12, 0x03, 0x11, 0x37, 0x38, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x01, 0x02, 0x03, 0x12, 0x03, 0x12, + 0x02, 0x2f, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x03, 0x06, 0x12, 0x03, 0x12, 0x02, 0x19, + 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x03, 0x01, 0x12, 0x03, 0x12, 0x1a, 0x2a, 0x0a, 0x0c, + 0x0a, 0x05, 0x04, 0x01, 0x02, 0x03, 0x03, 0x12, 0x03, 0x12, 0x2d, 0x2e, 0x0a, 0x0b, 0x0a, 0x04, + 0x04, 0x01, 0x02, 0x04, 0x12, 0x03, 0x13, 0x02, 0x32, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, + 0x04, 0x06, 0x12, 0x03, 0x13, 0x02, 0x19, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x04, 0x01, + 0x12, 0x03, 0x13, 0x1a, 0x2d, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x04, 0x03, 0x12, 0x03, + 0x13, 0x30, 0x31, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x01, 0x02, 0x05, 0x12, 0x03, 0x14, 0x02, 0x38, + 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x05, 0x06, 0x12, 0x03, 0x14, 0x02, 0x19, 0x0a, 0x0c, + 0x0a, 0x05, 0x04, 0x01, 0x02, 0x05, 0x01, 0x12, 0x03, 0x14, 0x1a, 0x33, 0x0a, 0x0c, 0x0a, 0x05, + 0x04, 0x01, 0x02, 0x05, 0x03, 0x12, 0x03, 0x14, 0x36, 0x37, 0x0a, 0x4c, 0x0a, 0x02, 0x04, 0x02, + 0x12, 0x04, 0x18, 0x00, 0x31, 0x01, 0x1a, 0x40, 0x20, 0x41, 0x20, 0x70, 0x6f, 0x6c, 0x69, 0x63, + 0x79, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x67, 0x6f, 0x76, 0x65, 0x72, 0x6e, 0x73, 0x20, 0x61, + 0x64, 0x64, 0x69, 0x6e, 0x67, 0x2f, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x69, 0x6e, 0x67, 0x20, 0x6d, + 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x20, 0x6f, 0x72, 0x20, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, + 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x0a, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x02, 0x01, 0x12, + 0x03, 0x18, 0x08, 0x18, 0x0a, 0x1b, 0x0a, 0x04, 0x04, 0x02, 0x04, 0x00, 0x12, 0x04, 0x1a, 0x02, + 0x20, 0x03, 0x1a, 0x0d, 0x20, 0x42, 0x61, 0x73, 0x65, 0x20, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, + 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x04, 0x00, 0x01, 0x12, 0x03, 0x1a, 0x07, 0x11, 0x0a, + 0x0d, 0x0a, 0x06, 0x04, 0x02, 0x04, 0x00, 0x02, 0x00, 0x12, 0x03, 0x1b, 0x04, 0x20, 0x0a, 0x0e, + 0x0a, 0x07, 0x04, 0x02, 0x04, 0x00, 0x02, 0x00, 0x01, 0x12, 0x03, 0x1b, 0x04, 0x1b, 0x0a, 0x0e, + 0x0a, 0x07, 0x04, 0x02, 0x04, 0x00, 0x02, 0x00, 0x02, 0x12, 0x03, 0x1b, 0x1e, 0x1f, 0x0a, 0x0d, + 0x0a, 0x06, 0x04, 0x02, 0x04, 0x00, 0x02, 0x01, 0x12, 0x03, 0x1c, 0x04, 0x1a, 0x0a, 0x0e, 0x0a, + 0x07, 0x04, 0x02, 0x04, 0x00, 0x02, 0x01, 0x01, 0x12, 0x03, 0x1c, 0x04, 0x15, 0x0a, 0x0e, 0x0a, + 0x07, 0x04, 0x02, 0x04, 0x00, 0x02, 0x01, 0x02, 0x12, 0x03, 0x1c, 0x18, 0x19, 0x0a, 0x0d, 0x0a, + 0x06, 0x04, 0x02, 0x04, 0x00, 0x02, 0x02, 0x12, 0x03, 0x1d, 0x04, 0x19, 0x0a, 0x0e, 0x0a, 0x07, + 0x04, 0x02, 0x04, 0x00, 0x02, 0x02, 0x01, 0x12, 0x03, 0x1d, 0x04, 0x14, 0x0a, 0x0e, 0x0a, 0x07, + 0x04, 0x02, 0x04, 0x00, 0x02, 0x02, 0x02, 0x12, 0x03, 0x1d, 0x17, 0x18, 0x0a, 0x0d, 0x0a, 0x06, + 0x04, 0x02, 0x04, 0x00, 0x02, 0x03, 0x12, 0x03, 0x1e, 0x04, 0x32, 0x0a, 0x0e, 0x0a, 0x07, 0x04, + 0x02, 0x04, 0x00, 0x02, 0x03, 0x01, 0x12, 0x03, 0x1e, 0x04, 0x2d, 0x0a, 0x0e, 0x0a, 0x07, 0x04, + 0x02, 0x04, 0x00, 0x02, 0x03, 0x02, 0x12, 0x03, 0x1e, 0x30, 0x31, 0x0a, 0x0d, 0x0a, 0x06, 0x04, + 0x02, 0x04, 0x00, 0x02, 0x04, 0x12, 0x03, 0x1f, 0x04, 0x29, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, + 0x04, 0x00, 0x02, 0x04, 0x01, 0x12, 0x03, 0x1f, 0x04, 0x24, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, + 0x04, 0x00, 0x02, 0x04, 0x02, 0x12, 0x03, 0x1f, 0x27, 0x28, 0x0a, 0x44, 0x0a, 0x04, 0x04, 0x02, + 0x03, 0x00, 0x12, 0x04, 0x23, 0x02, 0x25, 0x03, 0x1a, 0x36, 0x20, 0x43, 0x6f, 0x6d, 0x62, 0x69, + 0x6e, 0x65, 0x20, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x20, 0x70, 0x6f, 0x6c, 0x69, + 0x63, 0x69, 0x65, 0x73, 0x2e, 0x20, 0x41, 0x6c, 0x6c, 0x20, 0x6d, 0x75, 0x73, 0x74, 0x20, 0x65, + 0x76, 0x61, 0x6c, 0x75, 0x61, 0x74, 0x65, 0x20, 0x74, 0x6f, 0x20, 0x74, 0x72, 0x75, 0x65, 0x0a, + 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x03, 0x00, 0x01, 0x12, 0x03, 0x23, 0x0a, 0x16, 0x0a, 0x0d, + 0x0a, 0x06, 0x04, 0x02, 0x03, 0x00, 0x02, 0x00, 0x12, 0x03, 0x24, 0x04, 0x2b, 0x0a, 0x0e, 0x0a, + 0x07, 0x04, 0x02, 0x03, 0x00, 0x02, 0x00, 0x04, 0x12, 0x03, 0x24, 0x04, 0x0c, 0x0a, 0x0e, 0x0a, + 0x07, 0x04, 0x02, 0x03, 0x00, 0x02, 0x00, 0x06, 0x12, 0x03, 0x24, 0x0d, 0x1d, 0x0a, 0x0e, 0x0a, + 0x07, 0x04, 0x02, 0x03, 0x00, 0x02, 0x00, 0x01, 0x12, 0x03, 0x24, 0x1e, 0x26, 0x0a, 0x0e, 0x0a, + 0x07, 0x04, 0x02, 0x03, 0x00, 0x02, 0x00, 0x03, 0x12, 0x03, 0x24, 0x29, 0x2a, 0x0a, 0x44, 0x0a, + 0x04, 0x04, 0x02, 0x03, 0x01, 0x12, 0x04, 0x28, 0x02, 0x2a, 0x03, 0x1a, 0x36, 0x20, 0x43, 0x6f, + 0x6d, 0x62, 0x69, 0x6e, 0x65, 0x20, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x20, 0x70, + 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x2e, 0x20, 0x41, 0x6e, 0x79, 0x20, 0x6d, 0x75, 0x73, + 0x74, 0x20, 0x65, 0x76, 0x61, 0x6c, 0x75, 0x61, 0x74, 0x65, 0x20, 0x74, 0x6f, 0x20, 0x74, 0x72, + 0x75, 0x65, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x03, 0x01, 0x01, 0x12, 0x03, 0x28, 0x0a, + 0x16, 0x0a, 0x0d, 0x0a, 0x06, 0x04, 0x02, 0x03, 0x01, 0x02, 0x00, 0x12, 0x03, 0x29, 0x04, 0x2b, + 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, 0x01, 0x02, 0x00, 0x04, 0x12, 0x03, 0x29, 0x04, 0x0c, + 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, 0x01, 0x02, 0x00, 0x06, 0x12, 0x03, 0x29, 0x0d, 0x1d, + 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, 0x01, 0x02, 0x00, 0x01, 0x12, 0x03, 0x29, 0x1e, 0x26, + 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, 0x01, 0x02, 0x00, 0x03, 0x12, 0x03, 0x29, 0x29, 0x2a, + 0x0a, 0x0c, 0x0a, 0x04, 0x04, 0x02, 0x08, 0x00, 0x12, 0x04, 0x2c, 0x02, 0x30, 0x03, 0x0a, 0x0c, + 0x0a, 0x05, 0x04, 0x02, 0x08, 0x00, 0x01, 0x12, 0x03, 0x2c, 0x08, 0x0c, 0x0a, 0x0b, 0x0a, 0x04, + 0x04, 0x02, 0x02, 0x00, 0x12, 0x03, 0x2d, 0x04, 0x18, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, + 0x00, 0x06, 0x12, 0x03, 0x2d, 0x04, 0x0e, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x00, 0x01, + 0x12, 0x03, 0x2d, 0x0f, 0x13, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x00, 0x03, 0x12, 0x03, + 0x2d, 0x16, 0x17, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x02, 0x02, 0x01, 0x12, 0x03, 0x2e, 0x04, 0x23, + 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x01, 0x06, 0x12, 0x03, 0x2e, 0x04, 0x10, 0x0a, 0x0c, + 0x0a, 0x05, 0x04, 0x02, 0x02, 0x01, 0x01, 0x12, 0x03, 0x2e, 0x11, 0x1e, 0x0a, 0x0c, 0x0a, 0x05, + 0x04, 0x02, 0x02, 0x01, 0x03, 0x12, 0x03, 0x2e, 0x21, 0x22, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x02, + 0x02, 0x02, 0x12, 0x03, 0x2f, 0x04, 0x23, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x02, 0x06, + 0x12, 0x03, 0x2f, 0x04, 0x10, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x02, 0x01, 0x12, 0x03, + 0x2f, 0x11, 0x1e, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x02, 0x03, 0x12, 0x03, 0x2f, 0x21, + 0x22, 0x0a, 0x35, 0x0a, 0x02, 0x04, 0x03, 0x12, 0x04, 0x34, 0x00, 0x4d, 0x01, 0x1a, 0x29, 0x20, + 0x41, 0x20, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x67, 0x6f, + 0x76, 0x65, 0x72, 0x6e, 0x73, 0x20, 0x75, 0x70, 0x64, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x20, 0x6d, + 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x0a, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x03, 0x01, 0x12, + 0x03, 0x34, 0x08, 0x16, 0x0a, 0x1b, 0x0a, 0x04, 0x04, 0x03, 0x04, 0x00, 0x12, 0x04, 0x36, 0x02, + 0x3c, 0x03, 0x1a, 0x0d, 0x20, 0x42, 0x61, 0x73, 0x65, 0x20, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, + 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x04, 0x00, 0x01, 0x12, 0x03, 0x36, 0x07, 0x19, 0x0a, + 0x0d, 0x0a, 0x06, 0x04, 0x03, 0x04, 0x00, 0x02, 0x00, 0x12, 0x03, 0x37, 0x04, 0x29, 0x0a, 0x0e, + 0x0a, 0x07, 0x04, 0x03, 0x04, 0x00, 0x02, 0x00, 0x01, 0x12, 0x03, 0x37, 0x04, 0x24, 0x0a, 0x0e, + 0x0a, 0x07, 0x04, 0x03, 0x04, 0x00, 0x02, 0x00, 0x02, 0x12, 0x03, 0x37, 0x27, 0x28, 0x0a, 0x0d, + 0x0a, 0x06, 0x04, 0x03, 0x04, 0x00, 0x02, 0x01, 0x12, 0x03, 0x38, 0x04, 0x23, 0x0a, 0x0e, 0x0a, + 0x07, 0x04, 0x03, 0x04, 0x00, 0x02, 0x01, 0x01, 0x12, 0x03, 0x38, 0x04, 0x1e, 0x0a, 0x0e, 0x0a, + 0x07, 0x04, 0x03, 0x04, 0x00, 0x02, 0x01, 0x02, 0x12, 0x03, 0x38, 0x21, 0x22, 0x0a, 0x0d, 0x0a, + 0x06, 0x04, 0x03, 0x04, 0x00, 0x02, 0x02, 0x12, 0x03, 0x39, 0x04, 0x22, 0x0a, 0x0e, 0x0a, 0x07, + 0x04, 0x03, 0x04, 0x00, 0x02, 0x02, 0x01, 0x12, 0x03, 0x39, 0x04, 0x1d, 0x0a, 0x0e, 0x0a, 0x07, + 0x04, 0x03, 0x04, 0x00, 0x02, 0x02, 0x02, 0x12, 0x03, 0x39, 0x20, 0x21, 0x0a, 0x0d, 0x0a, 0x06, + 0x04, 0x03, 0x04, 0x00, 0x02, 0x03, 0x12, 0x03, 0x3a, 0x04, 0x2c, 0x0a, 0x0e, 0x0a, 0x07, 0x04, + 0x03, 0x04, 0x00, 0x02, 0x03, 0x01, 0x12, 0x03, 0x3a, 0x04, 0x27, 0x0a, 0x0e, 0x0a, 0x07, 0x04, + 0x03, 0x04, 0x00, 0x02, 0x03, 0x02, 0x12, 0x03, 0x3a, 0x2a, 0x2b, 0x0a, 0x0d, 0x0a, 0x06, 0x04, + 0x03, 0x04, 0x00, 0x02, 0x04, 0x12, 0x03, 0x3b, 0x04, 0x32, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x03, + 0x04, 0x00, 0x02, 0x04, 0x01, 0x12, 0x03, 0x3b, 0x04, 0x2d, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x03, + 0x04, 0x00, 0x02, 0x04, 0x02, 0x12, 0x03, 0x3b, 0x30, 0x31, 0x0a, 0x44, 0x0a, 0x04, 0x04, 0x03, + 0x03, 0x00, 0x12, 0x04, 0x3f, 0x02, 0x41, 0x03, 0x1a, 0x36, 0x20, 0x43, 0x6f, 0x6d, 0x62, 0x69, + 0x6e, 0x65, 0x20, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x20, 0x70, 0x6f, 0x6c, 0x69, + 0x63, 0x69, 0x65, 0x73, 0x2e, 0x20, 0x41, 0x6c, 0x6c, 0x20, 0x6d, 0x75, 0x73, 0x74, 0x20, 0x65, + 0x76, 0x61, 0x6c, 0x75, 0x61, 0x74, 0x65, 0x20, 0x74, 0x6f, 0x20, 0x74, 0x72, 0x75, 0x65, 0x0a, + 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x03, 0x00, 0x01, 0x12, 0x03, 0x3f, 0x0a, 0x16, 0x0a, 0x0d, + 0x0a, 0x06, 0x04, 0x03, 0x03, 0x00, 0x02, 0x00, 0x12, 0x03, 0x40, 0x04, 0x29, 0x0a, 0x0e, 0x0a, + 0x07, 0x04, 0x03, 0x03, 0x00, 0x02, 0x00, 0x04, 0x12, 0x03, 0x40, 0x04, 0x0c, 0x0a, 0x0e, 0x0a, + 0x07, 0x04, 0x03, 0x03, 0x00, 0x02, 0x00, 0x06, 0x12, 0x03, 0x40, 0x0d, 0x1b, 0x0a, 0x0e, 0x0a, + 0x07, 0x04, 0x03, 0x03, 0x00, 0x02, 0x00, 0x01, 0x12, 0x03, 0x40, 0x1c, 0x24, 0x0a, 0x0e, 0x0a, + 0x07, 0x04, 0x03, 0x03, 0x00, 0x02, 0x00, 0x03, 0x12, 0x03, 0x40, 0x27, 0x28, 0x0a, 0x44, 0x0a, + 0x04, 0x04, 0x03, 0x03, 0x01, 0x12, 0x04, 0x44, 0x02, 0x46, 0x03, 0x1a, 0x36, 0x20, 0x43, 0x6f, + 0x6d, 0x62, 0x69, 0x6e, 0x65, 0x20, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x20, 0x70, + 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x2e, 0x20, 0x41, 0x6e, 0x79, 0x20, 0x6d, 0x75, 0x73, + 0x74, 0x20, 0x65, 0x76, 0x61, 0x6c, 0x75, 0x61, 0x74, 0x65, 0x20, 0x74, 0x6f, 0x20, 0x74, 0x72, + 0x75, 0x65, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x03, 0x01, 0x01, 0x12, 0x03, 0x44, 0x0a, + 0x16, 0x0a, 0x0d, 0x0a, 0x06, 0x04, 0x03, 0x03, 0x01, 0x02, 0x00, 0x12, 0x03, 0x45, 0x04, 0x29, + 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x03, 0x03, 0x01, 0x02, 0x00, 0x04, 0x12, 0x03, 0x45, 0x04, 0x0c, + 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x03, 0x03, 0x01, 0x02, 0x00, 0x06, 0x12, 0x03, 0x45, 0x0d, 0x1b, + 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x03, 0x03, 0x01, 0x02, 0x00, 0x01, 0x12, 0x03, 0x45, 0x1c, 0x24, + 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x03, 0x03, 0x01, 0x02, 0x00, 0x03, 0x12, 0x03, 0x45, 0x27, 0x28, + 0x0a, 0x0c, 0x0a, 0x04, 0x04, 0x03, 0x08, 0x00, 0x12, 0x04, 0x48, 0x02, 0x4c, 0x03, 0x0a, 0x0c, + 0x0a, 0x05, 0x04, 0x03, 0x08, 0x00, 0x01, 0x12, 0x03, 0x48, 0x08, 0x0c, 0x0a, 0x0b, 0x0a, 0x04, + 0x04, 0x03, 0x02, 0x00, 0x12, 0x03, 0x49, 0x04, 0x20, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, + 0x00, 0x06, 0x12, 0x03, 0x49, 0x04, 0x16, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, 0x00, 0x01, + 0x12, 0x03, 0x49, 0x17, 0x1b, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, 0x00, 0x03, 0x12, 0x03, + 0x49, 0x1e, 0x1f, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x03, 0x02, 0x01, 0x12, 0x03, 0x4a, 0x04, 0x23, + 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, 0x01, 0x06, 0x12, 0x03, 0x4a, 0x04, 0x10, 0x0a, 0x0c, + 0x0a, 0x05, 0x04, 0x03, 0x02, 0x01, 0x01, 0x12, 0x03, 0x4a, 0x11, 0x1e, 0x0a, 0x0c, 0x0a, 0x05, + 0x04, 0x03, 0x02, 0x01, 0x03, 0x12, 0x03, 0x4a, 0x21, 0x22, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x03, + 0x02, 0x02, 0x12, 0x03, 0x4b, 0x04, 0x23, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, 0x02, 0x06, + 0x12, 0x03, 0x4b, 0x04, 0x10, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, 0x02, 0x01, 0x12, 0x03, + 0x4b, 0x11, 0x1e, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, 0x02, 0x03, 0x12, 0x03, 0x4b, 0x21, + 0x22, 0x0a, 0x38, 0x0a, 0x02, 0x04, 0x04, 0x12, 0x04, 0x50, 0x00, 0x68, 0x01, 0x1a, 0x2c, 0x20, + 0x41, 0x20, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x67, 0x6f, + 0x76, 0x65, 0x72, 0x6e, 0x73, 0x20, 0x75, 0x70, 0x64, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x20, 0x70, + 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x0a, 0x0a, 0x0a, 0x0a, 0x03, 0x04, + 0x04, 0x01, 0x12, 0x03, 0x50, 0x08, 0x1f, 0x0a, 0x1b, 0x0a, 0x04, 0x04, 0x04, 0x04, 0x00, 0x12, + 0x04, 0x52, 0x02, 0x57, 0x03, 0x1a, 0x0d, 0x20, 0x42, 0x61, 0x73, 0x65, 0x20, 0x70, 0x6f, 0x6c, + 0x69, 0x63, 0x79, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x04, 0x00, 0x01, 0x12, 0x03, 0x52, + 0x07, 0x1c, 0x0a, 0x0d, 0x0a, 0x06, 0x04, 0x04, 0x04, 0x00, 0x02, 0x00, 0x12, 0x03, 0x53, 0x04, + 0x2c, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x04, 0x04, 0x00, 0x02, 0x00, 0x01, 0x12, 0x03, 0x53, 0x04, + 0x27, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x04, 0x04, 0x00, 0x02, 0x00, 0x02, 0x12, 0x03, 0x53, 0x2a, + 0x2b, 0x0a, 0x0d, 0x0a, 0x06, 0x04, 0x04, 0x04, 0x00, 0x02, 0x01, 0x12, 0x03, 0x54, 0x04, 0x25, + 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x04, 0x04, 0x00, 0x02, 0x01, 0x01, 0x12, 0x03, 0x54, 0x04, 0x20, + 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x04, 0x04, 0x00, 0x02, 0x01, 0x02, 0x12, 0x03, 0x54, 0x23, 0x24, + 0x0a, 0x0d, 0x0a, 0x06, 0x04, 0x04, 0x04, 0x00, 0x02, 0x02, 0x12, 0x03, 0x55, 0x04, 0x2f, 0x0a, + 0x0e, 0x0a, 0x07, 0x04, 0x04, 0x04, 0x00, 0x02, 0x02, 0x01, 0x12, 0x03, 0x55, 0x04, 0x2a, 0x0a, + 0x0e, 0x0a, 0x07, 0x04, 0x04, 0x04, 0x00, 0x02, 0x02, 0x02, 0x12, 0x03, 0x55, 0x2d, 0x2e, 0x0a, + 0x0d, 0x0a, 0x06, 0x04, 0x04, 0x04, 0x00, 0x02, 0x03, 0x12, 0x03, 0x56, 0x04, 0x35, 0x0a, 0x0e, + 0x0a, 0x07, 0x04, 0x04, 0x04, 0x00, 0x02, 0x03, 0x01, 0x12, 0x03, 0x56, 0x04, 0x30, 0x0a, 0x0e, + 0x0a, 0x07, 0x04, 0x04, 0x04, 0x00, 0x02, 0x03, 0x02, 0x12, 0x03, 0x56, 0x33, 0x34, 0x0a, 0x44, + 0x0a, 0x04, 0x04, 0x04, 0x03, 0x00, 0x12, 0x04, 0x5a, 0x02, 0x5c, 0x03, 0x1a, 0x36, 0x20, 0x43, + 0x6f, 0x6d, 0x62, 0x69, 0x6e, 0x65, 0x20, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x20, + 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x2e, 0x20, 0x41, 0x6c, 0x6c, 0x20, 0x6d, 0x75, + 0x73, 0x74, 0x20, 0x65, 0x76, 0x61, 0x6c, 0x75, 0x61, 0x74, 0x65, 0x20, 0x74, 0x6f, 0x20, 0x74, + 0x72, 0x75, 0x65, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x03, 0x00, 0x01, 0x12, 0x03, 0x5a, + 0x0a, 0x16, 0x0a, 0x0d, 0x0a, 0x06, 0x04, 0x04, 0x03, 0x00, 0x02, 0x00, 0x12, 0x03, 0x5b, 0x04, + 0x32, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x04, 0x03, 0x00, 0x02, 0x00, 0x04, 0x12, 0x03, 0x5b, 0x04, + 0x0c, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x04, 0x03, 0x00, 0x02, 0x00, 0x06, 0x12, 0x03, 0x5b, 0x0d, + 0x24, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x04, 0x03, 0x00, 0x02, 0x00, 0x01, 0x12, 0x03, 0x5b, 0x25, + 0x2d, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x04, 0x03, 0x00, 0x02, 0x00, 0x03, 0x12, 0x03, 0x5b, 0x30, + 0x31, 0x0a, 0x44, 0x0a, 0x04, 0x04, 0x04, 0x03, 0x01, 0x12, 0x04, 0x5f, 0x02, 0x61, 0x03, 0x1a, + 0x36, 0x20, 0x43, 0x6f, 0x6d, 0x62, 0x69, 0x6e, 0x65, 0x20, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, + 0x6c, 0x65, 0x20, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x2e, 0x20, 0x41, 0x6e, 0x79, + 0x20, 0x6d, 0x75, 0x73, 0x74, 0x20, 0x65, 0x76, 0x61, 0x6c, 0x75, 0x61, 0x74, 0x65, 0x20, 0x74, + 0x6f, 0x20, 0x74, 0x72, 0x75, 0x65, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x03, 0x01, 0x01, + 0x12, 0x03, 0x5f, 0x0a, 0x16, 0x0a, 0x0d, 0x0a, 0x06, 0x04, 0x04, 0x03, 0x01, 0x02, 0x00, 0x12, + 0x03, 0x60, 0x04, 0x32, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x04, 0x03, 0x01, 0x02, 0x00, 0x04, 0x12, + 0x03, 0x60, 0x04, 0x0c, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x04, 0x03, 0x01, 0x02, 0x00, 0x06, 0x12, + 0x03, 0x60, 0x0d, 0x24, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x04, 0x03, 0x01, 0x02, 0x00, 0x01, 0x12, + 0x03, 0x60, 0x25, 0x2d, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x04, 0x03, 0x01, 0x02, 0x00, 0x03, 0x12, + 0x03, 0x60, 0x30, 0x31, 0x0a, 0x0c, 0x0a, 0x04, 0x04, 0x04, 0x08, 0x00, 0x12, 0x04, 0x63, 0x02, + 0x67, 0x03, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x08, 0x00, 0x01, 0x12, 0x03, 0x63, 0x08, 0x0c, + 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x04, 0x02, 0x00, 0x12, 0x03, 0x64, 0x04, 0x23, 0x0a, 0x0c, 0x0a, + 0x05, 0x04, 0x04, 0x02, 0x00, 0x06, 0x12, 0x03, 0x64, 0x04, 0x19, 0x0a, 0x0c, 0x0a, 0x05, 0x04, + 0x04, 0x02, 0x00, 0x01, 0x12, 0x03, 0x64, 0x1a, 0x1e, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x02, + 0x00, 0x03, 0x12, 0x03, 0x64, 0x21, 0x22, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x04, 0x02, 0x01, 0x12, + 0x03, 0x65, 0x04, 0x23, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x02, 0x01, 0x06, 0x12, 0x03, 0x65, + 0x04, 0x10, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x02, 0x01, 0x01, 0x12, 0x03, 0x65, 0x11, 0x1e, + 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x02, 0x01, 0x03, 0x12, 0x03, 0x65, 0x21, 0x22, 0x0a, 0x0b, + 0x0a, 0x04, 0x04, 0x04, 0x02, 0x02, 0x12, 0x03, 0x66, 0x04, 0x23, 0x0a, 0x0c, 0x0a, 0x05, 0x04, + 0x04, 0x02, 0x02, 0x06, 0x12, 0x03, 0x66, 0x04, 0x10, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x02, + 0x02, 0x01, 0x12, 0x03, 0x66, 0x11, 0x1e, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x02, 0x02, 0x03, + 0x12, 0x03, 0x66, 0x21, 0x22, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, 0x0a, 0xb8, 0x1a, + 0x0a, 0x2e, 0x6d, 0x6c, 0x73, 0x2f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, + 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x63, 0x72, 0x69, 0x70, + 0x74, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x12, 0x19, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x22, 0xa7, 0x01, 0x0a, 0x10, + 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, + 0x12, 0x29, 0x0a, 0x10, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x5f, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x0f, 0x69, 0x6e, 0x73, 0x74, + 0x61, 0x6c, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x73, 0x12, 0x27, 0x0a, 0x0f, 0x61, + 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x41, 0x64, 0x64, + 0x72, 0x65, 0x73, 0x73, 0x12, 0x3f, 0x0a, 0x1c, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x74, 0x65, + 0x64, 0x5f, 0x62, 0x79, 0x5f, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x61, 0x64, 0x64, + 0x72, 0x65, 0x73, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x19, 0x69, 0x6e, 0x69, 0x74, + 0x69, 0x61, 0x74, 0x65, 0x64, 0x42, 0x79, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x41, 0x64, + 0x64, 0x72, 0x65, 0x73, 0x73, 0x22, 0x80, 0x03, 0x0a, 0x16, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x4d, + 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x73, + 0x12, 0x50, 0x0a, 0x0d, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x5f, 0x61, 0x64, 0x64, 0x65, + 0x64, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, + 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, + 0x6e, 0x74, 0x73, 0x2e, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x43, 0x68, + 0x61, 0x6e, 0x67, 0x65, 0x52, 0x0c, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x41, 0x64, 0x64, + 0x65, 0x64, 0x12, 0x54, 0x0a, 0x0f, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x5f, 0x72, 0x65, + 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, - 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x49, 0x6e, 0x62, 0x6f, 0x78, 0x52, 0x0b, 0x64, - 0x6d, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x4f, 0x6e, 0x65, 0x12, 0x44, 0x0a, 0x0d, 0x64, 0x6d, - 0x5f, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x5f, 0x74, 0x77, 0x6f, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x20, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x49, 0x6e, - 0x62, 0x6f, 0x78, 0x52, 0x0b, 0x64, 0x6d, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x54, 0x77, 0x6f, - 0x2a, 0x88, 0x01, 0x0a, 0x10, 0x43, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x54, 0x79, 0x70, 0x65, 0x12, 0x21, 0x0a, 0x1d, 0x43, 0x4f, 0x4e, 0x56, 0x45, 0x52, 0x53, - 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, - 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x1b, 0x0a, 0x17, 0x43, 0x4f, 0x4e, 0x56, - 0x45, 0x52, 0x53, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x47, 0x52, - 0x4f, 0x55, 0x50, 0x10, 0x01, 0x12, 0x18, 0x0a, 0x14, 0x43, 0x4f, 0x4e, 0x56, 0x45, 0x52, 0x53, - 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x44, 0x4d, 0x10, 0x02, 0x12, - 0x1a, 0x0a, 0x16, 0x43, 0x4f, 0x4e, 0x56, 0x45, 0x52, 0x53, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, - 0x54, 0x59, 0x50, 0x45, 0x5f, 0x53, 0x59, 0x4e, 0x43, 0x10, 0x03, 0x42, 0xe7, 0x01, 0x0a, 0x1d, - 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x42, 0x12, 0x47, - 0x72, 0x6f, 0x75, 0x70, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x50, 0x72, 0x6f, 0x74, + 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, + 0x69, 0x70, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x0e, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, + 0x73, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x12, 0x5c, 0x0a, 0x13, 0x69, 0x6e, 0x73, 0x74, + 0x61, 0x6c, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x5f, 0x61, 0x64, 0x64, 0x65, 0x64, 0x18, + 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, + 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, + 0x73, 0x2e, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x43, 0x68, 0x61, 0x6e, + 0x67, 0x65, 0x52, 0x12, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x73, 0x41, 0x64, 0x64, 0x65, 0x64, 0x12, 0x60, 0x0a, 0x15, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, + 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x5f, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x18, + 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, + 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, + 0x73, 0x2e, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x43, 0x68, 0x61, 0x6e, + 0x67, 0x65, 0x52, 0x14, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x73, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x22, 0x9b, 0x04, 0x0a, 0x0c, 0x47, 0x72, 0x6f, + 0x75, 0x70, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x12, 0x31, 0x0a, 0x15, 0x69, 0x6e, 0x69, + 0x74, 0x69, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x62, 0x79, 0x5f, 0x69, 0x6e, 0x62, 0x6f, 0x78, 0x5f, + 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x12, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x61, + 0x74, 0x65, 0x64, 0x42, 0x79, 0x49, 0x6e, 0x62, 0x6f, 0x78, 0x49, 0x64, 0x12, 0x52, 0x0a, 0x0d, + 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x69, 0x6e, 0x62, 0x6f, 0x78, 0x65, 0x73, 0x18, 0x02, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, + 0x47, 0x72, 0x6f, 0x75, 0x70, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x2e, 0x49, 0x6e, 0x62, + 0x6f, 0x78, 0x52, 0x0c, 0x61, 0x64, 0x64, 0x65, 0x64, 0x49, 0x6e, 0x62, 0x6f, 0x78, 0x65, 0x73, + 0x12, 0x56, 0x0a, 0x0f, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x5f, 0x69, 0x6e, 0x62, 0x6f, + 0x78, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x78, 0x6d, 0x74, 0x70, + 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, + 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x55, 0x70, 0x64, 0x61, 0x74, + 0x65, 0x64, 0x2e, 0x49, 0x6e, 0x62, 0x6f, 0x78, 0x52, 0x0e, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, + 0x64, 0x49, 0x6e, 0x62, 0x6f, 0x78, 0x65, 0x73, 0x12, 0x71, 0x0a, 0x16, 0x6d, 0x65, 0x74, 0x61, + 0x64, 0x61, 0x74, 0x61, 0x5f, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x67, + 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x3b, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, + 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, + 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, + 0x64, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x43, + 0x68, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x14, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x46, + 0x69, 0x65, 0x6c, 0x64, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x1a, 0x22, 0x0a, 0x05, 0x49, + 0x6e, 0x62, 0x6f, 0x78, 0x12, 0x19, 0x0a, 0x08, 0x69, 0x6e, 0x62, 0x6f, 0x78, 0x5f, 0x69, 0x64, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x69, 0x6e, 0x62, 0x6f, 0x78, 0x49, 0x64, 0x1a, + 0x94, 0x01, 0x0a, 0x13, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x46, 0x69, 0x65, 0x6c, + 0x64, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x66, 0x69, 0x65, 0x6c, 0x64, + 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x66, 0x69, 0x65, + 0x6c, 0x64, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x09, 0x6f, 0x6c, 0x64, 0x5f, 0x76, 0x61, + 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x08, 0x6f, 0x6c, 0x64, + 0x56, 0x61, 0x6c, 0x75, 0x65, 0x88, 0x01, 0x01, 0x12, 0x20, 0x0a, 0x09, 0x6e, 0x65, 0x77, 0x5f, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x48, 0x01, 0x52, 0x08, 0x6e, + 0x65, 0x77, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x88, 0x01, 0x01, 0x42, 0x0c, 0x0a, 0x0a, 0x5f, 0x6f, + 0x6c, 0x64, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x42, 0x0c, 0x0a, 0x0a, 0x5f, 0x6e, 0x65, 0x77, + 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x42, 0xec, 0x01, 0x0a, 0x1d, 0x63, 0x6f, 0x6d, 0x2e, 0x78, + 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, + 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x42, 0x17, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x63, + 0x72, 0x69, 0x70, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x30, 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, 0x6d, 0x6c, 0x73, 0x2f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, @@ -1143,760 +1773,130 @@ pub const FILE_DESCRIPTOR_SET: &[u8] = &[ 0x73, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x1a, 0x58, 0x6d, 0x74, 0x70, 0x3a, 0x3a, 0x4d, 0x6c, 0x73, 0x3a, 0x3a, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, - 0x74, 0x65, 0x6e, 0x74, 0x73, 0x4a, 0xb8, 0x07, 0x0a, 0x06, 0x12, 0x04, 0x01, 0x00, 0x23, 0x01, - 0x0a, 0x24, 0x0a, 0x01, 0x0c, 0x12, 0x03, 0x01, 0x00, 0x12, 0x1a, 0x1a, 0x20, 0x47, 0x72, 0x6f, - 0x75, 0x70, 0x20, 0x69, 0x6d, 0x6d, 0x75, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x6d, 0x65, 0x74, - 0x61, 0x64, 0x61, 0x74, 0x61, 0x0a, 0x0a, 0x08, 0x0a, 0x01, 0x02, 0x12, 0x03, 0x03, 0x00, 0x22, - 0x0a, 0x08, 0x0a, 0x01, 0x08, 0x12, 0x03, 0x05, 0x00, 0x47, 0x0a, 0x09, 0x0a, 0x02, 0x08, 0x0b, - 0x12, 0x03, 0x05, 0x00, 0x47, 0x0a, 0x2f, 0x0a, 0x02, 0x04, 0x00, 0x12, 0x04, 0x09, 0x00, 0x10, - 0x01, 0x1a, 0x23, 0x20, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x20, 0x6d, 0x65, 0x74, - 0x61, 0x64, 0x61, 0x74, 0x61, 0x0a, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x00, 0x01, 0x12, 0x03, 0x09, - 0x08, 0x17, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x00, 0x02, 0x00, 0x12, 0x03, 0x0a, 0x02, 0x29, 0x0a, - 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x00, 0x06, 0x12, 0x03, 0x0a, 0x02, 0x12, 0x0a, 0x0c, 0x0a, - 0x05, 0x04, 0x00, 0x02, 0x00, 0x01, 0x12, 0x03, 0x0a, 0x13, 0x24, 0x0a, 0x0c, 0x0a, 0x05, 0x04, - 0x00, 0x02, 0x00, 0x03, 0x12, 0x03, 0x0a, 0x27, 0x28, 0x0a, 0x28, 0x0a, 0x04, 0x04, 0x00, 0x02, - 0x01, 0x12, 0x03, 0x0c, 0x02, 0x25, 0x1a, 0x1b, 0x20, 0x54, 0x68, 0x69, 0x73, 0x20, 0x77, 0x69, - 0x6c, 0x6c, 0x20, 0x62, 0x65, 0x20, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x20, 0x73, 0x6f, - 0x6f, 0x6e, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x01, 0x05, 0x12, 0x03, 0x0c, 0x02, - 0x08, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x01, 0x01, 0x12, 0x03, 0x0c, 0x09, 0x20, 0x0a, - 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x01, 0x03, 0x12, 0x03, 0x0c, 0x23, 0x24, 0x0a, 0x0b, 0x0a, - 0x04, 0x04, 0x00, 0x02, 0x02, 0x12, 0x03, 0x0d, 0x02, 0x1e, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, - 0x02, 0x02, 0x05, 0x12, 0x03, 0x0d, 0x02, 0x08, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x02, - 0x01, 0x12, 0x03, 0x0d, 0x09, 0x19, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x02, 0x03, 0x12, - 0x03, 0x0d, 0x1c, 0x1d, 0x0a, 0x3e, 0x0a, 0x04, 0x04, 0x00, 0x02, 0x03, 0x12, 0x03, 0x0f, 0x02, - 0x24, 0x1a, 0x31, 0x20, 0x53, 0x68, 0x6f, 0x75, 0x6c, 0x64, 0x20, 0x6f, 0x6e, 0x6c, 0x79, 0x20, - 0x62, 0x65, 0x20, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x43, - 0x4f, 0x4e, 0x56, 0x45, 0x52, 0x53, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x54, 0x59, 0x50, 0x45, - 0x5f, 0x44, 0x4d, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x03, 0x04, 0x12, 0x03, 0x0f, - 0x02, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x03, 0x06, 0x12, 0x03, 0x0f, 0x0b, 0x14, - 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x03, 0x01, 0x12, 0x03, 0x0f, 0x15, 0x1f, 0x0a, 0x0c, - 0x0a, 0x05, 0x04, 0x00, 0x02, 0x03, 0x03, 0x12, 0x03, 0x0f, 0x22, 0x23, 0x0a, 0x2e, 0x0a, 0x02, - 0x05, 0x00, 0x12, 0x04, 0x13, 0x00, 0x18, 0x01, 0x1a, 0x22, 0x20, 0x44, 0x65, 0x66, 0x69, 0x6e, - 0x65, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x79, 0x70, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x63, - 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x0a, 0x0a, 0x0a, 0x0a, 0x03, - 0x05, 0x00, 0x01, 0x12, 0x03, 0x13, 0x05, 0x15, 0x0a, 0x0b, 0x0a, 0x04, 0x05, 0x00, 0x02, 0x00, - 0x12, 0x03, 0x14, 0x02, 0x24, 0x0a, 0x0c, 0x0a, 0x05, 0x05, 0x00, 0x02, 0x00, 0x01, 0x12, 0x03, - 0x14, 0x02, 0x1f, 0x0a, 0x0c, 0x0a, 0x05, 0x05, 0x00, 0x02, 0x00, 0x02, 0x12, 0x03, 0x14, 0x22, - 0x23, 0x0a, 0x0b, 0x0a, 0x04, 0x05, 0x00, 0x02, 0x01, 0x12, 0x03, 0x15, 0x02, 0x1e, 0x0a, 0x0c, - 0x0a, 0x05, 0x05, 0x00, 0x02, 0x01, 0x01, 0x12, 0x03, 0x15, 0x02, 0x19, 0x0a, 0x0c, 0x0a, 0x05, - 0x05, 0x00, 0x02, 0x01, 0x02, 0x12, 0x03, 0x15, 0x1c, 0x1d, 0x0a, 0x0b, 0x0a, 0x04, 0x05, 0x00, - 0x02, 0x02, 0x12, 0x03, 0x16, 0x02, 0x1b, 0x0a, 0x0c, 0x0a, 0x05, 0x05, 0x00, 0x02, 0x02, 0x01, - 0x12, 0x03, 0x16, 0x02, 0x16, 0x0a, 0x0c, 0x0a, 0x05, 0x05, 0x00, 0x02, 0x02, 0x02, 0x12, 0x03, - 0x16, 0x19, 0x1a, 0x0a, 0x0b, 0x0a, 0x04, 0x05, 0x00, 0x02, 0x03, 0x12, 0x03, 0x17, 0x02, 0x1d, - 0x0a, 0x0c, 0x0a, 0x05, 0x05, 0x00, 0x02, 0x03, 0x01, 0x12, 0x03, 0x17, 0x02, 0x18, 0x0a, 0x0c, - 0x0a, 0x05, 0x05, 0x00, 0x02, 0x03, 0x02, 0x12, 0x03, 0x17, 0x1b, 0x1c, 0x0a, 0x28, 0x0a, 0x02, - 0x04, 0x01, 0x12, 0x04, 0x1b, 0x00, 0x1d, 0x01, 0x1a, 0x1c, 0x20, 0x57, 0x72, 0x61, 0x70, 0x70, - 0x65, 0x72, 0x20, 0x61, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x20, 0x61, 0x6e, 0x20, 0x49, 0x6e, 0x62, - 0x6f, 0x78, 0x20, 0x49, 0x64, 0x0a, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x01, 0x01, 0x12, 0x03, 0x1b, - 0x08, 0x0d, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x01, 0x02, 0x00, 0x12, 0x03, 0x1c, 0x02, 0x16, 0x0a, - 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x00, 0x05, 0x12, 0x03, 0x1c, 0x02, 0x08, 0x0a, 0x0c, 0x0a, - 0x05, 0x04, 0x01, 0x02, 0x00, 0x01, 0x12, 0x03, 0x1c, 0x09, 0x11, 0x0a, 0x0c, 0x0a, 0x05, 0x04, - 0x01, 0x02, 0x00, 0x03, 0x12, 0x03, 0x1c, 0x14, 0x15, 0x0a, 0x2b, 0x0a, 0x02, 0x04, 0x02, 0x12, - 0x04, 0x20, 0x00, 0x23, 0x01, 0x1a, 0x1f, 0x20, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x69, 0x6e, 0x67, - 0x20, 0x64, 0x6f, 0x65, 0x73, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x6d, 0x61, 0x74, 0x74, 0x65, 0x72, - 0x20, 0x68, 0x65, 0x72, 0x65, 0x0a, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x02, 0x01, 0x12, 0x03, 0x20, - 0x08, 0x11, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x02, 0x02, 0x00, 0x12, 0x03, 0x21, 0x02, 0x1a, 0x0a, - 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x00, 0x06, 0x12, 0x03, 0x21, 0x02, 0x07, 0x0a, 0x0c, 0x0a, - 0x05, 0x04, 0x02, 0x02, 0x00, 0x01, 0x12, 0x03, 0x21, 0x08, 0x15, 0x0a, 0x0c, 0x0a, 0x05, 0x04, - 0x02, 0x02, 0x00, 0x03, 0x12, 0x03, 0x21, 0x18, 0x19, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x02, 0x02, - 0x01, 0x12, 0x03, 0x22, 0x02, 0x1a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x01, 0x06, 0x12, - 0x03, 0x22, 0x02, 0x07, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x01, 0x01, 0x12, 0x03, 0x22, - 0x08, 0x15, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x01, 0x03, 0x12, 0x03, 0x22, 0x18, 0x19, - 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, 0x0a, 0x92, 0x0a, 0x0a, 0x31, 0x6d, 0x6c, 0x73, - 0x2f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, - 0x73, 0x2f, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x5f, 0x6d, 0x75, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5f, - 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x19, - 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x22, 0xcb, 0x02, 0x0a, 0x16, 0x47, 0x72, - 0x6f, 0x75, 0x70, 0x4d, 0x75, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, - 0x74, 0x61, 0x56, 0x31, 0x12, 0x61, 0x0a, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, - 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x41, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, - 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, - 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x4d, 0x75, 0x74, 0x61, 0x62, 0x6c, - 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x56, 0x31, 0x2e, 0x41, 0x74, 0x74, 0x72, - 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0a, 0x61, 0x74, 0x74, - 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x12, 0x41, 0x0a, 0x0a, 0x61, 0x64, 0x6d, 0x69, 0x6e, - 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x78, 0x6d, - 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, - 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x49, 0x6e, 0x62, 0x6f, 0x78, 0x65, 0x73, 0x52, - 0x09, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x4c, 0x0a, 0x10, 0x73, 0x75, - 0x70, 0x65, 0x72, 0x5f, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, - 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, - 0x2e, 0x49, 0x6e, 0x62, 0x6f, 0x78, 0x65, 0x73, 0x52, 0x0e, 0x73, 0x75, 0x70, 0x65, 0x72, 0x41, - 0x64, 0x6d, 0x69, 0x6e, 0x4c, 0x69, 0x73, 0x74, 0x1a, 0x3d, 0x0a, 0x0f, 0x41, 0x74, 0x74, 0x72, - 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, - 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, - 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, - 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x26, 0x0a, 0x07, 0x49, 0x6e, 0x62, 0x6f, 0x78, - 0x65, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x69, 0x6e, 0x62, 0x6f, 0x78, 0x5f, 0x69, 0x64, 0x73, 0x18, - 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x69, 0x6e, 0x62, 0x6f, 0x78, 0x49, 0x64, 0x73, 0x42, - 0xee, 0x01, 0x0a, 0x1d, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, - 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, - 0x73, 0x42, 0x19, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x4d, 0x75, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x4d, - 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x30, - 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, 0x6d, 0x6c, 0x73, 0x2f, - 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, - 0xa2, 0x02, 0x03, 0x58, 0x4d, 0x4d, 0xaa, 0x02, 0x18, 0x58, 0x6d, 0x74, 0x70, 0x2e, 0x4d, 0x6c, - 0x73, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, - 0x73, 0xca, 0x02, 0x18, 0x58, 0x6d, 0x74, 0x70, 0x5c, 0x4d, 0x6c, 0x73, 0x5c, 0x4d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0xe2, 0x02, 0x24, 0x58, - 0x6d, 0x74, 0x70, 0x5c, 0x4d, 0x6c, 0x73, 0x5c, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x43, - 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, - 0x61, 0x74, 0x61, 0xea, 0x02, 0x1a, 0x58, 0x6d, 0x74, 0x70, 0x3a, 0x3a, 0x4d, 0x6c, 0x73, 0x3a, - 0x3a, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, - 0x4a, 0xd2, 0x04, 0x0a, 0x06, 0x12, 0x04, 0x01, 0x00, 0x16, 0x01, 0x0a, 0x22, 0x0a, 0x01, 0x0c, - 0x12, 0x03, 0x01, 0x00, 0x12, 0x1a, 0x18, 0x20, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x20, 0x6d, 0x75, - 0x74, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x0a, 0x0a, - 0x08, 0x0a, 0x01, 0x02, 0x12, 0x03, 0x03, 0x00, 0x22, 0x0a, 0x08, 0x0a, 0x01, 0x08, 0x12, 0x03, - 0x05, 0x00, 0x47, 0x0a, 0x09, 0x0a, 0x02, 0x08, 0x0b, 0x12, 0x03, 0x05, 0x00, 0x47, 0x0a, 0x30, - 0x0a, 0x02, 0x04, 0x00, 0x12, 0x04, 0x0a, 0x00, 0x11, 0x01, 0x1a, 0x24, 0x20, 0x4d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x20, 0x6d, - 0x75, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x0a, - 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x00, 0x01, 0x12, 0x03, 0x0a, 0x08, 0x1e, 0x0a, 0x4a, 0x0a, 0x04, - 0x04, 0x00, 0x02, 0x00, 0x12, 0x03, 0x0c, 0x02, 0x25, 0x1a, 0x3d, 0x20, 0x4d, 0x61, 0x70, 0x20, - 0x74, 0x6f, 0x20, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x20, 0x76, 0x61, 0x72, 0x69, 0x6f, 0x75, 0x73, - 0x20, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x20, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, - 0x75, 0x74, 0x65, 0x73, 0x20, 0x28, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x20, 0x6e, 0x61, 0x6d, 0x65, - 0x2c, 0x20, 0x65, 0x74, 0x63, 0x2e, 0x29, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x00, - 0x06, 0x12, 0x03, 0x0c, 0x02, 0x15, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x00, 0x01, 0x12, - 0x03, 0x0c, 0x16, 0x20, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x00, 0x03, 0x12, 0x03, 0x0c, - 0x23, 0x24, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x00, 0x02, 0x01, 0x12, 0x03, 0x0d, 0x02, 0x19, 0x0a, - 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x01, 0x06, 0x12, 0x03, 0x0d, 0x02, 0x09, 0x0a, 0x0c, 0x0a, - 0x05, 0x04, 0x00, 0x02, 0x01, 0x01, 0x12, 0x03, 0x0d, 0x0a, 0x14, 0x0a, 0x0c, 0x0a, 0x05, 0x04, - 0x00, 0x02, 0x01, 0x03, 0x12, 0x03, 0x0d, 0x17, 0x18, 0x0a, 0x64, 0x0a, 0x04, 0x04, 0x00, 0x02, - 0x02, 0x12, 0x03, 0x10, 0x02, 0x1f, 0x1a, 0x57, 0x20, 0x43, 0x72, 0x65, 0x61, 0x74, 0x6f, 0x72, - 0x20, 0x73, 0x74, 0x61, 0x72, 0x74, 0x73, 0x20, 0x61, 0x73, 0x20, 0x6f, 0x6e, 0x6c, 0x79, 0x20, - 0x73, 0x75, 0x70, 0x65, 0x72, 0x5f, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x0a, 0x20, 0x4f, 0x6e, 0x6c, - 0x79, 0x20, 0x73, 0x75, 0x70, 0x65, 0x72, 0x5f, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x20, 0x63, 0x61, - 0x6e, 0x20, 0x61, 0x64, 0x64, 0x2f, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x20, 0x6f, 0x74, 0x68, - 0x65, 0x72, 0x20, 0x73, 0x75, 0x70, 0x65, 0x72, 0x5f, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x0a, 0x0a, - 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x02, 0x06, 0x12, 0x03, 0x10, 0x02, 0x09, 0x0a, 0x0c, 0x0a, - 0x05, 0x04, 0x00, 0x02, 0x02, 0x01, 0x12, 0x03, 0x10, 0x0a, 0x1a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, - 0x00, 0x02, 0x02, 0x03, 0x12, 0x03, 0x10, 0x1d, 0x1e, 0x0a, 0x39, 0x0a, 0x02, 0x04, 0x01, 0x12, - 0x04, 0x14, 0x00, 0x16, 0x01, 0x1a, 0x2d, 0x20, 0x57, 0x72, 0x61, 0x70, 0x70, 0x65, 0x72, 0x20, - 0x61, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x20, 0x61, 0x20, 0x6c, 0x69, 0x73, 0x74, 0x20, 0x6f, 0x66, - 0x20, 0x72, 0x65, 0x70, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x49, 0x6e, 0x62, 0x6f, 0x78, 0x20, - 0x49, 0x64, 0x73, 0x0a, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x01, 0x01, 0x12, 0x03, 0x14, 0x08, 0x0f, - 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x01, 0x02, 0x00, 0x12, 0x03, 0x15, 0x02, 0x20, 0x0a, 0x0c, 0x0a, - 0x05, 0x04, 0x01, 0x02, 0x00, 0x04, 0x12, 0x03, 0x15, 0x02, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, - 0x01, 0x02, 0x00, 0x05, 0x12, 0x03, 0x15, 0x0b, 0x11, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, - 0x00, 0x01, 0x12, 0x03, 0x15, 0x12, 0x1b, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x00, 0x03, - 0x12, 0x03, 0x15, 0x1e, 0x1f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, 0x0a, 0xfb, 0x31, - 0x0a, 0x2c, 0x6d, 0x6c, 0x73, 0x2f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, - 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2f, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x5f, 0x70, 0x65, 0x72, - 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x19, - 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x22, 0x5d, 0x0a, 0x19, 0x47, 0x72, 0x6f, - 0x75, 0x70, 0x4d, 0x75, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, - 0x69, 0x6f, 0x6e, 0x73, 0x56, 0x31, 0x12, 0x40, 0x0a, 0x08, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x69, - 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, - 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, - 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x53, 0x65, 0x74, 0x52, 0x08, - 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x22, 0xdf, 0x05, 0x0a, 0x09, 0x50, 0x6f, 0x6c, - 0x69, 0x63, 0x79, 0x53, 0x65, 0x74, 0x12, 0x57, 0x0a, 0x11, 0x61, 0x64, 0x64, 0x5f, 0x6d, 0x65, - 0x6d, 0x62, 0x65, 0x72, 0x5f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x2b, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x4d, 0x65, - 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x0f, - 0x61, 0x64, 0x64, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, - 0x5d, 0x0a, 0x14, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x5f, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, - 0x5f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, - 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, - 0x73, 0x68, 0x69, 0x70, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x12, 0x72, 0x65, 0x6d, 0x6f, - 0x76, 0x65, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x74, - 0x0a, 0x16, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, - 0x61, 0x5f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x3e, - 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x50, 0x6f, 0x6c, 0x69, 0x63, - 0x79, 0x53, 0x65, 0x74, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, - 0x61, 0x74, 0x61, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x14, - 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x50, 0x6f, - 0x6c, 0x69, 0x63, 0x79, 0x12, 0x5c, 0x0a, 0x10, 0x61, 0x64, 0x64, 0x5f, 0x61, 0x64, 0x6d, 0x69, - 0x6e, 0x5f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x32, - 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x50, 0x65, 0x72, 0x6d, 0x69, - 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, 0x6f, 0x6c, 0x69, - 0x63, 0x79, 0x52, 0x0e, 0x61, 0x64, 0x64, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x50, 0x6f, 0x6c, 0x69, - 0x63, 0x79, 0x12, 0x62, 0x0a, 0x13, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x5f, 0x61, 0x64, 0x6d, - 0x69, 0x6e, 0x5f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x32, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x50, 0x65, 0x72, 0x6d, - 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, 0x6f, 0x6c, - 0x69, 0x63, 0x79, 0x52, 0x11, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x41, 0x64, 0x6d, 0x69, 0x6e, - 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x6e, 0x0a, 0x19, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, - 0x5f, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x5f, 0x70, 0x6f, 0x6c, - 0x69, 0x63, 0x79, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x32, 0x2e, 0x78, 0x6d, 0x74, 0x70, - 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, - 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, - 0x73, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x17, 0x75, - 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, - 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x1a, 0x72, 0x0a, 0x19, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, - 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x45, 0x6e, - 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x3f, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, - 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, - 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, - 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x8a, 0x05, 0x0a, 0x10, 0x4d, - 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, - 0x4c, 0x0a, 0x04, 0x62, 0x61, 0x73, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x36, 0x2e, - 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, - 0x73, 0x68, 0x69, 0x70, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x42, 0x61, 0x73, 0x65, 0x50, - 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x48, 0x00, 0x52, 0x04, 0x62, 0x61, 0x73, 0x65, 0x12, 0x5f, 0x0a, - 0x0d, 0x61, 0x6e, 0x64, 0x5f, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x38, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, - 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, - 0x2e, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x50, 0x6f, 0x6c, 0x69, 0x63, - 0x79, 0x2e, 0x41, 0x6e, 0x64, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x00, - 0x52, 0x0c, 0x61, 0x6e, 0x64, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x5f, - 0x0a, 0x0d, 0x61, 0x6e, 0x79, 0x5f, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x38, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, - 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, - 0x73, 0x2e, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x50, 0x6f, 0x6c, 0x69, - 0x63, 0x79, 0x2e, 0x41, 0x6e, 0x79, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x48, - 0x00, 0x52, 0x0c, 0x61, 0x6e, 0x79, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x1a, - 0x57, 0x0a, 0x0c, 0x41, 0x6e, 0x64, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, - 0x47, 0x0a, 0x08, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, - 0x0b, 0x32, 0x2b, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x4d, 0x65, - 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x08, - 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x1a, 0x57, 0x0a, 0x0c, 0x41, 0x6e, 0x79, 0x43, - 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x47, 0x0a, 0x08, 0x70, 0x6f, 0x6c, 0x69, - 0x63, 0x69, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x78, 0x6d, 0x74, - 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, - 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, - 0x70, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x08, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, - 0x73, 0x22, 0xab, 0x01, 0x0a, 0x0a, 0x42, 0x61, 0x73, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, - 0x12, 0x1b, 0x0a, 0x17, 0x42, 0x41, 0x53, 0x45, 0x5f, 0x50, 0x4f, 0x4c, 0x49, 0x43, 0x59, 0x5f, - 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x15, 0x0a, - 0x11, 0x42, 0x41, 0x53, 0x45, 0x5f, 0x50, 0x4f, 0x4c, 0x49, 0x43, 0x59, 0x5f, 0x41, 0x4c, 0x4c, - 0x4f, 0x57, 0x10, 0x01, 0x12, 0x14, 0x0a, 0x10, 0x42, 0x41, 0x53, 0x45, 0x5f, 0x50, 0x4f, 0x4c, - 0x49, 0x43, 0x59, 0x5f, 0x44, 0x45, 0x4e, 0x59, 0x10, 0x02, 0x12, 0x2d, 0x0a, 0x29, 0x42, 0x41, - 0x53, 0x45, 0x5f, 0x50, 0x4f, 0x4c, 0x49, 0x43, 0x59, 0x5f, 0x41, 0x4c, 0x4c, 0x4f, 0x57, 0x5f, - 0x49, 0x46, 0x5f, 0x41, 0x44, 0x4d, 0x49, 0x4e, 0x5f, 0x4f, 0x52, 0x5f, 0x53, 0x55, 0x50, 0x45, - 0x52, 0x5f, 0x41, 0x44, 0x4d, 0x49, 0x4e, 0x10, 0x03, 0x12, 0x24, 0x0a, 0x20, 0x42, 0x41, 0x53, - 0x45, 0x5f, 0x50, 0x4f, 0x4c, 0x49, 0x43, 0x59, 0x5f, 0x41, 0x4c, 0x4c, 0x4f, 0x57, 0x5f, 0x49, - 0x46, 0x5f, 0x53, 0x55, 0x50, 0x45, 0x52, 0x5f, 0x41, 0x44, 0x4d, 0x49, 0x4e, 0x10, 0x04, 0x42, - 0x06, 0x0a, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x22, 0xac, 0x05, 0x0a, 0x0e, 0x4d, 0x65, 0x74, 0x61, - 0x64, 0x61, 0x74, 0x61, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x52, 0x0a, 0x04, 0x62, 0x61, - 0x73, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x3c, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, - 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, - 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x50, 0x6f, 0x6c, - 0x69, 0x63, 0x79, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x42, 0x61, 0x73, 0x65, - 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x48, 0x00, 0x52, 0x04, 0x62, 0x61, 0x73, 0x65, 0x12, 0x5d, - 0x0a, 0x0d, 0x61, 0x6e, 0x64, 0x5f, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x36, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, - 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, - 0x73, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, - 0x2e, 0x41, 0x6e, 0x64, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, - 0x0c, 0x61, 0x6e, 0x64, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x5d, 0x0a, - 0x0d, 0x61, 0x6e, 0x79, 0x5f, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x36, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, - 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, - 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, - 0x41, 0x6e, 0x79, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x0c, - 0x61, 0x6e, 0x79, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x1a, 0x55, 0x0a, 0x0c, - 0x41, 0x6e, 0x64, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x45, 0x0a, 0x08, - 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x29, - 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, - 0x61, 0x74, 0x61, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x08, 0x70, 0x6f, 0x6c, 0x69, 0x63, - 0x69, 0x65, 0x73, 0x1a, 0x55, 0x0a, 0x0c, 0x41, 0x6e, 0x79, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, - 0x69, 0x6f, 0x6e, 0x12, 0x45, 0x0a, 0x08, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x18, - 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, - 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, - 0x73, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, - 0x52, 0x08, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x22, 0xd1, 0x01, 0x0a, 0x12, 0x4d, - 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x42, 0x61, 0x73, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, - 0x79, 0x12, 0x24, 0x0a, 0x20, 0x4d, 0x45, 0x54, 0x41, 0x44, 0x41, 0x54, 0x41, 0x5f, 0x42, 0x41, - 0x53, 0x45, 0x5f, 0x50, 0x4f, 0x4c, 0x49, 0x43, 0x59, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, - 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x1e, 0x0a, 0x1a, 0x4d, 0x45, 0x54, 0x41, 0x44, - 0x41, 0x54, 0x41, 0x5f, 0x42, 0x41, 0x53, 0x45, 0x5f, 0x50, 0x4f, 0x4c, 0x49, 0x43, 0x59, 0x5f, - 0x41, 0x4c, 0x4c, 0x4f, 0x57, 0x10, 0x01, 0x12, 0x1d, 0x0a, 0x19, 0x4d, 0x45, 0x54, 0x41, 0x44, - 0x41, 0x54, 0x41, 0x5f, 0x42, 0x41, 0x53, 0x45, 0x5f, 0x50, 0x4f, 0x4c, 0x49, 0x43, 0x59, 0x5f, - 0x44, 0x45, 0x4e, 0x59, 0x10, 0x02, 0x12, 0x27, 0x0a, 0x23, 0x4d, 0x45, 0x54, 0x41, 0x44, 0x41, - 0x54, 0x41, 0x5f, 0x42, 0x41, 0x53, 0x45, 0x5f, 0x50, 0x4f, 0x4c, 0x49, 0x43, 0x59, 0x5f, 0x41, - 0x4c, 0x4c, 0x4f, 0x57, 0x5f, 0x49, 0x46, 0x5f, 0x41, 0x44, 0x4d, 0x49, 0x4e, 0x10, 0x03, 0x12, - 0x2d, 0x0a, 0x29, 0x4d, 0x45, 0x54, 0x41, 0x44, 0x41, 0x54, 0x41, 0x5f, 0x42, 0x41, 0x53, 0x45, - 0x5f, 0x50, 0x4f, 0x4c, 0x49, 0x43, 0x59, 0x5f, 0x41, 0x4c, 0x4c, 0x4f, 0x57, 0x5f, 0x49, 0x46, - 0x5f, 0x53, 0x55, 0x50, 0x45, 0x52, 0x5f, 0x41, 0x44, 0x4d, 0x49, 0x4e, 0x10, 0x04, 0x42, 0x06, - 0x0a, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x22, 0xd4, 0x05, 0x0a, 0x17, 0x50, 0x65, 0x72, 0x6d, 0x69, - 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, 0x6f, 0x6c, 0x69, - 0x63, 0x79, 0x12, 0x5e, 0x0a, 0x04, 0x62, 0x61, 0x73, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, - 0x32, 0x48, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x50, 0x65, 0x72, - 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, 0x6f, - 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, - 0x42, 0x61, 0x73, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x48, 0x00, 0x52, 0x04, 0x62, 0x61, - 0x73, 0x65, 0x12, 0x66, 0x0a, 0x0d, 0x61, 0x6e, 0x64, 0x5f, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, - 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3f, 0x2e, 0x78, 0x6d, 0x74, 0x70, - 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, - 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, - 0x73, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x41, 0x6e, - 0x64, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x0c, 0x61, 0x6e, - 0x64, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x66, 0x0a, 0x0d, 0x61, 0x6e, - 0x79, 0x5f, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x3f, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x50, 0x65, - 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, - 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x41, 0x6e, 0x79, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, - 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x0c, 0x61, 0x6e, 0x79, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, - 0x6f, 0x6e, 0x1a, 0x5e, 0x0a, 0x0c, 0x41, 0x6e, 0x64, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, - 0x6f, 0x6e, 0x12, 0x4e, 0x0a, 0x08, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x18, 0x01, - 0x20, 0x03, 0x28, 0x0b, 0x32, 0x32, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, - 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, - 0x2e, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x55, 0x70, 0x64, 0x61, - 0x74, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x08, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x69, - 0x65, 0x73, 0x1a, 0x5e, 0x0a, 0x0c, 0x41, 0x6e, 0x79, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, - 0x6f, 0x6e, 0x12, 0x4e, 0x0a, 0x08, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x18, 0x01, - 0x20, 0x03, 0x28, 0x0b, 0x32, 0x32, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, - 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, - 0x2e, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x55, 0x70, 0x64, 0x61, - 0x74, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x08, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x69, - 0x65, 0x73, 0x22, 0xc0, 0x01, 0x0a, 0x15, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, - 0x6e, 0x73, 0x42, 0x61, 0x73, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x27, 0x0a, 0x23, - 0x50, 0x45, 0x52, 0x4d, 0x49, 0x53, 0x53, 0x49, 0x4f, 0x4e, 0x53, 0x5f, 0x42, 0x41, 0x53, 0x45, - 0x5f, 0x50, 0x4f, 0x4c, 0x49, 0x43, 0x59, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, - 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x20, 0x0a, 0x1c, 0x50, 0x45, 0x52, 0x4d, 0x49, 0x53, 0x53, - 0x49, 0x4f, 0x4e, 0x53, 0x5f, 0x42, 0x41, 0x53, 0x45, 0x5f, 0x50, 0x4f, 0x4c, 0x49, 0x43, 0x59, - 0x5f, 0x44, 0x45, 0x4e, 0x59, 0x10, 0x01, 0x12, 0x2a, 0x0a, 0x26, 0x50, 0x45, 0x52, 0x4d, 0x49, - 0x53, 0x53, 0x49, 0x4f, 0x4e, 0x53, 0x5f, 0x42, 0x41, 0x53, 0x45, 0x5f, 0x50, 0x4f, 0x4c, 0x49, - 0x43, 0x59, 0x5f, 0x41, 0x4c, 0x4c, 0x4f, 0x57, 0x5f, 0x49, 0x46, 0x5f, 0x41, 0x44, 0x4d, 0x49, - 0x4e, 0x10, 0x02, 0x12, 0x30, 0x0a, 0x2c, 0x50, 0x45, 0x52, 0x4d, 0x49, 0x53, 0x53, 0x49, 0x4f, - 0x4e, 0x53, 0x5f, 0x42, 0x41, 0x53, 0x45, 0x5f, 0x50, 0x4f, 0x4c, 0x49, 0x43, 0x59, 0x5f, 0x41, - 0x4c, 0x4c, 0x4f, 0x57, 0x5f, 0x49, 0x46, 0x5f, 0x53, 0x55, 0x50, 0x45, 0x52, 0x5f, 0x41, 0x44, - 0x4d, 0x49, 0x4e, 0x10, 0x03, 0x42, 0x06, 0x0a, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x42, 0xea, 0x01, - 0x0a, 0x1d, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x42, - 0x15, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, - 0x73, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x30, 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, 0x6d, 0x6c, 0x73, 0x2f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0xa2, 0x02, 0x03, 0x58, 0x4d, 0x4d, - 0xaa, 0x02, 0x18, 0x58, 0x6d, 0x74, 0x70, 0x2e, 0x4d, 0x6c, 0x73, 0x2e, 0x4d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0xca, 0x02, 0x18, 0x58, 0x6d, - 0x74, 0x70, 0x5c, 0x4d, 0x6c, 0x73, 0x5c, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x43, 0x6f, - 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0xe2, 0x02, 0x24, 0x58, 0x6d, 0x74, 0x70, 0x5c, 0x4d, 0x6c, - 0x73, 0x5c, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, - 0x73, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x1a, - 0x58, 0x6d, 0x74, 0x70, 0x3a, 0x3a, 0x4d, 0x6c, 0x73, 0x3a, 0x3a, 0x4d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x4a, 0xe6, 0x18, 0x0a, 0x06, 0x12, - 0x04, 0x01, 0x00, 0x68, 0x01, 0x0a, 0x2e, 0x0a, 0x01, 0x0c, 0x12, 0x03, 0x01, 0x00, 0x12, 0x1a, - 0x24, 0x20, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x20, 0x6d, 0x75, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x20, - 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x6d, 0x65, 0x74, 0x61, - 0x64, 0x61, 0x74, 0x61, 0x0a, 0x0a, 0x08, 0x0a, 0x01, 0x02, 0x12, 0x03, 0x03, 0x00, 0x22, 0x0a, - 0x08, 0x0a, 0x01, 0x08, 0x12, 0x03, 0x05, 0x00, 0x47, 0x0a, 0x09, 0x0a, 0x02, 0x08, 0x0b, 0x12, - 0x03, 0x05, 0x00, 0x47, 0x0a, 0x30, 0x0a, 0x02, 0x04, 0x00, 0x12, 0x04, 0x09, 0x00, 0x0b, 0x01, - 0x1a, 0x24, 0x20, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x67, - 0x72, 0x6f, 0x75, 0x70, 0x20, 0x6d, 0x75, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x6d, 0x65, 0x74, - 0x61, 0x64, 0x61, 0x74, 0x61, 0x0a, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x00, 0x01, 0x12, 0x03, 0x09, - 0x08, 0x21, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x00, 0x02, 0x00, 0x12, 0x03, 0x0a, 0x02, 0x19, 0x0a, - 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x00, 0x06, 0x12, 0x03, 0x0a, 0x02, 0x0b, 0x0a, 0x0c, 0x0a, - 0x05, 0x04, 0x00, 0x02, 0x00, 0x01, 0x12, 0x03, 0x0a, 0x0c, 0x14, 0x0a, 0x0c, 0x0a, 0x05, 0x04, - 0x00, 0x02, 0x00, 0x03, 0x12, 0x03, 0x0a, 0x17, 0x18, 0x0a, 0x37, 0x0a, 0x02, 0x04, 0x01, 0x12, - 0x04, 0x0e, 0x00, 0x15, 0x01, 0x1a, 0x2b, 0x20, 0x54, 0x68, 0x65, 0x20, 0x73, 0x65, 0x74, 0x20, - 0x6f, 0x66, 0x20, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x20, 0x74, 0x68, 0x61, 0x74, - 0x20, 0x67, 0x6f, 0x76, 0x65, 0x72, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x67, 0x72, 0x6f, 0x75, - 0x70, 0x0a, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x01, 0x01, 0x12, 0x03, 0x0e, 0x08, 0x11, 0x0a, 0x0b, - 0x0a, 0x04, 0x04, 0x01, 0x02, 0x00, 0x12, 0x03, 0x0f, 0x02, 0x29, 0x0a, 0x0c, 0x0a, 0x05, 0x04, - 0x01, 0x02, 0x00, 0x06, 0x12, 0x03, 0x0f, 0x02, 0x12, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, - 0x00, 0x01, 0x12, 0x03, 0x0f, 0x13, 0x24, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x00, 0x03, - 0x12, 0x03, 0x0f, 0x27, 0x28, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x01, 0x02, 0x01, 0x12, 0x03, 0x10, - 0x02, 0x2c, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x01, 0x06, 0x12, 0x03, 0x10, 0x02, 0x12, - 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x01, 0x01, 0x12, 0x03, 0x10, 0x13, 0x27, 0x0a, 0x0c, - 0x0a, 0x05, 0x04, 0x01, 0x02, 0x01, 0x03, 0x12, 0x03, 0x10, 0x2a, 0x2b, 0x0a, 0x0b, 0x0a, 0x04, - 0x04, 0x01, 0x02, 0x02, 0x12, 0x03, 0x11, 0x02, 0x39, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, - 0x02, 0x06, 0x12, 0x03, 0x11, 0x02, 0x1d, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x02, 0x01, - 0x12, 0x03, 0x11, 0x1e, 0x34, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x02, 0x03, 0x12, 0x03, - 0x11, 0x37, 0x38, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x01, 0x02, 0x03, 0x12, 0x03, 0x12, 0x02, 0x2f, - 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x03, 0x06, 0x12, 0x03, 0x12, 0x02, 0x19, 0x0a, 0x0c, - 0x0a, 0x05, 0x04, 0x01, 0x02, 0x03, 0x01, 0x12, 0x03, 0x12, 0x1a, 0x2a, 0x0a, 0x0c, 0x0a, 0x05, - 0x04, 0x01, 0x02, 0x03, 0x03, 0x12, 0x03, 0x12, 0x2d, 0x2e, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x01, - 0x02, 0x04, 0x12, 0x03, 0x13, 0x02, 0x32, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x04, 0x06, - 0x12, 0x03, 0x13, 0x02, 0x19, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x04, 0x01, 0x12, 0x03, - 0x13, 0x1a, 0x2d, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x04, 0x03, 0x12, 0x03, 0x13, 0x30, - 0x31, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x01, 0x02, 0x05, 0x12, 0x03, 0x14, 0x02, 0x38, 0x0a, 0x0c, - 0x0a, 0x05, 0x04, 0x01, 0x02, 0x05, 0x06, 0x12, 0x03, 0x14, 0x02, 0x19, 0x0a, 0x0c, 0x0a, 0x05, - 0x04, 0x01, 0x02, 0x05, 0x01, 0x12, 0x03, 0x14, 0x1a, 0x33, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, - 0x02, 0x05, 0x03, 0x12, 0x03, 0x14, 0x36, 0x37, 0x0a, 0x4c, 0x0a, 0x02, 0x04, 0x02, 0x12, 0x04, - 0x18, 0x00, 0x31, 0x01, 0x1a, 0x40, 0x20, 0x41, 0x20, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x20, - 0x74, 0x68, 0x61, 0x74, 0x20, 0x67, 0x6f, 0x76, 0x65, 0x72, 0x6e, 0x73, 0x20, 0x61, 0x64, 0x64, - 0x69, 0x6e, 0x67, 0x2f, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x69, 0x6e, 0x67, 0x20, 0x6d, 0x65, 0x6d, - 0x62, 0x65, 0x72, 0x73, 0x20, 0x6f, 0x72, 0x20, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x0a, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x02, 0x01, 0x12, 0x03, 0x18, - 0x08, 0x18, 0x0a, 0x1b, 0x0a, 0x04, 0x04, 0x02, 0x04, 0x00, 0x12, 0x04, 0x1a, 0x02, 0x20, 0x03, - 0x1a, 0x0d, 0x20, 0x42, 0x61, 0x73, 0x65, 0x20, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x0a, 0x0a, - 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x04, 0x00, 0x01, 0x12, 0x03, 0x1a, 0x07, 0x11, 0x0a, 0x0d, 0x0a, - 0x06, 0x04, 0x02, 0x04, 0x00, 0x02, 0x00, 0x12, 0x03, 0x1b, 0x04, 0x20, 0x0a, 0x0e, 0x0a, 0x07, - 0x04, 0x02, 0x04, 0x00, 0x02, 0x00, 0x01, 0x12, 0x03, 0x1b, 0x04, 0x1b, 0x0a, 0x0e, 0x0a, 0x07, - 0x04, 0x02, 0x04, 0x00, 0x02, 0x00, 0x02, 0x12, 0x03, 0x1b, 0x1e, 0x1f, 0x0a, 0x0d, 0x0a, 0x06, - 0x04, 0x02, 0x04, 0x00, 0x02, 0x01, 0x12, 0x03, 0x1c, 0x04, 0x1a, 0x0a, 0x0e, 0x0a, 0x07, 0x04, - 0x02, 0x04, 0x00, 0x02, 0x01, 0x01, 0x12, 0x03, 0x1c, 0x04, 0x15, 0x0a, 0x0e, 0x0a, 0x07, 0x04, - 0x02, 0x04, 0x00, 0x02, 0x01, 0x02, 0x12, 0x03, 0x1c, 0x18, 0x19, 0x0a, 0x0d, 0x0a, 0x06, 0x04, - 0x02, 0x04, 0x00, 0x02, 0x02, 0x12, 0x03, 0x1d, 0x04, 0x19, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, - 0x04, 0x00, 0x02, 0x02, 0x01, 0x12, 0x03, 0x1d, 0x04, 0x14, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, - 0x04, 0x00, 0x02, 0x02, 0x02, 0x12, 0x03, 0x1d, 0x17, 0x18, 0x0a, 0x0d, 0x0a, 0x06, 0x04, 0x02, - 0x04, 0x00, 0x02, 0x03, 0x12, 0x03, 0x1e, 0x04, 0x32, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x04, - 0x00, 0x02, 0x03, 0x01, 0x12, 0x03, 0x1e, 0x04, 0x2d, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x04, - 0x00, 0x02, 0x03, 0x02, 0x12, 0x03, 0x1e, 0x30, 0x31, 0x0a, 0x0d, 0x0a, 0x06, 0x04, 0x02, 0x04, - 0x00, 0x02, 0x04, 0x12, 0x03, 0x1f, 0x04, 0x29, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x04, 0x00, - 0x02, 0x04, 0x01, 0x12, 0x03, 0x1f, 0x04, 0x24, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x04, 0x00, - 0x02, 0x04, 0x02, 0x12, 0x03, 0x1f, 0x27, 0x28, 0x0a, 0x44, 0x0a, 0x04, 0x04, 0x02, 0x03, 0x00, - 0x12, 0x04, 0x23, 0x02, 0x25, 0x03, 0x1a, 0x36, 0x20, 0x43, 0x6f, 0x6d, 0x62, 0x69, 0x6e, 0x65, - 0x20, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x20, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x69, - 0x65, 0x73, 0x2e, 0x20, 0x41, 0x6c, 0x6c, 0x20, 0x6d, 0x75, 0x73, 0x74, 0x20, 0x65, 0x76, 0x61, - 0x6c, 0x75, 0x61, 0x74, 0x65, 0x20, 0x74, 0x6f, 0x20, 0x74, 0x72, 0x75, 0x65, 0x0a, 0x0a, 0x0c, - 0x0a, 0x05, 0x04, 0x02, 0x03, 0x00, 0x01, 0x12, 0x03, 0x23, 0x0a, 0x16, 0x0a, 0x0d, 0x0a, 0x06, - 0x04, 0x02, 0x03, 0x00, 0x02, 0x00, 0x12, 0x03, 0x24, 0x04, 0x2b, 0x0a, 0x0e, 0x0a, 0x07, 0x04, - 0x02, 0x03, 0x00, 0x02, 0x00, 0x04, 0x12, 0x03, 0x24, 0x04, 0x0c, 0x0a, 0x0e, 0x0a, 0x07, 0x04, - 0x02, 0x03, 0x00, 0x02, 0x00, 0x06, 0x12, 0x03, 0x24, 0x0d, 0x1d, 0x0a, 0x0e, 0x0a, 0x07, 0x04, - 0x02, 0x03, 0x00, 0x02, 0x00, 0x01, 0x12, 0x03, 0x24, 0x1e, 0x26, 0x0a, 0x0e, 0x0a, 0x07, 0x04, - 0x02, 0x03, 0x00, 0x02, 0x00, 0x03, 0x12, 0x03, 0x24, 0x29, 0x2a, 0x0a, 0x44, 0x0a, 0x04, 0x04, - 0x02, 0x03, 0x01, 0x12, 0x04, 0x28, 0x02, 0x2a, 0x03, 0x1a, 0x36, 0x20, 0x43, 0x6f, 0x6d, 0x62, - 0x69, 0x6e, 0x65, 0x20, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x20, 0x70, 0x6f, 0x6c, - 0x69, 0x63, 0x69, 0x65, 0x73, 0x2e, 0x20, 0x41, 0x6e, 0x79, 0x20, 0x6d, 0x75, 0x73, 0x74, 0x20, - 0x65, 0x76, 0x61, 0x6c, 0x75, 0x61, 0x74, 0x65, 0x20, 0x74, 0x6f, 0x20, 0x74, 0x72, 0x75, 0x65, - 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x03, 0x01, 0x01, 0x12, 0x03, 0x28, 0x0a, 0x16, 0x0a, - 0x0d, 0x0a, 0x06, 0x04, 0x02, 0x03, 0x01, 0x02, 0x00, 0x12, 0x03, 0x29, 0x04, 0x2b, 0x0a, 0x0e, - 0x0a, 0x07, 0x04, 0x02, 0x03, 0x01, 0x02, 0x00, 0x04, 0x12, 0x03, 0x29, 0x04, 0x0c, 0x0a, 0x0e, - 0x0a, 0x07, 0x04, 0x02, 0x03, 0x01, 0x02, 0x00, 0x06, 0x12, 0x03, 0x29, 0x0d, 0x1d, 0x0a, 0x0e, - 0x0a, 0x07, 0x04, 0x02, 0x03, 0x01, 0x02, 0x00, 0x01, 0x12, 0x03, 0x29, 0x1e, 0x26, 0x0a, 0x0e, - 0x0a, 0x07, 0x04, 0x02, 0x03, 0x01, 0x02, 0x00, 0x03, 0x12, 0x03, 0x29, 0x29, 0x2a, 0x0a, 0x0c, - 0x0a, 0x04, 0x04, 0x02, 0x08, 0x00, 0x12, 0x04, 0x2c, 0x02, 0x30, 0x03, 0x0a, 0x0c, 0x0a, 0x05, - 0x04, 0x02, 0x08, 0x00, 0x01, 0x12, 0x03, 0x2c, 0x08, 0x0c, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x02, - 0x02, 0x00, 0x12, 0x03, 0x2d, 0x04, 0x18, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x00, 0x06, - 0x12, 0x03, 0x2d, 0x04, 0x0e, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x00, 0x01, 0x12, 0x03, - 0x2d, 0x0f, 0x13, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x00, 0x03, 0x12, 0x03, 0x2d, 0x16, - 0x17, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x02, 0x02, 0x01, 0x12, 0x03, 0x2e, 0x04, 0x23, 0x0a, 0x0c, - 0x0a, 0x05, 0x04, 0x02, 0x02, 0x01, 0x06, 0x12, 0x03, 0x2e, 0x04, 0x10, 0x0a, 0x0c, 0x0a, 0x05, - 0x04, 0x02, 0x02, 0x01, 0x01, 0x12, 0x03, 0x2e, 0x11, 0x1e, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, - 0x02, 0x01, 0x03, 0x12, 0x03, 0x2e, 0x21, 0x22, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x02, 0x02, 0x02, - 0x12, 0x03, 0x2f, 0x04, 0x23, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x02, 0x06, 0x12, 0x03, - 0x2f, 0x04, 0x10, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x02, 0x01, 0x12, 0x03, 0x2f, 0x11, - 0x1e, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x02, 0x03, 0x12, 0x03, 0x2f, 0x21, 0x22, 0x0a, - 0x35, 0x0a, 0x02, 0x04, 0x03, 0x12, 0x04, 0x34, 0x00, 0x4d, 0x01, 0x1a, 0x29, 0x20, 0x41, 0x20, - 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x67, 0x6f, 0x76, 0x65, - 0x72, 0x6e, 0x73, 0x20, 0x75, 0x70, 0x64, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x20, 0x6d, 0x65, 0x74, - 0x61, 0x64, 0x61, 0x74, 0x61, 0x0a, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x03, 0x01, 0x12, 0x03, 0x34, - 0x08, 0x16, 0x0a, 0x1b, 0x0a, 0x04, 0x04, 0x03, 0x04, 0x00, 0x12, 0x04, 0x36, 0x02, 0x3c, 0x03, - 0x1a, 0x0d, 0x20, 0x42, 0x61, 0x73, 0x65, 0x20, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x0a, 0x0a, - 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x04, 0x00, 0x01, 0x12, 0x03, 0x36, 0x07, 0x19, 0x0a, 0x0d, 0x0a, - 0x06, 0x04, 0x03, 0x04, 0x00, 0x02, 0x00, 0x12, 0x03, 0x37, 0x04, 0x29, 0x0a, 0x0e, 0x0a, 0x07, - 0x04, 0x03, 0x04, 0x00, 0x02, 0x00, 0x01, 0x12, 0x03, 0x37, 0x04, 0x24, 0x0a, 0x0e, 0x0a, 0x07, - 0x04, 0x03, 0x04, 0x00, 0x02, 0x00, 0x02, 0x12, 0x03, 0x37, 0x27, 0x28, 0x0a, 0x0d, 0x0a, 0x06, - 0x04, 0x03, 0x04, 0x00, 0x02, 0x01, 0x12, 0x03, 0x38, 0x04, 0x23, 0x0a, 0x0e, 0x0a, 0x07, 0x04, - 0x03, 0x04, 0x00, 0x02, 0x01, 0x01, 0x12, 0x03, 0x38, 0x04, 0x1e, 0x0a, 0x0e, 0x0a, 0x07, 0x04, - 0x03, 0x04, 0x00, 0x02, 0x01, 0x02, 0x12, 0x03, 0x38, 0x21, 0x22, 0x0a, 0x0d, 0x0a, 0x06, 0x04, - 0x03, 0x04, 0x00, 0x02, 0x02, 0x12, 0x03, 0x39, 0x04, 0x22, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x03, - 0x04, 0x00, 0x02, 0x02, 0x01, 0x12, 0x03, 0x39, 0x04, 0x1d, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x03, - 0x04, 0x00, 0x02, 0x02, 0x02, 0x12, 0x03, 0x39, 0x20, 0x21, 0x0a, 0x0d, 0x0a, 0x06, 0x04, 0x03, - 0x04, 0x00, 0x02, 0x03, 0x12, 0x03, 0x3a, 0x04, 0x2c, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x03, 0x04, - 0x00, 0x02, 0x03, 0x01, 0x12, 0x03, 0x3a, 0x04, 0x27, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x03, 0x04, - 0x00, 0x02, 0x03, 0x02, 0x12, 0x03, 0x3a, 0x2a, 0x2b, 0x0a, 0x0d, 0x0a, 0x06, 0x04, 0x03, 0x04, - 0x00, 0x02, 0x04, 0x12, 0x03, 0x3b, 0x04, 0x32, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x03, 0x04, 0x00, - 0x02, 0x04, 0x01, 0x12, 0x03, 0x3b, 0x04, 0x2d, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x03, 0x04, 0x00, - 0x02, 0x04, 0x02, 0x12, 0x03, 0x3b, 0x30, 0x31, 0x0a, 0x44, 0x0a, 0x04, 0x04, 0x03, 0x03, 0x00, - 0x12, 0x04, 0x3f, 0x02, 0x41, 0x03, 0x1a, 0x36, 0x20, 0x43, 0x6f, 0x6d, 0x62, 0x69, 0x6e, 0x65, - 0x20, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x20, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x69, - 0x65, 0x73, 0x2e, 0x20, 0x41, 0x6c, 0x6c, 0x20, 0x6d, 0x75, 0x73, 0x74, 0x20, 0x65, 0x76, 0x61, - 0x6c, 0x75, 0x61, 0x74, 0x65, 0x20, 0x74, 0x6f, 0x20, 0x74, 0x72, 0x75, 0x65, 0x0a, 0x0a, 0x0c, - 0x0a, 0x05, 0x04, 0x03, 0x03, 0x00, 0x01, 0x12, 0x03, 0x3f, 0x0a, 0x16, 0x0a, 0x0d, 0x0a, 0x06, - 0x04, 0x03, 0x03, 0x00, 0x02, 0x00, 0x12, 0x03, 0x40, 0x04, 0x29, 0x0a, 0x0e, 0x0a, 0x07, 0x04, - 0x03, 0x03, 0x00, 0x02, 0x00, 0x04, 0x12, 0x03, 0x40, 0x04, 0x0c, 0x0a, 0x0e, 0x0a, 0x07, 0x04, - 0x03, 0x03, 0x00, 0x02, 0x00, 0x06, 0x12, 0x03, 0x40, 0x0d, 0x1b, 0x0a, 0x0e, 0x0a, 0x07, 0x04, - 0x03, 0x03, 0x00, 0x02, 0x00, 0x01, 0x12, 0x03, 0x40, 0x1c, 0x24, 0x0a, 0x0e, 0x0a, 0x07, 0x04, - 0x03, 0x03, 0x00, 0x02, 0x00, 0x03, 0x12, 0x03, 0x40, 0x27, 0x28, 0x0a, 0x44, 0x0a, 0x04, 0x04, - 0x03, 0x03, 0x01, 0x12, 0x04, 0x44, 0x02, 0x46, 0x03, 0x1a, 0x36, 0x20, 0x43, 0x6f, 0x6d, 0x62, - 0x69, 0x6e, 0x65, 0x20, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x20, 0x70, 0x6f, 0x6c, - 0x69, 0x63, 0x69, 0x65, 0x73, 0x2e, 0x20, 0x41, 0x6e, 0x79, 0x20, 0x6d, 0x75, 0x73, 0x74, 0x20, - 0x65, 0x76, 0x61, 0x6c, 0x75, 0x61, 0x74, 0x65, 0x20, 0x74, 0x6f, 0x20, 0x74, 0x72, 0x75, 0x65, - 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x03, 0x01, 0x01, 0x12, 0x03, 0x44, 0x0a, 0x16, 0x0a, - 0x0d, 0x0a, 0x06, 0x04, 0x03, 0x03, 0x01, 0x02, 0x00, 0x12, 0x03, 0x45, 0x04, 0x29, 0x0a, 0x0e, - 0x0a, 0x07, 0x04, 0x03, 0x03, 0x01, 0x02, 0x00, 0x04, 0x12, 0x03, 0x45, 0x04, 0x0c, 0x0a, 0x0e, - 0x0a, 0x07, 0x04, 0x03, 0x03, 0x01, 0x02, 0x00, 0x06, 0x12, 0x03, 0x45, 0x0d, 0x1b, 0x0a, 0x0e, - 0x0a, 0x07, 0x04, 0x03, 0x03, 0x01, 0x02, 0x00, 0x01, 0x12, 0x03, 0x45, 0x1c, 0x24, 0x0a, 0x0e, - 0x0a, 0x07, 0x04, 0x03, 0x03, 0x01, 0x02, 0x00, 0x03, 0x12, 0x03, 0x45, 0x27, 0x28, 0x0a, 0x0c, - 0x0a, 0x04, 0x04, 0x03, 0x08, 0x00, 0x12, 0x04, 0x48, 0x02, 0x4c, 0x03, 0x0a, 0x0c, 0x0a, 0x05, - 0x04, 0x03, 0x08, 0x00, 0x01, 0x12, 0x03, 0x48, 0x08, 0x0c, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x03, - 0x02, 0x00, 0x12, 0x03, 0x49, 0x04, 0x20, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, 0x00, 0x06, - 0x12, 0x03, 0x49, 0x04, 0x16, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, 0x00, 0x01, 0x12, 0x03, - 0x49, 0x17, 0x1b, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, 0x00, 0x03, 0x12, 0x03, 0x49, 0x1e, - 0x1f, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x03, 0x02, 0x01, 0x12, 0x03, 0x4a, 0x04, 0x23, 0x0a, 0x0c, - 0x0a, 0x05, 0x04, 0x03, 0x02, 0x01, 0x06, 0x12, 0x03, 0x4a, 0x04, 0x10, 0x0a, 0x0c, 0x0a, 0x05, - 0x04, 0x03, 0x02, 0x01, 0x01, 0x12, 0x03, 0x4a, 0x11, 0x1e, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, - 0x02, 0x01, 0x03, 0x12, 0x03, 0x4a, 0x21, 0x22, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x03, 0x02, 0x02, - 0x12, 0x03, 0x4b, 0x04, 0x23, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, 0x02, 0x06, 0x12, 0x03, - 0x4b, 0x04, 0x10, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, 0x02, 0x01, 0x12, 0x03, 0x4b, 0x11, - 0x1e, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, 0x02, 0x03, 0x12, 0x03, 0x4b, 0x21, 0x22, 0x0a, - 0x38, 0x0a, 0x02, 0x04, 0x04, 0x12, 0x04, 0x50, 0x00, 0x68, 0x01, 0x1a, 0x2c, 0x20, 0x41, 0x20, - 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x67, 0x6f, 0x76, 0x65, - 0x72, 0x6e, 0x73, 0x20, 0x75, 0x70, 0x64, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x20, 0x70, 0x65, 0x72, - 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x0a, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x04, 0x01, - 0x12, 0x03, 0x50, 0x08, 0x1f, 0x0a, 0x1b, 0x0a, 0x04, 0x04, 0x04, 0x04, 0x00, 0x12, 0x04, 0x52, - 0x02, 0x57, 0x03, 0x1a, 0x0d, 0x20, 0x42, 0x61, 0x73, 0x65, 0x20, 0x70, 0x6f, 0x6c, 0x69, 0x63, - 0x79, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x04, 0x00, 0x01, 0x12, 0x03, 0x52, 0x07, 0x1c, - 0x0a, 0x0d, 0x0a, 0x06, 0x04, 0x04, 0x04, 0x00, 0x02, 0x00, 0x12, 0x03, 0x53, 0x04, 0x2c, 0x0a, - 0x0e, 0x0a, 0x07, 0x04, 0x04, 0x04, 0x00, 0x02, 0x00, 0x01, 0x12, 0x03, 0x53, 0x04, 0x27, 0x0a, - 0x0e, 0x0a, 0x07, 0x04, 0x04, 0x04, 0x00, 0x02, 0x00, 0x02, 0x12, 0x03, 0x53, 0x2a, 0x2b, 0x0a, - 0x0d, 0x0a, 0x06, 0x04, 0x04, 0x04, 0x00, 0x02, 0x01, 0x12, 0x03, 0x54, 0x04, 0x25, 0x0a, 0x0e, - 0x0a, 0x07, 0x04, 0x04, 0x04, 0x00, 0x02, 0x01, 0x01, 0x12, 0x03, 0x54, 0x04, 0x20, 0x0a, 0x0e, - 0x0a, 0x07, 0x04, 0x04, 0x04, 0x00, 0x02, 0x01, 0x02, 0x12, 0x03, 0x54, 0x23, 0x24, 0x0a, 0x0d, - 0x0a, 0x06, 0x04, 0x04, 0x04, 0x00, 0x02, 0x02, 0x12, 0x03, 0x55, 0x04, 0x2f, 0x0a, 0x0e, 0x0a, - 0x07, 0x04, 0x04, 0x04, 0x00, 0x02, 0x02, 0x01, 0x12, 0x03, 0x55, 0x04, 0x2a, 0x0a, 0x0e, 0x0a, - 0x07, 0x04, 0x04, 0x04, 0x00, 0x02, 0x02, 0x02, 0x12, 0x03, 0x55, 0x2d, 0x2e, 0x0a, 0x0d, 0x0a, - 0x06, 0x04, 0x04, 0x04, 0x00, 0x02, 0x03, 0x12, 0x03, 0x56, 0x04, 0x35, 0x0a, 0x0e, 0x0a, 0x07, - 0x04, 0x04, 0x04, 0x00, 0x02, 0x03, 0x01, 0x12, 0x03, 0x56, 0x04, 0x30, 0x0a, 0x0e, 0x0a, 0x07, - 0x04, 0x04, 0x04, 0x00, 0x02, 0x03, 0x02, 0x12, 0x03, 0x56, 0x33, 0x34, 0x0a, 0x44, 0x0a, 0x04, - 0x04, 0x04, 0x03, 0x00, 0x12, 0x04, 0x5a, 0x02, 0x5c, 0x03, 0x1a, 0x36, 0x20, 0x43, 0x6f, 0x6d, - 0x62, 0x69, 0x6e, 0x65, 0x20, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x20, 0x70, 0x6f, - 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x2e, 0x20, 0x41, 0x6c, 0x6c, 0x20, 0x6d, 0x75, 0x73, 0x74, - 0x20, 0x65, 0x76, 0x61, 0x6c, 0x75, 0x61, 0x74, 0x65, 0x20, 0x74, 0x6f, 0x20, 0x74, 0x72, 0x75, - 0x65, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x03, 0x00, 0x01, 0x12, 0x03, 0x5a, 0x0a, 0x16, - 0x0a, 0x0d, 0x0a, 0x06, 0x04, 0x04, 0x03, 0x00, 0x02, 0x00, 0x12, 0x03, 0x5b, 0x04, 0x32, 0x0a, - 0x0e, 0x0a, 0x07, 0x04, 0x04, 0x03, 0x00, 0x02, 0x00, 0x04, 0x12, 0x03, 0x5b, 0x04, 0x0c, 0x0a, - 0x0e, 0x0a, 0x07, 0x04, 0x04, 0x03, 0x00, 0x02, 0x00, 0x06, 0x12, 0x03, 0x5b, 0x0d, 0x24, 0x0a, - 0x0e, 0x0a, 0x07, 0x04, 0x04, 0x03, 0x00, 0x02, 0x00, 0x01, 0x12, 0x03, 0x5b, 0x25, 0x2d, 0x0a, - 0x0e, 0x0a, 0x07, 0x04, 0x04, 0x03, 0x00, 0x02, 0x00, 0x03, 0x12, 0x03, 0x5b, 0x30, 0x31, 0x0a, - 0x44, 0x0a, 0x04, 0x04, 0x04, 0x03, 0x01, 0x12, 0x04, 0x5f, 0x02, 0x61, 0x03, 0x1a, 0x36, 0x20, - 0x43, 0x6f, 0x6d, 0x62, 0x69, 0x6e, 0x65, 0x20, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, - 0x20, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x2e, 0x20, 0x41, 0x6e, 0x79, 0x20, 0x6d, - 0x75, 0x73, 0x74, 0x20, 0x65, 0x76, 0x61, 0x6c, 0x75, 0x61, 0x74, 0x65, 0x20, 0x74, 0x6f, 0x20, - 0x74, 0x72, 0x75, 0x65, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x03, 0x01, 0x01, 0x12, 0x03, - 0x5f, 0x0a, 0x16, 0x0a, 0x0d, 0x0a, 0x06, 0x04, 0x04, 0x03, 0x01, 0x02, 0x00, 0x12, 0x03, 0x60, - 0x04, 0x32, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x04, 0x03, 0x01, 0x02, 0x00, 0x04, 0x12, 0x03, 0x60, - 0x04, 0x0c, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x04, 0x03, 0x01, 0x02, 0x00, 0x06, 0x12, 0x03, 0x60, - 0x0d, 0x24, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x04, 0x03, 0x01, 0x02, 0x00, 0x01, 0x12, 0x03, 0x60, - 0x25, 0x2d, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x04, 0x03, 0x01, 0x02, 0x00, 0x03, 0x12, 0x03, 0x60, - 0x30, 0x31, 0x0a, 0x0c, 0x0a, 0x04, 0x04, 0x04, 0x08, 0x00, 0x12, 0x04, 0x63, 0x02, 0x67, 0x03, - 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x08, 0x00, 0x01, 0x12, 0x03, 0x63, 0x08, 0x0c, 0x0a, 0x0b, - 0x0a, 0x04, 0x04, 0x04, 0x02, 0x00, 0x12, 0x03, 0x64, 0x04, 0x23, 0x0a, 0x0c, 0x0a, 0x05, 0x04, - 0x04, 0x02, 0x00, 0x06, 0x12, 0x03, 0x64, 0x04, 0x19, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x02, - 0x00, 0x01, 0x12, 0x03, 0x64, 0x1a, 0x1e, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x02, 0x00, 0x03, - 0x12, 0x03, 0x64, 0x21, 0x22, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x04, 0x02, 0x01, 0x12, 0x03, 0x65, - 0x04, 0x23, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x02, 0x01, 0x06, 0x12, 0x03, 0x65, 0x04, 0x10, - 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x02, 0x01, 0x01, 0x12, 0x03, 0x65, 0x11, 0x1e, 0x0a, 0x0c, - 0x0a, 0x05, 0x04, 0x04, 0x02, 0x01, 0x03, 0x12, 0x03, 0x65, 0x21, 0x22, 0x0a, 0x0b, 0x0a, 0x04, - 0x04, 0x04, 0x02, 0x02, 0x12, 0x03, 0x66, 0x04, 0x23, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x02, - 0x02, 0x06, 0x12, 0x03, 0x66, 0x04, 0x10, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x02, 0x02, 0x01, - 0x12, 0x03, 0x66, 0x11, 0x1e, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x02, 0x02, 0x03, 0x12, 0x03, - 0x66, 0x21, 0x22, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, 0x0a, 0xb8, 0x1a, 0x0a, 0x2e, - 0x6d, 0x6c, 0x73, 0x2f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, - 0x65, 0x6e, 0x74, 0x73, 0x2f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x5f, - 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x19, - 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x22, 0xa7, 0x01, 0x0a, 0x10, 0x4d, 0x65, - 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x29, - 0x0a, 0x10, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, - 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x0f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, - 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x73, 0x12, 0x27, 0x0a, 0x0f, 0x61, 0x63, 0x63, - 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x0e, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, - 0x73, 0x73, 0x12, 0x3f, 0x0a, 0x1c, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x74, 0x65, 0x64, 0x5f, - 0x62, 0x79, 0x5f, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, - 0x73, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x19, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x61, - 0x74, 0x65, 0x64, 0x42, 0x79, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x41, 0x64, 0x64, 0x72, - 0x65, 0x73, 0x73, 0x22, 0x80, 0x03, 0x0a, 0x16, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x4d, 0x65, 0x6d, - 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x12, 0x50, - 0x0a, 0x0d, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x5f, 0x61, 0x64, 0x64, 0x65, 0x64, 0x18, - 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, - 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, - 0x73, 0x2e, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x43, 0x68, 0x61, 0x6e, - 0x67, 0x65, 0x52, 0x0c, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x41, 0x64, 0x64, 0x65, 0x64, - 0x12, 0x54, 0x0a, 0x0f, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x5f, 0x72, 0x65, 0x6d, 0x6f, - 0x76, 0x65, 0x64, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x78, 0x6d, 0x74, 0x70, - 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, - 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, - 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x0e, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x52, - 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x12, 0x5c, 0x0a, 0x13, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, - 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x5f, 0x61, 0x64, 0x64, 0x65, 0x64, 0x18, 0x03, 0x20, - 0x03, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, - 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, - 0x52, 0x12, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x41, - 0x64, 0x64, 0x65, 0x64, 0x12, 0x60, 0x0a, 0x15, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x5f, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x18, 0x04, 0x20, - 0x03, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, - 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, - 0x52, 0x14, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, - 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x22, 0x9b, 0x04, 0x0a, 0x0c, 0x47, 0x72, 0x6f, 0x75, 0x70, - 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x12, 0x31, 0x0a, 0x15, 0x69, 0x6e, 0x69, 0x74, 0x69, - 0x61, 0x74, 0x65, 0x64, 0x5f, 0x62, 0x79, 0x5f, 0x69, 0x6e, 0x62, 0x6f, 0x78, 0x5f, 0x69, 0x64, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x12, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x74, 0x65, - 0x64, 0x42, 0x79, 0x49, 0x6e, 0x62, 0x6f, 0x78, 0x49, 0x64, 0x12, 0x52, 0x0a, 0x0d, 0x61, 0x64, - 0x64, 0x65, 0x64, 0x5f, 0x69, 0x6e, 0x62, 0x6f, 0x78, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, - 0x0b, 0x32, 0x2d, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x47, 0x72, - 0x6f, 0x75, 0x70, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x2e, 0x49, 0x6e, 0x62, 0x6f, 0x78, - 0x52, 0x0c, 0x61, 0x64, 0x64, 0x65, 0x64, 0x49, 0x6e, 0x62, 0x6f, 0x78, 0x65, 0x73, 0x12, 0x56, - 0x0a, 0x0f, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x5f, 0x69, 0x6e, 0x62, 0x6f, 0x78, 0x65, - 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, - 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, - 0x6e, 0x74, 0x73, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, - 0x2e, 0x49, 0x6e, 0x62, 0x6f, 0x78, 0x52, 0x0e, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x49, - 0x6e, 0x62, 0x6f, 0x78, 0x65, 0x73, 0x12, 0x71, 0x0a, 0x16, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, - 0x74, 0x61, 0x5f, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x73, - 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x3b, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, - 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, - 0x74, 0x73, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x2e, - 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x43, 0x68, 0x61, - 0x6e, 0x67, 0x65, 0x52, 0x14, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x46, 0x69, 0x65, - 0x6c, 0x64, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x1a, 0x22, 0x0a, 0x05, 0x49, 0x6e, 0x62, - 0x6f, 0x78, 0x12, 0x19, 0x0a, 0x08, 0x69, 0x6e, 0x62, 0x6f, 0x78, 0x5f, 0x69, 0x64, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x69, 0x6e, 0x62, 0x6f, 0x78, 0x49, 0x64, 0x1a, 0x94, 0x01, - 0x0a, 0x13, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x43, - 0x68, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x5f, 0x6e, - 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x66, 0x69, 0x65, 0x6c, 0x64, - 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x09, 0x6f, 0x6c, 0x64, 0x5f, 0x76, 0x61, 0x6c, 0x75, - 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x08, 0x6f, 0x6c, 0x64, 0x56, 0x61, - 0x6c, 0x75, 0x65, 0x88, 0x01, 0x01, 0x12, 0x20, 0x0a, 0x09, 0x6e, 0x65, 0x77, 0x5f, 0x76, 0x61, - 0x6c, 0x75, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x48, 0x01, 0x52, 0x08, 0x6e, 0x65, 0x77, - 0x56, 0x61, 0x6c, 0x75, 0x65, 0x88, 0x01, 0x01, 0x42, 0x0c, 0x0a, 0x0a, 0x5f, 0x6f, 0x6c, 0x64, - 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x42, 0x0c, 0x0a, 0x0a, 0x5f, 0x6e, 0x65, 0x77, 0x5f, 0x76, - 0x61, 0x6c, 0x75, 0x65, 0x42, 0xec, 0x01, 0x0a, 0x1d, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x6d, 0x74, - 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, - 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x42, 0x17, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x63, 0x72, 0x69, - 0x70, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, - 0x01, 0x5a, 0x30, 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, 0x6d, - 0x6c, 0x73, 0x2f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, - 0x6e, 0x74, 0x73, 0xa2, 0x02, 0x03, 0x58, 0x4d, 0x4d, 0xaa, 0x02, 0x18, 0x58, 0x6d, 0x74, 0x70, - 0x2e, 0x4d, 0x6c, 0x73, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x74, - 0x65, 0x6e, 0x74, 0x73, 0xca, 0x02, 0x18, 0x58, 0x6d, 0x74, 0x70, 0x5c, 0x4d, 0x6c, 0x73, 0x5c, - 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0xe2, - 0x02, 0x24, 0x58, 0x6d, 0x74, 0x70, 0x5c, 0x4d, 0x6c, 0x73, 0x5c, 0x4d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, - 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x1a, 0x58, 0x6d, 0x74, 0x70, 0x3a, 0x3a, 0x4d, - 0x6c, 0x73, 0x3a, 0x3a, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, - 0x6e, 0x74, 0x73, 0x4a, 0xa8, 0x0f, 0x0a, 0x06, 0x12, 0x04, 0x01, 0x00, 0x38, 0x01, 0x0a, 0x2f, - 0x0a, 0x01, 0x0c, 0x12, 0x03, 0x01, 0x00, 0x12, 0x1a, 0x25, 0x20, 0x4d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x20, 0x65, 0x6e, 0x63, 0x6f, 0x64, - 0x69, 0x6e, 0x67, 0x20, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x75, 0x72, 0x65, 0x73, 0x0a, 0x0a, - 0x08, 0x0a, 0x01, 0x02, 0x12, 0x03, 0x03, 0x00, 0x22, 0x0a, 0x08, 0x0a, 0x01, 0x08, 0x12, 0x03, - 0x05, 0x00, 0x47, 0x0a, 0x09, 0x0a, 0x02, 0x08, 0x0b, 0x12, 0x03, 0x05, 0x00, 0x47, 0x0a, 0x3a, - 0x0a, 0x02, 0x04, 0x00, 0x12, 0x04, 0x09, 0x00, 0x0d, 0x01, 0x1a, 0x2e, 0x20, 0x41, 0x20, 0x67, - 0x72, 0x6f, 0x75, 0x70, 0x20, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x20, 0x61, 0x6e, 0x64, 0x20, - 0x61, 0x66, 0x66, 0x65, 0x63, 0x74, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x49, 0x44, 0x73, 0x0a, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x00, - 0x01, 0x12, 0x03, 0x09, 0x08, 0x18, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x00, 0x02, 0x00, 0x12, 0x03, - 0x0a, 0x02, 0x26, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x00, 0x04, 0x12, 0x03, 0x0a, 0x02, - 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x00, 0x05, 0x12, 0x03, 0x0a, 0x0b, 0x10, 0x0a, - 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x00, 0x01, 0x12, 0x03, 0x0a, 0x11, 0x21, 0x0a, 0x0c, 0x0a, - 0x05, 0x04, 0x00, 0x02, 0x00, 0x03, 0x12, 0x03, 0x0a, 0x24, 0x25, 0x0a, 0x0b, 0x0a, 0x04, 0x04, - 0x00, 0x02, 0x01, 0x12, 0x03, 0x0b, 0x02, 0x1d, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x01, - 0x05, 0x12, 0x03, 0x0b, 0x02, 0x08, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x01, 0x01, 0x12, - 0x03, 0x0b, 0x09, 0x18, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x01, 0x03, 0x12, 0x03, 0x0b, - 0x1b, 0x1c, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x00, 0x02, 0x02, 0x12, 0x03, 0x0c, 0x02, 0x2a, 0x0a, - 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x02, 0x05, 0x12, 0x03, 0x0c, 0x02, 0x08, 0x0a, 0x0c, 0x0a, - 0x05, 0x04, 0x00, 0x02, 0x02, 0x01, 0x12, 0x03, 0x0c, 0x09, 0x25, 0x0a, 0x0c, 0x0a, 0x05, 0x04, - 0x00, 0x02, 0x02, 0x03, 0x12, 0x03, 0x0c, 0x28, 0x29, 0x0a, 0x64, 0x0a, 0x02, 0x04, 0x01, 0x12, - 0x04, 0x10, 0x00, 0x1d, 0x01, 0x1a, 0x23, 0x20, 0x54, 0x68, 0x65, 0x20, 0x67, 0x72, 0x6f, 0x75, - 0x70, 0x20, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x20, 0x63, 0x68, 0x61, - 0x6e, 0x67, 0x65, 0x20, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x0a, 0x22, 0x33, 0x20, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x6c, 0x69, 0x6e, 0x74, 0x3a, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x52, - 0x45, 0x50, 0x45, 0x41, 0x54, 0x45, 0x44, 0x5f, 0x46, 0x49, 0x45, 0x4c, 0x44, 0x5f, 0x4e, 0x41, - 0x4d, 0x45, 0x53, 0x5f, 0x50, 0x4c, 0x55, 0x52, 0x41, 0x4c, 0x49, 0x5a, 0x45, 0x44, 0x0a, 0x0a, - 0x0a, 0x0a, 0x03, 0x04, 0x01, 0x01, 0x12, 0x03, 0x10, 0x08, 0x1e, 0x0a, 0x39, 0x0a, 0x04, 0x04, - 0x01, 0x02, 0x00, 0x12, 0x03, 0x14, 0x02, 0x2e, 0x1a, 0x2c, 0x20, 0x4d, 0x65, 0x6d, 0x62, 0x65, - 0x72, 0x73, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x68, 0x61, 0x76, 0x65, 0x20, 0x62, 0x65, 0x65, + 0x74, 0x65, 0x6e, 0x74, 0x73, 0x4a, 0xa8, 0x0f, 0x0a, 0x06, 0x12, 0x04, 0x01, 0x00, 0x38, 0x01, + 0x0a, 0x2f, 0x0a, 0x01, 0x0c, 0x12, 0x03, 0x01, 0x00, 0x12, 0x1a, 0x25, 0x20, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x20, 0x65, 0x6e, 0x63, + 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x75, 0x72, 0x65, 0x73, + 0x0a, 0x0a, 0x08, 0x0a, 0x01, 0x02, 0x12, 0x03, 0x03, 0x00, 0x22, 0x0a, 0x08, 0x0a, 0x01, 0x08, + 0x12, 0x03, 0x05, 0x00, 0x47, 0x0a, 0x09, 0x0a, 0x02, 0x08, 0x0b, 0x12, 0x03, 0x05, 0x00, 0x47, + 0x0a, 0x3a, 0x0a, 0x02, 0x04, 0x00, 0x12, 0x04, 0x09, 0x00, 0x0d, 0x01, 0x1a, 0x2e, 0x20, 0x41, + 0x20, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x20, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x20, 0x61, 0x6e, + 0x64, 0x20, 0x61, 0x66, 0x66, 0x65, 0x63, 0x74, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x73, 0x74, 0x61, + 0x6c, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x49, 0x44, 0x73, 0x0a, 0x0a, 0x0a, 0x0a, 0x03, + 0x04, 0x00, 0x01, 0x12, 0x03, 0x09, 0x08, 0x18, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x00, 0x02, 0x00, + 0x12, 0x03, 0x0a, 0x02, 0x26, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x00, 0x04, 0x12, 0x03, + 0x0a, 0x02, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x00, 0x05, 0x12, 0x03, 0x0a, 0x0b, + 0x10, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x00, 0x01, 0x12, 0x03, 0x0a, 0x11, 0x21, 0x0a, + 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x00, 0x03, 0x12, 0x03, 0x0a, 0x24, 0x25, 0x0a, 0x0b, 0x0a, + 0x04, 0x04, 0x00, 0x02, 0x01, 0x12, 0x03, 0x0b, 0x02, 0x1d, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, + 0x02, 0x01, 0x05, 0x12, 0x03, 0x0b, 0x02, 0x08, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x01, + 0x01, 0x12, 0x03, 0x0b, 0x09, 0x18, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x01, 0x03, 0x12, + 0x03, 0x0b, 0x1b, 0x1c, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x00, 0x02, 0x02, 0x12, 0x03, 0x0c, 0x02, + 0x2a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x02, 0x05, 0x12, 0x03, 0x0c, 0x02, 0x08, 0x0a, + 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x02, 0x01, 0x12, 0x03, 0x0c, 0x09, 0x25, 0x0a, 0x0c, 0x0a, + 0x05, 0x04, 0x00, 0x02, 0x02, 0x03, 0x12, 0x03, 0x0c, 0x28, 0x29, 0x0a, 0x64, 0x0a, 0x02, 0x04, + 0x01, 0x12, 0x04, 0x10, 0x00, 0x1d, 0x01, 0x1a, 0x23, 0x20, 0x54, 0x68, 0x65, 0x20, 0x67, 0x72, + 0x6f, 0x75, 0x70, 0x20, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x20, 0x63, + 0x68, 0x61, 0x6e, 0x67, 0x65, 0x20, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x0a, 0x22, 0x33, 0x20, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x6c, 0x69, 0x6e, 0x74, 0x3a, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, + 0x20, 0x52, 0x45, 0x50, 0x45, 0x41, 0x54, 0x45, 0x44, 0x5f, 0x46, 0x49, 0x45, 0x4c, 0x44, 0x5f, + 0x4e, 0x41, 0x4d, 0x45, 0x53, 0x5f, 0x50, 0x4c, 0x55, 0x52, 0x41, 0x4c, 0x49, 0x5a, 0x45, 0x44, + 0x0a, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x01, 0x01, 0x12, 0x03, 0x10, 0x08, 0x1e, 0x0a, 0x39, 0x0a, + 0x04, 0x04, 0x01, 0x02, 0x00, 0x12, 0x03, 0x14, 0x02, 0x2e, 0x1a, 0x2c, 0x20, 0x4d, 0x65, 0x6d, + 0x62, 0x65, 0x72, 0x73, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x68, 0x61, 0x76, 0x65, 0x20, 0x62, + 0x65, 0x65, 0x6e, 0x20, 0x61, 0x64, 0x64, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x00, + 0x04, 0x12, 0x03, 0x14, 0x02, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x00, 0x06, 0x12, + 0x03, 0x14, 0x0b, 0x1b, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x00, 0x01, 0x12, 0x03, 0x14, + 0x1c, 0x29, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x00, 0x03, 0x12, 0x03, 0x14, 0x2c, 0x2d, + 0x0a, 0x3b, 0x0a, 0x04, 0x04, 0x01, 0x02, 0x01, 0x12, 0x03, 0x16, 0x02, 0x30, 0x1a, 0x2e, 0x20, + 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x68, 0x61, 0x76, + 0x65, 0x20, 0x62, 0x65, 0x65, 0x6e, 0x20, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x20, 0x69, + 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x0a, 0x0a, 0x0c, 0x0a, + 0x05, 0x04, 0x01, 0x02, 0x01, 0x04, 0x12, 0x03, 0x16, 0x02, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, + 0x01, 0x02, 0x01, 0x06, 0x12, 0x03, 0x16, 0x0b, 0x1b, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, + 0x01, 0x01, 0x12, 0x03, 0x16, 0x1c, 0x2b, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x01, 0x03, + 0x12, 0x03, 0x16, 0x2e, 0x2f, 0x0a, 0x52, 0x0a, 0x04, 0x04, 0x01, 0x02, 0x02, 0x12, 0x03, 0x18, + 0x02, 0x34, 0x1a, 0x45, 0x20, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x73, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x68, 0x61, 0x76, 0x65, 0x20, 0x62, 0x65, 0x65, 0x6e, 0x20, 0x61, 0x64, 0x64, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, - 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x00, 0x04, 0x12, - 0x03, 0x14, 0x02, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x00, 0x06, 0x12, 0x03, 0x14, - 0x0b, 0x1b, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x00, 0x01, 0x12, 0x03, 0x14, 0x1c, 0x29, - 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x00, 0x03, 0x12, 0x03, 0x14, 0x2c, 0x2d, 0x0a, 0x3b, - 0x0a, 0x04, 0x04, 0x01, 0x02, 0x01, 0x12, 0x03, 0x16, 0x02, 0x30, 0x1a, 0x2e, 0x20, 0x4d, 0x65, - 0x6d, 0x62, 0x65, 0x72, 0x73, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x68, 0x61, 0x76, 0x65, 0x20, - 0x62, 0x65, 0x65, 0x6e, 0x20, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x20, - 0x74, 0x68, 0x65, 0x20, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, - 0x01, 0x02, 0x01, 0x04, 0x12, 0x03, 0x16, 0x02, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, - 0x01, 0x06, 0x12, 0x03, 0x16, 0x0b, 0x1b, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x01, 0x01, - 0x12, 0x03, 0x16, 0x1c, 0x2b, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x01, 0x03, 0x12, 0x03, - 0x16, 0x2e, 0x2f, 0x0a, 0x52, 0x0a, 0x04, 0x04, 0x01, 0x02, 0x02, 0x12, 0x03, 0x18, 0x02, 0x34, - 0x1a, 0x45, 0x20, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, - 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x68, 0x61, 0x76, 0x65, 0x20, 0x62, 0x65, 0x65, 0x6e, 0x20, - 0x61, 0x64, 0x64, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6f, 0x6d, - 0x6d, 0x69, 0x74, 0x2c, 0x20, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x65, 0x64, 0x20, 0x62, 0x79, 0x20, - 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x02, 0x04, - 0x12, 0x03, 0x18, 0x02, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x02, 0x06, 0x12, 0x03, - 0x18, 0x0b, 0x1b, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x02, 0x01, 0x12, 0x03, 0x18, 0x1c, - 0x2f, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x02, 0x03, 0x12, 0x03, 0x18, 0x32, 0x33, 0x0a, - 0x45, 0x0a, 0x04, 0x04, 0x01, 0x02, 0x03, 0x12, 0x03, 0x1a, 0x02, 0x36, 0x1a, 0x38, 0x20, 0x49, - 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x72, 0x65, 0x6d, - 0x6f, 0x76, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6f, 0x6d, 0x6d, - 0x69, 0x74, 0x2c, 0x20, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x65, 0x64, 0x20, 0x62, 0x79, 0x20, 0x6d, - 0x65, 0x6d, 0x62, 0x65, 0x72, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x03, 0x04, 0x12, - 0x03, 0x1a, 0x02, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x03, 0x06, 0x12, 0x03, 0x1a, - 0x0b, 0x1b, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x03, 0x01, 0x12, 0x03, 0x1a, 0x1c, 0x31, - 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x03, 0x03, 0x12, 0x03, 0x1a, 0x34, 0x35, 0x0a, 0x6b, - 0x0a, 0x02, 0x04, 0x02, 0x12, 0x04, 0x21, 0x00, 0x38, 0x01, 0x1a, 0x5f, 0x20, 0x41, 0x20, 0x73, - 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x68, - 0x61, 0x6e, 0x67, 0x65, 0x73, 0x20, 0x69, 0x6e, 0x20, 0x61, 0x20, 0x63, 0x6f, 0x6d, 0x6d, 0x69, - 0x74, 0x2e, 0x0a, 0x20, 0x49, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x73, 0x20, 0x61, 0x64, 0x64, - 0x65, 0x64, 0x2f, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x62, 0x6f, 0x78, - 0x65, 0x73, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x20, 0x74, - 0x6f, 0x20, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x0a, 0x0a, 0x0a, 0x0a, 0x03, 0x04, - 0x02, 0x01, 0x12, 0x03, 0x21, 0x08, 0x14, 0x0a, 0x41, 0x0a, 0x04, 0x04, 0x02, 0x03, 0x00, 0x12, - 0x04, 0x23, 0x02, 0x25, 0x03, 0x1a, 0x33, 0x20, 0x41, 0x6e, 0x20, 0x69, 0x6e, 0x62, 0x6f, 0x78, - 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x77, 0x61, 0x73, 0x20, 0x61, 0x64, 0x64, 0x65, 0x64, 0x20, - 0x6f, 0x72, 0x20, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, - 0x69, 0x73, 0x20, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, - 0x03, 0x00, 0x01, 0x12, 0x03, 0x23, 0x0a, 0x0f, 0x0a, 0x0d, 0x0a, 0x06, 0x04, 0x02, 0x03, 0x00, - 0x02, 0x00, 0x12, 0x03, 0x24, 0x04, 0x18, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, 0x00, 0x02, - 0x00, 0x05, 0x12, 0x03, 0x24, 0x04, 0x0a, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, 0x00, 0x02, - 0x00, 0x01, 0x12, 0x03, 0x24, 0x0b, 0x13, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, 0x00, 0x02, - 0x00, 0x03, 0x12, 0x03, 0x24, 0x16, 0x17, 0x0a, 0x3d, 0x0a, 0x04, 0x04, 0x02, 0x03, 0x01, 0x12, - 0x04, 0x28, 0x02, 0x2f, 0x03, 0x1a, 0x2f, 0x20, 0x41, 0x20, 0x73, 0x75, 0x6d, 0x6d, 0x61, 0x72, - 0x79, 0x20, 0x6f, 0x66, 0x20, 0x61, 0x20, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x20, 0x74, 0x6f, - 0x20, 0x74, 0x68, 0x65, 0x20, 0x6d, 0x75, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x6d, 0x65, 0x74, - 0x61, 0x64, 0x61, 0x74, 0x61, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x03, 0x01, 0x01, 0x12, - 0x03, 0x28, 0x0a, 0x1d, 0x0a, 0x2b, 0x0a, 0x06, 0x04, 0x02, 0x03, 0x01, 0x02, 0x00, 0x12, 0x03, - 0x2a, 0x04, 0x1a, 0x1a, 0x1c, 0x20, 0x54, 0x68, 0x65, 0x20, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x20, - 0x74, 0x68, 0x61, 0x74, 0x20, 0x77, 0x61, 0x73, 0x20, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, - 0x0a, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, 0x01, 0x02, 0x00, 0x05, 0x12, 0x03, 0x2a, 0x04, - 0x0a, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, 0x01, 0x02, 0x00, 0x01, 0x12, 0x03, 0x2a, 0x0b, - 0x15, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, 0x01, 0x02, 0x00, 0x03, 0x12, 0x03, 0x2a, 0x18, - 0x19, 0x0a, 0x23, 0x0a, 0x06, 0x04, 0x02, 0x03, 0x01, 0x02, 0x01, 0x12, 0x03, 0x2c, 0x04, 0x22, - 0x1a, 0x14, 0x20, 0x54, 0x68, 0x65, 0x20, 0x70, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x20, - 0x76, 0x61, 0x6c, 0x75, 0x65, 0x0a, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, 0x01, 0x02, 0x01, - 0x04, 0x12, 0x03, 0x2c, 0x04, 0x0c, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, 0x01, 0x02, 0x01, - 0x05, 0x12, 0x03, 0x2c, 0x0d, 0x13, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, 0x01, 0x02, 0x01, - 0x01, 0x12, 0x03, 0x2c, 0x14, 0x1d, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, 0x01, 0x02, 0x01, - 0x03, 0x12, 0x03, 0x2c, 0x20, 0x21, 0x0a, 0x22, 0x0a, 0x06, 0x04, 0x02, 0x03, 0x01, 0x02, 0x02, - 0x12, 0x03, 0x2e, 0x04, 0x22, 0x1a, 0x13, 0x20, 0x54, 0x68, 0x65, 0x20, 0x75, 0x70, 0x64, 0x61, - 0x74, 0x65, 0x64, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x0a, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, - 0x03, 0x01, 0x02, 0x02, 0x04, 0x12, 0x03, 0x2e, 0x04, 0x0c, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, - 0x03, 0x01, 0x02, 0x02, 0x05, 0x12, 0x03, 0x2e, 0x0d, 0x13, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, - 0x03, 0x01, 0x02, 0x02, 0x01, 0x12, 0x03, 0x2e, 0x14, 0x1d, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, - 0x03, 0x01, 0x02, 0x02, 0x03, 0x12, 0x03, 0x2e, 0x20, 0x21, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x02, - 0x02, 0x00, 0x12, 0x03, 0x31, 0x02, 0x23, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x00, 0x05, - 0x12, 0x03, 0x31, 0x02, 0x08, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x00, 0x01, 0x12, 0x03, - 0x31, 0x09, 0x1e, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x00, 0x03, 0x12, 0x03, 0x31, 0x21, - 0x22, 0x0a, 0x2e, 0x0a, 0x04, 0x04, 0x02, 0x02, 0x01, 0x12, 0x03, 0x33, 0x02, 0x23, 0x1a, 0x21, - 0x20, 0x54, 0x68, 0x65, 0x20, 0x69, 0x6e, 0x62, 0x6f, 0x78, 0x65, 0x73, 0x20, 0x61, 0x64, 0x64, - 0x65, 0x64, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, - 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x01, 0x04, 0x12, 0x03, 0x33, 0x02, 0x0a, 0x0a, - 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x01, 0x06, 0x12, 0x03, 0x33, 0x0b, 0x10, 0x0a, 0x0c, 0x0a, - 0x05, 0x04, 0x02, 0x02, 0x01, 0x01, 0x12, 0x03, 0x33, 0x11, 0x1e, 0x0a, 0x0c, 0x0a, 0x05, 0x04, - 0x02, 0x02, 0x01, 0x03, 0x12, 0x03, 0x33, 0x21, 0x22, 0x0a, 0x30, 0x0a, 0x04, 0x04, 0x02, 0x02, - 0x02, 0x12, 0x03, 0x35, 0x02, 0x25, 0x1a, 0x23, 0x20, 0x54, 0x68, 0x65, 0x20, 0x69, 0x6e, 0x62, - 0x6f, 0x78, 0x65, 0x73, 0x20, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x20, - 0x74, 0x68, 0x65, 0x20, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, - 0x02, 0x02, 0x02, 0x04, 0x12, 0x03, 0x35, 0x02, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, - 0x02, 0x06, 0x12, 0x03, 0x35, 0x0b, 0x10, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x02, 0x01, - 0x12, 0x03, 0x35, 0x11, 0x20, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x02, 0x03, 0x12, 0x03, - 0x35, 0x23, 0x24, 0x0a, 0x31, 0x0a, 0x04, 0x04, 0x02, 0x02, 0x03, 0x12, 0x03, 0x37, 0x02, 0x3a, - 0x1a, 0x24, 0x20, 0x54, 0x68, 0x65, 0x20, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x20, - 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, - 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x03, 0x04, 0x12, - 0x03, 0x37, 0x02, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x03, 0x06, 0x12, 0x03, 0x37, - 0x0b, 0x1e, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x03, 0x01, 0x12, 0x03, 0x37, 0x1f, 0x35, - 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x03, 0x03, 0x12, 0x03, 0x37, 0x38, 0x39, 0x62, 0x06, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x2c, 0x20, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x65, 0x64, 0x20, 0x62, + 0x79, 0x20, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, + 0x02, 0x04, 0x12, 0x03, 0x18, 0x02, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x02, 0x06, + 0x12, 0x03, 0x18, 0x0b, 0x1b, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x02, 0x01, 0x12, 0x03, + 0x18, 0x1c, 0x2f, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x02, 0x03, 0x12, 0x03, 0x18, 0x32, + 0x33, 0x0a, 0x45, 0x0a, 0x04, 0x04, 0x01, 0x02, 0x03, 0x12, 0x03, 0x1a, 0x02, 0x36, 0x1a, 0x38, + 0x20, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x72, + 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6f, + 0x6d, 0x6d, 0x69, 0x74, 0x2c, 0x20, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x65, 0x64, 0x20, 0x62, 0x79, + 0x20, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x03, + 0x04, 0x12, 0x03, 0x1a, 0x02, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x03, 0x06, 0x12, + 0x03, 0x1a, 0x0b, 0x1b, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x03, 0x01, 0x12, 0x03, 0x1a, + 0x1c, 0x31, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x03, 0x03, 0x12, 0x03, 0x1a, 0x34, 0x35, + 0x0a, 0x6b, 0x0a, 0x02, 0x04, 0x02, 0x12, 0x04, 0x21, 0x00, 0x38, 0x01, 0x1a, 0x5f, 0x20, 0x41, + 0x20, 0x73, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x20, 0x69, 0x6e, 0x20, 0x61, 0x20, 0x63, 0x6f, 0x6d, + 0x6d, 0x69, 0x74, 0x2e, 0x0a, 0x20, 0x49, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x73, 0x20, 0x61, + 0x64, 0x64, 0x65, 0x64, 0x2f, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x62, + 0x6f, 0x78, 0x65, 0x73, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x73, + 0x20, 0x74, 0x6f, 0x20, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x0a, 0x0a, 0x0a, 0x0a, + 0x03, 0x04, 0x02, 0x01, 0x12, 0x03, 0x21, 0x08, 0x14, 0x0a, 0x41, 0x0a, 0x04, 0x04, 0x02, 0x03, + 0x00, 0x12, 0x04, 0x23, 0x02, 0x25, 0x03, 0x1a, 0x33, 0x20, 0x41, 0x6e, 0x20, 0x69, 0x6e, 0x62, + 0x6f, 0x78, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x77, 0x61, 0x73, 0x20, 0x61, 0x64, 0x64, 0x65, + 0x64, 0x20, 0x6f, 0x72, 0x20, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x20, + 0x74, 0x68, 0x69, 0x73, 0x20, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, + 0x04, 0x02, 0x03, 0x00, 0x01, 0x12, 0x03, 0x23, 0x0a, 0x0f, 0x0a, 0x0d, 0x0a, 0x06, 0x04, 0x02, + 0x03, 0x00, 0x02, 0x00, 0x12, 0x03, 0x24, 0x04, 0x18, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, + 0x00, 0x02, 0x00, 0x05, 0x12, 0x03, 0x24, 0x04, 0x0a, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, + 0x00, 0x02, 0x00, 0x01, 0x12, 0x03, 0x24, 0x0b, 0x13, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, + 0x00, 0x02, 0x00, 0x03, 0x12, 0x03, 0x24, 0x16, 0x17, 0x0a, 0x3d, 0x0a, 0x04, 0x04, 0x02, 0x03, + 0x01, 0x12, 0x04, 0x28, 0x02, 0x2f, 0x03, 0x1a, 0x2f, 0x20, 0x41, 0x20, 0x73, 0x75, 0x6d, 0x6d, + 0x61, 0x72, 0x79, 0x20, 0x6f, 0x66, 0x20, 0x61, 0x20, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x20, + 0x74, 0x6f, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6d, 0x75, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x6d, + 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x03, 0x01, + 0x01, 0x12, 0x03, 0x28, 0x0a, 0x1d, 0x0a, 0x2b, 0x0a, 0x06, 0x04, 0x02, 0x03, 0x01, 0x02, 0x00, + 0x12, 0x03, 0x2a, 0x04, 0x1a, 0x1a, 0x1c, 0x20, 0x54, 0x68, 0x65, 0x20, 0x66, 0x69, 0x65, 0x6c, + 0x64, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x77, 0x61, 0x73, 0x20, 0x63, 0x68, 0x61, 0x6e, 0x67, + 0x65, 0x64, 0x0a, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, 0x01, 0x02, 0x00, 0x05, 0x12, 0x03, + 0x2a, 0x04, 0x0a, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, 0x01, 0x02, 0x00, 0x01, 0x12, 0x03, + 0x2a, 0x0b, 0x15, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, 0x01, 0x02, 0x00, 0x03, 0x12, 0x03, + 0x2a, 0x18, 0x19, 0x0a, 0x23, 0x0a, 0x06, 0x04, 0x02, 0x03, 0x01, 0x02, 0x01, 0x12, 0x03, 0x2c, + 0x04, 0x22, 0x1a, 0x14, 0x20, 0x54, 0x68, 0x65, 0x20, 0x70, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, + 0x73, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x0a, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, 0x01, + 0x02, 0x01, 0x04, 0x12, 0x03, 0x2c, 0x04, 0x0c, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, 0x01, + 0x02, 0x01, 0x05, 0x12, 0x03, 0x2c, 0x0d, 0x13, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, 0x01, + 0x02, 0x01, 0x01, 0x12, 0x03, 0x2c, 0x14, 0x1d, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x02, 0x03, 0x01, + 0x02, 0x01, 0x03, 0x12, 0x03, 0x2c, 0x20, 0x21, 0x0a, 0x22, 0x0a, 0x06, 0x04, 0x02, 0x03, 0x01, + 0x02, 0x02, 0x12, 0x03, 0x2e, 0x04, 0x22, 0x1a, 0x13, 0x20, 0x54, 0x68, 0x65, 0x20, 0x75, 0x70, + 0x64, 0x61, 0x74, 0x65, 0x64, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x0a, 0x0a, 0x0e, 0x0a, 0x07, + 0x04, 0x02, 0x03, 0x01, 0x02, 0x02, 0x04, 0x12, 0x03, 0x2e, 0x04, 0x0c, 0x0a, 0x0e, 0x0a, 0x07, + 0x04, 0x02, 0x03, 0x01, 0x02, 0x02, 0x05, 0x12, 0x03, 0x2e, 0x0d, 0x13, 0x0a, 0x0e, 0x0a, 0x07, + 0x04, 0x02, 0x03, 0x01, 0x02, 0x02, 0x01, 0x12, 0x03, 0x2e, 0x14, 0x1d, 0x0a, 0x0e, 0x0a, 0x07, + 0x04, 0x02, 0x03, 0x01, 0x02, 0x02, 0x03, 0x12, 0x03, 0x2e, 0x20, 0x21, 0x0a, 0x0b, 0x0a, 0x04, + 0x04, 0x02, 0x02, 0x00, 0x12, 0x03, 0x31, 0x02, 0x23, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, + 0x00, 0x05, 0x12, 0x03, 0x31, 0x02, 0x08, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x00, 0x01, + 0x12, 0x03, 0x31, 0x09, 0x1e, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x00, 0x03, 0x12, 0x03, + 0x31, 0x21, 0x22, 0x0a, 0x2e, 0x0a, 0x04, 0x04, 0x02, 0x02, 0x01, 0x12, 0x03, 0x33, 0x02, 0x23, + 0x1a, 0x21, 0x20, 0x54, 0x68, 0x65, 0x20, 0x69, 0x6e, 0x62, 0x6f, 0x78, 0x65, 0x73, 0x20, 0x61, + 0x64, 0x64, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6f, 0x6d, 0x6d, + 0x69, 0x74, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x01, 0x04, 0x12, 0x03, 0x33, 0x02, + 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x01, 0x06, 0x12, 0x03, 0x33, 0x0b, 0x10, 0x0a, + 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x01, 0x01, 0x12, 0x03, 0x33, 0x11, 0x1e, 0x0a, 0x0c, 0x0a, + 0x05, 0x04, 0x02, 0x02, 0x01, 0x03, 0x12, 0x03, 0x33, 0x21, 0x22, 0x0a, 0x30, 0x0a, 0x04, 0x04, + 0x02, 0x02, 0x02, 0x12, 0x03, 0x35, 0x02, 0x25, 0x1a, 0x23, 0x20, 0x54, 0x68, 0x65, 0x20, 0x69, + 0x6e, 0x62, 0x6f, 0x78, 0x65, 0x73, 0x20, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x20, 0x69, + 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x0a, 0x0a, 0x0c, 0x0a, + 0x05, 0x04, 0x02, 0x02, 0x02, 0x04, 0x12, 0x03, 0x35, 0x02, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, + 0x02, 0x02, 0x02, 0x06, 0x12, 0x03, 0x35, 0x0b, 0x10, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, + 0x02, 0x01, 0x12, 0x03, 0x35, 0x11, 0x20, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x02, 0x03, + 0x12, 0x03, 0x35, 0x23, 0x24, 0x0a, 0x31, 0x0a, 0x04, 0x04, 0x02, 0x02, 0x03, 0x12, 0x03, 0x37, + 0x02, 0x3a, 0x1a, 0x24, 0x20, 0x54, 0x68, 0x65, 0x20, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, + 0x61, 0x20, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x03, + 0x04, 0x12, 0x03, 0x37, 0x02, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x03, 0x06, 0x12, + 0x03, 0x37, 0x0b, 0x1e, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x03, 0x01, 0x12, 0x03, 0x37, + 0x1f, 0x35, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x03, 0x03, 0x12, 0x03, 0x37, 0x38, 0x39, + 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, ]; include!("xmtp.mls.message_contents.serde.rs"); // @@protoc_insertion_point(module) \ No newline at end of file diff --git a/xmtp_proto/src/gen/xmtp.mls.message_contents.serde.rs b/xmtp_proto/src/gen/xmtp.mls.message_contents.serde.rs index a7f5af0e8..b34d3b16a 100644 --- a/xmtp_proto/src/gen/xmtp.mls.message_contents.serde.rs +++ b/xmtp_proto/src/gen/xmtp.mls.message_contents.serde.rs @@ -4063,12 +4063,12 @@ impl serde::Serialize for UserPreferenceUpdate { { use serde::ser::SerializeStruct; let mut len = 0; - if !self.content.is_empty() { + if !self.contents.is_empty() { len += 1; } let mut struct_ser = serializer.serialize_struct("xmtp.mls.message_contents.UserPreferenceUpdate", len)?; - if !self.content.is_empty() { - struct_ser.serialize_field("content", &self.content.iter().map(pbjson::private::base64::encode).collect::>())?; + if !self.contents.is_empty() { + struct_ser.serialize_field("contents", &self.contents.iter().map(pbjson::private::base64::encode).collect::>())?; } struct_ser.end() } @@ -4080,12 +4080,12 @@ impl<'de> serde::Deserialize<'de> for UserPreferenceUpdate { D: serde::Deserializer<'de>, { const FIELDS: &[&str] = &[ - "content", + "contents", ]; #[allow(clippy::enum_variant_names)] enum GeneratedField { - Content, + Contents, } impl<'de> serde::Deserialize<'de> for GeneratedField { fn deserialize(deserializer: D) -> std::result::Result @@ -4107,7 +4107,7 @@ impl<'de> serde::Deserialize<'de> for UserPreferenceUpdate { E: serde::de::Error, { match value { - "content" => Ok(GeneratedField::Content), + "contents" => Ok(GeneratedField::Contents), _ => Err(serde::de::Error::unknown_field(value, FIELDS)), } } @@ -4127,14 +4127,14 @@ impl<'de> serde::Deserialize<'de> for UserPreferenceUpdate { where V: serde::de::MapAccess<'de>, { - let mut content__ = None; + let mut contents__ = None; while let Some(k) = map_.next_key()? { match k { - GeneratedField::Content => { - if content__.is_some() { - return Err(serde::de::Error::duplicate_field("content")); + GeneratedField::Contents => { + if contents__.is_some() { + return Err(serde::de::Error::duplicate_field("contents")); } - content__ = + contents__ = Some(map_.next_value::>>()? .into_iter().map(|x| x.0).collect()) ; @@ -4142,7 +4142,7 @@ impl<'de> serde::Deserialize<'de> for UserPreferenceUpdate { } } Ok(UserPreferenceUpdate { - content: content__.unwrap_or_default(), + contents: contents__.unwrap_or_default(), }) } }