From a806d1ab5609af2d821f6c9ecbded210445e00f5 Mon Sep 17 00:00:00 2001 From: Mitch Gildenberg Date: Fri, 10 Oct 2025 13:59:45 -0400 Subject: [PATCH 1/2] switch to switchboard-on-demand crate --- programs/switchboard-on-demand/.gitignore | 3 + programs/switchboard-on-demand/DOCS.md | 37 + .../switchboard-on-demand/MERGE_COMPLETE.md | 170 + programs/switchboard-on-demand/MIGRATION.md | 171 + programs/switchboard-on-demand/README.md | 120 + programs/switchboard-on-demand/firebase.json | 14 + programs/switchboard-on-demand/package.json | 12 + programs/switchboard-on-demand/rustfmt.toml | 3 + .../scripts/compile_docs.ts | 65 + .../src/account_info_compat.rs | 110 + .../switchboard-on-demand/src/accounts.rs | 1 + .../src/anchor_traits.rs | 48 + .../src/client/accounts/mod.rs | 13 + .../src/client/accounts/oracle_ext.rs | 10 + .../src/client/accounts/pull_feed_ext.rs | 10 + .../src/client/accounts/queue_ext.rs | 196 + .../src/client/accounts/state_ext.rs | 2 + .../src/client/associated_token_account.rs | 71 + .../src/client/crossbar.rs | 558 + .../src/client/gateway.rs | 415 + .../src/client/instructions/mod.rs | 12 + .../pull_feed_submit_response_consensus.rs | 53 + .../pull_feed_submit_response_ix.rs | 63 + .../pull_feed_submit_response_many_ix.rs | 60 + .../src/client/lut_owner.rs | 84 + .../switchboard-on-demand/src/client/mod.rs | 50 + .../src/client/oracle_job.rs | 8475 +++++++++++ .../src/client/oracle_job.serde.rs | 12677 ++++++++++++++++ .../src/client/pull_feed.rs | 596 + .../src/client/recent_slothashes.rs | 47 + .../src/client/secp256k1.rs | 128 + .../src/client/transaction_builder.rs | 856 ++ .../switchboard-on-demand/src/client/utils.rs | 434 + programs/switchboard-on-demand/src/decimal.rs | 230 + .../src/instruction_compat.rs | 144 + .../switchboard-on-demand/src/instructions.rs | 1 + programs/switchboard-on-demand/src/macros.rs | 179 + .../src/on_demand/accounts/mod.rs | 18 + .../src/on_demand/accounts/oracle.rs | 374 + .../src/on_demand/accounts/oracle_stats.rs | 95 + .../src/on_demand/accounts/pull_feed.rs | 496 + .../src/on_demand/accounts/queue.rs | 338 + .../src/on_demand/accounts/randomness.rs | 112 + .../src/on_demand/accounts/state.rs | 131 + .../src/on_demand/error.rs | 178 + .../instructions/guardian_quote_verify.rs | 149 + .../src/on_demand/instructions/mod.rs | 36 + .../instructions/oracle_heartbeat.rs | 180 + .../instructions/oracle_heartbeat_v2.rs | 89 + .../instructions/oracle_reset_lut.rs | 110 + .../instructions/oracle_set_configs.rs | 80 + .../on_demand/instructions/oracle_sync_lut.rs | 163 + .../on_demand/instructions/permission_set.rs | 89 + .../instructions/queue_garbage_collect.rs | 69 + .../instructions/queue_pay_rewards.rs | 133 + .../instructions/queue_pay_subsidy.rs | 163 + .../on_demand/instructions/queue_reset_lut.rs | 150 + .../instructions/randomness_commit.rs | 163 + .../src/on_demand/mod.rs | 87 + .../src/on_demand/oracle_quote/feed_info.rs | 132 + .../src/on_demand/oracle_quote/mod.rs | 55 + .../src/on_demand/oracle_quote/quote.rs | 781 + .../on_demand/oracle_quote/quote_account.rs | 277 + .../on_demand/oracle_quote/quote_verifier.rs | 1302 ++ .../src/on_demand/types.rs | 57 + programs/switchboard-on-demand/src/prelude.rs | 24 + .../switchboard-on-demand/src/program_id.rs | 34 + .../src/solana_compat.rs | 92 + .../src/sysvar/address_lookup_table.rs | 37 + .../switchboard-on-demand/src/sysvar/clock.rs | 63 + .../src/sysvar/ed25519_sysvar.rs | 320 + .../src/sysvar/ix_sysvar.rs | 234 + .../switchboard-on-demand/src/sysvar/mod.rs | 20 + .../src/sysvar/slothash_sysvar.rs | 110 + .../switchboard-on-demand/src/test_ids.rs | 25 + programs/switchboard-on-demand/src/types.rs | 2 + programs/switchboard-on-demand/src/utils.rs | 129 + .../src/v2_client_compat.rs | 105 + rust-toolchain.toml | 3 + 79 files changed, 33323 insertions(+) create mode 100644 programs/switchboard-on-demand/.gitignore create mode 100644 programs/switchboard-on-demand/DOCS.md create mode 100644 programs/switchboard-on-demand/MERGE_COMPLETE.md create mode 100644 programs/switchboard-on-demand/MIGRATION.md create mode 100644 programs/switchboard-on-demand/README.md create mode 100644 programs/switchboard-on-demand/firebase.json create mode 100644 programs/switchboard-on-demand/package.json create mode 100644 programs/switchboard-on-demand/rustfmt.toml create mode 100644 programs/switchboard-on-demand/scripts/compile_docs.ts create mode 100644 programs/switchboard-on-demand/src/account_info_compat.rs create mode 100644 programs/switchboard-on-demand/src/accounts.rs create mode 100644 programs/switchboard-on-demand/src/anchor_traits.rs create mode 100644 programs/switchboard-on-demand/src/client/accounts/mod.rs create mode 100644 programs/switchboard-on-demand/src/client/accounts/oracle_ext.rs create mode 100644 programs/switchboard-on-demand/src/client/accounts/pull_feed_ext.rs create mode 100644 programs/switchboard-on-demand/src/client/accounts/queue_ext.rs create mode 100644 programs/switchboard-on-demand/src/client/accounts/state_ext.rs create mode 100644 programs/switchboard-on-demand/src/client/associated_token_account.rs create mode 100644 programs/switchboard-on-demand/src/client/crossbar.rs create mode 100644 programs/switchboard-on-demand/src/client/gateway.rs create mode 100644 programs/switchboard-on-demand/src/client/instructions/mod.rs create mode 100644 programs/switchboard-on-demand/src/client/instructions/pull_feed_submit_response_consensus.rs create mode 100644 programs/switchboard-on-demand/src/client/instructions/pull_feed_submit_response_ix.rs create mode 100644 programs/switchboard-on-demand/src/client/instructions/pull_feed_submit_response_many_ix.rs create mode 100644 programs/switchboard-on-demand/src/client/lut_owner.rs create mode 100644 programs/switchboard-on-demand/src/client/mod.rs create mode 100644 programs/switchboard-on-demand/src/client/oracle_job.rs create mode 100644 programs/switchboard-on-demand/src/client/oracle_job.serde.rs create mode 100644 programs/switchboard-on-demand/src/client/pull_feed.rs create mode 100644 programs/switchboard-on-demand/src/client/recent_slothashes.rs create mode 100644 programs/switchboard-on-demand/src/client/secp256k1.rs create mode 100644 programs/switchboard-on-demand/src/client/transaction_builder.rs create mode 100644 programs/switchboard-on-demand/src/client/utils.rs create mode 100644 programs/switchboard-on-demand/src/decimal.rs create mode 100644 programs/switchboard-on-demand/src/instruction_compat.rs create mode 100644 programs/switchboard-on-demand/src/instructions.rs create mode 100644 programs/switchboard-on-demand/src/macros.rs create mode 100644 programs/switchboard-on-demand/src/on_demand/accounts/mod.rs create mode 100644 programs/switchboard-on-demand/src/on_demand/accounts/oracle.rs create mode 100644 programs/switchboard-on-demand/src/on_demand/accounts/oracle_stats.rs create mode 100644 programs/switchboard-on-demand/src/on_demand/accounts/pull_feed.rs create mode 100644 programs/switchboard-on-demand/src/on_demand/accounts/queue.rs create mode 100644 programs/switchboard-on-demand/src/on_demand/accounts/randomness.rs create mode 100644 programs/switchboard-on-demand/src/on_demand/accounts/state.rs create mode 100644 programs/switchboard-on-demand/src/on_demand/error.rs create mode 100644 programs/switchboard-on-demand/src/on_demand/instructions/guardian_quote_verify.rs create mode 100644 programs/switchboard-on-demand/src/on_demand/instructions/mod.rs create mode 100644 programs/switchboard-on-demand/src/on_demand/instructions/oracle_heartbeat.rs create mode 100644 programs/switchboard-on-demand/src/on_demand/instructions/oracle_heartbeat_v2.rs create mode 100644 programs/switchboard-on-demand/src/on_demand/instructions/oracle_reset_lut.rs create mode 100644 programs/switchboard-on-demand/src/on_demand/instructions/oracle_set_configs.rs create mode 100644 programs/switchboard-on-demand/src/on_demand/instructions/oracle_sync_lut.rs create mode 100644 programs/switchboard-on-demand/src/on_demand/instructions/permission_set.rs create mode 100644 programs/switchboard-on-demand/src/on_demand/instructions/queue_garbage_collect.rs create mode 100644 programs/switchboard-on-demand/src/on_demand/instructions/queue_pay_rewards.rs create mode 100644 programs/switchboard-on-demand/src/on_demand/instructions/queue_pay_subsidy.rs create mode 100644 programs/switchboard-on-demand/src/on_demand/instructions/queue_reset_lut.rs create mode 100644 programs/switchboard-on-demand/src/on_demand/instructions/randomness_commit.rs create mode 100644 programs/switchboard-on-demand/src/on_demand/mod.rs create mode 100644 programs/switchboard-on-demand/src/on_demand/oracle_quote/feed_info.rs create mode 100644 programs/switchboard-on-demand/src/on_demand/oracle_quote/mod.rs create mode 100644 programs/switchboard-on-demand/src/on_demand/oracle_quote/quote.rs create mode 100644 programs/switchboard-on-demand/src/on_demand/oracle_quote/quote_account.rs create mode 100644 programs/switchboard-on-demand/src/on_demand/oracle_quote/quote_verifier.rs create mode 100644 programs/switchboard-on-demand/src/on_demand/types.rs create mode 100644 programs/switchboard-on-demand/src/prelude.rs create mode 100644 programs/switchboard-on-demand/src/program_id.rs create mode 100644 programs/switchboard-on-demand/src/solana_compat.rs create mode 100644 programs/switchboard-on-demand/src/sysvar/address_lookup_table.rs create mode 100644 programs/switchboard-on-demand/src/sysvar/clock.rs create mode 100644 programs/switchboard-on-demand/src/sysvar/ed25519_sysvar.rs create mode 100644 programs/switchboard-on-demand/src/sysvar/ix_sysvar.rs create mode 100644 programs/switchboard-on-demand/src/sysvar/mod.rs create mode 100644 programs/switchboard-on-demand/src/sysvar/slothash_sysvar.rs create mode 100644 programs/switchboard-on-demand/src/test_ids.rs create mode 100644 programs/switchboard-on-demand/src/types.rs create mode 100644 programs/switchboard-on-demand/src/utils.rs create mode 100644 programs/switchboard-on-demand/src/v2_client_compat.rs create mode 100644 rust-toolchain.toml diff --git a/programs/switchboard-on-demand/.gitignore b/programs/switchboard-on-demand/.gitignore new file mode 100644 index 0000000000..c71a954be4 --- /dev/null +++ b/programs/switchboard-on-demand/.gitignore @@ -0,0 +1,3 @@ +!.env + +doc \ No newline at end of file diff --git a/programs/switchboard-on-demand/DOCS.md b/programs/switchboard-on-demand/DOCS.md new file mode 100644 index 0000000000..139b8929dc --- /dev/null +++ b/programs/switchboard-on-demand/DOCS.md @@ -0,0 +1,37 @@ +# Docs + +## Prerequisites + +To deploy the `switchboard-on-demand` docs site, you will need to install the Firebase CLI and connect your account. + +```bash +curl -sL https://firebase.tools | upgrade=true bash +``` + +After logging in (using `firebase login`), you will also need to make sure that your Firebase account has access to the `switchboard-docs` project: + +```bash +❯ firebase projects:list +✔ Preparing the list of your Firebase projects +┌────────────────────────┬────────────────────────┬────────────────┬──────────────────────┐ +│ Project Display Name │ Project ID │ Project Number │ Resource Location ID │ +├────────────────────────┼────────────────────────┼────────────────┼──────────────────────┤ +│ Switchboard Docs │ switchboard-docs │ 659732266249 │ [Not specified] │ +└────────────────────────┴────────────────────────┴────────────────┴──────────────────────┘ +``` + +If access is needed, contact [Mitch](mailto://mitch@switchboard.xyz) or [Jack](mailto://jack@switchboard.xyz). + +## Generate / Deploy Site + +To deploy the docs for the `switchboard-on-demand` Rust SDK, simply run the following script: + +```bash +# Generates the docs site and opens locally. +pnpm docgen --open + +# Generates the docs site and tries to deploy to Firebase. +# +# Note that you will need to be logged into the Firebase CLI (See above). +pnpm docgen:deploy +``` diff --git a/programs/switchboard-on-demand/MERGE_COMPLETE.md b/programs/switchboard-on-demand/MERGE_COMPLETE.md new file mode 100644 index 0000000000..8ed1c78761 --- /dev/null +++ b/programs/switchboard-on-demand/MERGE_COMPLETE.md @@ -0,0 +1,170 @@ +# ✅ Crate Merge Complete + +## Status: FULLY COMPLETE ✓ + +The `switchboard-on-demand-client` crate has been **successfully merged** into `switchboard-on-demand` under the `client` feature flag. + +## Verification Results + +### ✅ All Build Configurations Pass +```bash +✓ cargo check --no-default-features # On-chain only +✓ cargo check # Default (CPI) +✓ cargo check --features client # Client enabled +✓ cargo check --all-features # Everything +✓ cargo build --release --features client +``` + +### ✅ All Tests Pass +``` +test result: ok. 8 passed; 0 failed; 0 ignored +``` + +### ✅ Code Quality +- Clippy warnings: 11 (all minor, acceptable) +- No compilation errors +- No test failures + +## What Was Merged + +### Files Added (19 files, ~24,800 lines) +``` +src/client/ +├── accounts/ +│ ├── mod.rs +│ ├── oracle.rs +│ ├── pull_feed.rs +│ ├── queue.rs +│ └── state.rs +├── instructions/ +│ ├── mod.rs +│ ├── pull_feed_submit_response_consensus.rs +│ ├── pull_feed_submit_response_ix.rs +│ └── pull_feed_submit_response_many_ix.rs +├── associated_token_account.rs +├── crossbar.rs +├── gateway.rs +├── lut_owner.rs +├── mod.rs +├── oracle_job.rs +├── oracle_job.serde.rs +├── pull_feed.rs +├── recent_slothashes.rs +├── secp256k1.rs +├── transaction_builder.rs +└── utils.rs +``` + +### Files Modified +- `Cargo.toml` - Added client dependencies as optional +- `src/lib.rs` - Added client module with feature gate +- `src/prelude.rs` - Prevented namespace pollution +- `MIGRATION.md` - Created comprehensive migration guide + +### Dependencies Added (Optional, client feature only) +- `anchor-client >= 0.31.1` +- `anchor-lang >= 0.31.1` +- `solana-client >= 1.18` +- `solana-sdk >= 1.18` +- `reqwest 0.11` (rustls) +- `tokio ^1.41` (full) +- `tokio-stream >= 0.1.17` +- `prost 0.13.1` +- `pbjson 0.7.0` +- `dashmap 6.0.1` +- `base64 0.22` +- `base58 0.2.0` +- `bs58 0.4` +- `hex 0.4` +- `serde_json 1.0` +- `switchboard-utils 0.9` +- `lazy_static 1.5.0` + +## Technical Highlights + +### 1. Zero Namespace Pollution +Client types are NOT in the prelude. They must be explicitly imported: +```rust +use switchboard_on_demand::client::{Gateway, PullFeed}; +``` + +### 2. Type Compatibility Layer +- On-chain code uses `solana-program` types (v3 default, v2 via feature) +- Client code uses `anchor_client::solana_sdk` types +- Helper function bridges Pubkey types when needed + +### 3. Feature Flag Architecture +```toml +[features] +default = ["cpi"] +client = [ + "anchor-lang", "anchor-client", "tokio", "tokio-util", "futures", + "arc-swap", "reqwest", "prost", "pbjson", "dashmap", "tokio-stream", + "base58", "bs58", "lazy_static", "solana-client", "solana-sdk", + "hex", "base64", "serde_json", "switchboard-utils" +] +``` + +### 4. Backward Compatibility +- On-chain users: **NO CHANGES** required +- Client users: Import paths change (see MIGRATION.md) + +## Breaking Changes for Client Users + +**Old:** +```rust +use switchboard_on_demand_client::{Gateway, PullFeed}; +``` + +**New:** +```rust +use switchboard_on_demand::client::{Gateway, PullFeed}; +``` + +## Migration Path + +1. **Update Cargo.toml:** + ```diff + - switchboard-on-demand-client = "0.4.1" + + switchboard-on-demand = { version = "0.9.0", features = ["client"] } + ``` + +2. **Update imports:** + - Add `::client` to all import paths + - See `MIGRATION.md` for complete guide + +## Benefits + +✅ **Single Dependency** - One crate instead of two +✅ **Unified Versioning** - Client and on-chain in sync +✅ **Reduced Duplication** - Shared types and utilities +✅ **Better Maintenance** - Single codebase +✅ **Clear Separation** - Feature flags enforce boundaries +✅ **Zero Impact** - On-chain users unaffected + +## Next Steps + +1. ✅ Merge complete - All tests passing +2. ⏳ Update documentation +3. ⏳ Publish new version +4. ⏳ Deprecate old `switchboard-on-demand-client` crate +5. ⏳ Update examples and integration tests + +## Git Commits + +- `071556d7e` - Merge switchboard-on-demand-client into switchboard-on-demand +- `97dfec787` - Fix test compilation: replace new_with_borsh with new_with_bytes + +## Maintainer Notes + +The merge is **production-ready**. All compilation modes work correctly: +- On-chain program builds ✓ +- Client applications build ✓ +- Tests pass ✓ +- No regressions ✓ + +--- + +**Merge completed by:** Claude Code +**Date:** 2025-01-XX +**Status:** ✅ COMPLETE AND VERIFIED \ No newline at end of file diff --git a/programs/switchboard-on-demand/MIGRATION.md b/programs/switchboard-on-demand/MIGRATION.md new file mode 100644 index 0000000000..7bf20264cf --- /dev/null +++ b/programs/switchboard-on-demand/MIGRATION.md @@ -0,0 +1,171 @@ +# Client Crate Merge - Migration Guide + +## Overview + +The `switchboard-on-demand-client` crate has been successfully merged into `switchboard-on-demand` under the `client` feature flag. This consolidates the codebase and simplifies dependency management. + +## What Changed + +### For On-Chain/Program Users (No Changes Required) +If you only use the on-chain functionality (default features), **nothing changes**: + +```toml +[dependencies] +switchboard-on-demand = "0.9.0" +``` + +### For Client Users (Import Path Changes) + +**Old way (separate crate):** +```rust +use switchboard_on_demand_client::{Gateway, PullFeed, CrossbarClient}; +``` + +**New way (unified crate with feature flag):** +```toml +[dependencies] +switchboard-on-demand = { version = "0.9.0", features = ["client"] } +``` + +```rust +use switchboard_on_demand::client::{Gateway, PullFeed, CrossbarClient}; +``` + +## Feature Flags + +- **Default**: `["cpi"]` - On-chain program functionality only +- **`client`**: Enables off-chain client functionality (Gateway, Crossbar, transaction builders, etc.) +- **`anchor`**: Anchor framework integration +- **`devnet`**: Use devnet program IDs +- **`solana-v2`**: Use Solana SDK 2.2.x instead of default 3.0+ (on-chain only) + +### ⚠️ Feature Compatibility + +**Important:** The `solana-v2` and `client` features are **mutually exclusive** and cannot be used together. + +- ✅ `--features client` - Client with Solana v3 (default) +- ✅ `--features solana-v2` - On-chain with Solana v2 +- ❌ `--features solana-v2,client` - **NOT SUPPORTED** + +**Reason:** The client feature depends on `anchor-client` which uses Solana SDK 1.18+, while `solana-v2` uses Solana SDK 2.2.x. These versions have incompatible type signatures. + +## Module Structure + +### Client Module (`client` feature) +``` +switchboard_on_demand::client:: +├── Gateway // Gateway API client +├── CrossbarClient // Crossbar API client +├── PullFeed // Pull feed utilities +├── oracle_job::OracleJob // Oracle job definitions +├── accounts:: // Client-specific account utilities +│ ├── OracleAccountData +│ ├── PullFeedAccountData +│ ├── QueueAccountData +│ └── State +├── instructions:: // Instruction builders +├── lut_owner:: // Lookup table utilities +├── secp256k1:: // Signature verification +├── gateway:: // Gateway functions +└── utils:: // Client utilities +``` + +## Migration Steps + +### 1. Update Cargo.toml +```diff +[dependencies] +- switchboard-on-demand-client = "0.4.1" ++ switchboard-on-demand = { version = "0.9.0", features = ["client"] } +``` + +### 2. Update Imports +```diff +- use switchboard_on_demand_client::{Gateway, PullFeed}; ++ use switchboard_on_demand::client::{Gateway, PullFeed}; + +- use switchboard_on_demand_client::oracle_job::OracleJob; ++ use switchboard_on_demand::client::oracle_job::OracleJob; + +- use switchboard_on_demand_client::accounts::State; ++ use switchboard_on_demand::client::accounts::State; +``` + +### 3. Function and Type Changes + +#### Program ID Helper +The client now has its own version that returns `anchor_lang::prelude::Pubkey`: +```rust +use switchboard_on_demand::get_switchboard_on_demand_program_id; + +// Returns anchor-compatible Pubkey type +let program_id = get_switchboard_on_demand_program_id(); +``` + +#### Constants +Client-specific constants are available at the crate root when `client` feature is enabled: +```rust +use switchboard_on_demand::{LUT_SIGNER_SEED, ORACLE_STATS_SEED}; +``` + +## Key Technical Details + +### Type Compatibility +- Client code uses `anchor_client::solana_sdk` types for compatibility with anchor ecosystem +- On-chain code uses `solana-program` types (version 3.0+ by default, 2.2+ with `solana-v2` feature) +- Helper functions bridge between type systems where needed + +### No Namespace Pollution +Client types are **not** re-exported in the prelude to avoid naming conflicts. Always use explicit imports: +```rust +// ✅ Good +use switchboard_on_demand::client::{Gateway, PullFeed}; + +// ❌ Won't work - client types not in prelude +use switchboard_on_demand::prelude::*; // Only on-chain types +``` + +### Dependency Versions +Client-specific dependencies (when `client` feature is enabled): +- `anchor-client >= 0.31.1` +- `anchor-lang >= 0.31.1` +- `solana-client >= 1.18` +- `solana-sdk >= 1.18` +- `reqwest 0.11` (rustls) +- `tokio ^1.41` (full features) +- `prost 0.13.1` +- `dashmap 6.0.1` +- Plus utilities: `base64`, `hex`, `serde_json`, `switchboard-utils` + +## Benefits of the Merge + +1. **Single Dependency**: One crate instead of two +2. **Unified Versioning**: Client and on-chain code versioned together +3. **Reduced Duplication**: Shared types and utilities +4. **Better Maintenance**: Single codebase, simpler releases +5. **Cleaner Separation**: Feature flags provide clear on-chain vs off-chain distinction + +## Compile Times + +- **Without client feature**: ~same as before (on-chain only) +- **With client feature**: Includes additional dependencies but still reasonable + +## Testing + +Verify your migration: +```bash +# On-chain only +cargo check + +# With client +cargo check --features client + +# All features +cargo check --all-features +``` + +## Support + +For issues or questions: +- GitHub: https://github.com/switchboard-xyz/switchboard-on-demand +- Documentation: https://docs.switchboard.xyz \ No newline at end of file diff --git a/programs/switchboard-on-demand/README.md b/programs/switchboard-on-demand/README.md new file mode 100644 index 0000000000..b39f1c14bc --- /dev/null +++ b/programs/switchboard-on-demand/README.md @@ -0,0 +1,120 @@ +
+ +![Switchboard Logo](https://github.com/switchboard-xyz/core-sdk/raw/main/website/static/img/icons/switchboard/avatar.png) + +# switchboard-on-demand + +> A Rust library for seamless interaction with Switchboard Oracle accounts on the Solana blockchain. + +[![Crates.io](https://img.shields.io/crates/v/switchboard-solana.svg?style=flat-square&logo=rust)](https://crates.io/crates/switchboard-solana) +[![Discord](https://img.shields.io/discord/841525135311634443?label=Discord&logo=discord&logoColor=white&style=flat-square)](https://discord.gg/switchboardxyz) +[![Twitter Follow](https://img.shields.io/twitter/follow/switchboardxyz?style=social)](https://twitter.com/switchboardxyz) + +

+ Switchboard Documentation: docs.switchboard.xyz +
+ Rustdoc: switchboard-on-demand-rust-docs.web.app +

+ +
+ +## Overview + +`switchboard-on-demand` provides Rust developers with an efficient and easy-to-use client for integrating Solana-based oracles from Switchboard into their applications. This library empowers developers to leverage decentralized, trustless, and highly reliable oracle data for various applications, particularly in the DeFi and Web3 spaces. + +## Features + +- **On-Demand Oracle Data**: Fetch real-time, accurate, and tamper-proof data for blockchain applications. +- **Custom Oracle Creation**: Design and deploy your own oracles tailored to your specific data needs. +- **High Fidelity Financial Data**: Ideal for applications requiring precise and dependable financial data. +- **Privacy-Focused**: Operates within confidential runtimes to ensure data integrity and security. + +## Getting Started + +### Prerequisites + +Ensure you have the following installed: +- Rust (latest stable version) +- Cargo +- Solana CLI tools (if interacting directly with the Solana blockchain) + +### Installation + +Add `switchboard-on-demand` to your `Cargo.toml`: + +```toml +[dependencies] +switchboard-on-demand = "0.8.0" +``` + +### Using on chain + +```rust +use switchboard_on_demand::PullFeedAccountData; +use rust_decimal::Decimal; +use solana_program::sysvar::clock::Clock; + +pub fn solana_ix<'a>(mut ctx: Context>, params: Params) -> Result<()> { + // Parse the oracle feed account data + let feed = PullFeedAccountData::parse(ctx.accounts.sb_feed)?; + + // Configure staleness and accuracy requirements + let max_stale_slots = 100; // Maximum slots before data is considered stale + let min_samples = 5; // Minimum oracle samples required for accuracy + + // Get the verified oracle price with enhanced error handling + let price: Decimal = feed.get_value(&Clock::get()?, max_stale_slots, min_samples, true)?; + + msg!("Oracle Price: {}", price); + + Ok(()) +} +``` + +### Oracle Quote Verification + +The library includes advanced oracle quote verification functionality through the `QuoteVerifier` struct. This allows for cryptographically verified data from multiple oracles: + +```rust +use switchboard_on_demand::prelude::*; + +// Configure the verifier with required accounts +let mut verifier = QuoteVerifier::new(); +verifier + .queue(&queue_account) + .slothash_sysvar(&slothash_sysvar) + .ix_sysvar(&instructions_sysvar) + .clock_slot(clock_slot) + .max_age(150); + +// Verify the oracle quote from instruction at index 0 +let quote = verifier.verify_instruction_at(0)?; + +// Access verified feed data +for feed in quote.feeds() { + let feed_id = feed.feed_id(); + let value = feed.value(); + + msg!("Feed {}: {}", feed.hex_id(), value); +} +``` + +### Quote Program Integration + +The library now includes support for the dedicated quote program for oracle-managed updates: + +```rust +use switchboard_on_demand::{QUOTE_PROGRAM_ID, QuoteVerifier}; + +// The quote program ID is available as a constant +let quote_program = QUOTE_PROGRAM_ID; + +// Verify quotes from oracle accounts +let verified_quote = QuoteVerifier::new() + .queue(&queue_account) + .slothash_sysvar(&slothash_sysvar) + .ix_sysvar(&instructions_sysvar) + .clock_slot(clock_slot) + .max_age(150) + .verify_account(&oracle_account)?; +``` diff --git a/programs/switchboard-on-demand/firebase.json b/programs/switchboard-on-demand/firebase.json new file mode 100644 index 0000000000..1558d887cb --- /dev/null +++ b/programs/switchboard-on-demand/firebase.json @@ -0,0 +1,14 @@ +{ + "hosting": [ + { + "site": "switchboard-on-demand-rust-docs", + "public": "doc", + "rewrites": [ + { + "source": "**", + "destination": "index.html" + } + ] + } + ] +} diff --git a/programs/switchboard-on-demand/package.json b/programs/switchboard-on-demand/package.json new file mode 100644 index 0000000000..928c830f45 --- /dev/null +++ b/programs/switchboard-on-demand/package.json @@ -0,0 +1,12 @@ +{ + "name": "switchboard-on-demand-rust-docs", + "scripts": { + "docgen": "cargo doc --all-features --no-deps", + "docgen:compile": "pnpm docgen && ts-node ./scripts/compile_docs.ts", + "docgen:deploy": "pnpm docgen:compile && cd target && firebase deploy --project docs --only hosting:switchboard-on-demand-rust-docs" + }, + "dependencies": { + "@types/fs-extra": "^11.0.4", + "fs-extra": "^11.2.0" + } +} diff --git a/programs/switchboard-on-demand/rustfmt.toml b/programs/switchboard-on-demand/rustfmt.toml new file mode 100644 index 0000000000..36fb37ff95 --- /dev/null +++ b/programs/switchboard-on-demand/rustfmt.toml @@ -0,0 +1,3 @@ +reorder_imports = true +imports_granularity = "Module" +group_imports = "StdExternalCrate" diff --git a/programs/switchboard-on-demand/scripts/compile_docs.ts b/programs/switchboard-on-demand/scripts/compile_docs.ts new file mode 100644 index 0000000000..69d107df9f --- /dev/null +++ b/programs/switchboard-on-demand/scripts/compile_docs.ts @@ -0,0 +1,65 @@ +import { exec } from "child_process"; +import * as fs from "fs-extra"; +import path from "path"; + +type Replaces = { files: number }; + +async function replaceInFiles( + dir: string, + searchValue: string, + replaceValue: string +): Promise { + try { + const files = await fs.readdir(dir); + for (const file of files) { + const filePath = path.join(dir, file); + const stats = await fs.stat(filePath); + if (stats.isFile()) { + let content = await fs.readFile(filePath, "utf-8"); + content = content.replace(new RegExp(searchValue, "g"), replaceValue); + await fs.writeFile(filePath, content); + } else if (stats.isDirectory()) { + await replaceInFiles(filePath, searchValue, replaceValue); + } + } + } catch (error) { + console.error(`Error: ${error}`); + } +} + +(async () => { + // Copy docs site from ./target/doc to ./doc + const IN_DIR = path.join(__dirname, "../target/doc"); + const OUT_DIR = path.join(__dirname, "../doc"); + await fs.removeSync(OUT_DIR); + await fs.copy(IN_DIR, OUT_DIR, { overwrite: true }); + + // Remove the ../doc/crates.js file + await fs.remove(path.join(OUT_DIR, "crates.js")); + + // Find each file in ./doc/switchboard_on_demand and replace all "../static.files" with "static.files" + const SRC_DIR = path.join(OUT_DIR, "switchboard_on_demand"); + await replaceInFiles(SRC_DIR, "../static.files", "static.files"); + await replaceInFiles(SRC_DIR, "../src", "src"); + await replaceInFiles( + SRC_DIR, + "/switchboard_on_demand/index.html", + "/index.html" + ); + + // Find each file in ./doc/static.files and update search results. + const STATIC_DIR = path.join(OUT_DIR, "static.files"); + await replaceInFiles( + STATIC_DIR, + "link.href=item.href;", + `link.href=item.href.replace(/^\\.\\.\\/switchboard_on_demand\\//, '../');` + ); + + // Move contents of ./doc/switchboard_on_demand/ to ./doc + await fs.copy(SRC_DIR, OUT_DIR); + await fs.remove(SRC_DIR); + + // Need to use bash to copy over the font files. Using fs to do so was corrupting the woff2 files. + const STATIC_IN = path.join(IN_DIR, "static.files/*.woff2"); + exec(`cp ${STATIC_IN} ${STATIC_DIR}`); +})(); diff --git a/programs/switchboard-on-demand/src/account_info_compat.rs b/programs/switchboard-on-demand/src/account_info_compat.rs new file mode 100644 index 0000000000..c3717579f7 --- /dev/null +++ b/programs/switchboard-on-demand/src/account_info_compat.rs @@ -0,0 +1,110 @@ +//! Compatibility layer for different AccountInfo types +//! +//! This module provides compatibility between different AccountInfo implementations, +//! using pinocchio AccountInfo internally when the pinocchio feature is enabled, +//! otherwise falling back to anchor/solana-program AccountInfo types. + +// Use pinocchio AccountInfo when the feature is enabled for better performance +#[cfg(feature = "pinocchio")] +pub type AccountInfo = pinocchio::account_info::AccountInfo; + +// Otherwise use the appropriate AccountInfo type based on anchor feature +#[cfg(all(not(feature = "pinocchio"), feature = "anchor"))] +pub type AccountInfo<'a> = anchor_lang::prelude::AccountInfo<'a>; + +#[cfg(all(not(feature = "pinocchio"), not(feature = "anchor")))] +pub type AccountInfo<'a> = crate::solana_program::account_info::AccountInfo<'a>; + +/// Trait for types that can be converted to a reference to AccountInfo +#[cfg(feature = "pinocchio")] +pub trait AsAccountInfo<'a> { + fn as_account_info(&self) -> &AccountInfo; +} + +#[cfg(not(feature = "pinocchio"))] +pub trait AsAccountInfo<'a> { + fn as_account_info(&self) -> &AccountInfo<'a>; +} + +/// Implementation for the primary AccountInfo type +#[cfg(feature = "pinocchio")] +impl<'a> AsAccountInfo<'a> for AccountInfo { + #[inline(always)] + fn as_account_info(&self) -> &AccountInfo { + self + } +} + +#[cfg(not(feature = "pinocchio"))] +impl<'a> AsAccountInfo<'a> for AccountInfo<'a> { + #[inline(always)] + fn as_account_info(&self) -> &AccountInfo<'a> { + self + } +} + +/// Implementation for references to AccountInfo +#[cfg(feature = "pinocchio")] +impl<'a> AsAccountInfo<'a> for &AccountInfo { + #[inline(always)] + fn as_account_info(&self) -> &AccountInfo { + self + } +} + +#[cfg(not(feature = "pinocchio"))] +impl<'a> AsAccountInfo<'a> for &AccountInfo<'a> { + #[inline(always)] + fn as_account_info(&self) -> &AccountInfo<'a> { + self + } +} + +/// Helper macro to abstract field access differences between AccountInfo types +#[cfg(feature = "pinocchio")] +#[macro_export] +macro_rules! get_account_key { + ($account:expr) => { + $account.key() + }; +} + +#[cfg(not(feature = "pinocchio"))] +#[macro_export] +macro_rules! get_account_key { + ($account:expr) => { + $account.key + }; +} + +#[cfg(feature = "pinocchio")] +#[macro_export] +macro_rules! borrow_account_data { + ($account:expr) => { + $account.borrow_data_unchecked() + }; +} + +#[cfg(not(feature = "pinocchio"))] +#[macro_export] +macro_rules! borrow_account_data { + ($account:expr) => { + $account.data.borrow() + }; +} + +#[cfg(feature = "pinocchio")] +#[macro_export] +macro_rules! borrow_mut_account_data { + ($account:expr) => { + unsafe { $account.borrow_mut_data_unchecked() } + }; +} + +#[cfg(not(feature = "pinocchio"))] +#[macro_export] +macro_rules! borrow_mut_account_data { + ($account:expr) => { + $account.data.borrow_mut() + }; +} diff --git a/programs/switchboard-on-demand/src/accounts.rs b/programs/switchboard-on-demand/src/accounts.rs new file mode 100644 index 0000000000..2a208b9970 --- /dev/null +++ b/programs/switchboard-on-demand/src/accounts.rs @@ -0,0 +1 @@ +pub use crate::on_demand::accounts::*; diff --git a/programs/switchboard-on-demand/src/anchor_traits.rs b/programs/switchboard-on-demand/src/anchor_traits.rs new file mode 100644 index 0000000000..b50db25d40 --- /dev/null +++ b/programs/switchboard-on-demand/src/anchor_traits.rs @@ -0,0 +1,48 @@ +use borsh::BorshSerialize; +use solana_program::instruction::AccountMeta; + +use crate::{solana_program, Pubkey}; + +/// Traits pulled out of anchor-lang library to remove dependency conflicts +/// for users. +pub trait Discriminator { + /// The 8-byte discriminator used to identify the account or instruction type + const DISCRIMINATOR: &'static [u8]; + + /// Returns the discriminator for this type + fn discriminator() -> &'static [u8] { + Self::DISCRIMINATOR + } +} + +/// Trait for types that have an owner program +pub trait Owner { + /// Returns the program ID that owns this account type + fn owner() -> Pubkey; +} + +/// Trait marker for zero-copy deserialization +pub trait ZeroCopy {} + +/// Trait for converting types to Solana account metas +pub trait ToAccountMetas { + /// `is_signer` is given as an optional override for the signer meta field. + /// This covers the edge case when a program-derived-address needs to relay + /// a transaction from a client to another program but sign the transaction + /// before the relay. The client cannot mark the field as a signer, and so + /// we have to override the is_signer meta field given by the client. + fn to_account_metas(&self, is_signer: Option) -> Vec; +} + +/// Calculates the data for an instruction invocation, where the data is +/// `Sha256(:)[..8] || BorshSerialize(args)`. +/// `args` is a borsh serialized struct of named fields for each argument given +/// to an instruction. +pub trait InstructionData: Discriminator + BorshSerialize { + /// Serializes the instruction data with discriminator prefix + fn data(&self) -> Vec { + let mut d = Self::DISCRIMINATOR.to_vec(); + d.append(&mut borsh::to_vec(self).expect("Should always serialize")); + d + } +} diff --git a/programs/switchboard-on-demand/src/client/accounts/mod.rs b/programs/switchboard-on-demand/src/client/accounts/mod.rs new file mode 100644 index 0000000000..78f4714234 --- /dev/null +++ b/programs/switchboard-on-demand/src/client/accounts/mod.rs @@ -0,0 +1,13 @@ +// Re-export from on_demand/accounts which have the complete definitions +pub use crate::on_demand::accounts::{ + OracleAccountData, State, StateEpochInfo, PullFeedAccountData, QueueAccountData, +}; +pub use crate::on_demand::types::Quote; + +// Client-specific extensions remain in this module +mod oracle_ext; +mod pull_feed_ext; +mod queue_ext; +mod state_ext; + +pub use queue_ext::{Queue}; // Export the Queue wrapper struct diff --git a/programs/switchboard-on-demand/src/client/accounts/oracle_ext.rs b/programs/switchboard-on-demand/src/client/accounts/oracle_ext.rs new file mode 100644 index 0000000000..a992294ad2 --- /dev/null +++ b/programs/switchboard-on-demand/src/client/accounts/oracle_ext.rs @@ -0,0 +1,10 @@ +// Client-specific extensions for OracleAccountData +use super::super::lut_owner::LutOwner; +use crate::on_demand::accounts::OracleAccountData; + +// Client-specific trait implementation +impl LutOwner for OracleAccountData { + fn lut_slot(&self) -> u64 { + self.lut_slot + } +} diff --git a/programs/switchboard-on-demand/src/client/accounts/pull_feed_ext.rs b/programs/switchboard-on-demand/src/client/accounts/pull_feed_ext.rs new file mode 100644 index 0000000000..207b6ad5d7 --- /dev/null +++ b/programs/switchboard-on-demand/src/client/accounts/pull_feed_ext.rs @@ -0,0 +1,10 @@ +// Client-specific extensions for PullFeedAccountData +use super::super::lut_owner::LutOwner; +use crate::on_demand::accounts::PullFeedAccountData; + +// Client-specific trait implementation +impl LutOwner for PullFeedAccountData { + fn lut_slot(&self) -> u64 { + self.lut_slot + } +} diff --git a/programs/switchboard-on-demand/src/client/accounts/queue_ext.rs b/programs/switchboard-on-demand/src/client/accounts/queue_ext.rs new file mode 100644 index 0000000000..023aae41d9 --- /dev/null +++ b/programs/switchboard-on-demand/src/client/accounts/queue_ext.rs @@ -0,0 +1,196 @@ +// Client-specific extensions for QueueAccountData +use super::super::lut_owner::LutOwner; +use super::super::gateway::Gateway; +use super::super::crossbar::CrossbarClient; +use crate::on_demand::accounts::QueueAccountData; +use crate::RpcClient; +use crate::Pubkey; +use anyhow::{anyhow, Context}; +use anyhow::Error as AnyhowError; +use futures::future::join_all; + +// Client-specific trait implementation +impl LutOwner for QueueAccountData { + fn lut_slot(&self) -> u64 { + self.lut_slot + } +} + +impl QueueAccountData { + /// Loads queue data from on-chain + pub async fn load(client: &RpcClient, key: &Pubkey) -> Result { + let key_anchor: anchor_client::solana_sdk::pubkey::Pubkey = key.to_bytes().into(); + let account = client + .get_account_data(&key_anchor) + .await + .map_err(|_| anyhow!("QueueAccountData.load: Account not found"))?; + let buf = account[8..].to_vec(); + let parsed: &QueueAccountData = bytemuck::try_from_bytes(&buf) + .map_err(|e| anyhow!("Failed to parse QueueAccountData: {:?}", e))?; + Ok(*parsed) + } + + /// Fetches all gateways from the oracle accounts and tests them to see if they are reachable. + /// Returns a list of reachable gateways. + /// # Arguments + /// * `client` - The RPC client to use for fetching the oracle accounts. + /// # Returns + /// A list of reachable gateways. + pub async fn fetch_gateways(&self, client: &RpcClient) -> Result, AnyhowError> { + let oracles = self.fetch_oracles(client).await?; + let gateways = oracles + .into_iter() + .map(|x| x.1) + .filter_map(|x| x.gateway_uri()) + .map(Gateway::new) + .collect::>(); + + let mut test_futures = Vec::new(); + for gateway in gateways.iter() { + test_futures.push(gateway.test_gateway()); + } + let results = join_all(test_futures).await; + let mut good_gws = Vec::new(); + for (i, is_good) in results.into_iter().enumerate() { + if is_good { + good_gws.push(gateways[i].clone()); + } + } + Ok(good_gws) + } + + /// Fetches a gateway from the crossbar service + /// + /// # Arguments + /// * `crossbar` - The crossbar client to use for fetching gateways + /// + /// # Returns + /// * `Result` - A Gateway instance ready for use + pub async fn fetch_gateway_from_crossbar(&self, crossbar: &CrossbarClient) -> Result { + // Default to mainnet, but this could be made configurable + let network = "mainnet"; + + // Fetch gateways for the network + let gateways = crossbar.fetch_gateways(network).await + .context("Failed to fetch gateways from crossbar")?; + + let gateway_url = gateways + .first() + .ok_or_else(|| anyhow!("No gateways available for network: {}", network))?; + + Ok(Gateway::new(gateway_url.clone())) + } +} + +/// Higher-level Queue struct that matches the JavaScript pattern +/// +/// This struct represents a queue instance with a specific pubkey, +/// similar to the JavaScript Queue class which has a program and pubkey. +pub struct Queue { + pub pubkey: Pubkey, + pub client: RpcClient, +} + +impl Queue { + /// Default devnet queue key + pub const DEFAULT_DEVNET_KEY: &'static str = "EYiAmGSdsQTuCw413V5BzaruWuCCSDgTPtBGvLkXHbe7"; + + /// Default mainnet queue key + pub const DEFAULT_MAINNET_KEY: &'static str = "A43DyUGA7s8eXPxqEjJY6EBu1KKbNgfxF8h17VAHn13w"; + + /// Creates a new Queue instance + /// + /// # Arguments + /// * `client` - RPC client for Solana connections + /// * `pubkey` - The public key of the queue account + pub fn new(client: RpcClient, pubkey: Pubkey) -> Self { + Self { pubkey, client } + } + + /// Creates a Queue instance with the default mainnet key + /// + /// # Arguments + /// * `client` - RPC client for Solana connections + pub fn default_mainnet(client: RpcClient) -> Result { + let pubkey_str = Self::DEFAULT_MAINNET_KEY; + let bytes: [u8; 32] = bs58::decode(pubkey_str) + .into_vec() + .map_err(|e| anyhow!("Failed to decode mainnet queue key: {}", e))? + .try_into() + .map_err(|_| anyhow!("Invalid mainnet queue key length"))?; + let pubkey = Pubkey::new_from_array(bytes); + Ok(Self::new(client, pubkey)) + } + + /// Creates a Queue instance with the default devnet key + /// + /// # Arguments + /// * `client` - RPC client for Solana connections + pub fn default_devnet(client: RpcClient) -> Result { + let pubkey_str = Self::DEFAULT_DEVNET_KEY; + let bytes: [u8; 32] = bs58::decode(pubkey_str) + .into_vec() + .map_err(|e| anyhow!("Failed to decode devnet queue key: {}", e))? + .try_into() + .map_err(|_| anyhow!("Invalid devnet queue key length"))?; + let pubkey = Pubkey::new_from_array(bytes); + Ok(Self::new(client, pubkey)) + } + + /// Loads the queue data from on-chain + /// + /// # Returns + /// * `Result` - The queue account data + pub async fn load_data(&self) -> Result { + QueueAccountData::load(&self.client, &self.pubkey).await + } + + /// Fetches a gateway from the crossbar service, automatically detecting network + /// + /// This method matches the JavaScript implementation exactly: + /// 1. Tries to load data from the default mainnet queue + /// 2. If that fails, assumes devnet + /// 3. Fetches available gateways for the detected network + /// 4. Returns the first gateway + /// + /// # Arguments + /// * `crossbar` - The crossbar client to use for fetching gateways + /// + /// # Returns + /// * `Result` - A Gateway instance ready for use + /// + /// # Example + /// ```rust,no_run + /// use switchboard_on_demand::client::{CrossbarClient, Queue}; + /// use switchboard_on_demand::RpcClient; + /// + /// # async fn example() -> Result<(), Box> { + /// let client = RpcClient::new("https://api.mainnet-beta.solana.com".to_string()); + /// let queue = Queue::default_mainnet(client)?; + /// let crossbar = CrossbarClient::default(); + /// let gateway = queue.fetch_gateway_from_crossbar(&crossbar).await?; + /// # Ok(()) + /// # } + /// ``` + pub async fn fetch_gateway_from_crossbar(&self, crossbar: &CrossbarClient) -> Result { + let mut network = "mainnet"; + + // Try to load data from the default mainnet queue to detect network + let mainnet_client = RpcClient::new(self.client.url()); + let mainnet_queue = Queue::default_mainnet(mainnet_client)?; + + if mainnet_queue.load_data().await.is_err() { + network = "devnet"; + } + + // Fetch gateways for the detected network + let gateways = crossbar.fetch_gateways(network).await + .context("Failed to fetch gateways from crossbar")?; + + let gateway_url = gateways + .first() + .ok_or_else(|| anyhow!("No gateways available for network: {}", network))?; + + Ok(Gateway::new(gateway_url.clone())) + } +} diff --git a/programs/switchboard-on-demand/src/client/accounts/state_ext.rs b/programs/switchboard-on-demand/src/client/accounts/state_ext.rs new file mode 100644 index 0000000000..a1e3468d98 --- /dev/null +++ b/programs/switchboard-on-demand/src/client/accounts/state_ext.rs @@ -0,0 +1,2 @@ +// Client-specific extensions for State +// All state definitions are in on_demand/accounts/state.rs diff --git a/programs/switchboard-on-demand/src/client/associated_token_account.rs b/programs/switchboard-on-demand/src/client/associated_token_account.rs new file mode 100644 index 0000000000..d304a6bb00 --- /dev/null +++ b/programs/switchboard-on-demand/src/client/associated_token_account.rs @@ -0,0 +1,71 @@ +use lazy_static::lazy_static; +use crate::Pubkey; +use std::str::FromStr; + +lazy_static! { + pub static ref SPL_TOKEN_PROGRAM_ID: Pubkey = + Pubkey::from_str("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA").unwrap(); + pub static ref SPL_ASSOCIATED_TOKEN_ACCOUNT_PROGRAM_ID: Pubkey = + Pubkey::from_str("ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL").unwrap(); + pub static ref NATIVE_MINT: Pubkey = + Pubkey::from_str("So11111111111111111111111111111111111111112").unwrap(); +} + +pub fn get_associated_token_address_and_bump_seed( + wallet_address: &Pubkey, + token_mint_address: &Pubkey, + program_id: &Pubkey, + token_program_id: &Pubkey, +) -> (Pubkey, u8) { + get_associated_token_address_and_bump_seed_internal( + wallet_address, + token_mint_address, + program_id, + token_program_id, + ) +} + +/// Derives the associated token account address for the given wallet address +/// and token mint +pub fn get_associated_token_address( + wallet_address: &Pubkey, + token_mint_address: &Pubkey, +) -> Pubkey { + get_associated_token_address_with_program_id( + wallet_address, + token_mint_address, + &SPL_TOKEN_PROGRAM_ID, + ) +} + +/// Derives the associated token account address for the given wallet address, +/// token mint and token program id +pub fn get_associated_token_address_with_program_id( + wallet_address: &Pubkey, + token_mint_address: &Pubkey, + token_program_id: &Pubkey, +) -> Pubkey { + get_associated_token_address_and_bump_seed( + wallet_address, + token_mint_address, + &SPL_ASSOCIATED_TOKEN_ACCOUNT_PROGRAM_ID, + token_program_id, + ) + .0 +} + +fn get_associated_token_address_and_bump_seed_internal( + wallet_address: &Pubkey, + token_mint_address: &Pubkey, + program_id: &Pubkey, + token_program_id: &Pubkey, +) -> (Pubkey, u8) { + Pubkey::find_program_address( + &[ + &wallet_address.to_bytes(), + &token_program_id.to_bytes(), + &token_mint_address.to_bytes(), + ], + program_id, + ) +} diff --git a/programs/switchboard-on-demand/src/client/crossbar.rs b/programs/switchboard-on-demand/src/client/crossbar.rs new file mode 100644 index 0000000000..4d25e027df --- /dev/null +++ b/programs/switchboard-on-demand/src/client/crossbar.rs @@ -0,0 +1,558 @@ +#![allow(non_snake_case)] +use anyhow::anyhow; +use anyhow::Context; +use anyhow::Error as AnyhowError; +use base58::ToBase58; +use futures::{Stream, StreamExt}; +use hex; +use reqwest::Client; +use rust_decimal::Decimal; +use serde::de::Error as DeError; +use serde::{Deserialize, Deserializer, Serialize}; +use anchor_client::solana_sdk::genesis_config::ClusterType; +use crate::Pubkey; +use switchboard_utils::utils::median; +use tokio::time::interval; +use tokio::time::Duration; +use tokio_stream::wrappers::IntervalStream; + +#[derive(Serialize, Deserialize)] +pub struct StoreResponse { + pub cid: String, + pub feedHash: String, + pub queueHex: String, +} + +#[derive(Serialize, Deserialize)] +pub struct FetchSolanaUpdatesResponse { + pub success: bool, + pub pullIx: String, + pub responses: Vec, + pub lookupTables: Vec, +} + +#[derive(Serialize, Deserialize)] +pub struct Response { + pub oracle: String, + pub result: Option, + pub errors: String, +} + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct SimulateSolanaFeedsResponse { + pub feed: String, + pub feedHash: String, + pub results: Vec>, + #[serde(skip_deserializing, default)] + pub result: Option, +} + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct SimulateSuiFeedsResponse { + pub feed: String, + pub feedHash: String, + // The TS endpoint returns the results as strings. You can choose to parse them into Decimal if desired. + pub results: Vec, + // The result is already computed by the server; hence, no median calculation here. + #[serde(skip_deserializing, default)] + pub result: Option, + #[serde(default)] + pub stdev: Option, + #[serde(default)] + pub variance: Option, +} + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct SimulateFeedsResponse { + pub feedHash: String, + pub results: Vec, + #[serde(skip_deserializing, default)] + pub result: Decimal, +} + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct SuiOracleResult { + pub successValue: String, + pub isNegative: bool, + pub timestamp: u64, + pub oracleId: String, + #[serde(serialize_with = "bytes_to_hex", deserialize_with = "hex_to_bytes")] + pub signature: Vec, +} + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct SuiFeedConfigs { + pub feedHash: String, + pub maxVariance: u64, + pub minResponses: u64, + pub minSampleSize: u64, +} + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct SuiUpdateResponse { + pub aggregator_id: Option, + pub results: Vec, + pub feedConfigs: SuiFeedConfigs, + pub queue: String, + pub fee: u64, + pub failures: Vec, +} + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct FetchSuiUpdatesResponse { + pub responses: Vec, + pub failures: Vec, +} + +#[derive(Clone, Debug)] +pub struct CrossbarClient { + crossbar_url: String, + verbose: bool, + client: Client, +} + +fn hex_to_bytes<'de, D>(deserializer: D) -> Result, D::Error> +where + D: Deserializer<'de>, +{ + let s: String = Deserialize::deserialize(deserializer)?; + hex::decode(&s).map_err(DeError::custom) +} + +fn bytes_to_hex(bytes: &Vec, serializer: S) -> Result +where + S: serde::Serializer, +{ + // Convert the byte vector into a hex string. + let hex_string = hex::encode(bytes); + serializer.serialize_str(&hex_string) +} + +fn cluster_type_to_string(cluster_type: ClusterType) -> String { + match cluster_type { + ClusterType::MainnetBeta => "mainnet-beta", + ClusterType::Testnet => "testnet", + ClusterType::Devnet => "devnet", + ClusterType::Development => "development", + } + .to_string() +} + +impl Default for CrossbarClient { + fn default() -> Self { + Self::new("https://crossbar.switchboard.xyz", false) + } +} + +impl CrossbarClient { + pub fn new(crossbar_url: &str, verbose: bool) -> Self { + Self { + crossbar_url: crossbar_url.to_string(), + verbose, + client: Client::new(), + } + } + + /// # Arguments + /// * `feed_hash` - The feed hash of the jobs it performs + /// # Returns + /// * `Result` - The response from the crossbar gateway, + /// containing the json formatted oracle jobs + pub async fn fetch(&self, feed_hash: &str) -> Result { + let url = format!("{}/fetch/{}", self.crossbar_url, feed_hash); + let resp = self + .client + .get(&url) + .send() + .await + .context("Failed to send fetch request")?; + + let status = resp.status(); + if !status.is_success() { + if self.verbose { + eprintln!("{}", resp.text().await.context("Failed to fetch response")?); + } + return Err(anyhow!("Bad status code {}", status.as_u16())); + } + + resp.json().await.context("Failed to parse response") + } + + /// Store feed jobs in the crossbar gateway to a pinned IPFS address + pub async fn store( + &self, + queue_address: Pubkey, + jobs: &[serde_json::Value], + ) -> Result { + let queue = bs58::decode(queue_address.to_string()) + .into_vec() + .context("Failed to decode queue address")?; + let queue_hex = queue.to_base58(); + let payload = serde_json::json!({ "queue": queue_hex, "jobs": jobs }); + + let url = format!("{}/store", self.crossbar_url); + let resp = self + .client + .post(&url) + .json(&payload) + .header("Content-Type", "application/json") + .send() + .await + .context("Failed to send store request")?; + + let status = resp.status(); + if !status.is_success() { + if self.verbose { + eprintln!( + "{}: {}", + status, + resp.text().await.context("Failed to fetch response")? + ); + } + return Err(anyhow!("Bad status code {}", status.as_u16())); + } + + resp.json().await.context("Failed to parse response") + } + + pub async fn fetch_solana_updates( + &self, + network: ClusterType, + feed_pubkeys: &[Pubkey], + num_signatures: Option, + ) -> Result, AnyhowError> { + if feed_pubkeys.is_empty() { + return Err(anyhow!("Feed pubkeys are empty")); + } + + let feeds_param: Vec<_> = feed_pubkeys.iter().map(|x| x.to_string()).collect(); + let feeds_param = feeds_param.join(","); + let network = cluster_type_to_string(network); + let mut url = format!( + "{}/updates/solana/{}/{}", + self.crossbar_url, network, feeds_param + ); + if let Some(num_signatures) = num_signatures { + url.push_str(&format!("?numSignatures={}", num_signatures)); + } + + let resp = self.client.get(&url).send().await?; + + let status = resp.status(); + if !status.is_success() { + if self.verbose { + eprintln!( + "{}: {}", + status, + resp.text().await.context("Failed to fetch response")? + ); + } + return Err(anyhow!("Bad status code {}", status.as_u16())); + } + + resp.json().await.context("Failed to parse response") + } + + /// Simulate feed responses from the crossbar gateway for Solana feeds. + /// In addition to deserializing the JSON, compute the median for each response + /// and store it in the `result` field as an Option. + pub async fn simulate_solana_feeds( + &self, + network: ClusterType, + feed_pubkeys: &[Pubkey], + ) -> Result, AnyhowError> { + if feed_pubkeys.is_empty() { + return Err(anyhow!("Feed pubkeys are empty")); + } + + let feeds_param: Vec<_> = feed_pubkeys.iter().map(|x| x.to_string()).collect(); + let feeds_param = feeds_param.join(","); + let network = cluster_type_to_string(network); + let url = format!( + "{}/simulate/solana/{}/{}", + self.crossbar_url, network, feeds_param + ); + let resp = self.client.get(&url).send().await?; + + let status = resp.status(); + let raw = resp.text().await.context("Failed to fetch response")?; + if !status.is_success() { + if self.verbose { + eprintln!("{}: {}", status, raw); + } + return Err(anyhow!("Bad status code {}", status.as_u16())); + } + + let mut responses: Vec = serde_json::from_str(&raw)?; + // Compute the median result for each response + for response in responses.iter_mut() { + // Collect non-None decimals + let valid: Vec = response.results.iter().filter_map(|x| *x).collect(); + response.result = if valid.is_empty() { + None + } else { + Some(median(valid).expect("Failed to compute median")) + }; + } + Ok(responses) + } + + /// Simulate feed responses from the crossbar gateway. + /// In addition to deserializing the JSON, compute the median for each response + /// and store it in the `result` field. + pub async fn simulate_feeds( + &self, + feed_hashes: &[&str], + ) -> Result, AnyhowError> { + if feed_hashes.is_empty() { + return Err(anyhow!("Feed hashes are empty")); + } + + let feeds_param = feed_hashes.join(","); + let url = format!("{}/simulate/{}", self.crossbar_url, feeds_param); + let resp = self + .client + .get(&url) + .send() + .await + .context("Failed to send simulate feeds request")?; + + let status = resp.status(); + if !status.is_success() { + if self.verbose { + eprintln!( + "{}: {}", + status, + resp.text().await.context("Failed to fetch response")? + ); + } + return Err(anyhow!("Bad status code {}", status.as_u16())); + } + + let mut responses: Vec = + resp.json().await.context("Failed to parse response")?; + // Compute the median result for each response + for response in responses.iter_mut() { + response.result = median(response.results.clone()).expect("Failed to compute median"); + } + Ok(responses) + } + + /// Fetch the Sui feed update from the crossbar gateway. + /// + /// # Arguments + /// * `network` - The Sui network identifier (e.g., "mainnet", "testnet") + /// * `aggregator_addresses` - A slice of aggregator address strings. + /// + /// # Returns + /// * `Result` - The response containing Sui feed update data. + pub async fn fetch_sui_updates( + &self, + network: &str, + aggregator_addresses: &[&str], + ) -> Result { + if aggregator_addresses.is_empty() { + return Err(anyhow!("Aggregator addresses are empty")); + } + let feeds_param = aggregator_addresses.join(","); + let url = format!( + "{}/updates/sui/{}/{}", + self.crossbar_url, network, feeds_param + ); + let resp = self + .client + .get(&url) + .send() + .await + .context("Failed to send fetch Sui updates request")?; + let status = resp.status(); + if !status.is_success() { + if self.verbose { + eprintln!( + "{}: {}", + status, + resp.text().await.context("Failed to fetch response text")? + ); + } + return Err(anyhow!("Bad status code {}", status.as_u16())); + } + let mut update_response: FetchSuiUpdatesResponse = resp + .json() + .await + .context("Failed to parse fetch Sui updates response")?; + + // If the server did not include aggregator_id or it is empty, + // and if the number of responses matches the number of aggregator_addresses, + // we assign the aggregator addresses to the corresponding responses. + if update_response.responses.len() == aggregator_addresses.len() { + for (resp_item, &agg_id) in update_response + .responses + .iter_mut() + .zip(aggregator_addresses) + { + if resp_item.aggregator_id.is_none() + || resp_item.aggregator_id.as_ref().unwrap().is_empty() + { + resp_item.aggregator_id = Some(agg_id.to_string()); + } + } + } + Ok(update_response) + } + + /// Simulate feed responses for Sui from the crossbar gateway. + /// + /// # Arguments + /// * `network` - The Sui network identifier (e.g. "mainnet", "testnet") + /// * `feed_ids` - The list of feed ids as string slices. + /// + /// # Returns + /// * `Result, AnyhowError>` - The current simulated results for the requested feeds. + pub async fn simulate_sui_feeds( + &self, + network: &str, + feed_ids: &[&str], + ) -> Result, AnyhowError> { + if feed_ids.is_empty() { + return Err(anyhow!("Feed ids are empty")); + } + let feeds_param = feed_ids.join(","); + let url = format!( + "{}/simulate/sui/{}/{}", + self.crossbar_url, network, feeds_param + ); + let resp = self + .client + .get(&url) + .send() + .await + .context("Failed to send simulate sui feeds request")?; + let status = resp.status(); + let raw = resp + .text() + .await + .context("Failed to fetch response for simulate sui feeds")?; + if !status.is_success() { + if self.verbose { + eprintln!("{}: {}", status, raw); + } + return Err(anyhow!("Bad status code {}", status.as_u16())); + } + // Parse the response. We assume the TS server returns JSON matching SimulateSuiFeedsResponse. + let responses: Vec = + serde_json::from_str(&raw).context("Failed to parse simulate sui feeds response")?; + Ok(responses) + } + + /// Stream the simulation of feed responses from the crossbar gateway. + pub fn stream_simulate_feeds<'a>( + &'a self, + feed_hashes: Vec<&'a str>, + poll_interval: Duration, + ) -> impl Stream, AnyhowError>> + 'a { + // Create an interval timer stream. + let interval_stream = IntervalStream::new(interval(poll_interval)); + let feed_hashes = feed_hashes.clone(); + // For each tick, call the simulate_feeds function. + interval_stream.then(move |_| { + let feed_hashes = feed_hashes.clone(); + async move { self.simulate_feeds(&feed_hashes).await } + }) + } + + /// Stream the simulation of feed responses from the crossbar gateway for Solana feeds. + pub fn stream_simulate_solana_feeds<'a>( + &'a self, + network: anchor_client::solana_sdk::genesis_config::ClusterType, + feed_pubkeys: &'a [Pubkey], + poll_interval: Duration, + ) -> impl Stream, AnyhowError>> + 'a { + let interval_stream = IntervalStream::new(interval(poll_interval)); + interval_stream.then(move |_| { + let network = network; + async move { self.simulate_solana_feeds(network, feed_pubkeys).await } + }) + } + + /// Stream the simulation of Sui feed responses from the crossbar gateway. + pub fn stream_simulate_sui_feeds<'a>( + &'a self, + network: &'a str, + feed_ids: Vec<&'a str>, + poll_interval: Duration, + ) -> impl Stream, AnyhowError>> + 'a { + let interval_stream = IntervalStream::new(interval(poll_interval)); + interval_stream.then(move |_| { + let feed_ids = feed_ids.clone(); + async move { self.simulate_sui_feeds(network, &feed_ids).await } + }) + } + + /// Stream the Sui feed update responses from the crossbar gateway. + /// + /// # Arguments + /// * `network` - The Sui network identifier (e.g., "mainnet", "testnet") + /// * `aggregator_addresses` - A vector of aggregator address strings. + /// * `poll_interval` - The polling interval for updates. + /// + /// # Returns + /// * `impl Stream>` + /// - A stream of Sui update responses. + pub fn stream_sui_updates<'a>( + &'a self, + network: &'a str, + aggregator_addresses: Vec<&'a str>, + poll_interval: Duration, + ) -> impl Stream> + 'a { + let interval_stream = IntervalStream::new(interval(poll_interval)); + interval_stream.then(move |_| { + let aggregator_addresses = aggregator_addresses.clone(); + async move { self.fetch_sui_updates(network, &aggregator_addresses).await } + }) + } + + /// Fetches gateway URLs from the crossbar service for a specific network + /// + /// # Arguments + /// * `network` - The network to fetch gateways for ("mainnet" or "devnet") + /// + /// # Returns + /// * `Result, AnyhowError>` - A vector of gateway URLs + pub async fn fetch_gateways(&self, network: &str) -> Result, AnyhowError> { + let url = format!("{}/gateways?network={}", self.crossbar_url, network); + let resp = self + .client + .get(&url) + .send() + .await + .context("Failed to send fetch gateways request")?; + + let status = resp.status(); + if !status.is_success() { + if self.verbose { + eprintln!("{}: {}", status, resp.text().await.context("Failed to fetch response")?); + } + return Err(anyhow!("Bad status code {}", status.as_u16())); + } + + resp.json().await.context("Failed to parse gateways response") + } + +} + +#[cfg(test)] +mod tests { + use super::*; + use std::str::FromStr; + + #[tokio::test] + async fn test_crossbar_client_default_initialization() { + let key = Pubkey::from_str("D1MmZ3je8GCjLrTbWXotnZ797k6E56QkdyXyhPXZQocH").unwrap(); + let client = CrossbarClient::default(); + let resp = client + .simulate_solana_feeds(ClusterType::MainnetBeta, &[key]) + .await + .unwrap(); + println!("{:?}", resp); + } +} diff --git a/programs/switchboard-on-demand/src/client/gateway.rs b/programs/switchboard-on-demand/src/client/gateway.rs new file mode 100644 index 0000000000..e2bd444d8f --- /dev/null +++ b/programs/switchboard-on-demand/src/client/gateway.rs @@ -0,0 +1,415 @@ +use super::oracle_job::OracleJob; +use base64::prelude::*; +use prost::Message; +use reqwest::header::CONTENT_TYPE; +use reqwest::Client; +use serde::{Deserialize, Serialize}; +use std::sync::Arc; +use std::time::Duration; + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct MedianResponse { + pub value: String, + pub feed_hash: String, +} + +/// Parameters for the consensus route. +#[derive(Debug, Clone)] +pub struct FetchSignaturesConsensusParams { + pub recent_hash: Option, + pub feed_configs: Vec, // Your existing FeedConfig struct + pub use_timestamp: Option, + pub num_signatures: Option, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct FetchSignaturesConsensusResponse { + pub median_responses: Vec, + pub oracle_responses: Vec, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct ConsensusOracleResponse { + pub oracle_pubkey: String, + pub eth_address: String, + pub signature: String, + pub checksum: String, + pub recovery_id: i32, + pub feed_responses: Vec, + pub errors: Vec>, +} + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct FeedEvalResponse { + pub oracle_pubkey: String, + pub queue_pubkey: String, + pub oracle_signing_pubkey: String, + pub feed_hash: String, + pub recent_hash: String, + pub failure_error: String, + pub success_value: String, + pub msg: String, + pub signature: String, + pub recovery_id: i32, + pub recent_successes_if_failed: Vec, + pub timestamp: Option, +} + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct FeedEvalResponseSingle { + pub responses: Vec, + pub caller: String, + pub failures: Vec, +} + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct FeedEvalManyResponse { + pub feed_responses: Vec, + pub signature: String, + pub recovery_id: i32, + pub errors: Vec>, +} + +#[derive(Serialize, Deserialize, Debug)] +pub struct FetchSignaturesMultiResponse { + pub oracle_responses: Vec, + pub errors: Vec>, +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct FetchSignaturesBatchRequest { + pub api_version: String, + /// Chain metadata for the oracle to sign with + pub recent_hash: String, + /// Signing protocol for the oracle to use + pub signature_scheme: String, + /// Hashing scheme for the checksum used in the signature + pub hash_scheme: String, + pub feed_requests: Vec, + pub num_oracles: u32, + // Whether or not to use the timestamp in the checksum + #[serde(default)] + pub use_timestamp: bool, +} + +#[derive(Debug, Serialize, Deserialize, Clone, Default)] +pub struct FeedEvalBatchResponse { + pub feed_responses: Vec, + pub errors: Vec>, +} + +#[derive(Debug, Serialize, Deserialize, Clone, Default)] +pub struct FetchSignaturesBatchResponse { + pub oracle_responses: Vec, + pub errors: Vec, +} + +#[derive(Serialize, Deserialize, Debug)] +pub struct RandomnessRevealResponse { + pub signature: String, + pub recovery_id: i32, + pub value: Vec, +} + +#[derive(Serialize, Deserialize, Debug)] +pub struct AttestEnclaveResponse { + pub guardian: String, + pub signature: String, + pub recovery_id: i32, +} + +#[derive(Serialize, Deserialize, Debug)] +pub struct PingResponse { + pub oracle_pubkey: String, + pub oracle_authority: String, + pub queue: String, + pub rate_limit: i32, + pub version: String, + pub mr_enclave: String, + pub is_push_oracle: bool, + pub is_pull_oracle: bool, + pub is_gateway: bool, + pub is_guardian: bool, +} + +#[derive(Serialize, Deserialize, Debug)] +pub struct FetchQuoteResponse { + pub oracle_pubkey: String, + pub queue: String, + pub now: i64, + pub mr_enclave: String, + pub ed25519_pubkey: String, + pub secp256k1_pubkey: String, + pub quote: String, +} + +#[derive(Serialize, Deserialize, Debug)] +pub struct BridgeEnclaveResponse { + pub guardian: String, + pub oracle: String, + pub queue: String, + pub mr_enclave: String, + pub chain_hash: String, + pub oracle_ed25519_enclave_signer: String, + pub oracle_secp256k1_enclave_signer: String, + pub msg: String, + pub msg_prehash: String, + pub signature: String, + pub recovery_id: i32, +} + +#[derive(Debug, Clone, Default)] +pub struct Gateway { + gateway_url: String, + client: Arc, +} + +impl Gateway { + pub fn new(gateway_url: String) -> Self { + let client = Client::builder() + .timeout(Duration::from_secs(10)) + // Switchboard does its own keypair authentication + .danger_accept_invalid_certs(true) + .build() + .unwrap(); + + Self { + gateway_url, + client: Arc::new(client), + } + } + + /// Fetches signatures from the gateway + /// # Arguments + /// * `params` - FetchSignaturesParams + /// * `params.recent_hash` - The recent hash of the feed + /// * `params.encoded_jobs` - The encoded jobs + /// * `params.num_signatures` - The number of signatures to fetch + /// * `params.max_variance` - The maximum variance + /// * `params.min_responses` - The minimum number of responses + /// * `params.use_timestamp` - Whether to use the timestamp + /// # Returns + /// * `Result` + pub async fn fetch_signatures_from_encoded( + &self, + params: FetchSignaturesParams, + ) -> Result { + let url = format!("{}/gateway/api/v1/fetch_signatures", self.gateway_url); + let body = serde_json::json!({ + "api_version": "1.0.0", + "jobs_b64_encoded": params.encoded_jobs, + "recent_chainhash": params.recent_hash.unwrap_or_else(|| bs58::encode(vec![0; 32]).into_string()), + "signature_scheme": "Secp256k1", + "hash_scheme": "Sha256", + "num_oracles": params.num_signatures, + "max_variance": (params.max_variance.unwrap_or(1) as f64 * 1e9) as u64, + "min_responses": params.min_responses.unwrap_or(1), + "use_timestamp": params.use_timestamp.unwrap_or(false), + }); + + let res = self + .client + .post(&url) + .header(CONTENT_TYPE, "application/json") + .json(&body) + .send() + .await?; + + let raw = res.text().await?; + let res = serde_json::from_str::(&raw).unwrap(); + + Ok(res) + } + + /// Fetches signatures from the gateway using the multi-feed method + /// # Arguments + /// * `params` - FetchSignaturesMultiParams + /// * `params.recent_hash` - The recent hash of the feed + /// * `params.feed_configs` - The feed configurations + /// * `params.num_signatures` - The number of signatures to fetch + /// * `params.use_timestamp` - Whether to use the timestamp + /// # Returns + /// * `Result` + pub async fn fetch_signatures_multi( + &self, + params: FetchSignaturesMultiParams, + ) -> Result { + let url = format!("{}/gateway/api/v1/fetch_signatures_multi", self.gateway_url); + let mut feed_requests = vec![]; + + for config in params.feed_configs { + let max_variance = (config.max_variance.unwrap_or(1) as f64 * 1e9) as u64; + feed_requests.push(serde_json::json!({ + "jobs_b64_encoded": config.encoded_jobs, + "max_variance": max_variance, + "min_responses": config.min_responses.unwrap_or(1), + "use_timestamp": params.use_timestamp.unwrap_or(false), + })); + } + + let body = serde_json::json!({ + "api_version": "1.0.0", + "num_oracles": params.num_signatures.unwrap_or(1), + "recent_hash": params.recent_hash.unwrap_or_else(|| bs58::encode(vec![0; 32]).into_string()), + "signature_scheme": "Secp256k1", + "hash_scheme": "Sha256", + "feed_requests": feed_requests, + }); + + let res = self + .client + .post(&url) + .header(CONTENT_TYPE, "application/json") + .json(&body) + .send() + .await?; + let res = res.json::().await?; + + Ok(res) + } + + pub async fn fetch_signatures_batch( + &self, + params: FetchSignaturesBatchParams, + ) -> Result { + let url = format!("{}/gateway/api/v1/fetch_signatures_batch", self.gateway_url); + let req = FetchSignaturesBatchRequest { + api_version: "1.0.0".to_string(), + recent_hash: params + .recent_hash + .clone() + .unwrap_or_else(|| bs58::encode(vec![0; 32]).into_string()), + signature_scheme: "Secp256k1".to_string(), + hash_scheme: "Sha256".to_string(), + feed_requests: params.feed_configs.clone(), + num_oracles: params.num_signatures.unwrap_or(1), + use_timestamp: params.use_timestamp.unwrap_or(false), + }; + + let res = self + .client + .post(&url) + .header(CONTENT_TYPE, "application/json") + .json(&req) + .send() + .await?; + + let response = res.json::().await?; + Ok(response) + } + + pub async fn fetch_signatures_consensus( + &self, + params: FetchSignaturesConsensusParams, + ) -> Result { + let url = format!( + "{}/gateway/api/v1/fetch_signatures_consensus", + self.gateway_url + ); + println!("Fetching signatures from: {}", url); + // Build feed_requests array from feed_configs + let feed_requests: Vec = params + .feed_configs + .iter() + .map(|config| { + // If max_variance or min_responses are not provided, use default values. + let max_variance = config.max_variance.unwrap_or(1); + let min_responses = config.min_responses.unwrap_or(1); + serde_json::json!({ + "jobs_b64_encoded": config.encoded_jobs, + "max_variance": (max_variance as f64 * 1e9) as u64, + "min_responses": min_responses, + "use_timestamp": params.use_timestamp.unwrap_or(false) + }) + }) + .collect(); + + let body = serde_json::json!({ + "api_version": "1.0.0", + "recent_hash": params.recent_hash.unwrap_or_else(|| bs58::encode(vec![0; 32]).into_string()), + "signature_scheme": "Secp256k1", + "hash_scheme": "Sha256", + "feed_requests": feed_requests, + "num_oracles": params.num_signatures.unwrap_or(1) + }); + + let res = self + .client + .post(&url) + .header(CONTENT_TYPE, "application/json") + .json(&body) + .send() + .await?; + + let response = res.json::().await?; + Ok(response) + } + + pub async fn test_gateway(&self) -> bool { + let client = &self.client; + // Make HTTP request + let url = format!("{}/gateway/api/v1/test", self.gateway_url); + let response = client.get(&url).send().await; + + // Process response + if let Ok(resp) = response { + if let Ok(text) = resp.text().await { + !text.is_empty() + } else { + false + } + } else { + false + } + } +} + +#[derive(Debug)] +pub struct FetchSignaturesParams { + pub recent_hash: Option, + pub encoded_jobs: Vec, + pub num_signatures: u32, + pub max_variance: Option, + pub min_responses: Option, + pub use_timestamp: Option, +} + +#[derive(Debug, Clone)] +pub struct FeedConfig { + pub encoded_jobs: Vec, + pub max_variance: Option, + pub min_responses: Option, +} + +#[derive(Debug, Serialize, Deserialize, Clone, Default)] +pub struct BatchFeedRequest { + /// Vec of jobs to process. Each group is equivalent to 1 feed. + pub jobs_b64_encoded: Vec, + /// Allowed variance in the feed values + pub max_variance: u64, + /// Minimum number of responses required for the feed + pub min_responses: u32, +} + +#[derive(Debug)] +pub struct FetchSignaturesMultiParams { + pub recent_hash: Option, + pub feed_configs: Vec, + pub num_signatures: Option, + pub use_timestamp: Option, +} + +#[derive(Debug, Clone, Default)] +pub struct FetchSignaturesBatchParams { + pub recent_hash: Option, + pub feed_configs: Vec, + pub num_signatures: Option, + pub use_timestamp: Option, +} + +pub fn encode_jobs(job_array: &[OracleJob]) -> Vec { + job_array + .iter() + .map(|job| BASE64_STANDARD.encode(job.encode_length_delimited_to_vec())) + .collect() +} diff --git a/programs/switchboard-on-demand/src/client/instructions/mod.rs b/programs/switchboard-on-demand/src/client/instructions/mod.rs new file mode 100644 index 0000000000..31cc67df06 --- /dev/null +++ b/programs/switchboard-on-demand/src/client/instructions/mod.rs @@ -0,0 +1,12 @@ +pub mod pull_feed_submit_response_ix; +pub use pull_feed_submit_response_ix::*; +pub mod pull_feed_submit_response_many_ix; +pub use pull_feed_submit_response_many_ix::*; +pub mod pull_feed_submit_response_consensus; +pub use pull_feed_submit_response_consensus::*; +use sha2::{Digest, Sha256}; + +pub fn get_discriminator(name: &str) -> Vec { + let name = format!("global:{}", name); + Sha256::digest(&name)[..8].to_vec() +} diff --git a/programs/switchboard-on-demand/src/client/instructions/pull_feed_submit_response_consensus.rs b/programs/switchboard-on-demand/src/client/instructions/pull_feed_submit_response_consensus.rs new file mode 100644 index 0000000000..7e05e4cfce --- /dev/null +++ b/programs/switchboard-on-demand/src/client/instructions/pull_feed_submit_response_consensus.rs @@ -0,0 +1,53 @@ +use super::get_discriminator; +use borsh::{BorshDeserialize, BorshSerialize}; +use crate::AccountMeta; +use crate::Pubkey; +use anchor_client::solana_sdk::sysvar::instructions; + +#[derive(Clone, Debug)] +pub struct PullFeedSubmitResponseConsensus { + pub queue: Pubkey, + pub program_state: Pubkey, + pub recent_slothashes: Pubkey, + pub payer: Pubkey, + pub system_program: Pubkey, + pub reward_vault: Pubkey, + pub token_program: Pubkey, + pub token_mint: Pubkey, +} + +impl PullFeedSubmitResponseConsensus { + pub fn to_account_metas(&self, _is_signer: Option) -> Vec { + vec![ + AccountMeta::new_readonly(self.queue, false), + AccountMeta::new_readonly(self.program_state, false), + AccountMeta::new_readonly(self.recent_slothashes, false), + AccountMeta::new(self.payer, true), + AccountMeta::new_readonly(self.system_program, false), + AccountMeta::new(self.reward_vault, false), + AccountMeta::new_readonly(self.token_program, false), + AccountMeta::new_readonly(self.token_mint, false), + AccountMeta::new_readonly(instructions::id().to_bytes().into(), false), + ] + } +} + +#[derive(Clone, BorshSerialize, BorshDeserialize)] +pub struct PullFeedSubmitResponseConsensusParams { + pub slot: u64, + pub values: Vec, +} + +impl PullFeedSubmitResponseConsensusParams { + pub fn to_vec(&self) -> Vec { + let mut buffer: Vec = Vec::new(); + self.serialize(&mut buffer).unwrap(); + buffer + } + + pub fn data(&self) -> Vec { + let mut res = get_discriminator("pull_feed_submit_response_consensus").to_vec(); + res.extend_from_slice(&self.to_vec()); + res + } +} diff --git a/programs/switchboard-on-demand/src/client/instructions/pull_feed_submit_response_ix.rs b/programs/switchboard-on-demand/src/client/instructions/pull_feed_submit_response_ix.rs new file mode 100644 index 0000000000..0d36185b51 --- /dev/null +++ b/programs/switchboard-on-demand/src/client/instructions/pull_feed_submit_response_ix.rs @@ -0,0 +1,63 @@ +use super::get_discriminator; +use borsh::{BorshDeserialize, BorshSerialize}; +use crate::AccountMeta; +use crate::Pubkey; + +#[derive(Clone, Debug)] +pub struct PullFeedSubmitResponse { + pub feed: Pubkey, + pub queue: Pubkey, + pub program_state: Pubkey, + pub recent_slothashes: Pubkey, + pub payer: Pubkey, + pub system_program: Pubkey, + pub reward_vault: Pubkey, + pub token_program: Pubkey, + pub token_mint: Pubkey, +} + +impl PullFeedSubmitResponse { + pub fn to_account_metas(&self, _is_signer: Option) -> Vec { + vec![ + AccountMeta::new(self.feed, false), + AccountMeta::new_readonly(self.queue, false), + AccountMeta::new_readonly(self.program_state, false), + AccountMeta::new_readonly(self.recent_slothashes, false), + AccountMeta::new(self.payer, true), + AccountMeta::new_readonly(self.system_program, false), + AccountMeta::new(self.reward_vault, false), + AccountMeta::new_readonly(self.token_program, false), + AccountMeta::new_readonly(self.token_mint, false), + ] + } +} + +// 82 bytes +#[derive(Clone, BorshSerialize, BorshDeserialize)] +pub struct Submission { + pub value: i128, + pub signature: [u8; 64], + pub recovery_id: u8, + // If the oracle failed to produce response at the user request slot and it + // responds with an older signed vlaue state which slot its signed with by + // offset of requested. + pub offset: u8, +} +#[derive(Clone, BorshSerialize, BorshDeserialize)] +pub struct PullFeedSubmitResponseParams { + pub slot: u64, + pub submissions: Vec, +} +impl PullFeedSubmitResponseParams { + pub fn to_vec(&self) -> Vec { + let mut buffer: Vec = Vec::new(); + self.serialize(&mut buffer).unwrap(); + buffer + } + + pub fn data(&self) -> Vec { + let mut res = get_discriminator("pull_feed_submit_response").to_vec(); + res.extend_from_slice(&self.to_vec()); + res + } +} diff --git a/programs/switchboard-on-demand/src/client/instructions/pull_feed_submit_response_many_ix.rs b/programs/switchboard-on-demand/src/client/instructions/pull_feed_submit_response_many_ix.rs new file mode 100644 index 0000000000..54f99708bc --- /dev/null +++ b/programs/switchboard-on-demand/src/client/instructions/pull_feed_submit_response_many_ix.rs @@ -0,0 +1,60 @@ +use super::get_discriminator; +use borsh::{BorshDeserialize, BorshSerialize}; +use crate::AccountMeta; +use crate::Pubkey; +use anchor_client::solana_sdk::sysvar::instructions; + +#[derive(Clone, Debug)] +pub struct PullFeedSubmitResponseMany { + pub queue: Pubkey, + pub program_state: Pubkey, + pub recent_slothashes: Pubkey, + // mut + pub payer: Pubkey, + pub system_program: Pubkey, + // mut + pub reward_vault: Pubkey, + pub token_program: Pubkey, + pub token_mint: Pubkey, +} + +impl PullFeedSubmitResponseMany { + pub fn to_account_metas(&self, _is_signer: Option) -> Vec { + vec![ + AccountMeta::new_readonly(self.queue, false), + AccountMeta::new_readonly(self.program_state, false), + AccountMeta::new_readonly(self.recent_slothashes, false), + AccountMeta::new(self.payer, true), + AccountMeta::new_readonly(self.system_program, false), + AccountMeta::new(self.reward_vault, false), + AccountMeta::new_readonly(self.token_program, false), + AccountMeta::new_readonly(self.token_mint, false), + AccountMeta::new_readonly(instructions::id().to_bytes().into(), false), + ] + } +} + +#[derive(Clone, BorshSerialize, BorshDeserialize)] +pub struct MultiSubmission { + pub values: Vec, // i128::MAX is a sentinel value for missing data + pub signature: [u8; 64], + pub recovery_id: u8, +} +#[derive(Clone, BorshSerialize, BorshDeserialize)] +pub struct PullFeedSubmitResponseManyParams { + pub slot: u64, + pub submissions: Vec, +} +impl PullFeedSubmitResponseManyParams { + pub fn to_vec(&self) -> Vec { + let mut buffer: Vec = Vec::new(); + self.serialize(&mut buffer).unwrap(); + buffer + } + + pub fn data(&self) -> Vec { + let mut res = get_discriminator("pull_feed_submit_response_many").to_vec(); + res.extend_from_slice(&self.to_vec()); + res + } +} diff --git a/programs/switchboard-on-demand/src/client/lut_owner.rs b/programs/switchboard-on-demand/src/client/lut_owner.rs new file mode 100644 index 0000000000..ac4a147a5b --- /dev/null +++ b/programs/switchboard-on-demand/src/client/lut_owner.rs @@ -0,0 +1,84 @@ +#[allow(unused_imports)] +use crate::*; +use anyhow::anyhow; +use anyhow::Error as AnyhowError; +use crate::solana_compat::solana_client::nonblocking::rpc_client::RpcClient; +use anchor_client::solana_sdk::address_lookup_table::instruction::derive_lookup_table_address; +use anchor_client::solana_sdk::address_lookup_table::state::AddressLookupTable; +use anchor_client::solana_sdk::address_lookup_table::AddressLookupTableAccount; +use crate::Pubkey; + +pub trait LutOwner { + fn lut_slot(&self) -> u64; +} + +pub async fn load_lookup_table( + client: &RpcClient, + self_key: Pubkey, +) -> Result { + let account = client + .get_account_data(&self_key.to_bytes().into()) + .await + .map_err(|_| anyhow!("LutOwner.load_lookup_table: Oracle not found"))?; + let account = account[8..].to_vec(); + let data = bytemuck::try_from_bytes::(&account) + .map_err(|_| anyhow!("LutOwner.load_lookup_table: Invalid data"))?; + let lut_slot = data.lut_slot(); + let lut_signer: Pubkey = find_lut_signer(&self_key); + let lut_key: anchor_client::solana_sdk::pubkey::Pubkey = derive_lookup_table_address(&lut_signer.to_bytes().into(), lut_slot).0; + let lut_account = client + .get_account_data(&lut_key.to_bytes().into()) + .await + .map_err(|_| anyhow!("LutOwner.load_lookup_table: LUT not found"))?; + let parsed_lut = AddressLookupTable::deserialize(&lut_account) + .map_err(|_| anyhow!("LutOwner.load_lookup_table: Invalid LUT data"))?; + Ok(AddressLookupTableAccount { + addresses: parsed_lut.addresses.to_vec(), + key: lut_key, + }) +} + +pub async fn load_lookup_tables( + client: &RpcClient, + keys: &[Pubkey], +) -> Result, AnyhowError> { + // Account data uses v3 Pubkey, but RpcClient expects v2 Pubkey + let keys_v2: Vec<_> = keys.iter().map(|k| k.to_bytes().into()).collect(); + let accounts_data = client + .get_multiple_accounts(&keys_v2) + .await? + .into_iter() + .map(|acct| match acct { + Some(account) => account.data.get(8..).unwrap_or(&[]).to_vec(), + None => vec![], + }) + .collect::>(); + let mut lut_keys = Vec::new(); + let mut out = Vec::new(); + for (idx, account) in accounts_data.iter().enumerate() { + let data = bytemuck::try_from_bytes::(account); + if data.is_err() { + continue; + } + let lut_slot = data.unwrap().lut_slot(); + let lut_signer = find_lut_signer(&keys[idx]); + let lut_key = derive_lookup_table_address(&lut_signer, lut_slot).0; + lut_keys.push(lut_key.to_bytes().into()); + } + let lut_datas = client + .get_multiple_accounts(lut_keys.as_slice()) + .await? + .into_iter() + .map(|data| data.unwrap_or_default().data.to_vec()) + .collect::>>(); + for (idx, lut_data) in lut_datas.iter().enumerate() { + let parsed_lut = AddressLookupTable::deserialize(lut_data); + if let Ok(parsed_lut) = parsed_lut { + out.push(AddressLookupTableAccount { + addresses: parsed_lut.addresses.to_vec(), + key: lut_keys[idx].to_bytes().into(), + }); + } + } + Ok(out) +} diff --git a/programs/switchboard-on-demand/src/client/mod.rs b/programs/switchboard-on-demand/src/client/mod.rs new file mode 100644 index 0000000000..1b4a7bff66 --- /dev/null +++ b/programs/switchboard-on-demand/src/client/mod.rs @@ -0,0 +1,50 @@ +/// Core Crossbar protocol implementations and client functionality +pub mod crossbar; +pub use crossbar::*; + +/// Gateway client for interfacing with Switchboard's Crossbar API +pub mod gateway; +pub use gateway::*; + +/// Pull-based oracle feed management and data fetching utilities +pub mod pull_feed; +pub use self::pull_feed::PullFeed; + +/// Oracle job definitions, serialization, and protocol buffer handling +pub mod oracle_job; +pub use oracle_job::OracleJob; + +/// SECP256k1 cryptographic utilities and signature verification +pub mod secp256k1; +pub use secp256k1::*; + +/// Lookup table ownership and management functionality +pub mod lut_owner; +pub use lut_owner::*; + +/// Associated token account utilities and constants +pub mod associated_token_account; +pub use associated_token_account::*; + +/// Solana slot hash utilities and recent hash management +pub mod recent_slothashes; +pub use recent_slothashes::*; + +/// Client-specific account structures and deserialization utilities +pub mod accounts; +pub use accounts::*; + +/// Client-specific instruction builders for interacting with the Switchboard On-Demand program +pub mod instructions; +pub use instructions::*; + +/// Transaction building utilities +pub mod transaction_builder; +pub use transaction_builder::*; + +/// Client utility functions and helpers +pub mod utils; +pub use utils::*; + +/// Re-export prost for protobuf handling +pub use prost; \ No newline at end of file diff --git a/programs/switchboard-on-demand/src/client/oracle_job.rs b/programs/switchboard-on-demand/src/client/oracle_job.rs new file mode 100644 index 0000000000..5bc0c43859 --- /dev/null +++ b/programs/switchboard-on-demand/src/client/oracle_job.rs @@ -0,0 +1,8475 @@ +// @generated +/// / Represnts a list of tasks to be performed by a switchboard oracle. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct OracleJob { + /// / The chain of tasks to perform for this OracleJob. + #[prost(message, repeated, tag = "1")] + pub tasks: ::prost::alloc::vec::Vec, + /// / The weight to assign to this job's result when aggregating multiple job results. A higher + /// / weight means this job's result will have more influence on the final aggregated value. This + /// / value must be greater than or equal to 0. + #[prost(uint32, optional, tag = "2", default = "1")] + pub weight: ::core::option::Option, + #[prost(uint32, optional, tag = "3")] + pub min_responses: ::core::option::Option, + #[prost(uint32, optional, tag = "4")] + pub min_samples: ::core::option::Option, + #[prost(uint64, optional, tag = "5")] + pub max_variance: ::core::option::Option, + #[prost(string, optional, tag = "6")] + pub name: ::core::option::Option<::prost::alloc::string::String>, + #[prost(string, optional, tag = "7")] + pub queue: ::core::option::Option<::prost::alloc::string::String>, +} +/// Nested message and enum types in `OracleJob`. +pub mod oracle_job { + /// + /// The adapter will report the text body of a successful HTTP request to the + /// specified url, or return an error if the response status code is greater + /// than or equal to 400. + /// + /// _**Input**_: None + /// + /// _**Returns**_: String representation of the http response. + /// + /// _**Example**_: Basic HttpTask + /// + /// ```json + /// {"httpTask": {"url": " } + /// ``` + /// + /// _**Example**_: HttpTask example with headers + /// + /// ```json + /// { "httpTask": { "url": " "method": "METHOD_POST", "headers": \[ { "key": "MY_HEADER_KEY", "value": "MY_HEADER_VALUE" } \], "body": "{\"MY_BODY_KEY\":\"MY_BODY_VALUE\"}" } } + /// ``` + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct HttpTask { + /// / A string containing the URL to direct this HTTP request to. + #[prost(string, optional, tag = "1")] + pub url: ::core::option::Option<::prost::alloc::string::String>, + /// / The type of HTTP request to make. + #[prost(enumeration = "http_task::Method", optional, tag = "2")] + pub method: ::core::option::Option, + /// / A list of headers to add to this HttpTask. + #[prost(message, repeated, tag = "3")] + pub headers: ::prost::alloc::vec::Vec, + /// / A stringified body (if any) to add to this HttpTask. + #[prost(string, optional, tag = "4")] + pub body: ::core::option::Option<::prost::alloc::string::String>, + } + /// Nested message and enum types in `HttpTask`. + pub mod http_task { + /// / An object that represents a header to add to an HTTP request. + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct Header { + /// / A header key such as `Authorization` or `Content-Type` + #[prost(string, optional, tag = "1")] + pub key: ::core::option::Option<::prost::alloc::string::String>, + /// / A value for the given header key like `Basic MYAUTHKEY` or `application/json` + #[prost(string, optional, tag = "2")] + pub value: ::core::option::Option<::prost::alloc::string::String>, + } + /// / An enumeration representing the types of HTTP requests available to make. + #[derive( + Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration, + )] + #[repr(i32)] + pub enum Method { + /// / Unset HTTP method will default to METHOD_GET + Unkown = 0, + /// / Perform an HTTP 'GET' request. + Get = 1, + /// / Perform an HTTP 'POST' request. + Post = 2, + } + impl Method { + /// 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 { + Method::Unkown => "METHOD_UNKOWN", + Method::Get => "METHOD_GET", + Method::Post => "METHOD_POST", + } + } + /// Creates an enum from field names used in the ProtoBuf definition. + pub fn from_str_name(value: &str) -> ::core::option::Option { + match value { + "METHOD_UNKOWN" => Some(Self::Unkown), + "METHOD_GET" => Some(Self::Get), + "METHOD_POST" => Some(Self::Post), + _ => None, + } + } + } + } + /// + /// The adapter walks the path specified and returns the value found at that result. If returning + /// JSON data from the HttpGet or HttpPost adapters, you must use this adapter to parse the response. + /// + /// _**Input**_: String representation of a JSON object. + /// + /// _**Returns**_: A numerical result. + /// + /// _**Example**_: Parses the price field from a JSON object + /// + /// ```json + /// {"jsonParse": {"path": "$.price"} } + /// ``` + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct JsonParseTask { + /// / JSONPath formatted path to the element. + /// / + #[prost(string, optional, tag = "1")] + pub path: ::core::option::Option<::prost::alloc::string::String>, + /// / The technique that will be used to aggregate the results if walking the specified path returns multiple numerical results. + #[prost( + enumeration = "json_parse_task::AggregationMethod", + optional, + tag = "2" + )] + pub aggregation_method: ::core::option::Option, + } + /// Nested message and enum types in `JsonParseTask`. + pub mod json_parse_task { + /// / The methods of combining a list of numerical results. + #[derive( + Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration, + )] + #[repr(i32)] + pub enum AggregationMethod { + None = 0, + /// / Grab the minimum value of the results. + Min = 1, + /// / Grab the maximum value of the results. + Max = 2, + /// / Sum up all of the results. + Sum = 3, + /// / Average all of the results. + Mean = 4, + /// / Grab the median of the results. + Median = 5, + } + impl AggregationMethod { + /// 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 { + AggregationMethod::None => "NONE", + AggregationMethod::Min => "MIN", + AggregationMethod::Max => "MAX", + AggregationMethod::Sum => "SUM", + AggregationMethod::Mean => "MEAN", + AggregationMethod::Median => "MEDIAN", + } + } + /// Creates an enum from field names used in the ProtoBuf definition. + pub fn from_str_name(value: &str) -> ::core::option::Option { + match value { + "NONE" => Some(Self::None), + "MIN" => Some(Self::Min), + "MAX" => Some(Self::Max), + "SUM" => Some(Self::Sum), + "MEAN" => Some(Self::Mean), + "MEDIAN" => Some(Self::Median), + _ => None, + } + } + } + } + /// + /// Returns the median (middle) of all the results returned by the provided subtasks and subjobs. Nested tasks must return a Number. + /// + /// _**Input**_: None + /// + /// _**Returns**_: A numerical result. + /// + /// _**Example**_: Returns the median numerical result of 3 tasks. + /// + /// ```json + /// {"medianTask": {"tasks": \[{"valueTask": {"value": 10}},{"valueTask": {"value": 20}},{"valueTask": {"value": 30}}\]}} + /// ``` + /// + /// _**Example**_: Returns the median numerical result of 3 jobs. + /// + /// ```json + /// {"medianTask": {"jobs": \[{"tasks": [{"httpTask": {"url": " {"path": "$.price"}}\]},{"tasks": \[{"httpTask": {"url": " {"path": "$.price"}}\]},{"tasks": [{"httpTask": {"url": " {"path": "$[0][7]"}}]}]}} + /// ``` + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct MedianTask { + /// / A list of subtasks to process and produce a list of result values. + #[prost(message, repeated, tag = "1")] + pub tasks: ::prost::alloc::vec::Vec, + /// / A list of subjobs to process and produce a list of result values. + #[prost(message, repeated, tag = "2")] + pub jobs: ::prost::alloc::vec::Vec, + /// / The minimum number of values before a successful median can be yielded. + #[prost(int32, optional, tag = "3")] + pub min_successful_required: ::core::option::Option, + /// / The maximum range between the minimum and maximum values before a successful median can be yielded. + #[prost(string, optional, tag = "4")] + pub max_range_percent: ::core::option::Option<::prost::alloc::string::String>, + } + /// + /// Returns the mean (average) of all the results returned by the provided subtasks and subjobs. Nested tasks or jobs must return a Number. + /// + /// _**Input**_: None + /// + /// _**Returns**_: A numerical result. + /// + /// _**Example**_: Returns the mean numerical result of 3 tasks. + /// + /// ```json + /// {"meanTask": {"tasks": \[{"valueTask": {"value": 10}},{"valueTask": {"value": 20}},{"valueTask": {"value": 30}}\]}} + /// ``` + /// + /// _**Example**_: Returns the mean numerical result of 3 jobs. + /// + /// ```json + /// {"meanTask": {"jobs": \[{"tasks": [{"httpTask": {"url": " {"path": "$.price"}}\]},{"tasks": \[{"httpTask": {"url": " {"path": "$.price"}}\]},{"tasks": [{"httpTask": {"url": " {"path": "$[0][7]"}}]}]}} + /// ``` + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct MeanTask { + /// / A list of subtasks to process and produce a list of result values. + #[prost(message, repeated, tag = "1")] + pub tasks: ::prost::alloc::vec::Vec, + /// / A list of subjobs to process and produce a list of result values. + #[prost(message, repeated, tag = "2")] + pub jobs: ::prost::alloc::vec::Vec, + } + /// + /// Returns the maximum value of all the results returned by the provided subtasks and subjobs. Nested tasks or jobs must return a Number. + /// + /// _**Input**_: None + /// + /// _**Returns**_: A numerical result. + /// + /// _**Example**_: Returns the maximum numerical result from 3 tasks. + /// + /// ```json + /// {"maxTask": {"tasks": \[{"valueTask": {"value": 10}},{"valueTask": {"value": 20}},{"valueTask": {"value": 30}}\]}} + /// ``` + /// + /// _**Example**_: Returns the maximum numerical result from 3 jobs. + /// + /// ```json + /// {"maxTask": {"jobs": \[{"tasks": [{"httpTask": {"url": " {"path": "$.price"}}\]},{"tasks": \[{"httpTask": {"url": " {"path": "$.price"}}\]},{"tasks": [{"httpTask": {"url": " {"path": "$[0][7]"}}]}]}} + /// ``` + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct MaxTask { + /// / A list of subtasks to process and produce a list of result values. + #[prost(message, repeated, tag = "1")] + pub tasks: ::prost::alloc::vec::Vec, + /// / A list of subjobs to process and produce a list of result values. + #[prost(message, repeated, tag = "2")] + pub jobs: ::prost::alloc::vec::Vec, + } + /// + /// Returns the minimum value of all the results returned by the provided subtasks and subjobs. Nested tasks or jobs must return a Number. + /// + /// _**Input**_: None + /// + /// _**Returns**_: A numerical result. + /// + /// _**Example**_: Returns the minimum numerical result from 3 tasks. + /// + /// ```json + /// {"minTask": {"tasks": \[{"valueTask": {"value": 10}},{"valueTask": {"value": 20}},{"valueTask": {"value": 30}}\]}} + /// ``` + /// + /// _**Example**_: Returns the minimum numerical result from 3 jobs. + /// + /// ```json + /// {"minTask": {"jobs": \[{"tasks": [{"httpTask": {"url": " {"path": "$.price"}}\]},{"tasks": \[{"httpTask": {"url": " {"path": "$.price"}}\]},{"tasks": [{"httpTask": {"url": " {"path": "$[0][7]"}}]}]}} + /// ``` + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct MinTask { + /// / A list of subtasks to process and produce a list of result values. + #[prost(message, repeated, tag = "1")] + pub tasks: ::prost::alloc::vec::Vec, + /// / A list of subjobs to process and produce a list of result values. + #[prost(message, repeated, tag = "2")] + pub jobs: ::prost::alloc::vec::Vec, + } + /// + /// Returns a specified value. + /// + /// _**Input**_: None + /// + /// _**Returns**_: A numerical result. + /// + /// _**Example**_: Returns the value 10 + /// + /// ```json + /// {"valueTask": {"value": 10} } + /// ``` + /// + /// _**Example**_: Returns the currentRound result of an aggregator + /// + /// ```json + /// {"valueTask": {"aggregatorPubkey": "GvDMxPzN1sCj7L26YDK2HnMRXEQmQ2aemov8YBtPS7vR"} } + /// ``` + /// + /// _**Example**_: Returns the value stored in a CacheTask variable + /// + /// ```json + /// {"valueTask": {"big": "${ONE}"} } + /// ``` + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct ValueTask { + #[prost(oneof = "value_task::Value", tags = "1, 2, 3, 4, 5")] + pub value: ::core::option::Option, + } + /// Nested message and enum types in `ValueTask`. + pub mod value_task { + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Oneof)] + pub enum Value { + /// / The value that will be returned from this task. + #[prost(double, tag = "1")] + Value(f64), + /// / Specifies an aggregatorr to pull the value of. + #[prost(string, tag = "2")] + AggregatorPubkey(::prost::alloc::string::String), + /// / A stringified big.js. `Accepts variable expansion syntax.` + #[prost(string, tag = "3")] + Big(::prost::alloc::string::String), + /// / A stringified hex number (0x prefix is optional). + #[prost(string, tag = "4")] + Hex(::prost::alloc::string::String), + /// A utf8 string. + #[prost(string, tag = "5")] + Utf8(::prost::alloc::string::String), + } + } + /// + /// Opens and maintains a websocket for light speed data retrieval. + /// + /// _**Input**_: None + /// + /// _**Returns**_: String representation of the websocket subscription message. + /// + /// _**Example**_: Opens a coinbase websocket + /// + /// ```json + /// { "websocketTask": { "url": "wss://ws-feed.pro.coinbase.com", "subscription": "{\"type\":\"subscribe\",\"product_ids\":\[\"BTC-USD\"\],\"channels\":\[\"ticker\",{\"name\":\"ticker\",\"product_ids\":[\"BTC-USD\"\]}]}", "maxDataAgeSeconds": 15, "filter": "$\[?(@.type == 'ticker' && @.product_id == 'BTC-USD')\]" } } + /// ``` + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct WebsocketTask { + /// / The websocket url. + #[prost(string, optional, tag = "1")] + pub url: ::core::option::Option<::prost::alloc::string::String>, + /// / The websocket message to notify of a new subscription. + #[prost(string, optional, tag = "2")] + pub subscription: ::core::option::Option<::prost::alloc::string::String>, + /// / Minimum amount of time required between when the horses are taking out. + #[prost(int32, optional, tag = "3")] + pub max_data_age_seconds: ::core::option::Option, + /// / Incoming message JSONPath filter. + /// / Example: "$\[?(@.channel == 'ticker' && @.market == 'BTC/USD')\]" + #[prost(string, optional, tag = "4")] + pub filter: ::core::option::Option<::prost::alloc::string::String>, + } + /// + /// This task will run the `attempt` on the subtasks in an effort to produce a valid numerical result. If `attempt`. fails to produce an acceptable result, `on_failure` subtasks will be run instead. + /// + /// _**Input**_: The current running numerical result output from a task. + /// + /// _**Returns**_: A numerical result, else run `on_failure` subtasks. + /// + /// _**Example**_: Returns the numerical result from the conditionalTask's subtasks, else `on_failure` returns the numerical result from its subtasks. + /// + /// ```json + /// {"conditionalTask":{"attempt":\[{"tasks":[{"jupiterSwapTask":{"inTokenAddress":"EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v","outTokenAddress":"DUALa4FC2yREwZ59PHeu1un4wis36vHRv5hWVBmzykCJ"}}\]}],"onFailure":\[{"lpExchangeRateTask":{"orcaPoolAddress":"7yJ4gMRJhEoCR48aPE3EAWRmCoygakik81ZS1sajaTnE"}}\]}} + /// ``` + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct ConditionalTask { + /// / A list of subtasks to process in an attempt to produce a valid numerical result. + #[prost(message, repeated, tag = "1")] + pub attempt: ::prost::alloc::vec::Vec, + /// / A list of subtasks that will be run if `attempt` subtasks are unable to produce an acceptable + /// / result. + #[prost(message, repeated, tag = "2")] + pub on_failure: ::prost::alloc::vec::Vec, + } + /// + /// This task will divide a numerical input by a scalar value from a job of subtasks, an aggregator, or a big. + /// + /// _**Input**_: The current running numerical result output from a scalar value, an aggregator, a job of subtasks or a big. + /// + /// _**Returns**_: A numerical result. + /// + /// _**Example**_: Returns the numerical result by dividing by a job of subtasks. + /// + /// ```json + /// {"tasks":\[{"valueTask":{"value":100}},{"divideTask":{"job":{"tasks":[{"valueTask":{"value":10}}\]}}}]} + /// ``` + /// + /// _**Example**_: Returns the numerical result by dividing by an aggregator. + /// + /// ```json + /// {"tasks":\[{"valueTask":{"value":100}},{"divideTask":{"aggregatorPubkey":"GvDMxPzN1sCj7L26YDK2HnMRXEQmQ2aemov8YBtPS7vR"}}\]} + /// ``` + /// + /// _**Example**_: Returns the numerical result by dividing by a big. + /// + /// ```json + /// {"tasks":\[{"cacheTask":{"cacheItems":[{"variableName":"TEN","job":{"tasks":[{"valueTask":{"value":10}}\]}}]}},{"valueTask":{"value":100}},{"divideTask":{"big":"${TEN}"}}]} + /// ``` + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct DivideTask { + #[prost(oneof = "divide_task::Denominator", tags = "1, 2, 3, 4")] + pub denominator: ::core::option::Option, + } + /// Nested message and enum types in `DivideTask`. + pub mod divide_task { + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Oneof)] + pub enum Denominator { + /// / Specifies a basic scalar denominator to divide by. + #[prost(double, tag = "1")] + Scalar(f64), + /// / Specifies another aggregator resut to divide by. + #[prost(string, tag = "2")] + AggregatorPubkey(::prost::alloc::string::String), + /// / A job whose result is computed before dividing our numerical input by that result. + #[prost(message, tag = "3")] + Job(super::super::OracleJob), + /// / A stringified big.js. `Accepts variable expansion syntax.` + #[prost(string, tag = "4")] + Big(::prost::alloc::string::String), + } + } + /// + /// This task will multiply a numerical input by a scalar value from a job of subtasks, an aggregator, or a big. + /// + /// _**Input**_: The current running numerical result output from a scalar value, an aggregator, a job of subtasks or a big. + /// + /// _**Returns**_: A numerical result. + /// + /// _**Example**_: Returns the numerical result by multiplying by a job of subtasks. + /// + /// ```json + /// {"tasks":\[{"valueTask":{"value":100}},{"multiplyTask":{"job":{"tasks":[{"valueTask":{"value":10}}\]}}}]} + /// ``` + /// + /// _**Example**_: Returns the numerical result by multiplying by an aggregator. + /// + /// ```json + /// {"tasks":\[{"valueTask":{"value":100}},{"multiplyTask":{"aggregatorPubkey":"GvDMxPzN1sCj7L26YDK2HnMRXEQmQ2aemov8YBtPS7vR"}}\]} + /// ``` + /// + /// _**Example**_: Returns the numerical result by multiplying by a big. + /// + /// ```json + /// {"tasks":\[{"cacheTask":{"cacheItems":[{"variableName":"TEN","job":{"tasks":[{"valueTask":{"value":10}}\]}}]}},{"valueTask":{"value":100}},{"multiplyTask":{"big":"${TEN}"}}]} + /// ``` + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct MultiplyTask { + #[prost(oneof = "multiply_task::Multiple", tags = "1, 2, 3, 4")] + pub multiple: ::core::option::Option, + } + /// Nested message and enum types in `MultiplyTask`. + pub mod multiply_task { + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Oneof)] + pub enum Multiple { + /// / Specifies a scalar to multiply by. + #[prost(double, tag = "1")] + Scalar(f64), + /// / Specifies an aggregator to multiply by. + #[prost(string, tag = "2")] + AggregatorPubkey(::prost::alloc::string::String), + /// / A job whose result is computed before multiplying our numerical input by that result. + #[prost(message, tag = "3")] + Job(super::super::OracleJob), + /// / A stringified big.js. `Accepts variable expansion syntax.` + #[prost(string, tag = "4")] + Big(::prost::alloc::string::String), + } + } + /// + /// This task will add a numerical input by a scalar value from a job of subtasks, an aggregator, or a big. + /// + /// _**Input**_: The current running numerical result output from a scalar value, an aggregator, a job of subtasks or a big. + /// + /// _**Returns**_: A numerical result. + /// + /// _**Example**_: Returns the numerical result by adding by a job of subtasks. + /// + /// ```json + /// {"tasks":\[{"valueTask":{"value":100}},{"addTask":{"job":{"tasks":[{"valueTask":{"value":10}}\]}}}]} + /// ``` + /// + /// _**Example**_: Returns the numerical result by multiplying by an aggregator. + /// + /// ```json + /// {"tasks":\[{"valueTask":{"value":100}},{"addTask":{"aggregatorPubkey":"GvDMxPzN1sCj7L26YDK2HnMRXEQmQ2aemov8YBtPS7vR"}}\]} + /// ``` + /// + /// _**Example**_: Returns the numerical result by multiplying by a big. + /// + /// ```json + /// {"tasks":\[{"cacheTask":{"cacheItems":[{"variableName":"TEN","job":{"tasks":[{"valueTask":{"value":10}}\]}}]}},{"valueTask":{"value":100}},{"addTask":{"big":"${TEN}"}}]} + /// ``` + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct AddTask { + #[prost(oneof = "add_task::Addition", tags = "1, 2, 3, 4")] + pub addition: ::core::option::Option, + } + /// Nested message and enum types in `AddTask`. + pub mod add_task { + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Oneof)] + pub enum Addition { + /// / Specifies a scalar to add by. + #[prost(double, tag = "1")] + Scalar(f64), + /// / Specifies an aggregator to add by. + #[prost(string, tag = "2")] + AggregatorPubkey(::prost::alloc::string::String), + /// / A job whose result is computed before adding our numerical input by that result. + #[prost(message, tag = "3")] + Job(super::super::OracleJob), + /// / A stringified big.js. `Accepts variable expansion syntax.` + #[prost(string, tag = "4")] + Big(::prost::alloc::string::String), + } + } + /// + /// This task will subtract a numerical input by a scalar value from a job of subtasks, an aggregator, or a big. + /// + /// _**Input**_: The current running numerical result output from a scalar value, an aggregator, a job of subtasks or a big. + /// + /// _**Returns**_: A numerical result. + /// + /// _**Example**_: Returns the numerical result by subtracting by a job of subtasks. + /// + /// ```json + /// {"tasks":\[{"valueTask":{"value":100}},{"subtractTask":{"job":{"tasks":[{"valueTask":{"value":10}}\]}}}]} + /// ``` + /// + /// _**Example**_: Returns the numerical result by multiplying by an aggregator. + /// + /// ```json + /// {"tasks":\[{"valueTask":{"value":100}},{"subtractTask":{"aggregatorPubkey":"GvDMxPzN1sCj7L26YDK2HnMRXEQmQ2aemov8YBtPS7vR"}}\]} + /// ``` + /// + /// _**Example**_: Returns the numerical result by multiplying by a big. + /// + /// ```json + /// {"tasks":\[{"cacheTask":{"cacheItems":[{"variableName":"TEN","job":{"tasks":[{"valueTask":{"value":10}}\]}}]}},{"valueTask":{"value":100}},{"subtractTask":{"big":"${TEN}"}}]} + /// ``` + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct SubtractTask { + #[prost(oneof = "subtract_task::Subtraction", tags = "1, 2, 3, 4")] + pub subtraction: ::core::option::Option, + } + /// Nested message and enum types in `SubtractTask`. + pub mod subtract_task { + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Oneof)] + pub enum Subtraction { + /// / Specifies a scalar to subtract by. + #[prost(double, tag = "1")] + Scalar(f64), + /// / Specifies an aggregator to subtract by. + #[prost(string, tag = "2")] + AggregatorPubkey(::prost::alloc::string::String), + /// / A job whose result is computed before subtracting our numerical input by that result. + #[prost(message, tag = "3")] + Job(super::super::OracleJob), + /// / A stringified big.js. `Accepts variable expansion syntax.` + #[prost(string, tag = "4")] + Big(::prost::alloc::string::String), + } + } + /// + /// Fetch LP token price info from a number of supported exchanges. + /// + /// See our blog post on [Fair LP Token Oracles](/blog/2022/01/20/Fair-LP-Token-Oracles) + /// + /// *NOTE**: This is not the swap price but the price of the underlying LP token. + /// + /// _**Input**_: None + /// + /// _**Returns**_: The price of an LP token for a given AMM pool. + /// + /// _**Example**_: Fetch the Orca LP token price of the SOL/USDC pool + /// + /// ```json + /// { "lpTokenPriceTask": { "orcaPoolAddress": "APDFRM3HMr8CAGXwKHiu2f5ePSpaiEJhaURwhsRrUUt9" } } + /// ``` + /// + /// _**Example**_: Fetch the fair price Orca LP token price of the SOL/USDC pool + /// + /// ```json + /// { "lpTokenPriceTask": { "orcaPoolAddress": "APDFRM3HMr8CAGXwKHiu2f5ePSpaiEJhaURwhsRrUUt9", "useFairPrice": true, "priceFeedAddresses": \[ "GvDMxPzN1sCj7L26YDK2HnMRXEQmQ2aemov8YBtPS7vR", "BjUgj6YCnFBZ49wF54ddBVA9qu8TeqkFtkbqmZcee8uW" \] } } + /// ``` + /// + /// _**Example**_: Fetch the fair price Raydium LP token price of the SOL/USDC pool + /// + /// ```json + /// { "lpTokenPriceTask": { "raydiumPoolAddress": "58oQChx4yWmvKdwLLZzBi4ChoCc2fqCUWBkwMihLYQo2", "useFairPrice": true,"priceFeedAddresses": \["GvDMxPzN1sCj7L26YDK2HnMRXEQmQ2aemov8YBtPS7vR","BjUgj6YCnFBZ49wF54ddBVA9qu8TeqkFtkbqmZcee8uW" \] } } + /// ``` + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct LpTokenPriceTask { + /// / A list of Switchboard aggregator accounts used to calculate the fair LP price. This ensures the price is based on the previous round to mitigate flash loan price manipulation. + #[prost(string, repeated, tag = "5")] + pub price_feed_addresses: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, + /// / A list of OracleJobs to execute in order to yield the price feed jobs to use for the fair price formula. + #[prost(message, repeated, tag = "6")] + pub price_feed_jobs: ::prost::alloc::vec::Vec, + /// / If enabled and price_feed_addresses provided, the oracle will calculate the fair LP price based on the liquidity pool reserves. See our blog post for more information: + #[prost(bool, optional, tag = "7")] + pub use_fair_price: ::core::option::Option, + #[prost(oneof = "lp_token_price_task::PoolAddress", tags = "1, 2, 3, 4")] + pub pool_address: ::core::option::Option, + } + /// Nested message and enum types in `LpTokenPriceTask`. + pub mod lp_token_price_task { + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Oneof)] + pub enum PoolAddress { + /// / Mercurial finance pool address. A full list can be found here: + #[prost(string, tag = "1")] + MercurialPoolAddress(::prost::alloc::string::String), + /// / Saber pool address. A full list can be found here: + #[prost(string, tag = "2")] + SaberPoolAddress(::prost::alloc::string::String), + /// / Orca pool address. A full list can be found here: + #[prost(string, tag = "3")] + OrcaPoolAddress(::prost::alloc::string::String), + /// / The Raydium liquidity pool ammId. A full list can be found here: + #[prost(string, tag = "4")] + RaydiumPoolAddress(::prost::alloc::string::String), + } + } + /// + /// Fetch the current swap price for a given liquidity pool + /// + /// _**Input**_: None + /// + /// _**Returns**_: The swap price for a given AMM pool. + /// + /// _**Example**_: Fetch the exchange rate from the Orca SOL/USDC pool + /// + /// ```json + /// { "lpExchangeRateTask": { "orcaPoolAddress": "APDFRM3HMr8CAGXwKHiu2f5ePSpaiEJhaURwhsRrUUt9" } } + /// ``` + /// + /// _**Example**_: Fetch the exchange rate from the Raydium SOL/USDC pool + /// + /// ```json + /// { "lpExchangeRateTask": { "raydiumPoolAddress": "58oQChx4yWmvKdwLLZzBi4ChoCc2fqCUWBkwMihLYQo2" } } + /// ``` + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct LpExchangeRateTask { + /// / Used alongside mercurial_pool_address to specify the input token for a swap. + #[prost(string, optional, tag = "1")] + pub in_token_address: ::core::option::Option<::prost::alloc::string::String>, + /// / Used alongside mercurial_pool_address to specify the output token for a swap. + #[prost(string, optional, tag = "2")] + pub out_token_address: ::core::option::Option<::prost::alloc::string::String>, + #[prost(enumeration = "lp_exchange_rate_task::Chain", optional, tag = "9")] + pub chain: ::core::option::Option, + #[prost( + oneof = "lp_exchange_rate_task::PoolAddress", + tags = "3, 4, 5, 6, 7, 8" + )] + pub pool_address: ::core::option::Option, + } + /// Nested message and enum types in `LpExchangeRateTask`. + pub mod lp_exchange_rate_task { + #[derive( + Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration, + )] + #[repr(i32)] + pub enum Chain { + Solana = 0, + Eclipse = 1, + } + impl Chain { + /// 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 { + Chain::Solana => "SOLANA", + Chain::Eclipse => "ECLIPSE", + } + } + /// Creates an enum from field names used in the ProtoBuf definition. + pub fn from_str_name(value: &str) -> ::core::option::Option { + match value { + "SOLANA" => Some(Self::Solana), + "ECLIPSE" => Some(Self::Eclipse), + _ => None, + } + } + } + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Oneof)] + pub enum PoolAddress { + /// / Mercurial finance pool address. A full list can be found here: + #[prost(string, tag = "3")] + MercurialPoolAddress(::prost::alloc::string::String), + /// / Saber pool address. A full list can be found here: + #[prost(string, tag = "4")] + SaberPoolAddress(::prost::alloc::string::String), + /// / **@deprecated** Use orcaPoolAddress + #[prost(string, tag = "5")] + OrcaPoolTokenMintAddress(::prost::alloc::string::String), + /// / The Raydium liquidity pool ammId. A full list can be found here: + #[prost(string, tag = "6")] + RaydiumPoolAddress(::prost::alloc::string::String), + /// / Pool address for an Orca LP pool or whirlpool. + /// / A full list of Orca LP pools can be found here: + #[prost(string, tag = "7")] + OrcaPoolAddress(::prost::alloc::string::String), + /// / The Port reserve pubkey. A full list can be found here: + #[prost(string, tag = "8")] + PortReserveAddress(::prost::alloc::string::String), + } + } + /// + /// Find and extract text using regular expressions from the previous task's output. + /// + /// _**Input**_: String output from previous task + /// + /// _**Returns**_: The matched string based on the regex pattern and group number + /// + /// _**Example**_: Extract the first number from a string + /// + /// ```json + /// { + /// "regexExtractTask": { + /// "pattern": "\\d+", + /// "groupNumber": 0 + /// } + /// } + /// ``` + /// + /// _**Example**_: Extract text between quotes + /// + /// ```json + /// { + /// "regexExtractTask": { + /// "pattern": "\"(\[^\"\]+)\"", + /// "groupNumber": 1 + /// } + /// } + /// ``` + /// + /// _**Example**_: Extract the first JSON object from a stream + /// + /// ```json + /// { + /// "regexExtractTask": { + /// "pattern": "\\{\[^}\]+\\}" + /// } + /// } + /// ``` + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct RegexExtractTask { + /// / The regular expression pattern to match against the input string. + /// / Uses the fancy-regex Rust crate syntax. + #[prost(string, optional, tag = "1")] + pub pattern: ::core::option::Option<::prost::alloc::string::String>, + /// / The capture group number to extract (0 returns full match, 1+ returns respective capture group). + /// / Defaults to 0 if not specified. + #[prost(int32, optional, tag = "2")] + pub group_number: ::core::option::Option, + } + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct XStepPriceTask { + #[prost(oneof = "x_step_price_task::StepSource", tags = "1, 2")] + pub step_source: ::core::option::Option, + } + /// Nested message and enum types in `XStepPriceTask`. + pub mod x_step_price_task { + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Oneof)] + pub enum StepSource { + /// / median task containing the job definitions to fetch the STEP/USD price + #[prost(message, tag = "1")] + StepJob(super::MedianTask), + /// / existing aggregator pubkey for STEP/USD + #[prost(string, tag = "2")] + StepAggregatorPubkey(::prost::alloc::string::String), + } + } + /// + /// Takes a twap over a set period for a certain aggregator. Aggregators have an optional history buffer account storing the last N accepted results. The TwapTask will iterate over an aggregators history buffer and calculate the time weighted average of the samples within a given time period. + /// + /// _**Input**_: None + /// + /// _**Returns**_: The time weighted average of an aggregator over a given time period. + /// + /// _**Example**_: The 1hr Twap of the SOL/USD Aggregator, requiring at least 60 samples. + /// + /// ```json + /// { "twapTask": { "aggregatorPubkey": "GvDMxPzN1sCj7L26YDK2HnMRXEQmQ2aemov8YBtPS7vR", "period": 3600, "minSamples": 60, "weightByPropagationTime": true } } + /// ``` + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct TwapTask { + /// / The target aggregator for the TWAP. + #[prost(string, optional, tag = "1")] + pub aggregator_pubkey: ::core::option::Option<::prost::alloc::string::String>, + /// / Period, in seconds, the twap should account for + #[prost(int32, optional, tag = "2")] + pub period: ::core::option::Option, + /// / Weight samples by their propagation time + #[prost(bool, optional, tag = "3")] + pub weight_by_propagation_time: ::core::option::Option, + /// / Minimum number of samples in the history to calculate a valid result + #[prost(uint32, optional, tag = "4")] + pub min_samples: ::core::option::Option, + /// / Ending unix timestamp to collect values up to + #[prost(int32, optional, tag = "5")] + pub ending_unix_timestamp: ::core::option::Option, + /// / Execute the task to get the ending unix timestamp + #[prost(message, optional, tag = "6")] + pub ending_unix_timestamp_task: ::core::option::Option, + } + /// / Fetch the latest swap price on Serum's orderbook + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct SerumSwapTask { + /// / The serum pool to fetch swap price for + #[prost(string, optional, tag = "1")] + pub serum_pool_address: ::core::option::Option<::prost::alloc::string::String>, + } + /// + /// Round the current running result to an exponential power. + /// + /// _**Input**_: The current running numerical result. + /// + /// _**Returns**_: The input raised to an exponential power. + /// + /// _**Example**_: Raise 2 to the power of 3, 2^3 + /// + /// ```json + /// {"tasks":\[{"valueTask":{"value":2}},{"powTask":{"scalar":3}}\]} + /// ``` + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct PowTask { + #[prost(oneof = "pow_task::Exponent", tags = "1, 2, 3")] + pub exponent: ::core::option::Option, + } + /// Nested message and enum types in `PowTask`. + pub mod pow_task { + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Oneof)] + pub enum Exponent { + /// / Take the working value to the exponent of value. + #[prost(double, tag = "1")] + Scalar(f64), + /// / Take the working value to the exponent of the aggregators value. + #[prost(string, tag = "2")] + AggregatorPubkey(::prost::alloc::string::String), + /// / A stringified big.js. `Accepts variable expansion syntax.` + #[prost(string, tag = "3")] + Big(::prost::alloc::string::String), + } + } + /// / Fetch the lending rates for various Solana protocols + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct LendingRateTask { + /// / 01, apricot, francium, jet, larix, mango, port, solend, tulip + #[prost(string, optional, tag = "1")] + pub protocol: ::core::option::Option<::prost::alloc::string::String>, + /// / A token mint address supported by the chosen protocol + #[prost(string, optional, tag = "2")] + pub asset_mint: ::core::option::Option<::prost::alloc::string::String>, + #[prost(enumeration = "lending_rate_task::Field", optional, tag = "3")] + pub field: ::core::option::Option, + } + /// Nested message and enum types in `LendingRateTask`. + pub mod lending_rate_task { + #[derive( + Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration, + )] + #[repr(i32)] + pub enum Field { + /// / deposit lending rate + DepositRate = 0, + /// / borrow lending rate + BorrowRate = 1, + } + impl Field { + /// 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 { + Field::DepositRate => "FIELD_DEPOSIT_RATE", + Field::BorrowRate => "FIELD_BORROW_RATE", + } + } + /// Creates an enum from field names used in the ProtoBuf definition. + pub fn from_str_name(value: &str) -> ::core::option::Option { + match value { + "FIELD_DEPOSIT_RATE" => Some(Self::DepositRate), + "FIELD_BORROW_RATE" => Some(Self::BorrowRate), + _ => None, + } + } + } + } + /// / Fetch the current price for a Mango perpetual market + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct MangoPerpMarketTask { + /// / Mainnet address for a mango perpetual market. A full list can be found here: + #[prost(string, optional, tag = "1")] + pub perp_market_address: ::core::option::Option<::prost::alloc::string::String>, + } + /// + /// Fetch the simulated price for a swap on JupiterSwap. + /// + /// _**Input**_: None + /// + /// _**Returns**_: The swap price on Jupiter for a given input and output token mint address. + /// + /// _**Example**_: Fetch the JupiterSwap price for exchanging 1 SOL into USDC. + /// + /// ```json + /// { "jupiterSwapTask": { "inTokenAddress": "So11111111111111111111111111111111111111112", "outTokenAddress": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" } } + /// ``` + /// + /// _**Example**_: Fetch the JupiterSwap price for exchanging 1000 SOL into USDC. + /// + /// ```json + /// { "jupiterSwapTask": { "inTokenAddress": "So11111111111111111111111111111111111111112", "outTokenAddress": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", "baseAmount": "1000" } } + /// ``` + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct JupiterSwapTask { + /// / The input token address. + #[prost(string, optional, tag = "1")] + pub in_token_address: ::core::option::Option<::prost::alloc::string::String>, + /// / The output token address. + #[prost(string, optional, tag = "2")] + pub out_token_address: ::core::option::Option<::prost::alloc::string::String>, + /// / The allowable slippage on the swap in decimal form (e.g. 0.5 is 0.5% slippage) + #[prost(double, optional, tag = "9")] + pub slippage: ::core::option::Option, + #[prost(enumeration = "jupiter_swap_task::Version", optional, tag = "10")] + pub version: ::core::option::Option, + #[prost(oneof = "jupiter_swap_task::RoutesFilters", tags = "4, 5")] + pub routes_filters: ::core::option::Option, + #[prost(oneof = "jupiter_swap_task::SwapAmount", tags = "3, 6, 7, 8")] + pub swap_amount: ::core::option::Option, + } + /// Nested message and enum types in `JupiterSwapTask`. + pub mod jupiter_swap_task { + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct FilterList { + /// / A list of Jupiter AMM labels to allow or deny (e.g. 'Raydium', 'Orca') + #[prost(string, repeated, tag = "1")] + pub labels: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, + } + #[derive( + Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration, + )] + #[repr(i32)] + pub enum Version { + V1 = 0, + V2 = 1, + } + impl Version { + /// 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 { + Version::V1 => "VERSION_V1", + Version::V2 => "VERSION_V2", + } + } + /// Creates an enum from field names used in the ProtoBuf definition. + pub fn from_str_name(value: &str) -> ::core::option::Option { + match value { + "VERSION_V1" => Some(Self::V1), + "VERSION_V2" => Some(Self::V2), + _ => None, + } + } + } + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Oneof)] + pub enum RoutesFilters { + /// / A list of AMM markets to allow. + #[prost(message, tag = "4")] + AllowList(FilterList), + /// / A list of AMM markets to deny. + #[prost(message, tag = "5")] + DenyList(FilterList), + } + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Oneof)] + pub enum SwapAmount { + /// / The amount of `in_token_address` tokens to swap. + #[prost(double, tag = "3")] + BaseAmount(f64), + /// / The amount of `out_token_address` tokens to swap. + #[prost(double, tag = "6")] + QuoteAmount(f64), + /// / The amount of `in_token_address` tokens to swap. + #[prost(string, tag = "7")] + BaseAmountString(::prost::alloc::string::String), + /// / The amount of `out_token_address` tokens to swap. + #[prost(string, tag = "8")] + QuoteAmountString(::prost::alloc::string::String), + } + } + /// / Fetch the current price of a perpetual market. + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct PerpMarketTask { + #[prost(oneof = "perp_market_task::MarketAddress", tags = "1, 2, 3, 4")] + pub market_address: ::core::option::Option, + } + /// Nested message and enum types in `PerpMarketTask`. + pub mod perp_market_task { + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Oneof)] + pub enum MarketAddress { + /// / Market address for a mango perpetual market. A full list can be found here: + #[prost(string, tag = "1")] + MangoMarketAddress(::prost::alloc::string::String), + /// / Market address for a drift perpetual market. A full list can be found here: + #[prost(string, tag = "2")] + DriftMarketAddress(::prost::alloc::string::String), + /// / Market address for a zeta perpetual market. + #[prost(string, tag = "3")] + ZetaMarketAddress(::prost::alloc::string::String), + /// / Market address for a 01 protocol perpetual market. + #[prost(string, tag = "4")] + ZoMarketAddress(::prost::alloc::string::String), + } + } + /// + /// Fetch the current price of a Solana oracle protocol. + /// + /// _**Input**_: None + /// + /// _**Returns**_: The current price of an on-chain oracle. + /// + /// _**Example**_: The Switchboard SOL/USD oracle price. + /// + /// ```json + /// { "oracleTask": { "switchboardAddress": "GvDMxPzN1sCj7L26YDK2HnMRXEQmQ2aemov8YBtPS7vR" } } + /// ``` + /// + /// _**Example**_: The Pyth SOL/USD oracle price. + /// + /// ```json + /// { "oracleTask": { "pythAddress": "H6ARHf6YXhGYeQfUzQNGk6rDNnLBQKrenN712K4AQJEG" } } + /// ``` + /// + /// _**Example**_: The Chainlink SOL/USD oracle price. + /// + /// ```json + /// { "oracleTask": { "chainlinkAddress": "CcPVS9bqyXbD9cLnTbhhHazLsrua8QMFUHTutPtjyDzq" } } + /// ``` + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct OracleTask { + /// / Value (as a percentage) that the lower bound confidence interval is of the actual value. + /// / Confidence intervals that are larger that this treshold are rejected. + /// / + /// / The confidence interval should be provided as a raw percentage value. For example, to + /// / represent 10%, enter the value as 10, not 0.1. + /// + /// Deprecated "pyth_allowed_confidence_interval" + #[prost(double, optional, tag = "4")] + pub pyth_allowed_confidence_interval: ::core::option::Option, + #[prost(message, optional, tag = "5")] + pub chainlink_configs: ::core::option::Option, + #[prost(message, optional, tag = "6")] + pub pyth_configs: ::core::option::Option, + #[prost(message, optional, tag = "9")] + pub switchboard_configs: ::core::option::Option, + #[prost(message, optional, tag = "10")] + pub edge_configs: ::core::option::Option, + #[prost(message, optional, tag = "11")] + pub redstone_configs: ::core::option::Option, + #[prost(oneof = "oracle_task::AggregatorAddress", tags = "1, 2, 3, 7, 8")] + pub aggregator_address: ::core::option::Option, + } + /// Nested message and enum types in `OracleTask`. + pub mod oracle_task { + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct ChainlinkConfigs { + #[prost(string, optional, tag = "1")] + pub provider: ::core::option::Option<::prost::alloc::string::String>, + } + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct PythConfigs { + #[prost(string, optional, tag = "1")] + pub hermes_url: ::core::option::Option<::prost::alloc::string::String>, + #[prost(double, optional, tag = "2")] + pub pyth_allowed_confidence_interval: ::core::option::Option, + #[prost(int32, optional, tag = "3")] + pub max_stale_seconds: ::core::option::Option, + } + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct SwitchboardConfigs { + #[prost(int32, optional, tag = "1")] + pub version: ::core::option::Option, + #[prost(message, repeated, tag = "2")] + pub jobs: ::prost::alloc::vec::Vec, + } + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct EdgeConfigs {} + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct RedstoneConfigs {} + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Oneof)] + pub enum AggregatorAddress { + /// / Mainnet address of a Switchboard feed. Switchboard is decentralized and allows anyone to build their own feed. + #[prost(string, tag = "1")] + SwitchboardAddress(::prost::alloc::string::String), + /// / Mainnet address for a Pyth feed. A full list can be found here: + #[prost(string, tag = "2")] + PythAddress(::prost::alloc::string::String), + /// / Mainnet address for a Chainlink feed. A full list can be found here: + #[prost(string, tag = "3")] + ChainlinkAddress(::prost::alloc::string::String), + #[prost(string, tag = "7")] + EdgeId(::prost::alloc::string::String), + #[prost(string, tag = "8")] + RedstoneId(::prost::alloc::string::String), + } + } + /// / Load a parse an Anchor based solana account. + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct AnchorFetchTask { + /// / Owning program of the account to parse. + #[prost(string, optional, tag = "1")] + pub program_id: ::core::option::Option<::prost::alloc::string::String>, + /// / The account to parse. + #[prost(string, optional, tag = "2")] + pub account_address: ::core::option::Option<::prost::alloc::string::String>, + } + /// / Fetch the JSON representation of an SPL Stake Pool account. + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct SplStakePoolTask { + /// / The pubkey of the SPL Stake Pool. + #[prost(string, optional, tag = "1")] + pub pubkey: ::core::option::Option<::prost::alloc::string::String>, + } + /// / Fetch the JSON representation of an SPL token mint. + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct SplTokenParseTask { + #[prost(oneof = "spl_token_parse_task::AccountAddress", tags = "1, 2")] + pub account_address: ::core::option::Option, + } + /// Nested message and enum types in `SplTokenParseTask`. + pub mod spl_token_parse_task { + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Oneof)] + pub enum AccountAddress { + /// / The publicKey of a token account to fetch the mintInfo for. + #[prost(string, tag = "1")] + TokenAccountAddress(::prost::alloc::string::String), + /// / The publicKey of the token mint address. + #[prost(string, tag = "2")] + MintAddress(::prost::alloc::string::String), + } + } + /// / Fetch the swap price from UniSwap. + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct UniswapExchangeRateTask { + /// / The input token address. + #[prost(string, optional, tag = "1")] + pub in_token_address: ::core::option::Option<::prost::alloc::string::String>, + /// / The output token address. + #[prost(string, optional, tag = "2")] + pub out_token_address: ::core::option::Option<::prost::alloc::string::String>, + /// / The amount of tokens to swap. + #[prost(double, optional, tag = "3")] + pub in_token_amount: ::core::option::Option, + /// / The allowable slippage in percent for the swap. + #[prost(double, optional, tag = "4")] + pub slippage: ::core::option::Option, + /// / The RPC provider to use for the swap. + #[prost(string, optional, tag = "5")] + pub provider: ::core::option::Option<::prost::alloc::string::String>, + /// / The version of the Uniswap exchange to use. + #[prost( + enumeration = "uniswap_exchange_rate_task::Version", + optional, + tag = "6" + )] + pub version: ::core::option::Option, + #[prost(string, optional, tag = "7")] + pub router_address: ::core::option::Option<::prost::alloc::string::String>, + #[prost(string, optional, tag = "8")] + pub factory_address: ::core::option::Option<::prost::alloc::string::String>, + #[prost(string, optional, tag = "9")] + pub quoter_address: ::core::option::Option<::prost::alloc::string::String>, + } + /// Nested message and enum types in `UniswapExchangeRateTask`. + pub mod uniswap_exchange_rate_task { + #[derive( + Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration, + )] + #[repr(i32)] + pub enum Version { + V2Deprecated = 0, + V3Deprecated = 1, + V2 = 2, + V3 = 3, + } + impl Version { + /// 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 { + Version::V2Deprecated => "VERSION_V2_DEPRECATED", + Version::V3Deprecated => "VERSION_V3_DEPRECATED", + Version::V2 => "VERSION_V2", + Version::V3 => "VERSION_V3", + } + } + /// Creates an enum from field names used in the ProtoBuf definition. + pub fn from_str_name(value: &str) -> ::core::option::Option { + match value { + "VERSION_V2_DEPRECATED" => Some(Self::V2Deprecated), + "VERSION_V3_DEPRECATED" => Some(Self::V3Deprecated), + "VERSION_V2" => Some(Self::V2), + "VERSION_V3" => Some(Self::V3), + _ => None, + } + } + } + } + /// / Fetch the swap price from SushiSwap. + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct SushiswapExchangeRateTask { + /// / The input token address. + #[prost(string, optional, tag = "1")] + pub in_token_address: ::core::option::Option<::prost::alloc::string::String>, + /// / The output token address. + #[prost(string, optional, tag = "2")] + pub out_token_address: ::core::option::Option<::prost::alloc::string::String>, + /// / The amount of tokens to swap. + #[prost(double, optional, tag = "3")] + pub in_token_amount: ::core::option::Option, + /// / The allowable slippage in percent for the swap. + #[prost(double, optional, tag = "4")] + pub slippage: ::core::option::Option, + /// / The RPC provider to use for the swap. + #[prost(string, optional, tag = "5")] + pub provider: ::core::option::Option<::prost::alloc::string::String>, + } + /// / Fetch the swap price from PancakeSwap. + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct PancakeswapExchangeRateTask { + /// / The input token address. + #[prost(string, optional, tag = "1")] + pub in_token_address: ::core::option::Option<::prost::alloc::string::String>, + /// / The output token address. + #[prost(string, optional, tag = "2")] + pub out_token_address: ::core::option::Option<::prost::alloc::string::String>, + /// / The amount of tokens to swap. + #[prost(double, optional, tag = "3")] + pub in_token_amount: ::core::option::Option, + /// / The allowable slippage in percent for the swap. + #[prost(double, optional, tag = "4")] + pub slippage: ::core::option::Option, + /// / The RPC provider to use for the swap. + #[prost(string, optional, tag = "5")] + pub provider: ::core::option::Option<::prost::alloc::string::String>, + } + /// + /// Execute a job and store the result in a variable to reference later. + /// + /// _**Input**_: None + /// + /// _**Returns**_: The input + /// + /// _**Example**_: CacheTask storing ${ONE} = 1 + /// + /// ```json + /// { "cacheTask": { "cacheItems": \[ { "variableName": "ONE", "job": { "tasks": [ { "valueTask": { "value": 1 } } \] } } ] } } + /// ``` + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct CacheTask { + /// / A list of cached variables to reference in the job with `${VARIABLE_NAME}`. + #[prost(message, repeated, tag = "1")] + pub cache_items: ::prost::alloc::vec::Vec, + } + /// Nested message and enum types in `CacheTask`. + pub mod cache_task { + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct CacheItem { + /// / The name of the variable to store in cache to reference later with `${VARIABLE_NAME}`. + #[prost(string, optional, tag = "1")] + pub variable_name: ::core::option::Option<::prost::alloc::string::String>, + /// / The OracleJob to execute to yield the value to store in cache. + #[prost(message, optional, tag = "2")] + pub job: ::core::option::Option, + } + } + /// / Return the difference between an oracle's clock and the current timestamp at `SYSVAR_CLOCK_PUBKEY`. + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct SysclockOffsetTask {} + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct MarinadeStateTask {} + /// / Fetch the account data in a stringified buffer format. + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct SolanaAccountDataFetchTask { + /// / The on-chain account to fetch the account data from. + #[prost(string, optional, tag = "1")] + pub pubkey: ::core::option::Option<::prost::alloc::string::String>, + #[prost( + enumeration = "solana_account_data_fetch_task::Network", + optional, + tag = "2" + )] + pub network: ::core::option::Option, + } + /// Nested message and enum types in `SolanaAccountDataFetchTask`. + pub mod solana_account_data_fetch_task { + #[derive( + Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration, + )] + #[repr(i32)] + pub enum Network { + Mainnet = 0, + Testnet = 1, + Devnet = 2, + } + impl Network { + /// 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 { + Network::Mainnet => "NETWORK_MAINNET", + Network::Testnet => "NETWORK_TESTNET", + Network::Devnet => "NETWORK_DEVNET", + } + } + /// Creates an enum from field names used in the ProtoBuf definition. + pub fn from_str_name(value: &str) -> ::core::option::Option { + match value { + "NETWORK_MAINNET" => Some(Self::Mainnet), + "NETWORK_TESTNET" => Some(Self::Testnet), + "NETWORK_DEVNET" => Some(Self::Devnet), + _ => None, + } + } + } + } + /// + /// Return a timestamp from a crontab instruction. + /// + /// _**Input**_: None + /// + /// _**Returns**_: A timestamp + /// + /// _**Example**_: Return the unix timestamp for the on-chain SYSCLOCK + /// + /// ```json + /// {"cronParseTask":{"cronPattern":"* * * * * *","clockOffset":0,"clock":"SYSCLOCK"}} + /// ``` + /// + /// _**Example**_: Return the unix timestamp for next friday at 5pm UTC + /// + /// ```json + /// {"cronParseTask":{"cronPattern":"0 17 * * 5","clockOffset":0,"clock":0}} + /// ``` + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct CronParseTask { + /// / The cron pattern to parse. + #[prost(string, optional, tag = "1")] + pub cron_pattern: ::core::option::Option<::prost::alloc::string::String>, + /// / The timestamp offset to calculate the next run. + #[prost(int32, optional, tag = "2")] + pub clock_offset: ::core::option::Option, + /// / Use the TaskRunner's clock or the on-chain SYSCLOCK. + #[prost(enumeration = "cron_parse_task::ClockType", optional, tag = "3")] + pub clock: ::core::option::Option, + } + /// Nested message and enum types in `CronParseTask`. + pub mod cron_parse_task { + #[derive( + Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration, + )] + #[repr(i32)] + pub enum ClockType { + /// / Use the TaskRunners system clock for the current time. + Oracle = 0, + /// / Use the on-chain SYSCLOCK for the current time. + Sysclock = 1, + } + impl ClockType { + /// 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 { + ClockType::Oracle => "ORACLE", + ClockType::Sysclock => "SYSCLOCK", + } + } + /// Creates an enum from field names used in the ProtoBuf definition. + pub fn from_str_name(value: &str) -> ::core::option::Option { + match value { + "ORACLE" => Some(Self::Oracle), + "SYSCLOCK" => Some(Self::Sysclock), + _ => None, + } + } + } + } + /// / Return the deserialized value from a stringified buffer. + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct BufferLayoutParseTask { + /// / The buffer offset to start deserializing from. + #[prost(uint32, optional, tag = "1")] + pub offset: ::core::option::Option, + /// / The endianness of the stored value. + #[prost(enumeration = "buffer_layout_parse_task::Endian", optional, tag = "2")] + pub endian: ::core::option::Option, + /// / The type of value to deserialize. + #[prost( + enumeration = "buffer_layout_parse_task::BufferParseType", + optional, + tag = "3" + )] + pub r#type: ::core::option::Option, + } + /// Nested message and enum types in `BufferLayoutParseTask`. + pub mod buffer_layout_parse_task { + #[derive( + Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration, + )] + #[repr(i32)] + pub enum Endian { + /// Use little endian byte order. + LittleEndian = 0, + /// Use big endian byte order. + BigEndian = 1, + } + impl Endian { + /// 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 { + Endian::LittleEndian => "LITTLE_ENDIAN", + Endian::BigEndian => "BIG_ENDIAN", + } + } + /// Creates an enum from field names used in the ProtoBuf definition. + pub fn from_str_name(value: &str) -> ::core::option::Option { + match value { + "LITTLE_ENDIAN" => Some(Self::LittleEndian), + "BIG_ENDIAN" => Some(Self::BigEndian), + _ => None, + } + } + } + #[derive( + Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration, + )] + #[repr(i32)] + pub enum BufferParseType { + /// / A public key. + Pubkey = 1, + /// / A boolean. + Bool = 2, + /// / An 8-bit unsigned value. + U8 = 3, + /// / An 8-bit signed value. + I8 = 4, + /// / A 16-bit unsigned value. + U16 = 5, + /// / A 16-bit signed value. + I16 = 6, + /// / A 32-bit unsigned value. + U32 = 7, + /// / A 32-bit signed value. + I32 = 8, + /// / A 32-bit IEEE floating point value. + F32 = 9, + /// / A 64-bit unsigned value. + U64 = 10, + /// / A 64-bit signed value. + I64 = 11, + /// / A 64-bit IEEE floating point value. + F64 = 12, + /// / A 128-bit unsigned value. + U128 = 13, + /// / A 128-bit signed value. + I128 = 14, + } + impl BufferParseType { + /// 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 { + BufferParseType::Pubkey => "pubkey", + BufferParseType::Bool => "bool", + BufferParseType::U8 => "u8", + BufferParseType::I8 => "i8", + BufferParseType::U16 => "u16", + BufferParseType::I16 => "i16", + BufferParseType::U32 => "u32", + BufferParseType::I32 => "i32", + BufferParseType::F32 => "f32", + BufferParseType::U64 => "u64", + BufferParseType::I64 => "i64", + BufferParseType::F64 => "f64", + BufferParseType::U128 => "u128", + BufferParseType::I128 => "i128", + } + } + /// Creates an enum from field names used in the ProtoBuf definition. + pub fn from_str_name(value: &str) -> ::core::option::Option { + match value { + "pubkey" => Some(Self::Pubkey), + "bool" => Some(Self::Bool), + "u8" => Some(Self::U8), + "i8" => Some(Self::I8), + "u16" => Some(Self::U16), + "i16" => Some(Self::I16), + "u32" => Some(Self::U32), + "i32" => Some(Self::I32), + "f32" => Some(Self::F32), + "u64" => Some(Self::U64), + "i64" => Some(Self::I64), + "f64" => Some(Self::F64), + "u128" => Some(Self::U128), + "i128" => Some(Self::I128), + _ => None, + } + } + } + } + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct HistoryFunctionTask { + #[prost(enumeration = "history_function_task::Method", optional, tag = "1")] + pub method: ::core::option::Option, + #[prost(string, optional, tag = "2")] + pub aggregator_address: ::core::option::Option<::prost::alloc::string::String>, + #[prost(uint32, optional, tag = "3")] + pub period: ::core::option::Option, + } + /// Nested message and enum types in `HistoryFunctionTask`. + pub mod history_function_task { + #[derive( + Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration, + )] + #[repr(i32)] + pub enum Method { + Min = 0, + Max = 1, + } + impl Method { + /// 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 { + Method::Min => "METHOD_MIN", + Method::Max => "METHOD_MAX", + } + } + /// Creates an enum from field names used in the ProtoBuf definition. + pub fn from_str_name(value: &str) -> ::core::option::Option { + match value { + "METHOD_MIN" => Some(Self::Min), + "METHOD_MAX" => Some(Self::Max), + _ => None, + } + } + } + } + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct VwapTask { + #[prost(string, optional, tag = "1")] + pub price_aggregator_address: ::core::option::Option<::prost::alloc::string::String>, + #[prost(string, optional, tag = "2")] + pub volume_aggregator_address: ::core::option::Option<::prost::alloc::string::String>, + #[prost(uint32, optional, tag = "3")] + pub period: ::core::option::Option, + } + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct EwmaTask { + #[prost(string, optional, tag = "1")] + pub aggregator_address: ::core::option::Option<::prost::alloc::string::String>, + #[prost(int32, optional, tag = "2")] + pub period: ::core::option::Option, + #[prost(double, optional, tag = "3")] + pub lambda: ::core::option::Option, + } + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct ComparisonTask { + /// / The type of operator to use on the left (lhs) and right (rhs) operand. + #[prost(enumeration = "comparison_task::Operation", optional, tag = "1")] + pub op: ::core::option::Option, + /// / The OracleJob to execute if the condition evaluates to true. + #[prost(message, optional, tag = "6")] + pub on_true: ::core::option::Option, + /// / The result to use if the condition evaluates to true. Can be set to a `${CACHE_KEY}`. + #[prost(string, optional, tag = "7")] + pub on_true_value: ::core::option::Option<::prost::alloc::string::String>, + /// / The OracleJob to execute if the condition evaluates to false. + #[prost(message, optional, tag = "8")] + pub on_false: ::core::option::Option, + /// / The result to use if the condition evaluates to false. Can be set to a `${CACHE_KEY}`. + #[prost(string, optional, tag = "9")] + pub on_false_value: ::core::option::Option<::prost::alloc::string::String>, + /// / The OracleJob to execute if the condition fails to evaluate. + #[prost(message, optional, tag = "10")] + pub on_failure: ::core::option::Option, + /// / The result to use if the condition fails to evaluate. Can be set to a `${CACHE_KEY}`. + #[prost(string, optional, tag = "11")] + pub on_failure_value: ::core::option::Option<::prost::alloc::string::String>, + #[prost(oneof = "comparison_task::Lhs", tags = "2, 3")] + pub lhs: ::core::option::Option, + #[prost(oneof = "comparison_task::Rhs", tags = "4, 5")] + pub rhs: ::core::option::Option, + } + /// Nested message and enum types in `ComparisonTask`. + pub mod comparison_task { + #[derive( + Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration, + )] + #[repr(i32)] + pub enum Operation { + /// / Use the equals to '==' operator. + Eq = 0, + /// / Use the greater than '>' operator. + Gt = 1, + /// / Use the less than '<' operator. + Lt = 2, + } + impl Operation { + /// 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 { + Operation::Eq => "OPERATION_EQ", + Operation::Gt => "OPERATION_GT", + Operation::Lt => "OPERATION_LT", + } + } + /// Creates an enum from field names used in the ProtoBuf definition. + pub fn from_str_name(value: &str) -> ::core::option::Option { + match value { + "OPERATION_EQ" => Some(Self::Eq), + "OPERATION_GT" => Some(Self::Gt), + "OPERATION_LT" => Some(Self::Lt), + _ => None, + } + } + } + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Oneof)] + pub enum Lhs { + /// / OracleJob where the executed result is equal to the left hand side operand. + #[prost(message, tag = "2")] + Lhs(super::super::OracleJob), + /// / String or `${CACHE_KEY}` representing the left hand side operand. + #[prost(string, tag = "3")] + LhsValue(::prost::alloc::string::String), + } + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Oneof)] + pub enum Rhs { + /// / OracleJob where the executed result is equal to the right hand side operand. + #[prost(message, tag = "4")] + Rhs(super::super::OracleJob), + /// / String or `${CACHE_KEY}` representing the right hand side operand. + #[prost(string, tag = "5")] + RhsValue(::prost::alloc::string::String), + } + } + /// + /// Round the current running result to a set number of decimal places. + /// + /// _**Input**_: The current running numerical result. + /// + /// _**Returns**_: The running result rounded to a set number of decimal places. + /// + /// _**Example**_: Round down the running resul to 8 decimal places + /// + /// ```json + /// { "roundTask": { "method": "METHOD_ROUND_DOWN", "decimals": 8 } } + /// ``` + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct RoundTask { + /// / The rounding method to use. + #[prost(enumeration = "round_task::Method", optional, tag = "1")] + pub method: ::core::option::Option, + /// / The number of decimals to round to. + #[prost(int32, optional, tag = "2")] + pub decimals: ::core::option::Option, + } + /// Nested message and enum types in `RoundTask`. + pub mod round_task { + #[derive( + Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration, + )] + #[repr(i32)] + pub enum Method { + /// / Round the result down. + RoundUp = 0, + /// / Round the result up. + RoundDown = 1, + } + impl Method { + /// 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 { + Method::RoundUp => "METHOD_ROUND_UP", + Method::RoundDown => "METHOD_ROUND_DOWN", + } + } + /// Creates an enum from field names used in the ProtoBuf definition. + pub fn from_str_name(value: &str) -> ::core::option::Option { + match value { + "METHOD_ROUND_UP" => Some(Self::RoundUp), + "METHOD_ROUND_DOWN" => Some(Self::RoundDown), + _ => None, + } + } + } + } + /// + /// Bound the running result to an upper/lower bound. This is typically the last task in an OracleJob. + /// + /// _**Input**_: The current running numerical result. + /// + /// _**Returns**_: The running result bounded to an upper or lower bound if it exceeds a given threshold. + /// + /// _**Example**_: Bound the running result to a value between 0.90 and 1.10 + /// + /// ```json + /// { "boundTask": { "lowerBoundValue": "0.90","onExceedsLowerBoundValue": "0.90","upperBoundValue": "1.10","onExceedsUpperBoundValue": "1.10" } } + /// ``` + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct BoundTask { + /// / The OracleJob to execute for the lower bound value. + #[prost(message, optional, tag = "1")] + pub lower_bound: ::core::option::Option, + /// / The value to use for the lower bound. Can be set to a `${CACHE_KEY}`. + #[prost(string, optional, tag = "2")] + pub lower_bound_value: ::core::option::Option<::prost::alloc::string::String>, + /// / The OracleJob to execute for the upper bound value. + #[prost(message, optional, tag = "3")] + pub upper_bound: ::core::option::Option, + /// / The value to use for the upper bound. Can be set to a `${CACHE_KEY}`. + #[prost(string, optional, tag = "4")] + pub upper_bound_value: ::core::option::Option<::prost::alloc::string::String>, + /// / The OracleJob to execute if the upper bound is exceeded. + #[prost(message, optional, tag = "5")] + pub on_exceeds_upper_bound: ::core::option::Option, + /// / The value to use if the upper bound is exceeded. Can be set to a `${CACHE_KEY}`. + #[prost(string, optional, tag = "6")] + pub on_exceeds_upper_bound_value: ::core::option::Option<::prost::alloc::string::String>, + /// / The OracleJob to execute if the lower bound is exceeded. + #[prost(message, optional, tag = "7")] + pub on_exceeds_lower_bound: ::core::option::Option, + /// / The value to use if the lower bound is exceeded. Can be set to a `${CACHE_KEY}`. + #[prost(string, optional, tag = "8")] + pub on_exceeds_lower_bound_value: ::core::option::Option<::prost::alloc::string::String>, + } + /// + /// Securely request secrets from a Switchboard SecretsServer that are owned by a specific authority. Any secrets that are returned for the current feed will then be unwrapped into variables to be accessed later. + /// + /// _**Input**_: None + /// + /// _**Returns**_: The input + /// + /// _**Example**_: SecretsTask + /// + /// ```json + /// { "secretsTask": { "authority": "Accb21tUCWocJea6Uk3DgrNZawgmKegDVeHw8cGMDPi5" } } + /// ``` + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct SecretsTask { + /// / The authority of the secrets that are to be requested. + #[prost(string, optional, tag = "1")] + pub authority: ::core::option::Option<::prost::alloc::string::String>, + /// / The url of the server to request secrets from. The default is + #[prost(string, optional, tag = "2")] + pub url: ::core::option::Option<::prost::alloc::string::String>, + } + /// / Grab the price of an Sanctum LST relative to SOL. + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct SanctumLstPriceTask { + /// / The address of the LST mint. + /// / + /// / e.g. INF - 5oVNBeEEQvYi1cX3ir8Dx5n1P7pdxydbGF2X4TxVusJm + #[prost(string, optional, tag = "1")] + pub lst_mint: ::core::option::Option<::prost::alloc::string::String>, + /// / Allow the check to see if the LST was cranked for the current epoch to be skipped. + #[prost(bool, optional, tag = "2")] + pub skip_epoch_check: ::core::option::Option, + } + /// / OndoUsdyTask represents a task that computes the price of USDY relative to USD using a + /// / specified strategy. + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct OndoUsdyTask { + /// / The strategy used to determine the price of USDY. + #[prost(enumeration = "ondo_usdy_task::Strategy", optional, tag = "1")] + pub strategy: ::core::option::Option, + } + /// Nested message and enum types in `OndoUsdyTask`. + pub mod ondo_usdy_task { + /// / Strategy specifies the method used to determine the price of USDY. + /// / + /// / - STRATEGY_FAIR_VALUE: Computes the price based on a fair value model. + /// / - STRATEGY_MARKET: Fetches the price directly from the market. + #[derive( + Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration, + )] + #[repr(i32)] + pub enum Strategy { + FairValue = 0, + Market = 1, + } + impl Strategy { + /// 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 { + Strategy::FairValue => "STRATEGY_FAIR_VALUE", + Strategy::Market => "STRATEGY_MARKET", + } + } + /// Creates an enum from field names used in the ProtoBuf definition. + pub fn from_str_name(value: &str) -> ::core::option::Option { + match value { + "STRATEGY_FAIR_VALUE" => Some(Self::FairValue), + "STRATEGY_MARKET" => Some(Self::Market), + _ => None, + } + } + } + } + /// / Grab the swap price from a Meteora pool. + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct MeteoraSwapTask { + /// / The address of the pool. + #[prost(string, optional, tag = "1")] + pub pool: ::core::option::Option<::prost::alloc::string::String>, + /// / The pool type. + #[prost(enumeration = "meteora_swap_task::Type", optional, tag = "2")] + pub r#type: ::core::option::Option, + } + /// Nested message and enum types in `MeteoraSwapTask`. + pub mod meteora_swap_task { + #[derive( + Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration, + )] + #[repr(i32)] + pub enum Type { + Dlmm = 0, + Standard = 1, + } + impl Type { + /// 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 { + Type::Dlmm => "TYPE_DLMM", + Type::Standard => "TYPE_STANDARD", + } + } + /// Creates an enum from field names used in the ProtoBuf definition. + pub fn from_str_name(value: &str) -> ::core::option::Option { + match value { + "TYPE_DLMM" => Some(Self::Dlmm), + "TYPE_STANDARD" => Some(Self::Standard), + _ => None, + } + } + } + } + /// / Get current time in seconds since Unix epoch. + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct UnixTimeTask { + /// / The offset to subtract from the current time. + #[prost(int32, optional, tag = "1")] + pub offset: ::core::option::Option, + } + /// + /// Fetch pricing information for Maple Finance assets. + /// + /// _**Input**_: None + /// + /// _**Returns**_: The requested price or value based on the specified method. + /// + /// _**Example**_: Fetch the syrupUSDC fair price from Maple Finance + /// + /// ```json + /// { "mapleFinanceTask": { "method": "METHOD_SYRUP_USDC_FAIR_PRICE" } } + /// ``` + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct MapleFinanceTask { + /// / The specific method to use for this task. + #[prost(enumeration = "maple_finance_task::Method", optional, tag = "1")] + pub method: ::core::option::Option, + } + /// Nested message and enum types in `MapleFinanceTask`. + pub mod maple_finance_task { + /// / Specifies the method to use for fetching Maple Finance data. + #[derive( + Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration, + )] + #[repr(i32)] + pub enum Method { + /// / Fetch the fair price of syrupUSDC in the Maple Finance ecosystem. + SyrupUsdcFairPrice = 0, + } + impl Method { + /// 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 { + Method::SyrupUsdcFairPrice => "METHOD_SYRUP_USDC_FAIR_PRICE", + } + } + /// Creates an enum from field names used in the ProtoBuf definition. + pub fn from_str_name(value: &str) -> ::core::option::Option { + match value { + "METHOD_SYRUP_USDC_FAIR_PRICE" => Some(Self::SyrupUsdcFairPrice), + _ => None, + } + } + } + } + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct GlyphTask { + #[prost(string, optional, tag = "1")] + pub pool_address: ::core::option::Option<::prost::alloc::string::String>, + #[prost(bool, optional, tag = "2")] + pub zero_for_one: ::core::option::Option, + } + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct CorexTask { + #[prost(string, optional, tag = "1")] + pub in_token: ::core::option::Option<::prost::alloc::string::String>, + #[prost(string, optional, tag = "2")] + pub out_token: ::core::option::Option<::prost::alloc::string::String>, + #[prost(double, optional, tag = "3")] + pub slippage: ::core::option::Option, + } + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct AftermathTask { + #[prost(string, optional, tag = "1")] + pub pool_address: ::core::option::Option<::prost::alloc::string::String>, + #[prost(double, optional, tag = "2")] + pub in_amount: ::core::option::Option, + #[prost(string, optional, tag = "3")] + pub in_coin_type: ::core::option::Option<::prost::alloc::string::String>, + #[prost(string, optional, tag = "4")] + pub out_coin_type: ::core::option::Option<::prost::alloc::string::String>, + } + /// + /// Interacts with a Large Language Model (LLM) to generate a text response based on a user-provided prompt. + /// + /// _**Input**_: None + /// + /// _**Returns**_: Text generated by the LLM based on the provided prompt and configuration. + /// + /// _**Example**_: Using OpenAI's GPT-4 model to generate a joke. + /// + /// ```json + /// { + /// "llmTask": { + /// "providerConfig": { + /// "openai": { + /// "model": "gpt-4", + /// "userPrompt": "Tell me a joke.", + /// "temperature": 0.7, + /// "secretNameApiKey": "${OPENAI_API_KEY}" + /// } + /// } + /// } + /// } + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct LlmTask { + #[prost(oneof = "llm_task::ProviderConfig", tags = "1, 2, 3")] + pub provider_config: ::core::option::Option, + } + /// Nested message and enum types in `LlmTask`. + pub mod llm_task { + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct OpenAiConfig { + #[prost(string, optional, tag = "1")] + pub model: ::core::option::Option<::prost::alloc::string::String>, + #[prost(string, optional, tag = "2")] + pub user_prompt: ::core::option::Option<::prost::alloc::string::String>, + #[prost(double, optional, tag = "3")] + pub temperature: ::core::option::Option, + #[prost(string, optional, tag = "4")] + pub secret_name_api_key: ::core::option::Option<::prost::alloc::string::String>, + } + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct GroqConfig { + #[prost(string, optional, tag = "1")] + pub model: ::core::option::Option<::prost::alloc::string::String>, + #[prost(string, optional, tag = "2")] + pub user_prompt: ::core::option::Option<::prost::alloc::string::String>, + #[prost(double, optional, tag = "3")] + pub temperature: ::core::option::Option, + #[prost(string, optional, tag = "4")] + pub secret_name_api_key: ::core::option::Option<::prost::alloc::string::String>, + } + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct GrokXaiConfig { + #[prost(string, optional, tag = "1")] + pub model: ::core::option::Option<::prost::alloc::string::String>, + #[prost(string, optional, tag = "2")] + pub user_prompt: ::core::option::Option<::prost::alloc::string::String>, + #[prost(double, optional, tag = "3")] + pub temperature: ::core::option::Option, + #[prost(string, optional, tag = "4")] + pub secret_name_api_key: ::core::option::Option<::prost::alloc::string::String>, + } + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Oneof)] + pub enum ProviderConfig { + #[prost(message, tag = "1")] + Openai(OpenAiConfig), + #[prost(message, tag = "2")] + Groq(GroqConfig), + #[prost(message, tag = "3")] + Grokxai(GrokXaiConfig), + } + } + /// + /// Fetch the current price of Solayer's sUSD stablecoin by reading its interest-bearing mint configuration. + /// + /// _**Input**_: None + /// + /// _**Returns**_: The current price of sUSD relative to USD (1.0 = $1.00) + /// + /// _**Example**_: Fetch the current sUSD price + /// + /// ```json + /// { "solayerSusdTask": {} } + /// ``` + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct SolayerSusdTask {} + /// + /// Fetch pricing information from Curve Finance pools. + /// + /// _**Input**_: None + /// + /// _**Returns**_: The current price/exchange rate from the specified Curve pool. + /// + /// _**Example**_: Fetch the price from a Curve pool on Ethereum + /// + /// ```json + /// { + /// "curveFinanceTask": { + /// "chain": "CHAIN_ETHEREUM", + /// "poolAddress": "0xbebc44782c7db0a1a60cb6fe97d0b483032ff1c7", + /// "outDecimals": 18 + /// } + /// } + /// ``` + /// + /// _**Example**_: Fetch the price using a custom RPC provider + /// + /// ```json + /// { + /// "curveFinanceTask": { + /// "chain": "CHAIN_ETHEREUM", + /// "provider": " + /// "poolAddress": "0xbebc44782c7db0a1a60cb6fe97d0b483032ff1c7", + /// "outDecimals": 18 + /// } + /// } + /// ``` + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct CurveFinanceTask { + /// / Required. Specifies which blockchain to use when reading information from Curve Finance. + #[prost(enumeration = "curve_finance_task::Chain", optional, tag = "1")] + pub chain: ::core::option::Option, + /// / Optional. The RPC endpoint to use for blockchain requests. If not specified, a default RPC will be used which may have rate limits. + #[prost(string, optional, tag = "2")] + pub provider: ::core::option::Option<::prost::alloc::string::String>, + /// / The on-chain address of the Curve Finance pool to fetch pricing data from. + #[prost(string, optional, tag = "3")] + pub pool_address: ::core::option::Option<::prost::alloc::string::String>, + /// / The number of decimal places to include in the returned price value. + #[prost(uint32, optional, tag = "4")] + pub out_decimals: ::core::option::Option, + } + /// Nested message and enum types in `CurveFinanceTask`. + pub mod curve_finance_task { + #[derive( + Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration, + )] + #[repr(i32)] + pub enum Chain { + /// / Use the Ethereum blockchain for fetching Curve Finance data + Ethereum = 0, + } + impl Chain { + /// 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 { + Chain::Ethereum => "CHAIN_ETHEREUM", + } + } + /// Creates an enum from field names used in the ProtoBuf definition. + pub fn from_str_name(value: &str) -> ::core::option::Option { + match value { + "CHAIN_ETHEREUM" => Some(Self::Ethereum), + _ => None, + } + } + } + } + /// + /// Fetches tETH/WETH redemption rate + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct TurboEthRedemptionRateTask { + #[prost(string, optional, tag = "1")] + pub provider: ::core::option::Option<::prost::alloc::string::String>, + } + /// + /// Fetch the current swap price from a BitFlux pool. + /// + /// _**Input**_: None + /// + /// _**Returns**_: The swap price between the specified input and output tokens. + /// + /// _**Example**_: Fetch the swap price using a custom RPC provider + /// + /// ```json + /// { + /// "bitFluxTask": { + /// "provider": " + /// "poolAddress": "0x0000000000000000000000000000000000000000", + /// "inToken": "0x0000000000000000000000000000000000000000", + /// "outToken": "0x0000000000000000000000000000000000000000" + /// } + /// } + /// ``` + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct BitFluxTask { + /// / Optional. The RPC endpoint to use for requests. If not specified, a default RPC will be used. + #[prost(string, optional, tag = "1")] + pub provider: ::core::option::Option<::prost::alloc::string::String>, + /// / The address of the BitFlux pool. + #[prost(string, optional, tag = "2")] + pub pool_address: ::core::option::Option<::prost::alloc::string::String>, + /// / The address of the input token. + #[prost(string, optional, tag = "3")] + pub in_token: ::core::option::Option<::prost::alloc::string::String>, + /// / The address of the output token. + #[prost(string, optional, tag = "4")] + pub out_token: ::core::option::Option<::prost::alloc::string::String>, + } + /// + /// Fetch the current price for Fragmetric liquid restaking tokens. + /// + /// _**Input**_: None + /// + /// _**Returns**_: The current price of the specified Fragmetric token relative to SOL (1.0 = 1 SOL) + /// + /// _**Example**_: Fetch the fragSOL token price + /// + /// ```json + /// { "fragmetricTask": { "token": "TOKEN_FRAG_SOL" } } + /// ``` + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct FragmetricTask { + /// / The Fragmetric token to fetch the price for + #[prost(enumeration = "fragmetric_task::Token", optional, tag = "1")] + pub token: ::core::option::Option, + } + /// Nested message and enum types in `FragmetricTask`. + pub mod fragmetric_task { + #[derive( + Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration, + )] + #[repr(i32)] + pub enum Token { + /// / Fragmetric's liquid restaking token (fragSOL) + FragSol = 0, + /// / Fragmetric's native staking token (nSOL) + NSol = 1, + } + impl Token { + /// 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 { + Token::FragSol => "TOKEN_FRAG_SOL", + Token::NSol => "TOKEN_N_SOL", + } + } + /// Creates an enum from field names used in the ProtoBuf definition. + pub fn from_str_name(value: &str) -> ::core::option::Option { + match value { + "TOKEN_FRAG_SOL" => Some(Self::FragSol), + "TOKEN_N_SOL" => Some(Self::NSol), + _ => None, + } + } + } + } + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct EtherfuseTask { + #[prost(enumeration = "etherfuse_task::Token", optional, tag = "1")] + pub token: ::core::option::Option, + } + /// Nested message and enum types in `EtherfuseTask`. + pub mod etherfuse_task { + #[derive( + Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration, + )] + #[repr(i32)] + pub enum Token { + Cetes = 0, + Ustry = 1, + Eurob = 2, + Tesouro = 3, + Gilts = 4, + } + impl Token { + /// 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 { + Token::Cetes => "TOKEN_CETES", + Token::Ustry => "TOKEN_USTRY", + Token::Eurob => "TOKEN_EUROB", + Token::Tesouro => "TOKEN_TESOURO", + Token::Gilts => "TOKEN_GILTS", + } + } + /// Creates an enum from field names used in the ProtoBuf definition. + pub fn from_str_name(value: &str) -> ::core::option::Option { + match value { + "TOKEN_CETES" => Some(Self::Cetes), + "TOKEN_USTRY" => Some(Self::Ustry), + "TOKEN_EUROB" => Some(Self::Eurob), + "TOKEN_TESOURO" => Some(Self::Tesouro), + "TOKEN_GILTS" => Some(Self::Gilts), + _ => None, + } + } + } + } + /// + /// Query historical yield data for a given Liquid Staking Token (LST) + /// and perform a statistical reduction operation over the dataset. + /// + /// _**Input**_: LST mint address, reduction operation type, and number of epochs to sample. + /// + /// _**Returns**_: The computed yield value based on the specified operation. + /// + /// _**Example**_: Compute the median APY for an LST over the last 100 epochs + /// + /// ```json + /// { + /// "lstHistoricalYieldTask": { + /// "lstMint": "J1toso1uCk3RLmjorhTtrVwY9HJ7X8V9yYac6Y7kGCPn", + /// "operation": "OPERATION_MEDIAN", + /// "epochs": 100 + /// } + /// } + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct LstHistoricalYieldTask { + /// / Required. The LST mint address for which historical yield data is queried. + #[prost(string, optional, tag = "1")] + pub lst_mint: ::core::option::Option<::prost::alloc::string::String>, + /// / Required. The statistical operation to apply to the historical yield dataset. + #[prost( + enumeration = "lst_historical_yield_task::Operation", + optional, + tag = "2" + )] + pub operation: ::core::option::Option, + /// / Optional. The number of epochs to sample for the computation. + /// / - If `epochs = 0`, all available historical data will be used. + /// / - If `epochs > 0`, only the last `epochs` entries will be included. + #[prost(int32, optional, tag = "3")] + pub epochs: ::core::option::Option, + } + /// Nested message and enum types in `LstHistoricalYieldTask`. + pub mod lst_historical_yield_task { + #[derive( + Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration, + )] + #[repr(i32)] + pub enum Operation { + Median = 0, + Mean = 1, + Min = 2, + Max = 3, + } + impl Operation { + /// 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 { + Operation::Median => "OPERATION_MEDIAN", + Operation::Mean => "OPERATION_MEAN", + Operation::Min => "OPERATION_MIN", + Operation::Max => "OPERATION_MAX", + } + } + /// Creates an enum from field names used in the ProtoBuf definition. + pub fn from_str_name(value: &str) -> ::core::option::Option { + match value { + "OPERATION_MEDIAN" => Some(Self::Median), + "OPERATION_MEAN" => Some(Self::Mean), + "OPERATION_MIN" => Some(Self::Min), + "OPERATION_MAX" => Some(Self::Max), + _ => None, + } + } + } + } + /// + /// Execute a swap task in the Pump AMM based on the given parameters. + /// + /// _**Input**_: Pool address, input token amount, max allowed slippage, and swap direction. + /// + /// _**Returns**_: Executes the swap operation in the Pump AMM with the given parameters. + /// + /// _**Example**_: Swap 10 tokens from X to Y with a maximum slippage of 0.5% + /// + /// ```json + /// { + /// "pumpAmmTask": { + /// "pool_address": "Gf7sXMoP8iRw4iiXmJ1nq4vxcRycbGXy5RL8a8LnTd3v", + /// "in_amount": "10", + /// "max_slippage": 0.5, + /// "is_x_for_y": true + /// } + /// } + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct PumpAmmTask { + /// / Required. The address of the liquidity pool in the Pump AMM. + #[prost(string, optional, tag = "1")] + pub pool_address: ::core::option::Option<::prost::alloc::string::String>, + /// / Optional. The input token amount for the swap. + /// / - This value should in full units of the input token. + /// / - Default value: `1` (Swap 1 full token). + #[prost(double, optional, tag = "2")] + pub in_amount: ::core::option::Option, + /// / Optional. The maximum allowed slippage for the swap, expressed as a percentage. + /// / - Example: `0.5` represents 0.5% slippage tolerance. + /// / - Default value: `3` (3% slippage tolerance). + #[prost(double, optional, tag = "3")] + pub max_slippage: ::core::option::Option, + /// / Optional. Indicates the swap direction: + /// / - `true`: Swapping token X for token Y. + /// / - `false`: Swapping token Y for token X. + /// / - Default value: `true`. + #[prost(bool, optional, tag = "4")] + pub is_x_for_y: ::core::option::Option, + } + /// + /// Derive the fair LP token price for a given Pump AMM liquidity pool. + /// + /// _**Input**_: Pool address, X token price job, Y token price job. + /// _**Returns**_: The fair LP token price for the given Pump AMM liquidity pool. + /// _**Example**_: Derive the fair LP token price for a given Pump AMM liquidity pool. + /// ```json + /// { + /// "pumpAmmLpTokenPriceTask": { + /// "pool_address": "Gf7sXMoP8iRw4iiXmJ1nq4vxcRycbGXy5RL8a8LnTd3v", // USDC/SOL + /// "x_price_job": { + /// "oracleTask": { + /// "switchboardAddress": "..." // USDC/USD + /// } + /// }, + /// "y_price_job": { + /// "oracleTask": { + /// "switchboardAddress": "..." // SOL/USD + /// } + /// } + /// } + /// } + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct PumpAmmLpTokenPriceTask { + /// / Required. The address of the liquidity pool in the Pump AMM. + #[prost(string, optional, tag = "1")] + pub pool_address: ::core::option::Option<::prost::alloc::string::String>, + /// / Required. The job to execute to fetch the price of the pool x token + #[prost(message, optional, tag = "2")] + pub x_price_job: ::core::option::Option, + /// / Required. The job to execute + #[prost(message, optional, tag = "3")] + pub y_price_job: ::core::option::Option, + } + /// + /// Get the exchange rate between and Exponent vault pricipal token and + /// underlying token. + /// _**Input**_: Vault address + /// _**Returns**_: The exchange rate between the vault principal token and + /// underlying token. + /// _**Example**_: Get the exchange rate between the vault principal token and + /// underlying token. + /// ```json + /// { + /// "exponentTask": { + /// "vault": "9YbaicMsXrtupkpD72pdWBfU6R7EJfSByw75sEpDM1uH" + /// } + /// } + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct ExponentTask { + #[prost(string, optional, tag = "1")] + pub vault: ::core::option::Option<::prost::alloc::string::String>, + } + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct ExponentPtLinearPricingTask { + #[prost(string, optional, tag = "1")] + pub vault: ::core::option::Option<::prost::alloc::string::String>, + #[prost(double, optional, tag = "2")] + pub start_price: ::core::option::Option, + } + /// + /// Apply Solana Token 2022 extension modifiers to a feed. + /// _**Input**_: Token address and extension type. + /// _**Returns**_: The value associated with the token2022 extension. + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct SolanaToken2022ExtensionTask { + #[prost(string, optional, tag = "1")] + pub mint: ::core::option::Option<::prost::alloc::string::String>, + #[prost( + enumeration = "solana_token2022_extension_task::Token2022Extension", + optional, + tag = "2" + )] + pub extension: ::core::option::Option, + } + /// Nested message and enum types in `SolanaToken2022ExtensionTask`. + pub mod solana_token2022_extension_task { + #[derive( + Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration, + )] + #[repr(i32)] + pub enum Token2022Extension { + Token2022ScaledAmountFactor = 0, + } + impl Token2022Extension { + /// 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 { + Token2022Extension::Token2022ScaledAmountFactor => { + "TOKEN_2022_SCALED_AMOUNT_FACTOR" + } + } + } + /// Creates an enum from field names used in the ProtoBuf definition. + pub fn from_str_name(value: &str) -> ::core::option::Option { + match value { + "TOKEN_2022_SCALED_AMOUNT_FACTOR" => Some(Self::Token2022ScaledAmountFactor), + _ => None, + } + } + } + } + /// + /// Fetch a *live* spot price straight out of the global **Surge** websocket + /// cache – the same cache that powers our high-speed on-chain oracles. + /// + /// _**Input**_ + /// • `symbol` – the trading-pair symbol as it appears on the exchange + /// • `source` – which exchange’s stream to read from + /// • `BINANCE` (weight 3) + /// • `BYBIT` (weight 2) + /// • `OKX` (weight 2) + /// • `COINBASE` (weight 1) + /// • `WEIGHTED` (default) – use the *weighted median* of all + /// fresh quotes (<= 5 s old) with the weights shown above. + /// + /// _**Returns**_ + /// The most recent price available from the chosen source. + /// The task fails if the cached tick is older than **5 s**. + /// + /// _**Example**_: Pull the Binance price for BTC / USDT + /// ```json + /// { + /// "switchboardSurgeTask": { + /// "source": "BINANCE", + /// "symbol": "BTCUSDT" + /// } + /// } + /// ``` + /// + /// _**Example**_: Use the weighted-median oracle for BTC / USDT + /// ```json + /// { + /// "switchboardSurgeTask": { + /// "source": "WEIGHTED", // or omit — WEIGHTED is the default + /// "symbol": "BTCUSDT" + /// } + /// } + /// ``` + /// + /// _**Notes**_ + /// • Symbols are auto-normalised (case-insensitive, punctuation removed). + /// • If a venue’s price is stale (> 5 s) it is ignored in the WEIGHTED + /// calculation. The task errors if **no** fresh price remains. + /// • The weighted-median algorithm is the same one Hyperliquid uses in + /// production: cumulative weights 3 / 2 / 2 / 1 / 1 / 1 / 1 / 1 across the + /// eight venues (we currently stream the first four). + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct SwitchboardSurgeTask { + /// Determines which source will be used for pricing. + /// Default: WEIGHTED average across all sources. + #[prost(enumeration = "switchboard_surge_task::Source", optional, tag = "1")] + pub source: ::core::option::Option, + #[prost(string, optional, tag = "2")] + pub symbol: ::core::option::Option<::prost::alloc::string::String>, + } + /// Nested message and enum types in `SwitchboardSurgeTask`. + pub mod switchboard_surge_task { + #[derive( + Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration, + )] + #[repr(i32)] + pub enum Source { + Weighted = 0, + Binance = 1, + Okx = 2, + Bybit = 3, + Coinbase = 4, + } + impl Source { + /// 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 { + Source::Weighted => "WEIGHTED", + Source::Binance => "BINANCE", + Source::Okx => "OKX", + Source::Bybit => "BYBIT", + Source::Coinbase => "COINBASE", + } + } + /// Creates an enum from field names used in the ProtoBuf definition. + pub fn from_str_name(value: &str) -> ::core::option::Option { + match value { + "WEIGHTED" => Some(Self::Weighted), + "BINANCE" => Some(Self::Binance), + "OKX" => Some(Self::Okx), + "BYBIT" => Some(Self::Bybit), + "COINBASE" => Some(Self::Coinbase), + _ => None, + } + } + } + } + /// / Represents a singular operation performed by an oracle to yield an eventual numerical result. + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct Task { + #[prost( + oneof = "task::Task", + tags = "1, 2, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 63, 64, 65, 66, 67, 68, 69, 70" + )] + pub task: ::core::option::Option, + } + /// Nested message and enum types in `Task`. + pub mod task { + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Oneof)] + pub enum Task { + #[prost(message, tag = "1")] + HttpTask(super::HttpTask), + #[prost(message, tag = "2")] + JsonParseTask(super::JsonParseTask), + #[prost(message, tag = "4")] + MedianTask(super::MedianTask), + #[prost(message, tag = "5")] + MeanTask(super::MeanTask), + #[prost(message, tag = "6")] + WebsocketTask(super::WebsocketTask), + #[prost(message, tag = "7")] + DivideTask(super::DivideTask), + #[prost(message, tag = "8")] + MultiplyTask(super::MultiplyTask), + #[prost(message, tag = "9")] + LpTokenPriceTask(super::LpTokenPriceTask), + #[prost(message, tag = "10")] + LpExchangeRateTask(super::LpExchangeRateTask), + #[prost(message, tag = "11")] + ConditionalTask(super::ConditionalTask), + #[prost(message, tag = "12")] + ValueTask(super::ValueTask), + #[prost(message, tag = "13")] + MaxTask(super::MaxTask), + #[prost(message, tag = "14")] + RegexExtractTask(super::RegexExtractTask), + #[prost(message, tag = "15")] + XstepPriceTask(super::XStepPriceTask), + #[prost(message, tag = "16")] + AddTask(super::AddTask), + #[prost(message, tag = "17")] + SubtractTask(super::SubtractTask), + #[prost(message, tag = "18")] + TwapTask(super::TwapTask), + #[prost(message, tag = "19")] + SerumSwapTask(super::SerumSwapTask), + #[prost(message, tag = "20")] + PowTask(super::PowTask), + #[prost(message, tag = "21")] + LendingRateTask(super::LendingRateTask), + #[prost(message, tag = "22")] + MangoPerpMarketTask(super::MangoPerpMarketTask), + #[prost(message, tag = "23")] + JupiterSwapTask(super::JupiterSwapTask), + #[prost(message, tag = "24")] + PerpMarketTask(super::PerpMarketTask), + #[prost(message, tag = "25")] + OracleTask(super::OracleTask), + #[prost(message, tag = "26")] + AnchorFetchTask(super::AnchorFetchTask), + #[prost(message, tag = "29")] + SplStakePoolTask(super::SplStakePoolTask), + #[prost(message, tag = "30")] + SplTokenParseTask(super::SplTokenParseTask), + #[prost(message, tag = "31")] + UniswapExchangeRateTask(super::UniswapExchangeRateTask), + #[prost(message, tag = "32")] + SushiswapExchangeRateTask(super::SushiswapExchangeRateTask), + #[prost(message, tag = "33")] + PancakeswapExchangeRateTask(super::PancakeswapExchangeRateTask), + #[prost(message, tag = "34")] + CacheTask(super::CacheTask), + #[prost(message, tag = "35")] + SysclockOffsetTask(super::SysclockOffsetTask), + #[prost(message, tag = "36")] + MarinadeStateTask(super::MarinadeStateTask), + #[prost(message, tag = "37")] + SolanaAccountDataFetchTask(super::SolanaAccountDataFetchTask), + #[prost(message, tag = "38")] + BufferLayoutParseTask(super::BufferLayoutParseTask), + #[prost(message, tag = "39")] + CronParseTask(super::CronParseTask), + #[prost(message, tag = "40")] + MinTask(super::MinTask), + #[prost(message, tag = "41")] + HistoryFunctionTask(super::HistoryFunctionTask), + #[prost(message, tag = "42")] + VwapTask(super::VwapTask), + #[prost(message, tag = "43")] + EwmaTask(super::EwmaTask), + #[prost(message, tag = "44")] + ComparisonTask(super::ComparisonTask), + #[prost(message, tag = "45")] + RoundTask(super::RoundTask), + #[prost(message, tag = "46")] + BoundTask(super::BoundTask), + #[prost(message, tag = "47")] + SecretsTask(super::SecretsTask), + #[prost(message, tag = "48")] + SanctumLstPriceTask(super::SanctumLstPriceTask), + #[prost(message, tag = "49")] + OndoUsdyTask(super::OndoUsdyTask), + #[prost(message, tag = "50")] + MeteoraSwapTask(super::MeteoraSwapTask), + #[prost(message, tag = "51")] + UnixTimeTask(super::UnixTimeTask), + #[prost(message, tag = "52")] + MapleFinanceTask(super::MapleFinanceTask), + #[prost(message, tag = "53")] + GlyphTask(super::GlyphTask), + #[prost(message, tag = "54")] + CorexTask(super::CorexTask), + #[prost(message, tag = "55")] + LlmTask(super::LlmTask), + #[prost(message, tag = "56")] + SolayerSusdTask(super::SolayerSusdTask), + #[prost(message, tag = "57")] + CurveFinanceTask(super::CurveFinanceTask), + #[prost(message, tag = "58")] + TurboEthRedemptionRateTask(super::TurboEthRedemptionRateTask), + #[prost(message, tag = "59")] + BitFluxTask(super::BitFluxTask), + #[prost(message, tag = "60")] + FragmetricTask(super::FragmetricTask), + #[prost(message, tag = "61")] + AftermathTask(super::AftermathTask), + #[prost(message, tag = "63")] + EtherfuseTask(super::EtherfuseTask), + #[prost(message, tag = "64")] + LstHistoricalYieldTask(super::LstHistoricalYieldTask), + #[prost(message, tag = "65")] + PumpAmmTask(super::PumpAmmTask), + #[prost(message, tag = "66")] + PumpAmmLpTokenPriceTask(super::PumpAmmLpTokenPriceTask), + #[prost(message, tag = "67")] + ExponentTask(super::ExponentTask), + #[prost(message, tag = "68")] + ExponentPtLinearPricingTask(super::ExponentPtLinearPricingTask), + #[prost(message, tag = "69")] + SolanaToken2022ExtensionTask(super::SolanaToken2022ExtensionTask), + #[prost(message, tag = "70")] + SwitchboardSurgeTask(super::SwitchboardSurgeTask), + } + } +} +/// Encoded file descriptor set for the `oracle_job` package +pub const FILE_DESCRIPTOR_SET: &[u8] = &[ + 0x0a, 0xe4, 0xbf, 0x05, 0x0a, 0x11, 0x6a, 0x6f, 0x62, 0x5f, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, + 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0a, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x5f, + 0x6a, 0x6f, 0x62, 0x22, 0xe3, 0x96, 0x01, 0x0a, 0x09, 0x4f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x4a, + 0x6f, 0x62, 0x12, 0x30, 0x0a, 0x05, 0x74, 0x61, 0x73, 0x6b, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x1a, 0x2e, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x5f, 0x6a, 0x6f, 0x62, 0x2e, 0x4f, + 0x72, 0x61, 0x63, 0x6c, 0x65, 0x4a, 0x6f, 0x62, 0x2e, 0x54, 0x61, 0x73, 0x6b, 0x52, 0x05, 0x74, + 0x61, 0x73, 0x6b, 0x73, 0x12, 0x19, 0x0a, 0x06, 0x77, 0x65, 0x69, 0x67, 0x68, 0x74, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x0d, 0x3a, 0x01, 0x31, 0x52, 0x06, 0x77, 0x65, 0x69, 0x67, 0x68, 0x74, 0x12, + 0x23, 0x0a, 0x0d, 0x6d, 0x69, 0x6e, 0x5f, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x73, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0c, 0x6d, 0x69, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x73, 0x12, 0x1f, 0x0a, 0x0b, 0x6d, 0x69, 0x6e, 0x5f, 0x73, 0x61, 0x6d, 0x70, + 0x6c, 0x65, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a, 0x6d, 0x69, 0x6e, 0x53, 0x61, + 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x6d, 0x61, 0x78, 0x5f, 0x76, 0x61, 0x72, + 0x69, 0x61, 0x6e, 0x63, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x6d, 0x61, 0x78, + 0x56, 0x61, 0x72, 0x69, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, + 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, + 0x71, 0x75, 0x65, 0x75, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x71, 0x75, 0x65, + 0x75, 0x65, 0x1a, 0xa0, 0x02, 0x0a, 0x08, 0x48, 0x74, 0x74, 0x70, 0x54, 0x61, 0x73, 0x6b, 0x12, + 0x10, 0x0a, 0x03, 0x75, 0x72, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, + 0x6c, 0x12, 0x3d, 0x0a, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x0e, 0x32, 0x25, 0x2e, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x5f, 0x6a, 0x6f, 0x62, 0x2e, 0x4f, + 0x72, 0x61, 0x63, 0x6c, 0x65, 0x4a, 0x6f, 0x62, 0x2e, 0x48, 0x74, 0x74, 0x70, 0x54, 0x61, 0x73, + 0x6b, 0x2e, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x52, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, + 0x12, 0x3f, 0x0a, 0x07, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x25, 0x2e, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x5f, 0x6a, 0x6f, 0x62, 0x2e, 0x4f, + 0x72, 0x61, 0x63, 0x6c, 0x65, 0x4a, 0x6f, 0x62, 0x2e, 0x48, 0x74, 0x74, 0x70, 0x54, 0x61, 0x73, + 0x6b, 0x2e, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x52, 0x07, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, + 0x73, 0x12, 0x12, 0x0a, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x04, 0x62, 0x6f, 0x64, 0x79, 0x1a, 0x30, 0x0a, 0x06, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 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, 0x22, 0x3c, 0x0a, 0x06, 0x4d, 0x65, 0x74, 0x68, 0x6f, + 0x64, 0x12, 0x11, 0x0a, 0x0d, 0x4d, 0x45, 0x54, 0x48, 0x4f, 0x44, 0x5f, 0x55, 0x4e, 0x4b, 0x4f, + 0x57, 0x4e, 0x10, 0x00, 0x12, 0x0e, 0x0a, 0x0a, 0x4d, 0x45, 0x54, 0x48, 0x4f, 0x44, 0x5f, 0x47, + 0x45, 0x54, 0x10, 0x01, 0x12, 0x0f, 0x0a, 0x0b, 0x4d, 0x45, 0x54, 0x48, 0x4f, 0x44, 0x5f, 0x50, + 0x4f, 0x53, 0x54, 0x10, 0x02, 0x1a, 0xd9, 0x01, 0x0a, 0x0d, 0x4a, 0x73, 0x6f, 0x6e, 0x50, 0x61, + 0x72, 0x73, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x12, 0x64, 0x0a, 0x12, 0x61, + 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6d, 0x65, 0x74, 0x68, 0x6f, + 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x35, 0x2e, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, + 0x5f, 0x6a, 0x6f, 0x62, 0x2e, 0x4f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x4a, 0x6f, 0x62, 0x2e, 0x4a, + 0x73, 0x6f, 0x6e, 0x50, 0x61, 0x72, 0x73, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x2e, 0x41, 0x67, 0x67, + 0x72, 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x52, 0x11, + 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x74, 0x68, 0x6f, + 0x64, 0x22, 0x4e, 0x0a, 0x11, 0x41, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x12, 0x08, 0x0a, 0x04, 0x4e, 0x4f, 0x4e, 0x45, 0x10, 0x00, + 0x12, 0x07, 0x0a, 0x03, 0x4d, 0x49, 0x4e, 0x10, 0x01, 0x12, 0x07, 0x0a, 0x03, 0x4d, 0x41, 0x58, + 0x10, 0x02, 0x12, 0x07, 0x0a, 0x03, 0x53, 0x55, 0x4d, 0x10, 0x03, 0x12, 0x08, 0x0a, 0x04, 0x4d, + 0x45, 0x41, 0x4e, 0x10, 0x04, 0x12, 0x0a, 0x0a, 0x06, 0x4d, 0x45, 0x44, 0x49, 0x41, 0x4e, 0x10, + 0x05, 0x1a, 0xcd, 0x01, 0x0a, 0x0a, 0x4d, 0x65, 0x64, 0x69, 0x61, 0x6e, 0x54, 0x61, 0x73, 0x6b, + 0x12, 0x30, 0x0a, 0x05, 0x74, 0x61, 0x73, 0x6b, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x1a, 0x2e, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x5f, 0x6a, 0x6f, 0x62, 0x2e, 0x4f, 0x72, 0x61, + 0x63, 0x6c, 0x65, 0x4a, 0x6f, 0x62, 0x2e, 0x54, 0x61, 0x73, 0x6b, 0x52, 0x05, 0x74, 0x61, 0x73, + 0x6b, 0x73, 0x12, 0x29, 0x0a, 0x04, 0x6a, 0x6f, 0x62, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x15, 0x2e, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x5f, 0x6a, 0x6f, 0x62, 0x2e, 0x4f, 0x72, + 0x61, 0x63, 0x6c, 0x65, 0x4a, 0x6f, 0x62, 0x52, 0x04, 0x6a, 0x6f, 0x62, 0x73, 0x12, 0x36, 0x0a, + 0x17, 0x6d, 0x69, 0x6e, 0x5f, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x66, 0x75, 0x6c, 0x5f, + 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x15, + 0x6d, 0x69, 0x6e, 0x53, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x66, 0x75, 0x6c, 0x52, 0x65, 0x71, + 0x75, 0x69, 0x72, 0x65, 0x64, 0x12, 0x2a, 0x0a, 0x11, 0x6d, 0x61, 0x78, 0x5f, 0x72, 0x61, 0x6e, + 0x67, 0x65, 0x5f, 0x70, 0x65, 0x72, 0x63, 0x65, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x0f, 0x6d, 0x61, 0x78, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x50, 0x65, 0x72, 0x63, 0x65, 0x6e, + 0x74, 0x1a, 0x67, 0x0a, 0x08, 0x4d, 0x65, 0x61, 0x6e, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x30, 0x0a, + 0x05, 0x74, 0x61, 0x73, 0x6b, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x6f, + 0x72, 0x61, 0x63, 0x6c, 0x65, 0x5f, 0x6a, 0x6f, 0x62, 0x2e, 0x4f, 0x72, 0x61, 0x63, 0x6c, 0x65, + 0x4a, 0x6f, 0x62, 0x2e, 0x54, 0x61, 0x73, 0x6b, 0x52, 0x05, 0x74, 0x61, 0x73, 0x6b, 0x73, 0x12, + 0x29, 0x0a, 0x04, 0x6a, 0x6f, 0x62, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, + 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x5f, 0x6a, 0x6f, 0x62, 0x2e, 0x4f, 0x72, 0x61, 0x63, 0x6c, + 0x65, 0x4a, 0x6f, 0x62, 0x52, 0x04, 0x6a, 0x6f, 0x62, 0x73, 0x1a, 0x66, 0x0a, 0x07, 0x4d, 0x61, + 0x78, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x30, 0x0a, 0x05, 0x74, 0x61, 0x73, 0x6b, 0x73, 0x18, 0x01, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x5f, 0x6a, 0x6f, + 0x62, 0x2e, 0x4f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x4a, 0x6f, 0x62, 0x2e, 0x54, 0x61, 0x73, 0x6b, + 0x52, 0x05, 0x74, 0x61, 0x73, 0x6b, 0x73, 0x12, 0x29, 0x0a, 0x04, 0x6a, 0x6f, 0x62, 0x73, 0x18, + 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x5f, 0x6a, + 0x6f, 0x62, 0x2e, 0x4f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x4a, 0x6f, 0x62, 0x52, 0x04, 0x6a, 0x6f, + 0x62, 0x73, 0x1a, 0x66, 0x0a, 0x07, 0x4d, 0x69, 0x6e, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x30, 0x0a, + 0x05, 0x74, 0x61, 0x73, 0x6b, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x6f, + 0x72, 0x61, 0x63, 0x6c, 0x65, 0x5f, 0x6a, 0x6f, 0x62, 0x2e, 0x4f, 0x72, 0x61, 0x63, 0x6c, 0x65, + 0x4a, 0x6f, 0x62, 0x2e, 0x54, 0x61, 0x73, 0x6b, 0x52, 0x05, 0x74, 0x61, 0x73, 0x6b, 0x73, 0x12, + 0x29, 0x0a, 0x04, 0x6a, 0x6f, 0x62, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, + 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x5f, 0x6a, 0x6f, 0x62, 0x2e, 0x4f, 0x72, 0x61, 0x63, 0x6c, + 0x65, 0x4a, 0x6f, 0x62, 0x52, 0x04, 0x6a, 0x6f, 0x62, 0x73, 0x1a, 0x99, 0x01, 0x0a, 0x09, 0x56, + 0x61, 0x6c, 0x75, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x16, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, + 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x01, 0x48, 0x00, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, + 0x12, 0x2d, 0x0a, 0x11, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x6f, 0x72, 0x5f, 0x70, + 0x75, 0x62, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x10, 0x61, + 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x6f, 0x72, 0x50, 0x75, 0x62, 0x6b, 0x65, 0x79, 0x12, + 0x12, 0x0a, 0x03, 0x62, 0x69, 0x67, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x03, + 0x62, 0x69, 0x67, 0x12, 0x12, 0x0a, 0x03, 0x68, 0x65, 0x78, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, + 0x48, 0x00, 0x52, 0x03, 0x68, 0x65, 0x78, 0x12, 0x14, 0x0a, 0x04, 0x75, 0x74, 0x66, 0x38, 0x18, + 0x05, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x04, 0x75, 0x74, 0x66, 0x38, 0x42, 0x07, 0x0a, + 0x05, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x1a, 0x8e, 0x01, 0x0a, 0x0d, 0x57, 0x65, 0x62, 0x73, 0x6f, + 0x63, 0x6b, 0x65, 0x74, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x72, 0x6c, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x6c, 0x12, 0x22, 0x0a, 0x0c, 0x73, 0x75, + 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x0c, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x2f, + 0x0a, 0x14, 0x6d, 0x61, 0x78, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x61, 0x67, 0x65, 0x5f, 0x73, + 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x11, 0x6d, 0x61, + 0x78, 0x44, 0x61, 0x74, 0x61, 0x41, 0x67, 0x65, 0x53, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x12, + 0x16, 0x0a, 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x1a, 0x82, 0x01, 0x0a, 0x0f, 0x43, 0x6f, 0x6e, 0x64, + 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x34, 0x0a, 0x07, 0x61, + 0x74, 0x74, 0x65, 0x6d, 0x70, 0x74, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x6f, + 0x72, 0x61, 0x63, 0x6c, 0x65, 0x5f, 0x6a, 0x6f, 0x62, 0x2e, 0x4f, 0x72, 0x61, 0x63, 0x6c, 0x65, + 0x4a, 0x6f, 0x62, 0x2e, 0x54, 0x61, 0x73, 0x6b, 0x52, 0x07, 0x61, 0x74, 0x74, 0x65, 0x6d, 0x70, + 0x74, 0x12, 0x39, 0x0a, 0x0a, 0x6f, 0x6e, 0x5f, 0x66, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x18, + 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x5f, 0x6a, + 0x6f, 0x62, 0x2e, 0x4f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x4a, 0x6f, 0x62, 0x2e, 0x54, 0x61, 0x73, + 0x6b, 0x52, 0x09, 0x6f, 0x6e, 0x46, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x1a, 0xa3, 0x01, 0x0a, + 0x0a, 0x44, 0x69, 0x76, 0x69, 0x64, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x18, 0x0a, 0x06, 0x73, + 0x63, 0x61, 0x6c, 0x61, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x01, 0x48, 0x00, 0x52, 0x06, 0x73, + 0x63, 0x61, 0x6c, 0x61, 0x72, 0x12, 0x2d, 0x0a, 0x11, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, + 0x74, 0x6f, 0x72, 0x5f, 0x70, 0x75, 0x62, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x48, 0x00, 0x52, 0x10, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x6f, 0x72, 0x50, 0x75, + 0x62, 0x6b, 0x65, 0x79, 0x12, 0x29, 0x0a, 0x03, 0x6a, 0x6f, 0x62, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x15, 0x2e, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x5f, 0x6a, 0x6f, 0x62, 0x2e, 0x4f, + 0x72, 0x61, 0x63, 0x6c, 0x65, 0x4a, 0x6f, 0x62, 0x48, 0x00, 0x52, 0x03, 0x6a, 0x6f, 0x62, 0x12, + 0x12, 0x0a, 0x03, 0x62, 0x69, 0x67, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x03, + 0x62, 0x69, 0x67, 0x42, 0x0d, 0x0a, 0x0b, 0x44, 0x65, 0x6e, 0x6f, 0x6d, 0x69, 0x6e, 0x61, 0x74, + 0x6f, 0x72, 0x1a, 0xa2, 0x01, 0x0a, 0x0c, 0x4d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x79, 0x54, + 0x61, 0x73, 0x6b, 0x12, 0x18, 0x0a, 0x06, 0x73, 0x63, 0x61, 0x6c, 0x61, 0x72, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x01, 0x48, 0x00, 0x52, 0x06, 0x73, 0x63, 0x61, 0x6c, 0x61, 0x72, 0x12, 0x2d, 0x0a, + 0x11, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x6f, 0x72, 0x5f, 0x70, 0x75, 0x62, 0x6b, + 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x10, 0x61, 0x67, 0x67, 0x72, + 0x65, 0x67, 0x61, 0x74, 0x6f, 0x72, 0x50, 0x75, 0x62, 0x6b, 0x65, 0x79, 0x12, 0x29, 0x0a, 0x03, + 0x6a, 0x6f, 0x62, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x6f, 0x72, 0x61, 0x63, + 0x6c, 0x65, 0x5f, 0x6a, 0x6f, 0x62, 0x2e, 0x4f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x4a, 0x6f, 0x62, + 0x48, 0x00, 0x52, 0x03, 0x6a, 0x6f, 0x62, 0x12, 0x12, 0x0a, 0x03, 0x62, 0x69, 0x67, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x03, 0x62, 0x69, 0x67, 0x42, 0x0a, 0x0a, 0x08, 0x4d, + 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x1a, 0x9d, 0x01, 0x0a, 0x07, 0x41, 0x64, 0x64, 0x54, + 0x61, 0x73, 0x6b, 0x12, 0x18, 0x0a, 0x06, 0x73, 0x63, 0x61, 0x6c, 0x61, 0x72, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x01, 0x48, 0x00, 0x52, 0x06, 0x73, 0x63, 0x61, 0x6c, 0x61, 0x72, 0x12, 0x2d, 0x0a, + 0x11, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x6f, 0x72, 0x5f, 0x70, 0x75, 0x62, 0x6b, + 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x10, 0x61, 0x67, 0x67, 0x72, + 0x65, 0x67, 0x61, 0x74, 0x6f, 0x72, 0x50, 0x75, 0x62, 0x6b, 0x65, 0x79, 0x12, 0x29, 0x0a, 0x03, + 0x6a, 0x6f, 0x62, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x6f, 0x72, 0x61, 0x63, + 0x6c, 0x65, 0x5f, 0x6a, 0x6f, 0x62, 0x2e, 0x4f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x4a, 0x6f, 0x62, + 0x48, 0x00, 0x52, 0x03, 0x6a, 0x6f, 0x62, 0x12, 0x12, 0x0a, 0x03, 0x62, 0x69, 0x67, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x03, 0x62, 0x69, 0x67, 0x42, 0x0a, 0x0a, 0x08, 0x41, + 0x64, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x1a, 0xa5, 0x01, 0x0a, 0x0c, 0x53, 0x75, 0x62, 0x74, + 0x72, 0x61, 0x63, 0x74, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x18, 0x0a, 0x06, 0x73, 0x63, 0x61, 0x6c, + 0x61, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x01, 0x48, 0x00, 0x52, 0x06, 0x73, 0x63, 0x61, 0x6c, + 0x61, 0x72, 0x12, 0x2d, 0x0a, 0x11, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x6f, 0x72, + 0x5f, 0x70, 0x75, 0x62, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, + 0x10, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x6f, 0x72, 0x50, 0x75, 0x62, 0x6b, 0x65, + 0x79, 0x12, 0x29, 0x0a, 0x03, 0x6a, 0x6f, 0x62, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, + 0x2e, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x5f, 0x6a, 0x6f, 0x62, 0x2e, 0x4f, 0x72, 0x61, 0x63, + 0x6c, 0x65, 0x4a, 0x6f, 0x62, 0x48, 0x00, 0x52, 0x03, 0x6a, 0x6f, 0x62, 0x12, 0x12, 0x0a, 0x03, + 0x62, 0x69, 0x67, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x03, 0x62, 0x69, 0x67, + 0x42, 0x0d, 0x0a, 0x0b, 0x53, 0x75, 0x62, 0x74, 0x72, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x1a, + 0x82, 0x03, 0x0a, 0x10, 0x4c, 0x70, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x50, 0x72, 0x69, 0x63, 0x65, + 0x54, 0x61, 0x73, 0x6b, 0x12, 0x36, 0x0a, 0x16, 0x6d, 0x65, 0x72, 0x63, 0x75, 0x72, 0x69, 0x61, + 0x6c, 0x5f, 0x70, 0x6f, 0x6f, 0x6c, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x14, 0x6d, 0x65, 0x72, 0x63, 0x75, 0x72, 0x69, 0x61, + 0x6c, 0x50, 0x6f, 0x6f, 0x6c, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x2e, 0x0a, 0x12, + 0x73, 0x61, 0x62, 0x65, 0x72, 0x5f, 0x70, 0x6f, 0x6f, 0x6c, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, + 0x73, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x10, 0x73, 0x61, 0x62, 0x65, + 0x72, 0x50, 0x6f, 0x6f, 0x6c, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x2c, 0x0a, 0x11, + 0x6f, 0x72, 0x63, 0x61, 0x5f, 0x70, 0x6f, 0x6f, 0x6c, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, + 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x0f, 0x6f, 0x72, 0x63, 0x61, 0x50, + 0x6f, 0x6f, 0x6c, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x32, 0x0a, 0x14, 0x72, 0x61, + 0x79, 0x64, 0x69, 0x75, 0x6d, 0x5f, 0x70, 0x6f, 0x6f, 0x6c, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, + 0x73, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x12, 0x72, 0x61, 0x79, 0x64, + 0x69, 0x75, 0x6d, 0x50, 0x6f, 0x6f, 0x6c, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x30, + 0x0a, 0x14, 0x70, 0x72, 0x69, 0x63, 0x65, 0x5f, 0x66, 0x65, 0x65, 0x64, 0x5f, 0x61, 0x64, 0x64, + 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x12, 0x70, 0x72, + 0x69, 0x63, 0x65, 0x46, 0x65, 0x65, 0x64, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, + 0x12, 0x3d, 0x0a, 0x0f, 0x70, 0x72, 0x69, 0x63, 0x65, 0x5f, 0x66, 0x65, 0x65, 0x64, 0x5f, 0x6a, + 0x6f, 0x62, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x6f, 0x72, 0x61, 0x63, + 0x6c, 0x65, 0x5f, 0x6a, 0x6f, 0x62, 0x2e, 0x4f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x4a, 0x6f, 0x62, + 0x52, 0x0d, 0x70, 0x72, 0x69, 0x63, 0x65, 0x46, 0x65, 0x65, 0x64, 0x4a, 0x6f, 0x62, 0x73, 0x12, + 0x24, 0x0a, 0x0e, 0x75, 0x73, 0x65, 0x5f, 0x66, 0x61, 0x69, 0x72, 0x5f, 0x70, 0x72, 0x69, 0x63, + 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x75, 0x73, 0x65, 0x46, 0x61, 0x69, 0x72, + 0x50, 0x72, 0x69, 0x63, 0x65, 0x42, 0x0d, 0x0a, 0x0b, 0x50, 0x6f, 0x6f, 0x6c, 0x41, 0x64, 0x64, + 0x72, 0x65, 0x73, 0x73, 0x1a, 0xa5, 0x04, 0x0a, 0x12, 0x4c, 0x70, 0x45, 0x78, 0x63, 0x68, 0x61, + 0x6e, 0x67, 0x65, 0x52, 0x61, 0x74, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x28, 0x0a, 0x10, 0x69, + 0x6e, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x69, 0x6e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x41, 0x64, + 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x2a, 0x0a, 0x11, 0x6f, 0x75, 0x74, 0x5f, 0x74, 0x6f, 0x6b, + 0x65, 0x6e, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x0f, 0x6f, 0x75, 0x74, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, + 0x73, 0x12, 0x36, 0x0a, 0x16, 0x6d, 0x65, 0x72, 0x63, 0x75, 0x72, 0x69, 0x61, 0x6c, 0x5f, 0x70, + 0x6f, 0x6f, 0x6c, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x09, 0x48, 0x00, 0x52, 0x14, 0x6d, 0x65, 0x72, 0x63, 0x75, 0x72, 0x69, 0x61, 0x6c, 0x50, 0x6f, + 0x6f, 0x6c, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x2e, 0x0a, 0x12, 0x73, 0x61, 0x62, + 0x65, 0x72, 0x5f, 0x70, 0x6f, 0x6f, 0x6c, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x10, 0x73, 0x61, 0x62, 0x65, 0x72, 0x50, 0x6f, + 0x6f, 0x6c, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x44, 0x0a, 0x1c, 0x6f, 0x72, 0x63, + 0x61, 0x5f, 0x70, 0x6f, 0x6f, 0x6c, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x5f, 0x6d, 0x69, 0x6e, + 0x74, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x42, + 0x02, 0x18, 0x01, 0x48, 0x00, 0x52, 0x18, 0x6f, 0x72, 0x63, 0x61, 0x50, 0x6f, 0x6f, 0x6c, 0x54, + 0x6f, 0x6b, 0x65, 0x6e, 0x4d, 0x69, 0x6e, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, + 0x32, 0x0a, 0x14, 0x72, 0x61, 0x79, 0x64, 0x69, 0x75, 0x6d, 0x5f, 0x70, 0x6f, 0x6f, 0x6c, 0x5f, + 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, + 0x12, 0x72, 0x61, 0x79, 0x64, 0x69, 0x75, 0x6d, 0x50, 0x6f, 0x6f, 0x6c, 0x41, 0x64, 0x64, 0x72, + 0x65, 0x73, 0x73, 0x12, 0x2c, 0x0a, 0x11, 0x6f, 0x72, 0x63, 0x61, 0x5f, 0x70, 0x6f, 0x6f, 0x6c, + 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, + 0x52, 0x0f, 0x6f, 0x72, 0x63, 0x61, 0x50, 0x6f, 0x6f, 0x6c, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, + 0x73, 0x12, 0x32, 0x0a, 0x14, 0x70, 0x6f, 0x72, 0x74, 0x5f, 0x72, 0x65, 0x73, 0x65, 0x72, 0x76, + 0x65, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x48, + 0x00, 0x52, 0x12, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x41, 0x64, + 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x44, 0x0a, 0x05, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x18, 0x09, + 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2e, 0x2e, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x5f, 0x6a, 0x6f, + 0x62, 0x2e, 0x4f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x4a, 0x6f, 0x62, 0x2e, 0x4c, 0x70, 0x45, 0x78, + 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x61, 0x74, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x2e, 0x43, + 0x68, 0x61, 0x69, 0x6e, 0x52, 0x05, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x22, 0x20, 0x0a, 0x05, 0x43, + 0x68, 0x61, 0x69, 0x6e, 0x12, 0x0a, 0x0a, 0x06, 0x53, 0x4f, 0x4c, 0x41, 0x4e, 0x41, 0x10, 0x00, + 0x12, 0x0b, 0x0a, 0x07, 0x45, 0x43, 0x4c, 0x49, 0x50, 0x53, 0x45, 0x10, 0x01, 0x42, 0x0d, 0x0a, + 0x0b, 0x50, 0x6f, 0x6f, 0x6c, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x1a, 0x4f, 0x0a, 0x10, + 0x52, 0x65, 0x67, 0x65, 0x78, 0x45, 0x78, 0x74, 0x72, 0x61, 0x63, 0x74, 0x54, 0x61, 0x73, 0x6b, + 0x12, 0x18, 0x0a, 0x07, 0x70, 0x61, 0x74, 0x74, 0x65, 0x72, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x07, 0x70, 0x61, 0x74, 0x74, 0x65, 0x72, 0x6e, 0x12, 0x21, 0x0a, 0x0c, 0x67, 0x72, + 0x6f, 0x75, 0x70, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, + 0x52, 0x0b, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x1a, 0x95, 0x01, + 0x0a, 0x0e, 0x58, 0x53, 0x74, 0x65, 0x70, 0x50, 0x72, 0x69, 0x63, 0x65, 0x54, 0x61, 0x73, 0x6b, + 0x12, 0x3d, 0x0a, 0x08, 0x73, 0x74, 0x65, 0x70, 0x5f, 0x6a, 0x6f, 0x62, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x5f, 0x6a, 0x6f, 0x62, 0x2e, + 0x4f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x4a, 0x6f, 0x62, 0x2e, 0x4d, 0x65, 0x64, 0x69, 0x61, 0x6e, + 0x54, 0x61, 0x73, 0x6b, 0x48, 0x00, 0x52, 0x07, 0x73, 0x74, 0x65, 0x70, 0x4a, 0x6f, 0x62, 0x12, + 0x36, 0x0a, 0x16, 0x73, 0x74, 0x65, 0x70, 0x5f, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, + 0x6f, 0x72, 0x5f, 0x70, 0x75, 0x62, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, + 0x00, 0x52, 0x14, 0x73, 0x74, 0x65, 0x70, 0x41, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x6f, + 0x72, 0x50, 0x75, 0x62, 0x6b, 0x65, 0x79, 0x42, 0x0c, 0x0a, 0x0a, 0x53, 0x74, 0x65, 0x70, 0x53, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x1a, 0xc3, 0x02, 0x0a, 0x08, 0x54, 0x77, 0x61, 0x70, 0x54, 0x61, + 0x73, 0x6b, 0x12, 0x2b, 0x0a, 0x11, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x6f, 0x72, + 0x5f, 0x70, 0x75, 0x62, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x61, + 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x6f, 0x72, 0x50, 0x75, 0x62, 0x6b, 0x65, 0x79, 0x12, + 0x16, 0x0a, 0x06, 0x70, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, + 0x06, 0x70, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x12, 0x3b, 0x0a, 0x1a, 0x77, 0x65, 0x69, 0x67, 0x68, + 0x74, 0x5f, 0x62, 0x79, 0x5f, 0x70, 0x72, 0x6f, 0x70, 0x61, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x17, 0x77, 0x65, 0x69, + 0x67, 0x68, 0x74, 0x42, 0x79, 0x50, 0x72, 0x6f, 0x70, 0x61, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x54, 0x69, 0x6d, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x6d, 0x69, 0x6e, 0x5f, 0x73, 0x61, 0x6d, 0x70, + 0x6c, 0x65, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a, 0x6d, 0x69, 0x6e, 0x53, 0x61, + 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x12, 0x32, 0x0a, 0x15, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x5f, + 0x75, 0x6e, 0x69, 0x78, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x05, + 0x20, 0x01, 0x28, 0x05, 0x52, 0x13, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x55, 0x6e, 0x69, 0x78, + 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x60, 0x0a, 0x1a, 0x65, 0x6e, 0x64, + 0x69, 0x6e, 0x67, 0x5f, 0x75, 0x6e, 0x69, 0x78, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, + 0x6d, 0x70, 0x5f, 0x74, 0x61, 0x73, 0x6b, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, + 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x5f, 0x6a, 0x6f, 0x62, 0x2e, 0x4f, 0x72, 0x61, 0x63, 0x6c, + 0x65, 0x4a, 0x6f, 0x62, 0x2e, 0x43, 0x72, 0x6f, 0x6e, 0x50, 0x61, 0x72, 0x73, 0x65, 0x54, 0x61, + 0x73, 0x6b, 0x52, 0x17, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x55, 0x6e, 0x69, 0x78, 0x54, 0x69, + 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x54, 0x61, 0x73, 0x6b, 0x1a, 0x3d, 0x0a, 0x0d, 0x53, + 0x65, 0x72, 0x75, 0x6d, 0x53, 0x77, 0x61, 0x70, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x2c, 0x0a, 0x12, + 0x73, 0x65, 0x72, 0x75, 0x6d, 0x5f, 0x70, 0x6f, 0x6f, 0x6c, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, + 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x73, 0x65, 0x72, 0x75, 0x6d, 0x50, + 0x6f, 0x6f, 0x6c, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x1a, 0x72, 0x0a, 0x07, 0x50, 0x6f, + 0x77, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x18, 0x0a, 0x06, 0x73, 0x63, 0x61, 0x6c, 0x61, 0x72, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x01, 0x48, 0x00, 0x52, 0x06, 0x73, 0x63, 0x61, 0x6c, 0x61, 0x72, 0x12, + 0x2d, 0x0a, 0x11, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x6f, 0x72, 0x5f, 0x70, 0x75, + 0x62, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x10, 0x61, 0x67, + 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x6f, 0x72, 0x50, 0x75, 0x62, 0x6b, 0x65, 0x79, 0x12, 0x12, + 0x0a, 0x03, 0x62, 0x69, 0x67, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x03, 0x62, + 0x69, 0x67, 0x42, 0x0a, 0x0a, 0x08, 0x45, 0x78, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x1a, 0xc7, + 0x01, 0x0a, 0x0f, 0x4c, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x52, 0x61, 0x74, 0x65, 0x54, 0x61, + 0x73, 0x6b, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x12, 0x1d, + 0x0a, 0x0a, 0x61, 0x73, 0x73, 0x65, 0x74, 0x5f, 0x6d, 0x69, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x09, 0x61, 0x73, 0x73, 0x65, 0x74, 0x4d, 0x69, 0x6e, 0x74, 0x12, 0x41, 0x0a, + 0x05, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2b, 0x2e, 0x6f, + 0x72, 0x61, 0x63, 0x6c, 0x65, 0x5f, 0x6a, 0x6f, 0x62, 0x2e, 0x4f, 0x72, 0x61, 0x63, 0x6c, 0x65, + 0x4a, 0x6f, 0x62, 0x2e, 0x4c, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x52, 0x61, 0x74, 0x65, 0x54, + 0x61, 0x73, 0x6b, 0x2e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x52, 0x05, 0x66, 0x69, 0x65, 0x6c, 0x64, + 0x22, 0x36, 0x0a, 0x05, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x12, 0x16, 0x0a, 0x12, 0x46, 0x49, 0x45, + 0x4c, 0x44, 0x5f, 0x44, 0x45, 0x50, 0x4f, 0x53, 0x49, 0x54, 0x5f, 0x52, 0x41, 0x54, 0x45, 0x10, + 0x00, 0x12, 0x15, 0x0a, 0x11, 0x46, 0x49, 0x45, 0x4c, 0x44, 0x5f, 0x42, 0x4f, 0x52, 0x52, 0x4f, + 0x57, 0x5f, 0x52, 0x41, 0x54, 0x45, 0x10, 0x01, 0x1a, 0x45, 0x0a, 0x13, 0x4d, 0x61, 0x6e, 0x67, + 0x6f, 0x50, 0x65, 0x72, 0x70, 0x4d, 0x61, 0x72, 0x6b, 0x65, 0x74, 0x54, 0x61, 0x73, 0x6b, 0x12, + 0x2e, 0x0a, 0x13, 0x70, 0x65, 0x72, 0x70, 0x5f, 0x6d, 0x61, 0x72, 0x6b, 0x65, 0x74, 0x5f, 0x61, + 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x70, 0x65, + 0x72, 0x70, 0x4d, 0x61, 0x72, 0x6b, 0x65, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x1a, + 0x8a, 0x05, 0x0a, 0x0f, 0x4a, 0x75, 0x70, 0x69, 0x74, 0x65, 0x72, 0x53, 0x77, 0x61, 0x70, 0x54, + 0x61, 0x73, 0x6b, 0x12, 0x28, 0x0a, 0x10, 0x69, 0x6e, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x5f, + 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x69, + 0x6e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x2a, 0x0a, + 0x11, 0x6f, 0x75, 0x74, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, + 0x73, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x6f, 0x75, 0x74, 0x54, 0x6f, 0x6b, + 0x65, 0x6e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x51, 0x0a, 0x0a, 0x61, 0x6c, 0x6c, + 0x6f, 0x77, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x30, 0x2e, + 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x5f, 0x6a, 0x6f, 0x62, 0x2e, 0x4f, 0x72, 0x61, 0x63, 0x6c, + 0x65, 0x4a, 0x6f, 0x62, 0x2e, 0x4a, 0x75, 0x70, 0x69, 0x74, 0x65, 0x72, 0x53, 0x77, 0x61, 0x70, + 0x54, 0x61, 0x73, 0x6b, 0x2e, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x4c, 0x69, 0x73, 0x74, 0x48, + 0x00, 0x52, 0x09, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x4f, 0x0a, 0x09, + 0x64, 0x65, 0x6e, 0x79, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x30, 0x2e, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x5f, 0x6a, 0x6f, 0x62, 0x2e, 0x4f, 0x72, 0x61, + 0x63, 0x6c, 0x65, 0x4a, 0x6f, 0x62, 0x2e, 0x4a, 0x75, 0x70, 0x69, 0x74, 0x65, 0x72, 0x53, 0x77, + 0x61, 0x70, 0x54, 0x61, 0x73, 0x6b, 0x2e, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x4c, 0x69, 0x73, + 0x74, 0x48, 0x00, 0x52, 0x08, 0x64, 0x65, 0x6e, 0x79, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x21, 0x0a, + 0x0b, 0x62, 0x61, 0x73, 0x65, 0x5f, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x01, 0x48, 0x01, 0x52, 0x0a, 0x62, 0x61, 0x73, 0x65, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, + 0x12, 0x23, 0x0a, 0x0c, 0x71, 0x75, 0x6f, 0x74, 0x65, 0x5f, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, + 0x18, 0x06, 0x20, 0x01, 0x28, 0x01, 0x48, 0x01, 0x52, 0x0b, 0x71, 0x75, 0x6f, 0x74, 0x65, 0x41, + 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x2e, 0x0a, 0x12, 0x62, 0x61, 0x73, 0x65, 0x5f, 0x61, 0x6d, + 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x18, 0x07, 0x20, 0x01, 0x28, + 0x09, 0x48, 0x01, 0x52, 0x10, 0x62, 0x61, 0x73, 0x65, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x53, + 0x74, 0x72, 0x69, 0x6e, 0x67, 0x12, 0x30, 0x0a, 0x13, 0x71, 0x75, 0x6f, 0x74, 0x65, 0x5f, 0x61, + 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x18, 0x08, 0x20, 0x01, + 0x28, 0x09, 0x48, 0x01, 0x52, 0x11, 0x71, 0x75, 0x6f, 0x74, 0x65, 0x41, 0x6d, 0x6f, 0x75, 0x6e, + 0x74, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x6c, 0x69, 0x70, 0x70, + 0x61, 0x67, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x01, 0x52, 0x08, 0x73, 0x6c, 0x69, 0x70, 0x70, + 0x61, 0x67, 0x65, 0x12, 0x47, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x0a, + 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2d, 0x2e, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x5f, 0x6a, 0x6f, + 0x62, 0x2e, 0x4f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x4a, 0x6f, 0x62, 0x2e, 0x4a, 0x75, 0x70, 0x69, + 0x74, 0x65, 0x72, 0x53, 0x77, 0x61, 0x70, 0x54, 0x61, 0x73, 0x6b, 0x2e, 0x56, 0x65, 0x72, 0x73, + 0x69, 0x6f, 0x6e, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x1a, 0x24, 0x0a, 0x0a, + 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x6c, 0x61, + 0x62, 0x65, 0x6c, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x06, 0x6c, 0x61, 0x62, 0x65, + 0x6c, 0x73, 0x22, 0x29, 0x0a, 0x07, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x0e, 0x0a, + 0x0a, 0x56, 0x45, 0x52, 0x53, 0x49, 0x4f, 0x4e, 0x5f, 0x56, 0x31, 0x10, 0x00, 0x12, 0x0e, 0x0a, + 0x0a, 0x56, 0x45, 0x52, 0x53, 0x49, 0x4f, 0x4e, 0x5f, 0x56, 0x32, 0x10, 0x01, 0x42, 0x0f, 0x0a, + 0x0d, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x73, 0x42, 0x0c, + 0x0a, 0x0a, 0x53, 0x77, 0x61, 0x70, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x1a, 0xe9, 0x01, 0x0a, + 0x0e, 0x50, 0x65, 0x72, 0x70, 0x4d, 0x61, 0x72, 0x6b, 0x65, 0x74, 0x54, 0x61, 0x73, 0x6b, 0x12, + 0x32, 0x0a, 0x14, 0x6d, 0x61, 0x6e, 0x67, 0x6f, 0x5f, 0x6d, 0x61, 0x72, 0x6b, 0x65, 0x74, 0x5f, + 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, + 0x12, 0x6d, 0x61, 0x6e, 0x67, 0x6f, 0x4d, 0x61, 0x72, 0x6b, 0x65, 0x74, 0x41, 0x64, 0x64, 0x72, + 0x65, 0x73, 0x73, 0x12, 0x32, 0x0a, 0x14, 0x64, 0x72, 0x69, 0x66, 0x74, 0x5f, 0x6d, 0x61, 0x72, + 0x6b, 0x65, 0x74, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x48, 0x00, 0x52, 0x12, 0x64, 0x72, 0x69, 0x66, 0x74, 0x4d, 0x61, 0x72, 0x6b, 0x65, 0x74, + 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x30, 0x0a, 0x13, 0x7a, 0x65, 0x74, 0x61, 0x5f, + 0x6d, 0x61, 0x72, 0x6b, 0x65, 0x74, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x11, 0x7a, 0x65, 0x74, 0x61, 0x4d, 0x61, 0x72, 0x6b, + 0x65, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x2c, 0x0a, 0x11, 0x7a, 0x6f, 0x5f, + 0x6d, 0x61, 0x72, 0x6b, 0x65, 0x74, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x0f, 0x7a, 0x6f, 0x4d, 0x61, 0x72, 0x6b, 0x65, 0x74, + 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x42, 0x0f, 0x0a, 0x0d, 0x4d, 0x61, 0x72, 0x6b, 0x65, + 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x1a, 0xc5, 0x08, 0x0a, 0x0a, 0x4f, 0x72, 0x61, + 0x63, 0x6c, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x31, 0x0a, 0x13, 0x73, 0x77, 0x69, 0x74, 0x63, + 0x68, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x12, 0x73, 0x77, 0x69, 0x74, 0x63, 0x68, 0x62, 0x6f, + 0x61, 0x72, 0x64, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x23, 0x0a, 0x0c, 0x70, 0x79, + 0x74, 0x68, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x48, 0x00, 0x52, 0x0b, 0x70, 0x79, 0x74, 0x68, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, + 0x2d, 0x0a, 0x11, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x5f, 0x61, 0x64, 0x64, + 0x72, 0x65, 0x73, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x10, 0x63, 0x68, + 0x61, 0x69, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x19, + 0x0a, 0x07, 0x65, 0x64, 0x67, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x48, + 0x00, 0x52, 0x06, 0x65, 0x64, 0x67, 0x65, 0x49, 0x64, 0x12, 0x21, 0x0a, 0x0b, 0x72, 0x65, 0x64, + 0x73, 0x74, 0x6f, 0x6e, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, + 0x52, 0x0a, 0x72, 0x65, 0x64, 0x73, 0x74, 0x6f, 0x6e, 0x65, 0x49, 0x64, 0x12, 0x47, 0x0a, 0x20, + 0x70, 0x79, 0x74, 0x68, 0x5f, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x65, 0x64, 0x5f, 0x63, 0x6f, 0x6e, + 0x66, 0x69, 0x64, 0x65, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, + 0x18, 0x04, 0x20, 0x01, 0x28, 0x01, 0x52, 0x1d, 0x70, 0x79, 0x74, 0x68, 0x41, 0x6c, 0x6c, 0x6f, + 0x77, 0x65, 0x64, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x64, 0x65, 0x6e, 0x63, 0x65, 0x49, 0x6e, 0x74, + 0x65, 0x72, 0x76, 0x61, 0x6c, 0x12, 0x5e, 0x0a, 0x11, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x6c, 0x69, + 0x6e, 0x6b, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x31, 0x2e, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x5f, 0x6a, 0x6f, 0x62, 0x2e, 0x4f, 0x72, + 0x61, 0x63, 0x6c, 0x65, 0x4a, 0x6f, 0x62, 0x2e, 0x4f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x54, 0x61, + 0x73, 0x6b, 0x2e, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x43, 0x6f, 0x6e, 0x66, + 0x69, 0x67, 0x73, 0x52, 0x10, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x43, 0x6f, + 0x6e, 0x66, 0x69, 0x67, 0x73, 0x12, 0x4f, 0x0a, 0x0c, 0x70, 0x79, 0x74, 0x68, 0x5f, 0x63, 0x6f, + 0x6e, 0x66, 0x69, 0x67, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x6f, 0x72, + 0x61, 0x63, 0x6c, 0x65, 0x5f, 0x6a, 0x6f, 0x62, 0x2e, 0x4f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x4a, + 0x6f, 0x62, 0x2e, 0x4f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x2e, 0x50, 0x79, + 0x74, 0x68, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x52, 0x0b, 0x70, 0x79, 0x74, 0x68, 0x43, + 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x12, 0x64, 0x0a, 0x13, 0x73, 0x77, 0x69, 0x74, 0x63, 0x68, + 0x62, 0x6f, 0x61, 0x72, 0x64, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x18, 0x09, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x33, 0x2e, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x5f, 0x6a, 0x6f, 0x62, + 0x2e, 0x4f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x4a, 0x6f, 0x62, 0x2e, 0x4f, 0x72, 0x61, 0x63, 0x6c, + 0x65, 0x54, 0x61, 0x73, 0x6b, 0x2e, 0x53, 0x77, 0x69, 0x74, 0x63, 0x68, 0x62, 0x6f, 0x61, 0x72, + 0x64, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x52, 0x12, 0x73, 0x77, 0x69, 0x74, 0x63, 0x68, + 0x62, 0x6f, 0x61, 0x72, 0x64, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x12, 0x4f, 0x0a, 0x0c, + 0x65, 0x64, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x18, 0x0a, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x5f, 0x6a, 0x6f, 0x62, 0x2e, + 0x4f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x4a, 0x6f, 0x62, 0x2e, 0x4f, 0x72, 0x61, 0x63, 0x6c, 0x65, + 0x54, 0x61, 0x73, 0x6b, 0x2e, 0x45, 0x64, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, + 0x52, 0x0b, 0x65, 0x64, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x12, 0x5b, 0x0a, + 0x10, 0x72, 0x65, 0x64, 0x73, 0x74, 0x6f, 0x6e, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, + 0x73, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x30, 0x2e, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, + 0x5f, 0x6a, 0x6f, 0x62, 0x2e, 0x4f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x4a, 0x6f, 0x62, 0x2e, 0x4f, + 0x72, 0x61, 0x63, 0x6c, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x2e, 0x52, 0x65, 0x64, 0x73, 0x74, 0x6f, + 0x6e, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x52, 0x0f, 0x72, 0x65, 0x64, 0x73, 0x74, + 0x6f, 0x6e, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x1a, 0x2e, 0x0a, 0x10, 0x43, 0x68, + 0x61, 0x69, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x12, 0x1a, + 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x08, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x1a, 0xa1, 0x01, 0x0a, 0x0b, 0x50, + 0x79, 0x74, 0x68, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x68, 0x65, + 0x72, 0x6d, 0x65, 0x73, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, + 0x68, 0x65, 0x72, 0x6d, 0x65, 0x73, 0x55, 0x72, 0x6c, 0x12, 0x47, 0x0a, 0x20, 0x70, 0x79, 0x74, + 0x68, 0x5f, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x65, 0x64, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x64, + 0x65, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x01, 0x52, 0x1d, 0x70, 0x79, 0x74, 0x68, 0x41, 0x6c, 0x6c, 0x6f, 0x77, 0x65, 0x64, + 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x64, 0x65, 0x6e, 0x63, 0x65, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, + 0x61, 0x6c, 0x12, 0x2a, 0x0a, 0x11, 0x6d, 0x61, 0x78, 0x5f, 0x73, 0x74, 0x61, 0x6c, 0x65, 0x5f, + 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0f, 0x6d, + 0x61, 0x78, 0x53, 0x74, 0x61, 0x6c, 0x65, 0x53, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x1a, 0x59, + 0x0a, 0x12, 0x53, 0x77, 0x69, 0x74, 0x63, 0x68, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x43, 0x6f, 0x6e, + 0x66, 0x69, 0x67, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x29, + 0x0a, 0x04, 0x6a, 0x6f, 0x62, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x6f, + 0x72, 0x61, 0x63, 0x6c, 0x65, 0x5f, 0x6a, 0x6f, 0x62, 0x2e, 0x4f, 0x72, 0x61, 0x63, 0x6c, 0x65, + 0x4a, 0x6f, 0x62, 0x52, 0x04, 0x6a, 0x6f, 0x62, 0x73, 0x1a, 0x0d, 0x0a, 0x0b, 0x45, 0x64, 0x67, + 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x1a, 0x11, 0x0a, 0x0f, 0x52, 0x65, 0x64, 0x73, + 0x74, 0x6f, 0x6e, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x42, 0x13, 0x0a, 0x11, 0x41, + 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x6f, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, + 0x1a, 0x59, 0x0a, 0x0f, 0x41, 0x6e, 0x63, 0x68, 0x6f, 0x72, 0x46, 0x65, 0x74, 0x63, 0x68, 0x54, + 0x61, 0x73, 0x6b, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x5f, 0x69, + 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x61, 0x6d, + 0x49, 0x64, 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, 0x1a, 0x2a, 0x0a, 0x10, 0x53, + 0x70, 0x6c, 0x53, 0x74, 0x61, 0x6b, 0x65, 0x50, 0x6f, 0x6f, 0x6c, 0x54, 0x61, 0x73, 0x6b, 0x12, + 0x16, 0x0a, 0x06, 0x70, 0x75, 0x62, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x06, 0x70, 0x75, 0x62, 0x6b, 0x65, 0x79, 0x1a, 0x80, 0x01, 0x0a, 0x11, 0x53, 0x70, 0x6c, 0x54, + 0x6f, 0x6b, 0x65, 0x6e, 0x50, 0x61, 0x72, 0x73, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x34, 0x0a, + 0x15, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x5f, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x61, + 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x13, + 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x41, 0x64, 0x64, 0x72, + 0x65, 0x73, 0x73, 0x12, 0x23, 0x0a, 0x0c, 0x6d, 0x69, 0x6e, 0x74, 0x5f, 0x61, 0x64, 0x64, 0x72, + 0x65, 0x73, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x0b, 0x6d, 0x69, 0x6e, + 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x42, 0x10, 0x0a, 0x0e, 0x41, 0x63, 0x63, 0x6f, + 0x75, 0x6e, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x1a, 0xf8, 0x03, 0x0a, 0x17, 0x55, + 0x6e, 0x69, 0x73, 0x77, 0x61, 0x70, 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x61, + 0x74, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x28, 0x0a, 0x10, 0x69, 0x6e, 0x5f, 0x74, 0x6f, 0x6b, + 0x65, 0x6e, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x0e, 0x69, 0x6e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, + 0x12, 0x2a, 0x0a, 0x11, 0x6f, 0x75, 0x74, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x5f, 0x61, 0x64, + 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x6f, 0x75, 0x74, + 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x26, 0x0a, 0x0f, + 0x69, 0x6e, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x5f, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x01, 0x52, 0x0d, 0x69, 0x6e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x41, 0x6d, + 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x6c, 0x69, 0x70, 0x70, 0x61, 0x67, 0x65, + 0x18, 0x04, 0x20, 0x01, 0x28, 0x01, 0x52, 0x08, 0x73, 0x6c, 0x69, 0x70, 0x70, 0x61, 0x67, 0x65, + 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x18, 0x05, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x12, 0x4f, 0x0a, 0x07, + 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x35, 0x2e, + 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x5f, 0x6a, 0x6f, 0x62, 0x2e, 0x4f, 0x72, 0x61, 0x63, 0x6c, + 0x65, 0x4a, 0x6f, 0x62, 0x2e, 0x55, 0x6e, 0x69, 0x73, 0x77, 0x61, 0x70, 0x45, 0x78, 0x63, 0x68, + 0x61, 0x6e, 0x67, 0x65, 0x52, 0x61, 0x74, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x2e, 0x56, 0x65, 0x72, + 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x25, 0x0a, + 0x0e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, + 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x41, 0x64, 0x64, + 0x72, 0x65, 0x73, 0x73, 0x12, 0x27, 0x0a, 0x0f, 0x66, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x79, 0x5f, + 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x66, + 0x61, 0x63, 0x74, 0x6f, 0x72, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x25, 0x0a, + 0x0e, 0x71, 0x75, 0x6f, 0x74, 0x65, 0x72, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, + 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x71, 0x75, 0x6f, 0x74, 0x65, 0x72, 0x41, 0x64, 0x64, + 0x72, 0x65, 0x73, 0x73, 0x22, 0x5f, 0x0a, 0x07, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, + 0x19, 0x0a, 0x15, 0x56, 0x45, 0x52, 0x53, 0x49, 0x4f, 0x4e, 0x5f, 0x56, 0x32, 0x5f, 0x44, 0x45, + 0x50, 0x52, 0x45, 0x43, 0x41, 0x54, 0x45, 0x44, 0x10, 0x00, 0x12, 0x19, 0x0a, 0x15, 0x56, 0x45, + 0x52, 0x53, 0x49, 0x4f, 0x4e, 0x5f, 0x56, 0x33, 0x5f, 0x44, 0x45, 0x50, 0x52, 0x45, 0x43, 0x41, + 0x54, 0x45, 0x44, 0x10, 0x01, 0x12, 0x0e, 0x0a, 0x0a, 0x56, 0x45, 0x52, 0x53, 0x49, 0x4f, 0x4e, + 0x5f, 0x56, 0x32, 0x10, 0x02, 0x12, 0x0e, 0x0a, 0x0a, 0x56, 0x45, 0x52, 0x53, 0x49, 0x4f, 0x4e, + 0x5f, 0x56, 0x33, 0x10, 0x03, 0x1a, 0xd1, 0x01, 0x0a, 0x19, 0x53, 0x75, 0x73, 0x68, 0x69, 0x73, + 0x77, 0x61, 0x70, 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x61, 0x74, 0x65, 0x54, + 0x61, 0x73, 0x6b, 0x12, 0x28, 0x0a, 0x10, 0x69, 0x6e, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x5f, + 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x69, + 0x6e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x2a, 0x0a, + 0x11, 0x6f, 0x75, 0x74, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, + 0x73, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x6f, 0x75, 0x74, 0x54, 0x6f, 0x6b, + 0x65, 0x6e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x26, 0x0a, 0x0f, 0x69, 0x6e, 0x5f, + 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x5f, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x01, 0x52, 0x0d, 0x69, 0x6e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x41, 0x6d, 0x6f, 0x75, 0x6e, + 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x6c, 0x69, 0x70, 0x70, 0x61, 0x67, 0x65, 0x18, 0x04, 0x20, + 0x01, 0x28, 0x01, 0x52, 0x08, 0x73, 0x6c, 0x69, 0x70, 0x70, 0x61, 0x67, 0x65, 0x12, 0x1a, 0x0a, + 0x08, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x08, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x1a, 0xd3, 0x01, 0x0a, 0x1b, 0x50, 0x61, + 0x6e, 0x63, 0x61, 0x6b, 0x65, 0x73, 0x77, 0x61, 0x70, 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, + 0x65, 0x52, 0x61, 0x74, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x28, 0x0a, 0x10, 0x69, 0x6e, 0x5f, + 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x0e, 0x69, 0x6e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x41, 0x64, 0x64, 0x72, + 0x65, 0x73, 0x73, 0x12, 0x2a, 0x0a, 0x11, 0x6f, 0x75, 0x74, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, + 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, + 0x6f, 0x75, 0x74, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, + 0x26, 0x0a, 0x0f, 0x69, 0x6e, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x5f, 0x61, 0x6d, 0x6f, 0x75, + 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x01, 0x52, 0x0d, 0x69, 0x6e, 0x54, 0x6f, 0x6b, 0x65, + 0x6e, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x6c, 0x69, 0x70, 0x70, + 0x61, 0x67, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x01, 0x52, 0x08, 0x73, 0x6c, 0x69, 0x70, 0x70, + 0x61, 0x67, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x18, + 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x1a, + 0xb2, 0x01, 0x0a, 0x09, 0x43, 0x61, 0x63, 0x68, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x4a, 0x0a, + 0x0b, 0x63, 0x61, 0x63, 0x68, 0x65, 0x5f, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x18, 0x01, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x5f, 0x6a, 0x6f, 0x62, 0x2e, + 0x4f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x4a, 0x6f, 0x62, 0x2e, 0x43, 0x61, 0x63, 0x68, 0x65, 0x54, + 0x61, 0x73, 0x6b, 0x2e, 0x43, 0x61, 0x63, 0x68, 0x65, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x0a, 0x63, + 0x61, 0x63, 0x68, 0x65, 0x49, 0x74, 0x65, 0x6d, 0x73, 0x1a, 0x59, 0x0a, 0x09, 0x43, 0x61, 0x63, + 0x68, 0x65, 0x49, 0x74, 0x65, 0x6d, 0x12, 0x23, 0x0a, 0x0d, 0x76, 0x61, 0x72, 0x69, 0x61, 0x62, + 0x6c, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x76, + 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x27, 0x0a, 0x03, 0x6a, + 0x6f, 0x62, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x6f, 0x72, 0x61, 0x63, 0x6c, + 0x65, 0x5f, 0x6a, 0x6f, 0x62, 0x2e, 0x4f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x4a, 0x6f, 0x62, 0x52, + 0x03, 0x6a, 0x6f, 0x62, 0x1a, 0x14, 0x0a, 0x12, 0x53, 0x79, 0x73, 0x63, 0x6c, 0x6f, 0x63, 0x6b, + 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x54, 0x61, 0x73, 0x6b, 0x1a, 0x13, 0x0a, 0x11, 0x4d, 0x61, + 0x72, 0x69, 0x6e, 0x61, 0x64, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x1a, + 0xd1, 0x01, 0x0a, 0x1a, 0x53, 0x6f, 0x6c, 0x61, 0x6e, 0x61, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, + 0x74, 0x44, 0x61, 0x74, 0x61, 0x46, 0x65, 0x74, 0x63, 0x68, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x16, + 0x0a, 0x06, 0x70, 0x75, 0x62, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, + 0x70, 0x75, 0x62, 0x6b, 0x65, 0x79, 0x12, 0x52, 0x0a, 0x07, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, + 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x38, 0x2e, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, + 0x5f, 0x6a, 0x6f, 0x62, 0x2e, 0x4f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x4a, 0x6f, 0x62, 0x2e, 0x53, + 0x6f, 0x6c, 0x61, 0x6e, 0x61, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x44, 0x61, 0x74, 0x61, + 0x46, 0x65, 0x74, 0x63, 0x68, 0x54, 0x61, 0x73, 0x6b, 0x2e, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, + 0x6b, 0x52, 0x07, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x22, 0x47, 0x0a, 0x07, 0x4e, 0x65, + 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x12, 0x13, 0x0a, 0x0f, 0x4e, 0x45, 0x54, 0x57, 0x4f, 0x52, 0x4b, + 0x5f, 0x4d, 0x41, 0x49, 0x4e, 0x4e, 0x45, 0x54, 0x10, 0x00, 0x12, 0x13, 0x0a, 0x0f, 0x4e, 0x45, + 0x54, 0x57, 0x4f, 0x52, 0x4b, 0x5f, 0x54, 0x45, 0x53, 0x54, 0x4e, 0x45, 0x54, 0x10, 0x01, 0x12, + 0x12, 0x0a, 0x0e, 0x4e, 0x45, 0x54, 0x57, 0x4f, 0x52, 0x4b, 0x5f, 0x44, 0x45, 0x56, 0x4e, 0x45, + 0x54, 0x10, 0x02, 0x1a, 0xc1, 0x01, 0x0a, 0x0d, 0x43, 0x72, 0x6f, 0x6e, 0x50, 0x61, 0x72, 0x73, + 0x65, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x72, 0x6f, 0x6e, 0x5f, 0x70, 0x61, + 0x74, 0x74, 0x65, 0x72, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x72, 0x6f, + 0x6e, 0x50, 0x61, 0x74, 0x74, 0x65, 0x72, 0x6e, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x6c, 0x6f, 0x63, + 0x6b, 0x5f, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0b, + 0x63, 0x6c, 0x6f, 0x63, 0x6b, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x12, 0x43, 0x0a, 0x05, 0x63, + 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2d, 0x2e, 0x6f, 0x72, 0x61, + 0x63, 0x6c, 0x65, 0x5f, 0x6a, 0x6f, 0x62, 0x2e, 0x4f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x4a, 0x6f, + 0x62, 0x2e, 0x43, 0x72, 0x6f, 0x6e, 0x50, 0x61, 0x72, 0x73, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x2e, + 0x43, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x79, 0x70, 0x65, 0x52, 0x05, 0x63, 0x6c, 0x6f, 0x63, 0x6b, + 0x22, 0x25, 0x0a, 0x09, 0x43, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0a, 0x0a, + 0x06, 0x4f, 0x52, 0x41, 0x43, 0x4c, 0x45, 0x10, 0x00, 0x12, 0x0c, 0x0a, 0x08, 0x53, 0x59, 0x53, + 0x43, 0x4c, 0x4f, 0x43, 0x4b, 0x10, 0x01, 0x1a, 0x8f, 0x03, 0x0a, 0x15, 0x42, 0x75, 0x66, 0x66, + 0x65, 0x72, 0x4c, 0x61, 0x79, 0x6f, 0x75, 0x74, 0x50, 0x61, 0x72, 0x73, 0x65, 0x54, 0x61, 0x73, + 0x6b, 0x12, 0x16, 0x0a, 0x06, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0d, 0x52, 0x06, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x12, 0x4a, 0x0a, 0x06, 0x65, 0x6e, 0x64, + 0x69, 0x61, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x32, 0x2e, 0x6f, 0x72, 0x61, 0x63, + 0x6c, 0x65, 0x5f, 0x6a, 0x6f, 0x62, 0x2e, 0x4f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x4a, 0x6f, 0x62, + 0x2e, 0x42, 0x75, 0x66, 0x66, 0x65, 0x72, 0x4c, 0x61, 0x79, 0x6f, 0x75, 0x74, 0x50, 0x61, 0x72, + 0x73, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x2e, 0x45, 0x6e, 0x64, 0x69, 0x61, 0x6e, 0x52, 0x06, 0x65, + 0x6e, 0x64, 0x69, 0x61, 0x6e, 0x12, 0x4f, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x0e, 0x32, 0x3b, 0x2e, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x5f, 0x6a, 0x6f, 0x62, + 0x2e, 0x4f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x4a, 0x6f, 0x62, 0x2e, 0x42, 0x75, 0x66, 0x66, 0x65, + 0x72, 0x4c, 0x61, 0x79, 0x6f, 0x75, 0x74, 0x50, 0x61, 0x72, 0x73, 0x65, 0x54, 0x61, 0x73, 0x6b, + 0x2e, 0x42, 0x75, 0x66, 0x66, 0x65, 0x72, 0x50, 0x61, 0x72, 0x73, 0x65, 0x54, 0x79, 0x70, 0x65, + 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x22, 0x2b, 0x0a, 0x06, 0x45, 0x6e, 0x64, 0x69, 0x61, 0x6e, + 0x12, 0x11, 0x0a, 0x0d, 0x4c, 0x49, 0x54, 0x54, 0x4c, 0x45, 0x5f, 0x45, 0x4e, 0x44, 0x49, 0x41, + 0x4e, 0x10, 0x00, 0x12, 0x0e, 0x0a, 0x0a, 0x42, 0x49, 0x47, 0x5f, 0x45, 0x4e, 0x44, 0x49, 0x41, + 0x4e, 0x10, 0x01, 0x22, 0x93, 0x01, 0x0a, 0x0f, 0x42, 0x75, 0x66, 0x66, 0x65, 0x72, 0x50, 0x61, + 0x72, 0x73, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0a, 0x0a, 0x06, 0x70, 0x75, 0x62, 0x6b, 0x65, + 0x79, 0x10, 0x01, 0x12, 0x08, 0x0a, 0x04, 0x62, 0x6f, 0x6f, 0x6c, 0x10, 0x02, 0x12, 0x06, 0x0a, + 0x02, 0x75, 0x38, 0x10, 0x03, 0x12, 0x06, 0x0a, 0x02, 0x69, 0x38, 0x10, 0x04, 0x12, 0x07, 0x0a, + 0x03, 0x75, 0x31, 0x36, 0x10, 0x05, 0x12, 0x07, 0x0a, 0x03, 0x69, 0x31, 0x36, 0x10, 0x06, 0x12, + 0x07, 0x0a, 0x03, 0x75, 0x33, 0x32, 0x10, 0x07, 0x12, 0x07, 0x0a, 0x03, 0x69, 0x33, 0x32, 0x10, + 0x08, 0x12, 0x07, 0x0a, 0x03, 0x66, 0x33, 0x32, 0x10, 0x09, 0x12, 0x07, 0x0a, 0x03, 0x75, 0x36, + 0x34, 0x10, 0x0a, 0x12, 0x07, 0x0a, 0x03, 0x69, 0x36, 0x34, 0x10, 0x0b, 0x12, 0x07, 0x0a, 0x03, + 0x66, 0x36, 0x34, 0x10, 0x0c, 0x12, 0x08, 0x0a, 0x04, 0x75, 0x31, 0x32, 0x38, 0x10, 0x0d, 0x12, + 0x08, 0x0a, 0x04, 0x69, 0x31, 0x32, 0x38, 0x10, 0x0e, 0x1a, 0xd0, 0x01, 0x0a, 0x13, 0x48, 0x69, + 0x73, 0x74, 0x6f, 0x72, 0x79, 0x46, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x61, 0x73, + 0x6b, 0x12, 0x48, 0x0a, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0e, 0x32, 0x30, 0x2e, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x5f, 0x6a, 0x6f, 0x62, 0x2e, 0x4f, + 0x72, 0x61, 0x63, 0x6c, 0x65, 0x4a, 0x6f, 0x62, 0x2e, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, + 0x46, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x61, 0x73, 0x6b, 0x2e, 0x4d, 0x65, 0x74, + 0x68, 0x6f, 0x64, 0x52, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x12, 0x2d, 0x0a, 0x12, 0x61, + 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x6f, 0x72, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, + 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, + 0x74, 0x6f, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x65, + 0x72, 0x69, 0x6f, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x06, 0x70, 0x65, 0x72, 0x69, + 0x6f, 0x64, 0x22, 0x28, 0x0a, 0x06, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x12, 0x0e, 0x0a, 0x0a, + 0x4d, 0x45, 0x54, 0x48, 0x4f, 0x44, 0x5f, 0x4d, 0x49, 0x4e, 0x10, 0x00, 0x12, 0x0e, 0x0a, 0x0a, + 0x4d, 0x45, 0x54, 0x48, 0x4f, 0x44, 0x5f, 0x4d, 0x41, 0x58, 0x10, 0x01, 0x1a, 0x98, 0x01, 0x0a, + 0x08, 0x56, 0x77, 0x61, 0x70, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x38, 0x0a, 0x18, 0x70, 0x72, 0x69, + 0x63, 0x65, 0x5f, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x6f, 0x72, 0x5f, 0x61, 0x64, + 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x16, 0x70, 0x72, 0x69, + 0x63, 0x65, 0x41, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x6f, 0x72, 0x41, 0x64, 0x64, 0x72, + 0x65, 0x73, 0x73, 0x12, 0x3a, 0x0a, 0x19, 0x76, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x5f, 0x61, 0x67, + 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x6f, 0x72, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x17, 0x76, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x41, 0x67, + 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x6f, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, + 0x16, 0x0a, 0x06, 0x70, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, + 0x06, 0x70, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x1a, 0x69, 0x0a, 0x08, 0x45, 0x77, 0x6d, 0x61, 0x54, + 0x61, 0x73, 0x6b, 0x12, 0x2d, 0x0a, 0x12, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x6f, + 0x72, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x11, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x6f, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, + 0x73, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x05, 0x52, 0x06, 0x70, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x6c, 0x61, + 0x6d, 0x62, 0x64, 0x61, 0x18, 0x03, 0x20, 0x01, 0x28, 0x01, 0x52, 0x06, 0x6c, 0x61, 0x6d, 0x62, + 0x64, 0x61, 0x1a, 0xc1, 0x04, 0x0a, 0x0e, 0x43, 0x6f, 0x6d, 0x70, 0x61, 0x72, 0x69, 0x73, 0x6f, + 0x6e, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x3e, 0x0a, 0x02, 0x6f, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0e, 0x32, 0x2e, 0x2e, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x5f, 0x6a, 0x6f, 0x62, 0x2e, 0x4f, + 0x72, 0x61, 0x63, 0x6c, 0x65, 0x4a, 0x6f, 0x62, 0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x61, 0x72, 0x69, + 0x73, 0x6f, 0x6e, 0x54, 0x61, 0x73, 0x6b, 0x2e, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x52, 0x02, 0x6f, 0x70, 0x12, 0x29, 0x0a, 0x03, 0x6c, 0x68, 0x73, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x5f, 0x6a, 0x6f, 0x62, 0x2e, + 0x4f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x4a, 0x6f, 0x62, 0x48, 0x00, 0x52, 0x03, 0x6c, 0x68, 0x73, + 0x12, 0x1d, 0x0a, 0x09, 0x6c, 0x68, 0x73, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x08, 0x6c, 0x68, 0x73, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, + 0x29, 0x0a, 0x03, 0x72, 0x68, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x6f, + 0x72, 0x61, 0x63, 0x6c, 0x65, 0x5f, 0x6a, 0x6f, 0x62, 0x2e, 0x4f, 0x72, 0x61, 0x63, 0x6c, 0x65, + 0x4a, 0x6f, 0x62, 0x48, 0x01, 0x52, 0x03, 0x72, 0x68, 0x73, 0x12, 0x1d, 0x0a, 0x09, 0x72, 0x68, + 0x73, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x48, 0x01, 0x52, + 0x08, 0x72, 0x68, 0x73, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x2e, 0x0a, 0x07, 0x6f, 0x6e, 0x5f, + 0x74, 0x72, 0x75, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x6f, 0x72, 0x61, + 0x63, 0x6c, 0x65, 0x5f, 0x6a, 0x6f, 0x62, 0x2e, 0x4f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x4a, 0x6f, + 0x62, 0x52, 0x06, 0x6f, 0x6e, 0x54, 0x72, 0x75, 0x65, 0x12, 0x22, 0x0a, 0x0d, 0x6f, 0x6e, 0x5f, + 0x74, 0x72, 0x75, 0x65, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x0b, 0x6f, 0x6e, 0x54, 0x72, 0x75, 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x30, 0x0a, + 0x08, 0x6f, 0x6e, 0x5f, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x15, 0x2e, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x5f, 0x6a, 0x6f, 0x62, 0x2e, 0x4f, 0x72, 0x61, + 0x63, 0x6c, 0x65, 0x4a, 0x6f, 0x62, 0x52, 0x07, 0x6f, 0x6e, 0x46, 0x61, 0x6c, 0x73, 0x65, 0x12, + 0x24, 0x0a, 0x0e, 0x6f, 0x6e, 0x5f, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x5f, 0x76, 0x61, 0x6c, 0x75, + 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x6f, 0x6e, 0x46, 0x61, 0x6c, 0x73, 0x65, + 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x34, 0x0a, 0x0a, 0x6f, 0x6e, 0x5f, 0x66, 0x61, 0x69, 0x6c, + 0x75, 0x72, 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x6f, 0x72, 0x61, 0x63, + 0x6c, 0x65, 0x5f, 0x6a, 0x6f, 0x62, 0x2e, 0x4f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x4a, 0x6f, 0x62, + 0x52, 0x09, 0x6f, 0x6e, 0x46, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x12, 0x28, 0x0a, 0x10, 0x6f, + 0x6e, 0x5f, 0x66, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, + 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x6f, 0x6e, 0x46, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, + 0x56, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x41, 0x0a, 0x09, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x12, 0x10, 0x0a, 0x0c, 0x4f, 0x50, 0x45, 0x52, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, + 0x45, 0x51, 0x10, 0x00, 0x12, 0x10, 0x0a, 0x0c, 0x4f, 0x50, 0x45, 0x52, 0x41, 0x54, 0x49, 0x4f, + 0x4e, 0x5f, 0x47, 0x54, 0x10, 0x01, 0x12, 0x10, 0x0a, 0x0c, 0x4f, 0x50, 0x45, 0x52, 0x41, 0x54, + 0x49, 0x4f, 0x4e, 0x5f, 0x4c, 0x54, 0x10, 0x02, 0x42, 0x05, 0x0a, 0x03, 0x4c, 0x48, 0x53, 0x42, + 0x05, 0x0a, 0x03, 0x52, 0x48, 0x53, 0x1a, 0x9d, 0x01, 0x0a, 0x09, 0x52, 0x6f, 0x75, 0x6e, 0x64, + 0x54, 0x61, 0x73, 0x6b, 0x12, 0x3e, 0x0a, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0e, 0x32, 0x26, 0x2e, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x5f, 0x6a, 0x6f, + 0x62, 0x2e, 0x4f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x4a, 0x6f, 0x62, 0x2e, 0x52, 0x6f, 0x75, 0x6e, + 0x64, 0x54, 0x61, 0x73, 0x6b, 0x2e, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x52, 0x06, 0x6d, 0x65, + 0x74, 0x68, 0x6f, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x64, 0x65, 0x63, 0x69, 0x6d, 0x61, 0x6c, 0x73, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x64, 0x65, 0x63, 0x69, 0x6d, 0x61, 0x6c, 0x73, + 0x22, 0x34, 0x0a, 0x06, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x12, 0x13, 0x0a, 0x0f, 0x4d, 0x45, + 0x54, 0x48, 0x4f, 0x44, 0x5f, 0x52, 0x4f, 0x55, 0x4e, 0x44, 0x5f, 0x55, 0x50, 0x10, 0x00, 0x12, + 0x15, 0x0a, 0x11, 0x4d, 0x45, 0x54, 0x48, 0x4f, 0x44, 0x5f, 0x52, 0x4f, 0x55, 0x4e, 0x44, 0x5f, + 0x44, 0x4f, 0x57, 0x4e, 0x10, 0x01, 0x1a, 0xeb, 0x03, 0x0a, 0x09, 0x42, 0x6f, 0x75, 0x6e, 0x64, + 0x54, 0x61, 0x73, 0x6b, 0x12, 0x36, 0x0a, 0x0b, 0x6c, 0x6f, 0x77, 0x65, 0x72, 0x5f, 0x62, 0x6f, + 0x75, 0x6e, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x6f, 0x72, 0x61, 0x63, + 0x6c, 0x65, 0x5f, 0x6a, 0x6f, 0x62, 0x2e, 0x4f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x4a, 0x6f, 0x62, + 0x52, 0x0a, 0x6c, 0x6f, 0x77, 0x65, 0x72, 0x42, 0x6f, 0x75, 0x6e, 0x64, 0x12, 0x2a, 0x0a, 0x11, + 0x6c, 0x6f, 0x77, 0x65, 0x72, 0x5f, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x76, 0x61, 0x6c, 0x75, + 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x6c, 0x6f, 0x77, 0x65, 0x72, 0x42, 0x6f, + 0x75, 0x6e, 0x64, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x36, 0x0a, 0x0b, 0x75, 0x70, 0x70, 0x65, + 0x72, 0x5f, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, + 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x5f, 0x6a, 0x6f, 0x62, 0x2e, 0x4f, 0x72, 0x61, 0x63, 0x6c, + 0x65, 0x4a, 0x6f, 0x62, 0x52, 0x0a, 0x75, 0x70, 0x70, 0x65, 0x72, 0x42, 0x6f, 0x75, 0x6e, 0x64, + 0x12, 0x2a, 0x0a, 0x11, 0x75, 0x70, 0x70, 0x65, 0x72, 0x5f, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x5f, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x75, 0x70, 0x70, + 0x65, 0x72, 0x42, 0x6f, 0x75, 0x6e, 0x64, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x4a, 0x0a, 0x16, + 0x6f, 0x6e, 0x5f, 0x65, 0x78, 0x63, 0x65, 0x65, 0x64, 0x73, 0x5f, 0x75, 0x70, 0x70, 0x65, 0x72, + 0x5f, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x6f, + 0x72, 0x61, 0x63, 0x6c, 0x65, 0x5f, 0x6a, 0x6f, 0x62, 0x2e, 0x4f, 0x72, 0x61, 0x63, 0x6c, 0x65, + 0x4a, 0x6f, 0x62, 0x52, 0x13, 0x6f, 0x6e, 0x45, 0x78, 0x63, 0x65, 0x65, 0x64, 0x73, 0x55, 0x70, + 0x70, 0x65, 0x72, 0x42, 0x6f, 0x75, 0x6e, 0x64, 0x12, 0x3e, 0x0a, 0x1c, 0x6f, 0x6e, 0x5f, 0x65, + 0x78, 0x63, 0x65, 0x65, 0x64, 0x73, 0x5f, 0x75, 0x70, 0x70, 0x65, 0x72, 0x5f, 0x62, 0x6f, 0x75, + 0x6e, 0x64, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x18, + 0x6f, 0x6e, 0x45, 0x78, 0x63, 0x65, 0x65, 0x64, 0x73, 0x55, 0x70, 0x70, 0x65, 0x72, 0x42, 0x6f, + 0x75, 0x6e, 0x64, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x4a, 0x0a, 0x16, 0x6f, 0x6e, 0x5f, 0x65, + 0x78, 0x63, 0x65, 0x65, 0x64, 0x73, 0x5f, 0x6c, 0x6f, 0x77, 0x65, 0x72, 0x5f, 0x62, 0x6f, 0x75, + 0x6e, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x6f, 0x72, 0x61, 0x63, 0x6c, + 0x65, 0x5f, 0x6a, 0x6f, 0x62, 0x2e, 0x4f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x4a, 0x6f, 0x62, 0x52, + 0x13, 0x6f, 0x6e, 0x45, 0x78, 0x63, 0x65, 0x65, 0x64, 0x73, 0x4c, 0x6f, 0x77, 0x65, 0x72, 0x42, + 0x6f, 0x75, 0x6e, 0x64, 0x12, 0x3e, 0x0a, 0x1c, 0x6f, 0x6e, 0x5f, 0x65, 0x78, 0x63, 0x65, 0x65, + 0x64, 0x73, 0x5f, 0x6c, 0x6f, 0x77, 0x65, 0x72, 0x5f, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x76, + 0x61, 0x6c, 0x75, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x18, 0x6f, 0x6e, 0x45, 0x78, + 0x63, 0x65, 0x65, 0x64, 0x73, 0x4c, 0x6f, 0x77, 0x65, 0x72, 0x42, 0x6f, 0x75, 0x6e, 0x64, 0x56, + 0x61, 0x6c, 0x75, 0x65, 0x1a, 0x3d, 0x0a, 0x0b, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x73, 0x54, + 0x61, 0x73, 0x6b, 0x12, 0x1c, 0x0a, 0x09, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, + 0x79, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x72, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, + 0x75, 0x72, 0x6c, 0x1a, 0x5a, 0x0a, 0x13, 0x53, 0x61, 0x6e, 0x63, 0x74, 0x75, 0x6d, 0x4c, 0x73, + 0x74, 0x50, 0x72, 0x69, 0x63, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x19, 0x0a, 0x08, 0x6c, 0x73, + 0x74, 0x5f, 0x6d, 0x69, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6c, 0x73, + 0x74, 0x4d, 0x69, 0x6e, 0x74, 0x12, 0x28, 0x0a, 0x10, 0x73, 0x6b, 0x69, 0x70, 0x5f, 0x65, 0x70, + 0x6f, 0x63, 0x68, 0x5f, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, + 0x0e, 0x73, 0x6b, 0x69, 0x70, 0x45, 0x70, 0x6f, 0x63, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x1a, + 0x91, 0x01, 0x0a, 0x0c, 0x4f, 0x6e, 0x64, 0x6f, 0x55, 0x73, 0x64, 0x79, 0x54, 0x61, 0x73, 0x6b, + 0x12, 0x47, 0x0a, 0x08, 0x73, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0e, 0x32, 0x2b, 0x2e, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x5f, 0x6a, 0x6f, 0x62, 0x2e, + 0x4f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x4a, 0x6f, 0x62, 0x2e, 0x4f, 0x6e, 0x64, 0x6f, 0x55, 0x73, + 0x64, 0x79, 0x54, 0x61, 0x73, 0x6b, 0x2e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x52, + 0x08, 0x73, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x22, 0x38, 0x0a, 0x08, 0x53, 0x74, 0x72, + 0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x17, 0x0a, 0x13, 0x53, 0x54, 0x52, 0x41, 0x54, 0x45, 0x47, + 0x59, 0x5f, 0x46, 0x41, 0x49, 0x52, 0x5f, 0x56, 0x41, 0x4c, 0x55, 0x45, 0x10, 0x00, 0x12, 0x13, + 0x0a, 0x0f, 0x53, 0x54, 0x52, 0x41, 0x54, 0x45, 0x47, 0x59, 0x5f, 0x4d, 0x41, 0x52, 0x4b, 0x45, + 0x54, 0x10, 0x01, 0x1a, 0x8f, 0x01, 0x0a, 0x0f, 0x4d, 0x65, 0x74, 0x65, 0x6f, 0x72, 0x61, 0x53, + 0x77, 0x61, 0x70, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x6f, 0x6f, 0x6c, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x6f, 0x6f, 0x6c, 0x12, 0x3e, 0x0a, 0x04, 0x74, + 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2a, 0x2e, 0x6f, 0x72, 0x61, 0x63, + 0x6c, 0x65, 0x5f, 0x6a, 0x6f, 0x62, 0x2e, 0x4f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x4a, 0x6f, 0x62, + 0x2e, 0x4d, 0x65, 0x74, 0x65, 0x6f, 0x72, 0x61, 0x53, 0x77, 0x61, 0x70, 0x54, 0x61, 0x73, 0x6b, + 0x2e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x22, 0x28, 0x0a, 0x04, 0x54, + 0x79, 0x70, 0x65, 0x12, 0x0d, 0x0a, 0x09, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x44, 0x4c, 0x4d, 0x4d, + 0x10, 0x00, 0x12, 0x11, 0x0a, 0x0d, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x53, 0x54, 0x41, 0x4e, 0x44, + 0x41, 0x52, 0x44, 0x10, 0x01, 0x1a, 0x26, 0x0a, 0x0c, 0x55, 0x6e, 0x69, 0x78, 0x54, 0x69, 0x6d, + 0x65, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x16, 0x0a, 0x06, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x1a, 0x85, 0x01, + 0x0a, 0x10, 0x4d, 0x61, 0x70, 0x6c, 0x65, 0x46, 0x69, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x54, 0x61, + 0x73, 0x6b, 0x12, 0x45, 0x0a, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0e, 0x32, 0x2d, 0x2e, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x5f, 0x6a, 0x6f, 0x62, 0x2e, + 0x4f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x4a, 0x6f, 0x62, 0x2e, 0x4d, 0x61, 0x70, 0x6c, 0x65, 0x46, + 0x69, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x2e, 0x4d, 0x65, 0x74, 0x68, 0x6f, + 0x64, 0x52, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x22, 0x2a, 0x0a, 0x06, 0x4d, 0x65, 0x74, + 0x68, 0x6f, 0x64, 0x12, 0x20, 0x0a, 0x1c, 0x4d, 0x45, 0x54, 0x48, 0x4f, 0x44, 0x5f, 0x53, 0x59, + 0x52, 0x55, 0x50, 0x5f, 0x55, 0x53, 0x44, 0x43, 0x5f, 0x46, 0x41, 0x49, 0x52, 0x5f, 0x50, 0x52, + 0x49, 0x43, 0x45, 0x10, 0x00, 0x1a, 0x50, 0x0a, 0x09, 0x47, 0x6c, 0x79, 0x70, 0x68, 0x54, 0x61, + 0x73, 0x6b, 0x12, 0x21, 0x0a, 0x0c, 0x70, 0x6f, 0x6f, 0x6c, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, + 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x70, 0x6f, 0x6f, 0x6c, 0x41, 0x64, + 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x20, 0x0a, 0x0c, 0x7a, 0x65, 0x72, 0x6f, 0x5f, 0x66, 0x6f, + 0x72, 0x5f, 0x6f, 0x6e, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x7a, 0x65, 0x72, + 0x6f, 0x46, 0x6f, 0x72, 0x4f, 0x6e, 0x65, 0x1a, 0x5f, 0x0a, 0x09, 0x43, 0x6f, 0x72, 0x65, 0x78, + 0x54, 0x61, 0x73, 0x6b, 0x12, 0x19, 0x0a, 0x08, 0x69, 0x6e, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x69, 0x6e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, + 0x1b, 0x0a, 0x09, 0x6f, 0x75, 0x74, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x08, 0x6f, 0x75, 0x74, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x1a, 0x0a, 0x08, + 0x73, 0x6c, 0x69, 0x70, 0x70, 0x61, 0x67, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x01, 0x52, 0x08, + 0x73, 0x6c, 0x69, 0x70, 0x70, 0x61, 0x67, 0x65, 0x1a, 0x95, 0x01, 0x0a, 0x0d, 0x41, 0x66, 0x74, + 0x65, 0x72, 0x6d, 0x61, 0x74, 0x68, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x21, 0x0a, 0x0c, 0x70, 0x6f, + 0x6f, 0x6c, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x0b, 0x70, 0x6f, 0x6f, 0x6c, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x1b, 0x0a, + 0x09, 0x69, 0x6e, 0x5f, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x01, + 0x52, 0x08, 0x69, 0x6e, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x20, 0x0a, 0x0c, 0x69, 0x6e, + 0x5f, 0x63, 0x6f, 0x69, 0x6e, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x0a, 0x69, 0x6e, 0x43, 0x6f, 0x69, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x12, 0x22, 0x0a, 0x0d, + 0x6f, 0x75, 0x74, 0x5f, 0x63, 0x6f, 0x69, 0x6e, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x04, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x0b, 0x6f, 0x75, 0x74, 0x43, 0x6f, 0x69, 0x6e, 0x54, 0x79, 0x70, 0x65, + 0x1a, 0xb5, 0x05, 0x0a, 0x07, 0x4c, 0x6c, 0x6d, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x44, 0x0a, 0x06, + 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x69, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x6f, + 0x72, 0x61, 0x63, 0x6c, 0x65, 0x5f, 0x6a, 0x6f, 0x62, 0x2e, 0x4f, 0x72, 0x61, 0x63, 0x6c, 0x65, + 0x4a, 0x6f, 0x62, 0x2e, 0x4c, 0x6c, 0x6d, 0x54, 0x61, 0x73, 0x6b, 0x2e, 0x4f, 0x70, 0x65, 0x6e, + 0x41, 0x49, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x48, 0x00, 0x52, 0x06, 0x6f, 0x70, 0x65, 0x6e, + 0x61, 0x69, 0x12, 0x3e, 0x0a, 0x04, 0x67, 0x72, 0x6f, 0x71, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x28, 0x2e, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x5f, 0x6a, 0x6f, 0x62, 0x2e, 0x4f, 0x72, + 0x61, 0x63, 0x6c, 0x65, 0x4a, 0x6f, 0x62, 0x2e, 0x4c, 0x6c, 0x6d, 0x54, 0x61, 0x73, 0x6b, 0x2e, + 0x47, 0x72, 0x6f, 0x71, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x48, 0x00, 0x52, 0x04, 0x67, 0x72, + 0x6f, 0x71, 0x12, 0x47, 0x0a, 0x07, 0x67, 0x72, 0x6f, 0x6b, 0x78, 0x61, 0x69, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x5f, 0x6a, 0x6f, 0x62, + 0x2e, 0x4f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x4a, 0x6f, 0x62, 0x2e, 0x4c, 0x6c, 0x6d, 0x54, 0x61, + 0x73, 0x6b, 0x2e, 0x47, 0x72, 0x6f, 0x6b, 0x58, 0x41, 0x49, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, + 0x48, 0x00, 0x52, 0x07, 0x67, 0x72, 0x6f, 0x6b, 0x78, 0x61, 0x69, 0x1a, 0x96, 0x01, 0x0a, 0x0c, + 0x4f, 0x70, 0x65, 0x6e, 0x41, 0x49, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x14, 0x0a, 0x05, + 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6d, 0x6f, 0x64, + 0x65, 0x6c, 0x12, 0x1f, 0x0a, 0x0b, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x70, 0x72, 0x6f, 0x6d, 0x70, + 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x75, 0x73, 0x65, 0x72, 0x50, 0x72, 0x6f, + 0x6d, 0x70, 0x74, 0x12, 0x20, 0x0a, 0x0b, 0x74, 0x65, 0x6d, 0x70, 0x65, 0x72, 0x61, 0x74, 0x75, + 0x72, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x01, 0x52, 0x0b, 0x74, 0x65, 0x6d, 0x70, 0x65, 0x72, + 0x61, 0x74, 0x75, 0x72, 0x65, 0x12, 0x2d, 0x0a, 0x13, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x5f, + 0x6e, 0x61, 0x6d, 0x65, 0x5f, 0x61, 0x70, 0x69, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x10, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x41, 0x70, + 0x69, 0x4b, 0x65, 0x79, 0x1a, 0x94, 0x01, 0x0a, 0x0a, 0x47, 0x72, 0x6f, 0x71, 0x43, 0x6f, 0x6e, + 0x66, 0x69, 0x67, 0x12, 0x14, 0x0a, 0x05, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x05, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x12, 0x1f, 0x0a, 0x0b, 0x75, 0x73, 0x65, + 0x72, 0x5f, 0x70, 0x72, 0x6f, 0x6d, 0x70, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, + 0x75, 0x73, 0x65, 0x72, 0x50, 0x72, 0x6f, 0x6d, 0x70, 0x74, 0x12, 0x20, 0x0a, 0x0b, 0x74, 0x65, + 0x6d, 0x70, 0x65, 0x72, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x01, 0x52, + 0x0b, 0x74, 0x65, 0x6d, 0x70, 0x65, 0x72, 0x61, 0x74, 0x75, 0x72, 0x65, 0x12, 0x2d, 0x0a, 0x13, + 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x5f, 0x61, 0x70, 0x69, 0x5f, + 0x6b, 0x65, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x73, 0x65, 0x63, 0x72, 0x65, + 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x41, 0x70, 0x69, 0x4b, 0x65, 0x79, 0x1a, 0x97, 0x01, 0x0a, 0x0d, + 0x47, 0x72, 0x6f, 0x6b, 0x58, 0x41, 0x49, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x14, 0x0a, + 0x05, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6d, 0x6f, + 0x64, 0x65, 0x6c, 0x12, 0x1f, 0x0a, 0x0b, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x70, 0x72, 0x6f, 0x6d, + 0x70, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x75, 0x73, 0x65, 0x72, 0x50, 0x72, + 0x6f, 0x6d, 0x70, 0x74, 0x12, 0x20, 0x0a, 0x0b, 0x74, 0x65, 0x6d, 0x70, 0x65, 0x72, 0x61, 0x74, + 0x75, 0x72, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x01, 0x52, 0x0b, 0x74, 0x65, 0x6d, 0x70, 0x65, + 0x72, 0x61, 0x74, 0x75, 0x72, 0x65, 0x12, 0x2d, 0x0a, 0x13, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, + 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x5f, 0x61, 0x70, 0x69, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x04, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x10, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x41, + 0x70, 0x69, 0x4b, 0x65, 0x79, 0x42, 0x11, 0x0a, 0x0f, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, + 0x72, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x1a, 0x11, 0x0a, 0x0f, 0x53, 0x6f, 0x6c, 0x61, + 0x79, 0x65, 0x72, 0x53, 0x75, 0x73, 0x64, 0x54, 0x61, 0x73, 0x6b, 0x1a, 0xd5, 0x01, 0x0a, 0x10, + 0x43, 0x75, 0x72, 0x76, 0x65, 0x46, 0x69, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x54, 0x61, 0x73, 0x6b, + 0x12, 0x42, 0x0a, 0x05, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, + 0x2c, 0x2e, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x5f, 0x6a, 0x6f, 0x62, 0x2e, 0x4f, 0x72, 0x61, + 0x63, 0x6c, 0x65, 0x4a, 0x6f, 0x62, 0x2e, 0x43, 0x75, 0x72, 0x76, 0x65, 0x46, 0x69, 0x6e, 0x61, + 0x6e, 0x63, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x2e, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x52, 0x05, 0x63, + 0x68, 0x61, 0x69, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, + 0x12, 0x21, 0x0a, 0x0c, 0x70, 0x6f, 0x6f, 0x6c, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x70, 0x6f, 0x6f, 0x6c, 0x41, 0x64, 0x64, 0x72, + 0x65, 0x73, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x6f, 0x75, 0x74, 0x5f, 0x64, 0x65, 0x63, 0x69, 0x6d, + 0x61, 0x6c, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0b, 0x6f, 0x75, 0x74, 0x44, 0x65, + 0x63, 0x69, 0x6d, 0x61, 0x6c, 0x73, 0x22, 0x1b, 0x0a, 0x05, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x12, + 0x12, 0x0a, 0x0e, 0x43, 0x48, 0x41, 0x49, 0x4e, 0x5f, 0x45, 0x54, 0x48, 0x45, 0x52, 0x45, 0x55, + 0x4d, 0x10, 0x00, 0x1a, 0x38, 0x0a, 0x1a, 0x54, 0x75, 0x72, 0x62, 0x6f, 0x45, 0x74, 0x68, 0x52, + 0x65, 0x64, 0x65, 0x6d, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x61, 0x74, 0x65, 0x54, 0x61, 0x73, + 0x6b, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x1a, 0x84, 0x01, + 0x0a, 0x0b, 0x42, 0x69, 0x74, 0x46, 0x6c, 0x75, 0x78, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x1a, 0x0a, + 0x08, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x08, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x12, 0x21, 0x0a, 0x0c, 0x70, 0x6f, 0x6f, + 0x6c, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0b, 0x70, 0x6f, 0x6f, 0x6c, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x19, 0x0a, 0x08, + 0x69, 0x6e, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, + 0x69, 0x6e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x1b, 0x0a, 0x09, 0x6f, 0x75, 0x74, 0x5f, 0x74, + 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6f, 0x75, 0x74, 0x54, + 0x6f, 0x6b, 0x65, 0x6e, 0x1a, 0x80, 0x01, 0x0a, 0x0e, 0x46, 0x72, 0x61, 0x67, 0x6d, 0x65, 0x74, + 0x72, 0x69, 0x63, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x40, 0x0a, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2a, 0x2e, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x5f, + 0x6a, 0x6f, 0x62, 0x2e, 0x4f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x4a, 0x6f, 0x62, 0x2e, 0x46, 0x72, + 0x61, 0x67, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x54, 0x61, 0x73, 0x6b, 0x2e, 0x54, 0x6f, 0x6b, + 0x65, 0x6e, 0x52, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x2c, 0x0a, 0x05, 0x54, 0x6f, 0x6b, + 0x65, 0x6e, 0x12, 0x12, 0x0a, 0x0e, 0x54, 0x4f, 0x4b, 0x45, 0x4e, 0x5f, 0x46, 0x52, 0x41, 0x47, + 0x5f, 0x53, 0x4f, 0x4c, 0x10, 0x00, 0x12, 0x0f, 0x0a, 0x0b, 0x54, 0x4f, 0x4b, 0x45, 0x4e, 0x5f, + 0x4e, 0x5f, 0x53, 0x4f, 0x4c, 0x10, 0x01, 0x1a, 0xb0, 0x01, 0x0a, 0x0d, 0x45, 0x74, 0x68, 0x65, + 0x72, 0x66, 0x75, 0x73, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x3f, 0x0a, 0x05, 0x74, 0x6f, 0x6b, + 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x29, 0x2e, 0x6f, 0x72, 0x61, 0x63, 0x6c, + 0x65, 0x5f, 0x6a, 0x6f, 0x62, 0x2e, 0x4f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x4a, 0x6f, 0x62, 0x2e, + 0x45, 0x74, 0x68, 0x65, 0x72, 0x66, 0x75, 0x73, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x2e, 0x54, 0x6f, + 0x6b, 0x65, 0x6e, 0x52, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x5e, 0x0a, 0x05, 0x54, 0x6f, + 0x6b, 0x65, 0x6e, 0x12, 0x0f, 0x0a, 0x0b, 0x54, 0x4f, 0x4b, 0x45, 0x4e, 0x5f, 0x43, 0x45, 0x54, + 0x45, 0x53, 0x10, 0x00, 0x12, 0x0f, 0x0a, 0x0b, 0x54, 0x4f, 0x4b, 0x45, 0x4e, 0x5f, 0x55, 0x53, + 0x54, 0x52, 0x59, 0x10, 0x01, 0x12, 0x0f, 0x0a, 0x0b, 0x54, 0x4f, 0x4b, 0x45, 0x4e, 0x5f, 0x45, + 0x55, 0x52, 0x4f, 0x42, 0x10, 0x02, 0x12, 0x11, 0x0a, 0x0d, 0x54, 0x4f, 0x4b, 0x45, 0x4e, 0x5f, + 0x54, 0x45, 0x53, 0x4f, 0x55, 0x52, 0x4f, 0x10, 0x03, 0x12, 0x0f, 0x0a, 0x0b, 0x54, 0x4f, 0x4b, + 0x45, 0x4e, 0x5f, 0x47, 0x49, 0x4c, 0x54, 0x53, 0x10, 0x04, 0x1a, 0xfe, 0x01, 0x0a, 0x16, 0x4c, + 0x73, 0x74, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x69, 0x63, 0x61, 0x6c, 0x59, 0x69, 0x65, 0x6c, + 0x64, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x19, 0x0a, 0x08, 0x6c, 0x73, 0x74, 0x5f, 0x6d, 0x69, 0x6e, + 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6c, 0x73, 0x74, 0x4d, 0x69, 0x6e, 0x74, + 0x12, 0x54, 0x0a, 0x09, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x0e, 0x32, 0x36, 0x2e, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x5f, 0x6a, 0x6f, 0x62, + 0x2e, 0x4f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x4a, 0x6f, 0x62, 0x2e, 0x4c, 0x73, 0x74, 0x48, 0x69, + 0x73, 0x74, 0x6f, 0x72, 0x69, 0x63, 0x61, 0x6c, 0x59, 0x69, 0x65, 0x6c, 0x64, 0x54, 0x61, 0x73, + 0x6b, 0x2e, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x09, 0x6f, 0x70, 0x65, + 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x16, 0x0a, 0x06, 0x65, 0x70, 0x6f, 0x63, 0x68, 0x73, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x65, 0x70, 0x6f, 0x63, 0x68, 0x73, 0x22, 0x5b, + 0x0a, 0x09, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x14, 0x0a, 0x10, 0x4f, + 0x50, 0x45, 0x52, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x4d, 0x45, 0x44, 0x49, 0x41, 0x4e, 0x10, + 0x00, 0x12, 0x12, 0x0a, 0x0e, 0x4f, 0x50, 0x45, 0x52, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x4d, + 0x45, 0x41, 0x4e, 0x10, 0x01, 0x12, 0x11, 0x0a, 0x0d, 0x4f, 0x50, 0x45, 0x52, 0x41, 0x54, 0x49, + 0x4f, 0x4e, 0x5f, 0x4d, 0x49, 0x4e, 0x10, 0x02, 0x12, 0x11, 0x0a, 0x0d, 0x4f, 0x50, 0x45, 0x52, + 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x4d, 0x41, 0x58, 0x10, 0x03, 0x1a, 0x8d, 0x01, 0x0a, 0x0b, + 0x50, 0x75, 0x6d, 0x70, 0x41, 0x6d, 0x6d, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x21, 0x0a, 0x0c, 0x70, + 0x6f, 0x6f, 0x6c, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x0b, 0x70, 0x6f, 0x6f, 0x6c, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x1b, + 0x0a, 0x09, 0x69, 0x6e, 0x5f, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x01, 0x52, 0x08, 0x69, 0x6e, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x6d, + 0x61, 0x78, 0x5f, 0x73, 0x6c, 0x69, 0x70, 0x70, 0x61, 0x67, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x01, 0x52, 0x0b, 0x6d, 0x61, 0x78, 0x53, 0x6c, 0x69, 0x70, 0x70, 0x61, 0x67, 0x65, 0x12, 0x1b, + 0x0a, 0x0a, 0x69, 0x73, 0x5f, 0x78, 0x5f, 0x66, 0x6f, 0x72, 0x5f, 0x79, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x08, 0x52, 0x07, 0x69, 0x73, 0x58, 0x46, 0x6f, 0x72, 0x59, 0x1a, 0xaa, 0x01, 0x0a, 0x17, + 0x50, 0x75, 0x6d, 0x70, 0x41, 0x6d, 0x6d, 0x4c, 0x70, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x50, 0x72, + 0x69, 0x63, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x21, 0x0a, 0x0c, 0x70, 0x6f, 0x6f, 0x6c, 0x5f, + 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x70, + 0x6f, 0x6f, 0x6c, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x35, 0x0a, 0x0b, 0x78, 0x5f, + 0x70, 0x72, 0x69, 0x63, 0x65, 0x5f, 0x6a, 0x6f, 0x62, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x15, 0x2e, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x5f, 0x6a, 0x6f, 0x62, 0x2e, 0x4f, 0x72, 0x61, + 0x63, 0x6c, 0x65, 0x4a, 0x6f, 0x62, 0x52, 0x09, 0x78, 0x50, 0x72, 0x69, 0x63, 0x65, 0x4a, 0x6f, + 0x62, 0x12, 0x35, 0x0a, 0x0b, 0x79, 0x5f, 0x70, 0x72, 0x69, 0x63, 0x65, 0x5f, 0x6a, 0x6f, 0x62, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x5f, + 0x6a, 0x6f, 0x62, 0x2e, 0x4f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x4a, 0x6f, 0x62, 0x52, 0x09, 0x79, + 0x50, 0x72, 0x69, 0x63, 0x65, 0x4a, 0x6f, 0x62, 0x1a, 0x24, 0x0a, 0x0c, 0x45, 0x78, 0x70, 0x6f, + 0x6e, 0x65, 0x6e, 0x74, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x75, 0x6c, + 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x75, 0x6c, 0x74, 0x1a, 0x54, + 0x0a, 0x1b, 0x45, 0x78, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x50, 0x54, 0x4c, 0x69, 0x6e, 0x65, + 0x61, 0x72, 0x50, 0x72, 0x69, 0x63, 0x69, 0x6e, 0x67, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x14, 0x0a, + 0x05, 0x76, 0x61, 0x75, 0x6c, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, + 0x75, 0x6c, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x70, 0x72, 0x69, + 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x01, 0x52, 0x0a, 0x73, 0x74, 0x61, 0x72, 0x74, 0x50, + 0x72, 0x69, 0x63, 0x65, 0x1a, 0xd2, 0x01, 0x0a, 0x1c, 0x53, 0x6f, 0x6c, 0x61, 0x6e, 0x61, 0x54, + 0x6f, 0x6b, 0x65, 0x6e, 0x32, 0x30, 0x32, 0x32, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, + 0x6e, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x12, 0x0a, 0x04, 0x6d, 0x69, 0x6e, 0x74, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x04, 0x6d, 0x69, 0x6e, 0x74, 0x12, 0x63, 0x0a, 0x09, 0x65, 0x78, 0x74, + 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x45, 0x2e, 0x6f, + 0x72, 0x61, 0x63, 0x6c, 0x65, 0x5f, 0x6a, 0x6f, 0x62, 0x2e, 0x4f, 0x72, 0x61, 0x63, 0x6c, 0x65, + 0x4a, 0x6f, 0x62, 0x2e, 0x53, 0x6f, 0x6c, 0x61, 0x6e, 0x61, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x32, + 0x30, 0x32, 0x32, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x54, 0x61, 0x73, 0x6b, + 0x2e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x32, 0x30, 0x32, 0x32, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, + 0x69, 0x6f, 0x6e, 0x52, 0x09, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x39, + 0x0a, 0x12, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x32, 0x30, 0x32, 0x32, 0x45, 0x78, 0x74, 0x65, 0x6e, + 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x23, 0x0a, 0x1f, 0x54, 0x4f, 0x4b, 0x45, 0x4e, 0x5f, 0x32, 0x30, + 0x32, 0x32, 0x5f, 0x53, 0x43, 0x41, 0x4c, 0x45, 0x44, 0x5f, 0x41, 0x4d, 0x4f, 0x55, 0x4e, 0x54, + 0x5f, 0x46, 0x41, 0x43, 0x54, 0x4f, 0x52, 0x10, 0x00, 0x1a, 0xc0, 0x01, 0x0a, 0x14, 0x53, 0x77, + 0x69, 0x74, 0x63, 0x68, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x53, 0x75, 0x72, 0x67, 0x65, 0x54, 0x61, + 0x73, 0x6b, 0x12, 0x49, 0x0a, 0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0e, 0x32, 0x31, 0x2e, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x5f, 0x6a, 0x6f, 0x62, 0x2e, + 0x4f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x4a, 0x6f, 0x62, 0x2e, 0x53, 0x77, 0x69, 0x74, 0x63, 0x68, + 0x62, 0x6f, 0x61, 0x72, 0x64, 0x53, 0x75, 0x72, 0x67, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x2e, 0x53, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x16, 0x0a, + 0x06, 0x73, 0x79, 0x6d, 0x62, 0x6f, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, + 0x79, 0x6d, 0x62, 0x6f, 0x6c, 0x22, 0x45, 0x0a, 0x06, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, + 0x0c, 0x0a, 0x08, 0x57, 0x45, 0x49, 0x47, 0x48, 0x54, 0x45, 0x44, 0x10, 0x00, 0x12, 0x0b, 0x0a, + 0x07, 0x42, 0x49, 0x4e, 0x41, 0x4e, 0x43, 0x45, 0x10, 0x01, 0x12, 0x07, 0x0a, 0x03, 0x4f, 0x4b, + 0x58, 0x10, 0x02, 0x12, 0x09, 0x0a, 0x05, 0x42, 0x59, 0x42, 0x49, 0x54, 0x10, 0x03, 0x12, 0x0c, + 0x0a, 0x08, 0x43, 0x4f, 0x49, 0x4e, 0x42, 0x41, 0x53, 0x45, 0x10, 0x04, 0x1a, 0xbb, 0x2b, 0x0a, + 0x04, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x3d, 0x0a, 0x09, 0x68, 0x74, 0x74, 0x70, 0x5f, 0x74, 0x61, + 0x73, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x6f, 0x72, 0x61, 0x63, 0x6c, + 0x65, 0x5f, 0x6a, 0x6f, 0x62, 0x2e, 0x4f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x4a, 0x6f, 0x62, 0x2e, + 0x48, 0x74, 0x74, 0x70, 0x54, 0x61, 0x73, 0x6b, 0x48, 0x00, 0x52, 0x08, 0x68, 0x74, 0x74, 0x70, + 0x54, 0x61, 0x73, 0x6b, 0x12, 0x4d, 0x0a, 0x0f, 0x6a, 0x73, 0x6f, 0x6e, 0x5f, 0x70, 0x61, 0x72, + 0x73, 0x65, 0x5f, 0x74, 0x61, 0x73, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, + 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x5f, 0x6a, 0x6f, 0x62, 0x2e, 0x4f, 0x72, 0x61, 0x63, 0x6c, + 0x65, 0x4a, 0x6f, 0x62, 0x2e, 0x4a, 0x73, 0x6f, 0x6e, 0x50, 0x61, 0x72, 0x73, 0x65, 0x54, 0x61, + 0x73, 0x6b, 0x48, 0x00, 0x52, 0x0d, 0x6a, 0x73, 0x6f, 0x6e, 0x50, 0x61, 0x72, 0x73, 0x65, 0x54, + 0x61, 0x73, 0x6b, 0x12, 0x43, 0x0a, 0x0b, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x6e, 0x5f, 0x74, 0x61, + 0x73, 0x6b, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x6f, 0x72, 0x61, 0x63, 0x6c, + 0x65, 0x5f, 0x6a, 0x6f, 0x62, 0x2e, 0x4f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x4a, 0x6f, 0x62, 0x2e, + 0x4d, 0x65, 0x64, 0x69, 0x61, 0x6e, 0x54, 0x61, 0x73, 0x6b, 0x48, 0x00, 0x52, 0x0a, 0x6d, 0x65, + 0x64, 0x69, 0x61, 0x6e, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x3d, 0x0a, 0x09, 0x6d, 0x65, 0x61, 0x6e, + 0x5f, 0x74, 0x61, 0x73, 0x6b, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x6f, 0x72, + 0x61, 0x63, 0x6c, 0x65, 0x5f, 0x6a, 0x6f, 0x62, 0x2e, 0x4f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x4a, + 0x6f, 0x62, 0x2e, 0x4d, 0x65, 0x61, 0x6e, 0x54, 0x61, 0x73, 0x6b, 0x48, 0x00, 0x52, 0x08, 0x6d, + 0x65, 0x61, 0x6e, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x4c, 0x0a, 0x0e, 0x77, 0x65, 0x62, 0x73, 0x6f, + 0x63, 0x6b, 0x65, 0x74, 0x5f, 0x74, 0x61, 0x73, 0x6b, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x23, 0x2e, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x5f, 0x6a, 0x6f, 0x62, 0x2e, 0x4f, 0x72, 0x61, + 0x63, 0x6c, 0x65, 0x4a, 0x6f, 0x62, 0x2e, 0x57, 0x65, 0x62, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, + 0x54, 0x61, 0x73, 0x6b, 0x48, 0x00, 0x52, 0x0d, 0x77, 0x65, 0x62, 0x73, 0x6f, 0x63, 0x6b, 0x65, + 0x74, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x43, 0x0a, 0x0b, 0x64, 0x69, 0x76, 0x69, 0x64, 0x65, 0x5f, + 0x74, 0x61, 0x73, 0x6b, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x6f, 0x72, 0x61, + 0x63, 0x6c, 0x65, 0x5f, 0x6a, 0x6f, 0x62, 0x2e, 0x4f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x4a, 0x6f, + 0x62, 0x2e, 0x44, 0x69, 0x76, 0x69, 0x64, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x48, 0x00, 0x52, 0x0a, + 0x64, 0x69, 0x76, 0x69, 0x64, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x49, 0x0a, 0x0d, 0x6d, 0x75, + 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x79, 0x5f, 0x74, 0x61, 0x73, 0x6b, 0x18, 0x08, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x22, 0x2e, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x5f, 0x6a, 0x6f, 0x62, 0x2e, 0x4f, + 0x72, 0x61, 0x63, 0x6c, 0x65, 0x4a, 0x6f, 0x62, 0x2e, 0x4d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, + 0x79, 0x54, 0x61, 0x73, 0x6b, 0x48, 0x00, 0x52, 0x0c, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, + 0x79, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x57, 0x0a, 0x13, 0x6c, 0x70, 0x5f, 0x74, 0x6f, 0x6b, 0x65, + 0x6e, 0x5f, 0x70, 0x72, 0x69, 0x63, 0x65, 0x5f, 0x74, 0x61, 0x73, 0x6b, 0x18, 0x09, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x5f, 0x6a, 0x6f, 0x62, 0x2e, + 0x4f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x4a, 0x6f, 0x62, 0x2e, 0x4c, 0x70, 0x54, 0x6f, 0x6b, 0x65, + 0x6e, 0x50, 0x72, 0x69, 0x63, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x48, 0x00, 0x52, 0x10, 0x6c, 0x70, + 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x50, 0x72, 0x69, 0x63, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x5d, + 0x0a, 0x15, 0x6c, 0x70, 0x5f, 0x65, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x5f, 0x72, 0x61, + 0x74, 0x65, 0x5f, 0x74, 0x61, 0x73, 0x6b, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, + 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x5f, 0x6a, 0x6f, 0x62, 0x2e, 0x4f, 0x72, 0x61, 0x63, 0x6c, + 0x65, 0x4a, 0x6f, 0x62, 0x2e, 0x4c, 0x70, 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x52, + 0x61, 0x74, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x48, 0x00, 0x52, 0x12, 0x6c, 0x70, 0x45, 0x78, 0x63, + 0x68, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x61, 0x74, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x52, 0x0a, + 0x10, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x5f, 0x74, 0x61, 0x73, + 0x6b, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, + 0x5f, 0x6a, 0x6f, 0x62, 0x2e, 0x4f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x4a, 0x6f, 0x62, 0x2e, 0x43, + 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x54, 0x61, 0x73, 0x6b, 0x48, 0x00, + 0x52, 0x0f, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x54, 0x61, 0x73, + 0x6b, 0x12, 0x40, 0x0a, 0x0a, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x5f, 0x74, 0x61, 0x73, 0x6b, 0x18, + 0x0c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x5f, 0x6a, + 0x6f, 0x62, 0x2e, 0x4f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x4a, 0x6f, 0x62, 0x2e, 0x56, 0x61, 0x6c, + 0x75, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x48, 0x00, 0x52, 0x09, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x54, + 0x61, 0x73, 0x6b, 0x12, 0x3a, 0x0a, 0x08, 0x6d, 0x61, 0x78, 0x5f, 0x74, 0x61, 0x73, 0x6b, 0x18, + 0x0d, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x5f, 0x6a, + 0x6f, 0x62, 0x2e, 0x4f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x4a, 0x6f, 0x62, 0x2e, 0x4d, 0x61, 0x78, + 0x54, 0x61, 0x73, 0x6b, 0x48, 0x00, 0x52, 0x07, 0x6d, 0x61, 0x78, 0x54, 0x61, 0x73, 0x6b, 0x12, + 0x56, 0x0a, 0x12, 0x72, 0x65, 0x67, 0x65, 0x78, 0x5f, 0x65, 0x78, 0x74, 0x72, 0x61, 0x63, 0x74, + 0x5f, 0x74, 0x61, 0x73, 0x6b, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x6f, 0x72, + 0x61, 0x63, 0x6c, 0x65, 0x5f, 0x6a, 0x6f, 0x62, 0x2e, 0x4f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x4a, + 0x6f, 0x62, 0x2e, 0x52, 0x65, 0x67, 0x65, 0x78, 0x45, 0x78, 0x74, 0x72, 0x61, 0x63, 0x74, 0x54, + 0x61, 0x73, 0x6b, 0x48, 0x00, 0x52, 0x10, 0x72, 0x65, 0x67, 0x65, 0x78, 0x45, 0x78, 0x74, 0x72, + 0x61, 0x63, 0x74, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x50, 0x0a, 0x10, 0x78, 0x73, 0x74, 0x65, 0x70, + 0x5f, 0x70, 0x72, 0x69, 0x63, 0x65, 0x5f, 0x74, 0x61, 0x73, 0x6b, 0x18, 0x0f, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x24, 0x2e, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x5f, 0x6a, 0x6f, 0x62, 0x2e, 0x4f, + 0x72, 0x61, 0x63, 0x6c, 0x65, 0x4a, 0x6f, 0x62, 0x2e, 0x58, 0x53, 0x74, 0x65, 0x70, 0x50, 0x72, + 0x69, 0x63, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x48, 0x00, 0x52, 0x0e, 0x78, 0x73, 0x74, 0x65, 0x70, + 0x50, 0x72, 0x69, 0x63, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x3a, 0x0a, 0x08, 0x61, 0x64, 0x64, + 0x5f, 0x74, 0x61, 0x73, 0x6b, 0x18, 0x10, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x6f, 0x72, + 0x61, 0x63, 0x6c, 0x65, 0x5f, 0x6a, 0x6f, 0x62, 0x2e, 0x4f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x4a, + 0x6f, 0x62, 0x2e, 0x41, 0x64, 0x64, 0x54, 0x61, 0x73, 0x6b, 0x48, 0x00, 0x52, 0x07, 0x61, 0x64, + 0x64, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x49, 0x0a, 0x0d, 0x73, 0x75, 0x62, 0x74, 0x72, 0x61, 0x63, + 0x74, 0x5f, 0x74, 0x61, 0x73, 0x6b, 0x18, 0x11, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x6f, + 0x72, 0x61, 0x63, 0x6c, 0x65, 0x5f, 0x6a, 0x6f, 0x62, 0x2e, 0x4f, 0x72, 0x61, 0x63, 0x6c, 0x65, + 0x4a, 0x6f, 0x62, 0x2e, 0x53, 0x75, 0x62, 0x74, 0x72, 0x61, 0x63, 0x74, 0x54, 0x61, 0x73, 0x6b, + 0x48, 0x00, 0x52, 0x0c, 0x73, 0x75, 0x62, 0x74, 0x72, 0x61, 0x63, 0x74, 0x54, 0x61, 0x73, 0x6b, + 0x12, 0x3d, 0x0a, 0x09, 0x74, 0x77, 0x61, 0x70, 0x5f, 0x74, 0x61, 0x73, 0x6b, 0x18, 0x12, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x5f, 0x6a, 0x6f, 0x62, + 0x2e, 0x4f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x4a, 0x6f, 0x62, 0x2e, 0x54, 0x77, 0x61, 0x70, 0x54, + 0x61, 0x73, 0x6b, 0x48, 0x00, 0x52, 0x08, 0x74, 0x77, 0x61, 0x70, 0x54, 0x61, 0x73, 0x6b, 0x12, + 0x4d, 0x0a, 0x0f, 0x73, 0x65, 0x72, 0x75, 0x6d, 0x5f, 0x73, 0x77, 0x61, 0x70, 0x5f, 0x74, 0x61, + 0x73, 0x6b, 0x18, 0x13, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x6f, 0x72, 0x61, 0x63, 0x6c, + 0x65, 0x5f, 0x6a, 0x6f, 0x62, 0x2e, 0x4f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x4a, 0x6f, 0x62, 0x2e, + 0x53, 0x65, 0x72, 0x75, 0x6d, 0x53, 0x77, 0x61, 0x70, 0x54, 0x61, 0x73, 0x6b, 0x48, 0x00, 0x52, + 0x0d, 0x73, 0x65, 0x72, 0x75, 0x6d, 0x53, 0x77, 0x61, 0x70, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x3a, + 0x0a, 0x08, 0x70, 0x6f, 0x77, 0x5f, 0x74, 0x61, 0x73, 0x6b, 0x18, 0x14, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x1d, 0x2e, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x5f, 0x6a, 0x6f, 0x62, 0x2e, 0x4f, 0x72, + 0x61, 0x63, 0x6c, 0x65, 0x4a, 0x6f, 0x62, 0x2e, 0x50, 0x6f, 0x77, 0x54, 0x61, 0x73, 0x6b, 0x48, + 0x00, 0x52, 0x07, 0x70, 0x6f, 0x77, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x53, 0x0a, 0x11, 0x6c, 0x65, + 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x72, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x61, 0x73, 0x6b, 0x18, + 0x15, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x5f, 0x6a, + 0x6f, 0x62, 0x2e, 0x4f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x4a, 0x6f, 0x62, 0x2e, 0x4c, 0x65, 0x6e, + 0x64, 0x69, 0x6e, 0x67, 0x52, 0x61, 0x74, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x48, 0x00, 0x52, 0x0f, + 0x6c, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x52, 0x61, 0x74, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x12, + 0x60, 0x0a, 0x16, 0x6d, 0x61, 0x6e, 0x67, 0x6f, 0x5f, 0x70, 0x65, 0x72, 0x70, 0x5f, 0x6d, 0x61, + 0x72, 0x6b, 0x65, 0x74, 0x5f, 0x74, 0x61, 0x73, 0x6b, 0x18, 0x16, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x29, 0x2e, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x5f, 0x6a, 0x6f, 0x62, 0x2e, 0x4f, 0x72, 0x61, + 0x63, 0x6c, 0x65, 0x4a, 0x6f, 0x62, 0x2e, 0x4d, 0x61, 0x6e, 0x67, 0x6f, 0x50, 0x65, 0x72, 0x70, + 0x4d, 0x61, 0x72, 0x6b, 0x65, 0x74, 0x54, 0x61, 0x73, 0x6b, 0x48, 0x00, 0x52, 0x13, 0x6d, 0x61, + 0x6e, 0x67, 0x6f, 0x50, 0x65, 0x72, 0x70, 0x4d, 0x61, 0x72, 0x6b, 0x65, 0x74, 0x54, 0x61, 0x73, + 0x6b, 0x12, 0x53, 0x0a, 0x11, 0x6a, 0x75, 0x70, 0x69, 0x74, 0x65, 0x72, 0x5f, 0x73, 0x77, 0x61, + 0x70, 0x5f, 0x74, 0x61, 0x73, 0x6b, 0x18, 0x17, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x6f, + 0x72, 0x61, 0x63, 0x6c, 0x65, 0x5f, 0x6a, 0x6f, 0x62, 0x2e, 0x4f, 0x72, 0x61, 0x63, 0x6c, 0x65, + 0x4a, 0x6f, 0x62, 0x2e, 0x4a, 0x75, 0x70, 0x69, 0x74, 0x65, 0x72, 0x53, 0x77, 0x61, 0x70, 0x54, + 0x61, 0x73, 0x6b, 0x48, 0x00, 0x52, 0x0f, 0x6a, 0x75, 0x70, 0x69, 0x74, 0x65, 0x72, 0x53, 0x77, + 0x61, 0x70, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x50, 0x0a, 0x10, 0x70, 0x65, 0x72, 0x70, 0x5f, 0x6d, + 0x61, 0x72, 0x6b, 0x65, 0x74, 0x5f, 0x74, 0x61, 0x73, 0x6b, 0x18, 0x18, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x24, 0x2e, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x5f, 0x6a, 0x6f, 0x62, 0x2e, 0x4f, 0x72, + 0x61, 0x63, 0x6c, 0x65, 0x4a, 0x6f, 0x62, 0x2e, 0x50, 0x65, 0x72, 0x70, 0x4d, 0x61, 0x72, 0x6b, + 0x65, 0x74, 0x54, 0x61, 0x73, 0x6b, 0x48, 0x00, 0x52, 0x0e, 0x70, 0x65, 0x72, 0x70, 0x4d, 0x61, + 0x72, 0x6b, 0x65, 0x74, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x43, 0x0a, 0x0b, 0x6f, 0x72, 0x61, 0x63, + 0x6c, 0x65, 0x5f, 0x74, 0x61, 0x73, 0x6b, 0x18, 0x19, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, + 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x5f, 0x6a, 0x6f, 0x62, 0x2e, 0x4f, 0x72, 0x61, 0x63, 0x6c, + 0x65, 0x4a, 0x6f, 0x62, 0x2e, 0x4f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x48, + 0x00, 0x52, 0x0a, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x53, 0x0a, + 0x11, 0x61, 0x6e, 0x63, 0x68, 0x6f, 0x72, 0x5f, 0x66, 0x65, 0x74, 0x63, 0x68, 0x5f, 0x74, 0x61, + 0x73, 0x6b, 0x18, 0x1a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x6f, 0x72, 0x61, 0x63, 0x6c, + 0x65, 0x5f, 0x6a, 0x6f, 0x62, 0x2e, 0x4f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x4a, 0x6f, 0x62, 0x2e, + 0x41, 0x6e, 0x63, 0x68, 0x6f, 0x72, 0x46, 0x65, 0x74, 0x63, 0x68, 0x54, 0x61, 0x73, 0x6b, 0x48, + 0x00, 0x52, 0x0f, 0x61, 0x6e, 0x63, 0x68, 0x6f, 0x72, 0x46, 0x65, 0x74, 0x63, 0x68, 0x54, 0x61, + 0x73, 0x6b, 0x12, 0x57, 0x0a, 0x13, 0x73, 0x70, 0x6c, 0x5f, 0x73, 0x74, 0x61, 0x6b, 0x65, 0x5f, + 0x70, 0x6f, 0x6f, 0x6c, 0x5f, 0x74, 0x61, 0x73, 0x6b, 0x18, 0x1d, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x26, 0x2e, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x5f, 0x6a, 0x6f, 0x62, 0x2e, 0x4f, 0x72, 0x61, + 0x63, 0x6c, 0x65, 0x4a, 0x6f, 0x62, 0x2e, 0x53, 0x70, 0x6c, 0x53, 0x74, 0x61, 0x6b, 0x65, 0x50, + 0x6f, 0x6f, 0x6c, 0x54, 0x61, 0x73, 0x6b, 0x48, 0x00, 0x52, 0x10, 0x73, 0x70, 0x6c, 0x53, 0x74, + 0x61, 0x6b, 0x65, 0x50, 0x6f, 0x6f, 0x6c, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x5a, 0x0a, 0x14, 0x73, + 0x70, 0x6c, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x5f, 0x70, 0x61, 0x72, 0x73, 0x65, 0x5f, 0x74, + 0x61, 0x73, 0x6b, 0x18, 0x1e, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x6f, 0x72, 0x61, 0x63, + 0x6c, 0x65, 0x5f, 0x6a, 0x6f, 0x62, 0x2e, 0x4f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x4a, 0x6f, 0x62, + 0x2e, 0x53, 0x70, 0x6c, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x50, 0x61, 0x72, 0x73, 0x65, 0x54, 0x61, + 0x73, 0x6b, 0x48, 0x00, 0x52, 0x11, 0x73, 0x70, 0x6c, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x50, 0x61, + 0x72, 0x73, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x6c, 0x0a, 0x1a, 0x75, 0x6e, 0x69, 0x73, 0x77, + 0x61, 0x70, 0x5f, 0x65, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x5f, 0x72, 0x61, 0x74, 0x65, + 0x5f, 0x74, 0x61, 0x73, 0x6b, 0x18, 0x1f, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x6f, 0x72, + 0x61, 0x63, 0x6c, 0x65, 0x5f, 0x6a, 0x6f, 0x62, 0x2e, 0x4f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x4a, + 0x6f, 0x62, 0x2e, 0x55, 0x6e, 0x69, 0x73, 0x77, 0x61, 0x70, 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, + 0x67, 0x65, 0x52, 0x61, 0x74, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x48, 0x00, 0x52, 0x17, 0x75, 0x6e, + 0x69, 0x73, 0x77, 0x61, 0x70, 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x61, 0x74, + 0x65, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x72, 0x0a, 0x1c, 0x73, 0x75, 0x73, 0x68, 0x69, 0x73, 0x77, + 0x61, 0x70, 0x5f, 0x65, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x5f, 0x72, 0x61, 0x74, 0x65, + 0x5f, 0x74, 0x61, 0x73, 0x6b, 0x18, 0x20, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x6f, 0x72, + 0x61, 0x63, 0x6c, 0x65, 0x5f, 0x6a, 0x6f, 0x62, 0x2e, 0x4f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x4a, + 0x6f, 0x62, 0x2e, 0x53, 0x75, 0x73, 0x68, 0x69, 0x73, 0x77, 0x61, 0x70, 0x45, 0x78, 0x63, 0x68, + 0x61, 0x6e, 0x67, 0x65, 0x52, 0x61, 0x74, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x48, 0x00, 0x52, 0x19, + 0x73, 0x75, 0x73, 0x68, 0x69, 0x73, 0x77, 0x61, 0x70, 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, + 0x65, 0x52, 0x61, 0x74, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x78, 0x0a, 0x1e, 0x70, 0x61, 0x6e, + 0x63, 0x61, 0x6b, 0x65, 0x73, 0x77, 0x61, 0x70, 0x5f, 0x65, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, + 0x65, 0x5f, 0x72, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x61, 0x73, 0x6b, 0x18, 0x21, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x31, 0x2e, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x5f, 0x6a, 0x6f, 0x62, 0x2e, 0x4f, + 0x72, 0x61, 0x63, 0x6c, 0x65, 0x4a, 0x6f, 0x62, 0x2e, 0x50, 0x61, 0x6e, 0x63, 0x61, 0x6b, 0x65, + 0x73, 0x77, 0x61, 0x70, 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x61, 0x74, 0x65, + 0x54, 0x61, 0x73, 0x6b, 0x48, 0x00, 0x52, 0x1b, 0x70, 0x61, 0x6e, 0x63, 0x61, 0x6b, 0x65, 0x73, + 0x77, 0x61, 0x70, 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x61, 0x74, 0x65, 0x54, + 0x61, 0x73, 0x6b, 0x12, 0x40, 0x0a, 0x0a, 0x63, 0x61, 0x63, 0x68, 0x65, 0x5f, 0x74, 0x61, 0x73, + 0x6b, 0x18, 0x22, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, + 0x5f, 0x6a, 0x6f, 0x62, 0x2e, 0x4f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x4a, 0x6f, 0x62, 0x2e, 0x43, + 0x61, 0x63, 0x68, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x48, 0x00, 0x52, 0x09, 0x63, 0x61, 0x63, 0x68, + 0x65, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x5c, 0x0a, 0x14, 0x73, 0x79, 0x73, 0x63, 0x6c, 0x6f, 0x63, + 0x6b, 0x5f, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x5f, 0x74, 0x61, 0x73, 0x6b, 0x18, 0x23, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x5f, 0x6a, 0x6f, 0x62, + 0x2e, 0x4f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x4a, 0x6f, 0x62, 0x2e, 0x53, 0x79, 0x73, 0x63, 0x6c, + 0x6f, 0x63, 0x6b, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x54, 0x61, 0x73, 0x6b, 0x48, 0x00, 0x52, + 0x12, 0x73, 0x79, 0x73, 0x63, 0x6c, 0x6f, 0x63, 0x6b, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x54, + 0x61, 0x73, 0x6b, 0x12, 0x59, 0x0a, 0x13, 0x6d, 0x61, 0x72, 0x69, 0x6e, 0x61, 0x64, 0x65, 0x5f, + 0x73, 0x74, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x61, 0x73, 0x6b, 0x18, 0x24, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x27, 0x2e, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x5f, 0x6a, 0x6f, 0x62, 0x2e, 0x4f, 0x72, + 0x61, 0x63, 0x6c, 0x65, 0x4a, 0x6f, 0x62, 0x2e, 0x4d, 0x61, 0x72, 0x69, 0x6e, 0x61, 0x64, 0x65, + 0x53, 0x74, 0x61, 0x74, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x48, 0x00, 0x52, 0x11, 0x6d, 0x61, 0x72, + 0x69, 0x6e, 0x61, 0x64, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x76, + 0x0a, 0x1e, 0x73, 0x6f, 0x6c, 0x61, 0x6e, 0x61, 0x5f, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, + 0x5f, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x66, 0x65, 0x74, 0x63, 0x68, 0x5f, 0x74, 0x61, 0x73, 0x6b, + 0x18, 0x25, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x30, 0x2e, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x5f, + 0x6a, 0x6f, 0x62, 0x2e, 0x4f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x4a, 0x6f, 0x62, 0x2e, 0x53, 0x6f, + 0x6c, 0x61, 0x6e, 0x61, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x44, 0x61, 0x74, 0x61, 0x46, + 0x65, 0x74, 0x63, 0x68, 0x54, 0x61, 0x73, 0x6b, 0x48, 0x00, 0x52, 0x1a, 0x73, 0x6f, 0x6c, 0x61, + 0x6e, 0x61, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x44, 0x61, 0x74, 0x61, 0x46, 0x65, 0x74, + 0x63, 0x68, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x66, 0x0a, 0x18, 0x62, 0x75, 0x66, 0x66, 0x65, 0x72, + 0x5f, 0x6c, 0x61, 0x79, 0x6f, 0x75, 0x74, 0x5f, 0x70, 0x61, 0x72, 0x73, 0x65, 0x5f, 0x74, 0x61, + 0x73, 0x6b, 0x18, 0x26, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x6f, 0x72, 0x61, 0x63, 0x6c, + 0x65, 0x5f, 0x6a, 0x6f, 0x62, 0x2e, 0x4f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x4a, 0x6f, 0x62, 0x2e, + 0x42, 0x75, 0x66, 0x66, 0x65, 0x72, 0x4c, 0x61, 0x79, 0x6f, 0x75, 0x74, 0x50, 0x61, 0x72, 0x73, + 0x65, 0x54, 0x61, 0x73, 0x6b, 0x48, 0x00, 0x52, 0x15, 0x62, 0x75, 0x66, 0x66, 0x65, 0x72, 0x4c, + 0x61, 0x79, 0x6f, 0x75, 0x74, 0x50, 0x61, 0x72, 0x73, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x4d, + 0x0a, 0x0f, 0x63, 0x72, 0x6f, 0x6e, 0x5f, 0x70, 0x61, 0x72, 0x73, 0x65, 0x5f, 0x74, 0x61, 0x73, + 0x6b, 0x18, 0x27, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, + 0x5f, 0x6a, 0x6f, 0x62, 0x2e, 0x4f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x4a, 0x6f, 0x62, 0x2e, 0x43, + 0x72, 0x6f, 0x6e, 0x50, 0x61, 0x72, 0x73, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x48, 0x00, 0x52, 0x0d, + 0x63, 0x72, 0x6f, 0x6e, 0x50, 0x61, 0x72, 0x73, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x3a, 0x0a, + 0x08, 0x6d, 0x69, 0x6e, 0x5f, 0x74, 0x61, 0x73, 0x6b, 0x18, 0x28, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x1d, 0x2e, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x5f, 0x6a, 0x6f, 0x62, 0x2e, 0x4f, 0x72, 0x61, + 0x63, 0x6c, 0x65, 0x4a, 0x6f, 0x62, 0x2e, 0x4d, 0x69, 0x6e, 0x54, 0x61, 0x73, 0x6b, 0x48, 0x00, + 0x52, 0x07, 0x6d, 0x69, 0x6e, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x5f, 0x0a, 0x15, 0x68, 0x69, 0x73, + 0x74, 0x6f, 0x72, 0x79, 0x5f, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x74, 0x61, + 0x73, 0x6b, 0x18, 0x29, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x6f, 0x72, 0x61, 0x63, 0x6c, + 0x65, 0x5f, 0x6a, 0x6f, 0x62, 0x2e, 0x4f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x4a, 0x6f, 0x62, 0x2e, + 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x46, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x54, + 0x61, 0x73, 0x6b, 0x48, 0x00, 0x52, 0x13, 0x68, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x46, 0x75, + 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x3d, 0x0a, 0x09, 0x76, 0x77, + 0x61, 0x70, 0x5f, 0x74, 0x61, 0x73, 0x6b, 0x18, 0x2a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, + 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x5f, 0x6a, 0x6f, 0x62, 0x2e, 0x4f, 0x72, 0x61, 0x63, 0x6c, + 0x65, 0x4a, 0x6f, 0x62, 0x2e, 0x56, 0x77, 0x61, 0x70, 0x54, 0x61, 0x73, 0x6b, 0x48, 0x00, 0x52, + 0x08, 0x76, 0x77, 0x61, 0x70, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x3d, 0x0a, 0x09, 0x65, 0x77, 0x6d, + 0x61, 0x5f, 0x74, 0x61, 0x73, 0x6b, 0x18, 0x2b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x6f, + 0x72, 0x61, 0x63, 0x6c, 0x65, 0x5f, 0x6a, 0x6f, 0x62, 0x2e, 0x4f, 0x72, 0x61, 0x63, 0x6c, 0x65, + 0x4a, 0x6f, 0x62, 0x2e, 0x45, 0x77, 0x6d, 0x61, 0x54, 0x61, 0x73, 0x6b, 0x48, 0x00, 0x52, 0x08, + 0x65, 0x77, 0x6d, 0x61, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x4f, 0x0a, 0x0f, 0x63, 0x6f, 0x6d, 0x70, + 0x61, 0x72, 0x69, 0x73, 0x6f, 0x6e, 0x5f, 0x74, 0x61, 0x73, 0x6b, 0x18, 0x2c, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x24, 0x2e, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x5f, 0x6a, 0x6f, 0x62, 0x2e, 0x4f, + 0x72, 0x61, 0x63, 0x6c, 0x65, 0x4a, 0x6f, 0x62, 0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x61, 0x72, 0x69, + 0x73, 0x6f, 0x6e, 0x54, 0x61, 0x73, 0x6b, 0x48, 0x00, 0x52, 0x0e, 0x63, 0x6f, 0x6d, 0x70, 0x61, + 0x72, 0x69, 0x73, 0x6f, 0x6e, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x40, 0x0a, 0x0a, 0x72, 0x6f, 0x75, + 0x6e, 0x64, 0x5f, 0x74, 0x61, 0x73, 0x6b, 0x18, 0x2d, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, + 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x5f, 0x6a, 0x6f, 0x62, 0x2e, 0x4f, 0x72, 0x61, 0x63, 0x6c, + 0x65, 0x4a, 0x6f, 0x62, 0x2e, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x54, 0x61, 0x73, 0x6b, 0x48, 0x00, + 0x52, 0x09, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x40, 0x0a, 0x0a, 0x62, + 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x74, 0x61, 0x73, 0x6b, 0x18, 0x2e, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x1f, 0x2e, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x5f, 0x6a, 0x6f, 0x62, 0x2e, 0x4f, 0x72, 0x61, + 0x63, 0x6c, 0x65, 0x4a, 0x6f, 0x62, 0x2e, 0x42, 0x6f, 0x75, 0x6e, 0x64, 0x54, 0x61, 0x73, 0x6b, + 0x48, 0x00, 0x52, 0x09, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x46, 0x0a, + 0x0c, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x73, 0x5f, 0x74, 0x61, 0x73, 0x6b, 0x18, 0x2f, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x5f, 0x6a, 0x6f, 0x62, + 0x2e, 0x4f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x4a, 0x6f, 0x62, 0x2e, 0x53, 0x65, 0x63, 0x72, 0x65, + 0x74, 0x73, 0x54, 0x61, 0x73, 0x6b, 0x48, 0x00, 0x52, 0x0b, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, + 0x73, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x60, 0x0a, 0x16, 0x73, 0x61, 0x6e, 0x63, 0x74, 0x75, 0x6d, + 0x5f, 0x6c, 0x73, 0x74, 0x5f, 0x70, 0x72, 0x69, 0x63, 0x65, 0x5f, 0x74, 0x61, 0x73, 0x6b, 0x18, + 0x30, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x5f, 0x6a, + 0x6f, 0x62, 0x2e, 0x4f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x4a, 0x6f, 0x62, 0x2e, 0x53, 0x61, 0x6e, + 0x63, 0x74, 0x75, 0x6d, 0x4c, 0x73, 0x74, 0x50, 0x72, 0x69, 0x63, 0x65, 0x54, 0x61, 0x73, 0x6b, + 0x48, 0x00, 0x52, 0x13, 0x73, 0x61, 0x6e, 0x63, 0x74, 0x75, 0x6d, 0x4c, 0x73, 0x74, 0x50, 0x72, + 0x69, 0x63, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x4a, 0x0a, 0x0e, 0x6f, 0x6e, 0x64, 0x6f, 0x5f, + 0x75, 0x73, 0x64, 0x79, 0x5f, 0x74, 0x61, 0x73, 0x6b, 0x18, 0x31, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x22, 0x2e, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x5f, 0x6a, 0x6f, 0x62, 0x2e, 0x4f, 0x72, 0x61, + 0x63, 0x6c, 0x65, 0x4a, 0x6f, 0x62, 0x2e, 0x4f, 0x6e, 0x64, 0x6f, 0x55, 0x73, 0x64, 0x79, 0x54, + 0x61, 0x73, 0x6b, 0x48, 0x00, 0x52, 0x0c, 0x6f, 0x6e, 0x64, 0x6f, 0x55, 0x73, 0x64, 0x79, 0x54, + 0x61, 0x73, 0x6b, 0x12, 0x53, 0x0a, 0x11, 0x6d, 0x65, 0x74, 0x65, 0x6f, 0x72, 0x61, 0x5f, 0x73, + 0x77, 0x61, 0x70, 0x5f, 0x74, 0x61, 0x73, 0x6b, 0x18, 0x32, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, + 0x2e, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x5f, 0x6a, 0x6f, 0x62, 0x2e, 0x4f, 0x72, 0x61, 0x63, + 0x6c, 0x65, 0x4a, 0x6f, 0x62, 0x2e, 0x4d, 0x65, 0x74, 0x65, 0x6f, 0x72, 0x61, 0x53, 0x77, 0x61, + 0x70, 0x54, 0x61, 0x73, 0x6b, 0x48, 0x00, 0x52, 0x0f, 0x6d, 0x65, 0x74, 0x65, 0x6f, 0x72, 0x61, + 0x53, 0x77, 0x61, 0x70, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x4a, 0x0a, 0x0e, 0x75, 0x6e, 0x69, 0x78, + 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x74, 0x61, 0x73, 0x6b, 0x18, 0x33, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x22, 0x2e, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x5f, 0x6a, 0x6f, 0x62, 0x2e, 0x4f, 0x72, + 0x61, 0x63, 0x6c, 0x65, 0x4a, 0x6f, 0x62, 0x2e, 0x55, 0x6e, 0x69, 0x78, 0x54, 0x69, 0x6d, 0x65, + 0x54, 0x61, 0x73, 0x6b, 0x48, 0x00, 0x52, 0x0c, 0x75, 0x6e, 0x69, 0x78, 0x54, 0x69, 0x6d, 0x65, + 0x54, 0x61, 0x73, 0x6b, 0x12, 0x56, 0x0a, 0x12, 0x6d, 0x61, 0x70, 0x6c, 0x65, 0x5f, 0x66, 0x69, + 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x74, 0x61, 0x73, 0x6b, 0x18, 0x34, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x26, 0x2e, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x5f, 0x6a, 0x6f, 0x62, 0x2e, 0x4f, 0x72, + 0x61, 0x63, 0x6c, 0x65, 0x4a, 0x6f, 0x62, 0x2e, 0x4d, 0x61, 0x70, 0x6c, 0x65, 0x46, 0x69, 0x6e, + 0x61, 0x6e, 0x63, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x48, 0x00, 0x52, 0x10, 0x6d, 0x61, 0x70, 0x6c, + 0x65, 0x46, 0x69, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x40, 0x0a, 0x0a, + 0x67, 0x6c, 0x79, 0x70, 0x68, 0x5f, 0x74, 0x61, 0x73, 0x6b, 0x18, 0x35, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x1f, 0x2e, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x5f, 0x6a, 0x6f, 0x62, 0x2e, 0x4f, 0x72, + 0x61, 0x63, 0x6c, 0x65, 0x4a, 0x6f, 0x62, 0x2e, 0x47, 0x6c, 0x79, 0x70, 0x68, 0x54, 0x61, 0x73, + 0x6b, 0x48, 0x00, 0x52, 0x09, 0x67, 0x6c, 0x79, 0x70, 0x68, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x40, + 0x0a, 0x0a, 0x63, 0x6f, 0x72, 0x65, 0x78, 0x5f, 0x74, 0x61, 0x73, 0x6b, 0x18, 0x36, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x5f, 0x6a, 0x6f, 0x62, 0x2e, + 0x4f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x4a, 0x6f, 0x62, 0x2e, 0x43, 0x6f, 0x72, 0x65, 0x78, 0x54, + 0x61, 0x73, 0x6b, 0x48, 0x00, 0x52, 0x09, 0x63, 0x6f, 0x72, 0x65, 0x78, 0x54, 0x61, 0x73, 0x6b, + 0x12, 0x3a, 0x0a, 0x08, 0x6c, 0x6c, 0x6d, 0x5f, 0x74, 0x61, 0x73, 0x6b, 0x18, 0x37, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x5f, 0x6a, 0x6f, 0x62, 0x2e, + 0x4f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x4a, 0x6f, 0x62, 0x2e, 0x4c, 0x6c, 0x6d, 0x54, 0x61, 0x73, + 0x6b, 0x48, 0x00, 0x52, 0x07, 0x6c, 0x6c, 0x6d, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x53, 0x0a, 0x11, + 0x73, 0x6f, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x5f, 0x73, 0x75, 0x73, 0x64, 0x5f, 0x74, 0x61, 0x73, + 0x6b, 0x18, 0x38, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, + 0x5f, 0x6a, 0x6f, 0x62, 0x2e, 0x4f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x4a, 0x6f, 0x62, 0x2e, 0x53, + 0x6f, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x53, 0x75, 0x73, 0x64, 0x54, 0x61, 0x73, 0x6b, 0x48, 0x00, + 0x52, 0x0f, 0x73, 0x6f, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x53, 0x75, 0x73, 0x64, 0x54, 0x61, 0x73, + 0x6b, 0x12, 0x56, 0x0a, 0x12, 0x63, 0x75, 0x72, 0x76, 0x65, 0x5f, 0x66, 0x69, 0x6e, 0x61, 0x6e, + 0x63, 0x65, 0x5f, 0x74, 0x61, 0x73, 0x6b, 0x18, 0x39, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, + 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x5f, 0x6a, 0x6f, 0x62, 0x2e, 0x4f, 0x72, 0x61, 0x63, 0x6c, + 0x65, 0x4a, 0x6f, 0x62, 0x2e, 0x43, 0x75, 0x72, 0x76, 0x65, 0x46, 0x69, 0x6e, 0x61, 0x6e, 0x63, + 0x65, 0x54, 0x61, 0x73, 0x6b, 0x48, 0x00, 0x52, 0x10, 0x63, 0x75, 0x72, 0x76, 0x65, 0x46, 0x69, + 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x76, 0x0a, 0x1e, 0x74, 0x75, 0x72, + 0x62, 0x6f, 0x5f, 0x65, 0x74, 0x68, 0x5f, 0x72, 0x65, 0x64, 0x65, 0x6d, 0x70, 0x74, 0x69, 0x6f, + 0x6e, 0x5f, 0x72, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x61, 0x73, 0x6b, 0x18, 0x3a, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x30, 0x2e, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x5f, 0x6a, 0x6f, 0x62, 0x2e, 0x4f, + 0x72, 0x61, 0x63, 0x6c, 0x65, 0x4a, 0x6f, 0x62, 0x2e, 0x54, 0x75, 0x72, 0x62, 0x6f, 0x45, 0x74, + 0x68, 0x52, 0x65, 0x64, 0x65, 0x6d, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x61, 0x74, 0x65, 0x54, + 0x61, 0x73, 0x6b, 0x48, 0x00, 0x52, 0x1a, 0x74, 0x75, 0x72, 0x62, 0x6f, 0x45, 0x74, 0x68, 0x52, + 0x65, 0x64, 0x65, 0x6d, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x61, 0x74, 0x65, 0x54, 0x61, 0x73, + 0x6b, 0x12, 0x47, 0x0a, 0x0d, 0x62, 0x69, 0x74, 0x5f, 0x66, 0x6c, 0x75, 0x78, 0x5f, 0x74, 0x61, + 0x73, 0x6b, 0x18, 0x3b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x6f, 0x72, 0x61, 0x63, 0x6c, + 0x65, 0x5f, 0x6a, 0x6f, 0x62, 0x2e, 0x4f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x4a, 0x6f, 0x62, 0x2e, + 0x42, 0x69, 0x74, 0x46, 0x6c, 0x75, 0x78, 0x54, 0x61, 0x73, 0x6b, 0x48, 0x00, 0x52, 0x0b, 0x62, + 0x69, 0x74, 0x46, 0x6c, 0x75, 0x78, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x4f, 0x0a, 0x0f, 0x66, 0x72, + 0x61, 0x67, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x5f, 0x74, 0x61, 0x73, 0x6b, 0x18, 0x3c, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x5f, 0x6a, 0x6f, 0x62, + 0x2e, 0x4f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x4a, 0x6f, 0x62, 0x2e, 0x46, 0x72, 0x61, 0x67, 0x6d, + 0x65, 0x74, 0x72, 0x69, 0x63, 0x54, 0x61, 0x73, 0x6b, 0x48, 0x00, 0x52, 0x0e, 0x66, 0x72, 0x61, + 0x67, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x4c, 0x0a, 0x0e, 0x61, + 0x66, 0x74, 0x65, 0x72, 0x6d, 0x61, 0x74, 0x68, 0x5f, 0x74, 0x61, 0x73, 0x6b, 0x18, 0x3d, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x5f, 0x6a, 0x6f, 0x62, + 0x2e, 0x4f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x4a, 0x6f, 0x62, 0x2e, 0x41, 0x66, 0x74, 0x65, 0x72, + 0x6d, 0x61, 0x74, 0x68, 0x54, 0x61, 0x73, 0x6b, 0x48, 0x00, 0x52, 0x0d, 0x61, 0x66, 0x74, 0x65, + 0x72, 0x6d, 0x61, 0x74, 0x68, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x4c, 0x0a, 0x0e, 0x65, 0x74, 0x68, + 0x65, 0x72, 0x66, 0x75, 0x73, 0x65, 0x5f, 0x74, 0x61, 0x73, 0x6b, 0x18, 0x3f, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x23, 0x2e, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x5f, 0x6a, 0x6f, 0x62, 0x2e, 0x4f, + 0x72, 0x61, 0x63, 0x6c, 0x65, 0x4a, 0x6f, 0x62, 0x2e, 0x45, 0x74, 0x68, 0x65, 0x72, 0x66, 0x75, + 0x73, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x48, 0x00, 0x52, 0x0d, 0x65, 0x74, 0x68, 0x65, 0x72, 0x66, + 0x75, 0x73, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x69, 0x0a, 0x19, 0x6c, 0x73, 0x74, 0x5f, 0x68, + 0x69, 0x73, 0x74, 0x6f, 0x72, 0x69, 0x63, 0x61, 0x6c, 0x5f, 0x79, 0x69, 0x65, 0x6c, 0x64, 0x5f, + 0x74, 0x61, 0x73, 0x6b, 0x18, 0x40, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x6f, 0x72, 0x61, + 0x63, 0x6c, 0x65, 0x5f, 0x6a, 0x6f, 0x62, 0x2e, 0x4f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x4a, 0x6f, + 0x62, 0x2e, 0x4c, 0x73, 0x74, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x69, 0x63, 0x61, 0x6c, 0x59, + 0x69, 0x65, 0x6c, 0x64, 0x54, 0x61, 0x73, 0x6b, 0x48, 0x00, 0x52, 0x16, 0x6c, 0x73, 0x74, 0x48, + 0x69, 0x73, 0x74, 0x6f, 0x72, 0x69, 0x63, 0x61, 0x6c, 0x59, 0x69, 0x65, 0x6c, 0x64, 0x54, 0x61, + 0x73, 0x6b, 0x12, 0x47, 0x0a, 0x0d, 0x70, 0x75, 0x6d, 0x70, 0x5f, 0x61, 0x6d, 0x6d, 0x5f, 0x74, + 0x61, 0x73, 0x6b, 0x18, 0x41, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x6f, 0x72, 0x61, 0x63, + 0x6c, 0x65, 0x5f, 0x6a, 0x6f, 0x62, 0x2e, 0x4f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x4a, 0x6f, 0x62, + 0x2e, 0x50, 0x75, 0x6d, 0x70, 0x41, 0x6d, 0x6d, 0x54, 0x61, 0x73, 0x6b, 0x48, 0x00, 0x52, 0x0b, + 0x70, 0x75, 0x6d, 0x70, 0x41, 0x6d, 0x6d, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x6e, 0x0a, 0x1c, 0x70, + 0x75, 0x6d, 0x70, 0x5f, 0x61, 0x6d, 0x6d, 0x5f, 0x6c, 0x70, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, + 0x5f, 0x70, 0x72, 0x69, 0x63, 0x65, 0x5f, 0x74, 0x61, 0x73, 0x6b, 0x18, 0x42, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x2d, 0x2e, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x5f, 0x6a, 0x6f, 0x62, 0x2e, 0x4f, + 0x72, 0x61, 0x63, 0x6c, 0x65, 0x4a, 0x6f, 0x62, 0x2e, 0x50, 0x75, 0x6d, 0x70, 0x41, 0x6d, 0x6d, + 0x4c, 0x70, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x50, 0x72, 0x69, 0x63, 0x65, 0x54, 0x61, 0x73, 0x6b, + 0x48, 0x00, 0x52, 0x17, 0x70, 0x75, 0x6d, 0x70, 0x41, 0x6d, 0x6d, 0x4c, 0x70, 0x54, 0x6f, 0x6b, + 0x65, 0x6e, 0x50, 0x72, 0x69, 0x63, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x49, 0x0a, 0x0d, 0x65, + 0x78, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x5f, 0x74, 0x61, 0x73, 0x6b, 0x18, 0x43, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x5f, 0x6a, 0x6f, 0x62, 0x2e, + 0x4f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x4a, 0x6f, 0x62, 0x2e, 0x45, 0x78, 0x70, 0x6f, 0x6e, 0x65, + 0x6e, 0x74, 0x54, 0x61, 0x73, 0x6b, 0x48, 0x00, 0x52, 0x0c, 0x65, 0x78, 0x70, 0x6f, 0x6e, 0x65, + 0x6e, 0x74, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x79, 0x0a, 0x1f, 0x65, 0x78, 0x70, 0x6f, 0x6e, 0x65, + 0x6e, 0x74, 0x5f, 0x70, 0x74, 0x5f, 0x6c, 0x69, 0x6e, 0x65, 0x61, 0x72, 0x5f, 0x70, 0x72, 0x69, + 0x63, 0x69, 0x6e, 0x67, 0x5f, 0x74, 0x61, 0x73, 0x6b, 0x18, 0x44, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x31, 0x2e, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x5f, 0x6a, 0x6f, 0x62, 0x2e, 0x4f, 0x72, 0x61, + 0x63, 0x6c, 0x65, 0x4a, 0x6f, 0x62, 0x2e, 0x45, 0x78, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x50, + 0x54, 0x4c, 0x69, 0x6e, 0x65, 0x61, 0x72, 0x50, 0x72, 0x69, 0x63, 0x69, 0x6e, 0x67, 0x54, 0x61, + 0x73, 0x6b, 0x48, 0x00, 0x52, 0x1b, 0x65, 0x78, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x50, 0x74, + 0x4c, 0x69, 0x6e, 0x65, 0x61, 0x72, 0x50, 0x72, 0x69, 0x63, 0x69, 0x6e, 0x67, 0x54, 0x61, 0x73, + 0x6b, 0x12, 0x7c, 0x0a, 0x20, 0x73, 0x6f, 0x6c, 0x61, 0x6e, 0x61, 0x5f, 0x74, 0x6f, 0x6b, 0x65, + 0x6e, 0x5f, 0x32, 0x30, 0x32, 0x32, 0x5f, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, + 0x5f, 0x74, 0x61, 0x73, 0x6b, 0x18, 0x45, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x32, 0x2e, 0x6f, 0x72, + 0x61, 0x63, 0x6c, 0x65, 0x5f, 0x6a, 0x6f, 0x62, 0x2e, 0x4f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x4a, + 0x6f, 0x62, 0x2e, 0x53, 0x6f, 0x6c, 0x61, 0x6e, 0x61, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x32, 0x30, + 0x32, 0x32, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x54, 0x61, 0x73, 0x6b, 0x48, + 0x00, 0x52, 0x1c, 0x73, 0x6f, 0x6c, 0x61, 0x6e, 0x61, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x32, 0x30, + 0x32, 0x32, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x54, 0x61, 0x73, 0x6b, 0x12, + 0x62, 0x0a, 0x16, 0x73, 0x77, 0x69, 0x74, 0x63, 0x68, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x5f, 0x73, + 0x75, 0x72, 0x67, 0x65, 0x5f, 0x74, 0x61, 0x73, 0x6b, 0x18, 0x46, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x2a, 0x2e, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x5f, 0x6a, 0x6f, 0x62, 0x2e, 0x4f, 0x72, 0x61, + 0x63, 0x6c, 0x65, 0x4a, 0x6f, 0x62, 0x2e, 0x53, 0x77, 0x69, 0x74, 0x63, 0x68, 0x62, 0x6f, 0x61, + 0x72, 0x64, 0x53, 0x75, 0x72, 0x67, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x48, 0x00, 0x52, 0x14, 0x73, + 0x77, 0x69, 0x74, 0x63, 0x68, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x53, 0x75, 0x72, 0x67, 0x65, 0x54, + 0x61, 0x73, 0x6b, 0x42, 0x06, 0x0a, 0x04, 0x54, 0x61, 0x73, 0x6b, 0x4a, 0x04, 0x08, 0x1b, 0x10, + 0x1c, 0x4a, 0x04, 0x08, 0x1c, 0x10, 0x1d, 0x4a, 0x04, 0x08, 0x3e, 0x10, 0x3f, 0x52, 0x12, 0x64, + 0x65, 0x66, 0x69, 0x5f, 0x6b, 0x69, 0x6e, 0x67, 0x64, 0x6f, 0x6d, 0x73, 0x5f, 0x74, 0x61, 0x73, + 0x6b, 0x52, 0x08, 0x74, 0x70, 0x73, 0x5f, 0x74, 0x61, 0x73, 0x6b, 0x52, 0x0d, 0x68, 0x6f, 0x70, + 0x5f, 0x73, 0x77, 0x61, 0x70, 0x5f, 0x74, 0x61, 0x73, 0x6b, 0x4a, 0xda, 0xa8, 0x04, 0x0a, 0x07, + 0x12, 0x05, 0x00, 0x00, 0xb8, 0x0d, 0x01, 0x0a, 0x08, 0x0a, 0x01, 0x0c, 0x12, 0x03, 0x00, 0x00, + 0x12, 0x0a, 0x08, 0x0a, 0x01, 0x02, 0x12, 0x03, 0x02, 0x00, 0x13, 0x0a, 0x52, 0x0a, 0x02, 0x04, + 0x00, 0x12, 0x05, 0x05, 0x00, 0xb8, 0x0d, 0x01, 0x1a, 0x45, 0x2f, 0x20, 0x52, 0x65, 0x70, 0x72, + 0x65, 0x73, 0x6e, 0x74, 0x73, 0x20, 0x61, 0x20, 0x6c, 0x69, 0x73, 0x74, 0x20, 0x6f, 0x66, 0x20, + 0x74, 0x61, 0x73, 0x6b, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x62, 0x65, 0x20, 0x70, 0x65, 0x72, 0x66, + 0x6f, 0x72, 0x6d, 0x65, 0x64, 0x20, 0x62, 0x79, 0x20, 0x61, 0x20, 0x73, 0x77, 0x69, 0x74, 0x63, + 0x68, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x20, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x2e, 0x0a, 0x0a, + 0x0a, 0x0a, 0x03, 0x04, 0x00, 0x01, 0x12, 0x03, 0x05, 0x08, 0x11, 0x0a, 0xeb, 0x04, 0x0a, 0x04, + 0x04, 0x00, 0x03, 0x00, 0x12, 0x04, 0x1b, 0x02, 0x38, 0x03, 0x1a, 0xdc, 0x04, 0x0a, 0x54, 0x68, + 0x65, 0x20, 0x61, 0x64, 0x61, 0x70, 0x74, 0x65, 0x72, 0x20, 0x77, 0x69, 0x6c, 0x6c, 0x20, 0x72, + 0x65, 0x70, 0x6f, 0x72, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x65, 0x78, 0x74, 0x20, 0x62, + 0x6f, 0x64, 0x79, 0x20, 0x6f, 0x66, 0x20, 0x61, 0x20, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, + 0x66, 0x75, 0x6c, 0x20, 0x48, 0x54, 0x54, 0x50, 0x20, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x20, 0x74, 0x6f, 0x20, 0x74, 0x68, 0x65, 0x0a, 0x73, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x65, + 0x64, 0x20, 0x75, 0x72, 0x6c, 0x2c, 0x20, 0x6f, 0x72, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, + 0x20, 0x61, 0x6e, 0x20, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x20, 0x69, 0x66, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x20, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, + 0x20, 0x63, 0x6f, 0x64, 0x65, 0x20, 0x69, 0x73, 0x20, 0x67, 0x72, 0x65, 0x61, 0x74, 0x65, 0x72, + 0x0a, 0x74, 0x68, 0x61, 0x6e, 0x20, 0x6f, 0x72, 0x20, 0x65, 0x71, 0x75, 0x61, 0x6c, 0x20, 0x74, + 0x6f, 0x20, 0x34, 0x30, 0x30, 0x2e, 0x0a, 0x0a, 0x5f, 0x2a, 0x2a, 0x49, 0x6e, 0x70, 0x75, 0x74, + 0x2a, 0x2a, 0x5f, 0x3a, 0x20, 0x4e, 0x6f, 0x6e, 0x65, 0x0a, 0x0a, 0x5f, 0x2a, 0x2a, 0x52, 0x65, + 0x74, 0x75, 0x72, 0x6e, 0x73, 0x2a, 0x2a, 0x5f, 0x3a, 0x20, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, + 0x20, 0x72, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, + 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x68, 0x74, 0x74, 0x70, 0x20, 0x72, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x0a, 0x0a, 0x5f, 0x2a, 0x2a, 0x45, 0x78, 0x61, 0x6d, 0x70, 0x6c, + 0x65, 0x2a, 0x2a, 0x5f, 0x3a, 0x20, 0x42, 0x61, 0x73, 0x69, 0x63, 0x20, 0x48, 0x74, 0x74, 0x70, + 0x54, 0x61, 0x73, 0x6b, 0x0a, 0x0a, 0x60, 0x60, 0x60, 0x6a, 0x73, 0x6f, 0x6e, 0x0a, 0x7b, 0x22, + 0x68, 0x74, 0x74, 0x70, 0x54, 0x61, 0x73, 0x6b, 0x22, 0x3a, 0x20, 0x7b, 0x22, 0x75, 0x72, 0x6c, + 0x22, 0x3a, 0x20, 0x22, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x6d, 0x79, 0x77, 0x65, + 0x62, 0x73, 0x69, 0x74, 0x65, 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x70, 0x61, 0x74, 0x68, 0x22, 0x7d, + 0x20, 0x7d, 0x0a, 0x60, 0x60, 0x60, 0x0a, 0x0a, 0x5f, 0x2a, 0x2a, 0x45, 0x78, 0x61, 0x6d, 0x70, + 0x6c, 0x65, 0x2a, 0x2a, 0x5f, 0x3a, 0x20, 0x48, 0x74, 0x74, 0x70, 0x54, 0x61, 0x73, 0x6b, 0x20, + 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x68, 0x65, 0x61, + 0x64, 0x65, 0x72, 0x73, 0x0a, 0x0a, 0x60, 0x60, 0x60, 0x6a, 0x73, 0x6f, 0x6e, 0x0a, 0x7b, 0x20, + 0x22, 0x68, 0x74, 0x74, 0x70, 0x54, 0x61, 0x73, 0x6b, 0x22, 0x3a, 0x20, 0x7b, 0x20, 0x22, 0x75, + 0x72, 0x6c, 0x22, 0x3a, 0x20, 0x22, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x6d, 0x79, + 0x77, 0x65, 0x62, 0x73, 0x69, 0x74, 0x65, 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x70, 0x61, 0x74, 0x68, + 0x22, 0x2c, 0x20, 0x22, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x22, 0x3a, 0x20, 0x22, 0x4d, 0x45, + 0x54, 0x48, 0x4f, 0x44, 0x5f, 0x50, 0x4f, 0x53, 0x54, 0x22, 0x2c, 0x20, 0x22, 0x68, 0x65, 0x61, + 0x64, 0x65, 0x72, 0x73, 0x22, 0x3a, 0x20, 0x5b, 0x20, 0x7b, 0x20, 0x22, 0x6b, 0x65, 0x79, 0x22, + 0x3a, 0x20, 0x22, 0x4d, 0x59, 0x5f, 0x48, 0x45, 0x41, 0x44, 0x45, 0x52, 0x5f, 0x4b, 0x45, 0x59, + 0x22, 0x2c, 0x20, 0x22, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x3a, 0x20, 0x22, 0x4d, 0x59, 0x5f, + 0x48, 0x45, 0x41, 0x44, 0x45, 0x52, 0x5f, 0x56, 0x41, 0x4c, 0x55, 0x45, 0x22, 0x20, 0x7d, 0x20, + 0x5d, 0x2c, 0x20, 0x22, 0x62, 0x6f, 0x64, 0x79, 0x22, 0x3a, 0x20, 0x22, 0x7b, 0x5c, 0x22, 0x4d, + 0x59, 0x5f, 0x42, 0x4f, 0x44, 0x59, 0x5f, 0x4b, 0x45, 0x59, 0x5c, 0x22, 0x3a, 0x5c, 0x22, 0x4d, + 0x59, 0x5f, 0x42, 0x4f, 0x44, 0x59, 0x5f, 0x56, 0x41, 0x4c, 0x55, 0x45, 0x5c, 0x22, 0x7d, 0x22, + 0x20, 0x7d, 0x20, 0x7d, 0x0a, 0x60, 0x60, 0x60, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x03, + 0x00, 0x01, 0x12, 0x03, 0x1b, 0x0a, 0x12, 0x0a, 0x5c, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x00, 0x04, + 0x00, 0x12, 0x04, 0x1d, 0x04, 0x24, 0x05, 0x1a, 0x4c, 0x2f, 0x20, 0x41, 0x6e, 0x20, 0x65, 0x6e, + 0x75, 0x6d, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x72, 0x65, 0x70, 0x72, 0x65, 0x73, + 0x65, 0x6e, 0x74, 0x69, 0x6e, 0x67, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x79, 0x70, 0x65, 0x73, + 0x20, 0x6f, 0x66, 0x20, 0x48, 0x54, 0x54, 0x50, 0x20, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x73, 0x20, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x74, 0x6f, 0x20, 0x6d, + 0x61, 0x6b, 0x65, 0x2e, 0x0a, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x00, 0x04, 0x00, 0x01, + 0x12, 0x03, 0x1d, 0x09, 0x0f, 0x0a, 0x40, 0x0a, 0x08, 0x04, 0x00, 0x03, 0x00, 0x04, 0x00, 0x02, + 0x00, 0x12, 0x03, 0x1f, 0x06, 0x18, 0x1a, 0x2f, 0x2f, 0x20, 0x55, 0x6e, 0x73, 0x65, 0x74, 0x20, + 0x48, 0x54, 0x54, 0x50, 0x20, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x20, 0x77, 0x69, 0x6c, 0x6c, + 0x20, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x20, 0x74, 0x6f, 0x20, 0x4d, 0x45, 0x54, 0x48, + 0x4f, 0x44, 0x5f, 0x47, 0x45, 0x54, 0x0a, 0x0a, 0x10, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x00, 0x04, + 0x00, 0x02, 0x00, 0x01, 0x12, 0x03, 0x1f, 0x06, 0x13, 0x0a, 0x10, 0x0a, 0x09, 0x04, 0x00, 0x03, + 0x00, 0x04, 0x00, 0x02, 0x00, 0x02, 0x12, 0x03, 0x1f, 0x16, 0x17, 0x0a, 0x32, 0x0a, 0x08, 0x04, + 0x00, 0x03, 0x00, 0x04, 0x00, 0x02, 0x01, 0x12, 0x03, 0x21, 0x06, 0x15, 0x1a, 0x21, 0x2f, 0x20, + 0x50, 0x65, 0x72, 0x66, 0x6f, 0x72, 0x6d, 0x20, 0x61, 0x6e, 0x20, 0x48, 0x54, 0x54, 0x50, 0x20, + 0x27, 0x47, 0x45, 0x54, 0x27, 0x20, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x0a, 0x0a, + 0x10, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x00, 0x04, 0x00, 0x02, 0x01, 0x01, 0x12, 0x03, 0x21, 0x06, + 0x10, 0x0a, 0x10, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x00, 0x04, 0x00, 0x02, 0x01, 0x02, 0x12, 0x03, + 0x21, 0x13, 0x14, 0x0a, 0x33, 0x0a, 0x08, 0x04, 0x00, 0x03, 0x00, 0x04, 0x00, 0x02, 0x02, 0x12, + 0x03, 0x23, 0x06, 0x16, 0x1a, 0x22, 0x2f, 0x20, 0x50, 0x65, 0x72, 0x66, 0x6f, 0x72, 0x6d, 0x20, + 0x61, 0x6e, 0x20, 0x48, 0x54, 0x54, 0x50, 0x20, 0x27, 0x50, 0x4f, 0x53, 0x54, 0x27, 0x20, 0x72, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x0a, 0x0a, 0x10, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x00, + 0x04, 0x00, 0x02, 0x02, 0x01, 0x12, 0x03, 0x23, 0x06, 0x11, 0x0a, 0x10, 0x0a, 0x09, 0x04, 0x00, + 0x03, 0x00, 0x04, 0x00, 0x02, 0x02, 0x02, 0x12, 0x03, 0x23, 0x14, 0x15, 0x0a, 0x50, 0x0a, 0x06, + 0x04, 0x00, 0x03, 0x00, 0x03, 0x00, 0x12, 0x04, 0x27, 0x04, 0x2c, 0x05, 0x1a, 0x40, 0x2f, 0x20, + 0x41, 0x6e, 0x20, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x72, + 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x73, 0x20, 0x61, 0x20, 0x68, 0x65, 0x61, 0x64, + 0x65, 0x72, 0x20, 0x74, 0x6f, 0x20, 0x61, 0x64, 0x64, 0x20, 0x74, 0x6f, 0x20, 0x61, 0x6e, 0x20, + 0x48, 0x54, 0x54, 0x50, 0x20, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x0a, 0x0a, 0x0e, + 0x0a, 0x07, 0x04, 0x00, 0x03, 0x00, 0x03, 0x00, 0x01, 0x12, 0x03, 0x27, 0x0c, 0x12, 0x0a, 0x4a, + 0x0a, 0x08, 0x04, 0x00, 0x03, 0x00, 0x03, 0x00, 0x02, 0x00, 0x12, 0x03, 0x29, 0x06, 0x1e, 0x1a, + 0x39, 0x2f, 0x20, 0x41, 0x20, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x20, 0x6b, 0x65, 0x79, 0x20, + 0x73, 0x75, 0x63, 0x68, 0x20, 0x61, 0x73, 0x20, 0x60, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, + 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x60, 0x20, 0x6f, 0x72, 0x20, 0x60, 0x43, 0x6f, 0x6e, 0x74, + 0x65, 0x6e, 0x74, 0x2d, 0x54, 0x79, 0x70, 0x65, 0x60, 0x0a, 0x0a, 0x10, 0x0a, 0x09, 0x04, 0x00, + 0x03, 0x00, 0x03, 0x00, 0x02, 0x00, 0x04, 0x12, 0x03, 0x29, 0x06, 0x0e, 0x0a, 0x10, 0x0a, 0x09, + 0x04, 0x00, 0x03, 0x00, 0x03, 0x00, 0x02, 0x00, 0x05, 0x12, 0x03, 0x29, 0x0f, 0x15, 0x0a, 0x10, + 0x0a, 0x09, 0x04, 0x00, 0x03, 0x00, 0x03, 0x00, 0x02, 0x00, 0x01, 0x12, 0x03, 0x29, 0x16, 0x19, + 0x0a, 0x10, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x00, 0x03, 0x00, 0x02, 0x00, 0x03, 0x12, 0x03, 0x29, + 0x1c, 0x1d, 0x0a, 0x61, 0x0a, 0x08, 0x04, 0x00, 0x03, 0x00, 0x03, 0x00, 0x02, 0x01, 0x12, 0x03, + 0x2b, 0x06, 0x20, 0x1a, 0x50, 0x2f, 0x20, 0x41, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x20, 0x66, + 0x6f, 0x72, 0x20, 0x74, 0x68, 0x65, 0x20, 0x67, 0x69, 0x76, 0x65, 0x6e, 0x20, 0x68, 0x65, 0x61, + 0x64, 0x65, 0x72, 0x20, 0x6b, 0x65, 0x79, 0x20, 0x6c, 0x69, 0x6b, 0x65, 0x20, 0x60, 0x42, 0x61, + 0x73, 0x69, 0x63, 0x20, 0x4d, 0x59, 0x41, 0x55, 0x54, 0x48, 0x4b, 0x45, 0x59, 0x60, 0x20, 0x6f, + 0x72, 0x20, 0x60, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x6a, + 0x73, 0x6f, 0x6e, 0x60, 0x0a, 0x0a, 0x10, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x00, 0x03, 0x00, 0x02, + 0x01, 0x04, 0x12, 0x03, 0x2b, 0x06, 0x0e, 0x0a, 0x10, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x00, 0x03, + 0x00, 0x02, 0x01, 0x05, 0x12, 0x03, 0x2b, 0x0f, 0x15, 0x0a, 0x10, 0x0a, 0x09, 0x04, 0x00, 0x03, + 0x00, 0x03, 0x00, 0x02, 0x01, 0x01, 0x12, 0x03, 0x2b, 0x16, 0x1b, 0x0a, 0x10, 0x0a, 0x09, 0x04, + 0x00, 0x03, 0x00, 0x03, 0x00, 0x02, 0x01, 0x03, 0x12, 0x03, 0x2b, 0x1e, 0x1f, 0x0a, 0x4d, 0x0a, + 0x06, 0x04, 0x00, 0x03, 0x00, 0x02, 0x00, 0x12, 0x03, 0x2e, 0x04, 0x1c, 0x1a, 0x3e, 0x2f, 0x20, + 0x41, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, + 0x69, 0x6e, 0x67, 0x20, 0x74, 0x68, 0x65, 0x20, 0x55, 0x52, 0x4c, 0x20, 0x74, 0x6f, 0x20, 0x64, + 0x69, 0x72, 0x65, 0x63, 0x74, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x48, 0x54, 0x54, 0x50, 0x20, + 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x20, 0x74, 0x6f, 0x2e, 0x0a, 0x0a, 0x0e, 0x0a, 0x07, + 0x04, 0x00, 0x03, 0x00, 0x02, 0x00, 0x04, 0x12, 0x03, 0x2e, 0x04, 0x0c, 0x0a, 0x0e, 0x0a, 0x07, + 0x04, 0x00, 0x03, 0x00, 0x02, 0x00, 0x05, 0x12, 0x03, 0x2e, 0x0d, 0x13, 0x0a, 0x0e, 0x0a, 0x07, + 0x04, 0x00, 0x03, 0x00, 0x02, 0x00, 0x01, 0x12, 0x03, 0x2e, 0x14, 0x17, 0x0a, 0x0e, 0x0a, 0x07, + 0x04, 0x00, 0x03, 0x00, 0x02, 0x00, 0x03, 0x12, 0x03, 0x2e, 0x1a, 0x1b, 0x0a, 0x33, 0x0a, 0x06, + 0x04, 0x00, 0x03, 0x00, 0x02, 0x01, 0x12, 0x03, 0x31, 0x04, 0x1f, 0x1a, 0x24, 0x2f, 0x20, 0x54, + 0x68, 0x65, 0x20, 0x74, 0x79, 0x70, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x48, 0x54, 0x54, 0x50, 0x20, + 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x20, 0x74, 0x6f, 0x20, 0x6d, 0x61, 0x6b, 0x65, 0x2e, + 0x0a, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x00, 0x02, 0x01, 0x04, 0x12, 0x03, 0x31, 0x04, + 0x0c, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x00, 0x02, 0x01, 0x06, 0x12, 0x03, 0x31, 0x0d, + 0x13, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x00, 0x02, 0x01, 0x01, 0x12, 0x03, 0x31, 0x14, + 0x1a, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x00, 0x02, 0x01, 0x03, 0x12, 0x03, 0x31, 0x1d, + 0x1e, 0x0a, 0x3c, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x00, 0x02, 0x02, 0x12, 0x03, 0x34, 0x04, 0x20, + 0x1a, 0x2d, 0x2f, 0x20, 0x41, 0x20, 0x6c, 0x69, 0x73, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x68, 0x65, + 0x61, 0x64, 0x65, 0x72, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x61, 0x64, 0x64, 0x20, 0x74, 0x6f, 0x20, + 0x74, 0x68, 0x69, 0x73, 0x20, 0x48, 0x74, 0x74, 0x70, 0x54, 0x61, 0x73, 0x6b, 0x2e, 0x0a, 0x0a, + 0x0e, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x00, 0x02, 0x02, 0x04, 0x12, 0x03, 0x34, 0x04, 0x0c, 0x0a, + 0x0e, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x00, 0x02, 0x02, 0x06, 0x12, 0x03, 0x34, 0x0d, 0x13, 0x0a, + 0x0e, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x00, 0x02, 0x02, 0x01, 0x12, 0x03, 0x34, 0x14, 0x1b, 0x0a, + 0x0e, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x00, 0x02, 0x02, 0x03, 0x12, 0x03, 0x34, 0x1e, 0x1f, 0x0a, + 0x46, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x00, 0x02, 0x03, 0x12, 0x03, 0x37, 0x04, 0x1d, 0x1a, 0x37, + 0x2f, 0x20, 0x41, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x69, 0x66, 0x69, 0x65, 0x64, 0x20, + 0x62, 0x6f, 0x64, 0x79, 0x20, 0x28, 0x69, 0x66, 0x20, 0x61, 0x6e, 0x79, 0x29, 0x20, 0x74, 0x6f, + 0x20, 0x61, 0x64, 0x64, 0x20, 0x74, 0x6f, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x48, 0x74, 0x74, + 0x70, 0x54, 0x61, 0x73, 0x6b, 0x2e, 0x0a, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x00, 0x02, + 0x03, 0x04, 0x12, 0x03, 0x37, 0x04, 0x0c, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x00, 0x02, + 0x03, 0x05, 0x12, 0x03, 0x37, 0x0d, 0x13, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x00, 0x02, + 0x03, 0x01, 0x12, 0x03, 0x37, 0x14, 0x18, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x00, 0x02, + 0x03, 0x03, 0x12, 0x03, 0x37, 0x1b, 0x1c, 0x0a, 0x95, 0x03, 0x0a, 0x04, 0x04, 0x00, 0x03, 0x01, + 0x12, 0x04, 0x48, 0x02, 0x5d, 0x03, 0x1a, 0x86, 0x03, 0x0a, 0x54, 0x68, 0x65, 0x20, 0x61, 0x64, + 0x61, 0x70, 0x74, 0x65, 0x72, 0x20, 0x77, 0x61, 0x6c, 0x6b, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x70, 0x61, 0x74, 0x68, 0x20, 0x73, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x65, 0x64, 0x20, 0x61, + 0x6e, 0x64, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x76, + 0x61, 0x6c, 0x75, 0x65, 0x20, 0x66, 0x6f, 0x75, 0x6e, 0x64, 0x20, 0x61, 0x74, 0x20, 0x74, 0x68, + 0x61, 0x74, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x2e, 0x20, 0x49, 0x66, 0x20, 0x72, 0x65, + 0x74, 0x75, 0x72, 0x6e, 0x69, 0x6e, 0x67, 0x0a, 0x4a, 0x53, 0x4f, 0x4e, 0x20, 0x64, 0x61, 0x74, + 0x61, 0x20, 0x66, 0x72, 0x6f, 0x6d, 0x20, 0x74, 0x68, 0x65, 0x20, 0x48, 0x74, 0x74, 0x70, 0x47, + 0x65, 0x74, 0x20, 0x6f, 0x72, 0x20, 0x48, 0x74, 0x74, 0x70, 0x50, 0x6f, 0x73, 0x74, 0x20, 0x61, + 0x64, 0x61, 0x70, 0x74, 0x65, 0x72, 0x73, 0x2c, 0x20, 0x79, 0x6f, 0x75, 0x20, 0x6d, 0x75, 0x73, + 0x74, 0x20, 0x75, 0x73, 0x65, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x61, 0x64, 0x61, 0x70, 0x74, + 0x65, 0x72, 0x20, 0x74, 0x6f, 0x20, 0x70, 0x61, 0x72, 0x73, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x0a, 0x0a, 0x5f, 0x2a, 0x2a, 0x49, 0x6e, + 0x70, 0x75, 0x74, 0x2a, 0x2a, 0x5f, 0x3a, 0x20, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x20, 0x72, + 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6f, 0x66, + 0x20, 0x61, 0x20, 0x4a, 0x53, 0x4f, 0x4e, 0x20, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x2e, 0x0a, + 0x0a, 0x5f, 0x2a, 0x2a, 0x52, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x73, 0x2a, 0x2a, 0x5f, 0x3a, 0x20, + 0x41, 0x20, 0x6e, 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x6c, 0x20, 0x72, 0x65, 0x73, 0x75, + 0x6c, 0x74, 0x2e, 0x0a, 0x0a, 0x5f, 0x2a, 0x2a, 0x45, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2a, + 0x2a, 0x5f, 0x3a, 0x20, 0x50, 0x61, 0x72, 0x73, 0x65, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, + 0x72, 0x69, 0x63, 0x65, 0x20, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x66, 0x72, 0x6f, 0x6d, 0x20, + 0x61, 0x20, 0x4a, 0x53, 0x4f, 0x4e, 0x20, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x0a, 0x0a, 0x60, + 0x60, 0x60, 0x6a, 0x73, 0x6f, 0x6e, 0x0a, 0x7b, 0x22, 0x6a, 0x73, 0x6f, 0x6e, 0x50, 0x61, 0x72, + 0x73, 0x65, 0x22, 0x3a, 0x20, 0x7b, 0x22, 0x70, 0x61, 0x74, 0x68, 0x22, 0x3a, 0x20, 0x22, 0x24, + 0x2e, 0x70, 0x72, 0x69, 0x63, 0x65, 0x22, 0x7d, 0x20, 0x7d, 0x0a, 0x60, 0x60, 0x60, 0x0a, 0x0a, + 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x03, 0x01, 0x01, 0x12, 0x03, 0x48, 0x0a, 0x17, 0x0a, 0x79, 0x0a, + 0x06, 0x04, 0x00, 0x03, 0x01, 0x02, 0x00, 0x12, 0x03, 0x4b, 0x04, 0x1d, 0x1a, 0x6a, 0x2f, 0x20, + 0x4a, 0x53, 0x4f, 0x4e, 0x50, 0x61, 0x74, 0x68, 0x20, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x74, + 0x65, 0x64, 0x20, 0x70, 0x61, 0x74, 0x68, 0x20, 0x74, 0x6f, 0x20, 0x74, 0x68, 0x65, 0x20, 0x65, + 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x20, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, + 0x74, 0x2e, 0x6c, 0x79, 0x2f, 0x75, 0x4c, 0x74, 0x77, 0x0a, 0x2f, 0x20, 0x68, 0x74, 0x74, 0x70, + 0x73, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x6e, 0x70, 0x6d, 0x6a, 0x73, 0x2e, 0x63, 0x6f, + 0x6d, 0x2f, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x2f, 0x6a, 0x73, 0x6f, 0x6e, 0x70, 0x61, + 0x74, 0x68, 0x2d, 0x70, 0x6c, 0x75, 0x73, 0x0a, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x01, + 0x02, 0x00, 0x04, 0x12, 0x03, 0x4b, 0x04, 0x0c, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x01, + 0x02, 0x00, 0x05, 0x12, 0x03, 0x4b, 0x0d, 0x13, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x01, + 0x02, 0x00, 0x01, 0x12, 0x03, 0x4b, 0x14, 0x18, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x01, + 0x02, 0x00, 0x03, 0x12, 0x03, 0x4b, 0x1b, 0x1c, 0x0a, 0x48, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x01, + 0x04, 0x00, 0x12, 0x04, 0x4e, 0x04, 0x5a, 0x05, 0x1a, 0x38, 0x2f, 0x20, 0x54, 0x68, 0x65, 0x20, + 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x73, 0x20, 0x6f, 0x66, 0x20, 0x63, 0x6f, 0x6d, 0x62, 0x69, + 0x6e, 0x69, 0x6e, 0x67, 0x20, 0x61, 0x20, 0x6c, 0x69, 0x73, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x6e, + 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x6c, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, + 0x2e, 0x0a, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x01, 0x04, 0x00, 0x01, 0x12, 0x03, 0x4e, + 0x09, 0x1a, 0x0a, 0x0f, 0x0a, 0x08, 0x04, 0x00, 0x03, 0x01, 0x04, 0x00, 0x02, 0x00, 0x12, 0x03, + 0x4f, 0x06, 0x0f, 0x0a, 0x10, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x01, 0x04, 0x00, 0x02, 0x00, 0x01, + 0x12, 0x03, 0x4f, 0x06, 0x0a, 0x0a, 0x10, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x01, 0x04, 0x00, 0x02, + 0x00, 0x02, 0x12, 0x03, 0x4f, 0x0d, 0x0e, 0x0a, 0x3a, 0x0a, 0x08, 0x04, 0x00, 0x03, 0x01, 0x04, + 0x00, 0x02, 0x01, 0x12, 0x03, 0x51, 0x06, 0x0e, 0x1a, 0x29, 0x2f, 0x20, 0x47, 0x72, 0x61, 0x62, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x6d, 0x69, 0x6e, 0x69, 0x6d, 0x75, 0x6d, 0x20, 0x76, 0x61, 0x6c, + 0x75, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, + 0x73, 0x2e, 0x0a, 0x0a, 0x10, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x01, 0x04, 0x00, 0x02, 0x01, 0x01, + 0x12, 0x03, 0x51, 0x06, 0x09, 0x0a, 0x10, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x01, 0x04, 0x00, 0x02, + 0x01, 0x02, 0x12, 0x03, 0x51, 0x0c, 0x0d, 0x0a, 0x3a, 0x0a, 0x08, 0x04, 0x00, 0x03, 0x01, 0x04, + 0x00, 0x02, 0x02, 0x12, 0x03, 0x53, 0x06, 0x0e, 0x1a, 0x29, 0x2f, 0x20, 0x47, 0x72, 0x61, 0x62, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x6d, 0x61, 0x78, 0x69, 0x6d, 0x75, 0x6d, 0x20, 0x76, 0x61, 0x6c, + 0x75, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, + 0x73, 0x2e, 0x0a, 0x0a, 0x10, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x01, 0x04, 0x00, 0x02, 0x02, 0x01, + 0x12, 0x03, 0x53, 0x06, 0x09, 0x0a, 0x10, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x01, 0x04, 0x00, 0x02, + 0x02, 0x02, 0x12, 0x03, 0x53, 0x0c, 0x0d, 0x0a, 0x2e, 0x0a, 0x08, 0x04, 0x00, 0x03, 0x01, 0x04, + 0x00, 0x02, 0x03, 0x12, 0x03, 0x55, 0x06, 0x0e, 0x1a, 0x1d, 0x2f, 0x20, 0x53, 0x75, 0x6d, 0x20, + 0x75, 0x70, 0x20, 0x61, 0x6c, 0x6c, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x72, 0x65, + 0x73, 0x75, 0x6c, 0x74, 0x73, 0x2e, 0x0a, 0x0a, 0x10, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x01, 0x04, + 0x00, 0x02, 0x03, 0x01, 0x12, 0x03, 0x55, 0x06, 0x09, 0x0a, 0x10, 0x0a, 0x09, 0x04, 0x00, 0x03, + 0x01, 0x04, 0x00, 0x02, 0x03, 0x02, 0x12, 0x03, 0x55, 0x0c, 0x0d, 0x0a, 0x2f, 0x0a, 0x08, 0x04, + 0x00, 0x03, 0x01, 0x04, 0x00, 0x02, 0x04, 0x12, 0x03, 0x57, 0x06, 0x0f, 0x1a, 0x1e, 0x2f, 0x20, + 0x41, 0x76, 0x65, 0x72, 0x61, 0x67, 0x65, 0x20, 0x61, 0x6c, 0x6c, 0x20, 0x6f, 0x66, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x2e, 0x0a, 0x0a, 0x10, 0x0a, 0x09, + 0x04, 0x00, 0x03, 0x01, 0x04, 0x00, 0x02, 0x04, 0x01, 0x12, 0x03, 0x57, 0x06, 0x0a, 0x0a, 0x10, + 0x0a, 0x09, 0x04, 0x00, 0x03, 0x01, 0x04, 0x00, 0x02, 0x04, 0x02, 0x12, 0x03, 0x57, 0x0d, 0x0e, + 0x0a, 0x33, 0x0a, 0x08, 0x04, 0x00, 0x03, 0x01, 0x04, 0x00, 0x02, 0x05, 0x12, 0x03, 0x59, 0x06, + 0x11, 0x1a, 0x22, 0x2f, 0x20, 0x47, 0x72, 0x61, 0x62, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6d, 0x65, + 0x64, 0x69, 0x61, 0x6e, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x72, 0x65, 0x73, 0x75, + 0x6c, 0x74, 0x73, 0x2e, 0x0a, 0x0a, 0x10, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x01, 0x04, 0x00, 0x02, + 0x05, 0x01, 0x12, 0x03, 0x59, 0x06, 0x0c, 0x0a, 0x10, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x01, 0x04, + 0x00, 0x02, 0x05, 0x02, 0x12, 0x03, 0x59, 0x0f, 0x10, 0x0a, 0x8c, 0x01, 0x0a, 0x06, 0x04, 0x00, + 0x03, 0x01, 0x02, 0x01, 0x12, 0x03, 0x5c, 0x04, 0x36, 0x1a, 0x7d, 0x2f, 0x20, 0x54, 0x68, 0x65, + 0x20, 0x74, 0x65, 0x63, 0x68, 0x6e, 0x69, 0x71, 0x75, 0x65, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, + 0x77, 0x69, 0x6c, 0x6c, 0x20, 0x62, 0x65, 0x20, 0x75, 0x73, 0x65, 0x64, 0x20, 0x74, 0x6f, 0x20, + 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x72, 0x65, + 0x73, 0x75, 0x6c, 0x74, 0x73, 0x20, 0x69, 0x66, 0x20, 0x77, 0x61, 0x6c, 0x6b, 0x69, 0x6e, 0x67, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x65, 0x64, 0x20, 0x70, + 0x61, 0x74, 0x68, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x73, 0x20, 0x6d, 0x75, 0x6c, 0x74, + 0x69, 0x70, 0x6c, 0x65, 0x20, 0x6e, 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x6c, 0x20, 0x72, + 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x2e, 0x0a, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x01, + 0x02, 0x01, 0x04, 0x12, 0x03, 0x5c, 0x04, 0x0c, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x01, + 0x02, 0x01, 0x06, 0x12, 0x03, 0x5c, 0x0d, 0x1e, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x01, + 0x02, 0x01, 0x01, 0x12, 0x03, 0x5c, 0x1f, 0x31, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x01, + 0x02, 0x01, 0x03, 0x12, 0x03, 0x5c, 0x34, 0x35, 0x0a, 0x84, 0x07, 0x0a, 0x04, 0x04, 0x00, 0x03, + 0x02, 0x12, 0x04, 0x72, 0x02, 0x7b, 0x03, 0x1a, 0xf5, 0x06, 0x0a, 0x52, 0x65, 0x74, 0x75, 0x72, + 0x6e, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x6e, 0x20, 0x28, 0x6d, + 0x69, 0x64, 0x64, 0x6c, 0x65, 0x29, 0x20, 0x6f, 0x66, 0x20, 0x61, 0x6c, 0x6c, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, + 0x65, 0x64, 0x20, 0x62, 0x79, 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, + 0x65, 0x64, 0x20, 0x73, 0x75, 0x62, 0x74, 0x61, 0x73, 0x6b, 0x73, 0x20, 0x61, 0x6e, 0x64, 0x20, + 0x73, 0x75, 0x62, 0x6a, 0x6f, 0x62, 0x73, 0x2e, 0x20, 0x4e, 0x65, 0x73, 0x74, 0x65, 0x64, 0x20, + 0x74, 0x61, 0x73, 0x6b, 0x73, 0x20, 0x6d, 0x75, 0x73, 0x74, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, + 0x6e, 0x20, 0x61, 0x20, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x2e, 0x0a, 0x0a, 0x5f, 0x2a, 0x2a, + 0x49, 0x6e, 0x70, 0x75, 0x74, 0x2a, 0x2a, 0x5f, 0x3a, 0x20, 0x4e, 0x6f, 0x6e, 0x65, 0x0a, 0x0a, + 0x5f, 0x2a, 0x2a, 0x52, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x73, 0x2a, 0x2a, 0x5f, 0x3a, 0x20, 0x41, + 0x20, 0x6e, 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x6c, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, + 0x74, 0x2e, 0x0a, 0x0a, 0x5f, 0x2a, 0x2a, 0x45, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2a, 0x2a, + 0x5f, 0x3a, 0x20, 0x52, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6d, + 0x65, 0x64, 0x69, 0x61, 0x6e, 0x20, 0x6e, 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x6c, 0x20, + 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x33, 0x20, 0x74, 0x61, 0x73, 0x6b, + 0x73, 0x2e, 0x0a, 0x0a, 0x60, 0x60, 0x60, 0x6a, 0x73, 0x6f, 0x6e, 0x0a, 0x7b, 0x22, 0x6d, 0x65, + 0x64, 0x69, 0x61, 0x6e, 0x54, 0x61, 0x73, 0x6b, 0x22, 0x3a, 0x20, 0x7b, 0x22, 0x74, 0x61, 0x73, + 0x6b, 0x73, 0x22, 0x3a, 0x20, 0x5b, 0x7b, 0x22, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x54, 0x61, 0x73, + 0x6b, 0x22, 0x3a, 0x20, 0x7b, 0x22, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x3a, 0x20, 0x31, 0x30, + 0x7d, 0x7d, 0x2c, 0x7b, 0x22, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x22, 0x3a, + 0x20, 0x7b, 0x22, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x3a, 0x20, 0x32, 0x30, 0x7d, 0x7d, 0x2c, + 0x7b, 0x22, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x22, 0x3a, 0x20, 0x7b, 0x22, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x3a, 0x20, 0x33, 0x30, 0x7d, 0x7d, 0x5d, 0x7d, 0x7d, 0x0a, + 0x60, 0x60, 0x60, 0x0a, 0x0a, 0x5f, 0x2a, 0x2a, 0x45, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2a, + 0x2a, 0x5f, 0x3a, 0x20, 0x52, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x6d, 0x65, 0x64, 0x69, 0x61, 0x6e, 0x20, 0x6e, 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x6c, + 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x33, 0x20, 0x6a, 0x6f, 0x62, + 0x73, 0x2e, 0x0a, 0x0a, 0x60, 0x60, 0x60, 0x6a, 0x73, 0x6f, 0x6e, 0x0a, 0x7b, 0x22, 0x6d, 0x65, + 0x64, 0x69, 0x61, 0x6e, 0x54, 0x61, 0x73, 0x6b, 0x22, 0x3a, 0x20, 0x7b, 0x22, 0x6a, 0x6f, 0x62, + 0x73, 0x22, 0x3a, 0x20, 0x5b, 0x7b, 0x22, 0x74, 0x61, 0x73, 0x6b, 0x73, 0x22, 0x3a, 0x20, 0x5b, + 0x7b, 0x22, 0x68, 0x74, 0x74, 0x70, 0x54, 0x61, 0x73, 0x6b, 0x22, 0x3a, 0x20, 0x7b, 0x22, 0x75, + 0x72, 0x6c, 0x22, 0x3a, 0x20, 0x22, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x77, 0x77, + 0x77, 0x2e, 0x62, 0x69, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x61, 0x70, + 0x69, 0x2f, 0x76, 0x33, 0x2f, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x72, 0x2f, 0x70, 0x72, 0x69, 0x63, + 0x65, 0x3f, 0x73, 0x79, 0x6d, 0x62, 0x6f, 0x6c, 0x3d, 0x53, 0x4f, 0x4c, 0x55, 0x53, 0x44, 0x54, + 0x22, 0x7d, 0x7d, 0x2c, 0x7b, 0x22, 0x6a, 0x73, 0x6f, 0x6e, 0x50, 0x61, 0x72, 0x73, 0x65, 0x54, + 0x61, 0x73, 0x6b, 0x22, 0x3a, 0x20, 0x7b, 0x22, 0x70, 0x61, 0x74, 0x68, 0x22, 0x3a, 0x20, 0x22, + 0x24, 0x2e, 0x70, 0x72, 0x69, 0x63, 0x65, 0x22, 0x7d, 0x7d, 0x5d, 0x7d, 0x2c, 0x7b, 0x22, 0x74, + 0x61, 0x73, 0x6b, 0x73, 0x22, 0x3a, 0x20, 0x5b, 0x7b, 0x22, 0x68, 0x74, 0x74, 0x70, 0x54, 0x61, + 0x73, 0x6b, 0x22, 0x3a, 0x20, 0x7b, 0x22, 0x75, 0x72, 0x6c, 0x22, 0x3a, 0x20, 0x22, 0x68, 0x74, + 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x62, 0x69, 0x6e, 0x61, 0x6e, 0x63, + 0x65, 0x2e, 0x75, 0x73, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x33, 0x2f, 0x74, 0x69, 0x63, 0x6b, + 0x65, 0x72, 0x2f, 0x70, 0x72, 0x69, 0x63, 0x65, 0x3f, 0x73, 0x79, 0x6d, 0x62, 0x6f, 0x6c, 0x3d, + 0x53, 0x4f, 0x4c, 0x55, 0x53, 0x44, 0x22, 0x7d, 0x7d, 0x2c, 0x7b, 0x22, 0x6a, 0x73, 0x6f, 0x6e, + 0x50, 0x61, 0x72, 0x73, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x22, 0x3a, 0x20, 0x7b, 0x22, 0x70, 0x61, + 0x74, 0x68, 0x22, 0x3a, 0x20, 0x22, 0x24, 0x2e, 0x70, 0x72, 0x69, 0x63, 0x65, 0x22, 0x7d, 0x7d, + 0x5d, 0x7d, 0x2c, 0x7b, 0x22, 0x74, 0x61, 0x73, 0x6b, 0x73, 0x22, 0x3a, 0x20, 0x5b, 0x7b, 0x22, + 0x68, 0x74, 0x74, 0x70, 0x54, 0x61, 0x73, 0x6b, 0x22, 0x3a, 0x20, 0x7b, 0x22, 0x75, 0x72, 0x6c, + 0x22, 0x3a, 0x20, 0x22, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x61, 0x70, 0x69, 0x2d, + 0x70, 0x75, 0x62, 0x2e, 0x62, 0x69, 0x74, 0x66, 0x69, 0x6e, 0x65, 0x78, 0x2e, 0x63, 0x6f, 0x6d, + 0x2f, 0x76, 0x32, 0x2f, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x72, 0x73, 0x3f, 0x73, 0x79, 0x6d, 0x62, + 0x6f, 0x6c, 0x73, 0x3d, 0x74, 0x53, 0x4f, 0x4c, 0x55, 0x53, 0x44, 0x22, 0x7d, 0x7d, 0x2c, 0x7b, + 0x22, 0x6a, 0x73, 0x6f, 0x6e, 0x50, 0x61, 0x72, 0x73, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x22, 0x3a, + 0x20, 0x7b, 0x22, 0x70, 0x61, 0x74, 0x68, 0x22, 0x3a, 0x20, 0x22, 0x24, 0x5b, 0x30, 0x5d, 0x5b, + 0x37, 0x5d, 0x22, 0x7d, 0x7d, 0x5d, 0x7d, 0x5d, 0x7d, 0x7d, 0x0a, 0x60, 0x60, 0x60, 0x0a, 0x0a, + 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x03, 0x02, 0x01, 0x12, 0x03, 0x72, 0x0a, 0x14, 0x0a, 0x54, 0x0a, + 0x06, 0x04, 0x00, 0x03, 0x02, 0x02, 0x00, 0x12, 0x03, 0x74, 0x04, 0x1c, 0x1a, 0x45, 0x2f, 0x20, + 0x41, 0x20, 0x6c, 0x69, 0x73, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x73, 0x75, 0x62, 0x74, 0x61, 0x73, + 0x6b, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x20, 0x61, 0x6e, + 0x64, 0x20, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x65, 0x20, 0x61, 0x20, 0x6c, 0x69, 0x73, 0x74, + 0x20, 0x6f, 0x66, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, + 0x73, 0x2e, 0x0a, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x02, 0x02, 0x00, 0x04, 0x12, 0x03, + 0x74, 0x04, 0x0c, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x02, 0x02, 0x00, 0x06, 0x12, 0x03, + 0x74, 0x0d, 0x11, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x02, 0x02, 0x00, 0x01, 0x12, 0x03, + 0x74, 0x12, 0x17, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x02, 0x02, 0x00, 0x03, 0x12, 0x03, + 0x74, 0x1a, 0x1b, 0x0a, 0x53, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x02, 0x02, 0x01, 0x12, 0x03, 0x76, + 0x04, 0x20, 0x1a, 0x44, 0x2f, 0x20, 0x41, 0x20, 0x6c, 0x69, 0x73, 0x74, 0x20, 0x6f, 0x66, 0x20, + 0x73, 0x75, 0x62, 0x6a, 0x6f, 0x62, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x70, 0x72, 0x6f, 0x63, 0x65, + 0x73, 0x73, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x65, 0x20, 0x61, + 0x20, 0x6c, 0x69, 0x73, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x20, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x2e, 0x0a, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x02, + 0x02, 0x01, 0x04, 0x12, 0x03, 0x76, 0x04, 0x0c, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x02, + 0x02, 0x01, 0x06, 0x12, 0x03, 0x76, 0x0d, 0x16, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x02, + 0x02, 0x01, 0x01, 0x12, 0x03, 0x76, 0x17, 0x1b, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x02, + 0x02, 0x01, 0x03, 0x12, 0x03, 0x76, 0x1e, 0x1f, 0x0a, 0x59, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x02, + 0x02, 0x02, 0x12, 0x03, 0x78, 0x04, 0x2f, 0x1a, 0x4a, 0x2f, 0x20, 0x54, 0x68, 0x65, 0x20, 0x6d, + 0x69, 0x6e, 0x69, 0x6d, 0x75, 0x6d, 0x20, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x20, 0x6f, 0x66, + 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x20, 0x62, 0x65, 0x66, 0x6f, 0x72, 0x65, 0x20, 0x61, + 0x20, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x66, 0x75, 0x6c, 0x20, 0x6d, 0x65, 0x64, 0x69, + 0x61, 0x6e, 0x20, 0x63, 0x61, 0x6e, 0x20, 0x62, 0x65, 0x20, 0x79, 0x69, 0x65, 0x6c, 0x64, 0x65, + 0x64, 0x2e, 0x0a, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x02, 0x02, 0x02, 0x04, 0x12, 0x03, + 0x78, 0x04, 0x0c, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x02, 0x02, 0x02, 0x05, 0x12, 0x03, + 0x78, 0x0d, 0x12, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x02, 0x02, 0x02, 0x01, 0x12, 0x03, + 0x78, 0x13, 0x2a, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x02, 0x02, 0x02, 0x03, 0x12, 0x03, + 0x78, 0x2d, 0x2e, 0x0a, 0x75, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x02, 0x02, 0x03, 0x12, 0x03, 0x7a, + 0x04, 0x2a, 0x1a, 0x66, 0x2f, 0x20, 0x54, 0x68, 0x65, 0x20, 0x6d, 0x61, 0x78, 0x69, 0x6d, 0x75, + 0x6d, 0x20, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x20, 0x62, 0x65, 0x74, 0x77, 0x65, 0x65, 0x6e, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x6d, 0x69, 0x6e, 0x69, 0x6d, 0x75, 0x6d, 0x20, 0x61, 0x6e, 0x64, 0x20, + 0x6d, 0x61, 0x78, 0x69, 0x6d, 0x75, 0x6d, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x20, 0x62, + 0x65, 0x66, 0x6f, 0x72, 0x65, 0x20, 0x61, 0x20, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x66, + 0x75, 0x6c, 0x20, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x6e, 0x20, 0x63, 0x61, 0x6e, 0x20, 0x62, 0x65, + 0x20, 0x79, 0x69, 0x65, 0x6c, 0x64, 0x65, 0x64, 0x2e, 0x0a, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x00, + 0x03, 0x02, 0x02, 0x03, 0x04, 0x12, 0x03, 0x7a, 0x04, 0x0c, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x00, + 0x03, 0x02, 0x02, 0x03, 0x05, 0x12, 0x03, 0x7a, 0x0d, 0x13, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x00, + 0x03, 0x02, 0x02, 0x03, 0x01, 0x12, 0x03, 0x7a, 0x14, 0x25, 0x0a, 0x0e, 0x0a, 0x07, 0x04, 0x00, + 0x03, 0x02, 0x02, 0x03, 0x03, 0x12, 0x03, 0x7a, 0x28, 0x29, 0x0a, 0x85, 0x07, 0x0a, 0x04, 0x04, + 0x00, 0x03, 0x03, 0x12, 0x06, 0x90, 0x01, 0x02, 0x95, 0x01, 0x03, 0x1a, 0xf4, 0x06, 0x0a, 0x52, + 0x65, 0x74, 0x75, 0x72, 0x6e, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6d, 0x65, 0x61, 0x6e, 0x20, + 0x28, 0x61, 0x76, 0x65, 0x72, 0x61, 0x67, 0x65, 0x29, 0x20, 0x6f, 0x66, 0x20, 0x61, 0x6c, 0x6c, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x20, 0x72, 0x65, 0x74, + 0x75, 0x72, 0x6e, 0x65, 0x64, 0x20, 0x62, 0x79, 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x72, 0x6f, + 0x76, 0x69, 0x64, 0x65, 0x64, 0x20, 0x73, 0x75, 0x62, 0x74, 0x61, 0x73, 0x6b, 0x73, 0x20, 0x61, + 0x6e, 0x64, 0x20, 0x73, 0x75, 0x62, 0x6a, 0x6f, 0x62, 0x73, 0x2e, 0x20, 0x4e, 0x65, 0x73, 0x74, + 0x65, 0x64, 0x20, 0x74, 0x61, 0x73, 0x6b, 0x73, 0x20, 0x6f, 0x72, 0x20, 0x6a, 0x6f, 0x62, 0x73, + 0x20, 0x6d, 0x75, 0x73, 0x74, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x61, 0x20, 0x4e, + 0x75, 0x6d, 0x62, 0x65, 0x72, 0x2e, 0x0a, 0x0a, 0x5f, 0x2a, 0x2a, 0x49, 0x6e, 0x70, 0x75, 0x74, + 0x2a, 0x2a, 0x5f, 0x3a, 0x20, 0x4e, 0x6f, 0x6e, 0x65, 0x0a, 0x0a, 0x5f, 0x2a, 0x2a, 0x52, 0x65, + 0x74, 0x75, 0x72, 0x6e, 0x73, 0x2a, 0x2a, 0x5f, 0x3a, 0x20, 0x41, 0x20, 0x6e, 0x75, 0x6d, 0x65, + 0x72, 0x69, 0x63, 0x61, 0x6c, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x2e, 0x0a, 0x0a, 0x5f, + 0x2a, 0x2a, 0x45, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2a, 0x2a, 0x5f, 0x3a, 0x20, 0x52, 0x65, + 0x74, 0x75, 0x72, 0x6e, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6d, 0x65, 0x61, 0x6e, 0x20, 0x6e, + 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x6c, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x20, + 0x6f, 0x66, 0x20, 0x33, 0x20, 0x74, 0x61, 0x73, 0x6b, 0x73, 0x2e, 0x0a, 0x0a, 0x60, 0x60, 0x60, + 0x6a, 0x73, 0x6f, 0x6e, 0x0a, 0x7b, 0x22, 0x6d, 0x65, 0x61, 0x6e, 0x54, 0x61, 0x73, 0x6b, 0x22, + 0x3a, 0x20, 0x7b, 0x22, 0x74, 0x61, 0x73, 0x6b, 0x73, 0x22, 0x3a, 0x20, 0x5b, 0x7b, 0x22, 0x76, + 0x61, 0x6c, 0x75, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x22, 0x3a, 0x20, 0x7b, 0x22, 0x76, 0x61, 0x6c, + 0x75, 0x65, 0x22, 0x3a, 0x20, 0x31, 0x30, 0x7d, 0x7d, 0x2c, 0x7b, 0x22, 0x76, 0x61, 0x6c, 0x75, + 0x65, 0x54, 0x61, 0x73, 0x6b, 0x22, 0x3a, 0x20, 0x7b, 0x22, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, + 0x3a, 0x20, 0x32, 0x30, 0x7d, 0x7d, 0x2c, 0x7b, 0x22, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x54, 0x61, + 0x73, 0x6b, 0x22, 0x3a, 0x20, 0x7b, 0x22, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x3a, 0x20, 0x33, + 0x30, 0x7d, 0x7d, 0x5d, 0x7d, 0x7d, 0x0a, 0x60, 0x60, 0x60, 0x0a, 0x0a, 0x5f, 0x2a, 0x2a, 0x45, + 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2a, 0x2a, 0x5f, 0x3a, 0x20, 0x52, 0x65, 0x74, 0x75, 0x72, + 0x6e, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6d, 0x65, 0x61, 0x6e, 0x20, 0x6e, 0x75, 0x6d, 0x65, + 0x72, 0x69, 0x63, 0x61, 0x6c, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x20, 0x6f, 0x66, 0x20, + 0x33, 0x20, 0x6a, 0x6f, 0x62, 0x73, 0x2e, 0x0a, 0x0a, 0x60, 0x60, 0x60, 0x6a, 0x73, 0x6f, 0x6e, + 0x0a, 0x7b, 0x22, 0x6d, 0x65, 0x61, 0x6e, 0x54, 0x61, 0x73, 0x6b, 0x22, 0x3a, 0x20, 0x7b, 0x22, + 0x6a, 0x6f, 0x62, 0x73, 0x22, 0x3a, 0x20, 0x5b, 0x7b, 0x22, 0x74, 0x61, 0x73, 0x6b, 0x73, 0x22, + 0x3a, 0x20, 0x5b, 0x7b, 0x22, 0x68, 0x74, 0x74, 0x70, 0x54, 0x61, 0x73, 0x6b, 0x22, 0x3a, 0x20, + 0x7b, 0x22, 0x75, 0x72, 0x6c, 0x22, 0x3a, 0x20, 0x22, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, + 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x62, 0x69, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x2e, 0x63, 0x6f, 0x6d, + 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x33, 0x2f, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x72, 0x2f, 0x70, + 0x72, 0x69, 0x63, 0x65, 0x3f, 0x73, 0x79, 0x6d, 0x62, 0x6f, 0x6c, 0x3d, 0x53, 0x4f, 0x4c, 0x55, + 0x53, 0x44, 0x54, 0x22, 0x7d, 0x7d, 0x2c, 0x7b, 0x22, 0x6a, 0x73, 0x6f, 0x6e, 0x50, 0x61, 0x72, + 0x73, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x22, 0x3a, 0x20, 0x7b, 0x22, 0x70, 0x61, 0x74, 0x68, 0x22, + 0x3a, 0x20, 0x22, 0x24, 0x2e, 0x70, 0x72, 0x69, 0x63, 0x65, 0x22, 0x7d, 0x7d, 0x5d, 0x7d, 0x2c, + 0x7b, 0x22, 0x74, 0x61, 0x73, 0x6b, 0x73, 0x22, 0x3a, 0x20, 0x5b, 0x7b, 0x22, 0x68, 0x74, 0x74, + 0x70, 0x54, 0x61, 0x73, 0x6b, 0x22, 0x3a, 0x20, 0x7b, 0x22, 0x75, 0x72, 0x6c, 0x22, 0x3a, 0x20, + 0x22, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x62, 0x69, 0x6e, + 0x61, 0x6e, 0x63, 0x65, 0x2e, 0x75, 0x73, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x33, 0x2f, 0x74, + 0x69, 0x63, 0x6b, 0x65, 0x72, 0x2f, 0x70, 0x72, 0x69, 0x63, 0x65, 0x3f, 0x73, 0x79, 0x6d, 0x62, + 0x6f, 0x6c, 0x3d, 0x53, 0x4f, 0x4c, 0x55, 0x53, 0x44, 0x22, 0x7d, 0x7d, 0x2c, 0x7b, 0x22, 0x6a, + 0x73, 0x6f, 0x6e, 0x50, 0x61, 0x72, 0x73, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x22, 0x3a, 0x20, 0x7b, + 0x22, 0x70, 0x61, 0x74, 0x68, 0x22, 0x3a, 0x20, 0x22, 0x24, 0x2e, 0x70, 0x72, 0x69, 0x63, 0x65, + 0x22, 0x7d, 0x7d, 0x5d, 0x7d, 0x2c, 0x7b, 0x22, 0x74, 0x61, 0x73, 0x6b, 0x73, 0x22, 0x3a, 0x20, + 0x5b, 0x7b, 0x22, 0x68, 0x74, 0x74, 0x70, 0x54, 0x61, 0x73, 0x6b, 0x22, 0x3a, 0x20, 0x7b, 0x22, + 0x75, 0x72, 0x6c, 0x22, 0x3a, 0x20, 0x22, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x61, + 0x70, 0x69, 0x2d, 0x70, 0x75, 0x62, 0x2e, 0x62, 0x69, 0x74, 0x66, 0x69, 0x6e, 0x65, 0x78, 0x2e, + 0x63, 0x6f, 0x6d, 0x2f, 0x76, 0x32, 0x2f, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x72, 0x73, 0x3f, 0x73, + 0x79, 0x6d, 0x62, 0x6f, 0x6c, 0x73, 0x3d, 0x74, 0x53, 0x4f, 0x4c, 0x55, 0x53, 0x44, 0x22, 0x7d, + 0x7d, 0x2c, 0x7b, 0x22, 0x6a, 0x73, 0x6f, 0x6e, 0x50, 0x61, 0x72, 0x73, 0x65, 0x54, 0x61, 0x73, + 0x6b, 0x22, 0x3a, 0x20, 0x7b, 0x22, 0x70, 0x61, 0x74, 0x68, 0x22, 0x3a, 0x20, 0x22, 0x24, 0x5b, + 0x30, 0x5d, 0x5b, 0x37, 0x5d, 0x22, 0x7d, 0x7d, 0x5d, 0x7d, 0x5d, 0x7d, 0x7d, 0x0a, 0x60, 0x60, + 0x60, 0x0a, 0x0a, 0x0d, 0x0a, 0x05, 0x04, 0x00, 0x03, 0x03, 0x01, 0x12, 0x04, 0x90, 0x01, 0x0a, + 0x12, 0x0a, 0x55, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x03, 0x02, 0x00, 0x12, 0x04, 0x92, 0x01, 0x04, + 0x1c, 0x1a, 0x45, 0x2f, 0x20, 0x41, 0x20, 0x6c, 0x69, 0x73, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x73, + 0x75, 0x62, 0x74, 0x61, 0x73, 0x6b, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x70, 0x72, 0x6f, 0x63, 0x65, + 0x73, 0x73, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x65, 0x20, 0x61, + 0x20, 0x6c, 0x69, 0x73, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x20, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x2e, 0x0a, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x03, + 0x02, 0x00, 0x04, 0x12, 0x04, 0x92, 0x01, 0x04, 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, + 0x03, 0x02, 0x00, 0x06, 0x12, 0x04, 0x92, 0x01, 0x0d, 0x11, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, + 0x03, 0x03, 0x02, 0x00, 0x01, 0x12, 0x04, 0x92, 0x01, 0x12, 0x17, 0x0a, 0x0f, 0x0a, 0x07, 0x04, + 0x00, 0x03, 0x03, 0x02, 0x00, 0x03, 0x12, 0x04, 0x92, 0x01, 0x1a, 0x1b, 0x0a, 0x54, 0x0a, 0x06, + 0x04, 0x00, 0x03, 0x03, 0x02, 0x01, 0x12, 0x04, 0x94, 0x01, 0x04, 0x20, 0x1a, 0x44, 0x2f, 0x20, + 0x41, 0x20, 0x6c, 0x69, 0x73, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x73, 0x75, 0x62, 0x6a, 0x6f, 0x62, + 0x73, 0x20, 0x74, 0x6f, 0x20, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x20, 0x61, 0x6e, 0x64, + 0x20, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x65, 0x20, 0x61, 0x20, 0x6c, 0x69, 0x73, 0x74, 0x20, + 0x6f, 0x66, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, + 0x2e, 0x0a, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x03, 0x02, 0x01, 0x04, 0x12, 0x04, 0x94, + 0x01, 0x04, 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x03, 0x02, 0x01, 0x06, 0x12, 0x04, + 0x94, 0x01, 0x0d, 0x16, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x03, 0x02, 0x01, 0x01, 0x12, + 0x04, 0x94, 0x01, 0x17, 0x1b, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x03, 0x02, 0x01, 0x03, + 0x12, 0x04, 0x94, 0x01, 0x1e, 0x1f, 0x0a, 0x8c, 0x07, 0x0a, 0x04, 0x04, 0x00, 0x03, 0x04, 0x12, + 0x06, 0xaa, 0x01, 0x02, 0xaf, 0x01, 0x03, 0x1a, 0xfb, 0x06, 0x0a, 0x52, 0x65, 0x74, 0x75, 0x72, + 0x6e, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6d, 0x61, 0x78, 0x69, 0x6d, 0x75, 0x6d, 0x20, 0x76, + 0x61, 0x6c, 0x75, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x61, 0x6c, 0x6c, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x65, 0x64, + 0x20, 0x62, 0x79, 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x64, + 0x20, 0x73, 0x75, 0x62, 0x74, 0x61, 0x73, 0x6b, 0x73, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x73, 0x75, + 0x62, 0x6a, 0x6f, 0x62, 0x73, 0x2e, 0x20, 0x4e, 0x65, 0x73, 0x74, 0x65, 0x64, 0x20, 0x74, 0x61, + 0x73, 0x6b, 0x73, 0x20, 0x6f, 0x72, 0x20, 0x6a, 0x6f, 0x62, 0x73, 0x20, 0x6d, 0x75, 0x73, 0x74, + 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x61, 0x20, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, + 0x2e, 0x0a, 0x0a, 0x5f, 0x2a, 0x2a, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x2a, 0x2a, 0x5f, 0x3a, 0x20, + 0x4e, 0x6f, 0x6e, 0x65, 0x0a, 0x0a, 0x5f, 0x2a, 0x2a, 0x52, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x73, + 0x2a, 0x2a, 0x5f, 0x3a, 0x20, 0x41, 0x20, 0x6e, 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x6c, + 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x2e, 0x0a, 0x0a, 0x5f, 0x2a, 0x2a, 0x45, 0x78, 0x61, + 0x6d, 0x70, 0x6c, 0x65, 0x2a, 0x2a, 0x5f, 0x3a, 0x20, 0x52, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x73, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x6d, 0x61, 0x78, 0x69, 0x6d, 0x75, 0x6d, 0x20, 0x6e, 0x75, 0x6d, + 0x65, 0x72, 0x69, 0x63, 0x61, 0x6c, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x20, 0x66, 0x72, + 0x6f, 0x6d, 0x20, 0x33, 0x20, 0x74, 0x61, 0x73, 0x6b, 0x73, 0x2e, 0x0a, 0x0a, 0x60, 0x60, 0x60, + 0x6a, 0x73, 0x6f, 0x6e, 0x0a, 0x7b, 0x22, 0x6d, 0x61, 0x78, 0x54, 0x61, 0x73, 0x6b, 0x22, 0x3a, + 0x20, 0x7b, 0x22, 0x74, 0x61, 0x73, 0x6b, 0x73, 0x22, 0x3a, 0x20, 0x5b, 0x7b, 0x22, 0x76, 0x61, + 0x6c, 0x75, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x22, 0x3a, 0x20, 0x7b, 0x22, 0x76, 0x61, 0x6c, 0x75, + 0x65, 0x22, 0x3a, 0x20, 0x31, 0x30, 0x7d, 0x7d, 0x2c, 0x7b, 0x22, 0x76, 0x61, 0x6c, 0x75, 0x65, + 0x54, 0x61, 0x73, 0x6b, 0x22, 0x3a, 0x20, 0x7b, 0x22, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x3a, + 0x20, 0x32, 0x30, 0x7d, 0x7d, 0x2c, 0x7b, 0x22, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x54, 0x61, 0x73, + 0x6b, 0x22, 0x3a, 0x20, 0x7b, 0x22, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x3a, 0x20, 0x33, 0x30, + 0x7d, 0x7d, 0x5d, 0x7d, 0x7d, 0x0a, 0x60, 0x60, 0x60, 0x0a, 0x0a, 0x5f, 0x2a, 0x2a, 0x45, 0x78, + 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2a, 0x2a, 0x5f, 0x3a, 0x20, 0x52, 0x65, 0x74, 0x75, 0x72, 0x6e, + 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6d, 0x61, 0x78, 0x69, 0x6d, 0x75, 0x6d, 0x20, 0x6e, 0x75, + 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x6c, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x20, 0x66, + 0x72, 0x6f, 0x6d, 0x20, 0x33, 0x20, 0x6a, 0x6f, 0x62, 0x73, 0x2e, 0x0a, 0x0a, 0x60, 0x60, 0x60, + 0x6a, 0x73, 0x6f, 0x6e, 0x0a, 0x7b, 0x22, 0x6d, 0x61, 0x78, 0x54, 0x61, 0x73, 0x6b, 0x22, 0x3a, + 0x20, 0x7b, 0x22, 0x6a, 0x6f, 0x62, 0x73, 0x22, 0x3a, 0x20, 0x5b, 0x7b, 0x22, 0x74, 0x61, 0x73, + 0x6b, 0x73, 0x22, 0x3a, 0x20, 0x5b, 0x7b, 0x22, 0x68, 0x74, 0x74, 0x70, 0x54, 0x61, 0x73, 0x6b, + 0x22, 0x3a, 0x20, 0x7b, 0x22, 0x75, 0x72, 0x6c, 0x22, 0x3a, 0x20, 0x22, 0x68, 0x74, 0x74, 0x70, + 0x73, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x62, 0x69, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x2e, + 0x63, 0x6f, 0x6d, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x33, 0x2f, 0x74, 0x69, 0x63, 0x6b, 0x65, + 0x72, 0x2f, 0x70, 0x72, 0x69, 0x63, 0x65, 0x3f, 0x73, 0x79, 0x6d, 0x62, 0x6f, 0x6c, 0x3d, 0x53, + 0x4f, 0x4c, 0x55, 0x53, 0x44, 0x54, 0x22, 0x7d, 0x7d, 0x2c, 0x7b, 0x22, 0x6a, 0x73, 0x6f, 0x6e, + 0x50, 0x61, 0x72, 0x73, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x22, 0x3a, 0x20, 0x7b, 0x22, 0x70, 0x61, + 0x74, 0x68, 0x22, 0x3a, 0x20, 0x22, 0x24, 0x2e, 0x70, 0x72, 0x69, 0x63, 0x65, 0x22, 0x7d, 0x7d, + 0x5d, 0x7d, 0x2c, 0x7b, 0x22, 0x74, 0x61, 0x73, 0x6b, 0x73, 0x22, 0x3a, 0x20, 0x5b, 0x7b, 0x22, + 0x68, 0x74, 0x74, 0x70, 0x54, 0x61, 0x73, 0x6b, 0x22, 0x3a, 0x20, 0x7b, 0x22, 0x75, 0x72, 0x6c, + 0x22, 0x3a, 0x20, 0x22, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, + 0x62, 0x69, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x2e, 0x75, 0x73, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, + 0x33, 0x2f, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x72, 0x2f, 0x70, 0x72, 0x69, 0x63, 0x65, 0x3f, 0x73, + 0x79, 0x6d, 0x62, 0x6f, 0x6c, 0x3d, 0x53, 0x4f, 0x4c, 0x55, 0x53, 0x44, 0x22, 0x7d, 0x7d, 0x2c, + 0x7b, 0x22, 0x6a, 0x73, 0x6f, 0x6e, 0x50, 0x61, 0x72, 0x73, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x22, + 0x3a, 0x20, 0x7b, 0x22, 0x70, 0x61, 0x74, 0x68, 0x22, 0x3a, 0x20, 0x22, 0x24, 0x2e, 0x70, 0x72, + 0x69, 0x63, 0x65, 0x22, 0x7d, 0x7d, 0x5d, 0x7d, 0x2c, 0x7b, 0x22, 0x74, 0x61, 0x73, 0x6b, 0x73, + 0x22, 0x3a, 0x20, 0x5b, 0x7b, 0x22, 0x68, 0x74, 0x74, 0x70, 0x54, 0x61, 0x73, 0x6b, 0x22, 0x3a, + 0x20, 0x7b, 0x22, 0x75, 0x72, 0x6c, 0x22, 0x3a, 0x20, 0x22, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, + 0x2f, 0x2f, 0x61, 0x70, 0x69, 0x2d, 0x70, 0x75, 0x62, 0x2e, 0x62, 0x69, 0x74, 0x66, 0x69, 0x6e, + 0x65, 0x78, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x76, 0x32, 0x2f, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x72, + 0x73, 0x3f, 0x73, 0x79, 0x6d, 0x62, 0x6f, 0x6c, 0x73, 0x3d, 0x74, 0x53, 0x4f, 0x4c, 0x55, 0x53, + 0x44, 0x22, 0x7d, 0x7d, 0x2c, 0x7b, 0x22, 0x6a, 0x73, 0x6f, 0x6e, 0x50, 0x61, 0x72, 0x73, 0x65, + 0x54, 0x61, 0x73, 0x6b, 0x22, 0x3a, 0x20, 0x7b, 0x22, 0x70, 0x61, 0x74, 0x68, 0x22, 0x3a, 0x20, + 0x22, 0x24, 0x5b, 0x30, 0x5d, 0x5b, 0x37, 0x5d, 0x22, 0x7d, 0x7d, 0x5d, 0x7d, 0x5d, 0x7d, 0x7d, + 0x0a, 0x60, 0x60, 0x60, 0x0a, 0x0a, 0x0d, 0x0a, 0x05, 0x04, 0x00, 0x03, 0x04, 0x01, 0x12, 0x04, + 0xaa, 0x01, 0x0a, 0x11, 0x0a, 0x55, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x04, 0x02, 0x00, 0x12, 0x04, + 0xac, 0x01, 0x04, 0x1c, 0x1a, 0x45, 0x2f, 0x20, 0x41, 0x20, 0x6c, 0x69, 0x73, 0x74, 0x20, 0x6f, + 0x66, 0x20, 0x73, 0x75, 0x62, 0x74, 0x61, 0x73, 0x6b, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x70, 0x72, + 0x6f, 0x63, 0x65, 0x73, 0x73, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, + 0x65, 0x20, 0x61, 0x20, 0x6c, 0x69, 0x73, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x72, 0x65, 0x73, 0x75, + 0x6c, 0x74, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x2e, 0x0a, 0x0a, 0x0f, 0x0a, 0x07, 0x04, + 0x00, 0x03, 0x04, 0x02, 0x00, 0x04, 0x12, 0x04, 0xac, 0x01, 0x04, 0x0c, 0x0a, 0x0f, 0x0a, 0x07, + 0x04, 0x00, 0x03, 0x04, 0x02, 0x00, 0x06, 0x12, 0x04, 0xac, 0x01, 0x0d, 0x11, 0x0a, 0x0f, 0x0a, + 0x07, 0x04, 0x00, 0x03, 0x04, 0x02, 0x00, 0x01, 0x12, 0x04, 0xac, 0x01, 0x12, 0x17, 0x0a, 0x0f, + 0x0a, 0x07, 0x04, 0x00, 0x03, 0x04, 0x02, 0x00, 0x03, 0x12, 0x04, 0xac, 0x01, 0x1a, 0x1b, 0x0a, + 0x54, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x04, 0x02, 0x01, 0x12, 0x04, 0xae, 0x01, 0x04, 0x20, 0x1a, + 0x44, 0x2f, 0x20, 0x41, 0x20, 0x6c, 0x69, 0x73, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x73, 0x75, 0x62, + 0x6a, 0x6f, 0x62, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x20, + 0x61, 0x6e, 0x64, 0x20, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x65, 0x20, 0x61, 0x20, 0x6c, 0x69, + 0x73, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x20, 0x76, 0x61, 0x6c, + 0x75, 0x65, 0x73, 0x2e, 0x0a, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x04, 0x02, 0x01, 0x04, + 0x12, 0x04, 0xae, 0x01, 0x04, 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x04, 0x02, 0x01, + 0x06, 0x12, 0x04, 0xae, 0x01, 0x0d, 0x16, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x04, 0x02, + 0x01, 0x01, 0x12, 0x04, 0xae, 0x01, 0x17, 0x1b, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x04, + 0x02, 0x01, 0x03, 0x12, 0x04, 0xae, 0x01, 0x1e, 0x1f, 0x0a, 0x8c, 0x07, 0x0a, 0x04, 0x04, 0x00, + 0x03, 0x05, 0x12, 0x06, 0xc4, 0x01, 0x02, 0xc9, 0x01, 0x03, 0x1a, 0xfb, 0x06, 0x0a, 0x52, 0x65, + 0x74, 0x75, 0x72, 0x6e, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6d, 0x69, 0x6e, 0x69, 0x6d, 0x75, + 0x6d, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x61, 0x6c, 0x6c, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, + 0x6e, 0x65, 0x64, 0x20, 0x62, 0x79, 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x72, 0x6f, 0x76, 0x69, + 0x64, 0x65, 0x64, 0x20, 0x73, 0x75, 0x62, 0x74, 0x61, 0x73, 0x6b, 0x73, 0x20, 0x61, 0x6e, 0x64, + 0x20, 0x73, 0x75, 0x62, 0x6a, 0x6f, 0x62, 0x73, 0x2e, 0x20, 0x4e, 0x65, 0x73, 0x74, 0x65, 0x64, + 0x20, 0x74, 0x61, 0x73, 0x6b, 0x73, 0x20, 0x6f, 0x72, 0x20, 0x6a, 0x6f, 0x62, 0x73, 0x20, 0x6d, + 0x75, 0x73, 0x74, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x61, 0x20, 0x4e, 0x75, 0x6d, + 0x62, 0x65, 0x72, 0x2e, 0x0a, 0x0a, 0x5f, 0x2a, 0x2a, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x2a, 0x2a, + 0x5f, 0x3a, 0x20, 0x4e, 0x6f, 0x6e, 0x65, 0x0a, 0x0a, 0x5f, 0x2a, 0x2a, 0x52, 0x65, 0x74, 0x75, + 0x72, 0x6e, 0x73, 0x2a, 0x2a, 0x5f, 0x3a, 0x20, 0x41, 0x20, 0x6e, 0x75, 0x6d, 0x65, 0x72, 0x69, + 0x63, 0x61, 0x6c, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x2e, 0x0a, 0x0a, 0x5f, 0x2a, 0x2a, + 0x45, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2a, 0x2a, 0x5f, 0x3a, 0x20, 0x52, 0x65, 0x74, 0x75, + 0x72, 0x6e, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6d, 0x69, 0x6e, 0x69, 0x6d, 0x75, 0x6d, 0x20, + 0x6e, 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x6c, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, + 0x20, 0x66, 0x72, 0x6f, 0x6d, 0x20, 0x33, 0x20, 0x74, 0x61, 0x73, 0x6b, 0x73, 0x2e, 0x0a, 0x0a, + 0x60, 0x60, 0x60, 0x6a, 0x73, 0x6f, 0x6e, 0x0a, 0x7b, 0x22, 0x6d, 0x69, 0x6e, 0x54, 0x61, 0x73, + 0x6b, 0x22, 0x3a, 0x20, 0x7b, 0x22, 0x74, 0x61, 0x73, 0x6b, 0x73, 0x22, 0x3a, 0x20, 0x5b, 0x7b, + 0x22, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x22, 0x3a, 0x20, 0x7b, 0x22, 0x76, + 0x61, 0x6c, 0x75, 0x65, 0x22, 0x3a, 0x20, 0x31, 0x30, 0x7d, 0x7d, 0x2c, 0x7b, 0x22, 0x76, 0x61, + 0x6c, 0x75, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x22, 0x3a, 0x20, 0x7b, 0x22, 0x76, 0x61, 0x6c, 0x75, + 0x65, 0x22, 0x3a, 0x20, 0x32, 0x30, 0x7d, 0x7d, 0x2c, 0x7b, 0x22, 0x76, 0x61, 0x6c, 0x75, 0x65, + 0x54, 0x61, 0x73, 0x6b, 0x22, 0x3a, 0x20, 0x7b, 0x22, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x3a, + 0x20, 0x33, 0x30, 0x7d, 0x7d, 0x5d, 0x7d, 0x7d, 0x0a, 0x60, 0x60, 0x60, 0x0a, 0x0a, 0x5f, 0x2a, + 0x2a, 0x45, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2a, 0x2a, 0x5f, 0x3a, 0x20, 0x52, 0x65, 0x74, + 0x75, 0x72, 0x6e, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6d, 0x69, 0x6e, 0x69, 0x6d, 0x75, 0x6d, + 0x20, 0x6e, 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x6c, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, + 0x74, 0x20, 0x66, 0x72, 0x6f, 0x6d, 0x20, 0x33, 0x20, 0x6a, 0x6f, 0x62, 0x73, 0x2e, 0x0a, 0x0a, + 0x60, 0x60, 0x60, 0x6a, 0x73, 0x6f, 0x6e, 0x0a, 0x7b, 0x22, 0x6d, 0x69, 0x6e, 0x54, 0x61, 0x73, + 0x6b, 0x22, 0x3a, 0x20, 0x7b, 0x22, 0x6a, 0x6f, 0x62, 0x73, 0x22, 0x3a, 0x20, 0x5b, 0x7b, 0x22, + 0x74, 0x61, 0x73, 0x6b, 0x73, 0x22, 0x3a, 0x20, 0x5b, 0x7b, 0x22, 0x68, 0x74, 0x74, 0x70, 0x54, + 0x61, 0x73, 0x6b, 0x22, 0x3a, 0x20, 0x7b, 0x22, 0x75, 0x72, 0x6c, 0x22, 0x3a, 0x20, 0x22, 0x68, + 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x62, 0x69, 0x6e, 0x61, 0x6e, + 0x63, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x33, 0x2f, 0x74, 0x69, + 0x63, 0x6b, 0x65, 0x72, 0x2f, 0x70, 0x72, 0x69, 0x63, 0x65, 0x3f, 0x73, 0x79, 0x6d, 0x62, 0x6f, + 0x6c, 0x3d, 0x53, 0x4f, 0x4c, 0x55, 0x53, 0x44, 0x54, 0x22, 0x7d, 0x7d, 0x2c, 0x7b, 0x22, 0x6a, + 0x73, 0x6f, 0x6e, 0x50, 0x61, 0x72, 0x73, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x22, 0x3a, 0x20, 0x7b, + 0x22, 0x70, 0x61, 0x74, 0x68, 0x22, 0x3a, 0x20, 0x22, 0x24, 0x2e, 0x70, 0x72, 0x69, 0x63, 0x65, + 0x22, 0x7d, 0x7d, 0x5d, 0x7d, 0x2c, 0x7b, 0x22, 0x74, 0x61, 0x73, 0x6b, 0x73, 0x22, 0x3a, 0x20, + 0x5b, 0x7b, 0x22, 0x68, 0x74, 0x74, 0x70, 0x54, 0x61, 0x73, 0x6b, 0x22, 0x3a, 0x20, 0x7b, 0x22, + 0x75, 0x72, 0x6c, 0x22, 0x3a, 0x20, 0x22, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x77, + 0x77, 0x77, 0x2e, 0x62, 0x69, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x2e, 0x75, 0x73, 0x2f, 0x61, 0x70, + 0x69, 0x2f, 0x76, 0x33, 0x2f, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x72, 0x2f, 0x70, 0x72, 0x69, 0x63, + 0x65, 0x3f, 0x73, 0x79, 0x6d, 0x62, 0x6f, 0x6c, 0x3d, 0x53, 0x4f, 0x4c, 0x55, 0x53, 0x44, 0x22, + 0x7d, 0x7d, 0x2c, 0x7b, 0x22, 0x6a, 0x73, 0x6f, 0x6e, 0x50, 0x61, 0x72, 0x73, 0x65, 0x54, 0x61, + 0x73, 0x6b, 0x22, 0x3a, 0x20, 0x7b, 0x22, 0x70, 0x61, 0x74, 0x68, 0x22, 0x3a, 0x20, 0x22, 0x24, + 0x2e, 0x70, 0x72, 0x69, 0x63, 0x65, 0x22, 0x7d, 0x7d, 0x5d, 0x7d, 0x2c, 0x7b, 0x22, 0x74, 0x61, + 0x73, 0x6b, 0x73, 0x22, 0x3a, 0x20, 0x5b, 0x7b, 0x22, 0x68, 0x74, 0x74, 0x70, 0x54, 0x61, 0x73, + 0x6b, 0x22, 0x3a, 0x20, 0x7b, 0x22, 0x75, 0x72, 0x6c, 0x22, 0x3a, 0x20, 0x22, 0x68, 0x74, 0x74, + 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x61, 0x70, 0x69, 0x2d, 0x70, 0x75, 0x62, 0x2e, 0x62, 0x69, 0x74, + 0x66, 0x69, 0x6e, 0x65, 0x78, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x76, 0x32, 0x2f, 0x74, 0x69, 0x63, + 0x6b, 0x65, 0x72, 0x73, 0x3f, 0x73, 0x79, 0x6d, 0x62, 0x6f, 0x6c, 0x73, 0x3d, 0x74, 0x53, 0x4f, + 0x4c, 0x55, 0x53, 0x44, 0x22, 0x7d, 0x7d, 0x2c, 0x7b, 0x22, 0x6a, 0x73, 0x6f, 0x6e, 0x50, 0x61, + 0x72, 0x73, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x22, 0x3a, 0x20, 0x7b, 0x22, 0x70, 0x61, 0x74, 0x68, + 0x22, 0x3a, 0x20, 0x22, 0x24, 0x5b, 0x30, 0x5d, 0x5b, 0x37, 0x5d, 0x22, 0x7d, 0x7d, 0x5d, 0x7d, + 0x5d, 0x7d, 0x7d, 0x0a, 0x60, 0x60, 0x60, 0x0a, 0x0a, 0x0d, 0x0a, 0x05, 0x04, 0x00, 0x03, 0x05, + 0x01, 0x12, 0x04, 0xc4, 0x01, 0x0a, 0x11, 0x0a, 0x55, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x05, 0x02, + 0x00, 0x12, 0x04, 0xc6, 0x01, 0x04, 0x1c, 0x1a, 0x45, 0x2f, 0x20, 0x41, 0x20, 0x6c, 0x69, 0x73, + 0x74, 0x20, 0x6f, 0x66, 0x20, 0x73, 0x75, 0x62, 0x74, 0x61, 0x73, 0x6b, 0x73, 0x20, 0x74, 0x6f, + 0x20, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x70, 0x72, 0x6f, + 0x64, 0x75, 0x63, 0x65, 0x20, 0x61, 0x20, 0x6c, 0x69, 0x73, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x72, + 0x65, 0x73, 0x75, 0x6c, 0x74, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x2e, 0x0a, 0x0a, 0x0f, + 0x0a, 0x07, 0x04, 0x00, 0x03, 0x05, 0x02, 0x00, 0x04, 0x12, 0x04, 0xc6, 0x01, 0x04, 0x0c, 0x0a, + 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x05, 0x02, 0x00, 0x06, 0x12, 0x04, 0xc6, 0x01, 0x0d, 0x11, + 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x05, 0x02, 0x00, 0x01, 0x12, 0x04, 0xc6, 0x01, 0x12, + 0x17, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x05, 0x02, 0x00, 0x03, 0x12, 0x04, 0xc6, 0x01, + 0x1a, 0x1b, 0x0a, 0x54, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x05, 0x02, 0x01, 0x12, 0x04, 0xc8, 0x01, + 0x04, 0x20, 0x1a, 0x44, 0x2f, 0x20, 0x41, 0x20, 0x6c, 0x69, 0x73, 0x74, 0x20, 0x6f, 0x66, 0x20, + 0x73, 0x75, 0x62, 0x6a, 0x6f, 0x62, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x70, 0x72, 0x6f, 0x63, 0x65, + 0x73, 0x73, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x65, 0x20, 0x61, + 0x20, 0x6c, 0x69, 0x73, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x20, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x2e, 0x0a, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x05, + 0x02, 0x01, 0x04, 0x12, 0x04, 0xc8, 0x01, 0x04, 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, + 0x05, 0x02, 0x01, 0x06, 0x12, 0x04, 0xc8, 0x01, 0x0d, 0x16, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, + 0x03, 0x05, 0x02, 0x01, 0x01, 0x12, 0x04, 0xc8, 0x01, 0x17, 0x1b, 0x0a, 0x0f, 0x0a, 0x07, 0x04, + 0x00, 0x03, 0x05, 0x02, 0x01, 0x03, 0x12, 0x04, 0xc8, 0x01, 0x1e, 0x1f, 0x0a, 0xc7, 0x03, 0x0a, + 0x04, 0x04, 0x00, 0x03, 0x06, 0x12, 0x06, 0xe4, 0x01, 0x02, 0xf1, 0x01, 0x03, 0x1a, 0xb6, 0x03, + 0x0a, 0x52, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x73, 0x20, 0x61, 0x20, 0x73, 0x70, 0x65, 0x63, 0x69, + 0x66, 0x69, 0x65, 0x64, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x2e, 0x0a, 0x0a, 0x5f, 0x2a, 0x2a, + 0x49, 0x6e, 0x70, 0x75, 0x74, 0x2a, 0x2a, 0x5f, 0x3a, 0x20, 0x4e, 0x6f, 0x6e, 0x65, 0x0a, 0x0a, + 0x5f, 0x2a, 0x2a, 0x52, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x73, 0x2a, 0x2a, 0x5f, 0x3a, 0x20, 0x41, + 0x20, 0x6e, 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x6c, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, + 0x74, 0x2e, 0x0a, 0x0a, 0x5f, 0x2a, 0x2a, 0x45, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2a, 0x2a, + 0x5f, 0x3a, 0x20, 0x52, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x76, + 0x61, 0x6c, 0x75, 0x65, 0x20, 0x31, 0x30, 0x0a, 0x0a, 0x60, 0x60, 0x60, 0x6a, 0x73, 0x6f, 0x6e, + 0x0a, 0x7b, 0x22, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x22, 0x3a, 0x20, 0x7b, + 0x22, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x3a, 0x20, 0x31, 0x30, 0x7d, 0x20, 0x7d, 0x0a, 0x60, + 0x60, 0x60, 0x0a, 0x0a, 0x5f, 0x2a, 0x2a, 0x45, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2a, 0x2a, + 0x5f, 0x3a, 0x20, 0x52, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, + 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x20, 0x72, 0x65, 0x73, 0x75, + 0x6c, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x61, 0x6e, 0x20, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, + 0x74, 0x6f, 0x72, 0x0a, 0x0a, 0x60, 0x60, 0x60, 0x6a, 0x73, 0x6f, 0x6e, 0x0a, 0x7b, 0x22, 0x76, + 0x61, 0x6c, 0x75, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x22, 0x3a, 0x20, 0x7b, 0x22, 0x61, 0x67, 0x67, + 0x72, 0x65, 0x67, 0x61, 0x74, 0x6f, 0x72, 0x50, 0x75, 0x62, 0x6b, 0x65, 0x79, 0x22, 0x3a, 0x20, + 0x22, 0x47, 0x76, 0x44, 0x4d, 0x78, 0x50, 0x7a, 0x4e, 0x31, 0x73, 0x43, 0x6a, 0x37, 0x4c, 0x32, + 0x36, 0x59, 0x44, 0x4b, 0x32, 0x48, 0x6e, 0x4d, 0x52, 0x58, 0x45, 0x51, 0x6d, 0x51, 0x32, 0x61, + 0x65, 0x6d, 0x6f, 0x76, 0x38, 0x59, 0x42, 0x74, 0x50, 0x53, 0x37, 0x76, 0x52, 0x22, 0x7d, 0x20, + 0x7d, 0x0a, 0x60, 0x60, 0x60, 0x0a, 0x0a, 0x5f, 0x2a, 0x2a, 0x45, 0x78, 0x61, 0x6d, 0x70, 0x6c, + 0x65, 0x2a, 0x2a, 0x5f, 0x3a, 0x20, 0x52, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x73, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x20, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x64, 0x20, 0x69, + 0x6e, 0x20, 0x61, 0x20, 0x43, 0x61, 0x63, 0x68, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x20, 0x76, 0x61, + 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x0a, 0x0a, 0x60, 0x60, 0x60, 0x6a, 0x73, 0x6f, 0x6e, 0x0a, + 0x7b, 0x22, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x22, 0x3a, 0x20, 0x7b, 0x22, + 0x62, 0x69, 0x67, 0x22, 0x3a, 0x20, 0x22, 0x24, 0x7b, 0x4f, 0x4e, 0x45, 0x7d, 0x22, 0x7d, 0x20, + 0x7d, 0x0a, 0x60, 0x60, 0x60, 0x0a, 0x0a, 0x0d, 0x0a, 0x05, 0x04, 0x00, 0x03, 0x06, 0x01, 0x12, + 0x04, 0xe4, 0x01, 0x0a, 0x13, 0x0a, 0x10, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x06, 0x08, 0x00, 0x12, + 0x06, 0xe5, 0x01, 0x04, 0xf0, 0x01, 0x05, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x06, 0x08, + 0x00, 0x01, 0x12, 0x04, 0xe5, 0x01, 0x0a, 0x0f, 0x0a, 0x42, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x06, + 0x02, 0x00, 0x12, 0x04, 0xe7, 0x01, 0x06, 0x17, 0x1a, 0x32, 0x2f, 0x20, 0x54, 0x68, 0x65, 0x20, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x77, 0x69, 0x6c, 0x6c, 0x20, + 0x62, 0x65, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x65, 0x64, 0x20, 0x66, 0x72, 0x6f, 0x6d, + 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x74, 0x61, 0x73, 0x6b, 0x2e, 0x0a, 0x0a, 0x0f, 0x0a, 0x07, + 0x04, 0x00, 0x03, 0x06, 0x02, 0x00, 0x05, 0x12, 0x04, 0xe7, 0x01, 0x06, 0x0c, 0x0a, 0x0f, 0x0a, + 0x07, 0x04, 0x00, 0x03, 0x06, 0x02, 0x00, 0x01, 0x12, 0x04, 0xe7, 0x01, 0x0d, 0x12, 0x0a, 0x0f, + 0x0a, 0x07, 0x04, 0x00, 0x03, 0x06, 0x02, 0x00, 0x03, 0x12, 0x04, 0xe7, 0x01, 0x15, 0x16, 0x0a, + 0x41, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x06, 0x02, 0x01, 0x12, 0x04, 0xe9, 0x01, 0x06, 0x23, 0x1a, + 0x31, 0x2f, 0x20, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x65, 0x73, 0x20, 0x61, 0x6e, 0x20, + 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x6f, 0x72, 0x72, 0x20, 0x74, 0x6f, 0x20, 0x70, + 0x75, 0x6c, 0x6c, 0x20, 0x74, 0x68, 0x65, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x20, 0x6f, 0x66, + 0x2e, 0x0a, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x06, 0x02, 0x01, 0x05, 0x12, 0x04, 0xe9, + 0x01, 0x06, 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x06, 0x02, 0x01, 0x01, 0x12, 0x04, + 0xe9, 0x01, 0x0d, 0x1e, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x06, 0x02, 0x01, 0x03, 0x12, + 0x04, 0xe9, 0x01, 0x21, 0x22, 0x0a, 0x4d, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x06, 0x02, 0x02, 0x12, + 0x04, 0xeb, 0x01, 0x06, 0x15, 0x1a, 0x3d, 0x2f, 0x20, 0x41, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, + 0x67, 0x69, 0x66, 0x69, 0x65, 0x64, 0x20, 0x62, 0x69, 0x67, 0x2e, 0x6a, 0x73, 0x2e, 0x20, 0x60, + 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x73, 0x20, 0x76, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, + 0x20, 0x65, 0x78, 0x70, 0x61, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x73, 0x79, 0x6e, 0x74, 0x61, + 0x78, 0x2e, 0x60, 0x0a, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x06, 0x02, 0x02, 0x05, 0x12, + 0x04, 0xeb, 0x01, 0x06, 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x06, 0x02, 0x02, 0x01, + 0x12, 0x04, 0xeb, 0x01, 0x0d, 0x10, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x06, 0x02, 0x02, + 0x03, 0x12, 0x04, 0xeb, 0x01, 0x13, 0x14, 0x0a, 0x44, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x06, 0x02, + 0x03, 0x12, 0x04, 0xed, 0x01, 0x06, 0x15, 0x1a, 0x34, 0x2f, 0x20, 0x41, 0x20, 0x73, 0x74, 0x72, + 0x69, 0x6e, 0x67, 0x69, 0x66, 0x69, 0x65, 0x64, 0x20, 0x68, 0x65, 0x78, 0x20, 0x6e, 0x75, 0x6d, + 0x62, 0x65, 0x72, 0x20, 0x28, 0x30, 0x78, 0x20, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x20, 0x69, + 0x73, 0x20, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x29, 0x2e, 0x0a, 0x0a, 0x0f, 0x0a, + 0x07, 0x04, 0x00, 0x03, 0x06, 0x02, 0x03, 0x05, 0x12, 0x04, 0xed, 0x01, 0x06, 0x0c, 0x0a, 0x0f, + 0x0a, 0x07, 0x04, 0x00, 0x03, 0x06, 0x02, 0x03, 0x01, 0x12, 0x04, 0xed, 0x01, 0x0d, 0x10, 0x0a, + 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x06, 0x02, 0x03, 0x03, 0x12, 0x04, 0xed, 0x01, 0x13, 0x14, + 0x0a, 0x20, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x06, 0x02, 0x04, 0x12, 0x04, 0xef, 0x01, 0x06, 0x16, + 0x1a, 0x10, 0x20, 0x41, 0x20, 0x75, 0x74, 0x66, 0x38, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, + 0x2e, 0x0a, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x06, 0x02, 0x04, 0x05, 0x12, 0x04, 0xef, + 0x01, 0x06, 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x06, 0x02, 0x04, 0x01, 0x12, 0x04, + 0xef, 0x01, 0x0d, 0x11, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x06, 0x02, 0x04, 0x03, 0x12, + 0x04, 0xef, 0x01, 0x14, 0x15, 0x0a, 0x9f, 0x04, 0x0a, 0x04, 0x04, 0x00, 0x03, 0x07, 0x12, 0x06, + 0x80, 0x02, 0x02, 0x8a, 0x02, 0x03, 0x1a, 0x8e, 0x04, 0x0a, 0x4f, 0x70, 0x65, 0x6e, 0x73, 0x20, + 0x61, 0x6e, 0x64, 0x20, 0x6d, 0x61, 0x69, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x73, 0x20, 0x61, 0x20, + 0x77, 0x65, 0x62, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x6c, 0x69, + 0x67, 0x68, 0x74, 0x20, 0x73, 0x70, 0x65, 0x65, 0x64, 0x20, 0x64, 0x61, 0x74, 0x61, 0x20, 0x72, + 0x65, 0x74, 0x72, 0x69, 0x65, 0x76, 0x61, 0x6c, 0x2e, 0x0a, 0x0a, 0x5f, 0x2a, 0x2a, 0x49, 0x6e, + 0x70, 0x75, 0x74, 0x2a, 0x2a, 0x5f, 0x3a, 0x20, 0x4e, 0x6f, 0x6e, 0x65, 0x0a, 0x0a, 0x5f, 0x2a, + 0x2a, 0x52, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x73, 0x2a, 0x2a, 0x5f, 0x3a, 0x20, 0x53, 0x74, 0x72, + 0x69, 0x6e, 0x67, 0x20, 0x72, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x77, 0x65, 0x62, 0x73, 0x6f, 0x63, + 0x6b, 0x65, 0x74, 0x20, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, + 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x0a, 0x0a, 0x5f, 0x2a, 0x2a, 0x45, 0x78, + 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2a, 0x2a, 0x5f, 0x3a, 0x20, 0x4f, 0x70, 0x65, 0x6e, 0x73, 0x20, + 0x61, 0x20, 0x63, 0x6f, 0x69, 0x6e, 0x62, 0x61, 0x73, 0x65, 0x20, 0x77, 0x65, 0x62, 0x73, 0x6f, + 0x63, 0x6b, 0x65, 0x74, 0x0a, 0x0a, 0x60, 0x60, 0x60, 0x6a, 0x73, 0x6f, 0x6e, 0x0a, 0x7b, 0x20, + 0x22, 0x77, 0x65, 0x62, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x54, 0x61, 0x73, 0x6b, 0x22, 0x3a, + 0x20, 0x7b, 0x20, 0x22, 0x75, 0x72, 0x6c, 0x22, 0x3a, 0x20, 0x22, 0x77, 0x73, 0x73, 0x3a, 0x2f, + 0x2f, 0x77, 0x73, 0x2d, 0x66, 0x65, 0x65, 0x64, 0x2e, 0x70, 0x72, 0x6f, 0x2e, 0x63, 0x6f, 0x69, + 0x6e, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x22, 0x2c, 0x20, 0x22, 0x73, 0x75, 0x62, + 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x3a, 0x20, 0x22, 0x7b, 0x5c, 0x22, + 0x74, 0x79, 0x70, 0x65, 0x5c, 0x22, 0x3a, 0x5c, 0x22, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, + 0x62, 0x65, 0x5c, 0x22, 0x2c, 0x5c, 0x22, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x5f, 0x69, + 0x64, 0x73, 0x5c, 0x22, 0x3a, 0x5b, 0x5c, 0x22, 0x42, 0x54, 0x43, 0x2d, 0x55, 0x53, 0x44, 0x5c, + 0x22, 0x5d, 0x2c, 0x5c, 0x22, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x5c, 0x22, 0x3a, + 0x5b, 0x5c, 0x22, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x72, 0x5c, 0x22, 0x2c, 0x7b, 0x5c, 0x22, 0x6e, + 0x61, 0x6d, 0x65, 0x5c, 0x22, 0x3a, 0x5c, 0x22, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x72, 0x5c, 0x22, + 0x2c, 0x5c, 0x22, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x5f, 0x69, 0x64, 0x73, 0x5c, 0x22, + 0x3a, 0x5b, 0x5c, 0x22, 0x42, 0x54, 0x43, 0x2d, 0x55, 0x53, 0x44, 0x5c, 0x22, 0x5d, 0x7d, 0x5d, + 0x7d, 0x22, 0x2c, 0x20, 0x22, 0x6d, 0x61, 0x78, 0x44, 0x61, 0x74, 0x61, 0x41, 0x67, 0x65, 0x53, + 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x22, 0x3a, 0x20, 0x31, 0x35, 0x2c, 0x20, 0x22, 0x66, 0x69, + 0x6c, 0x74, 0x65, 0x72, 0x22, 0x3a, 0x20, 0x22, 0x24, 0x5b, 0x3f, 0x28, 0x40, 0x2e, 0x74, 0x79, + 0x70, 0x65, 0x20, 0x3d, 0x3d, 0x20, 0x27, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x72, 0x27, 0x20, 0x26, + 0x26, 0x20, 0x40, 0x2e, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x5f, 0x69, 0x64, 0x20, 0x3d, + 0x3d, 0x20, 0x27, 0x42, 0x54, 0x43, 0x2d, 0x55, 0x53, 0x44, 0x27, 0x29, 0x5d, 0x22, 0x20, 0x7d, + 0x20, 0x7d, 0x0a, 0x60, 0x60, 0x60, 0x0a, 0x0a, 0x0d, 0x0a, 0x05, 0x04, 0x00, 0x03, 0x07, 0x01, + 0x12, 0x04, 0x80, 0x02, 0x0a, 0x17, 0x0a, 0x25, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x07, 0x02, 0x00, + 0x12, 0x04, 0x82, 0x02, 0x04, 0x1c, 0x1a, 0x15, 0x2f, 0x20, 0x54, 0x68, 0x65, 0x20, 0x77, 0x65, + 0x62, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x20, 0x75, 0x72, 0x6c, 0x2e, 0x0a, 0x0a, 0x0f, 0x0a, + 0x07, 0x04, 0x00, 0x03, 0x07, 0x02, 0x00, 0x04, 0x12, 0x04, 0x82, 0x02, 0x04, 0x0c, 0x0a, 0x0f, + 0x0a, 0x07, 0x04, 0x00, 0x03, 0x07, 0x02, 0x00, 0x05, 0x12, 0x04, 0x82, 0x02, 0x0d, 0x13, 0x0a, + 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x07, 0x02, 0x00, 0x01, 0x12, 0x04, 0x82, 0x02, 0x14, 0x17, + 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x07, 0x02, 0x00, 0x03, 0x12, 0x04, 0x82, 0x02, 0x1a, + 0x1b, 0x0a, 0x49, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x07, 0x02, 0x01, 0x12, 0x04, 0x84, 0x02, 0x04, + 0x25, 0x1a, 0x39, 0x2f, 0x20, 0x54, 0x68, 0x65, 0x20, 0x77, 0x65, 0x62, 0x73, 0x6f, 0x63, 0x6b, + 0x65, 0x74, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x20, 0x74, 0x6f, 0x20, 0x6e, 0x6f, + 0x74, 0x69, 0x66, 0x79, 0x20, 0x6f, 0x66, 0x20, 0x61, 0x20, 0x6e, 0x65, 0x77, 0x20, 0x73, 0x75, + 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x0a, 0x0a, 0x0f, 0x0a, 0x07, + 0x04, 0x00, 0x03, 0x07, 0x02, 0x01, 0x04, 0x12, 0x04, 0x84, 0x02, 0x04, 0x0c, 0x0a, 0x0f, 0x0a, + 0x07, 0x04, 0x00, 0x03, 0x07, 0x02, 0x01, 0x05, 0x12, 0x04, 0x84, 0x02, 0x0d, 0x13, 0x0a, 0x0f, + 0x0a, 0x07, 0x04, 0x00, 0x03, 0x07, 0x02, 0x01, 0x01, 0x12, 0x04, 0x84, 0x02, 0x14, 0x20, 0x0a, + 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x07, 0x02, 0x01, 0x03, 0x12, 0x04, 0x84, 0x02, 0x23, 0x24, + 0x0a, 0x5a, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x07, 0x02, 0x02, 0x12, 0x04, 0x86, 0x02, 0x04, 0x2c, + 0x1a, 0x4a, 0x2f, 0x20, 0x4d, 0x69, 0x6e, 0x69, 0x6d, 0x75, 0x6d, 0x20, 0x61, 0x6d, 0x6f, 0x75, + 0x6e, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x69, 0x6d, 0x65, 0x20, 0x72, 0x65, 0x71, 0x75, 0x69, + 0x72, 0x65, 0x64, 0x20, 0x62, 0x65, 0x74, 0x77, 0x65, 0x65, 0x6e, 0x20, 0x77, 0x68, 0x65, 0x6e, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x68, 0x6f, 0x72, 0x73, 0x65, 0x73, 0x20, 0x61, 0x72, 0x65, 0x20, + 0x74, 0x61, 0x6b, 0x69, 0x6e, 0x67, 0x20, 0x6f, 0x75, 0x74, 0x2e, 0x0a, 0x0a, 0x0f, 0x0a, 0x07, + 0x04, 0x00, 0x03, 0x07, 0x02, 0x02, 0x04, 0x12, 0x04, 0x86, 0x02, 0x04, 0x0c, 0x0a, 0x0f, 0x0a, + 0x07, 0x04, 0x00, 0x03, 0x07, 0x02, 0x02, 0x05, 0x12, 0x04, 0x86, 0x02, 0x0d, 0x12, 0x0a, 0x0f, + 0x0a, 0x07, 0x04, 0x00, 0x03, 0x07, 0x02, 0x02, 0x01, 0x12, 0x04, 0x86, 0x02, 0x13, 0x27, 0x0a, + 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x07, 0x02, 0x02, 0x03, 0x12, 0x04, 0x86, 0x02, 0x2a, 0x2b, + 0x0a, 0x76, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x07, 0x02, 0x03, 0x12, 0x04, 0x89, 0x02, 0x04, 0x1f, + 0x1a, 0x66, 0x2f, 0x20, 0x49, 0x6e, 0x63, 0x6f, 0x6d, 0x69, 0x6e, 0x67, 0x20, 0x6d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x20, 0x4a, 0x53, 0x4f, 0x4e, 0x50, 0x61, 0x74, 0x68, 0x20, 0x66, 0x69, + 0x6c, 0x74, 0x65, 0x72, 0x2e, 0x0a, 0x2f, 0x20, 0x45, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x3a, + 0x20, 0x22, 0x24, 0x5b, 0x3f, 0x28, 0x40, 0x2e, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x20, + 0x3d, 0x3d, 0x20, 0x27, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x72, 0x27, 0x20, 0x26, 0x26, 0x20, 0x40, + 0x2e, 0x6d, 0x61, 0x72, 0x6b, 0x65, 0x74, 0x20, 0x3d, 0x3d, 0x20, 0x27, 0x42, 0x54, 0x43, 0x2f, + 0x55, 0x53, 0x44, 0x27, 0x29, 0x5d, 0x22, 0x0a, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x07, + 0x02, 0x03, 0x04, 0x12, 0x04, 0x89, 0x02, 0x04, 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, + 0x07, 0x02, 0x03, 0x05, 0x12, 0x04, 0x89, 0x02, 0x0d, 0x13, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, + 0x03, 0x07, 0x02, 0x03, 0x01, 0x12, 0x04, 0x89, 0x02, 0x14, 0x1a, 0x0a, 0x0f, 0x0a, 0x07, 0x04, + 0x00, 0x03, 0x07, 0x02, 0x03, 0x03, 0x12, 0x04, 0x89, 0x02, 0x1d, 0x1e, 0x0a, 0xae, 0x06, 0x0a, + 0x04, 0x04, 0x00, 0x03, 0x08, 0x12, 0x06, 0x99, 0x02, 0x02, 0x9f, 0x02, 0x03, 0x1a, 0x9d, 0x06, + 0x0a, 0x54, 0x68, 0x69, 0x73, 0x20, 0x74, 0x61, 0x73, 0x6b, 0x20, 0x77, 0x69, 0x6c, 0x6c, 0x20, + 0x72, 0x75, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x60, 0x61, 0x74, 0x74, 0x65, 0x6d, 0x70, 0x74, + 0x60, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x75, 0x62, 0x74, 0x61, 0x73, 0x6b, + 0x73, 0x20, 0x69, 0x6e, 0x20, 0x61, 0x6e, 0x20, 0x65, 0x66, 0x66, 0x6f, 0x72, 0x74, 0x20, 0x74, + 0x6f, 0x20, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x65, 0x20, 0x61, 0x20, 0x76, 0x61, 0x6c, 0x69, + 0x64, 0x20, 0x6e, 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x6c, 0x20, 0x72, 0x65, 0x73, 0x75, + 0x6c, 0x74, 0x2e, 0x20, 0x49, 0x66, 0x20, 0x60, 0x61, 0x74, 0x74, 0x65, 0x6d, 0x70, 0x74, 0x60, + 0x2e, 0x20, 0x66, 0x61, 0x69, 0x6c, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x70, 0x72, 0x6f, 0x64, 0x75, + 0x63, 0x65, 0x20, 0x61, 0x6e, 0x20, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x61, 0x62, 0x6c, 0x65, + 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x2c, 0x20, 0x60, 0x6f, 0x6e, 0x5f, 0x66, 0x61, 0x69, + 0x6c, 0x75, 0x72, 0x65, 0x60, 0x20, 0x73, 0x75, 0x62, 0x74, 0x61, 0x73, 0x6b, 0x73, 0x20, 0x77, + 0x69, 0x6c, 0x6c, 0x20, 0x62, 0x65, 0x20, 0x72, 0x75, 0x6e, 0x20, 0x69, 0x6e, 0x73, 0x74, 0x65, + 0x61, 0x64, 0x2e, 0x0a, 0x0a, 0x5f, 0x2a, 0x2a, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x2a, 0x2a, 0x5f, + 0x3a, 0x20, 0x54, 0x68, 0x65, 0x20, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x20, 0x72, 0x75, + 0x6e, 0x6e, 0x69, 0x6e, 0x67, 0x20, 0x6e, 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x6c, 0x20, + 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x20, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x20, 0x66, 0x72, + 0x6f, 0x6d, 0x20, 0x61, 0x20, 0x74, 0x61, 0x73, 0x6b, 0x2e, 0x0a, 0x0a, 0x5f, 0x2a, 0x2a, 0x52, + 0x65, 0x74, 0x75, 0x72, 0x6e, 0x73, 0x2a, 0x2a, 0x5f, 0x3a, 0x20, 0x41, 0x20, 0x6e, 0x75, 0x6d, + 0x65, 0x72, 0x69, 0x63, 0x61, 0x6c, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x2c, 0x20, 0x65, + 0x6c, 0x73, 0x65, 0x20, 0x72, 0x75, 0x6e, 0x20, 0x60, 0x6f, 0x6e, 0x5f, 0x66, 0x61, 0x69, 0x6c, + 0x75, 0x72, 0x65, 0x60, 0x20, 0x73, 0x75, 0x62, 0x74, 0x61, 0x73, 0x6b, 0x73, 0x2e, 0x0a, 0x0a, + 0x5f, 0x2a, 0x2a, 0x45, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2a, 0x2a, 0x5f, 0x3a, 0x20, 0x52, + 0x65, 0x74, 0x75, 0x72, 0x6e, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6e, 0x75, 0x6d, 0x65, 0x72, + 0x69, 0x63, 0x61, 0x6c, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x20, 0x66, 0x72, 0x6f, 0x6d, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, + 0x54, 0x61, 0x73, 0x6b, 0x27, 0x73, 0x20, 0x73, 0x75, 0x62, 0x74, 0x61, 0x73, 0x6b, 0x73, 0x2c, + 0x20, 0x65, 0x6c, 0x73, 0x65, 0x20, 0x60, 0x6f, 0x6e, 0x5f, 0x66, 0x61, 0x69, 0x6c, 0x75, 0x72, + 0x65, 0x60, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6e, + 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x6c, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x20, + 0x66, 0x72, 0x6f, 0x6d, 0x20, 0x69, 0x74, 0x73, 0x20, 0x73, 0x75, 0x62, 0x74, 0x61, 0x73, 0x6b, + 0x73, 0x2e, 0x0a, 0x0a, 0x60, 0x60, 0x60, 0x6a, 0x73, 0x6f, 0x6e, 0x0a, 0x7b, 0x22, 0x63, 0x6f, + 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x54, 0x61, 0x73, 0x6b, 0x22, 0x3a, 0x7b, + 0x22, 0x61, 0x74, 0x74, 0x65, 0x6d, 0x70, 0x74, 0x22, 0x3a, 0x5b, 0x7b, 0x22, 0x74, 0x61, 0x73, + 0x6b, 0x73, 0x22, 0x3a, 0x5b, 0x7b, 0x22, 0x6a, 0x75, 0x70, 0x69, 0x74, 0x65, 0x72, 0x53, 0x77, + 0x61, 0x70, 0x54, 0x61, 0x73, 0x6b, 0x22, 0x3a, 0x7b, 0x22, 0x69, 0x6e, 0x54, 0x6f, 0x6b, 0x65, + 0x6e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x22, 0x3a, 0x22, 0x45, 0x50, 0x6a, 0x46, 0x57, + 0x64, 0x64, 0x35, 0x41, 0x75, 0x66, 0x71, 0x53, 0x53, 0x71, 0x65, 0x4d, 0x32, 0x71, 0x4e, 0x31, + 0x78, 0x7a, 0x79, 0x62, 0x61, 0x70, 0x43, 0x38, 0x47, 0x34, 0x77, 0x45, 0x47, 0x47, 0x6b, 0x5a, + 0x77, 0x79, 0x54, 0x44, 0x74, 0x31, 0x76, 0x22, 0x2c, 0x22, 0x6f, 0x75, 0x74, 0x54, 0x6f, 0x6b, + 0x65, 0x6e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x22, 0x3a, 0x22, 0x44, 0x55, 0x41, 0x4c, + 0x61, 0x34, 0x46, 0x43, 0x32, 0x79, 0x52, 0x45, 0x77, 0x5a, 0x35, 0x39, 0x50, 0x48, 0x65, 0x75, + 0x31, 0x75, 0x6e, 0x34, 0x77, 0x69, 0x73, 0x33, 0x36, 0x76, 0x48, 0x52, 0x76, 0x35, 0x68, 0x57, + 0x56, 0x42, 0x6d, 0x7a, 0x79, 0x6b, 0x43, 0x4a, 0x22, 0x7d, 0x7d, 0x5d, 0x7d, 0x5d, 0x2c, 0x22, + 0x6f, 0x6e, 0x46, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x22, 0x3a, 0x5b, 0x7b, 0x22, 0x6c, 0x70, + 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x61, 0x74, 0x65, 0x54, 0x61, 0x73, 0x6b, + 0x22, 0x3a, 0x7b, 0x22, 0x6f, 0x72, 0x63, 0x61, 0x50, 0x6f, 0x6f, 0x6c, 0x41, 0x64, 0x64, 0x72, + 0x65, 0x73, 0x73, 0x22, 0x3a, 0x22, 0x37, 0x79, 0x4a, 0x34, 0x67, 0x4d, 0x52, 0x4a, 0x68, 0x45, + 0x6f, 0x43, 0x52, 0x34, 0x38, 0x61, 0x50, 0x45, 0x33, 0x45, 0x41, 0x57, 0x52, 0x6d, 0x43, 0x6f, + 0x79, 0x67, 0x61, 0x6b, 0x69, 0x6b, 0x38, 0x31, 0x5a, 0x53, 0x31, 0x73, 0x61, 0x6a, 0x61, 0x54, + 0x6e, 0x45, 0x22, 0x7d, 0x7d, 0x5d, 0x7d, 0x7d, 0x0a, 0x60, 0x60, 0x60, 0x0a, 0x0a, 0x0d, 0x0a, + 0x05, 0x04, 0x00, 0x03, 0x08, 0x01, 0x12, 0x04, 0x99, 0x02, 0x0a, 0x19, 0x0a, 0x63, 0x0a, 0x06, + 0x04, 0x00, 0x03, 0x08, 0x02, 0x00, 0x12, 0x04, 0x9b, 0x02, 0x04, 0x1e, 0x1a, 0x53, 0x2f, 0x20, + 0x41, 0x20, 0x6c, 0x69, 0x73, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x73, 0x75, 0x62, 0x74, 0x61, 0x73, + 0x6b, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x20, 0x69, 0x6e, + 0x20, 0x61, 0x6e, 0x20, 0x61, 0x74, 0x74, 0x65, 0x6d, 0x70, 0x74, 0x20, 0x74, 0x6f, 0x20, 0x70, + 0x72, 0x6f, 0x64, 0x75, 0x63, 0x65, 0x20, 0x61, 0x20, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x20, 0x6e, + 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x6c, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x2e, + 0x0a, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x08, 0x02, 0x00, 0x04, 0x12, 0x04, 0x9b, 0x02, + 0x04, 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x08, 0x02, 0x00, 0x06, 0x12, 0x04, 0x9b, + 0x02, 0x0d, 0x11, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x08, 0x02, 0x00, 0x01, 0x12, 0x04, + 0x9b, 0x02, 0x12, 0x19, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x08, 0x02, 0x00, 0x03, 0x12, + 0x04, 0x9b, 0x02, 0x1c, 0x1d, 0x0a, 0x7a, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x08, 0x02, 0x01, 0x12, + 0x04, 0x9e, 0x02, 0x04, 0x21, 0x1a, 0x6a, 0x2f, 0x20, 0x41, 0x20, 0x6c, 0x69, 0x73, 0x74, 0x20, + 0x6f, 0x66, 0x20, 0x73, 0x75, 0x62, 0x74, 0x61, 0x73, 0x6b, 0x73, 0x20, 0x74, 0x68, 0x61, 0x74, + 0x20, 0x77, 0x69, 0x6c, 0x6c, 0x20, 0x62, 0x65, 0x20, 0x72, 0x75, 0x6e, 0x20, 0x69, 0x66, 0x20, + 0x60, 0x61, 0x74, 0x74, 0x65, 0x6d, 0x70, 0x74, 0x60, 0x20, 0x73, 0x75, 0x62, 0x74, 0x61, 0x73, + 0x6b, 0x73, 0x20, 0x61, 0x72, 0x65, 0x20, 0x75, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x74, 0x6f, + 0x20, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x65, 0x20, 0x61, 0x6e, 0x20, 0x61, 0x63, 0x63, 0x65, + 0x70, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x0a, 0x2f, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x2e, + 0x0a, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x08, 0x02, 0x01, 0x04, 0x12, 0x04, 0x9e, 0x02, + 0x04, 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x08, 0x02, 0x01, 0x06, 0x12, 0x04, 0x9e, + 0x02, 0x0d, 0x11, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x08, 0x02, 0x01, 0x01, 0x12, 0x04, + 0x9e, 0x02, 0x12, 0x1c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x08, 0x02, 0x01, 0x03, 0x12, + 0x04, 0x9e, 0x02, 0x1f, 0x20, 0x0a, 0xab, 0x07, 0x0a, 0x04, 0x04, 0x00, 0x03, 0x09, 0x12, 0x06, + 0xba, 0x02, 0x02, 0xc5, 0x02, 0x03, 0x1a, 0x9a, 0x07, 0x0a, 0x54, 0x68, 0x69, 0x73, 0x20, 0x74, + 0x61, 0x73, 0x6b, 0x20, 0x77, 0x69, 0x6c, 0x6c, 0x20, 0x64, 0x69, 0x76, 0x69, 0x64, 0x65, 0x20, + 0x61, 0x20, 0x6e, 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x6c, 0x20, 0x69, 0x6e, 0x70, 0x75, + 0x74, 0x20, 0x62, 0x79, 0x20, 0x61, 0x20, 0x73, 0x63, 0x61, 0x6c, 0x61, 0x72, 0x20, 0x76, 0x61, + 0x6c, 0x75, 0x65, 0x20, 0x66, 0x72, 0x6f, 0x6d, 0x20, 0x61, 0x20, 0x6a, 0x6f, 0x62, 0x20, 0x6f, + 0x66, 0x20, 0x73, 0x75, 0x62, 0x74, 0x61, 0x73, 0x6b, 0x73, 0x2c, 0x20, 0x61, 0x6e, 0x20, 0x61, + 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x6f, 0x72, 0x2c, 0x20, 0x6f, 0x72, 0x20, 0x61, 0x20, + 0x62, 0x69, 0x67, 0x2e, 0x0a, 0x0a, 0x5f, 0x2a, 0x2a, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x2a, 0x2a, + 0x5f, 0x3a, 0x20, 0x54, 0x68, 0x65, 0x20, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x20, 0x72, + 0x75, 0x6e, 0x6e, 0x69, 0x6e, 0x67, 0x20, 0x6e, 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x6c, + 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x20, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x20, 0x66, + 0x72, 0x6f, 0x6d, 0x20, 0x61, 0x20, 0x73, 0x63, 0x61, 0x6c, 0x61, 0x72, 0x20, 0x76, 0x61, 0x6c, + 0x75, 0x65, 0x2c, 0x20, 0x61, 0x6e, 0x20, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x6f, + 0x72, 0x2c, 0x20, 0x61, 0x20, 0x6a, 0x6f, 0x62, 0x20, 0x6f, 0x66, 0x20, 0x73, 0x75, 0x62, 0x74, + 0x61, 0x73, 0x6b, 0x73, 0x20, 0x6f, 0x72, 0x20, 0x61, 0x20, 0x62, 0x69, 0x67, 0x2e, 0x0a, 0x0a, + 0x5f, 0x2a, 0x2a, 0x52, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x73, 0x2a, 0x2a, 0x5f, 0x3a, 0x20, 0x41, + 0x20, 0x6e, 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x6c, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, + 0x74, 0x2e, 0x0a, 0x0a, 0x5f, 0x2a, 0x2a, 0x45, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2a, 0x2a, + 0x5f, 0x3a, 0x20, 0x52, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6e, + 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x6c, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x20, + 0x62, 0x79, 0x20, 0x64, 0x69, 0x76, 0x69, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x62, 0x79, 0x20, 0x61, + 0x20, 0x6a, 0x6f, 0x62, 0x20, 0x6f, 0x66, 0x20, 0x73, 0x75, 0x62, 0x74, 0x61, 0x73, 0x6b, 0x73, + 0x2e, 0x0a, 0x0a, 0x60, 0x60, 0x60, 0x6a, 0x73, 0x6f, 0x6e, 0x0a, 0x7b, 0x22, 0x74, 0x61, 0x73, + 0x6b, 0x73, 0x22, 0x3a, 0x5b, 0x7b, 0x22, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x54, 0x61, 0x73, 0x6b, + 0x22, 0x3a, 0x7b, 0x22, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x3a, 0x31, 0x30, 0x30, 0x7d, 0x7d, + 0x2c, 0x7b, 0x22, 0x64, 0x69, 0x76, 0x69, 0x64, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x22, 0x3a, 0x7b, + 0x22, 0x6a, 0x6f, 0x62, 0x22, 0x3a, 0x7b, 0x22, 0x74, 0x61, 0x73, 0x6b, 0x73, 0x22, 0x3a, 0x5b, + 0x7b, 0x22, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x22, 0x3a, 0x7b, 0x22, 0x76, + 0x61, 0x6c, 0x75, 0x65, 0x22, 0x3a, 0x31, 0x30, 0x7d, 0x7d, 0x5d, 0x7d, 0x7d, 0x7d, 0x5d, 0x7d, + 0x0a, 0x60, 0x60, 0x60, 0x0a, 0x0a, 0x5f, 0x2a, 0x2a, 0x45, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, + 0x2a, 0x2a, 0x5f, 0x3a, 0x20, 0x52, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x73, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x6e, 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x6c, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, + 0x74, 0x20, 0x62, 0x79, 0x20, 0x64, 0x69, 0x76, 0x69, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x62, 0x79, + 0x20, 0x61, 0x6e, 0x20, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x6f, 0x72, 0x2e, 0x0a, + 0x0a, 0x60, 0x60, 0x60, 0x6a, 0x73, 0x6f, 0x6e, 0x0a, 0x7b, 0x22, 0x74, 0x61, 0x73, 0x6b, 0x73, + 0x22, 0x3a, 0x5b, 0x7b, 0x22, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x22, 0x3a, + 0x7b, 0x22, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x3a, 0x31, 0x30, 0x30, 0x7d, 0x7d, 0x2c, 0x7b, + 0x22, 0x64, 0x69, 0x76, 0x69, 0x64, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x22, 0x3a, 0x7b, 0x22, 0x61, + 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x6f, 0x72, 0x50, 0x75, 0x62, 0x6b, 0x65, 0x79, 0x22, + 0x3a, 0x22, 0x47, 0x76, 0x44, 0x4d, 0x78, 0x50, 0x7a, 0x4e, 0x31, 0x73, 0x43, 0x6a, 0x37, 0x4c, + 0x32, 0x36, 0x59, 0x44, 0x4b, 0x32, 0x48, 0x6e, 0x4d, 0x52, 0x58, 0x45, 0x51, 0x6d, 0x51, 0x32, + 0x61, 0x65, 0x6d, 0x6f, 0x76, 0x38, 0x59, 0x42, 0x74, 0x50, 0x53, 0x37, 0x76, 0x52, 0x22, 0x7d, + 0x7d, 0x5d, 0x7d, 0x0a, 0x60, 0x60, 0x60, 0x0a, 0x0a, 0x5f, 0x2a, 0x2a, 0x45, 0x78, 0x61, 0x6d, + 0x70, 0x6c, 0x65, 0x2a, 0x2a, 0x5f, 0x3a, 0x20, 0x52, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x73, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x6e, 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x6c, 0x20, 0x72, 0x65, + 0x73, 0x75, 0x6c, 0x74, 0x20, 0x62, 0x79, 0x20, 0x64, 0x69, 0x76, 0x69, 0x64, 0x69, 0x6e, 0x67, + 0x20, 0x62, 0x79, 0x20, 0x61, 0x20, 0x62, 0x69, 0x67, 0x2e, 0x0a, 0x0a, 0x60, 0x60, 0x60, 0x6a, + 0x73, 0x6f, 0x6e, 0x0a, 0x7b, 0x22, 0x74, 0x61, 0x73, 0x6b, 0x73, 0x22, 0x3a, 0x5b, 0x7b, 0x22, + 0x63, 0x61, 0x63, 0x68, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x22, 0x3a, 0x7b, 0x22, 0x63, 0x61, 0x63, + 0x68, 0x65, 0x49, 0x74, 0x65, 0x6d, 0x73, 0x22, 0x3a, 0x5b, 0x7b, 0x22, 0x76, 0x61, 0x72, 0x69, + 0x61, 0x62, 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0x3a, 0x22, 0x54, 0x45, 0x4e, 0x22, 0x2c, + 0x22, 0x6a, 0x6f, 0x62, 0x22, 0x3a, 0x7b, 0x22, 0x74, 0x61, 0x73, 0x6b, 0x73, 0x22, 0x3a, 0x5b, + 0x7b, 0x22, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x22, 0x3a, 0x7b, 0x22, 0x76, + 0x61, 0x6c, 0x75, 0x65, 0x22, 0x3a, 0x31, 0x30, 0x7d, 0x7d, 0x5d, 0x7d, 0x7d, 0x5d, 0x7d, 0x7d, + 0x2c, 0x7b, 0x22, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x22, 0x3a, 0x7b, 0x22, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x3a, 0x31, 0x30, 0x30, 0x7d, 0x7d, 0x2c, 0x7b, 0x22, 0x64, + 0x69, 0x76, 0x69, 0x64, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x22, 0x3a, 0x7b, 0x22, 0x62, 0x69, 0x67, + 0x22, 0x3a, 0x22, 0x24, 0x7b, 0x54, 0x45, 0x4e, 0x7d, 0x22, 0x7d, 0x7d, 0x5d, 0x7d, 0x0a, 0x60, + 0x60, 0x60, 0x0a, 0x0a, 0x0d, 0x0a, 0x05, 0x04, 0x00, 0x03, 0x09, 0x01, 0x12, 0x04, 0xba, 0x02, + 0x0a, 0x14, 0x0a, 0x10, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x09, 0x08, 0x00, 0x12, 0x06, 0xbb, 0x02, + 0x04, 0xc4, 0x02, 0x05, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x09, 0x08, 0x00, 0x01, 0x12, + 0x04, 0xbb, 0x02, 0x0a, 0x15, 0x0a, 0x45, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x09, 0x02, 0x00, 0x12, + 0x04, 0xbd, 0x02, 0x06, 0x18, 0x1a, 0x35, 0x2f, 0x20, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, + 0x65, 0x73, 0x20, 0x61, 0x20, 0x62, 0x61, 0x73, 0x69, 0x63, 0x20, 0x73, 0x63, 0x61, 0x6c, 0x61, + 0x72, 0x20, 0x64, 0x65, 0x6e, 0x6f, 0x6d, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x20, 0x74, 0x6f, + 0x20, 0x64, 0x69, 0x76, 0x69, 0x64, 0x65, 0x20, 0x62, 0x79, 0x2e, 0x0a, 0x0a, 0x0f, 0x0a, 0x07, + 0x04, 0x00, 0x03, 0x09, 0x02, 0x00, 0x05, 0x12, 0x04, 0xbd, 0x02, 0x06, 0x0c, 0x0a, 0x0f, 0x0a, + 0x07, 0x04, 0x00, 0x03, 0x09, 0x02, 0x00, 0x01, 0x12, 0x04, 0xbd, 0x02, 0x0d, 0x13, 0x0a, 0x0f, + 0x0a, 0x07, 0x04, 0x00, 0x03, 0x09, 0x02, 0x00, 0x03, 0x12, 0x04, 0xbd, 0x02, 0x16, 0x17, 0x0a, + 0x43, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x09, 0x02, 0x01, 0x12, 0x04, 0xbf, 0x02, 0x06, 0x23, 0x1a, + 0x33, 0x2f, 0x20, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x65, 0x73, 0x20, 0x61, 0x6e, 0x6f, + 0x74, 0x68, 0x65, 0x72, 0x20, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x6f, 0x72, 0x20, + 0x72, 0x65, 0x73, 0x75, 0x74, 0x20, 0x74, 0x6f, 0x20, 0x64, 0x69, 0x76, 0x69, 0x64, 0x65, 0x20, + 0x62, 0x79, 0x2e, 0x0a, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x09, 0x02, 0x01, 0x05, 0x12, + 0x04, 0xbf, 0x02, 0x06, 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x09, 0x02, 0x01, 0x01, + 0x12, 0x04, 0xbf, 0x02, 0x0d, 0x1e, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x09, 0x02, 0x01, + 0x03, 0x12, 0x04, 0xbf, 0x02, 0x21, 0x22, 0x0a, 0x65, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x09, 0x02, + 0x02, 0x12, 0x04, 0xc1, 0x02, 0x06, 0x18, 0x1a, 0x55, 0x2f, 0x20, 0x41, 0x20, 0x6a, 0x6f, 0x62, + 0x20, 0x77, 0x68, 0x6f, 0x73, 0x65, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x20, 0x69, 0x73, + 0x20, 0x63, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x64, 0x20, 0x62, 0x65, 0x66, 0x6f, 0x72, 0x65, + 0x20, 0x64, 0x69, 0x76, 0x69, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x6f, 0x75, 0x72, 0x20, 0x6e, 0x75, + 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x6c, 0x20, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x20, 0x62, 0x79, + 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x2e, 0x0a, 0x0a, 0x0f, + 0x0a, 0x07, 0x04, 0x00, 0x03, 0x09, 0x02, 0x02, 0x06, 0x12, 0x04, 0xc1, 0x02, 0x06, 0x0f, 0x0a, + 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x09, 0x02, 0x02, 0x01, 0x12, 0x04, 0xc1, 0x02, 0x10, 0x13, + 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x09, 0x02, 0x02, 0x03, 0x12, 0x04, 0xc1, 0x02, 0x16, + 0x17, 0x0a, 0x4d, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x09, 0x02, 0x03, 0x12, 0x04, 0xc3, 0x02, 0x06, + 0x15, 0x1a, 0x3d, 0x2f, 0x20, 0x41, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x69, 0x66, 0x69, + 0x65, 0x64, 0x20, 0x62, 0x69, 0x67, 0x2e, 0x6a, 0x73, 0x2e, 0x20, 0x60, 0x41, 0x63, 0x63, 0x65, + 0x70, 0x74, 0x73, 0x20, 0x76, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x65, 0x78, 0x70, + 0x61, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x73, 0x79, 0x6e, 0x74, 0x61, 0x78, 0x2e, 0x60, 0x0a, + 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x09, 0x02, 0x03, 0x05, 0x12, 0x04, 0xc3, 0x02, 0x06, + 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x09, 0x02, 0x03, 0x01, 0x12, 0x04, 0xc3, 0x02, + 0x0d, 0x10, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x09, 0x02, 0x03, 0x03, 0x12, 0x04, 0xc3, + 0x02, 0x13, 0x14, 0x0a, 0xbc, 0x07, 0x0a, 0x04, 0x04, 0x00, 0x03, 0x0a, 0x12, 0x06, 0xe0, 0x02, + 0x02, 0xeb, 0x02, 0x03, 0x1a, 0xab, 0x07, 0x0a, 0x54, 0x68, 0x69, 0x73, 0x20, 0x74, 0x61, 0x73, + 0x6b, 0x20, 0x77, 0x69, 0x6c, 0x6c, 0x20, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x79, 0x20, + 0x61, 0x20, 0x6e, 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x6c, 0x20, 0x69, 0x6e, 0x70, 0x75, + 0x74, 0x20, 0x62, 0x79, 0x20, 0x61, 0x20, 0x73, 0x63, 0x61, 0x6c, 0x61, 0x72, 0x20, 0x76, 0x61, + 0x6c, 0x75, 0x65, 0x20, 0x66, 0x72, 0x6f, 0x6d, 0x20, 0x61, 0x20, 0x6a, 0x6f, 0x62, 0x20, 0x6f, + 0x66, 0x20, 0x73, 0x75, 0x62, 0x74, 0x61, 0x73, 0x6b, 0x73, 0x2c, 0x20, 0x61, 0x6e, 0x20, 0x61, + 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x6f, 0x72, 0x2c, 0x20, 0x6f, 0x72, 0x20, 0x61, 0x20, + 0x62, 0x69, 0x67, 0x2e, 0x0a, 0x0a, 0x5f, 0x2a, 0x2a, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x2a, 0x2a, + 0x5f, 0x3a, 0x20, 0x54, 0x68, 0x65, 0x20, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x20, 0x72, + 0x75, 0x6e, 0x6e, 0x69, 0x6e, 0x67, 0x20, 0x6e, 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x6c, + 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x20, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x20, 0x66, + 0x72, 0x6f, 0x6d, 0x20, 0x61, 0x20, 0x73, 0x63, 0x61, 0x6c, 0x61, 0x72, 0x20, 0x76, 0x61, 0x6c, + 0x75, 0x65, 0x2c, 0x20, 0x61, 0x6e, 0x20, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x6f, + 0x72, 0x2c, 0x20, 0x61, 0x20, 0x6a, 0x6f, 0x62, 0x20, 0x6f, 0x66, 0x20, 0x73, 0x75, 0x62, 0x74, + 0x61, 0x73, 0x6b, 0x73, 0x20, 0x6f, 0x72, 0x20, 0x61, 0x20, 0x62, 0x69, 0x67, 0x2e, 0x0a, 0x0a, + 0x5f, 0x2a, 0x2a, 0x52, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x73, 0x2a, 0x2a, 0x5f, 0x3a, 0x20, 0x41, + 0x20, 0x6e, 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x6c, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, + 0x74, 0x2e, 0x0a, 0x0a, 0x5f, 0x2a, 0x2a, 0x45, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2a, 0x2a, + 0x5f, 0x3a, 0x20, 0x52, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6e, + 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x6c, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x20, + 0x62, 0x79, 0x20, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x79, 0x69, 0x6e, 0x67, 0x20, 0x62, + 0x79, 0x20, 0x61, 0x20, 0x6a, 0x6f, 0x62, 0x20, 0x6f, 0x66, 0x20, 0x73, 0x75, 0x62, 0x74, 0x61, + 0x73, 0x6b, 0x73, 0x2e, 0x0a, 0x0a, 0x60, 0x60, 0x60, 0x6a, 0x73, 0x6f, 0x6e, 0x0a, 0x7b, 0x22, + 0x74, 0x61, 0x73, 0x6b, 0x73, 0x22, 0x3a, 0x5b, 0x7b, 0x22, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x54, + 0x61, 0x73, 0x6b, 0x22, 0x3a, 0x7b, 0x22, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x3a, 0x31, 0x30, + 0x30, 0x7d, 0x7d, 0x2c, 0x7b, 0x22, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x79, 0x54, 0x61, + 0x73, 0x6b, 0x22, 0x3a, 0x7b, 0x22, 0x6a, 0x6f, 0x62, 0x22, 0x3a, 0x7b, 0x22, 0x74, 0x61, 0x73, + 0x6b, 0x73, 0x22, 0x3a, 0x5b, 0x7b, 0x22, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x54, 0x61, 0x73, 0x6b, + 0x22, 0x3a, 0x7b, 0x22, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x3a, 0x31, 0x30, 0x7d, 0x7d, 0x5d, + 0x7d, 0x7d, 0x7d, 0x5d, 0x7d, 0x0a, 0x60, 0x60, 0x60, 0x0a, 0x0a, 0x5f, 0x2a, 0x2a, 0x45, 0x78, + 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2a, 0x2a, 0x5f, 0x3a, 0x20, 0x52, 0x65, 0x74, 0x75, 0x72, 0x6e, + 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6e, 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x6c, 0x20, + 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x20, 0x62, 0x79, 0x20, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, + 0x6c, 0x79, 0x69, 0x6e, 0x67, 0x20, 0x62, 0x79, 0x20, 0x61, 0x6e, 0x20, 0x61, 0x67, 0x67, 0x72, + 0x65, 0x67, 0x61, 0x74, 0x6f, 0x72, 0x2e, 0x0a, 0x0a, 0x60, 0x60, 0x60, 0x6a, 0x73, 0x6f, 0x6e, + 0x0a, 0x7b, 0x22, 0x74, 0x61, 0x73, 0x6b, 0x73, 0x22, 0x3a, 0x5b, 0x7b, 0x22, 0x76, 0x61, 0x6c, + 0x75, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x22, 0x3a, 0x7b, 0x22, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, + 0x3a, 0x31, 0x30, 0x30, 0x7d, 0x7d, 0x2c, 0x7b, 0x22, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, + 0x79, 0x54, 0x61, 0x73, 0x6b, 0x22, 0x3a, 0x7b, 0x22, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, + 0x74, 0x6f, 0x72, 0x50, 0x75, 0x62, 0x6b, 0x65, 0x79, 0x22, 0x3a, 0x22, 0x47, 0x76, 0x44, 0x4d, + 0x78, 0x50, 0x7a, 0x4e, 0x31, 0x73, 0x43, 0x6a, 0x37, 0x4c, 0x32, 0x36, 0x59, 0x44, 0x4b, 0x32, + 0x48, 0x6e, 0x4d, 0x52, 0x58, 0x45, 0x51, 0x6d, 0x51, 0x32, 0x61, 0x65, 0x6d, 0x6f, 0x76, 0x38, + 0x59, 0x42, 0x74, 0x50, 0x53, 0x37, 0x76, 0x52, 0x22, 0x7d, 0x7d, 0x5d, 0x7d, 0x0a, 0x60, 0x60, + 0x60, 0x0a, 0x0a, 0x5f, 0x2a, 0x2a, 0x45, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2a, 0x2a, 0x5f, + 0x3a, 0x20, 0x52, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6e, 0x75, + 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x6c, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x20, 0x62, + 0x79, 0x20, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x79, 0x69, 0x6e, 0x67, 0x20, 0x62, 0x79, + 0x20, 0x61, 0x20, 0x62, 0x69, 0x67, 0x2e, 0x0a, 0x0a, 0x60, 0x60, 0x60, 0x6a, 0x73, 0x6f, 0x6e, + 0x0a, 0x7b, 0x22, 0x74, 0x61, 0x73, 0x6b, 0x73, 0x22, 0x3a, 0x5b, 0x7b, 0x22, 0x63, 0x61, 0x63, + 0x68, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x22, 0x3a, 0x7b, 0x22, 0x63, 0x61, 0x63, 0x68, 0x65, 0x49, + 0x74, 0x65, 0x6d, 0x73, 0x22, 0x3a, 0x5b, 0x7b, 0x22, 0x76, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, + 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0x3a, 0x22, 0x54, 0x45, 0x4e, 0x22, 0x2c, 0x22, 0x6a, 0x6f, + 0x62, 0x22, 0x3a, 0x7b, 0x22, 0x74, 0x61, 0x73, 0x6b, 0x73, 0x22, 0x3a, 0x5b, 0x7b, 0x22, 0x76, + 0x61, 0x6c, 0x75, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x22, 0x3a, 0x7b, 0x22, 0x76, 0x61, 0x6c, 0x75, + 0x65, 0x22, 0x3a, 0x31, 0x30, 0x7d, 0x7d, 0x5d, 0x7d, 0x7d, 0x5d, 0x7d, 0x7d, 0x2c, 0x7b, 0x22, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x22, 0x3a, 0x7b, 0x22, 0x76, 0x61, 0x6c, + 0x75, 0x65, 0x22, 0x3a, 0x31, 0x30, 0x30, 0x7d, 0x7d, 0x2c, 0x7b, 0x22, 0x6d, 0x75, 0x6c, 0x74, + 0x69, 0x70, 0x6c, 0x79, 0x54, 0x61, 0x73, 0x6b, 0x22, 0x3a, 0x7b, 0x22, 0x62, 0x69, 0x67, 0x22, + 0x3a, 0x22, 0x24, 0x7b, 0x54, 0x45, 0x4e, 0x7d, 0x22, 0x7d, 0x7d, 0x5d, 0x7d, 0x0a, 0x60, 0x60, + 0x60, 0x0a, 0x0a, 0x0d, 0x0a, 0x05, 0x04, 0x00, 0x03, 0x0a, 0x01, 0x12, 0x04, 0xe0, 0x02, 0x0a, + 0x16, 0x0a, 0x10, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x0a, 0x08, 0x00, 0x12, 0x06, 0xe1, 0x02, 0x04, + 0xea, 0x02, 0x05, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x0a, 0x08, 0x00, 0x01, 0x12, 0x04, + 0xe1, 0x02, 0x0a, 0x12, 0x0a, 0x35, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x0a, 0x02, 0x00, 0x12, 0x04, + 0xe3, 0x02, 0x06, 0x18, 0x1a, 0x25, 0x2f, 0x20, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x65, + 0x73, 0x20, 0x61, 0x20, 0x73, 0x63, 0x61, 0x6c, 0x61, 0x72, 0x20, 0x74, 0x6f, 0x20, 0x6d, 0x75, + 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x79, 0x20, 0x62, 0x79, 0x2e, 0x0a, 0x0a, 0x0f, 0x0a, 0x07, 0x04, + 0x00, 0x03, 0x0a, 0x02, 0x00, 0x05, 0x12, 0x04, 0xe3, 0x02, 0x06, 0x0c, 0x0a, 0x0f, 0x0a, 0x07, + 0x04, 0x00, 0x03, 0x0a, 0x02, 0x00, 0x01, 0x12, 0x04, 0xe3, 0x02, 0x0d, 0x13, 0x0a, 0x0f, 0x0a, + 0x07, 0x04, 0x00, 0x03, 0x0a, 0x02, 0x00, 0x03, 0x12, 0x04, 0xe3, 0x02, 0x16, 0x17, 0x0a, 0x3a, + 0x0a, 0x06, 0x04, 0x00, 0x03, 0x0a, 0x02, 0x01, 0x12, 0x04, 0xe5, 0x02, 0x06, 0x23, 0x1a, 0x2a, + 0x2f, 0x20, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x65, 0x73, 0x20, 0x61, 0x6e, 0x20, 0x61, + 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x6f, 0x72, 0x20, 0x74, 0x6f, 0x20, 0x6d, 0x75, 0x6c, + 0x74, 0x69, 0x70, 0x6c, 0x79, 0x20, 0x62, 0x79, 0x2e, 0x0a, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, + 0x03, 0x0a, 0x02, 0x01, 0x05, 0x12, 0x04, 0xe5, 0x02, 0x06, 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, + 0x00, 0x03, 0x0a, 0x02, 0x01, 0x01, 0x12, 0x04, 0xe5, 0x02, 0x0d, 0x1e, 0x0a, 0x0f, 0x0a, 0x07, + 0x04, 0x00, 0x03, 0x0a, 0x02, 0x01, 0x03, 0x12, 0x04, 0xe5, 0x02, 0x21, 0x22, 0x0a, 0x68, 0x0a, + 0x06, 0x04, 0x00, 0x03, 0x0a, 0x02, 0x02, 0x12, 0x04, 0xe7, 0x02, 0x06, 0x18, 0x1a, 0x58, 0x2f, + 0x20, 0x41, 0x20, 0x6a, 0x6f, 0x62, 0x20, 0x77, 0x68, 0x6f, 0x73, 0x65, 0x20, 0x72, 0x65, 0x73, + 0x75, 0x6c, 0x74, 0x20, 0x69, 0x73, 0x20, 0x63, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x64, 0x20, + 0x62, 0x65, 0x66, 0x6f, 0x72, 0x65, 0x20, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x79, 0x69, + 0x6e, 0x67, 0x20, 0x6f, 0x75, 0x72, 0x20, 0x6e, 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x6c, + 0x20, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x20, 0x62, 0x79, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x72, + 0x65, 0x73, 0x75, 0x6c, 0x74, 0x2e, 0x0a, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x0a, 0x02, + 0x02, 0x06, 0x12, 0x04, 0xe7, 0x02, 0x06, 0x0f, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x0a, + 0x02, 0x02, 0x01, 0x12, 0x04, 0xe7, 0x02, 0x10, 0x13, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, + 0x0a, 0x02, 0x02, 0x03, 0x12, 0x04, 0xe7, 0x02, 0x16, 0x17, 0x0a, 0x4d, 0x0a, 0x06, 0x04, 0x00, + 0x03, 0x0a, 0x02, 0x03, 0x12, 0x04, 0xe9, 0x02, 0x06, 0x15, 0x1a, 0x3d, 0x2f, 0x20, 0x41, 0x20, + 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x69, 0x66, 0x69, 0x65, 0x64, 0x20, 0x62, 0x69, 0x67, 0x2e, + 0x6a, 0x73, 0x2e, 0x20, 0x60, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x73, 0x20, 0x76, 0x61, 0x72, + 0x69, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x65, 0x78, 0x70, 0x61, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x20, + 0x73, 0x79, 0x6e, 0x74, 0x61, 0x78, 0x2e, 0x60, 0x0a, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, + 0x0a, 0x02, 0x03, 0x05, 0x12, 0x04, 0xe9, 0x02, 0x06, 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, + 0x03, 0x0a, 0x02, 0x03, 0x01, 0x12, 0x04, 0xe9, 0x02, 0x0d, 0x10, 0x0a, 0x0f, 0x0a, 0x07, 0x04, + 0x00, 0x03, 0x0a, 0x02, 0x03, 0x03, 0x12, 0x04, 0xe9, 0x02, 0x13, 0x14, 0x0a, 0xa3, 0x07, 0x0a, + 0x04, 0x04, 0x00, 0x03, 0x0b, 0x12, 0x06, 0x86, 0x03, 0x02, 0x91, 0x03, 0x03, 0x1a, 0x92, 0x07, + 0x0a, 0x54, 0x68, 0x69, 0x73, 0x20, 0x74, 0x61, 0x73, 0x6b, 0x20, 0x77, 0x69, 0x6c, 0x6c, 0x20, + 0x61, 0x64, 0x64, 0x20, 0x61, 0x20, 0x6e, 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x6c, 0x20, + 0x69, 0x6e, 0x70, 0x75, 0x74, 0x20, 0x62, 0x79, 0x20, 0x61, 0x20, 0x73, 0x63, 0x61, 0x6c, 0x61, + 0x72, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x20, 0x66, 0x72, 0x6f, 0x6d, 0x20, 0x61, 0x20, 0x6a, + 0x6f, 0x62, 0x20, 0x6f, 0x66, 0x20, 0x73, 0x75, 0x62, 0x74, 0x61, 0x73, 0x6b, 0x73, 0x2c, 0x20, + 0x61, 0x6e, 0x20, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x6f, 0x72, 0x2c, 0x20, 0x6f, + 0x72, 0x20, 0x61, 0x20, 0x62, 0x69, 0x67, 0x2e, 0x0a, 0x0a, 0x5f, 0x2a, 0x2a, 0x49, 0x6e, 0x70, + 0x75, 0x74, 0x2a, 0x2a, 0x5f, 0x3a, 0x20, 0x54, 0x68, 0x65, 0x20, 0x63, 0x75, 0x72, 0x72, 0x65, + 0x6e, 0x74, 0x20, 0x72, 0x75, 0x6e, 0x6e, 0x69, 0x6e, 0x67, 0x20, 0x6e, 0x75, 0x6d, 0x65, 0x72, + 0x69, 0x63, 0x61, 0x6c, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x20, 0x6f, 0x75, 0x74, 0x70, + 0x75, 0x74, 0x20, 0x66, 0x72, 0x6f, 0x6d, 0x20, 0x61, 0x20, 0x73, 0x63, 0x61, 0x6c, 0x61, 0x72, + 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x2c, 0x20, 0x61, 0x6e, 0x20, 0x61, 0x67, 0x67, 0x72, 0x65, + 0x67, 0x61, 0x74, 0x6f, 0x72, 0x2c, 0x20, 0x61, 0x20, 0x6a, 0x6f, 0x62, 0x20, 0x6f, 0x66, 0x20, + 0x73, 0x75, 0x62, 0x74, 0x61, 0x73, 0x6b, 0x73, 0x20, 0x6f, 0x72, 0x20, 0x61, 0x20, 0x62, 0x69, + 0x67, 0x2e, 0x0a, 0x0a, 0x5f, 0x2a, 0x2a, 0x52, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x73, 0x2a, 0x2a, + 0x5f, 0x3a, 0x20, 0x41, 0x20, 0x6e, 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x6c, 0x20, 0x72, + 0x65, 0x73, 0x75, 0x6c, 0x74, 0x2e, 0x0a, 0x0a, 0x5f, 0x2a, 0x2a, 0x45, 0x78, 0x61, 0x6d, 0x70, + 0x6c, 0x65, 0x2a, 0x2a, 0x5f, 0x3a, 0x20, 0x52, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x73, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x6e, 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x6c, 0x20, 0x72, 0x65, 0x73, + 0x75, 0x6c, 0x74, 0x20, 0x62, 0x79, 0x20, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x62, 0x79, + 0x20, 0x61, 0x20, 0x6a, 0x6f, 0x62, 0x20, 0x6f, 0x66, 0x20, 0x73, 0x75, 0x62, 0x74, 0x61, 0x73, + 0x6b, 0x73, 0x2e, 0x0a, 0x0a, 0x60, 0x60, 0x60, 0x6a, 0x73, 0x6f, 0x6e, 0x0a, 0x7b, 0x22, 0x74, + 0x61, 0x73, 0x6b, 0x73, 0x22, 0x3a, 0x5b, 0x7b, 0x22, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x54, 0x61, + 0x73, 0x6b, 0x22, 0x3a, 0x7b, 0x22, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x3a, 0x31, 0x30, 0x30, + 0x7d, 0x7d, 0x2c, 0x7b, 0x22, 0x61, 0x64, 0x64, 0x54, 0x61, 0x73, 0x6b, 0x22, 0x3a, 0x7b, 0x22, + 0x6a, 0x6f, 0x62, 0x22, 0x3a, 0x7b, 0x22, 0x74, 0x61, 0x73, 0x6b, 0x73, 0x22, 0x3a, 0x5b, 0x7b, + 0x22, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x22, 0x3a, 0x7b, 0x22, 0x76, 0x61, + 0x6c, 0x75, 0x65, 0x22, 0x3a, 0x31, 0x30, 0x7d, 0x7d, 0x5d, 0x7d, 0x7d, 0x7d, 0x5d, 0x7d, 0x0a, + 0x60, 0x60, 0x60, 0x0a, 0x0a, 0x5f, 0x2a, 0x2a, 0x45, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2a, + 0x2a, 0x5f, 0x3a, 0x20, 0x52, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x6e, 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x6c, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, + 0x20, 0x62, 0x79, 0x20, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x79, 0x69, 0x6e, 0x67, 0x20, + 0x62, 0x79, 0x20, 0x61, 0x6e, 0x20, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x6f, 0x72, + 0x2e, 0x0a, 0x0a, 0x60, 0x60, 0x60, 0x6a, 0x73, 0x6f, 0x6e, 0x0a, 0x7b, 0x22, 0x74, 0x61, 0x73, + 0x6b, 0x73, 0x22, 0x3a, 0x5b, 0x7b, 0x22, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x54, 0x61, 0x73, 0x6b, + 0x22, 0x3a, 0x7b, 0x22, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x3a, 0x31, 0x30, 0x30, 0x7d, 0x7d, + 0x2c, 0x7b, 0x22, 0x61, 0x64, 0x64, 0x54, 0x61, 0x73, 0x6b, 0x22, 0x3a, 0x7b, 0x22, 0x61, 0x67, + 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x6f, 0x72, 0x50, 0x75, 0x62, 0x6b, 0x65, 0x79, 0x22, 0x3a, + 0x22, 0x47, 0x76, 0x44, 0x4d, 0x78, 0x50, 0x7a, 0x4e, 0x31, 0x73, 0x43, 0x6a, 0x37, 0x4c, 0x32, + 0x36, 0x59, 0x44, 0x4b, 0x32, 0x48, 0x6e, 0x4d, 0x52, 0x58, 0x45, 0x51, 0x6d, 0x51, 0x32, 0x61, + 0x65, 0x6d, 0x6f, 0x76, 0x38, 0x59, 0x42, 0x74, 0x50, 0x53, 0x37, 0x76, 0x52, 0x22, 0x7d, 0x7d, + 0x5d, 0x7d, 0x0a, 0x60, 0x60, 0x60, 0x0a, 0x0a, 0x5f, 0x2a, 0x2a, 0x45, 0x78, 0x61, 0x6d, 0x70, + 0x6c, 0x65, 0x2a, 0x2a, 0x5f, 0x3a, 0x20, 0x52, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x73, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x6e, 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x6c, 0x20, 0x72, 0x65, 0x73, + 0x75, 0x6c, 0x74, 0x20, 0x62, 0x79, 0x20, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x79, 0x69, + 0x6e, 0x67, 0x20, 0x62, 0x79, 0x20, 0x61, 0x20, 0x62, 0x69, 0x67, 0x2e, 0x0a, 0x0a, 0x60, 0x60, + 0x60, 0x6a, 0x73, 0x6f, 0x6e, 0x0a, 0x7b, 0x22, 0x74, 0x61, 0x73, 0x6b, 0x73, 0x22, 0x3a, 0x5b, + 0x7b, 0x22, 0x63, 0x61, 0x63, 0x68, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x22, 0x3a, 0x7b, 0x22, 0x63, + 0x61, 0x63, 0x68, 0x65, 0x49, 0x74, 0x65, 0x6d, 0x73, 0x22, 0x3a, 0x5b, 0x7b, 0x22, 0x76, 0x61, + 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0x3a, 0x22, 0x54, 0x45, 0x4e, + 0x22, 0x2c, 0x22, 0x6a, 0x6f, 0x62, 0x22, 0x3a, 0x7b, 0x22, 0x74, 0x61, 0x73, 0x6b, 0x73, 0x22, + 0x3a, 0x5b, 0x7b, 0x22, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x22, 0x3a, 0x7b, + 0x22, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x3a, 0x31, 0x30, 0x7d, 0x7d, 0x5d, 0x7d, 0x7d, 0x5d, + 0x7d, 0x7d, 0x2c, 0x7b, 0x22, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x22, 0x3a, + 0x7b, 0x22, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x3a, 0x31, 0x30, 0x30, 0x7d, 0x7d, 0x2c, 0x7b, + 0x22, 0x61, 0x64, 0x64, 0x54, 0x61, 0x73, 0x6b, 0x22, 0x3a, 0x7b, 0x22, 0x62, 0x69, 0x67, 0x22, + 0x3a, 0x22, 0x24, 0x7b, 0x54, 0x45, 0x4e, 0x7d, 0x22, 0x7d, 0x7d, 0x5d, 0x7d, 0x0a, 0x60, 0x60, + 0x60, 0x0a, 0x0a, 0x0d, 0x0a, 0x05, 0x04, 0x00, 0x03, 0x0b, 0x01, 0x12, 0x04, 0x86, 0x03, 0x0a, + 0x11, 0x0a, 0x10, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x0b, 0x08, 0x00, 0x12, 0x06, 0x87, 0x03, 0x04, + 0x90, 0x03, 0x05, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x0b, 0x08, 0x00, 0x01, 0x12, 0x04, + 0x87, 0x03, 0x0a, 0x12, 0x0a, 0x30, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x0b, 0x02, 0x00, 0x12, 0x04, + 0x89, 0x03, 0x06, 0x18, 0x1a, 0x20, 0x2f, 0x20, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x65, + 0x73, 0x20, 0x61, 0x20, 0x73, 0x63, 0x61, 0x6c, 0x61, 0x72, 0x20, 0x74, 0x6f, 0x20, 0x61, 0x64, + 0x64, 0x20, 0x62, 0x79, 0x2e, 0x0a, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x0b, 0x02, 0x00, + 0x05, 0x12, 0x04, 0x89, 0x03, 0x06, 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x0b, 0x02, + 0x00, 0x01, 0x12, 0x04, 0x89, 0x03, 0x0d, 0x13, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x0b, + 0x02, 0x00, 0x03, 0x12, 0x04, 0x89, 0x03, 0x16, 0x17, 0x0a, 0x35, 0x0a, 0x06, 0x04, 0x00, 0x03, + 0x0b, 0x02, 0x01, 0x12, 0x04, 0x8b, 0x03, 0x06, 0x23, 0x1a, 0x25, 0x2f, 0x20, 0x53, 0x70, 0x65, + 0x63, 0x69, 0x66, 0x69, 0x65, 0x73, 0x20, 0x61, 0x6e, 0x20, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, + 0x61, 0x74, 0x6f, 0x72, 0x20, 0x74, 0x6f, 0x20, 0x61, 0x64, 0x64, 0x20, 0x62, 0x79, 0x2e, 0x0a, + 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x0b, 0x02, 0x01, 0x05, 0x12, 0x04, 0x8b, 0x03, 0x06, + 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x0b, 0x02, 0x01, 0x01, 0x12, 0x04, 0x8b, 0x03, + 0x0d, 0x1e, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x0b, 0x02, 0x01, 0x03, 0x12, 0x04, 0x8b, + 0x03, 0x21, 0x22, 0x0a, 0x63, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x0b, 0x02, 0x02, 0x12, 0x04, 0x8d, + 0x03, 0x06, 0x18, 0x1a, 0x53, 0x2f, 0x20, 0x41, 0x20, 0x6a, 0x6f, 0x62, 0x20, 0x77, 0x68, 0x6f, + 0x73, 0x65, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x20, 0x69, 0x73, 0x20, 0x63, 0x6f, 0x6d, + 0x70, 0x75, 0x74, 0x65, 0x64, 0x20, 0x62, 0x65, 0x66, 0x6f, 0x72, 0x65, 0x20, 0x61, 0x64, 0x64, + 0x69, 0x6e, 0x67, 0x20, 0x6f, 0x75, 0x72, 0x20, 0x6e, 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, + 0x6c, 0x20, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x20, 0x62, 0x79, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, + 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x2e, 0x0a, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x0b, + 0x02, 0x02, 0x06, 0x12, 0x04, 0x8d, 0x03, 0x06, 0x0f, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, + 0x0b, 0x02, 0x02, 0x01, 0x12, 0x04, 0x8d, 0x03, 0x10, 0x13, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, + 0x03, 0x0b, 0x02, 0x02, 0x03, 0x12, 0x04, 0x8d, 0x03, 0x16, 0x17, 0x0a, 0x4d, 0x0a, 0x06, 0x04, + 0x00, 0x03, 0x0b, 0x02, 0x03, 0x12, 0x04, 0x8f, 0x03, 0x06, 0x15, 0x1a, 0x3d, 0x2f, 0x20, 0x41, + 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x69, 0x66, 0x69, 0x65, 0x64, 0x20, 0x62, 0x69, 0x67, + 0x2e, 0x6a, 0x73, 0x2e, 0x20, 0x60, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x73, 0x20, 0x76, 0x61, + 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x65, 0x78, 0x70, 0x61, 0x6e, 0x73, 0x69, 0x6f, 0x6e, + 0x20, 0x73, 0x79, 0x6e, 0x74, 0x61, 0x78, 0x2e, 0x60, 0x0a, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, + 0x03, 0x0b, 0x02, 0x03, 0x05, 0x12, 0x04, 0x8f, 0x03, 0x06, 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, + 0x00, 0x03, 0x0b, 0x02, 0x03, 0x01, 0x12, 0x04, 0x8f, 0x03, 0x0d, 0x10, 0x0a, 0x0f, 0x0a, 0x07, + 0x04, 0x00, 0x03, 0x0b, 0x02, 0x03, 0x03, 0x12, 0x04, 0x8f, 0x03, 0x13, 0x14, 0x0a, 0xbc, 0x07, + 0x0a, 0x04, 0x04, 0x00, 0x03, 0x0c, 0x12, 0x06, 0xac, 0x03, 0x02, 0xb7, 0x03, 0x03, 0x1a, 0xab, + 0x07, 0x0a, 0x54, 0x68, 0x69, 0x73, 0x20, 0x74, 0x61, 0x73, 0x6b, 0x20, 0x77, 0x69, 0x6c, 0x6c, + 0x20, 0x73, 0x75, 0x62, 0x74, 0x72, 0x61, 0x63, 0x74, 0x20, 0x61, 0x20, 0x6e, 0x75, 0x6d, 0x65, + 0x72, 0x69, 0x63, 0x61, 0x6c, 0x20, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x20, 0x62, 0x79, 0x20, 0x61, + 0x20, 0x73, 0x63, 0x61, 0x6c, 0x61, 0x72, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x20, 0x66, 0x72, + 0x6f, 0x6d, 0x20, 0x61, 0x20, 0x6a, 0x6f, 0x62, 0x20, 0x6f, 0x66, 0x20, 0x73, 0x75, 0x62, 0x74, + 0x61, 0x73, 0x6b, 0x73, 0x2c, 0x20, 0x61, 0x6e, 0x20, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, + 0x74, 0x6f, 0x72, 0x2c, 0x20, 0x6f, 0x72, 0x20, 0x61, 0x20, 0x62, 0x69, 0x67, 0x2e, 0x0a, 0x0a, + 0x5f, 0x2a, 0x2a, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x2a, 0x2a, 0x5f, 0x3a, 0x20, 0x54, 0x68, 0x65, + 0x20, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x20, 0x72, 0x75, 0x6e, 0x6e, 0x69, 0x6e, 0x67, + 0x20, 0x6e, 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x6c, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, + 0x74, 0x20, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x20, 0x66, 0x72, 0x6f, 0x6d, 0x20, 0x61, 0x20, + 0x73, 0x63, 0x61, 0x6c, 0x61, 0x72, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x2c, 0x20, 0x61, 0x6e, + 0x20, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x6f, 0x72, 0x2c, 0x20, 0x61, 0x20, 0x6a, + 0x6f, 0x62, 0x20, 0x6f, 0x66, 0x20, 0x73, 0x75, 0x62, 0x74, 0x61, 0x73, 0x6b, 0x73, 0x20, 0x6f, + 0x72, 0x20, 0x61, 0x20, 0x62, 0x69, 0x67, 0x2e, 0x0a, 0x0a, 0x5f, 0x2a, 0x2a, 0x52, 0x65, 0x74, + 0x75, 0x72, 0x6e, 0x73, 0x2a, 0x2a, 0x5f, 0x3a, 0x20, 0x41, 0x20, 0x6e, 0x75, 0x6d, 0x65, 0x72, + 0x69, 0x63, 0x61, 0x6c, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x2e, 0x0a, 0x0a, 0x5f, 0x2a, + 0x2a, 0x45, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2a, 0x2a, 0x5f, 0x3a, 0x20, 0x52, 0x65, 0x74, + 0x75, 0x72, 0x6e, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6e, 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, + 0x61, 0x6c, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x20, 0x62, 0x79, 0x20, 0x73, 0x75, 0x62, + 0x74, 0x72, 0x61, 0x63, 0x74, 0x69, 0x6e, 0x67, 0x20, 0x62, 0x79, 0x20, 0x61, 0x20, 0x6a, 0x6f, + 0x62, 0x20, 0x6f, 0x66, 0x20, 0x73, 0x75, 0x62, 0x74, 0x61, 0x73, 0x6b, 0x73, 0x2e, 0x0a, 0x0a, + 0x60, 0x60, 0x60, 0x6a, 0x73, 0x6f, 0x6e, 0x0a, 0x7b, 0x22, 0x74, 0x61, 0x73, 0x6b, 0x73, 0x22, + 0x3a, 0x5b, 0x7b, 0x22, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x22, 0x3a, 0x7b, + 0x22, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x3a, 0x31, 0x30, 0x30, 0x7d, 0x7d, 0x2c, 0x7b, 0x22, + 0x73, 0x75, 0x62, 0x74, 0x72, 0x61, 0x63, 0x74, 0x54, 0x61, 0x73, 0x6b, 0x22, 0x3a, 0x7b, 0x22, + 0x6a, 0x6f, 0x62, 0x22, 0x3a, 0x7b, 0x22, 0x74, 0x61, 0x73, 0x6b, 0x73, 0x22, 0x3a, 0x5b, 0x7b, + 0x22, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x22, 0x3a, 0x7b, 0x22, 0x76, 0x61, + 0x6c, 0x75, 0x65, 0x22, 0x3a, 0x31, 0x30, 0x7d, 0x7d, 0x5d, 0x7d, 0x7d, 0x7d, 0x5d, 0x7d, 0x0a, + 0x60, 0x60, 0x60, 0x0a, 0x0a, 0x5f, 0x2a, 0x2a, 0x45, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2a, + 0x2a, 0x5f, 0x3a, 0x20, 0x52, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x6e, 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x6c, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, + 0x20, 0x62, 0x79, 0x20, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x79, 0x69, 0x6e, 0x67, 0x20, + 0x62, 0x79, 0x20, 0x61, 0x6e, 0x20, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x6f, 0x72, + 0x2e, 0x0a, 0x0a, 0x60, 0x60, 0x60, 0x6a, 0x73, 0x6f, 0x6e, 0x0a, 0x7b, 0x22, 0x74, 0x61, 0x73, + 0x6b, 0x73, 0x22, 0x3a, 0x5b, 0x7b, 0x22, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x54, 0x61, 0x73, 0x6b, + 0x22, 0x3a, 0x7b, 0x22, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x3a, 0x31, 0x30, 0x30, 0x7d, 0x7d, + 0x2c, 0x7b, 0x22, 0x73, 0x75, 0x62, 0x74, 0x72, 0x61, 0x63, 0x74, 0x54, 0x61, 0x73, 0x6b, 0x22, + 0x3a, 0x7b, 0x22, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x6f, 0x72, 0x50, 0x75, 0x62, + 0x6b, 0x65, 0x79, 0x22, 0x3a, 0x22, 0x47, 0x76, 0x44, 0x4d, 0x78, 0x50, 0x7a, 0x4e, 0x31, 0x73, + 0x43, 0x6a, 0x37, 0x4c, 0x32, 0x36, 0x59, 0x44, 0x4b, 0x32, 0x48, 0x6e, 0x4d, 0x52, 0x58, 0x45, + 0x51, 0x6d, 0x51, 0x32, 0x61, 0x65, 0x6d, 0x6f, 0x76, 0x38, 0x59, 0x42, 0x74, 0x50, 0x53, 0x37, + 0x76, 0x52, 0x22, 0x7d, 0x7d, 0x5d, 0x7d, 0x0a, 0x60, 0x60, 0x60, 0x0a, 0x0a, 0x5f, 0x2a, 0x2a, + 0x45, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2a, 0x2a, 0x5f, 0x3a, 0x20, 0x52, 0x65, 0x74, 0x75, + 0x72, 0x6e, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6e, 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, + 0x6c, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x20, 0x62, 0x79, 0x20, 0x6d, 0x75, 0x6c, 0x74, + 0x69, 0x70, 0x6c, 0x79, 0x69, 0x6e, 0x67, 0x20, 0x62, 0x79, 0x20, 0x61, 0x20, 0x62, 0x69, 0x67, + 0x2e, 0x0a, 0x0a, 0x60, 0x60, 0x60, 0x6a, 0x73, 0x6f, 0x6e, 0x0a, 0x7b, 0x22, 0x74, 0x61, 0x73, + 0x6b, 0x73, 0x22, 0x3a, 0x5b, 0x7b, 0x22, 0x63, 0x61, 0x63, 0x68, 0x65, 0x54, 0x61, 0x73, 0x6b, + 0x22, 0x3a, 0x7b, 0x22, 0x63, 0x61, 0x63, 0x68, 0x65, 0x49, 0x74, 0x65, 0x6d, 0x73, 0x22, 0x3a, + 0x5b, 0x7b, 0x22, 0x76, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x22, + 0x3a, 0x22, 0x54, 0x45, 0x4e, 0x22, 0x2c, 0x22, 0x6a, 0x6f, 0x62, 0x22, 0x3a, 0x7b, 0x22, 0x74, + 0x61, 0x73, 0x6b, 0x73, 0x22, 0x3a, 0x5b, 0x7b, 0x22, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x54, 0x61, + 0x73, 0x6b, 0x22, 0x3a, 0x7b, 0x22, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x3a, 0x31, 0x30, 0x7d, + 0x7d, 0x5d, 0x7d, 0x7d, 0x5d, 0x7d, 0x7d, 0x2c, 0x7b, 0x22, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x54, + 0x61, 0x73, 0x6b, 0x22, 0x3a, 0x7b, 0x22, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x3a, 0x31, 0x30, + 0x30, 0x7d, 0x7d, 0x2c, 0x7b, 0x22, 0x73, 0x75, 0x62, 0x74, 0x72, 0x61, 0x63, 0x74, 0x54, 0x61, + 0x73, 0x6b, 0x22, 0x3a, 0x7b, 0x22, 0x62, 0x69, 0x67, 0x22, 0x3a, 0x22, 0x24, 0x7b, 0x54, 0x45, + 0x4e, 0x7d, 0x22, 0x7d, 0x7d, 0x5d, 0x7d, 0x0a, 0x60, 0x60, 0x60, 0x0a, 0x0a, 0x0d, 0x0a, 0x05, + 0x04, 0x00, 0x03, 0x0c, 0x01, 0x12, 0x04, 0xac, 0x03, 0x0a, 0x16, 0x0a, 0x10, 0x0a, 0x06, 0x04, + 0x00, 0x03, 0x0c, 0x08, 0x00, 0x12, 0x06, 0xad, 0x03, 0x04, 0xb6, 0x03, 0x05, 0x0a, 0x0f, 0x0a, + 0x07, 0x04, 0x00, 0x03, 0x0c, 0x08, 0x00, 0x01, 0x12, 0x04, 0xad, 0x03, 0x0a, 0x15, 0x0a, 0x35, + 0x0a, 0x06, 0x04, 0x00, 0x03, 0x0c, 0x02, 0x00, 0x12, 0x04, 0xaf, 0x03, 0x06, 0x18, 0x1a, 0x25, + 0x2f, 0x20, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x65, 0x73, 0x20, 0x61, 0x20, 0x73, 0x63, + 0x61, 0x6c, 0x61, 0x72, 0x20, 0x74, 0x6f, 0x20, 0x73, 0x75, 0x62, 0x74, 0x72, 0x61, 0x63, 0x74, + 0x20, 0x62, 0x79, 0x2e, 0x0a, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x0c, 0x02, 0x00, 0x05, + 0x12, 0x04, 0xaf, 0x03, 0x06, 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x0c, 0x02, 0x00, + 0x01, 0x12, 0x04, 0xaf, 0x03, 0x0d, 0x13, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x0c, 0x02, + 0x00, 0x03, 0x12, 0x04, 0xaf, 0x03, 0x16, 0x17, 0x0a, 0x3a, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x0c, + 0x02, 0x01, 0x12, 0x04, 0xb1, 0x03, 0x06, 0x23, 0x1a, 0x2a, 0x2f, 0x20, 0x53, 0x70, 0x65, 0x63, + 0x69, 0x66, 0x69, 0x65, 0x73, 0x20, 0x61, 0x6e, 0x20, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, + 0x74, 0x6f, 0x72, 0x20, 0x74, 0x6f, 0x20, 0x73, 0x75, 0x62, 0x74, 0x72, 0x61, 0x63, 0x74, 0x20, + 0x62, 0x79, 0x2e, 0x0a, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x0c, 0x02, 0x01, 0x05, 0x12, + 0x04, 0xb1, 0x03, 0x06, 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x0c, 0x02, 0x01, 0x01, + 0x12, 0x04, 0xb1, 0x03, 0x0d, 0x1e, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x0c, 0x02, 0x01, + 0x03, 0x12, 0x04, 0xb1, 0x03, 0x21, 0x22, 0x0a, 0x68, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x0c, 0x02, + 0x02, 0x12, 0x04, 0xb3, 0x03, 0x06, 0x18, 0x1a, 0x58, 0x2f, 0x20, 0x41, 0x20, 0x6a, 0x6f, 0x62, + 0x20, 0x77, 0x68, 0x6f, 0x73, 0x65, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x20, 0x69, 0x73, + 0x20, 0x63, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x64, 0x20, 0x62, 0x65, 0x66, 0x6f, 0x72, 0x65, + 0x20, 0x73, 0x75, 0x62, 0x74, 0x72, 0x61, 0x63, 0x74, 0x69, 0x6e, 0x67, 0x20, 0x6f, 0x75, 0x72, + 0x20, 0x6e, 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x6c, 0x20, 0x69, 0x6e, 0x70, 0x75, 0x74, + 0x20, 0x62, 0x79, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x2e, + 0x0a, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x0c, 0x02, 0x02, 0x06, 0x12, 0x04, 0xb3, 0x03, + 0x06, 0x0f, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x0c, 0x02, 0x02, 0x01, 0x12, 0x04, 0xb3, + 0x03, 0x10, 0x13, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x0c, 0x02, 0x02, 0x03, 0x12, 0x04, + 0xb3, 0x03, 0x16, 0x17, 0x0a, 0x4d, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x0c, 0x02, 0x03, 0x12, 0x04, + 0xb5, 0x03, 0x06, 0x15, 0x1a, 0x3d, 0x2f, 0x20, 0x41, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, + 0x69, 0x66, 0x69, 0x65, 0x64, 0x20, 0x62, 0x69, 0x67, 0x2e, 0x6a, 0x73, 0x2e, 0x20, 0x60, 0x41, + 0x63, 0x63, 0x65, 0x70, 0x74, 0x73, 0x20, 0x76, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x20, + 0x65, 0x78, 0x70, 0x61, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x73, 0x79, 0x6e, 0x74, 0x61, 0x78, + 0x2e, 0x60, 0x0a, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x0c, 0x02, 0x03, 0x05, 0x12, 0x04, + 0xb5, 0x03, 0x06, 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x0c, 0x02, 0x03, 0x01, 0x12, + 0x04, 0xb5, 0x03, 0x0d, 0x10, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x0c, 0x02, 0x03, 0x03, + 0x12, 0x04, 0xb5, 0x03, 0x13, 0x14, 0x0a, 0x8c, 0x09, 0x0a, 0x04, 0x04, 0x00, 0x03, 0x0d, 0x12, + 0x06, 0xd7, 0x03, 0x02, 0xe8, 0x03, 0x03, 0x1a, 0xfb, 0x08, 0x0a, 0x46, 0x65, 0x74, 0x63, 0x68, + 0x20, 0x4c, 0x50, 0x20, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x20, 0x70, 0x72, 0x69, 0x63, 0x65, 0x20, + 0x69, 0x6e, 0x66, 0x6f, 0x20, 0x66, 0x72, 0x6f, 0x6d, 0x20, 0x61, 0x20, 0x6e, 0x75, 0x6d, 0x62, + 0x65, 0x72, 0x20, 0x6f, 0x66, 0x20, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x20, + 0x65, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x2e, 0x0a, 0x0a, 0x53, 0x65, 0x65, 0x20, + 0x6f, 0x75, 0x72, 0x20, 0x62, 0x6c, 0x6f, 0x67, 0x20, 0x70, 0x6f, 0x73, 0x74, 0x20, 0x6f, 0x6e, + 0x20, 0x5b, 0x46, 0x61, 0x69, 0x72, 0x20, 0x4c, 0x50, 0x20, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x20, + 0x4f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x73, 0x5d, 0x28, 0x2f, 0x62, 0x6c, 0x6f, 0x67, 0x2f, 0x32, + 0x30, 0x32, 0x32, 0x2f, 0x30, 0x31, 0x2f, 0x32, 0x30, 0x2f, 0x46, 0x61, 0x69, 0x72, 0x2d, 0x4c, + 0x50, 0x2d, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x2d, 0x4f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x73, 0x29, + 0x0a, 0x0a, 0x2a, 0x4e, 0x4f, 0x54, 0x45, 0x2a, 0x2a, 0x3a, 0x20, 0x54, 0x68, 0x69, 0x73, 0x20, + 0x69, 0x73, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x77, 0x61, 0x70, 0x20, + 0x70, 0x72, 0x69, 0x63, 0x65, 0x20, 0x62, 0x75, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x72, + 0x69, 0x63, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x75, 0x6e, 0x64, 0x65, 0x72, + 0x6c, 0x79, 0x69, 0x6e, 0x67, 0x20, 0x4c, 0x50, 0x20, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x2e, 0x0a, + 0x0a, 0x5f, 0x2a, 0x2a, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x2a, 0x2a, 0x5f, 0x3a, 0x20, 0x4e, 0x6f, + 0x6e, 0x65, 0x0a, 0x0a, 0x5f, 0x2a, 0x2a, 0x52, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x73, 0x2a, 0x2a, + 0x5f, 0x3a, 0x20, 0x54, 0x68, 0x65, 0x20, 0x70, 0x72, 0x69, 0x63, 0x65, 0x20, 0x6f, 0x66, 0x20, + 0x61, 0x6e, 0x20, 0x4c, 0x50, 0x20, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x20, 0x66, 0x6f, 0x72, 0x20, + 0x61, 0x20, 0x67, 0x69, 0x76, 0x65, 0x6e, 0x20, 0x41, 0x4d, 0x4d, 0x20, 0x70, 0x6f, 0x6f, 0x6c, + 0x2e, 0x0a, 0x0a, 0x5f, 0x2a, 0x2a, 0x45, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2a, 0x2a, 0x5f, + 0x3a, 0x20, 0x46, 0x65, 0x74, 0x63, 0x68, 0x20, 0x74, 0x68, 0x65, 0x20, 0x4f, 0x72, 0x63, 0x61, + 0x20, 0x4c, 0x50, 0x20, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x20, 0x70, 0x72, 0x69, 0x63, 0x65, 0x20, + 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x53, 0x4f, 0x4c, 0x2f, 0x55, 0x53, 0x44, 0x43, 0x20, + 0x70, 0x6f, 0x6f, 0x6c, 0x0a, 0x0a, 0x60, 0x60, 0x60, 0x6a, 0x73, 0x6f, 0x6e, 0x0a, 0x7b, 0x20, + 0x22, 0x6c, 0x70, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x50, 0x72, 0x69, 0x63, 0x65, 0x54, 0x61, 0x73, + 0x6b, 0x22, 0x3a, 0x20, 0x7b, 0x20, 0x22, 0x6f, 0x72, 0x63, 0x61, 0x50, 0x6f, 0x6f, 0x6c, 0x41, + 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x22, 0x3a, 0x20, 0x22, 0x41, 0x50, 0x44, 0x46, 0x52, 0x4d, + 0x33, 0x48, 0x4d, 0x72, 0x38, 0x43, 0x41, 0x47, 0x58, 0x77, 0x4b, 0x48, 0x69, 0x75, 0x32, 0x66, + 0x35, 0x65, 0x50, 0x53, 0x70, 0x61, 0x69, 0x45, 0x4a, 0x68, 0x61, 0x55, 0x52, 0x77, 0x68, 0x73, + 0x52, 0x72, 0x55, 0x55, 0x74, 0x39, 0x22, 0x20, 0x7d, 0x20, 0x7d, 0x0a, 0x60, 0x60, 0x60, 0x0a, + 0x0a, 0x5f, 0x2a, 0x2a, 0x45, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2a, 0x2a, 0x5f, 0x3a, 0x20, + 0x46, 0x65, 0x74, 0x63, 0x68, 0x20, 0x74, 0x68, 0x65, 0x20, 0x66, 0x61, 0x69, 0x72, 0x20, 0x70, + 0x72, 0x69, 0x63, 0x65, 0x20, 0x4f, 0x72, 0x63, 0x61, 0x20, 0x4c, 0x50, 0x20, 0x74, 0x6f, 0x6b, + 0x65, 0x6e, 0x20, 0x70, 0x72, 0x69, 0x63, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x53, 0x4f, 0x4c, 0x2f, 0x55, 0x53, 0x44, 0x43, 0x20, 0x70, 0x6f, 0x6f, 0x6c, 0x0a, 0x0a, 0x60, + 0x60, 0x60, 0x6a, 0x73, 0x6f, 0x6e, 0x0a, 0x7b, 0x20, 0x22, 0x6c, 0x70, 0x54, 0x6f, 0x6b, 0x65, + 0x6e, 0x50, 0x72, 0x69, 0x63, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x22, 0x3a, 0x20, 0x7b, 0x20, 0x22, + 0x6f, 0x72, 0x63, 0x61, 0x50, 0x6f, 0x6f, 0x6c, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x22, + 0x3a, 0x20, 0x22, 0x41, 0x50, 0x44, 0x46, 0x52, 0x4d, 0x33, 0x48, 0x4d, 0x72, 0x38, 0x43, 0x41, + 0x47, 0x58, 0x77, 0x4b, 0x48, 0x69, 0x75, 0x32, 0x66, 0x35, 0x65, 0x50, 0x53, 0x70, 0x61, 0x69, + 0x45, 0x4a, 0x68, 0x61, 0x55, 0x52, 0x77, 0x68, 0x73, 0x52, 0x72, 0x55, 0x55, 0x74, 0x39, 0x22, + 0x2c, 0x20, 0x22, 0x75, 0x73, 0x65, 0x46, 0x61, 0x69, 0x72, 0x50, 0x72, 0x69, 0x63, 0x65, 0x22, + 0x3a, 0x20, 0x74, 0x72, 0x75, 0x65, 0x2c, 0x20, 0x22, 0x70, 0x72, 0x69, 0x63, 0x65, 0x46, 0x65, + 0x65, 0x64, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x22, 0x3a, 0x20, 0x5b, 0x20, + 0x22, 0x47, 0x76, 0x44, 0x4d, 0x78, 0x50, 0x7a, 0x4e, 0x31, 0x73, 0x43, 0x6a, 0x37, 0x4c, 0x32, + 0x36, 0x59, 0x44, 0x4b, 0x32, 0x48, 0x6e, 0x4d, 0x52, 0x58, 0x45, 0x51, 0x6d, 0x51, 0x32, 0x61, + 0x65, 0x6d, 0x6f, 0x76, 0x38, 0x59, 0x42, 0x74, 0x50, 0x53, 0x37, 0x76, 0x52, 0x22, 0x2c, 0x20, + 0x22, 0x42, 0x6a, 0x55, 0x67, 0x6a, 0x36, 0x59, 0x43, 0x6e, 0x46, 0x42, 0x5a, 0x34, 0x39, 0x77, + 0x46, 0x35, 0x34, 0x64, 0x64, 0x42, 0x56, 0x41, 0x39, 0x71, 0x75, 0x38, 0x54, 0x65, 0x71, 0x6b, + 0x46, 0x74, 0x6b, 0x62, 0x71, 0x6d, 0x5a, 0x63, 0x65, 0x65, 0x38, 0x75, 0x57, 0x22, 0x20, 0x5d, + 0x20, 0x7d, 0x20, 0x7d, 0x0a, 0x60, 0x60, 0x60, 0x0a, 0x0a, 0x5f, 0x2a, 0x2a, 0x45, 0x78, 0x61, + 0x6d, 0x70, 0x6c, 0x65, 0x2a, 0x2a, 0x5f, 0x3a, 0x20, 0x46, 0x65, 0x74, 0x63, 0x68, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x66, 0x61, 0x69, 0x72, 0x20, 0x70, 0x72, 0x69, 0x63, 0x65, 0x20, 0x52, 0x61, + 0x79, 0x64, 0x69, 0x75, 0x6d, 0x20, 0x4c, 0x50, 0x20, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x20, 0x70, + 0x72, 0x69, 0x63, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x53, 0x4f, 0x4c, 0x2f, + 0x55, 0x53, 0x44, 0x43, 0x20, 0x70, 0x6f, 0x6f, 0x6c, 0x0a, 0x0a, 0x60, 0x60, 0x60, 0x6a, 0x73, + 0x6f, 0x6e, 0x0a, 0x7b, 0x20, 0x22, 0x6c, 0x70, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x50, 0x72, 0x69, + 0x63, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x22, 0x3a, 0x20, 0x7b, 0x20, 0x22, 0x72, 0x61, 0x79, 0x64, + 0x69, 0x75, 0x6d, 0x50, 0x6f, 0x6f, 0x6c, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x22, 0x3a, + 0x20, 0x22, 0x35, 0x38, 0x6f, 0x51, 0x43, 0x68, 0x78, 0x34, 0x79, 0x57, 0x6d, 0x76, 0x4b, 0x64, + 0x77, 0x4c, 0x4c, 0x5a, 0x7a, 0x42, 0x69, 0x34, 0x43, 0x68, 0x6f, 0x43, 0x63, 0x32, 0x66, 0x71, + 0x43, 0x55, 0x57, 0x42, 0x6b, 0x77, 0x4d, 0x69, 0x68, 0x4c, 0x59, 0x51, 0x6f, 0x32, 0x22, 0x2c, + 0x20, 0x22, 0x75, 0x73, 0x65, 0x46, 0x61, 0x69, 0x72, 0x50, 0x72, 0x69, 0x63, 0x65, 0x22, 0x3a, + 0x20, 0x74, 0x72, 0x75, 0x65, 0x2c, 0x22, 0x70, 0x72, 0x69, 0x63, 0x65, 0x46, 0x65, 0x65, 0x64, + 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x22, 0x3a, 0x20, 0x5b, 0x22, 0x47, 0x76, + 0x44, 0x4d, 0x78, 0x50, 0x7a, 0x4e, 0x31, 0x73, 0x43, 0x6a, 0x37, 0x4c, 0x32, 0x36, 0x59, 0x44, + 0x4b, 0x32, 0x48, 0x6e, 0x4d, 0x52, 0x58, 0x45, 0x51, 0x6d, 0x51, 0x32, 0x61, 0x65, 0x6d, 0x6f, + 0x76, 0x38, 0x59, 0x42, 0x74, 0x50, 0x53, 0x37, 0x76, 0x52, 0x22, 0x2c, 0x22, 0x42, 0x6a, 0x55, + 0x67, 0x6a, 0x36, 0x59, 0x43, 0x6e, 0x46, 0x42, 0x5a, 0x34, 0x39, 0x77, 0x46, 0x35, 0x34, 0x64, + 0x64, 0x42, 0x56, 0x41, 0x39, 0x71, 0x75, 0x38, 0x54, 0x65, 0x71, 0x6b, 0x46, 0x74, 0x6b, 0x62, + 0x71, 0x6d, 0x5a, 0x63, 0x65, 0x65, 0x38, 0x75, 0x57, 0x22, 0x20, 0x5d, 0x20, 0x7d, 0x20, 0x7d, + 0x0a, 0x60, 0x60, 0x60, 0x0a, 0x0a, 0x0d, 0x0a, 0x05, 0x04, 0x00, 0x03, 0x0d, 0x01, 0x12, 0x04, + 0xd7, 0x03, 0x0a, 0x1a, 0x0a, 0x10, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x0d, 0x08, 0x00, 0x12, 0x06, + 0xd8, 0x03, 0x04, 0xe1, 0x03, 0x05, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x0d, 0x08, 0x00, + 0x01, 0x12, 0x04, 0xd8, 0x03, 0x0a, 0x15, 0x0a, 0x8c, 0x01, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x0d, + 0x02, 0x00, 0x12, 0x04, 0xda, 0x03, 0x06, 0x28, 0x1a, 0x7c, 0x2f, 0x20, 0x4d, 0x65, 0x72, 0x63, + 0x75, 0x72, 0x69, 0x61, 0x6c, 0x20, 0x66, 0x69, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x20, 0x70, 0x6f, + 0x6f, 0x6c, 0x20, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x2e, 0x20, 0x41, 0x20, 0x66, 0x75, + 0x6c, 0x6c, 0x20, 0x6c, 0x69, 0x73, 0x74, 0x20, 0x63, 0x61, 0x6e, 0x20, 0x62, 0x65, 0x20, 0x66, + 0x6f, 0x75, 0x6e, 0x64, 0x20, 0x68, 0x65, 0x72, 0x65, 0x3a, 0x20, 0x68, 0x74, 0x74, 0x70, 0x73, + 0x3a, 0x2f, 0x2f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6d, 0x65, + 0x72, 0x63, 0x75, 0x72, 0x69, 0x61, 0x6c, 0x2d, 0x66, 0x69, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x2f, + 0x73, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x2d, 0x73, 0x77, 0x61, 0x70, 0x2d, 0x6e, 0x2d, 0x70, 0x6f, + 0x6f, 0x6c, 0x2d, 0x6a, 0x73, 0x0a, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x0d, 0x02, 0x00, + 0x05, 0x12, 0x04, 0xda, 0x03, 0x06, 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x0d, 0x02, + 0x00, 0x01, 0x12, 0x04, 0xda, 0x03, 0x0d, 0x23, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x0d, + 0x02, 0x00, 0x03, 0x12, 0x04, 0xda, 0x03, 0x26, 0x27, 0x0a, 0x75, 0x0a, 0x06, 0x04, 0x00, 0x03, + 0x0d, 0x02, 0x01, 0x12, 0x04, 0xdc, 0x03, 0x06, 0x24, 0x1a, 0x65, 0x2f, 0x20, 0x53, 0x61, 0x62, + 0x65, 0x72, 0x20, 0x70, 0x6f, 0x6f, 0x6c, 0x20, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x2e, + 0x20, 0x41, 0x20, 0x66, 0x75, 0x6c, 0x6c, 0x20, 0x6c, 0x69, 0x73, 0x74, 0x20, 0x63, 0x61, 0x6e, + 0x20, 0x62, 0x65, 0x20, 0x66, 0x6f, 0x75, 0x6e, 0x64, 0x20, 0x68, 0x65, 0x72, 0x65, 0x3a, 0x20, + 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, + 0x6f, 0x6d, 0x2f, 0x73, 0x61, 0x62, 0x65, 0x72, 0x2d, 0x68, 0x71, 0x2f, 0x73, 0x61, 0x62, 0x65, + 0x72, 0x2d, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x2d, 0x64, 0x69, 0x73, 0x74, 0x0a, + 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x0d, 0x02, 0x01, 0x05, 0x12, 0x04, 0xdc, 0x03, 0x06, + 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x0d, 0x02, 0x01, 0x01, 0x12, 0x04, 0xdc, 0x03, + 0x0d, 0x1f, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x0d, 0x02, 0x01, 0x03, 0x12, 0x04, 0xdc, + 0x03, 0x22, 0x23, 0x0a, 0x5e, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x0d, 0x02, 0x02, 0x12, 0x04, 0xde, + 0x03, 0x06, 0x23, 0x1a, 0x4e, 0x2f, 0x20, 0x4f, 0x72, 0x63, 0x61, 0x20, 0x70, 0x6f, 0x6f, 0x6c, + 0x20, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x2e, 0x20, 0x41, 0x20, 0x66, 0x75, 0x6c, 0x6c, + 0x20, 0x6c, 0x69, 0x73, 0x74, 0x20, 0x63, 0x61, 0x6e, 0x20, 0x62, 0x65, 0x20, 0x66, 0x6f, 0x75, + 0x6e, 0x64, 0x20, 0x68, 0x65, 0x72, 0x65, 0x3a, 0x20, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, + 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x6f, 0x72, 0x63, 0x61, 0x2e, 0x73, 0x6f, 0x2f, 0x70, 0x6f, 0x6f, + 0x6c, 0x73, 0x0a, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x0d, 0x02, 0x02, 0x05, 0x12, 0x04, + 0xde, 0x03, 0x06, 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x0d, 0x02, 0x02, 0x01, 0x12, + 0x04, 0xde, 0x03, 0x0d, 0x1e, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x0d, 0x02, 0x02, 0x03, + 0x12, 0x04, 0xde, 0x03, 0x21, 0x22, 0x0a, 0x6c, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x0d, 0x02, 0x03, + 0x12, 0x04, 0xe0, 0x03, 0x06, 0x26, 0x1a, 0x5c, 0x2f, 0x20, 0x54, 0x68, 0x65, 0x20, 0x52, 0x61, + 0x79, 0x64, 0x69, 0x75, 0x6d, 0x20, 0x6c, 0x69, 0x71, 0x75, 0x69, 0x64, 0x69, 0x74, 0x79, 0x20, + 0x70, 0x6f, 0x6f, 0x6c, 0x20, 0x61, 0x6d, 0x6d, 0x49, 0x64, 0x2e, 0x20, 0x41, 0x20, 0x66, 0x75, + 0x6c, 0x6c, 0x20, 0x6c, 0x69, 0x73, 0x74, 0x20, 0x63, 0x61, 0x6e, 0x20, 0x62, 0x65, 0x20, 0x66, + 0x6f, 0x75, 0x6e, 0x64, 0x20, 0x68, 0x65, 0x72, 0x65, 0x3a, 0x20, 0x68, 0x74, 0x74, 0x70, 0x73, + 0x3a, 0x2f, 0x2f, 0x72, 0x61, 0x79, 0x64, 0x69, 0x75, 0x6d, 0x2e, 0x69, 0x6f, 0x2f, 0x70, 0x6f, + 0x6f, 0x6c, 0x73, 0x0a, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x0d, 0x02, 0x03, 0x05, 0x12, + 0x04, 0xe0, 0x03, 0x06, 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x0d, 0x02, 0x03, 0x01, + 0x12, 0x04, 0xe0, 0x03, 0x0d, 0x21, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x0d, 0x02, 0x03, + 0x03, 0x12, 0x04, 0xe0, 0x03, 0x24, 0x25, 0x0a, 0xc3, 0x01, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x0d, + 0x02, 0x04, 0x12, 0x04, 0xe3, 0x03, 0x04, 0x2d, 0x1a, 0xb2, 0x01, 0x2f, 0x20, 0x41, 0x20, 0x6c, + 0x69, 0x73, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x53, 0x77, 0x69, 0x74, 0x63, 0x68, 0x62, 0x6f, 0x61, + 0x72, 0x64, 0x20, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x6f, 0x72, 0x20, 0x61, 0x63, + 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x20, 0x75, 0x73, 0x65, 0x64, 0x20, 0x74, 0x6f, 0x20, 0x63, + 0x61, 0x6c, 0x63, 0x75, 0x6c, 0x61, 0x74, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x66, 0x61, 0x69, + 0x72, 0x20, 0x4c, 0x50, 0x20, 0x70, 0x72, 0x69, 0x63, 0x65, 0x2e, 0x20, 0x54, 0x68, 0x69, 0x73, + 0x20, 0x65, 0x6e, 0x73, 0x75, 0x72, 0x65, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x72, 0x69, + 0x63, 0x65, 0x20, 0x69, 0x73, 0x20, 0x62, 0x61, 0x73, 0x65, 0x64, 0x20, 0x6f, 0x6e, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x70, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x20, 0x72, 0x6f, 0x75, 0x6e, + 0x64, 0x20, 0x74, 0x6f, 0x20, 0x6d, 0x69, 0x74, 0x69, 0x67, 0x61, 0x74, 0x65, 0x20, 0x66, 0x6c, + 0x61, 0x73, 0x68, 0x20, 0x6c, 0x6f, 0x61, 0x6e, 0x20, 0x70, 0x72, 0x69, 0x63, 0x65, 0x20, 0x6d, + 0x61, 0x6e, 0x69, 0x70, 0x75, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x0a, 0x0a, 0x0f, 0x0a, + 0x07, 0x04, 0x00, 0x03, 0x0d, 0x02, 0x04, 0x04, 0x12, 0x04, 0xe3, 0x03, 0x04, 0x0c, 0x0a, 0x0f, + 0x0a, 0x07, 0x04, 0x00, 0x03, 0x0d, 0x02, 0x04, 0x05, 0x12, 0x04, 0xe3, 0x03, 0x0d, 0x13, 0x0a, + 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x0d, 0x02, 0x04, 0x01, 0x12, 0x04, 0xe3, 0x03, 0x14, 0x28, + 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x0d, 0x02, 0x04, 0x03, 0x12, 0x04, 0xe3, 0x03, 0x2b, + 0x2c, 0x0a, 0x7b, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x0d, 0x02, 0x05, 0x12, 0x04, 0xe5, 0x03, 0x04, + 0x2b, 0x1a, 0x6b, 0x2f, 0x20, 0x41, 0x20, 0x6c, 0x69, 0x73, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x4f, + 0x72, 0x61, 0x63, 0x6c, 0x65, 0x4a, 0x6f, 0x62, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x65, 0x78, 0x65, + 0x63, 0x75, 0x74, 0x65, 0x20, 0x69, 0x6e, 0x20, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x20, 0x74, 0x6f, + 0x20, 0x79, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x72, 0x69, 0x63, 0x65, + 0x20, 0x66, 0x65, 0x65, 0x64, 0x20, 0x6a, 0x6f, 0x62, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x75, 0x73, + 0x65, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x74, 0x68, 0x65, 0x20, 0x66, 0x61, 0x69, 0x72, 0x20, 0x70, + 0x72, 0x69, 0x63, 0x65, 0x20, 0x66, 0x6f, 0x72, 0x6d, 0x75, 0x6c, 0x61, 0x2e, 0x0a, 0x0a, 0x0f, + 0x0a, 0x07, 0x04, 0x00, 0x03, 0x0d, 0x02, 0x05, 0x04, 0x12, 0x04, 0xe5, 0x03, 0x04, 0x0c, 0x0a, + 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x0d, 0x02, 0x05, 0x06, 0x12, 0x04, 0xe5, 0x03, 0x0d, 0x16, + 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x0d, 0x02, 0x05, 0x01, 0x12, 0x04, 0xe5, 0x03, 0x17, + 0x26, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x0d, 0x02, 0x05, 0x03, 0x12, 0x04, 0xe5, 0x03, + 0x29, 0x2a, 0x0a, 0x80, 0x02, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x0d, 0x02, 0x06, 0x12, 0x04, 0xe7, + 0x03, 0x04, 0x25, 0x1a, 0xef, 0x01, 0x2f, 0x20, 0x49, 0x66, 0x20, 0x65, 0x6e, 0x61, 0x62, 0x6c, + 0x65, 0x64, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x70, 0x72, 0x69, 0x63, 0x65, 0x5f, 0x66, 0x65, 0x65, + 0x64, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x20, 0x70, 0x72, 0x6f, 0x76, + 0x69, 0x64, 0x65, 0x64, 0x2c, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, + 0x20, 0x77, 0x69, 0x6c, 0x6c, 0x20, 0x63, 0x61, 0x6c, 0x63, 0x75, 0x6c, 0x61, 0x74, 0x65, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x66, 0x61, 0x69, 0x72, 0x20, 0x4c, 0x50, 0x20, 0x70, 0x72, 0x69, 0x63, + 0x65, 0x20, 0x62, 0x61, 0x73, 0x65, 0x64, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6c, + 0x69, 0x71, 0x75, 0x69, 0x64, 0x69, 0x74, 0x79, 0x20, 0x70, 0x6f, 0x6f, 0x6c, 0x20, 0x72, 0x65, + 0x73, 0x65, 0x72, 0x76, 0x65, 0x73, 0x2e, 0x20, 0x53, 0x65, 0x65, 0x20, 0x6f, 0x75, 0x72, 0x20, + 0x62, 0x6c, 0x6f, 0x67, 0x20, 0x70, 0x6f, 0x73, 0x74, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x6d, 0x6f, + 0x72, 0x65, 0x20, 0x69, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x20, + 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x73, 0x77, 0x69, 0x74, 0x63, 0x68, 0x62, 0x6f, + 0x61, 0x72, 0x64, 0x78, 0x79, 0x7a, 0x2e, 0x6d, 0x65, 0x64, 0x69, 0x75, 0x6d, 0x2e, 0x63, 0x6f, + 0x6d, 0x2f, 0x66, 0x61, 0x69, 0x72, 0x2d, 0x6c, 0x70, 0x2d, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x2d, + 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x73, 0x2d, 0x39, 0x34, 0x61, 0x34, 0x35, 0x37, 0x63, 0x35, + 0x30, 0x32, 0x33, 0x39, 0x0a, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x0d, 0x02, 0x06, 0x04, + 0x12, 0x04, 0xe7, 0x03, 0x04, 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x0d, 0x02, 0x06, + 0x05, 0x12, 0x04, 0xe7, 0x03, 0x0d, 0x11, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x0d, 0x02, + 0x06, 0x01, 0x12, 0x04, 0xe7, 0x03, 0x12, 0x20, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x0d, + 0x02, 0x06, 0x03, 0x12, 0x04, 0xe7, 0x03, 0x23, 0x24, 0x0a, 0xfa, 0x03, 0x0a, 0x04, 0x04, 0x00, + 0x03, 0x0e, 0x12, 0x06, 0xfd, 0x03, 0x02, 0x97, 0x04, 0x03, 0x1a, 0xe9, 0x03, 0x0a, 0x46, 0x65, + 0x74, 0x63, 0x68, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x20, + 0x73, 0x77, 0x61, 0x70, 0x20, 0x70, 0x72, 0x69, 0x63, 0x65, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x61, + 0x20, 0x67, 0x69, 0x76, 0x65, 0x6e, 0x20, 0x6c, 0x69, 0x71, 0x75, 0x69, 0x64, 0x69, 0x74, 0x79, + 0x20, 0x70, 0x6f, 0x6f, 0x6c, 0x0a, 0x0a, 0x5f, 0x2a, 0x2a, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x2a, + 0x2a, 0x5f, 0x3a, 0x20, 0x4e, 0x6f, 0x6e, 0x65, 0x0a, 0x0a, 0x5f, 0x2a, 0x2a, 0x52, 0x65, 0x74, + 0x75, 0x72, 0x6e, 0x73, 0x2a, 0x2a, 0x5f, 0x3a, 0x20, 0x54, 0x68, 0x65, 0x20, 0x73, 0x77, 0x61, + 0x70, 0x20, 0x70, 0x72, 0x69, 0x63, 0x65, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x61, 0x20, 0x67, 0x69, + 0x76, 0x65, 0x6e, 0x20, 0x41, 0x4d, 0x4d, 0x20, 0x70, 0x6f, 0x6f, 0x6c, 0x2e, 0x0a, 0x0a, 0x5f, + 0x2a, 0x2a, 0x45, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2a, 0x2a, 0x5f, 0x3a, 0x20, 0x46, 0x65, + 0x74, 0x63, 0x68, 0x20, 0x74, 0x68, 0x65, 0x20, 0x65, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, + 0x20, 0x72, 0x61, 0x74, 0x65, 0x20, 0x66, 0x72, 0x6f, 0x6d, 0x20, 0x74, 0x68, 0x65, 0x20, 0x4f, + 0x72, 0x63, 0x61, 0x20, 0x53, 0x4f, 0x4c, 0x2f, 0x55, 0x53, 0x44, 0x43, 0x20, 0x70, 0x6f, 0x6f, + 0x6c, 0x0a, 0x0a, 0x60, 0x60, 0x60, 0x6a, 0x73, 0x6f, 0x6e, 0x0a, 0x7b, 0x20, 0x22, 0x6c, 0x70, + 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x61, 0x74, 0x65, 0x54, 0x61, 0x73, 0x6b, + 0x22, 0x3a, 0x20, 0x7b, 0x20, 0x22, 0x6f, 0x72, 0x63, 0x61, 0x50, 0x6f, 0x6f, 0x6c, 0x41, 0x64, + 0x64, 0x72, 0x65, 0x73, 0x73, 0x22, 0x3a, 0x20, 0x22, 0x41, 0x50, 0x44, 0x46, 0x52, 0x4d, 0x33, + 0x48, 0x4d, 0x72, 0x38, 0x43, 0x41, 0x47, 0x58, 0x77, 0x4b, 0x48, 0x69, 0x75, 0x32, 0x66, 0x35, + 0x65, 0x50, 0x53, 0x70, 0x61, 0x69, 0x45, 0x4a, 0x68, 0x61, 0x55, 0x52, 0x77, 0x68, 0x73, 0x52, + 0x72, 0x55, 0x55, 0x74, 0x39, 0x22, 0x20, 0x7d, 0x20, 0x7d, 0x0a, 0x60, 0x60, 0x60, 0x0a, 0x0a, + 0x5f, 0x2a, 0x2a, 0x45, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2a, 0x2a, 0x5f, 0x3a, 0x20, 0x46, + 0x65, 0x74, 0x63, 0x68, 0x20, 0x74, 0x68, 0x65, 0x20, 0x65, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, + 0x65, 0x20, 0x72, 0x61, 0x74, 0x65, 0x20, 0x66, 0x72, 0x6f, 0x6d, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x52, 0x61, 0x79, 0x64, 0x69, 0x75, 0x6d, 0x20, 0x53, 0x4f, 0x4c, 0x2f, 0x55, 0x53, 0x44, 0x43, + 0x20, 0x70, 0x6f, 0x6f, 0x6c, 0x0a, 0x0a, 0x60, 0x60, 0x60, 0x6a, 0x73, 0x6f, 0x6e, 0x0a, 0x7b, + 0x20, 0x22, 0x6c, 0x70, 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x61, 0x74, 0x65, + 0x54, 0x61, 0x73, 0x6b, 0x22, 0x3a, 0x20, 0x7b, 0x20, 0x22, 0x72, 0x61, 0x79, 0x64, 0x69, 0x75, + 0x6d, 0x50, 0x6f, 0x6f, 0x6c, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x22, 0x3a, 0x20, 0x22, + 0x35, 0x38, 0x6f, 0x51, 0x43, 0x68, 0x78, 0x34, 0x79, 0x57, 0x6d, 0x76, 0x4b, 0x64, 0x77, 0x4c, + 0x4c, 0x5a, 0x7a, 0x42, 0x69, 0x34, 0x43, 0x68, 0x6f, 0x43, 0x63, 0x32, 0x66, 0x71, 0x43, 0x55, + 0x57, 0x42, 0x6b, 0x77, 0x4d, 0x69, 0x68, 0x4c, 0x59, 0x51, 0x6f, 0x32, 0x22, 0x20, 0x7d, 0x20, + 0x7d, 0x0a, 0x60, 0x60, 0x60, 0x0a, 0x0a, 0x0d, 0x0a, 0x05, 0x04, 0x00, 0x03, 0x0e, 0x01, 0x12, + 0x04, 0xfd, 0x03, 0x0a, 0x1c, 0x0a, 0x10, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x0e, 0x04, 0x00, 0x12, + 0x06, 0xfe, 0x03, 0x04, 0x81, 0x04, 0x05, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x0e, 0x04, + 0x00, 0x01, 0x12, 0x04, 0xfe, 0x03, 0x09, 0x0e, 0x0a, 0x10, 0x0a, 0x08, 0x04, 0x00, 0x03, 0x0e, + 0x04, 0x00, 0x02, 0x00, 0x12, 0x04, 0xff, 0x03, 0x06, 0x11, 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, + 0x03, 0x0e, 0x04, 0x00, 0x02, 0x00, 0x01, 0x12, 0x04, 0xff, 0x03, 0x06, 0x0c, 0x0a, 0x11, 0x0a, + 0x09, 0x04, 0x00, 0x03, 0x0e, 0x04, 0x00, 0x02, 0x00, 0x02, 0x12, 0x04, 0xff, 0x03, 0x0f, 0x10, + 0x0a, 0x10, 0x0a, 0x08, 0x04, 0x00, 0x03, 0x0e, 0x04, 0x00, 0x02, 0x01, 0x12, 0x04, 0x80, 0x04, + 0x06, 0x12, 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x0e, 0x04, 0x00, 0x02, 0x01, 0x01, 0x12, + 0x04, 0x80, 0x04, 0x06, 0x0d, 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x0e, 0x04, 0x00, 0x02, + 0x01, 0x02, 0x12, 0x04, 0x80, 0x04, 0x10, 0x11, 0x0a, 0x5f, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x0e, + 0x02, 0x00, 0x12, 0x04, 0x83, 0x04, 0x04, 0x29, 0x1a, 0x4f, 0x2f, 0x20, 0x55, 0x73, 0x65, 0x64, + 0x20, 0x61, 0x6c, 0x6f, 0x6e, 0x67, 0x73, 0x69, 0x64, 0x65, 0x20, 0x6d, 0x65, 0x72, 0x63, 0x75, + 0x72, 0x69, 0x61, 0x6c, 0x5f, 0x70, 0x6f, 0x6f, 0x6c, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, + 0x73, 0x20, 0x74, 0x6f, 0x20, 0x73, 0x70, 0x65, 0x63, 0x69, 0x66, 0x79, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x20, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x20, 0x66, 0x6f, 0x72, + 0x20, 0x61, 0x20, 0x73, 0x77, 0x61, 0x70, 0x2e, 0x0a, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, + 0x0e, 0x02, 0x00, 0x04, 0x12, 0x04, 0x83, 0x04, 0x04, 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, + 0x03, 0x0e, 0x02, 0x00, 0x05, 0x12, 0x04, 0x83, 0x04, 0x0d, 0x13, 0x0a, 0x0f, 0x0a, 0x07, 0x04, + 0x00, 0x03, 0x0e, 0x02, 0x00, 0x01, 0x12, 0x04, 0x83, 0x04, 0x14, 0x24, 0x0a, 0x0f, 0x0a, 0x07, + 0x04, 0x00, 0x03, 0x0e, 0x02, 0x00, 0x03, 0x12, 0x04, 0x83, 0x04, 0x27, 0x28, 0x0a, 0x60, 0x0a, + 0x06, 0x04, 0x00, 0x03, 0x0e, 0x02, 0x01, 0x12, 0x04, 0x85, 0x04, 0x04, 0x2a, 0x1a, 0x50, 0x2f, + 0x20, 0x55, 0x73, 0x65, 0x64, 0x20, 0x61, 0x6c, 0x6f, 0x6e, 0x67, 0x73, 0x69, 0x64, 0x65, 0x20, + 0x6d, 0x65, 0x72, 0x63, 0x75, 0x72, 0x69, 0x61, 0x6c, 0x5f, 0x70, 0x6f, 0x6f, 0x6c, 0x5f, 0x61, + 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x73, 0x70, 0x65, 0x63, 0x69, 0x66, + 0x79, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x20, 0x74, 0x6f, 0x6b, + 0x65, 0x6e, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x61, 0x20, 0x73, 0x77, 0x61, 0x70, 0x2e, 0x0a, 0x0a, + 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x0e, 0x02, 0x01, 0x04, 0x12, 0x04, 0x85, 0x04, 0x04, 0x0c, + 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x0e, 0x02, 0x01, 0x05, 0x12, 0x04, 0x85, 0x04, 0x0d, + 0x13, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x0e, 0x02, 0x01, 0x01, 0x12, 0x04, 0x85, 0x04, + 0x14, 0x25, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x0e, 0x02, 0x01, 0x03, 0x12, 0x04, 0x85, + 0x04, 0x28, 0x29, 0x0a, 0x10, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x0e, 0x08, 0x00, 0x12, 0x06, 0x86, + 0x04, 0x04, 0x94, 0x04, 0x05, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x0e, 0x08, 0x00, 0x01, + 0x12, 0x04, 0x86, 0x04, 0x0a, 0x15, 0x0a, 0x8c, 0x01, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x0e, 0x02, + 0x02, 0x12, 0x04, 0x88, 0x04, 0x06, 0x28, 0x1a, 0x7c, 0x2f, 0x20, 0x4d, 0x65, 0x72, 0x63, 0x75, + 0x72, 0x69, 0x61, 0x6c, 0x20, 0x66, 0x69, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x20, 0x70, 0x6f, 0x6f, + 0x6c, 0x20, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x2e, 0x20, 0x41, 0x20, 0x66, 0x75, 0x6c, + 0x6c, 0x20, 0x6c, 0x69, 0x73, 0x74, 0x20, 0x63, 0x61, 0x6e, 0x20, 0x62, 0x65, 0x20, 0x66, 0x6f, + 0x75, 0x6e, 0x64, 0x20, 0x68, 0x65, 0x72, 0x65, 0x3a, 0x20, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, + 0x2f, 0x2f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6d, 0x65, 0x72, + 0x63, 0x75, 0x72, 0x69, 0x61, 0x6c, 0x2d, 0x66, 0x69, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x2f, 0x73, + 0x74, 0x61, 0x62, 0x6c, 0x65, 0x2d, 0x73, 0x77, 0x61, 0x70, 0x2d, 0x6e, 0x2d, 0x70, 0x6f, 0x6f, + 0x6c, 0x2d, 0x6a, 0x73, 0x0a, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x0e, 0x02, 0x02, 0x05, + 0x12, 0x04, 0x88, 0x04, 0x06, 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x0e, 0x02, 0x02, + 0x01, 0x12, 0x04, 0x88, 0x04, 0x0d, 0x23, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x0e, 0x02, + 0x02, 0x03, 0x12, 0x04, 0x88, 0x04, 0x26, 0x27, 0x0a, 0x75, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x0e, + 0x02, 0x03, 0x12, 0x04, 0x8a, 0x04, 0x06, 0x24, 0x1a, 0x65, 0x2f, 0x20, 0x53, 0x61, 0x62, 0x65, + 0x72, 0x20, 0x70, 0x6f, 0x6f, 0x6c, 0x20, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x2e, 0x20, + 0x41, 0x20, 0x66, 0x75, 0x6c, 0x6c, 0x20, 0x6c, 0x69, 0x73, 0x74, 0x20, 0x63, 0x61, 0x6e, 0x20, + 0x62, 0x65, 0x20, 0x66, 0x6f, 0x75, 0x6e, 0x64, 0x20, 0x68, 0x65, 0x72, 0x65, 0x3a, 0x20, 0x68, + 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, + 0x6d, 0x2f, 0x73, 0x61, 0x62, 0x65, 0x72, 0x2d, 0x68, 0x71, 0x2f, 0x73, 0x61, 0x62, 0x65, 0x72, + 0x2d, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x2d, 0x64, 0x69, 0x73, 0x74, 0x0a, 0x0a, + 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x0e, 0x02, 0x03, 0x05, 0x12, 0x04, 0x8a, 0x04, 0x06, 0x0c, + 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x0e, 0x02, 0x03, 0x01, 0x12, 0x04, 0x8a, 0x04, 0x0d, + 0x1f, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x0e, 0x02, 0x03, 0x03, 0x12, 0x04, 0x8a, 0x04, + 0x22, 0x23, 0x0a, 0x36, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x0e, 0x02, 0x04, 0x12, 0x04, 0x8c, 0x04, + 0x06, 0x40, 0x1a, 0x26, 0x2f, 0x20, 0x2a, 0x2a, 0x40, 0x64, 0x65, 0x70, 0x72, 0x65, 0x63, 0x61, + 0x74, 0x65, 0x64, 0x2a, 0x2a, 0x20, 0x55, 0x73, 0x65, 0x20, 0x6f, 0x72, 0x63, 0x61, 0x50, 0x6f, + 0x6f, 0x6c, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x0a, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, + 0x03, 0x0e, 0x02, 0x04, 0x05, 0x12, 0x04, 0x8c, 0x04, 0x06, 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, + 0x00, 0x03, 0x0e, 0x02, 0x04, 0x01, 0x12, 0x04, 0x8c, 0x04, 0x0d, 0x29, 0x0a, 0x0f, 0x0a, 0x07, + 0x04, 0x00, 0x03, 0x0e, 0x02, 0x04, 0x03, 0x12, 0x04, 0x8c, 0x04, 0x2c, 0x2d, 0x0a, 0x0f, 0x0a, + 0x07, 0x04, 0x00, 0x03, 0x0e, 0x02, 0x04, 0x08, 0x12, 0x04, 0x8c, 0x04, 0x2e, 0x3f, 0x0a, 0x10, + 0x0a, 0x08, 0x04, 0x00, 0x03, 0x0e, 0x02, 0x04, 0x08, 0x03, 0x12, 0x04, 0x8c, 0x04, 0x2f, 0x3e, + 0x0a, 0x6c, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x0e, 0x02, 0x05, 0x12, 0x04, 0x8e, 0x04, 0x06, 0x26, + 0x1a, 0x5c, 0x2f, 0x20, 0x54, 0x68, 0x65, 0x20, 0x52, 0x61, 0x79, 0x64, 0x69, 0x75, 0x6d, 0x20, + 0x6c, 0x69, 0x71, 0x75, 0x69, 0x64, 0x69, 0x74, 0x79, 0x20, 0x70, 0x6f, 0x6f, 0x6c, 0x20, 0x61, + 0x6d, 0x6d, 0x49, 0x64, 0x2e, 0x20, 0x41, 0x20, 0x66, 0x75, 0x6c, 0x6c, 0x20, 0x6c, 0x69, 0x73, + 0x74, 0x20, 0x63, 0x61, 0x6e, 0x20, 0x62, 0x65, 0x20, 0x66, 0x6f, 0x75, 0x6e, 0x64, 0x20, 0x68, + 0x65, 0x72, 0x65, 0x3a, 0x20, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x72, 0x61, 0x79, + 0x64, 0x69, 0x75, 0x6d, 0x2e, 0x69, 0x6f, 0x2f, 0x70, 0x6f, 0x6f, 0x6c, 0x73, 0x0a, 0x0a, 0x0f, + 0x0a, 0x07, 0x04, 0x00, 0x03, 0x0e, 0x02, 0x05, 0x05, 0x12, 0x04, 0x8e, 0x04, 0x06, 0x0c, 0x0a, + 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x0e, 0x02, 0x05, 0x01, 0x12, 0x04, 0x8e, 0x04, 0x0d, 0x21, + 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x0e, 0x02, 0x05, 0x03, 0x12, 0x04, 0x8e, 0x04, 0x24, + 0x25, 0x0a, 0x8d, 0x01, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x0e, 0x02, 0x06, 0x12, 0x04, 0x91, 0x04, + 0x06, 0x23, 0x1a, 0x7d, 0x2f, 0x20, 0x50, 0x6f, 0x6f, 0x6c, 0x20, 0x61, 0x64, 0x64, 0x72, 0x65, + 0x73, 0x73, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x61, 0x6e, 0x20, 0x4f, 0x72, 0x63, 0x61, 0x20, 0x4c, + 0x50, 0x20, 0x70, 0x6f, 0x6f, 0x6c, 0x20, 0x6f, 0x72, 0x20, 0x77, 0x68, 0x69, 0x72, 0x6c, 0x70, + 0x6f, 0x6f, 0x6c, 0x2e, 0x0a, 0x2f, 0x20, 0x41, 0x20, 0x66, 0x75, 0x6c, 0x6c, 0x20, 0x6c, 0x69, + 0x73, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x4f, 0x72, 0x63, 0x61, 0x20, 0x4c, 0x50, 0x20, 0x70, 0x6f, + 0x6f, 0x6c, 0x73, 0x20, 0x63, 0x61, 0x6e, 0x20, 0x62, 0x65, 0x20, 0x66, 0x6f, 0x75, 0x6e, 0x64, + 0x20, 0x68, 0x65, 0x72, 0x65, 0x3a, 0x20, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x77, + 0x77, 0x77, 0x2e, 0x6f, 0x72, 0x63, 0x61, 0x2e, 0x73, 0x6f, 0x2f, 0x70, 0x6f, 0x6f, 0x6c, 0x73, + 0x0a, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x0e, 0x02, 0x06, 0x05, 0x12, 0x04, 0x91, 0x04, + 0x06, 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x0e, 0x02, 0x06, 0x01, 0x12, 0x04, 0x91, + 0x04, 0x0d, 0x1e, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x0e, 0x02, 0x06, 0x03, 0x12, 0x04, + 0x91, 0x04, 0x21, 0x22, 0x0a, 0x6f, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x0e, 0x02, 0x07, 0x12, 0x04, + 0x93, 0x04, 0x06, 0x26, 0x1a, 0x5f, 0x2f, 0x20, 0x54, 0x68, 0x65, 0x20, 0x50, 0x6f, 0x72, 0x74, + 0x20, 0x72, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x20, 0x70, 0x75, 0x62, 0x6b, 0x65, 0x79, 0x2e, + 0x20, 0x41, 0x20, 0x66, 0x75, 0x6c, 0x6c, 0x20, 0x6c, 0x69, 0x73, 0x74, 0x20, 0x63, 0x61, 0x6e, + 0x20, 0x62, 0x65, 0x20, 0x66, 0x6f, 0x75, 0x6e, 0x64, 0x20, 0x68, 0x65, 0x72, 0x65, 0x3a, 0x20, + 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x61, 0x70, 0x69, 0x2d, 0x76, 0x31, 0x2e, 0x70, + 0x6f, 0x72, 0x74, 0x2e, 0x66, 0x69, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x2f, 0x72, 0x65, 0x73, 0x65, + 0x72, 0x76, 0x65, 0x73, 0x0a, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x0e, 0x02, 0x07, 0x05, + 0x12, 0x04, 0x93, 0x04, 0x06, 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x0e, 0x02, 0x07, + 0x01, 0x12, 0x04, 0x93, 0x04, 0x0d, 0x21, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x0e, 0x02, + 0x07, 0x03, 0x12, 0x04, 0x93, 0x04, 0x24, 0x25, 0x0a, 0x0e, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x0e, + 0x02, 0x08, 0x12, 0x04, 0x96, 0x04, 0x04, 0x1d, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x0e, + 0x02, 0x08, 0x04, 0x12, 0x04, 0x96, 0x04, 0x04, 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, + 0x0e, 0x02, 0x08, 0x06, 0x12, 0x04, 0x96, 0x04, 0x0d, 0x12, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, + 0x03, 0x0e, 0x02, 0x08, 0x01, 0x12, 0x04, 0x96, 0x04, 0x13, 0x18, 0x0a, 0x0f, 0x0a, 0x07, 0x04, + 0x00, 0x03, 0x0e, 0x02, 0x08, 0x03, 0x12, 0x04, 0x96, 0x04, 0x1b, 0x1c, 0x0a, 0xe4, 0x04, 0x0a, + 0x04, 0x04, 0x00, 0x03, 0x0f, 0x12, 0x06, 0xc1, 0x04, 0x02, 0xc8, 0x04, 0x03, 0x1a, 0xd3, 0x04, + 0x0a, 0x46, 0x69, 0x6e, 0x64, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x65, 0x78, 0x74, 0x72, 0x61, 0x63, + 0x74, 0x20, 0x74, 0x65, 0x78, 0x74, 0x20, 0x75, 0x73, 0x69, 0x6e, 0x67, 0x20, 0x72, 0x65, 0x67, + 0x75, 0x6c, 0x61, 0x72, 0x20, 0x65, 0x78, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, + 0x20, 0x66, 0x72, 0x6f, 0x6d, 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x72, 0x65, 0x76, 0x69, 0x6f, + 0x75, 0x73, 0x20, 0x74, 0x61, 0x73, 0x6b, 0x27, 0x73, 0x20, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, + 0x2e, 0x0a, 0x0a, 0x5f, 0x2a, 0x2a, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x2a, 0x2a, 0x5f, 0x3a, 0x20, + 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x20, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x20, 0x66, 0x72, + 0x6f, 0x6d, 0x20, 0x70, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x20, 0x74, 0x61, 0x73, 0x6b, + 0x0a, 0x0a, 0x5f, 0x2a, 0x2a, 0x52, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x73, 0x2a, 0x2a, 0x5f, 0x3a, + 0x20, 0x54, 0x68, 0x65, 0x20, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x64, 0x20, 0x73, 0x74, 0x72, + 0x69, 0x6e, 0x67, 0x20, 0x62, 0x61, 0x73, 0x65, 0x64, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x72, 0x65, 0x67, 0x65, 0x78, 0x20, 0x70, 0x61, 0x74, 0x74, 0x65, 0x72, 0x6e, 0x20, 0x61, + 0x6e, 0x64, 0x20, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x20, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x0a, + 0x0a, 0x5f, 0x2a, 0x2a, 0x45, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2a, 0x2a, 0x5f, 0x3a, 0x20, + 0x45, 0x78, 0x74, 0x72, 0x61, 0x63, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x66, 0x69, 0x72, 0x73, + 0x74, 0x20, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x20, 0x66, 0x72, 0x6f, 0x6d, 0x20, 0x61, 0x20, + 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x0a, 0x0a, 0x60, 0x60, 0x60, 0x6a, 0x73, 0x6f, 0x6e, 0x0a, + 0x7b, 0x0a, 0x22, 0x72, 0x65, 0x67, 0x65, 0x78, 0x45, 0x78, 0x74, 0x72, 0x61, 0x63, 0x74, 0x54, + 0x61, 0x73, 0x6b, 0x22, 0x3a, 0x20, 0x7b, 0x0a, 0x22, 0x70, 0x61, 0x74, 0x74, 0x65, 0x72, 0x6e, + 0x22, 0x3a, 0x20, 0x22, 0x5c, 0x5c, 0x64, 0x2b, 0x22, 0x2c, 0x0a, 0x22, 0x67, 0x72, 0x6f, 0x75, + 0x70, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x22, 0x3a, 0x20, 0x30, 0x0a, 0x7d, 0x0a, 0x7d, 0x0a, + 0x60, 0x60, 0x60, 0x0a, 0x0a, 0x5f, 0x2a, 0x2a, 0x45, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2a, + 0x2a, 0x5f, 0x3a, 0x20, 0x45, 0x78, 0x74, 0x72, 0x61, 0x63, 0x74, 0x20, 0x74, 0x65, 0x78, 0x74, + 0x20, 0x62, 0x65, 0x74, 0x77, 0x65, 0x65, 0x6e, 0x20, 0x71, 0x75, 0x6f, 0x74, 0x65, 0x73, 0x0a, + 0x0a, 0x60, 0x60, 0x60, 0x6a, 0x73, 0x6f, 0x6e, 0x0a, 0x7b, 0x0a, 0x22, 0x72, 0x65, 0x67, 0x65, + 0x78, 0x45, 0x78, 0x74, 0x72, 0x61, 0x63, 0x74, 0x54, 0x61, 0x73, 0x6b, 0x22, 0x3a, 0x20, 0x7b, + 0x0a, 0x22, 0x70, 0x61, 0x74, 0x74, 0x65, 0x72, 0x6e, 0x22, 0x3a, 0x20, 0x22, 0x5c, 0x22, 0x28, + 0x5b, 0x5e, 0x5c, 0x22, 0x5d, 0x2b, 0x29, 0x5c, 0x22, 0x22, 0x2c, 0x0a, 0x22, 0x67, 0x72, 0x6f, + 0x75, 0x70, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x22, 0x3a, 0x20, 0x31, 0x0a, 0x7d, 0x0a, 0x7d, + 0x0a, 0x60, 0x60, 0x60, 0x0a, 0x0a, 0x5f, 0x2a, 0x2a, 0x45, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, + 0x2a, 0x2a, 0x5f, 0x3a, 0x20, 0x45, 0x78, 0x74, 0x72, 0x61, 0x63, 0x74, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x66, 0x69, 0x72, 0x73, 0x74, 0x20, 0x4a, 0x53, 0x4f, 0x4e, 0x20, 0x6f, 0x62, 0x6a, 0x65, + 0x63, 0x74, 0x20, 0x66, 0x72, 0x6f, 0x6d, 0x20, 0x61, 0x20, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, + 0x0a, 0x0a, 0x60, 0x60, 0x60, 0x6a, 0x73, 0x6f, 0x6e, 0x0a, 0x7b, 0x0a, 0x22, 0x72, 0x65, 0x67, + 0x65, 0x78, 0x45, 0x78, 0x74, 0x72, 0x61, 0x63, 0x74, 0x54, 0x61, 0x73, 0x6b, 0x22, 0x3a, 0x20, + 0x7b, 0x0a, 0x22, 0x70, 0x61, 0x74, 0x74, 0x65, 0x72, 0x6e, 0x22, 0x3a, 0x20, 0x22, 0x5c, 0x5c, + 0x7b, 0x5b, 0x5e, 0x7d, 0x5d, 0x2b, 0x5c, 0x5c, 0x7d, 0x22, 0x0a, 0x7d, 0x0a, 0x7d, 0x0a, 0x60, + 0x60, 0x60, 0x0a, 0x0a, 0x0d, 0x0a, 0x05, 0x04, 0x00, 0x03, 0x0f, 0x01, 0x12, 0x04, 0xc1, 0x04, + 0x0a, 0x1a, 0x0a, 0x7e, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x0f, 0x02, 0x00, 0x12, 0x04, 0xc4, 0x04, + 0x04, 0x20, 0x1a, 0x6e, 0x2f, 0x20, 0x54, 0x68, 0x65, 0x20, 0x72, 0x65, 0x67, 0x75, 0x6c, 0x61, + 0x72, 0x20, 0x65, 0x78, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x70, 0x61, 0x74, + 0x74, 0x65, 0x72, 0x6e, 0x20, 0x74, 0x6f, 0x20, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x20, 0x61, 0x67, + 0x61, 0x69, 0x6e, 0x73, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x20, + 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x0a, 0x2f, 0x20, 0x55, 0x73, 0x65, 0x73, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x66, 0x61, 0x6e, 0x63, 0x79, 0x2d, 0x72, 0x65, 0x67, 0x65, 0x78, 0x20, 0x52, + 0x75, 0x73, 0x74, 0x20, 0x63, 0x72, 0x61, 0x74, 0x65, 0x20, 0x73, 0x79, 0x6e, 0x74, 0x61, 0x78, + 0x2e, 0x0a, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x0f, 0x02, 0x00, 0x04, 0x12, 0x04, 0xc4, + 0x04, 0x04, 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x0f, 0x02, 0x00, 0x05, 0x12, 0x04, + 0xc4, 0x04, 0x0d, 0x13, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x0f, 0x02, 0x00, 0x01, 0x12, + 0x04, 0xc4, 0x04, 0x14, 0x1b, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x0f, 0x02, 0x00, 0x03, + 0x12, 0x04, 0xc4, 0x04, 0x1e, 0x1f, 0x0a, 0x96, 0x01, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x0f, 0x02, + 0x01, 0x12, 0x04, 0xc7, 0x04, 0x04, 0x24, 0x1a, 0x85, 0x01, 0x2f, 0x20, 0x54, 0x68, 0x65, 0x20, + 0x63, 0x61, 0x70, 0x74, 0x75, 0x72, 0x65, 0x20, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x20, 0x6e, 0x75, + 0x6d, 0x62, 0x65, 0x72, 0x20, 0x74, 0x6f, 0x20, 0x65, 0x78, 0x74, 0x72, 0x61, 0x63, 0x74, 0x20, + 0x28, 0x30, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x73, 0x20, 0x66, 0x75, 0x6c, 0x6c, 0x20, + 0x6d, 0x61, 0x74, 0x63, 0x68, 0x2c, 0x20, 0x31, 0x2b, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, + 0x73, 0x20, 0x72, 0x65, 0x73, 0x70, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x20, 0x63, 0x61, 0x70, + 0x74, 0x75, 0x72, 0x65, 0x20, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x29, 0x2e, 0x0a, 0x2f, 0x20, 0x44, + 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x30, 0x20, 0x69, 0x66, 0x20, + 0x6e, 0x6f, 0x74, 0x20, 0x73, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x65, 0x64, 0x2e, 0x0a, 0x0a, + 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x0f, 0x02, 0x01, 0x04, 0x12, 0x04, 0xc7, 0x04, 0x04, 0x0c, + 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x0f, 0x02, 0x01, 0x05, 0x12, 0x04, 0xc7, 0x04, 0x0d, + 0x12, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x0f, 0x02, 0x01, 0x01, 0x12, 0x04, 0xc7, 0x04, + 0x13, 0x1f, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x0f, 0x02, 0x01, 0x03, 0x12, 0x04, 0xc7, + 0x04, 0x22, 0x23, 0x0a, 0x0e, 0x0a, 0x04, 0x04, 0x00, 0x03, 0x10, 0x12, 0x06, 0xca, 0x04, 0x02, + 0xd1, 0x04, 0x03, 0x0a, 0x0d, 0x0a, 0x05, 0x04, 0x00, 0x03, 0x10, 0x01, 0x12, 0x04, 0xca, 0x04, + 0x0a, 0x18, 0x0a, 0x10, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x10, 0x08, 0x00, 0x12, 0x06, 0xcb, 0x04, + 0x04, 0xd0, 0x04, 0x05, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x10, 0x08, 0x00, 0x01, 0x12, + 0x04, 0xcb, 0x04, 0x0a, 0x14, 0x0a, 0x59, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x10, 0x02, 0x00, 0x12, + 0x04, 0xcd, 0x04, 0x06, 0x1e, 0x1a, 0x49, 0x2f, 0x20, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x6e, 0x20, + 0x74, 0x61, 0x73, 0x6b, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x69, 0x6e, 0x67, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x6a, 0x6f, 0x62, 0x20, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, + 0x6f, 0x6e, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x66, 0x65, 0x74, 0x63, 0x68, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x53, 0x54, 0x45, 0x50, 0x2f, 0x55, 0x53, 0x44, 0x20, 0x70, 0x72, 0x69, 0x63, 0x65, 0x0a, + 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x10, 0x02, 0x00, 0x06, 0x12, 0x04, 0xcd, 0x04, 0x06, + 0x10, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x10, 0x02, 0x00, 0x01, 0x12, 0x04, 0xcd, 0x04, + 0x11, 0x19, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x10, 0x02, 0x00, 0x03, 0x12, 0x04, 0xcd, + 0x04, 0x1c, 0x1d, 0x0a, 0x3a, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x10, 0x02, 0x01, 0x12, 0x04, 0xcf, + 0x04, 0x06, 0x28, 0x1a, 0x2a, 0x2f, 0x20, 0x65, 0x78, 0x69, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x20, + 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x6f, 0x72, 0x20, 0x70, 0x75, 0x62, 0x6b, 0x65, + 0x79, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x53, 0x54, 0x45, 0x50, 0x2f, 0x55, 0x53, 0x44, 0x0a, 0x0a, + 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x10, 0x02, 0x01, 0x05, 0x12, 0x04, 0xcf, 0x04, 0x06, 0x0c, + 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x10, 0x02, 0x01, 0x01, 0x12, 0x04, 0xcf, 0x04, 0x0d, + 0x23, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x10, 0x02, 0x01, 0x03, 0x12, 0x04, 0xcf, 0x04, + 0x26, 0x27, 0x0a, 0x9b, 0x05, 0x0a, 0x04, 0x04, 0x00, 0x03, 0x11, 0x12, 0x06, 0xe0, 0x04, 0x02, + 0xed, 0x04, 0x03, 0x1a, 0x8a, 0x05, 0x0a, 0x54, 0x61, 0x6b, 0x65, 0x73, 0x20, 0x61, 0x20, 0x74, + 0x77, 0x61, 0x70, 0x20, 0x6f, 0x76, 0x65, 0x72, 0x20, 0x61, 0x20, 0x73, 0x65, 0x74, 0x20, 0x70, + 0x65, 0x72, 0x69, 0x6f, 0x64, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x61, 0x20, 0x63, 0x65, 0x72, 0x74, + 0x61, 0x69, 0x6e, 0x20, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x6f, 0x72, 0x2e, 0x20, + 0x41, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x6f, 0x72, 0x73, 0x20, 0x68, 0x61, 0x76, 0x65, + 0x20, 0x61, 0x6e, 0x20, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x20, 0x68, 0x69, 0x73, + 0x74, 0x6f, 0x72, 0x79, 0x20, 0x62, 0x75, 0x66, 0x66, 0x65, 0x72, 0x20, 0x61, 0x63, 0x63, 0x6f, + 0x75, 0x6e, 0x74, 0x20, 0x73, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x6c, 0x61, 0x73, 0x74, 0x20, 0x4e, 0x20, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x20, + 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x2e, 0x20, 0x54, 0x68, 0x65, 0x20, 0x54, 0x77, 0x61, + 0x70, 0x54, 0x61, 0x73, 0x6b, 0x20, 0x77, 0x69, 0x6c, 0x6c, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, + 0x74, 0x65, 0x20, 0x6f, 0x76, 0x65, 0x72, 0x20, 0x61, 0x6e, 0x20, 0x61, 0x67, 0x67, 0x72, 0x65, + 0x67, 0x61, 0x74, 0x6f, 0x72, 0x73, 0x20, 0x68, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x20, 0x62, + 0x75, 0x66, 0x66, 0x65, 0x72, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x63, 0x61, 0x6c, 0x63, 0x75, 0x6c, + 0x61, 0x74, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x69, 0x6d, 0x65, 0x20, 0x77, 0x65, 0x69, + 0x67, 0x68, 0x74, 0x65, 0x64, 0x20, 0x61, 0x76, 0x65, 0x72, 0x61, 0x67, 0x65, 0x20, 0x6f, 0x66, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x20, 0x77, 0x69, 0x74, + 0x68, 0x69, 0x6e, 0x20, 0x61, 0x20, 0x67, 0x69, 0x76, 0x65, 0x6e, 0x20, 0x74, 0x69, 0x6d, 0x65, + 0x20, 0x70, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x2e, 0x0a, 0x0a, 0x5f, 0x2a, 0x2a, 0x49, 0x6e, 0x70, + 0x75, 0x74, 0x2a, 0x2a, 0x5f, 0x3a, 0x20, 0x4e, 0x6f, 0x6e, 0x65, 0x0a, 0x0a, 0x5f, 0x2a, 0x2a, + 0x52, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x73, 0x2a, 0x2a, 0x5f, 0x3a, 0x20, 0x54, 0x68, 0x65, 0x20, + 0x74, 0x69, 0x6d, 0x65, 0x20, 0x77, 0x65, 0x69, 0x67, 0x68, 0x74, 0x65, 0x64, 0x20, 0x61, 0x76, + 0x65, 0x72, 0x61, 0x67, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x61, 0x6e, 0x20, 0x61, 0x67, 0x67, 0x72, + 0x65, 0x67, 0x61, 0x74, 0x6f, 0x72, 0x20, 0x6f, 0x76, 0x65, 0x72, 0x20, 0x61, 0x20, 0x67, 0x69, + 0x76, 0x65, 0x6e, 0x20, 0x74, 0x69, 0x6d, 0x65, 0x20, 0x70, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x2e, + 0x0a, 0x0a, 0x5f, 0x2a, 0x2a, 0x45, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2a, 0x2a, 0x5f, 0x3a, + 0x20, 0x54, 0x68, 0x65, 0x20, 0x31, 0x68, 0x72, 0x20, 0x54, 0x77, 0x61, 0x70, 0x20, 0x6f, 0x66, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x53, 0x4f, 0x4c, 0x2f, 0x55, 0x53, 0x44, 0x20, 0x41, 0x67, 0x67, + 0x72, 0x65, 0x67, 0x61, 0x74, 0x6f, 0x72, 0x2c, 0x20, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x69, + 0x6e, 0x67, 0x20, 0x61, 0x74, 0x20, 0x6c, 0x65, 0x61, 0x73, 0x74, 0x20, 0x36, 0x30, 0x20, 0x73, + 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x0a, 0x0a, 0x60, 0x60, 0x60, 0x6a, 0x73, 0x6f, 0x6e, + 0x0a, 0x7b, 0x20, 0x22, 0x74, 0x77, 0x61, 0x70, 0x54, 0x61, 0x73, 0x6b, 0x22, 0x3a, 0x20, 0x7b, + 0x20, 0x22, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x6f, 0x72, 0x50, 0x75, 0x62, 0x6b, + 0x65, 0x79, 0x22, 0x3a, 0x20, 0x22, 0x47, 0x76, 0x44, 0x4d, 0x78, 0x50, 0x7a, 0x4e, 0x31, 0x73, + 0x43, 0x6a, 0x37, 0x4c, 0x32, 0x36, 0x59, 0x44, 0x4b, 0x32, 0x48, 0x6e, 0x4d, 0x52, 0x58, 0x45, + 0x51, 0x6d, 0x51, 0x32, 0x61, 0x65, 0x6d, 0x6f, 0x76, 0x38, 0x59, 0x42, 0x74, 0x50, 0x53, 0x37, + 0x76, 0x52, 0x22, 0x2c, 0x20, 0x22, 0x70, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x22, 0x3a, 0x20, 0x33, + 0x36, 0x30, 0x30, 0x2c, 0x20, 0x22, 0x6d, 0x69, 0x6e, 0x53, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, + 0x22, 0x3a, 0x20, 0x36, 0x30, 0x2c, 0x20, 0x22, 0x77, 0x65, 0x69, 0x67, 0x68, 0x74, 0x42, 0x79, + 0x50, 0x72, 0x6f, 0x70, 0x61, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x69, 0x6d, 0x65, 0x22, + 0x3a, 0x20, 0x74, 0x72, 0x75, 0x65, 0x20, 0x20, 0x7d, 0x20, 0x7d, 0x0a, 0x60, 0x60, 0x60, 0x0a, + 0x0a, 0x0d, 0x0a, 0x05, 0x04, 0x00, 0x03, 0x11, 0x01, 0x12, 0x04, 0xe0, 0x04, 0x0a, 0x12, 0x0a, + 0x36, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x11, 0x02, 0x00, 0x12, 0x04, 0xe2, 0x04, 0x04, 0x2a, 0x1a, + 0x26, 0x2f, 0x20, 0x54, 0x68, 0x65, 0x20, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x20, 0x61, 0x67, + 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x6f, 0x72, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x54, 0x57, 0x41, 0x50, 0x2e, 0x0a, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x11, 0x02, + 0x00, 0x04, 0x12, 0x04, 0xe2, 0x04, 0x04, 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x11, + 0x02, 0x00, 0x05, 0x12, 0x04, 0xe2, 0x04, 0x0d, 0x13, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, + 0x11, 0x02, 0x00, 0x01, 0x12, 0x04, 0xe2, 0x04, 0x14, 0x25, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, + 0x03, 0x11, 0x02, 0x00, 0x03, 0x12, 0x04, 0xe2, 0x04, 0x28, 0x29, 0x0a, 0x42, 0x0a, 0x06, 0x04, + 0x00, 0x03, 0x11, 0x02, 0x01, 0x12, 0x04, 0xe4, 0x04, 0x04, 0x1e, 0x1a, 0x32, 0x2f, 0x20, 0x50, + 0x65, 0x72, 0x69, 0x6f, 0x64, 0x2c, 0x20, 0x69, 0x6e, 0x20, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, + 0x73, 0x2c, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x77, 0x61, 0x70, 0x20, 0x73, 0x68, 0x6f, 0x75, + 0x6c, 0x64, 0x20, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x20, 0x66, 0x6f, 0x72, 0x0a, 0x0a, + 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x11, 0x02, 0x01, 0x04, 0x12, 0x04, 0xe4, 0x04, 0x04, 0x0c, + 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x11, 0x02, 0x01, 0x05, 0x12, 0x04, 0xe4, 0x04, 0x0d, + 0x12, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x11, 0x02, 0x01, 0x01, 0x12, 0x04, 0xe4, 0x04, + 0x13, 0x19, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x11, 0x02, 0x01, 0x03, 0x12, 0x04, 0xe4, + 0x04, 0x1c, 0x1d, 0x0a, 0x3b, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x11, 0x02, 0x02, 0x12, 0x04, 0xe6, + 0x04, 0x04, 0x31, 0x1a, 0x2b, 0x2f, 0x20, 0x57, 0x65, 0x69, 0x67, 0x68, 0x74, 0x20, 0x73, 0x61, + 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x20, 0x62, 0x79, 0x20, 0x74, 0x68, 0x65, 0x69, 0x72, 0x20, 0x70, + 0x72, 0x6f, 0x70, 0x61, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x74, 0x69, 0x6d, 0x65, 0x0a, + 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x11, 0x02, 0x02, 0x04, 0x12, 0x04, 0xe6, 0x04, 0x04, + 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x11, 0x02, 0x02, 0x05, 0x12, 0x04, 0xe6, 0x04, + 0x0d, 0x11, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x11, 0x02, 0x02, 0x01, 0x12, 0x04, 0xe6, + 0x04, 0x12, 0x2c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x11, 0x02, 0x02, 0x03, 0x12, 0x04, + 0xe6, 0x04, 0x2f, 0x30, 0x0a, 0x57, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x11, 0x02, 0x03, 0x12, 0x04, + 0xe8, 0x04, 0x04, 0x24, 0x1a, 0x47, 0x2f, 0x20, 0x4d, 0x69, 0x6e, 0x69, 0x6d, 0x75, 0x6d, 0x20, + 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x20, 0x6f, 0x66, 0x20, 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, + 0x73, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x68, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, + 0x20, 0x74, 0x6f, 0x20, 0x63, 0x61, 0x6c, 0x63, 0x75, 0x6c, 0x61, 0x74, 0x65, 0x20, 0x61, 0x20, + 0x76, 0x61, 0x6c, 0x69, 0x64, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x0a, 0x0a, 0x0f, 0x0a, + 0x07, 0x04, 0x00, 0x03, 0x11, 0x02, 0x03, 0x04, 0x12, 0x04, 0xe8, 0x04, 0x04, 0x0c, 0x0a, 0x0f, + 0x0a, 0x07, 0x04, 0x00, 0x03, 0x11, 0x02, 0x03, 0x05, 0x12, 0x04, 0xe8, 0x04, 0x0d, 0x13, 0x0a, + 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x11, 0x02, 0x03, 0x01, 0x12, 0x04, 0xe8, 0x04, 0x14, 0x1f, + 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x11, 0x02, 0x03, 0x03, 0x12, 0x04, 0xe8, 0x04, 0x22, + 0x23, 0x0a, 0x40, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x11, 0x02, 0x04, 0x12, 0x04, 0xea, 0x04, 0x04, + 0x2d, 0x1a, 0x30, 0x2f, 0x20, 0x45, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x75, 0x6e, 0x69, 0x78, + 0x20, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x20, 0x74, 0x6f, 0x20, 0x63, 0x6f, + 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x20, 0x75, 0x70, 0x20, + 0x74, 0x6f, 0x0a, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x11, 0x02, 0x04, 0x04, 0x12, 0x04, + 0xea, 0x04, 0x04, 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x11, 0x02, 0x04, 0x05, 0x12, + 0x04, 0xea, 0x04, 0x0d, 0x12, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x11, 0x02, 0x04, 0x01, + 0x12, 0x04, 0xea, 0x04, 0x13, 0x28, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x11, 0x02, 0x04, + 0x03, 0x12, 0x04, 0xea, 0x04, 0x2b, 0x2c, 0x0a, 0x44, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x11, 0x02, + 0x05, 0x12, 0x04, 0xec, 0x04, 0x04, 0x3a, 0x1a, 0x34, 0x2f, 0x20, 0x45, 0x78, 0x65, 0x63, 0x75, + 0x74, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x61, 0x73, 0x6b, 0x20, 0x74, 0x6f, 0x20, 0x67, + 0x65, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x75, 0x6e, + 0x69, 0x78, 0x20, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x0a, 0x0a, 0x0f, 0x0a, + 0x07, 0x04, 0x00, 0x03, 0x11, 0x02, 0x05, 0x04, 0x12, 0x04, 0xec, 0x04, 0x04, 0x0c, 0x0a, 0x0f, + 0x0a, 0x07, 0x04, 0x00, 0x03, 0x11, 0x02, 0x05, 0x06, 0x12, 0x04, 0xec, 0x04, 0x0d, 0x1a, 0x0a, + 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x11, 0x02, 0x05, 0x01, 0x12, 0x04, 0xec, 0x04, 0x1b, 0x35, + 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x11, 0x02, 0x05, 0x03, 0x12, 0x04, 0xec, 0x04, 0x38, + 0x39, 0x0a, 0x43, 0x0a, 0x04, 0x04, 0x00, 0x03, 0x12, 0x12, 0x06, 0xf0, 0x04, 0x02, 0xf3, 0x04, + 0x03, 0x1a, 0x33, 0x2f, 0x20, 0x46, 0x65, 0x74, 0x63, 0x68, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6c, + 0x61, 0x74, 0x65, 0x73, 0x74, 0x20, 0x73, 0x77, 0x61, 0x70, 0x20, 0x70, 0x72, 0x69, 0x63, 0x65, + 0x20, 0x6f, 0x6e, 0x20, 0x53, 0x65, 0x72, 0x75, 0x6d, 0x27, 0x73, 0x20, 0x6f, 0x72, 0x64, 0x65, + 0x72, 0x62, 0x6f, 0x6f, 0x6b, 0x0a, 0x0a, 0x0d, 0x0a, 0x05, 0x04, 0x00, 0x03, 0x12, 0x01, 0x12, + 0x04, 0xf0, 0x04, 0x0a, 0x17, 0x0a, 0x39, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x12, 0x02, 0x00, 0x12, + 0x04, 0xf2, 0x04, 0x04, 0x2b, 0x1a, 0x29, 0x2f, 0x20, 0x54, 0x68, 0x65, 0x20, 0x73, 0x65, 0x72, + 0x75, 0x6d, 0x20, 0x70, 0x6f, 0x6f, 0x6c, 0x20, 0x74, 0x6f, 0x20, 0x66, 0x65, 0x74, 0x63, 0x68, + 0x20, 0x73, 0x77, 0x61, 0x70, 0x20, 0x70, 0x72, 0x69, 0x63, 0x65, 0x20, 0x66, 0x6f, 0x72, 0x0a, + 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x12, 0x02, 0x00, 0x04, 0x12, 0x04, 0xf2, 0x04, 0x04, + 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x12, 0x02, 0x00, 0x05, 0x12, 0x04, 0xf2, 0x04, + 0x0d, 0x13, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x12, 0x02, 0x00, 0x01, 0x12, 0x04, 0xf2, + 0x04, 0x14, 0x26, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x12, 0x02, 0x00, 0x03, 0x12, 0x04, + 0xf2, 0x04, 0x29, 0x2a, 0x0a, 0xb5, 0x02, 0x0a, 0x04, 0x04, 0x00, 0x03, 0x13, 0x12, 0x06, 0x82, + 0x05, 0x02, 0x8b, 0x05, 0x03, 0x1a, 0xa4, 0x02, 0x0a, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x20, 0x72, 0x75, 0x6e, 0x6e, 0x69, + 0x6e, 0x67, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x20, 0x74, 0x6f, 0x20, 0x61, 0x6e, 0x20, + 0x65, 0x78, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x20, 0x70, 0x6f, 0x77, 0x65, + 0x72, 0x2e, 0x0a, 0x0a, 0x5f, 0x2a, 0x2a, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x2a, 0x2a, 0x5f, 0x3a, + 0x20, 0x54, 0x68, 0x65, 0x20, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x20, 0x72, 0x75, 0x6e, + 0x6e, 0x69, 0x6e, 0x67, 0x20, 0x6e, 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x6c, 0x20, 0x72, + 0x65, 0x73, 0x75, 0x6c, 0x74, 0x2e, 0x0a, 0x0a, 0x5f, 0x2a, 0x2a, 0x52, 0x65, 0x74, 0x75, 0x72, + 0x6e, 0x73, 0x2a, 0x2a, 0x5f, 0x3a, 0x20, 0x54, 0x68, 0x65, 0x20, 0x69, 0x6e, 0x70, 0x75, 0x74, + 0x20, 0x72, 0x61, 0x69, 0x73, 0x65, 0x64, 0x20, 0x74, 0x6f, 0x20, 0x61, 0x6e, 0x20, 0x65, 0x78, + 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x20, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x2e, + 0x0a, 0x0a, 0x5f, 0x2a, 0x2a, 0x45, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2a, 0x2a, 0x5f, 0x3a, + 0x20, 0x52, 0x61, 0x69, 0x73, 0x65, 0x20, 0x32, 0x20, 0x74, 0x6f, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x70, 0x6f, 0x77, 0x65, 0x72, 0x20, 0x6f, 0x66, 0x20, 0x33, 0x2c, 0x20, 0x32, 0x5e, 0x33, 0x0a, + 0x0a, 0x60, 0x60, 0x60, 0x6a, 0x73, 0x6f, 0x6e, 0x0a, 0x7b, 0x22, 0x74, 0x61, 0x73, 0x6b, 0x73, + 0x22, 0x3a, 0x5b, 0x7b, 0x22, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x22, 0x3a, + 0x7b, 0x22, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x3a, 0x32, 0x7d, 0x7d, 0x2c, 0x7b, 0x22, 0x70, + 0x6f, 0x77, 0x54, 0x61, 0x73, 0x6b, 0x22, 0x3a, 0x7b, 0x22, 0x73, 0x63, 0x61, 0x6c, 0x61, 0x72, + 0x22, 0x3a, 0x33, 0x7d, 0x7d, 0x5d, 0x7d, 0x0a, 0x60, 0x60, 0x60, 0x0a, 0x0a, 0x0d, 0x0a, 0x05, + 0x04, 0x00, 0x03, 0x13, 0x01, 0x12, 0x04, 0x82, 0x05, 0x0a, 0x11, 0x0a, 0x10, 0x0a, 0x06, 0x04, + 0x00, 0x03, 0x13, 0x08, 0x00, 0x12, 0x06, 0x83, 0x05, 0x04, 0x8a, 0x05, 0x05, 0x0a, 0x0f, 0x0a, + 0x07, 0x04, 0x00, 0x03, 0x13, 0x08, 0x00, 0x01, 0x12, 0x04, 0x83, 0x05, 0x0a, 0x12, 0x0a, 0x43, + 0x0a, 0x06, 0x04, 0x00, 0x03, 0x13, 0x02, 0x00, 0x12, 0x04, 0x85, 0x05, 0x06, 0x18, 0x1a, 0x33, + 0x2f, 0x20, 0x54, 0x61, 0x6b, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x77, 0x6f, 0x72, 0x6b, 0x69, + 0x6e, 0x67, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x20, 0x74, 0x6f, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x65, 0x78, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x76, 0x61, 0x6c, 0x75, + 0x65, 0x2e, 0x0a, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x13, 0x02, 0x00, 0x05, 0x12, 0x04, + 0x85, 0x05, 0x06, 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x13, 0x02, 0x00, 0x01, 0x12, + 0x04, 0x85, 0x05, 0x0d, 0x13, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x13, 0x02, 0x00, 0x03, + 0x12, 0x04, 0x85, 0x05, 0x16, 0x17, 0x0a, 0x53, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x13, 0x02, 0x01, + 0x12, 0x04, 0x87, 0x05, 0x06, 0x23, 0x1a, 0x43, 0x2f, 0x20, 0x54, 0x61, 0x6b, 0x65, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x77, 0x6f, 0x72, 0x6b, 0x69, 0x6e, 0x67, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, + 0x20, 0x74, 0x6f, 0x20, 0x74, 0x68, 0x65, 0x20, 0x65, 0x78, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, + 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, + 0x6f, 0x72, 0x73, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x2e, 0x0a, 0x0a, 0x0f, 0x0a, 0x07, 0x04, + 0x00, 0x03, 0x13, 0x02, 0x01, 0x05, 0x12, 0x04, 0x87, 0x05, 0x06, 0x0c, 0x0a, 0x0f, 0x0a, 0x07, + 0x04, 0x00, 0x03, 0x13, 0x02, 0x01, 0x01, 0x12, 0x04, 0x87, 0x05, 0x0d, 0x1e, 0x0a, 0x0f, 0x0a, + 0x07, 0x04, 0x00, 0x03, 0x13, 0x02, 0x01, 0x03, 0x12, 0x04, 0x87, 0x05, 0x21, 0x22, 0x0a, 0x4d, + 0x0a, 0x06, 0x04, 0x00, 0x03, 0x13, 0x02, 0x02, 0x12, 0x04, 0x89, 0x05, 0x06, 0x15, 0x1a, 0x3d, + 0x2f, 0x20, 0x41, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x69, 0x66, 0x69, 0x65, 0x64, 0x20, + 0x62, 0x69, 0x67, 0x2e, 0x6a, 0x73, 0x2e, 0x20, 0x60, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x73, + 0x20, 0x76, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x65, 0x78, 0x70, 0x61, 0x6e, 0x73, + 0x69, 0x6f, 0x6e, 0x20, 0x73, 0x79, 0x6e, 0x74, 0x61, 0x78, 0x2e, 0x60, 0x0a, 0x0a, 0x0f, 0x0a, + 0x07, 0x04, 0x00, 0x03, 0x13, 0x02, 0x02, 0x05, 0x12, 0x04, 0x89, 0x05, 0x06, 0x0c, 0x0a, 0x0f, + 0x0a, 0x07, 0x04, 0x00, 0x03, 0x13, 0x02, 0x02, 0x01, 0x12, 0x04, 0x89, 0x05, 0x0d, 0x10, 0x0a, + 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x13, 0x02, 0x02, 0x03, 0x12, 0x04, 0x89, 0x05, 0x13, 0x14, + 0x0a, 0x47, 0x0a, 0x04, 0x04, 0x00, 0x03, 0x14, 0x12, 0x06, 0x8e, 0x05, 0x02, 0x9a, 0x05, 0x03, + 0x1a, 0x37, 0x2f, 0x20, 0x46, 0x65, 0x74, 0x63, 0x68, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6c, 0x65, + 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x72, 0x61, 0x74, 0x65, 0x73, 0x20, 0x66, 0x6f, 0x72, 0x20, + 0x76, 0x61, 0x72, 0x69, 0x6f, 0x75, 0x73, 0x20, 0x53, 0x6f, 0x6c, 0x61, 0x6e, 0x61, 0x20, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x73, 0x0a, 0x0a, 0x0d, 0x0a, 0x05, 0x04, 0x00, 0x03, + 0x14, 0x01, 0x12, 0x04, 0x8e, 0x05, 0x0a, 0x19, 0x0a, 0x50, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x14, + 0x02, 0x00, 0x12, 0x04, 0x90, 0x05, 0x04, 0x21, 0x1a, 0x40, 0x2f, 0x20, 0x30, 0x31, 0x2c, 0x20, + 0x61, 0x70, 0x72, 0x69, 0x63, 0x6f, 0x74, 0x2c, 0x20, 0x66, 0x72, 0x61, 0x6e, 0x63, 0x69, 0x75, + 0x6d, 0x2c, 0x20, 0x6a, 0x65, 0x74, 0x2c, 0x20, 0x6c, 0x61, 0x72, 0x69, 0x78, 0x2c, 0x20, 0x6d, + 0x61, 0x6e, 0x67, 0x6f, 0x2c, 0x20, 0x70, 0x6f, 0x72, 0x74, 0x2c, 0x20, 0x73, 0x6f, 0x6c, 0x65, + 0x6e, 0x64, 0x2c, 0x20, 0x74, 0x75, 0x6c, 0x69, 0x70, 0x0a, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, + 0x03, 0x14, 0x02, 0x00, 0x04, 0x12, 0x04, 0x90, 0x05, 0x04, 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, + 0x00, 0x03, 0x14, 0x02, 0x00, 0x05, 0x12, 0x04, 0x90, 0x05, 0x0d, 0x13, 0x0a, 0x0f, 0x0a, 0x07, + 0x04, 0x00, 0x03, 0x14, 0x02, 0x00, 0x01, 0x12, 0x04, 0x90, 0x05, 0x14, 0x1c, 0x0a, 0x0f, 0x0a, + 0x07, 0x04, 0x00, 0x03, 0x14, 0x02, 0x00, 0x03, 0x12, 0x04, 0x90, 0x05, 0x1f, 0x20, 0x0a, 0x48, + 0x0a, 0x06, 0x04, 0x00, 0x03, 0x14, 0x02, 0x01, 0x12, 0x04, 0x92, 0x05, 0x04, 0x23, 0x1a, 0x38, + 0x2f, 0x20, 0x41, 0x20, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x20, 0x6d, 0x69, 0x6e, 0x74, 0x20, 0x61, + 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x20, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, + 0x20, 0x62, 0x79, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x68, 0x6f, 0x73, 0x65, 0x6e, 0x20, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x0a, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x14, + 0x02, 0x01, 0x04, 0x12, 0x04, 0x92, 0x05, 0x04, 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, + 0x14, 0x02, 0x01, 0x05, 0x12, 0x04, 0x92, 0x05, 0x0d, 0x13, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, + 0x03, 0x14, 0x02, 0x01, 0x01, 0x12, 0x04, 0x92, 0x05, 0x14, 0x1e, 0x0a, 0x0f, 0x0a, 0x07, 0x04, + 0x00, 0x03, 0x14, 0x02, 0x01, 0x03, 0x12, 0x04, 0x92, 0x05, 0x21, 0x22, 0x0a, 0x10, 0x0a, 0x06, + 0x04, 0x00, 0x03, 0x14, 0x04, 0x00, 0x12, 0x06, 0x93, 0x05, 0x04, 0x98, 0x05, 0x05, 0x0a, 0x0f, + 0x0a, 0x07, 0x04, 0x00, 0x03, 0x14, 0x04, 0x00, 0x01, 0x12, 0x04, 0x93, 0x05, 0x09, 0x0e, 0x0a, + 0x29, 0x0a, 0x08, 0x04, 0x00, 0x03, 0x14, 0x04, 0x00, 0x02, 0x00, 0x12, 0x04, 0x95, 0x05, 0x06, + 0x1d, 0x1a, 0x17, 0x2f, 0x20, 0x64, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x20, 0x6c, 0x65, 0x6e, + 0x64, 0x69, 0x6e, 0x67, 0x20, 0x72, 0x61, 0x74, 0x65, 0x0a, 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, + 0x03, 0x14, 0x04, 0x00, 0x02, 0x00, 0x01, 0x12, 0x04, 0x95, 0x05, 0x06, 0x18, 0x0a, 0x11, 0x0a, + 0x09, 0x04, 0x00, 0x03, 0x14, 0x04, 0x00, 0x02, 0x00, 0x02, 0x12, 0x04, 0x95, 0x05, 0x1b, 0x1c, + 0x0a, 0x28, 0x0a, 0x08, 0x04, 0x00, 0x03, 0x14, 0x04, 0x00, 0x02, 0x01, 0x12, 0x04, 0x97, 0x05, + 0x06, 0x1c, 0x1a, 0x16, 0x2f, 0x20, 0x62, 0x6f, 0x72, 0x72, 0x6f, 0x77, 0x20, 0x6c, 0x65, 0x6e, + 0x64, 0x69, 0x6e, 0x67, 0x20, 0x72, 0x61, 0x74, 0x65, 0x0a, 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, + 0x03, 0x14, 0x04, 0x00, 0x02, 0x01, 0x01, 0x12, 0x04, 0x97, 0x05, 0x06, 0x17, 0x0a, 0x11, 0x0a, + 0x09, 0x04, 0x00, 0x03, 0x14, 0x04, 0x00, 0x02, 0x01, 0x02, 0x12, 0x04, 0x97, 0x05, 0x1a, 0x1b, + 0x0a, 0x0e, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x14, 0x02, 0x02, 0x12, 0x04, 0x99, 0x05, 0x04, 0x1d, + 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x14, 0x02, 0x02, 0x04, 0x12, 0x04, 0x99, 0x05, 0x04, + 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x14, 0x02, 0x02, 0x06, 0x12, 0x04, 0x99, 0x05, + 0x0d, 0x12, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x14, 0x02, 0x02, 0x01, 0x12, 0x04, 0x99, + 0x05, 0x13, 0x18, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x14, 0x02, 0x02, 0x03, 0x12, 0x04, + 0x99, 0x05, 0x1b, 0x1c, 0x0a, 0x47, 0x0a, 0x04, 0x04, 0x00, 0x03, 0x15, 0x12, 0x06, 0x9d, 0x05, + 0x02, 0xa0, 0x05, 0x03, 0x1a, 0x37, 0x2f, 0x20, 0x46, 0x65, 0x74, 0x63, 0x68, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x20, 0x70, 0x72, 0x69, 0x63, 0x65, 0x20, + 0x66, 0x6f, 0x72, 0x20, 0x61, 0x20, 0x4d, 0x61, 0x6e, 0x67, 0x6f, 0x20, 0x70, 0x65, 0x72, 0x70, + 0x65, 0x74, 0x75, 0x61, 0x6c, 0x20, 0x6d, 0x61, 0x72, 0x6b, 0x65, 0x74, 0x0a, 0x0a, 0x0d, 0x0a, + 0x05, 0x04, 0x00, 0x03, 0x15, 0x01, 0x12, 0x04, 0x9d, 0x05, 0x0a, 0x1d, 0x0a, 0xb0, 0x01, 0x0a, + 0x06, 0x04, 0x00, 0x03, 0x15, 0x02, 0x00, 0x12, 0x04, 0x9f, 0x05, 0x04, 0x2c, 0x1a, 0x9f, 0x01, + 0x2f, 0x20, 0x4d, 0x61, 0x69, 0x6e, 0x6e, 0x65, 0x74, 0x20, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, + 0x73, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x61, 0x20, 0x6d, 0x61, 0x6e, 0x67, 0x6f, 0x20, 0x70, 0x65, + 0x72, 0x70, 0x65, 0x74, 0x75, 0x61, 0x6c, 0x20, 0x6d, 0x61, 0x72, 0x6b, 0x65, 0x74, 0x2e, 0x20, + 0x41, 0x20, 0x66, 0x75, 0x6c, 0x6c, 0x20, 0x6c, 0x69, 0x73, 0x74, 0x20, 0x63, 0x61, 0x6e, 0x20, + 0x62, 0x65, 0x20, 0x66, 0x6f, 0x75, 0x6e, 0x64, 0x20, 0x68, 0x65, 0x72, 0x65, 0x3a, 0x20, 0x68, + 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, + 0x6d, 0x2f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x2d, 0x66, 0x6f, 0x75, + 0x6e, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x6d, 0x61, 0x6e, 0x67, 0x6f, 0x2d, 0x63, 0x6c, + 0x69, 0x65, 0x6e, 0x74, 0x2d, 0x76, 0x33, 0x2f, 0x62, 0x6c, 0x6f, 0x62, 0x2f, 0x6d, 0x61, 0x69, + 0x6e, 0x2f, 0x73, 0x72, 0x63, 0x2f, 0x69, 0x64, 0x73, 0x2e, 0x6a, 0x73, 0x6f, 0x6e, 0x0a, 0x0a, + 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x15, 0x02, 0x00, 0x04, 0x12, 0x04, 0x9f, 0x05, 0x04, 0x0c, + 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x15, 0x02, 0x00, 0x05, 0x12, 0x04, 0x9f, 0x05, 0x0d, + 0x13, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x15, 0x02, 0x00, 0x01, 0x12, 0x04, 0x9f, 0x05, + 0x14, 0x27, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x15, 0x02, 0x00, 0x03, 0x12, 0x04, 0x9f, + 0x05, 0x2a, 0x2b, 0x0a, 0xbc, 0x05, 0x0a, 0x04, 0x04, 0x00, 0x03, 0x16, 0x12, 0x06, 0xb5, 0x05, + 0x02, 0xdb, 0x05, 0x03, 0x1a, 0xab, 0x05, 0x0a, 0x46, 0x65, 0x74, 0x63, 0x68, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x73, 0x69, 0x6d, 0x75, 0x6c, 0x61, 0x74, 0x65, 0x64, 0x20, 0x70, 0x72, 0x69, 0x63, + 0x65, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x61, 0x20, 0x73, 0x77, 0x61, 0x70, 0x20, 0x6f, 0x6e, 0x20, + 0x4a, 0x75, 0x70, 0x69, 0x74, 0x65, 0x72, 0x53, 0x77, 0x61, 0x70, 0x2e, 0x0a, 0x0a, 0x5f, 0x2a, + 0x2a, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x2a, 0x2a, 0x5f, 0x3a, 0x20, 0x4e, 0x6f, 0x6e, 0x65, 0x0a, + 0x0a, 0x5f, 0x2a, 0x2a, 0x52, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x73, 0x2a, 0x2a, 0x5f, 0x3a, 0x20, + 0x54, 0x68, 0x65, 0x20, 0x73, 0x77, 0x61, 0x70, 0x20, 0x70, 0x72, 0x69, 0x63, 0x65, 0x20, 0x6f, + 0x6e, 0x20, 0x4a, 0x75, 0x70, 0x69, 0x74, 0x65, 0x72, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x61, 0x20, + 0x67, 0x69, 0x76, 0x65, 0x6e, 0x20, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x20, 0x61, 0x6e, 0x64, 0x20, + 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x20, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x20, 0x6d, 0x69, 0x6e, + 0x74, 0x20, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x2e, 0x0a, 0x0a, 0x5f, 0x2a, 0x2a, 0x45, + 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2a, 0x2a, 0x5f, 0x3a, 0x20, 0x46, 0x65, 0x74, 0x63, 0x68, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x4a, 0x75, 0x70, 0x69, 0x74, 0x65, 0x72, 0x53, 0x77, 0x61, 0x70, + 0x20, 0x70, 0x72, 0x69, 0x63, 0x65, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x65, 0x78, 0x63, 0x68, 0x61, + 0x6e, 0x67, 0x69, 0x6e, 0x67, 0x20, 0x31, 0x20, 0x53, 0x4f, 0x4c, 0x20, 0x69, 0x6e, 0x74, 0x6f, + 0x20, 0x55, 0x53, 0x44, 0x43, 0x2e, 0x0a, 0x0a, 0x60, 0x60, 0x60, 0x6a, 0x73, 0x6f, 0x6e, 0x0a, + 0x7b, 0x20, 0x22, 0x6a, 0x75, 0x70, 0x69, 0x74, 0x65, 0x72, 0x53, 0x77, 0x61, 0x70, 0x54, 0x61, + 0x73, 0x6b, 0x22, 0x3a, 0x20, 0x7b, 0x20, 0x22, 0x69, 0x6e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x41, + 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x22, 0x3a, 0x20, 0x22, 0x53, 0x6f, 0x31, 0x31, 0x31, 0x31, + 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, + 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, + 0x31, 0x31, 0x31, 0x31, 0x32, 0x22, 0x2c, 0x20, 0x22, 0x6f, 0x75, 0x74, 0x54, 0x6f, 0x6b, 0x65, + 0x6e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x22, 0x3a, 0x20, 0x22, 0x45, 0x50, 0x6a, 0x46, + 0x57, 0x64, 0x64, 0x35, 0x41, 0x75, 0x66, 0x71, 0x53, 0x53, 0x71, 0x65, 0x4d, 0x32, 0x71, 0x4e, + 0x31, 0x78, 0x7a, 0x79, 0x62, 0x61, 0x70, 0x43, 0x38, 0x47, 0x34, 0x77, 0x45, 0x47, 0x47, 0x6b, + 0x5a, 0x77, 0x79, 0x54, 0x44, 0x74, 0x31, 0x76, 0x22, 0x20, 0x7d, 0x20, 0x7d, 0x0a, 0x60, 0x60, + 0x60, 0x0a, 0x0a, 0x5f, 0x2a, 0x2a, 0x45, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2a, 0x2a, 0x5f, + 0x3a, 0x20, 0x46, 0x65, 0x74, 0x63, 0x68, 0x20, 0x74, 0x68, 0x65, 0x20, 0x4a, 0x75, 0x70, 0x69, + 0x74, 0x65, 0x72, 0x53, 0x77, 0x61, 0x70, 0x20, 0x70, 0x72, 0x69, 0x63, 0x65, 0x20, 0x66, 0x6f, + 0x72, 0x20, 0x65, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x69, 0x6e, 0x67, 0x20, 0x31, 0x30, 0x30, + 0x30, 0x20, 0x53, 0x4f, 0x4c, 0x20, 0x69, 0x6e, 0x74, 0x6f, 0x20, 0x55, 0x53, 0x44, 0x43, 0x2e, + 0x0a, 0x0a, 0x60, 0x60, 0x60, 0x6a, 0x73, 0x6f, 0x6e, 0x0a, 0x7b, 0x20, 0x22, 0x6a, 0x75, 0x70, + 0x69, 0x74, 0x65, 0x72, 0x53, 0x77, 0x61, 0x70, 0x54, 0x61, 0x73, 0x6b, 0x22, 0x3a, 0x20, 0x7b, + 0x20, 0x22, 0x69, 0x6e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, + 0x22, 0x3a, 0x20, 0x22, 0x53, 0x6f, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, + 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, + 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x32, 0x22, + 0x2c, 0x20, 0x22, 0x6f, 0x75, 0x74, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x41, 0x64, 0x64, 0x72, 0x65, + 0x73, 0x73, 0x22, 0x3a, 0x20, 0x22, 0x45, 0x50, 0x6a, 0x46, 0x57, 0x64, 0x64, 0x35, 0x41, 0x75, + 0x66, 0x71, 0x53, 0x53, 0x71, 0x65, 0x4d, 0x32, 0x71, 0x4e, 0x31, 0x78, 0x7a, 0x79, 0x62, 0x61, + 0x70, 0x43, 0x38, 0x47, 0x34, 0x77, 0x45, 0x47, 0x47, 0x6b, 0x5a, 0x77, 0x79, 0x54, 0x44, 0x74, + 0x31, 0x76, 0x22, 0x2c, 0x20, 0x22, 0x62, 0x61, 0x73, 0x65, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, + 0x22, 0x3a, 0x20, 0x22, 0x31, 0x30, 0x30, 0x30, 0x22, 0x20, 0x7d, 0x20, 0x7d, 0x0a, 0x60, 0x60, + 0x60, 0x0a, 0x0a, 0x0d, 0x0a, 0x05, 0x04, 0x00, 0x03, 0x16, 0x01, 0x12, 0x04, 0xb5, 0x05, 0x0a, + 0x19, 0x0a, 0x2b, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x16, 0x02, 0x00, 0x12, 0x04, 0xb7, 0x05, 0x04, + 0x29, 0x1a, 0x1b, 0x2f, 0x20, 0x54, 0x68, 0x65, 0x20, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x20, 0x74, + 0x6f, 0x6b, 0x65, 0x6e, 0x20, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x2e, 0x0a, 0x0a, 0x0f, + 0x0a, 0x07, 0x04, 0x00, 0x03, 0x16, 0x02, 0x00, 0x04, 0x12, 0x04, 0xb7, 0x05, 0x04, 0x0c, 0x0a, + 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x16, 0x02, 0x00, 0x05, 0x12, 0x04, 0xb7, 0x05, 0x0d, 0x13, + 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x16, 0x02, 0x00, 0x01, 0x12, 0x04, 0xb7, 0x05, 0x14, + 0x24, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x16, 0x02, 0x00, 0x03, 0x12, 0x04, 0xb7, 0x05, + 0x27, 0x28, 0x0a, 0x2c, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x16, 0x02, 0x01, 0x12, 0x04, 0xb9, 0x05, + 0x04, 0x2a, 0x1a, 0x1c, 0x2f, 0x20, 0x54, 0x68, 0x65, 0x20, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, + 0x20, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x20, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x2e, 0x0a, + 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x16, 0x02, 0x01, 0x04, 0x12, 0x04, 0xb9, 0x05, 0x04, + 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x16, 0x02, 0x01, 0x05, 0x12, 0x04, 0xb9, 0x05, + 0x0d, 0x13, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x16, 0x02, 0x01, 0x01, 0x12, 0x04, 0xb9, + 0x05, 0x14, 0x25, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x16, 0x02, 0x01, 0x03, 0x12, 0x04, + 0xb9, 0x05, 0x28, 0x29, 0x0a, 0x10, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x16, 0x03, 0x00, 0x12, 0x06, + 0xbb, 0x05, 0x04, 0xbe, 0x05, 0x05, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x16, 0x03, 0x00, + 0x01, 0x12, 0x04, 0xbb, 0x05, 0x0c, 0x16, 0x0a, 0x5b, 0x0a, 0x08, 0x04, 0x00, 0x03, 0x16, 0x03, + 0x00, 0x02, 0x00, 0x12, 0x04, 0xbd, 0x05, 0x06, 0x21, 0x1a, 0x49, 0x2f, 0x20, 0x41, 0x20, 0x6c, + 0x69, 0x73, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x4a, 0x75, 0x70, 0x69, 0x74, 0x65, 0x72, 0x20, 0x41, + 0x4d, 0x4d, 0x20, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x61, 0x6c, 0x6c, + 0x6f, 0x77, 0x20, 0x6f, 0x72, 0x20, 0x64, 0x65, 0x6e, 0x79, 0x20, 0x28, 0x65, 0x2e, 0x67, 0x2e, + 0x20, 0x27, 0x52, 0x61, 0x79, 0x64, 0x69, 0x75, 0x6d, 0x27, 0x2c, 0x20, 0x27, 0x4f, 0x72, 0x63, + 0x61, 0x27, 0x29, 0x0a, 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x16, 0x03, 0x00, 0x02, 0x00, + 0x04, 0x12, 0x04, 0xbd, 0x05, 0x06, 0x0e, 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x16, 0x03, + 0x00, 0x02, 0x00, 0x05, 0x12, 0x04, 0xbd, 0x05, 0x0f, 0x15, 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, + 0x03, 0x16, 0x03, 0x00, 0x02, 0x00, 0x01, 0x12, 0x04, 0xbd, 0x05, 0x16, 0x1c, 0x0a, 0x11, 0x0a, + 0x09, 0x04, 0x00, 0x03, 0x16, 0x03, 0x00, 0x02, 0x00, 0x03, 0x12, 0x04, 0xbd, 0x05, 0x1f, 0x20, + 0x0a, 0x10, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x16, 0x08, 0x00, 0x12, 0x06, 0xc0, 0x05, 0x04, 0xc5, + 0x05, 0x05, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x16, 0x08, 0x00, 0x01, 0x12, 0x04, 0xc0, + 0x05, 0x0a, 0x17, 0x0a, 0x32, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x16, 0x02, 0x02, 0x12, 0x04, 0xc2, + 0x05, 0x06, 0x20, 0x1a, 0x22, 0x2f, 0x20, 0x41, 0x20, 0x6c, 0x69, 0x73, 0x74, 0x20, 0x6f, 0x66, + 0x20, 0x41, 0x4d, 0x4d, 0x20, 0x6d, 0x61, 0x72, 0x6b, 0x65, 0x74, 0x73, 0x20, 0x74, 0x6f, 0x20, + 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x2e, 0x0a, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x16, 0x02, + 0x02, 0x06, 0x12, 0x04, 0xc2, 0x05, 0x06, 0x10, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x16, + 0x02, 0x02, 0x01, 0x12, 0x04, 0xc2, 0x05, 0x11, 0x1b, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, + 0x16, 0x02, 0x02, 0x03, 0x12, 0x04, 0xc2, 0x05, 0x1e, 0x1f, 0x0a, 0x31, 0x0a, 0x06, 0x04, 0x00, + 0x03, 0x16, 0x02, 0x03, 0x12, 0x04, 0xc4, 0x05, 0x06, 0x1f, 0x1a, 0x21, 0x2f, 0x20, 0x41, 0x20, + 0x6c, 0x69, 0x73, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x41, 0x4d, 0x4d, 0x20, 0x6d, 0x61, 0x72, 0x6b, + 0x65, 0x74, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x64, 0x65, 0x6e, 0x79, 0x2e, 0x0a, 0x0a, 0x0f, 0x0a, + 0x07, 0x04, 0x00, 0x03, 0x16, 0x02, 0x03, 0x06, 0x12, 0x04, 0xc4, 0x05, 0x06, 0x10, 0x0a, 0x0f, + 0x0a, 0x07, 0x04, 0x00, 0x03, 0x16, 0x02, 0x03, 0x01, 0x12, 0x04, 0xc4, 0x05, 0x11, 0x1a, 0x0a, + 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x16, 0x02, 0x03, 0x03, 0x12, 0x04, 0xc4, 0x05, 0x1d, 0x1e, + 0x0a, 0x10, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x16, 0x08, 0x01, 0x12, 0x06, 0xc7, 0x05, 0x04, 0xd0, + 0x05, 0x05, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x16, 0x08, 0x01, 0x01, 0x12, 0x04, 0xc7, + 0x05, 0x0a, 0x14, 0x0a, 0x43, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x16, 0x02, 0x04, 0x12, 0x04, 0xc9, + 0x05, 0x06, 0x1d, 0x1a, 0x33, 0x2f, 0x20, 0x54, 0x68, 0x65, 0x20, 0x61, 0x6d, 0x6f, 0x75, 0x6e, + 0x74, 0x20, 0x6f, 0x66, 0x20, 0x60, 0x69, 0x6e, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x5f, 0x61, + 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x60, 0x20, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x20, 0x74, + 0x6f, 0x20, 0x73, 0x77, 0x61, 0x70, 0x2e, 0x0a, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x16, + 0x02, 0x04, 0x05, 0x12, 0x04, 0xc9, 0x05, 0x06, 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, + 0x16, 0x02, 0x04, 0x01, 0x12, 0x04, 0xc9, 0x05, 0x0d, 0x18, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, + 0x03, 0x16, 0x02, 0x04, 0x03, 0x12, 0x04, 0xc9, 0x05, 0x1b, 0x1c, 0x0a, 0x44, 0x0a, 0x06, 0x04, + 0x00, 0x03, 0x16, 0x02, 0x05, 0x12, 0x04, 0xcb, 0x05, 0x06, 0x1e, 0x1a, 0x34, 0x2f, 0x20, 0x54, + 0x68, 0x65, 0x20, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x60, 0x6f, 0x75, + 0x74, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x60, + 0x20, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x73, 0x77, 0x61, 0x70, 0x2e, + 0x0a, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x16, 0x02, 0x05, 0x05, 0x12, 0x04, 0xcb, 0x05, + 0x06, 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x16, 0x02, 0x05, 0x01, 0x12, 0x04, 0xcb, + 0x05, 0x0d, 0x19, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x16, 0x02, 0x05, 0x03, 0x12, 0x04, + 0xcb, 0x05, 0x1c, 0x1d, 0x0a, 0x43, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x16, 0x02, 0x06, 0x12, 0x04, + 0xcd, 0x05, 0x06, 0x24, 0x1a, 0x33, 0x2f, 0x20, 0x54, 0x68, 0x65, 0x20, 0x61, 0x6d, 0x6f, 0x75, + 0x6e, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x60, 0x69, 0x6e, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x5f, + 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x60, 0x20, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x20, + 0x74, 0x6f, 0x20, 0x73, 0x77, 0x61, 0x70, 0x2e, 0x0a, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, + 0x16, 0x02, 0x06, 0x05, 0x12, 0x04, 0xcd, 0x05, 0x06, 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, + 0x03, 0x16, 0x02, 0x06, 0x01, 0x12, 0x04, 0xcd, 0x05, 0x0d, 0x1f, 0x0a, 0x0f, 0x0a, 0x07, 0x04, + 0x00, 0x03, 0x16, 0x02, 0x06, 0x03, 0x12, 0x04, 0xcd, 0x05, 0x22, 0x23, 0x0a, 0x44, 0x0a, 0x06, + 0x04, 0x00, 0x03, 0x16, 0x02, 0x07, 0x12, 0x04, 0xcf, 0x05, 0x06, 0x25, 0x1a, 0x34, 0x2f, 0x20, + 0x54, 0x68, 0x65, 0x20, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x60, 0x6f, + 0x75, 0x74, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, + 0x60, 0x20, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x73, 0x77, 0x61, 0x70, + 0x2e, 0x0a, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x16, 0x02, 0x07, 0x05, 0x12, 0x04, 0xcf, + 0x05, 0x06, 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x16, 0x02, 0x07, 0x01, 0x12, 0x04, + 0xcf, 0x05, 0x0d, 0x20, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x16, 0x02, 0x07, 0x03, 0x12, + 0x04, 0xcf, 0x05, 0x23, 0x24, 0x0a, 0x61, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x16, 0x02, 0x08, 0x12, + 0x04, 0xd3, 0x05, 0x04, 0x21, 0x1a, 0x51, 0x2f, 0x20, 0x54, 0x68, 0x65, 0x20, 0x61, 0x6c, 0x6c, + 0x6f, 0x77, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x73, 0x6c, 0x69, 0x70, 0x70, 0x61, 0x67, 0x65, 0x20, + 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x77, 0x61, 0x70, 0x20, 0x69, 0x6e, 0x20, 0x64, + 0x65, 0x63, 0x69, 0x6d, 0x61, 0x6c, 0x20, 0x66, 0x6f, 0x72, 0x6d, 0x20, 0x28, 0x65, 0x2e, 0x67, + 0x2e, 0x20, 0x30, 0x2e, 0x35, 0x20, 0x69, 0x73, 0x20, 0x30, 0x2e, 0x35, 0x25, 0x20, 0x73, 0x6c, + 0x69, 0x70, 0x70, 0x61, 0x67, 0x65, 0x29, 0x0a, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x16, + 0x02, 0x08, 0x04, 0x12, 0x04, 0xd3, 0x05, 0x04, 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, + 0x16, 0x02, 0x08, 0x05, 0x12, 0x04, 0xd3, 0x05, 0x0d, 0x13, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, + 0x03, 0x16, 0x02, 0x08, 0x01, 0x12, 0x04, 0xd3, 0x05, 0x14, 0x1c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, + 0x00, 0x03, 0x16, 0x02, 0x08, 0x03, 0x12, 0x04, 0xd3, 0x05, 0x1f, 0x20, 0x0a, 0x10, 0x0a, 0x06, + 0x04, 0x00, 0x03, 0x16, 0x04, 0x00, 0x12, 0x06, 0xd5, 0x05, 0x04, 0xd8, 0x05, 0x05, 0x0a, 0x0f, + 0x0a, 0x07, 0x04, 0x00, 0x03, 0x16, 0x04, 0x00, 0x01, 0x12, 0x04, 0xd5, 0x05, 0x09, 0x10, 0x0a, + 0x10, 0x0a, 0x08, 0x04, 0x00, 0x03, 0x16, 0x04, 0x00, 0x02, 0x00, 0x12, 0x04, 0xd6, 0x05, 0x06, + 0x15, 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x16, 0x04, 0x00, 0x02, 0x00, 0x01, 0x12, 0x04, + 0xd6, 0x05, 0x06, 0x10, 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x16, 0x04, 0x00, 0x02, 0x00, + 0x02, 0x12, 0x04, 0xd6, 0x05, 0x13, 0x14, 0x0a, 0x10, 0x0a, 0x08, 0x04, 0x00, 0x03, 0x16, 0x04, + 0x00, 0x02, 0x01, 0x12, 0x04, 0xd7, 0x05, 0x06, 0x15, 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, + 0x16, 0x04, 0x00, 0x02, 0x01, 0x01, 0x12, 0x04, 0xd7, 0x05, 0x06, 0x10, 0x0a, 0x11, 0x0a, 0x09, + 0x04, 0x00, 0x03, 0x16, 0x04, 0x00, 0x02, 0x01, 0x02, 0x12, 0x04, 0xd7, 0x05, 0x13, 0x14, 0x0a, + 0x0e, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x16, 0x02, 0x09, 0x12, 0x04, 0xda, 0x05, 0x04, 0x22, 0x0a, + 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x16, 0x02, 0x09, 0x04, 0x12, 0x04, 0xda, 0x05, 0x04, 0x0c, + 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x16, 0x02, 0x09, 0x06, 0x12, 0x04, 0xda, 0x05, 0x0d, + 0x14, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x16, 0x02, 0x09, 0x01, 0x12, 0x04, 0xda, 0x05, + 0x15, 0x1c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x16, 0x02, 0x09, 0x03, 0x12, 0x04, 0xda, + 0x05, 0x1f, 0x21, 0x0a, 0x41, 0x0a, 0x04, 0x04, 0x00, 0x03, 0x17, 0x12, 0x06, 0xde, 0x05, 0x02, + 0xe9, 0x05, 0x03, 0x1a, 0x31, 0x2f, 0x20, 0x46, 0x65, 0x74, 0x63, 0x68, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x20, 0x70, 0x72, 0x69, 0x63, 0x65, 0x20, 0x6f, + 0x66, 0x20, 0x61, 0x20, 0x70, 0x65, 0x72, 0x70, 0x65, 0x74, 0x75, 0x61, 0x6c, 0x20, 0x6d, 0x61, + 0x72, 0x6b, 0x65, 0x74, 0x2e, 0x0a, 0x0a, 0x0d, 0x0a, 0x05, 0x04, 0x00, 0x03, 0x17, 0x01, 0x12, + 0x04, 0xde, 0x05, 0x0a, 0x18, 0x0a, 0x10, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x17, 0x08, 0x00, 0x12, + 0x06, 0xdf, 0x05, 0x04, 0xe8, 0x05, 0x05, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x17, 0x08, + 0x00, 0x01, 0x12, 0x04, 0xdf, 0x05, 0x0a, 0x17, 0x0a, 0xaf, 0x01, 0x0a, 0x06, 0x04, 0x00, 0x03, + 0x17, 0x02, 0x00, 0x12, 0x04, 0xe1, 0x05, 0x06, 0x26, 0x1a, 0x9e, 0x01, 0x2f, 0x20, 0x4d, 0x61, + 0x72, 0x6b, 0x65, 0x74, 0x20, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x20, 0x66, 0x6f, 0x72, + 0x20, 0x61, 0x20, 0x6d, 0x61, 0x6e, 0x67, 0x6f, 0x20, 0x70, 0x65, 0x72, 0x70, 0x65, 0x74, 0x75, + 0x61, 0x6c, 0x20, 0x6d, 0x61, 0x72, 0x6b, 0x65, 0x74, 0x2e, 0x20, 0x41, 0x20, 0x66, 0x75, 0x6c, + 0x6c, 0x20, 0x6c, 0x69, 0x73, 0x74, 0x20, 0x63, 0x61, 0x6e, 0x20, 0x62, 0x65, 0x20, 0x66, 0x6f, + 0x75, 0x6e, 0x64, 0x20, 0x68, 0x65, 0x72, 0x65, 0x3a, 0x20, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, + 0x2f, 0x2f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x62, 0x6c, 0x6f, + 0x63, 0x6b, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x2d, 0x66, 0x6f, 0x75, 0x6e, 0x64, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x2f, 0x6d, 0x61, 0x6e, 0x67, 0x6f, 0x2d, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x2d, + 0x76, 0x33, 0x2f, 0x62, 0x6c, 0x6f, 0x62, 0x2f, 0x6d, 0x61, 0x69, 0x6e, 0x2f, 0x73, 0x72, 0x63, + 0x2f, 0x69, 0x64, 0x73, 0x2e, 0x6a, 0x73, 0x6f, 0x6e, 0x0a, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, + 0x03, 0x17, 0x02, 0x00, 0x05, 0x12, 0x04, 0xe1, 0x05, 0x06, 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, + 0x00, 0x03, 0x17, 0x02, 0x00, 0x01, 0x12, 0x04, 0xe1, 0x05, 0x0d, 0x21, 0x0a, 0x0f, 0x0a, 0x07, + 0x04, 0x00, 0x03, 0x17, 0x02, 0x00, 0x03, 0x12, 0x04, 0xe1, 0x05, 0x24, 0x25, 0x0a, 0xb2, 0x01, + 0x0a, 0x06, 0x04, 0x00, 0x03, 0x17, 0x02, 0x01, 0x12, 0x04, 0xe3, 0x05, 0x06, 0x26, 0x1a, 0xa1, + 0x01, 0x2f, 0x20, 0x4d, 0x61, 0x72, 0x6b, 0x65, 0x74, 0x20, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, + 0x73, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x61, 0x20, 0x64, 0x72, 0x69, 0x66, 0x74, 0x20, 0x70, 0x65, + 0x72, 0x70, 0x65, 0x74, 0x75, 0x61, 0x6c, 0x20, 0x6d, 0x61, 0x72, 0x6b, 0x65, 0x74, 0x2e, 0x20, + 0x41, 0x20, 0x66, 0x75, 0x6c, 0x6c, 0x20, 0x6c, 0x69, 0x73, 0x74, 0x20, 0x63, 0x61, 0x6e, 0x20, + 0x62, 0x65, 0x20, 0x66, 0x6f, 0x75, 0x6e, 0x64, 0x20, 0x68, 0x65, 0x72, 0x65, 0x3a, 0x20, 0x68, + 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, + 0x6d, 0x2f, 0x64, 0x72, 0x69, 0x66, 0x74, 0x2d, 0x6c, 0x61, 0x62, 0x73, 0x2f, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2d, 0x76, 0x31, 0x2f, 0x62, 0x6c, 0x6f, 0x62, 0x2f, 0x6d, 0x61, + 0x73, 0x74, 0x65, 0x72, 0x2f, 0x73, 0x64, 0x6b, 0x2f, 0x73, 0x72, 0x63, 0x2f, 0x63, 0x6f, 0x6e, + 0x73, 0x74, 0x61, 0x6e, 0x74, 0x73, 0x2f, 0x6d, 0x61, 0x72, 0x6b, 0x65, 0x74, 0x73, 0x2e, 0x74, + 0x73, 0x0a, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x17, 0x02, 0x01, 0x05, 0x12, 0x04, 0xe3, + 0x05, 0x06, 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x17, 0x02, 0x01, 0x01, 0x12, 0x04, + 0xe3, 0x05, 0x0d, 0x21, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x17, 0x02, 0x01, 0x03, 0x12, + 0x04, 0xe3, 0x05, 0x24, 0x25, 0x0a, 0x3e, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x17, 0x02, 0x02, 0x12, + 0x04, 0xe5, 0x05, 0x06, 0x25, 0x1a, 0x2e, 0x2f, 0x20, 0x4d, 0x61, 0x72, 0x6b, 0x65, 0x74, 0x20, + 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x61, 0x20, 0x7a, 0x65, + 0x74, 0x61, 0x20, 0x70, 0x65, 0x72, 0x70, 0x65, 0x74, 0x75, 0x61, 0x6c, 0x20, 0x6d, 0x61, 0x72, + 0x6b, 0x65, 0x74, 0x2e, 0x0a, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x17, 0x02, 0x02, 0x05, + 0x12, 0x04, 0xe5, 0x05, 0x06, 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x17, 0x02, 0x02, + 0x01, 0x12, 0x04, 0xe5, 0x05, 0x0d, 0x20, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x17, 0x02, + 0x02, 0x03, 0x12, 0x04, 0xe5, 0x05, 0x23, 0x24, 0x0a, 0x45, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x17, + 0x02, 0x03, 0x12, 0x04, 0xe7, 0x05, 0x06, 0x23, 0x1a, 0x35, 0x2f, 0x20, 0x4d, 0x61, 0x72, 0x6b, + 0x65, 0x74, 0x20, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x61, + 0x20, 0x30, 0x31, 0x20, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x20, 0x70, 0x65, 0x72, + 0x70, 0x65, 0x74, 0x75, 0x61, 0x6c, 0x20, 0x6d, 0x61, 0x72, 0x6b, 0x65, 0x74, 0x2e, 0x0a, 0x0a, + 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x17, 0x02, 0x03, 0x05, 0x12, 0x04, 0xe7, 0x05, 0x06, 0x0c, + 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x17, 0x02, 0x03, 0x01, 0x12, 0x04, 0xe7, 0x05, 0x0d, + 0x1e, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x17, 0x02, 0x03, 0x03, 0x12, 0x04, 0xe7, 0x05, + 0x21, 0x22, 0x0a, 0xdb, 0x04, 0x0a, 0x04, 0x04, 0x00, 0x03, 0x18, 0x12, 0x06, 0x84, 0x06, 0x02, + 0xab, 0x06, 0x03, 0x1a, 0xca, 0x04, 0x0a, 0x46, 0x65, 0x74, 0x63, 0x68, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x20, 0x70, 0x72, 0x69, 0x63, 0x65, 0x20, 0x6f, + 0x66, 0x20, 0x61, 0x20, 0x53, 0x6f, 0x6c, 0x61, 0x6e, 0x61, 0x20, 0x6f, 0x72, 0x61, 0x63, 0x6c, + 0x65, 0x20, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x0a, 0x0a, 0x5f, 0x2a, 0x2a, + 0x49, 0x6e, 0x70, 0x75, 0x74, 0x2a, 0x2a, 0x5f, 0x3a, 0x20, 0x4e, 0x6f, 0x6e, 0x65, 0x0a, 0x0a, + 0x5f, 0x2a, 0x2a, 0x52, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x73, 0x2a, 0x2a, 0x5f, 0x3a, 0x20, 0x54, + 0x68, 0x65, 0x20, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x20, 0x70, 0x72, 0x69, 0x63, 0x65, + 0x20, 0x6f, 0x66, 0x20, 0x61, 0x6e, 0x20, 0x6f, 0x6e, 0x2d, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x20, + 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x2e, 0x0a, 0x0a, 0x5f, 0x2a, 0x2a, 0x45, 0x78, 0x61, 0x6d, + 0x70, 0x6c, 0x65, 0x2a, 0x2a, 0x5f, 0x3a, 0x20, 0x54, 0x68, 0x65, 0x20, 0x53, 0x77, 0x69, 0x74, + 0x63, 0x68, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x20, 0x53, 0x4f, 0x4c, 0x2f, 0x55, 0x53, 0x44, 0x20, + 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x20, 0x70, 0x72, 0x69, 0x63, 0x65, 0x2e, 0x0a, 0x0a, 0x60, + 0x60, 0x60, 0x6a, 0x73, 0x6f, 0x6e, 0x0a, 0x7b, 0x20, 0x22, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, + 0x54, 0x61, 0x73, 0x6b, 0x22, 0x3a, 0x20, 0x7b, 0x20, 0x22, 0x73, 0x77, 0x69, 0x74, 0x63, 0x68, + 0x62, 0x6f, 0x61, 0x72, 0x64, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x22, 0x3a, 0x20, 0x22, + 0x47, 0x76, 0x44, 0x4d, 0x78, 0x50, 0x7a, 0x4e, 0x31, 0x73, 0x43, 0x6a, 0x37, 0x4c, 0x32, 0x36, + 0x59, 0x44, 0x4b, 0x32, 0x48, 0x6e, 0x4d, 0x52, 0x58, 0x45, 0x51, 0x6d, 0x51, 0x32, 0x61, 0x65, + 0x6d, 0x6f, 0x76, 0x38, 0x59, 0x42, 0x74, 0x50, 0x53, 0x37, 0x76, 0x52, 0x22, 0x20, 0x7d, 0x20, + 0x7d, 0x0a, 0x60, 0x60, 0x60, 0x0a, 0x0a, 0x5f, 0x2a, 0x2a, 0x45, 0x78, 0x61, 0x6d, 0x70, 0x6c, + 0x65, 0x2a, 0x2a, 0x5f, 0x3a, 0x20, 0x54, 0x68, 0x65, 0x20, 0x50, 0x79, 0x74, 0x68, 0x20, 0x53, + 0x4f, 0x4c, 0x2f, 0x55, 0x53, 0x44, 0x20, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x20, 0x70, 0x72, + 0x69, 0x63, 0x65, 0x2e, 0x0a, 0x0a, 0x60, 0x60, 0x60, 0x6a, 0x73, 0x6f, 0x6e, 0x0a, 0x7b, 0x20, + 0x22, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x22, 0x3a, 0x20, 0x7b, 0x20, + 0x22, 0x70, 0x79, 0x74, 0x68, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x22, 0x3a, 0x20, 0x22, + 0x48, 0x36, 0x41, 0x52, 0x48, 0x66, 0x36, 0x59, 0x58, 0x68, 0x47, 0x59, 0x65, 0x51, 0x66, 0x55, + 0x7a, 0x51, 0x4e, 0x47, 0x6b, 0x36, 0x72, 0x44, 0x4e, 0x6e, 0x4c, 0x42, 0x51, 0x4b, 0x72, 0x65, + 0x6e, 0x4e, 0x37, 0x31, 0x32, 0x4b, 0x34, 0x41, 0x51, 0x4a, 0x45, 0x47, 0x22, 0x20, 0x7d, 0x20, + 0x7d, 0x0a, 0x60, 0x60, 0x60, 0x0a, 0x0a, 0x5f, 0x2a, 0x2a, 0x45, 0x78, 0x61, 0x6d, 0x70, 0x6c, + 0x65, 0x2a, 0x2a, 0x5f, 0x3a, 0x20, 0x54, 0x68, 0x65, 0x20, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x6c, + 0x69, 0x6e, 0x6b, 0x20, 0x53, 0x4f, 0x4c, 0x2f, 0x55, 0x53, 0x44, 0x20, 0x6f, 0x72, 0x61, 0x63, + 0x6c, 0x65, 0x20, 0x70, 0x72, 0x69, 0x63, 0x65, 0x2e, 0x0a, 0x0a, 0x60, 0x60, 0x60, 0x6a, 0x73, + 0x6f, 0x6e, 0x0a, 0x7b, 0x20, 0x22, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x54, 0x61, 0x73, 0x6b, + 0x22, 0x3a, 0x20, 0x7b, 0x20, 0x22, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x41, + 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x22, 0x3a, 0x20, 0x22, 0x43, 0x63, 0x50, 0x56, 0x53, 0x39, + 0x62, 0x71, 0x79, 0x58, 0x62, 0x44, 0x39, 0x63, 0x4c, 0x6e, 0x54, 0x62, 0x68, 0x68, 0x48, 0x61, + 0x7a, 0x4c, 0x73, 0x72, 0x75, 0x61, 0x38, 0x51, 0x4d, 0x46, 0x55, 0x48, 0x54, 0x75, 0x74, 0x50, + 0x74, 0x6a, 0x79, 0x44, 0x7a, 0x71, 0x22, 0x20, 0x7d, 0x20, 0x7d, 0x0a, 0x60, 0x60, 0x60, 0x0a, + 0x0a, 0x0d, 0x0a, 0x05, 0x04, 0x00, 0x03, 0x18, 0x01, 0x12, 0x04, 0x84, 0x06, 0x0a, 0x14, 0x0a, + 0x10, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x18, 0x03, 0x00, 0x12, 0x06, 0x85, 0x06, 0x04, 0x87, 0x06, + 0x05, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x18, 0x03, 0x00, 0x01, 0x12, 0x04, 0x85, 0x06, + 0x0c, 0x1c, 0x0a, 0x10, 0x0a, 0x08, 0x04, 0x00, 0x03, 0x18, 0x03, 0x00, 0x02, 0x00, 0x12, 0x04, + 0x86, 0x06, 0x06, 0x23, 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x18, 0x03, 0x00, 0x02, 0x00, + 0x04, 0x12, 0x04, 0x86, 0x06, 0x06, 0x0e, 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x18, 0x03, + 0x00, 0x02, 0x00, 0x05, 0x12, 0x04, 0x86, 0x06, 0x0f, 0x15, 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, + 0x03, 0x18, 0x03, 0x00, 0x02, 0x00, 0x01, 0x12, 0x04, 0x86, 0x06, 0x16, 0x1e, 0x0a, 0x11, 0x0a, + 0x09, 0x04, 0x00, 0x03, 0x18, 0x03, 0x00, 0x02, 0x00, 0x03, 0x12, 0x04, 0x86, 0x06, 0x21, 0x22, + 0x0a, 0x10, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x18, 0x03, 0x01, 0x12, 0x06, 0x88, 0x06, 0x04, 0x8c, + 0x06, 0x05, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x18, 0x03, 0x01, 0x01, 0x12, 0x04, 0x88, + 0x06, 0x0c, 0x17, 0x0a, 0x10, 0x0a, 0x08, 0x04, 0x00, 0x03, 0x18, 0x03, 0x01, 0x02, 0x00, 0x12, + 0x04, 0x89, 0x06, 0x06, 0x25, 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x18, 0x03, 0x01, 0x02, + 0x00, 0x04, 0x12, 0x04, 0x89, 0x06, 0x06, 0x0e, 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x18, + 0x03, 0x01, 0x02, 0x00, 0x05, 0x12, 0x04, 0x89, 0x06, 0x0f, 0x15, 0x0a, 0x11, 0x0a, 0x09, 0x04, + 0x00, 0x03, 0x18, 0x03, 0x01, 0x02, 0x00, 0x01, 0x12, 0x04, 0x89, 0x06, 0x16, 0x20, 0x0a, 0x11, + 0x0a, 0x09, 0x04, 0x00, 0x03, 0x18, 0x03, 0x01, 0x02, 0x00, 0x03, 0x12, 0x04, 0x89, 0x06, 0x23, + 0x24, 0x0a, 0x10, 0x0a, 0x08, 0x04, 0x00, 0x03, 0x18, 0x03, 0x01, 0x02, 0x01, 0x12, 0x04, 0x8a, + 0x06, 0x06, 0x3b, 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x18, 0x03, 0x01, 0x02, 0x01, 0x04, + 0x12, 0x04, 0x8a, 0x06, 0x06, 0x0e, 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x18, 0x03, 0x01, + 0x02, 0x01, 0x05, 0x12, 0x04, 0x8a, 0x06, 0x0f, 0x15, 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, + 0x18, 0x03, 0x01, 0x02, 0x01, 0x01, 0x12, 0x04, 0x8a, 0x06, 0x16, 0x36, 0x0a, 0x11, 0x0a, 0x09, + 0x04, 0x00, 0x03, 0x18, 0x03, 0x01, 0x02, 0x01, 0x03, 0x12, 0x04, 0x8a, 0x06, 0x39, 0x3a, 0x0a, + 0x10, 0x0a, 0x08, 0x04, 0x00, 0x03, 0x18, 0x03, 0x01, 0x02, 0x02, 0x12, 0x04, 0x8b, 0x06, 0x06, + 0x2b, 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x18, 0x03, 0x01, 0x02, 0x02, 0x04, 0x12, 0x04, + 0x8b, 0x06, 0x06, 0x0e, 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x18, 0x03, 0x01, 0x02, 0x02, + 0x05, 0x12, 0x04, 0x8b, 0x06, 0x0f, 0x14, 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x18, 0x03, + 0x01, 0x02, 0x02, 0x01, 0x12, 0x04, 0x8b, 0x06, 0x15, 0x26, 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, + 0x03, 0x18, 0x03, 0x01, 0x02, 0x02, 0x03, 0x12, 0x04, 0x8b, 0x06, 0x29, 0x2a, 0x0a, 0x10, 0x0a, + 0x06, 0x04, 0x00, 0x03, 0x18, 0x03, 0x02, 0x12, 0x06, 0x8d, 0x06, 0x04, 0x90, 0x06, 0x05, 0x0a, + 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x18, 0x03, 0x02, 0x01, 0x12, 0x04, 0x8d, 0x06, 0x0c, 0x1e, + 0x0a, 0x10, 0x0a, 0x08, 0x04, 0x00, 0x03, 0x18, 0x03, 0x02, 0x02, 0x00, 0x12, 0x04, 0x8e, 0x06, + 0x06, 0x21, 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x18, 0x03, 0x02, 0x02, 0x00, 0x04, 0x12, + 0x04, 0x8e, 0x06, 0x06, 0x0e, 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x18, 0x03, 0x02, 0x02, + 0x00, 0x05, 0x12, 0x04, 0x8e, 0x06, 0x0f, 0x14, 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x18, + 0x03, 0x02, 0x02, 0x00, 0x01, 0x12, 0x04, 0x8e, 0x06, 0x15, 0x1c, 0x0a, 0x11, 0x0a, 0x09, 0x04, + 0x00, 0x03, 0x18, 0x03, 0x02, 0x02, 0x00, 0x03, 0x12, 0x04, 0x8e, 0x06, 0x1f, 0x20, 0x0a, 0x10, + 0x0a, 0x08, 0x04, 0x00, 0x03, 0x18, 0x03, 0x02, 0x02, 0x01, 0x12, 0x04, 0x8f, 0x06, 0x06, 0x22, + 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x18, 0x03, 0x02, 0x02, 0x01, 0x04, 0x12, 0x04, 0x8f, + 0x06, 0x06, 0x0e, 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x18, 0x03, 0x02, 0x02, 0x01, 0x06, + 0x12, 0x04, 0x8f, 0x06, 0x0f, 0x18, 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x18, 0x03, 0x02, + 0x02, 0x01, 0x01, 0x12, 0x04, 0x8f, 0x06, 0x19, 0x1d, 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, + 0x18, 0x03, 0x02, 0x02, 0x01, 0x03, 0x12, 0x04, 0x8f, 0x06, 0x20, 0x21, 0x0a, 0x10, 0x0a, 0x06, + 0x04, 0x00, 0x03, 0x18, 0x03, 0x03, 0x12, 0x06, 0x91, 0x06, 0x04, 0x92, 0x06, 0x05, 0x0a, 0x0f, + 0x0a, 0x07, 0x04, 0x00, 0x03, 0x18, 0x03, 0x03, 0x01, 0x12, 0x04, 0x91, 0x06, 0x0c, 0x17, 0x0a, + 0x10, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x18, 0x03, 0x04, 0x12, 0x06, 0x93, 0x06, 0x04, 0x94, 0x06, + 0x05, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x18, 0x03, 0x04, 0x01, 0x12, 0x04, 0x93, 0x06, + 0x0c, 0x1b, 0x0a, 0x10, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x18, 0x08, 0x00, 0x12, 0x06, 0x95, 0x06, + 0x04, 0x9e, 0x06, 0x05, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x18, 0x08, 0x00, 0x01, 0x12, + 0x04, 0x95, 0x06, 0x0a, 0x1b, 0x0a, 0x81, 0x01, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x18, 0x02, 0x00, + 0x12, 0x04, 0x97, 0x06, 0x06, 0x25, 0x1a, 0x71, 0x2f, 0x20, 0x4d, 0x61, 0x69, 0x6e, 0x6e, 0x65, + 0x74, 0x20, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x20, 0x6f, 0x66, 0x20, 0x61, 0x20, 0x53, + 0x77, 0x69, 0x74, 0x63, 0x68, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x20, 0x66, 0x65, 0x65, 0x64, 0x2e, + 0x20, 0x53, 0x77, 0x69, 0x74, 0x63, 0x68, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x20, 0x69, 0x73, 0x20, + 0x64, 0x65, 0x63, 0x65, 0x6e, 0x74, 0x72, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x20, 0x61, 0x6e, + 0x64, 0x20, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x73, 0x20, 0x61, 0x6e, 0x79, 0x6f, 0x6e, 0x65, 0x20, + 0x74, 0x6f, 0x20, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x20, 0x74, 0x68, 0x65, 0x69, 0x72, 0x20, 0x6f, + 0x77, 0x6e, 0x20, 0x66, 0x65, 0x65, 0x64, 0x2e, 0x0a, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, + 0x18, 0x02, 0x00, 0x05, 0x12, 0x04, 0x97, 0x06, 0x06, 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, + 0x03, 0x18, 0x02, 0x00, 0x01, 0x12, 0x04, 0x97, 0x06, 0x0d, 0x20, 0x0a, 0x0f, 0x0a, 0x07, 0x04, + 0x00, 0x03, 0x18, 0x02, 0x00, 0x03, 0x12, 0x04, 0x97, 0x06, 0x23, 0x24, 0x0a, 0x74, 0x0a, 0x06, + 0x04, 0x00, 0x03, 0x18, 0x02, 0x01, 0x12, 0x04, 0x99, 0x06, 0x06, 0x1e, 0x1a, 0x64, 0x2f, 0x20, + 0x4d, 0x61, 0x69, 0x6e, 0x6e, 0x65, 0x74, 0x20, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x20, + 0x66, 0x6f, 0x72, 0x20, 0x61, 0x20, 0x50, 0x79, 0x74, 0x68, 0x20, 0x66, 0x65, 0x65, 0x64, 0x2e, + 0x20, 0x41, 0x20, 0x66, 0x75, 0x6c, 0x6c, 0x20, 0x6c, 0x69, 0x73, 0x74, 0x20, 0x63, 0x61, 0x6e, + 0x20, 0x62, 0x65, 0x20, 0x66, 0x6f, 0x75, 0x6e, 0x64, 0x20, 0x68, 0x65, 0x72, 0x65, 0x3a, 0x20, + 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x70, 0x79, 0x74, 0x68, 0x2e, 0x6e, 0x65, 0x74, + 0x77, 0x6f, 0x72, 0x6b, 0x2f, 0x70, 0x72, 0x69, 0x63, 0x65, 0x2d, 0x66, 0x65, 0x65, 0x64, 0x73, + 0x2f, 0x0a, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x18, 0x02, 0x01, 0x05, 0x12, 0x04, 0x99, + 0x06, 0x06, 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x18, 0x02, 0x01, 0x01, 0x12, 0x04, + 0x99, 0x06, 0x0d, 0x19, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x18, 0x02, 0x01, 0x03, 0x12, + 0x04, 0x99, 0x06, 0x1c, 0x1d, 0x0a, 0x8d, 0x01, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x18, 0x02, 0x02, + 0x12, 0x04, 0x9b, 0x06, 0x06, 0x23, 0x1a, 0x7d, 0x2f, 0x20, 0x4d, 0x61, 0x69, 0x6e, 0x6e, 0x65, + 0x74, 0x20, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x61, 0x20, + 0x43, 0x68, 0x61, 0x69, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x20, 0x66, 0x65, 0x65, 0x64, 0x2e, 0x20, + 0x41, 0x20, 0x66, 0x75, 0x6c, 0x6c, 0x20, 0x6c, 0x69, 0x73, 0x74, 0x20, 0x63, 0x61, 0x6e, 0x20, + 0x62, 0x65, 0x20, 0x66, 0x6f, 0x75, 0x6e, 0x64, 0x20, 0x68, 0x65, 0x72, 0x65, 0x3a, 0x20, 0x68, + 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x64, 0x6f, 0x63, 0x73, 0x2e, 0x63, 0x68, 0x61, 0x69, + 0x6e, 0x2e, 0x6c, 0x69, 0x6e, 0x6b, 0x2f, 0x64, 0x6f, 0x63, 0x73, 0x2f, 0x73, 0x6f, 0x6c, 0x61, + 0x6e, 0x61, 0x2f, 0x64, 0x61, 0x74, 0x61, 0x2d, 0x66, 0x65, 0x65, 0x64, 0x73, 0x2d, 0x73, 0x6f, + 0x6c, 0x61, 0x6e, 0x61, 0x0a, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x18, 0x02, 0x02, 0x05, + 0x12, 0x04, 0x9b, 0x06, 0x06, 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x18, 0x02, 0x02, + 0x01, 0x12, 0x04, 0x9b, 0x06, 0x0d, 0x1e, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x18, 0x02, + 0x02, 0x03, 0x12, 0x04, 0x9b, 0x06, 0x21, 0x22, 0x0a, 0x0e, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x18, + 0x02, 0x03, 0x12, 0x04, 0x9c, 0x06, 0x06, 0x19, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x18, + 0x02, 0x03, 0x05, 0x12, 0x04, 0x9c, 0x06, 0x06, 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, + 0x18, 0x02, 0x03, 0x01, 0x12, 0x04, 0x9c, 0x06, 0x0d, 0x14, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, + 0x03, 0x18, 0x02, 0x03, 0x03, 0x12, 0x04, 0x9c, 0x06, 0x17, 0x18, 0x0a, 0x0e, 0x0a, 0x06, 0x04, + 0x00, 0x03, 0x18, 0x02, 0x04, 0x12, 0x04, 0x9d, 0x06, 0x06, 0x1d, 0x0a, 0x0f, 0x0a, 0x07, 0x04, + 0x00, 0x03, 0x18, 0x02, 0x04, 0x05, 0x12, 0x04, 0x9d, 0x06, 0x06, 0x0c, 0x0a, 0x0f, 0x0a, 0x07, + 0x04, 0x00, 0x03, 0x18, 0x02, 0x04, 0x01, 0x12, 0x04, 0x9d, 0x06, 0x0d, 0x18, 0x0a, 0x0f, 0x0a, + 0x07, 0x04, 0x00, 0x03, 0x18, 0x02, 0x04, 0x03, 0x12, 0x04, 0x9d, 0x06, 0x1b, 0x1c, 0x0a, 0xf0, + 0x02, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x18, 0x02, 0x05, 0x12, 0x04, 0xa4, 0x06, 0x04, 0x39, 0x1a, + 0xae, 0x02, 0x2f, 0x20, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x20, 0x28, 0x61, 0x73, 0x20, 0x61, 0x20, + 0x70, 0x65, 0x72, 0x63, 0x65, 0x6e, 0x74, 0x61, 0x67, 0x65, 0x29, 0x20, 0x74, 0x68, 0x61, 0x74, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x6c, 0x6f, 0x77, 0x65, 0x72, 0x20, 0x62, 0x6f, 0x75, 0x6e, 0x64, + 0x20, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x64, 0x65, 0x6e, 0x63, 0x65, 0x20, 0x69, 0x6e, 0x74, 0x65, + 0x72, 0x76, 0x61, 0x6c, 0x20, 0x69, 0x73, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x61, + 0x63, 0x74, 0x75, 0x61, 0x6c, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x2e, 0x0a, 0x2f, 0x20, 0x43, + 0x6f, 0x6e, 0x66, 0x69, 0x64, 0x65, 0x6e, 0x63, 0x65, 0x20, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, + 0x61, 0x6c, 0x73, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x61, 0x72, 0x65, 0x20, 0x6c, 0x61, 0x72, + 0x67, 0x65, 0x72, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x74, 0x72, + 0x65, 0x73, 0x68, 0x6f, 0x6c, 0x64, 0x20, 0x61, 0x72, 0x65, 0x20, 0x72, 0x65, 0x6a, 0x65, 0x63, + 0x74, 0x65, 0x64, 0x2e, 0x0a, 0x2f, 0x0a, 0x2f, 0x20, 0x54, 0x68, 0x65, 0x20, 0x63, 0x6f, 0x6e, + 0x66, 0x69, 0x64, 0x65, 0x6e, 0x63, 0x65, 0x20, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, + 0x20, 0x73, 0x68, 0x6f, 0x75, 0x6c, 0x64, 0x20, 0x62, 0x65, 0x20, 0x70, 0x72, 0x6f, 0x76, 0x69, + 0x64, 0x65, 0x64, 0x20, 0x61, 0x73, 0x20, 0x61, 0x20, 0x72, 0x61, 0x77, 0x20, 0x70, 0x65, 0x72, + 0x63, 0x65, 0x6e, 0x74, 0x61, 0x67, 0x65, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x2e, 0x20, 0x46, + 0x6f, 0x72, 0x20, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2c, 0x20, 0x74, 0x6f, 0x0a, 0x2f, + 0x20, 0x72, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x20, 0x31, 0x30, 0x25, 0x2c, 0x20, + 0x65, 0x6e, 0x74, 0x65, 0x72, 0x20, 0x74, 0x68, 0x65, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x20, + 0x61, 0x73, 0x20, 0x31, 0x30, 0x2c, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x30, 0x2e, 0x31, 0x2e, 0x0a, + 0x22, 0x2f, 0x20, 0x44, 0x65, 0x70, 0x72, 0x65, 0x63, 0x61, 0x74, 0x65, 0x64, 0x20, 0x22, 0x70, + 0x79, 0x74, 0x68, 0x5f, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x65, 0x64, 0x5f, 0x63, 0x6f, 0x6e, 0x66, + 0x69, 0x64, 0x65, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x22, + 0x0a, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x18, 0x02, 0x05, 0x04, 0x12, 0x04, 0xa4, 0x06, + 0x04, 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x18, 0x02, 0x05, 0x05, 0x12, 0x04, 0xa4, + 0x06, 0x0d, 0x13, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x18, 0x02, 0x05, 0x01, 0x12, 0x04, + 0xa4, 0x06, 0x14, 0x34, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x18, 0x02, 0x05, 0x03, 0x12, + 0x04, 0xa4, 0x06, 0x37, 0x38, 0x0a, 0x0e, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x18, 0x02, 0x06, 0x12, + 0x04, 0xa5, 0x06, 0x04, 0x34, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x18, 0x02, 0x06, 0x04, + 0x12, 0x04, 0xa5, 0x06, 0x04, 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x18, 0x02, 0x06, + 0x06, 0x12, 0x04, 0xa5, 0x06, 0x0d, 0x1d, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x18, 0x02, + 0x06, 0x01, 0x12, 0x04, 0xa5, 0x06, 0x1e, 0x2f, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x18, + 0x02, 0x06, 0x03, 0x12, 0x04, 0xa5, 0x06, 0x32, 0x33, 0x0a, 0x0e, 0x0a, 0x06, 0x04, 0x00, 0x03, + 0x18, 0x02, 0x07, 0x12, 0x04, 0xa6, 0x06, 0x04, 0x2a, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, + 0x18, 0x02, 0x07, 0x04, 0x12, 0x04, 0xa6, 0x06, 0x04, 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, + 0x03, 0x18, 0x02, 0x07, 0x06, 0x12, 0x04, 0xa6, 0x06, 0x0d, 0x18, 0x0a, 0x0f, 0x0a, 0x07, 0x04, + 0x00, 0x03, 0x18, 0x02, 0x07, 0x01, 0x12, 0x04, 0xa6, 0x06, 0x19, 0x25, 0x0a, 0x0f, 0x0a, 0x07, + 0x04, 0x00, 0x03, 0x18, 0x02, 0x07, 0x03, 0x12, 0x04, 0xa6, 0x06, 0x28, 0x29, 0x0a, 0x0e, 0x0a, + 0x06, 0x04, 0x00, 0x03, 0x18, 0x02, 0x08, 0x12, 0x04, 0xa7, 0x06, 0x04, 0x38, 0x0a, 0x0f, 0x0a, + 0x07, 0x04, 0x00, 0x03, 0x18, 0x02, 0x08, 0x04, 0x12, 0x04, 0xa7, 0x06, 0x04, 0x0c, 0x0a, 0x0f, + 0x0a, 0x07, 0x04, 0x00, 0x03, 0x18, 0x02, 0x08, 0x06, 0x12, 0x04, 0xa7, 0x06, 0x0d, 0x1f, 0x0a, + 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x18, 0x02, 0x08, 0x01, 0x12, 0x04, 0xa7, 0x06, 0x20, 0x33, + 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x18, 0x02, 0x08, 0x03, 0x12, 0x04, 0xa7, 0x06, 0x36, + 0x37, 0x0a, 0x0e, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x18, 0x02, 0x09, 0x12, 0x04, 0xa8, 0x06, 0x04, + 0x2b, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x18, 0x02, 0x09, 0x04, 0x12, 0x04, 0xa8, 0x06, + 0x04, 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x18, 0x02, 0x09, 0x06, 0x12, 0x04, 0xa8, + 0x06, 0x0d, 0x18, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x18, 0x02, 0x09, 0x01, 0x12, 0x04, + 0xa8, 0x06, 0x19, 0x25, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x18, 0x02, 0x09, 0x03, 0x12, + 0x04, 0xa8, 0x06, 0x28, 0x2a, 0x0a, 0x0e, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x18, 0x02, 0x0a, 0x12, + 0x04, 0xa9, 0x06, 0x04, 0x33, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x18, 0x02, 0x0a, 0x04, + 0x12, 0x04, 0xa9, 0x06, 0x04, 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x18, 0x02, 0x0a, + 0x06, 0x12, 0x04, 0xa9, 0x06, 0x0d, 0x1c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x18, 0x02, + 0x0a, 0x01, 0x12, 0x04, 0xa9, 0x06, 0x1d, 0x2d, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x18, + 0x02, 0x0a, 0x03, 0x12, 0x04, 0xa9, 0x06, 0x30, 0x32, 0x0a, 0x3f, 0x0a, 0x04, 0x04, 0x00, 0x03, + 0x19, 0x12, 0x06, 0xae, 0x06, 0x02, 0xb3, 0x06, 0x03, 0x1a, 0x2f, 0x2f, 0x20, 0x4c, 0x6f, 0x61, + 0x64, 0x20, 0x61, 0x20, 0x70, 0x61, 0x72, 0x73, 0x65, 0x20, 0x61, 0x6e, 0x20, 0x41, 0x6e, 0x63, + 0x68, 0x6f, 0x72, 0x20, 0x62, 0x61, 0x73, 0x65, 0x64, 0x20, 0x73, 0x6f, 0x6c, 0x61, 0x6e, 0x61, + 0x20, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x2e, 0x0a, 0x0a, 0x0d, 0x0a, 0x05, 0x04, 0x00, + 0x03, 0x19, 0x01, 0x12, 0x04, 0xae, 0x06, 0x0a, 0x19, 0x0a, 0x3a, 0x0a, 0x06, 0x04, 0x00, 0x03, + 0x19, 0x02, 0x00, 0x12, 0x04, 0xb0, 0x06, 0x04, 0x23, 0x1a, 0x2a, 0x2f, 0x20, 0x4f, 0x77, 0x6e, + 0x69, 0x6e, 0x67, 0x20, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x20, 0x6f, 0x66, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x20, 0x74, 0x6f, 0x20, 0x70, 0x61, + 0x72, 0x73, 0x65, 0x2e, 0x0a, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x19, 0x02, 0x00, 0x04, + 0x12, 0x04, 0xb0, 0x06, 0x04, 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x19, 0x02, 0x00, + 0x05, 0x12, 0x04, 0xb0, 0x06, 0x0d, 0x13, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x19, 0x02, + 0x00, 0x01, 0x12, 0x04, 0xb0, 0x06, 0x14, 0x1e, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x19, + 0x02, 0x00, 0x03, 0x12, 0x04, 0xb0, 0x06, 0x21, 0x22, 0x0a, 0x28, 0x0a, 0x06, 0x04, 0x00, 0x03, + 0x19, 0x02, 0x01, 0x12, 0x04, 0xb2, 0x06, 0x04, 0x28, 0x1a, 0x18, 0x2f, 0x20, 0x54, 0x68, 0x65, + 0x20, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x20, 0x74, 0x6f, 0x20, 0x70, 0x61, 0x72, 0x73, + 0x65, 0x2e, 0x0a, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x19, 0x02, 0x01, 0x04, 0x12, 0x04, + 0xb2, 0x06, 0x04, 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x19, 0x02, 0x01, 0x05, 0x12, + 0x04, 0xb2, 0x06, 0x0d, 0x13, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x19, 0x02, 0x01, 0x01, + 0x12, 0x04, 0xb2, 0x06, 0x14, 0x23, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x19, 0x02, 0x01, + 0x03, 0x12, 0x04, 0xb2, 0x06, 0x26, 0x27, 0x0a, 0x4e, 0x0a, 0x04, 0x04, 0x00, 0x03, 0x1a, 0x12, + 0x06, 0xb7, 0x06, 0x02, 0xba, 0x06, 0x03, 0x1a, 0x3e, 0x2f, 0x20, 0x46, 0x65, 0x74, 0x63, 0x68, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x4a, 0x53, 0x4f, 0x4e, 0x20, 0x72, 0x65, 0x70, 0x72, 0x65, 0x73, + 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6f, 0x66, 0x20, 0x61, 0x6e, 0x20, 0x53, + 0x50, 0x4c, 0x20, 0x53, 0x74, 0x61, 0x6b, 0x65, 0x20, 0x50, 0x6f, 0x6f, 0x6c, 0x20, 0x61, 0x63, + 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x2e, 0x0a, 0x0a, 0x0d, 0x0a, 0x05, 0x04, 0x00, 0x03, 0x1a, 0x01, + 0x12, 0x04, 0xb7, 0x06, 0x0a, 0x1a, 0x0a, 0x34, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x1a, 0x02, 0x00, + 0x12, 0x04, 0xb9, 0x06, 0x04, 0x1f, 0x1a, 0x24, 0x2f, 0x20, 0x54, 0x68, 0x65, 0x20, 0x70, 0x75, + 0x62, 0x6b, 0x65, 0x79, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x53, 0x50, 0x4c, 0x20, + 0x53, 0x74, 0x61, 0x6b, 0x65, 0x20, 0x50, 0x6f, 0x6f, 0x6c, 0x2e, 0x0a, 0x0a, 0x0f, 0x0a, 0x07, + 0x04, 0x00, 0x03, 0x1a, 0x02, 0x00, 0x04, 0x12, 0x04, 0xb9, 0x06, 0x04, 0x0c, 0x0a, 0x0f, 0x0a, + 0x07, 0x04, 0x00, 0x03, 0x1a, 0x02, 0x00, 0x05, 0x12, 0x04, 0xb9, 0x06, 0x0d, 0x13, 0x0a, 0x0f, + 0x0a, 0x07, 0x04, 0x00, 0x03, 0x1a, 0x02, 0x00, 0x01, 0x12, 0x04, 0xb9, 0x06, 0x14, 0x1a, 0x0a, + 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x1a, 0x02, 0x00, 0x03, 0x12, 0x04, 0xb9, 0x06, 0x1d, 0x1e, + 0x0a, 0x46, 0x0a, 0x04, 0x04, 0x00, 0x03, 0x1b, 0x12, 0x06, 0xbd, 0x06, 0x02, 0xc4, 0x06, 0x03, + 0x1a, 0x36, 0x2f, 0x20, 0x46, 0x65, 0x74, 0x63, 0x68, 0x20, 0x74, 0x68, 0x65, 0x20, 0x4a, 0x53, + 0x4f, 0x4e, 0x20, 0x72, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x20, 0x6f, 0x66, 0x20, 0x61, 0x6e, 0x20, 0x53, 0x50, 0x4c, 0x20, 0x74, 0x6f, 0x6b, 0x65, + 0x6e, 0x20, 0x6d, 0x69, 0x6e, 0x74, 0x2e, 0x0a, 0x0a, 0x0d, 0x0a, 0x05, 0x04, 0x00, 0x03, 0x1b, + 0x01, 0x12, 0x04, 0xbd, 0x06, 0x0a, 0x1b, 0x0a, 0x10, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x1b, 0x08, + 0x00, 0x12, 0x06, 0xbe, 0x06, 0x04, 0xc3, 0x06, 0x05, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, + 0x1b, 0x08, 0x00, 0x01, 0x12, 0x04, 0xbe, 0x06, 0x0a, 0x18, 0x0a, 0x4e, 0x0a, 0x06, 0x04, 0x00, + 0x03, 0x1b, 0x02, 0x00, 0x12, 0x04, 0xc0, 0x06, 0x06, 0x27, 0x1a, 0x3e, 0x2f, 0x20, 0x54, 0x68, + 0x65, 0x20, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x20, 0x6f, 0x66, 0x20, 0x61, + 0x20, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x20, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x20, 0x74, + 0x6f, 0x20, 0x66, 0x65, 0x74, 0x63, 0x68, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6d, 0x69, 0x6e, 0x74, + 0x49, 0x6e, 0x66, 0x6f, 0x20, 0x66, 0x6f, 0x72, 0x2e, 0x0a, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, + 0x03, 0x1b, 0x02, 0x00, 0x05, 0x12, 0x04, 0xc0, 0x06, 0x06, 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, + 0x00, 0x03, 0x1b, 0x02, 0x00, 0x01, 0x12, 0x04, 0xc0, 0x06, 0x0d, 0x22, 0x0a, 0x0f, 0x0a, 0x07, + 0x04, 0x00, 0x03, 0x1b, 0x02, 0x00, 0x03, 0x12, 0x04, 0xc0, 0x06, 0x25, 0x26, 0x0a, 0x3b, 0x0a, + 0x06, 0x04, 0x00, 0x03, 0x1b, 0x02, 0x01, 0x12, 0x04, 0xc2, 0x06, 0x06, 0x1e, 0x1a, 0x2b, 0x2f, + 0x20, 0x54, 0x68, 0x65, 0x20, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x20, 0x6f, + 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x20, 0x6d, 0x69, 0x6e, 0x74, + 0x20, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x2e, 0x0a, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, + 0x03, 0x1b, 0x02, 0x01, 0x05, 0x12, 0x04, 0xc2, 0x06, 0x06, 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, + 0x00, 0x03, 0x1b, 0x02, 0x01, 0x01, 0x12, 0x04, 0xc2, 0x06, 0x0d, 0x19, 0x0a, 0x0f, 0x0a, 0x07, + 0x04, 0x00, 0x03, 0x1b, 0x02, 0x01, 0x03, 0x12, 0x04, 0xc2, 0x06, 0x1c, 0x1d, 0x0a, 0x35, 0x0a, + 0x04, 0x04, 0x00, 0x03, 0x1c, 0x12, 0x06, 0xc7, 0x06, 0x02, 0xdd, 0x06, 0x03, 0x1a, 0x25, 0x2f, + 0x20, 0x46, 0x65, 0x74, 0x63, 0x68, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x77, 0x61, 0x70, 0x20, + 0x70, 0x72, 0x69, 0x63, 0x65, 0x20, 0x66, 0x72, 0x6f, 0x6d, 0x20, 0x55, 0x6e, 0x69, 0x53, 0x77, + 0x61, 0x70, 0x2e, 0x0a, 0x0a, 0x0d, 0x0a, 0x05, 0x04, 0x00, 0x03, 0x1c, 0x01, 0x12, 0x04, 0xc7, + 0x06, 0x0a, 0x21, 0x0a, 0x10, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x1c, 0x04, 0x00, 0x12, 0x06, 0xc8, + 0x06, 0x04, 0xcd, 0x06, 0x05, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x1c, 0x04, 0x00, 0x01, + 0x12, 0x04, 0xc8, 0x06, 0x09, 0x10, 0x0a, 0x10, 0x0a, 0x08, 0x04, 0x00, 0x03, 0x1c, 0x04, 0x00, + 0x02, 0x00, 0x12, 0x04, 0xc9, 0x06, 0x06, 0x20, 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x1c, + 0x04, 0x00, 0x02, 0x00, 0x01, 0x12, 0x04, 0xc9, 0x06, 0x06, 0x1b, 0x0a, 0x11, 0x0a, 0x09, 0x04, + 0x00, 0x03, 0x1c, 0x04, 0x00, 0x02, 0x00, 0x02, 0x12, 0x04, 0xc9, 0x06, 0x1e, 0x1f, 0x0a, 0x10, + 0x0a, 0x08, 0x04, 0x00, 0x03, 0x1c, 0x04, 0x00, 0x02, 0x01, 0x12, 0x04, 0xca, 0x06, 0x06, 0x20, + 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x1c, 0x04, 0x00, 0x02, 0x01, 0x01, 0x12, 0x04, 0xca, + 0x06, 0x06, 0x1b, 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x1c, 0x04, 0x00, 0x02, 0x01, 0x02, + 0x12, 0x04, 0xca, 0x06, 0x1e, 0x1f, 0x0a, 0x10, 0x0a, 0x08, 0x04, 0x00, 0x03, 0x1c, 0x04, 0x00, + 0x02, 0x02, 0x12, 0x04, 0xcb, 0x06, 0x06, 0x15, 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x1c, + 0x04, 0x00, 0x02, 0x02, 0x01, 0x12, 0x04, 0xcb, 0x06, 0x06, 0x10, 0x0a, 0x11, 0x0a, 0x09, 0x04, + 0x00, 0x03, 0x1c, 0x04, 0x00, 0x02, 0x02, 0x02, 0x12, 0x04, 0xcb, 0x06, 0x13, 0x14, 0x0a, 0x10, + 0x0a, 0x08, 0x04, 0x00, 0x03, 0x1c, 0x04, 0x00, 0x02, 0x03, 0x12, 0x04, 0xcc, 0x06, 0x06, 0x15, + 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x1c, 0x04, 0x00, 0x02, 0x03, 0x01, 0x12, 0x04, 0xcc, + 0x06, 0x06, 0x10, 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x1c, 0x04, 0x00, 0x02, 0x03, 0x02, + 0x12, 0x04, 0xcc, 0x06, 0x13, 0x14, 0x0a, 0x2b, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x1c, 0x02, 0x00, + 0x12, 0x04, 0xcf, 0x06, 0x04, 0x29, 0x1a, 0x1b, 0x2f, 0x20, 0x54, 0x68, 0x65, 0x20, 0x69, 0x6e, + 0x70, 0x75, 0x74, 0x20, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x20, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, + 0x73, 0x2e, 0x0a, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x1c, 0x02, 0x00, 0x04, 0x12, 0x04, + 0xcf, 0x06, 0x04, 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x1c, 0x02, 0x00, 0x05, 0x12, + 0x04, 0xcf, 0x06, 0x0d, 0x13, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x1c, 0x02, 0x00, 0x01, + 0x12, 0x04, 0xcf, 0x06, 0x14, 0x24, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x1c, 0x02, 0x00, + 0x03, 0x12, 0x04, 0xcf, 0x06, 0x27, 0x28, 0x0a, 0x2c, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x1c, 0x02, + 0x01, 0x12, 0x04, 0xd1, 0x06, 0x04, 0x2a, 0x1a, 0x1c, 0x2f, 0x20, 0x54, 0x68, 0x65, 0x20, 0x6f, + 0x75, 0x74, 0x70, 0x75, 0x74, 0x20, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x20, 0x61, 0x64, 0x64, 0x72, + 0x65, 0x73, 0x73, 0x2e, 0x0a, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x1c, 0x02, 0x01, 0x04, + 0x12, 0x04, 0xd1, 0x06, 0x04, 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x1c, 0x02, 0x01, + 0x05, 0x12, 0x04, 0xd1, 0x06, 0x0d, 0x13, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x1c, 0x02, + 0x01, 0x01, 0x12, 0x04, 0xd1, 0x06, 0x14, 0x25, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x1c, + 0x02, 0x01, 0x03, 0x12, 0x04, 0xd1, 0x06, 0x28, 0x29, 0x0a, 0x30, 0x0a, 0x06, 0x04, 0x00, 0x03, + 0x1c, 0x02, 0x02, 0x12, 0x04, 0xd3, 0x06, 0x04, 0x28, 0x1a, 0x20, 0x2f, 0x20, 0x54, 0x68, 0x65, + 0x20, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x6f, 0x6b, 0x65, 0x6e, + 0x73, 0x20, 0x74, 0x6f, 0x20, 0x73, 0x77, 0x61, 0x70, 0x2e, 0x0a, 0x0a, 0x0f, 0x0a, 0x07, 0x04, + 0x00, 0x03, 0x1c, 0x02, 0x02, 0x04, 0x12, 0x04, 0xd3, 0x06, 0x04, 0x0c, 0x0a, 0x0f, 0x0a, 0x07, + 0x04, 0x00, 0x03, 0x1c, 0x02, 0x02, 0x05, 0x12, 0x04, 0xd3, 0x06, 0x0d, 0x13, 0x0a, 0x0f, 0x0a, + 0x07, 0x04, 0x00, 0x03, 0x1c, 0x02, 0x02, 0x01, 0x12, 0x04, 0xd3, 0x06, 0x14, 0x23, 0x0a, 0x0f, + 0x0a, 0x07, 0x04, 0x00, 0x03, 0x1c, 0x02, 0x02, 0x03, 0x12, 0x04, 0xd3, 0x06, 0x26, 0x27, 0x0a, + 0x42, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x1c, 0x02, 0x03, 0x12, 0x04, 0xd5, 0x06, 0x04, 0x21, 0x1a, + 0x32, 0x2f, 0x20, 0x54, 0x68, 0x65, 0x20, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x61, 0x62, 0x6c, 0x65, + 0x20, 0x73, 0x6c, 0x69, 0x70, 0x70, 0x61, 0x67, 0x65, 0x20, 0x69, 0x6e, 0x20, 0x70, 0x65, 0x72, + 0x63, 0x65, 0x6e, 0x74, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x77, 0x61, + 0x70, 0x2e, 0x0a, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x1c, 0x02, 0x03, 0x04, 0x12, 0x04, + 0xd5, 0x06, 0x04, 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x1c, 0x02, 0x03, 0x05, 0x12, + 0x04, 0xd5, 0x06, 0x0d, 0x13, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x1c, 0x02, 0x03, 0x01, + 0x12, 0x04, 0xd5, 0x06, 0x14, 0x1c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x1c, 0x02, 0x03, + 0x03, 0x12, 0x04, 0xd5, 0x06, 0x1f, 0x20, 0x0a, 0x38, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x1c, 0x02, + 0x04, 0x12, 0x04, 0xd7, 0x06, 0x04, 0x21, 0x1a, 0x28, 0x2f, 0x20, 0x54, 0x68, 0x65, 0x20, 0x52, + 0x50, 0x43, 0x20, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x20, 0x74, 0x6f, 0x20, 0x75, + 0x73, 0x65, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x77, 0x61, 0x70, 0x2e, + 0x0a, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x1c, 0x02, 0x04, 0x04, 0x12, 0x04, 0xd7, 0x06, + 0x04, 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x1c, 0x02, 0x04, 0x05, 0x12, 0x04, 0xd7, + 0x06, 0x0d, 0x13, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x1c, 0x02, 0x04, 0x01, 0x12, 0x04, + 0xd7, 0x06, 0x14, 0x1c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x1c, 0x02, 0x04, 0x03, 0x12, + 0x04, 0xd7, 0x06, 0x1f, 0x20, 0x0a, 0x3e, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x1c, 0x02, 0x05, 0x12, + 0x04, 0xd9, 0x06, 0x04, 0x21, 0x1a, 0x2e, 0x2f, 0x20, 0x54, 0x68, 0x65, 0x20, 0x76, 0x65, 0x72, + 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x55, 0x6e, 0x69, 0x73, + 0x77, 0x61, 0x70, 0x20, 0x65, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x20, 0x74, 0x6f, 0x20, + 0x75, 0x73, 0x65, 0x2e, 0x0a, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x1c, 0x02, 0x05, 0x04, + 0x12, 0x04, 0xd9, 0x06, 0x04, 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x1c, 0x02, 0x05, + 0x06, 0x12, 0x04, 0xd9, 0x06, 0x0d, 0x14, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x1c, 0x02, + 0x05, 0x01, 0x12, 0x04, 0xd9, 0x06, 0x15, 0x1c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x1c, + 0x02, 0x05, 0x03, 0x12, 0x04, 0xd9, 0x06, 0x1f, 0x20, 0x0a, 0x0e, 0x0a, 0x06, 0x04, 0x00, 0x03, + 0x1c, 0x02, 0x06, 0x12, 0x04, 0xda, 0x06, 0x04, 0x27, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, + 0x1c, 0x02, 0x06, 0x04, 0x12, 0x04, 0xda, 0x06, 0x04, 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, + 0x03, 0x1c, 0x02, 0x06, 0x05, 0x12, 0x04, 0xda, 0x06, 0x0d, 0x13, 0x0a, 0x0f, 0x0a, 0x07, 0x04, + 0x00, 0x03, 0x1c, 0x02, 0x06, 0x01, 0x12, 0x04, 0xda, 0x06, 0x14, 0x22, 0x0a, 0x0f, 0x0a, 0x07, + 0x04, 0x00, 0x03, 0x1c, 0x02, 0x06, 0x03, 0x12, 0x04, 0xda, 0x06, 0x25, 0x26, 0x0a, 0x0e, 0x0a, + 0x06, 0x04, 0x00, 0x03, 0x1c, 0x02, 0x07, 0x12, 0x04, 0xdb, 0x06, 0x04, 0x28, 0x0a, 0x0f, 0x0a, + 0x07, 0x04, 0x00, 0x03, 0x1c, 0x02, 0x07, 0x04, 0x12, 0x04, 0xdb, 0x06, 0x04, 0x0c, 0x0a, 0x0f, + 0x0a, 0x07, 0x04, 0x00, 0x03, 0x1c, 0x02, 0x07, 0x05, 0x12, 0x04, 0xdb, 0x06, 0x0d, 0x13, 0x0a, + 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x1c, 0x02, 0x07, 0x01, 0x12, 0x04, 0xdb, 0x06, 0x14, 0x23, + 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x1c, 0x02, 0x07, 0x03, 0x12, 0x04, 0xdb, 0x06, 0x26, + 0x27, 0x0a, 0x0e, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x1c, 0x02, 0x08, 0x12, 0x04, 0xdc, 0x06, 0x04, + 0x27, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x1c, 0x02, 0x08, 0x04, 0x12, 0x04, 0xdc, 0x06, + 0x04, 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x1c, 0x02, 0x08, 0x05, 0x12, 0x04, 0xdc, + 0x06, 0x0d, 0x13, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x1c, 0x02, 0x08, 0x01, 0x12, 0x04, + 0xdc, 0x06, 0x14, 0x22, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x1c, 0x02, 0x08, 0x03, 0x12, + 0x04, 0xdc, 0x06, 0x25, 0x26, 0x0a, 0x37, 0x0a, 0x04, 0x04, 0x00, 0x03, 0x1d, 0x12, 0x06, 0xe0, + 0x06, 0x02, 0xeb, 0x06, 0x03, 0x1a, 0x27, 0x2f, 0x20, 0x46, 0x65, 0x74, 0x63, 0x68, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x73, 0x77, 0x61, 0x70, 0x20, 0x70, 0x72, 0x69, 0x63, 0x65, 0x20, 0x66, 0x72, + 0x6f, 0x6d, 0x20, 0x53, 0x75, 0x73, 0x68, 0x69, 0x53, 0x77, 0x61, 0x70, 0x2e, 0x0a, 0x0a, 0x0d, + 0x0a, 0x05, 0x04, 0x00, 0x03, 0x1d, 0x01, 0x12, 0x04, 0xe0, 0x06, 0x0a, 0x23, 0x0a, 0x2b, 0x0a, + 0x06, 0x04, 0x00, 0x03, 0x1d, 0x02, 0x00, 0x12, 0x04, 0xe2, 0x06, 0x04, 0x29, 0x1a, 0x1b, 0x2f, + 0x20, 0x54, 0x68, 0x65, 0x20, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x20, 0x74, 0x6f, 0x6b, 0x65, 0x6e, + 0x20, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x2e, 0x0a, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, + 0x03, 0x1d, 0x02, 0x00, 0x04, 0x12, 0x04, 0xe2, 0x06, 0x04, 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, + 0x00, 0x03, 0x1d, 0x02, 0x00, 0x05, 0x12, 0x04, 0xe2, 0x06, 0x0d, 0x13, 0x0a, 0x0f, 0x0a, 0x07, + 0x04, 0x00, 0x03, 0x1d, 0x02, 0x00, 0x01, 0x12, 0x04, 0xe2, 0x06, 0x14, 0x24, 0x0a, 0x0f, 0x0a, + 0x07, 0x04, 0x00, 0x03, 0x1d, 0x02, 0x00, 0x03, 0x12, 0x04, 0xe2, 0x06, 0x27, 0x28, 0x0a, 0x2c, + 0x0a, 0x06, 0x04, 0x00, 0x03, 0x1d, 0x02, 0x01, 0x12, 0x04, 0xe4, 0x06, 0x04, 0x2a, 0x1a, 0x1c, + 0x2f, 0x20, 0x54, 0x68, 0x65, 0x20, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x20, 0x74, 0x6f, 0x6b, + 0x65, 0x6e, 0x20, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x2e, 0x0a, 0x0a, 0x0f, 0x0a, 0x07, + 0x04, 0x00, 0x03, 0x1d, 0x02, 0x01, 0x04, 0x12, 0x04, 0xe4, 0x06, 0x04, 0x0c, 0x0a, 0x0f, 0x0a, + 0x07, 0x04, 0x00, 0x03, 0x1d, 0x02, 0x01, 0x05, 0x12, 0x04, 0xe4, 0x06, 0x0d, 0x13, 0x0a, 0x0f, + 0x0a, 0x07, 0x04, 0x00, 0x03, 0x1d, 0x02, 0x01, 0x01, 0x12, 0x04, 0xe4, 0x06, 0x14, 0x25, 0x0a, + 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x1d, 0x02, 0x01, 0x03, 0x12, 0x04, 0xe4, 0x06, 0x28, 0x29, + 0x0a, 0x30, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x1d, 0x02, 0x02, 0x12, 0x04, 0xe6, 0x06, 0x04, 0x28, + 0x1a, 0x20, 0x2f, 0x20, 0x54, 0x68, 0x65, 0x20, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x20, 0x6f, + 0x66, 0x20, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x73, 0x77, 0x61, 0x70, + 0x2e, 0x0a, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x1d, 0x02, 0x02, 0x04, 0x12, 0x04, 0xe6, + 0x06, 0x04, 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x1d, 0x02, 0x02, 0x05, 0x12, 0x04, + 0xe6, 0x06, 0x0d, 0x13, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x1d, 0x02, 0x02, 0x01, 0x12, + 0x04, 0xe6, 0x06, 0x14, 0x23, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x1d, 0x02, 0x02, 0x03, + 0x12, 0x04, 0xe6, 0x06, 0x26, 0x27, 0x0a, 0x42, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x1d, 0x02, 0x03, + 0x12, 0x04, 0xe8, 0x06, 0x04, 0x21, 0x1a, 0x32, 0x2f, 0x20, 0x54, 0x68, 0x65, 0x20, 0x61, 0x6c, + 0x6c, 0x6f, 0x77, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x73, 0x6c, 0x69, 0x70, 0x70, 0x61, 0x67, 0x65, + 0x20, 0x69, 0x6e, 0x20, 0x70, 0x65, 0x72, 0x63, 0x65, 0x6e, 0x74, 0x20, 0x66, 0x6f, 0x72, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x73, 0x77, 0x61, 0x70, 0x2e, 0x0a, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, + 0x03, 0x1d, 0x02, 0x03, 0x04, 0x12, 0x04, 0xe8, 0x06, 0x04, 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, + 0x00, 0x03, 0x1d, 0x02, 0x03, 0x05, 0x12, 0x04, 0xe8, 0x06, 0x0d, 0x13, 0x0a, 0x0f, 0x0a, 0x07, + 0x04, 0x00, 0x03, 0x1d, 0x02, 0x03, 0x01, 0x12, 0x04, 0xe8, 0x06, 0x14, 0x1c, 0x0a, 0x0f, 0x0a, + 0x07, 0x04, 0x00, 0x03, 0x1d, 0x02, 0x03, 0x03, 0x12, 0x04, 0xe8, 0x06, 0x1f, 0x20, 0x0a, 0x38, + 0x0a, 0x06, 0x04, 0x00, 0x03, 0x1d, 0x02, 0x04, 0x12, 0x04, 0xea, 0x06, 0x04, 0x21, 0x1a, 0x28, + 0x2f, 0x20, 0x54, 0x68, 0x65, 0x20, 0x52, 0x50, 0x43, 0x20, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, + 0x65, 0x72, 0x20, 0x74, 0x6f, 0x20, 0x75, 0x73, 0x65, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x73, 0x77, 0x61, 0x70, 0x2e, 0x0a, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x1d, + 0x02, 0x04, 0x04, 0x12, 0x04, 0xea, 0x06, 0x04, 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, + 0x1d, 0x02, 0x04, 0x05, 0x12, 0x04, 0xea, 0x06, 0x0d, 0x13, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, + 0x03, 0x1d, 0x02, 0x04, 0x01, 0x12, 0x04, 0xea, 0x06, 0x14, 0x1c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, + 0x00, 0x03, 0x1d, 0x02, 0x04, 0x03, 0x12, 0x04, 0xea, 0x06, 0x1f, 0x20, 0x0a, 0x39, 0x0a, 0x04, + 0x04, 0x00, 0x03, 0x1e, 0x12, 0x06, 0xee, 0x06, 0x02, 0xf9, 0x06, 0x03, 0x1a, 0x29, 0x2f, 0x20, + 0x46, 0x65, 0x74, 0x63, 0x68, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x77, 0x61, 0x70, 0x20, 0x70, + 0x72, 0x69, 0x63, 0x65, 0x20, 0x66, 0x72, 0x6f, 0x6d, 0x20, 0x50, 0x61, 0x6e, 0x63, 0x61, 0x6b, + 0x65, 0x53, 0x77, 0x61, 0x70, 0x2e, 0x0a, 0x0a, 0x0d, 0x0a, 0x05, 0x04, 0x00, 0x03, 0x1e, 0x01, + 0x12, 0x04, 0xee, 0x06, 0x0a, 0x25, 0x0a, 0x2b, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x1e, 0x02, 0x00, + 0x12, 0x04, 0xf0, 0x06, 0x04, 0x29, 0x1a, 0x1b, 0x2f, 0x20, 0x54, 0x68, 0x65, 0x20, 0x69, 0x6e, + 0x70, 0x75, 0x74, 0x20, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x20, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, + 0x73, 0x2e, 0x0a, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x1e, 0x02, 0x00, 0x04, 0x12, 0x04, + 0xf0, 0x06, 0x04, 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x1e, 0x02, 0x00, 0x05, 0x12, + 0x04, 0xf0, 0x06, 0x0d, 0x13, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x1e, 0x02, 0x00, 0x01, + 0x12, 0x04, 0xf0, 0x06, 0x14, 0x24, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x1e, 0x02, 0x00, + 0x03, 0x12, 0x04, 0xf0, 0x06, 0x27, 0x28, 0x0a, 0x2c, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x1e, 0x02, + 0x01, 0x12, 0x04, 0xf2, 0x06, 0x04, 0x2a, 0x1a, 0x1c, 0x2f, 0x20, 0x54, 0x68, 0x65, 0x20, 0x6f, + 0x75, 0x74, 0x70, 0x75, 0x74, 0x20, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x20, 0x61, 0x64, 0x64, 0x72, + 0x65, 0x73, 0x73, 0x2e, 0x0a, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x1e, 0x02, 0x01, 0x04, + 0x12, 0x04, 0xf2, 0x06, 0x04, 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x1e, 0x02, 0x01, + 0x05, 0x12, 0x04, 0xf2, 0x06, 0x0d, 0x13, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x1e, 0x02, + 0x01, 0x01, 0x12, 0x04, 0xf2, 0x06, 0x14, 0x25, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x1e, + 0x02, 0x01, 0x03, 0x12, 0x04, 0xf2, 0x06, 0x28, 0x29, 0x0a, 0x30, 0x0a, 0x06, 0x04, 0x00, 0x03, + 0x1e, 0x02, 0x02, 0x12, 0x04, 0xf4, 0x06, 0x04, 0x28, 0x1a, 0x20, 0x2f, 0x20, 0x54, 0x68, 0x65, + 0x20, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x6f, 0x6b, 0x65, 0x6e, + 0x73, 0x20, 0x74, 0x6f, 0x20, 0x73, 0x77, 0x61, 0x70, 0x2e, 0x0a, 0x0a, 0x0f, 0x0a, 0x07, 0x04, + 0x00, 0x03, 0x1e, 0x02, 0x02, 0x04, 0x12, 0x04, 0xf4, 0x06, 0x04, 0x0c, 0x0a, 0x0f, 0x0a, 0x07, + 0x04, 0x00, 0x03, 0x1e, 0x02, 0x02, 0x05, 0x12, 0x04, 0xf4, 0x06, 0x0d, 0x13, 0x0a, 0x0f, 0x0a, + 0x07, 0x04, 0x00, 0x03, 0x1e, 0x02, 0x02, 0x01, 0x12, 0x04, 0xf4, 0x06, 0x14, 0x23, 0x0a, 0x0f, + 0x0a, 0x07, 0x04, 0x00, 0x03, 0x1e, 0x02, 0x02, 0x03, 0x12, 0x04, 0xf4, 0x06, 0x26, 0x27, 0x0a, + 0x42, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x1e, 0x02, 0x03, 0x12, 0x04, 0xf6, 0x06, 0x04, 0x21, 0x1a, + 0x32, 0x2f, 0x20, 0x54, 0x68, 0x65, 0x20, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x61, 0x62, 0x6c, 0x65, + 0x20, 0x73, 0x6c, 0x69, 0x70, 0x70, 0x61, 0x67, 0x65, 0x20, 0x69, 0x6e, 0x20, 0x70, 0x65, 0x72, + 0x63, 0x65, 0x6e, 0x74, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x77, 0x61, + 0x70, 0x2e, 0x0a, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x1e, 0x02, 0x03, 0x04, 0x12, 0x04, + 0xf6, 0x06, 0x04, 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x1e, 0x02, 0x03, 0x05, 0x12, + 0x04, 0xf6, 0x06, 0x0d, 0x13, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x1e, 0x02, 0x03, 0x01, + 0x12, 0x04, 0xf6, 0x06, 0x14, 0x1c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x1e, 0x02, 0x03, + 0x03, 0x12, 0x04, 0xf6, 0x06, 0x1f, 0x20, 0x0a, 0x38, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x1e, 0x02, + 0x04, 0x12, 0x04, 0xf8, 0x06, 0x04, 0x21, 0x1a, 0x28, 0x2f, 0x20, 0x54, 0x68, 0x65, 0x20, 0x52, + 0x50, 0x43, 0x20, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x20, 0x74, 0x6f, 0x20, 0x75, + 0x73, 0x65, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x77, 0x61, 0x70, 0x2e, + 0x0a, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x1e, 0x02, 0x04, 0x04, 0x12, 0x04, 0xf8, 0x06, + 0x04, 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x1e, 0x02, 0x04, 0x05, 0x12, 0x04, 0xf8, + 0x06, 0x0d, 0x13, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x1e, 0x02, 0x04, 0x01, 0x12, 0x04, + 0xf8, 0x06, 0x14, 0x1c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x1e, 0x02, 0x04, 0x03, 0x12, + 0x04, 0xf8, 0x06, 0x1f, 0x20, 0x0a, 0xb8, 0x02, 0x0a, 0x04, 0x04, 0x00, 0x03, 0x1f, 0x12, 0x06, + 0x89, 0x07, 0x02, 0x92, 0x07, 0x03, 0x1a, 0xa7, 0x02, 0x0a, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, + 0x65, 0x20, 0x61, 0x20, 0x6a, 0x6f, 0x62, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x73, 0x74, 0x6f, 0x72, + 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x20, 0x69, 0x6e, 0x20, + 0x61, 0x20, 0x76, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x74, 0x6f, 0x20, 0x72, 0x65, + 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x20, 0x6c, 0x61, 0x74, 0x65, 0x72, 0x2e, 0x0a, 0x0a, + 0x5f, 0x2a, 0x2a, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x2a, 0x2a, 0x5f, 0x3a, 0x20, 0x4e, 0x6f, 0x6e, + 0x65, 0x0a, 0x0a, 0x5f, 0x2a, 0x2a, 0x52, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x73, 0x2a, 0x2a, 0x5f, + 0x3a, 0x20, 0x54, 0x68, 0x65, 0x20, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x0a, 0x0a, 0x5f, 0x2a, 0x2a, + 0x45, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2a, 0x2a, 0x5f, 0x3a, 0x20, 0x43, 0x61, 0x63, 0x68, + 0x65, 0x54, 0x61, 0x73, 0x6b, 0x20, 0x73, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x20, 0x24, 0x7b, + 0x4f, 0x4e, 0x45, 0x7d, 0x20, 0x3d, 0x20, 0x31, 0x0a, 0x0a, 0x60, 0x60, 0x60, 0x6a, 0x73, 0x6f, + 0x6e, 0x0a, 0x7b, 0x20, 0x22, 0x63, 0x61, 0x63, 0x68, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x22, 0x3a, + 0x20, 0x7b, 0x20, 0x22, 0x63, 0x61, 0x63, 0x68, 0x65, 0x49, 0x74, 0x65, 0x6d, 0x73, 0x22, 0x3a, + 0x20, 0x5b, 0x20, 0x7b, 0x20, 0x22, 0x76, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x4e, 0x61, + 0x6d, 0x65, 0x22, 0x3a, 0x20, 0x22, 0x4f, 0x4e, 0x45, 0x22, 0x2c, 0x20, 0x22, 0x6a, 0x6f, 0x62, + 0x22, 0x3a, 0x20, 0x7b, 0x20, 0x22, 0x74, 0x61, 0x73, 0x6b, 0x73, 0x22, 0x3a, 0x20, 0x5b, 0x20, + 0x7b, 0x20, 0x22, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x22, 0x3a, 0x20, 0x7b, + 0x20, 0x22, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x3a, 0x20, 0x31, 0x20, 0x7d, 0x20, 0x7d, 0x20, + 0x5d, 0x20, 0x7d, 0x20, 0x7d, 0x20, 0x5d, 0x20, 0x7d, 0x20, 0x7d, 0x0a, 0x60, 0x60, 0x60, 0x0a, + 0x0a, 0x0d, 0x0a, 0x05, 0x04, 0x00, 0x03, 0x1f, 0x01, 0x12, 0x04, 0x89, 0x07, 0x0a, 0x13, 0x0a, + 0x10, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x1f, 0x03, 0x00, 0x12, 0x06, 0x8a, 0x07, 0x04, 0x8f, 0x07, + 0x05, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x1f, 0x03, 0x00, 0x01, 0x12, 0x04, 0x8a, 0x07, + 0x0c, 0x15, 0x0a, 0x6b, 0x0a, 0x08, 0x04, 0x00, 0x03, 0x1f, 0x03, 0x00, 0x02, 0x00, 0x12, 0x04, + 0x8c, 0x07, 0x06, 0x28, 0x1a, 0x59, 0x2f, 0x20, 0x54, 0x68, 0x65, 0x20, 0x6e, 0x61, 0x6d, 0x65, + 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x76, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, + 0x20, 0x74, 0x6f, 0x20, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x20, 0x69, 0x6e, 0x20, 0x63, 0x61, 0x63, + 0x68, 0x65, 0x20, 0x74, 0x6f, 0x20, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x20, + 0x6c, 0x61, 0x74, 0x65, 0x72, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x60, 0x24, 0x7b, 0x56, 0x41, + 0x52, 0x49, 0x41, 0x42, 0x4c, 0x45, 0x5f, 0x4e, 0x41, 0x4d, 0x45, 0x7d, 0x60, 0x2e, 0x0a, 0x0a, + 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x1f, 0x03, 0x00, 0x02, 0x00, 0x04, 0x12, 0x04, 0x8c, 0x07, + 0x06, 0x0e, 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x1f, 0x03, 0x00, 0x02, 0x00, 0x05, 0x12, + 0x04, 0x8c, 0x07, 0x0f, 0x15, 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x1f, 0x03, 0x00, 0x02, + 0x00, 0x01, 0x12, 0x04, 0x8c, 0x07, 0x16, 0x23, 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x1f, + 0x03, 0x00, 0x02, 0x00, 0x03, 0x12, 0x04, 0x8c, 0x07, 0x26, 0x27, 0x0a, 0x53, 0x0a, 0x08, 0x04, + 0x00, 0x03, 0x1f, 0x03, 0x00, 0x02, 0x01, 0x12, 0x04, 0x8e, 0x07, 0x06, 0x21, 0x1a, 0x41, 0x2f, + 0x20, 0x54, 0x68, 0x65, 0x20, 0x4f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x4a, 0x6f, 0x62, 0x20, 0x74, + 0x6f, 0x20, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x20, 0x74, 0x6f, 0x20, 0x79, 0x69, 0x65, + 0x6c, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x20, 0x74, 0x6f, 0x20, + 0x73, 0x74, 0x6f, 0x72, 0x65, 0x20, 0x69, 0x6e, 0x20, 0x63, 0x61, 0x63, 0x68, 0x65, 0x2e, 0x0a, + 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x1f, 0x03, 0x00, 0x02, 0x01, 0x04, 0x12, 0x04, 0x8e, + 0x07, 0x06, 0x0e, 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x1f, 0x03, 0x00, 0x02, 0x01, 0x06, + 0x12, 0x04, 0x8e, 0x07, 0x0f, 0x18, 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x1f, 0x03, 0x00, + 0x02, 0x01, 0x01, 0x12, 0x04, 0x8e, 0x07, 0x19, 0x1c, 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, + 0x1f, 0x03, 0x00, 0x02, 0x01, 0x03, 0x12, 0x04, 0x8e, 0x07, 0x1f, 0x20, 0x0a, 0x5e, 0x0a, 0x06, + 0x04, 0x00, 0x03, 0x1f, 0x02, 0x00, 0x12, 0x04, 0x91, 0x07, 0x04, 0x27, 0x1a, 0x4e, 0x2f, 0x20, + 0x41, 0x20, 0x6c, 0x69, 0x73, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x63, 0x61, 0x63, 0x68, 0x65, 0x64, + 0x20, 0x76, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x72, 0x65, + 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6a, + 0x6f, 0x62, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x60, 0x24, 0x7b, 0x56, 0x41, 0x52, 0x49, 0x41, + 0x42, 0x4c, 0x45, 0x5f, 0x4e, 0x41, 0x4d, 0x45, 0x7d, 0x60, 0x2e, 0x0a, 0x0a, 0x0f, 0x0a, 0x07, + 0x04, 0x00, 0x03, 0x1f, 0x02, 0x00, 0x04, 0x12, 0x04, 0x91, 0x07, 0x04, 0x0c, 0x0a, 0x0f, 0x0a, + 0x07, 0x04, 0x00, 0x03, 0x1f, 0x02, 0x00, 0x06, 0x12, 0x04, 0x91, 0x07, 0x0d, 0x16, 0x0a, 0x0f, + 0x0a, 0x07, 0x04, 0x00, 0x03, 0x1f, 0x02, 0x00, 0x01, 0x12, 0x04, 0x91, 0x07, 0x17, 0x22, 0x0a, + 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x1f, 0x02, 0x00, 0x03, 0x12, 0x04, 0x91, 0x07, 0x25, 0x26, + 0x0a, 0x74, 0x0a, 0x04, 0x04, 0x00, 0x03, 0x20, 0x12, 0x04, 0x95, 0x07, 0x02, 0x1f, 0x1a, 0x66, + 0x2f, 0x20, 0x52, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x64, 0x69, 0x66, + 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x20, 0x62, 0x65, 0x74, 0x77, 0x65, 0x65, 0x6e, 0x20, + 0x61, 0x6e, 0x20, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x27, 0x73, 0x20, 0x63, 0x6c, 0x6f, 0x63, + 0x6b, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, + 0x74, 0x20, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x20, 0x61, 0x74, 0x20, 0x60, + 0x53, 0x59, 0x53, 0x56, 0x41, 0x52, 0x5f, 0x43, 0x4c, 0x4f, 0x43, 0x4b, 0x5f, 0x50, 0x55, 0x42, + 0x4b, 0x45, 0x59, 0x60, 0x2e, 0x0a, 0x0a, 0x0d, 0x0a, 0x05, 0x04, 0x00, 0x03, 0x20, 0x01, 0x12, + 0x04, 0x95, 0x07, 0x0a, 0x1c, 0x0a, 0x0c, 0x0a, 0x04, 0x04, 0x00, 0x03, 0x21, 0x12, 0x04, 0x97, + 0x07, 0x02, 0x1e, 0x0a, 0x0d, 0x0a, 0x05, 0x04, 0x00, 0x03, 0x21, 0x01, 0x12, 0x04, 0x97, 0x07, + 0x0a, 0x1b, 0x0a, 0x49, 0x0a, 0x04, 0x04, 0x00, 0x03, 0x22, 0x12, 0x06, 0x9a, 0x07, 0x02, 0xa3, + 0x07, 0x03, 0x1a, 0x39, 0x2f, 0x20, 0x46, 0x65, 0x74, 0x63, 0x68, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x20, 0x64, 0x61, 0x74, 0x61, 0x20, 0x69, 0x6e, 0x20, + 0x61, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x69, 0x66, 0x69, 0x65, 0x64, 0x20, 0x62, 0x75, + 0x66, 0x66, 0x65, 0x72, 0x20, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x2e, 0x0a, 0x0a, 0x0d, 0x0a, + 0x05, 0x04, 0x00, 0x03, 0x22, 0x01, 0x12, 0x04, 0x9a, 0x07, 0x0a, 0x24, 0x0a, 0x10, 0x0a, 0x06, + 0x04, 0x00, 0x03, 0x22, 0x04, 0x00, 0x12, 0x06, 0x9b, 0x07, 0x04, 0x9f, 0x07, 0x05, 0x0a, 0x0f, + 0x0a, 0x07, 0x04, 0x00, 0x03, 0x22, 0x04, 0x00, 0x01, 0x12, 0x04, 0x9b, 0x07, 0x09, 0x10, 0x0a, + 0x10, 0x0a, 0x08, 0x04, 0x00, 0x03, 0x22, 0x04, 0x00, 0x02, 0x00, 0x12, 0x04, 0x9c, 0x07, 0x06, + 0x1a, 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x22, 0x04, 0x00, 0x02, 0x00, 0x01, 0x12, 0x04, + 0x9c, 0x07, 0x06, 0x15, 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x22, 0x04, 0x00, 0x02, 0x00, + 0x02, 0x12, 0x04, 0x9c, 0x07, 0x18, 0x19, 0x0a, 0x10, 0x0a, 0x08, 0x04, 0x00, 0x03, 0x22, 0x04, + 0x00, 0x02, 0x01, 0x12, 0x04, 0x9d, 0x07, 0x06, 0x1a, 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, + 0x22, 0x04, 0x00, 0x02, 0x01, 0x01, 0x12, 0x04, 0x9d, 0x07, 0x06, 0x15, 0x0a, 0x11, 0x0a, 0x09, + 0x04, 0x00, 0x03, 0x22, 0x04, 0x00, 0x02, 0x01, 0x02, 0x12, 0x04, 0x9d, 0x07, 0x18, 0x19, 0x0a, + 0x10, 0x0a, 0x08, 0x04, 0x00, 0x03, 0x22, 0x04, 0x00, 0x02, 0x02, 0x12, 0x04, 0x9e, 0x07, 0x06, + 0x19, 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x22, 0x04, 0x00, 0x02, 0x02, 0x01, 0x12, 0x04, + 0x9e, 0x07, 0x06, 0x14, 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x22, 0x04, 0x00, 0x02, 0x02, + 0x02, 0x12, 0x04, 0x9e, 0x07, 0x17, 0x18, 0x0a, 0x47, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x22, 0x02, + 0x00, 0x12, 0x04, 0xa1, 0x07, 0x04, 0x1f, 0x1a, 0x37, 0x2f, 0x20, 0x54, 0x68, 0x65, 0x20, 0x6f, + 0x6e, 0x2d, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x20, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x20, + 0x74, 0x6f, 0x20, 0x66, 0x65, 0x74, 0x63, 0x68, 0x20, 0x74, 0x68, 0x65, 0x20, 0x61, 0x63, 0x63, + 0x6f, 0x75, 0x6e, 0x74, 0x20, 0x64, 0x61, 0x74, 0x61, 0x20, 0x66, 0x72, 0x6f, 0x6d, 0x2e, 0x0a, + 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x22, 0x02, 0x00, 0x04, 0x12, 0x04, 0xa1, 0x07, 0x04, + 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x22, 0x02, 0x00, 0x05, 0x12, 0x04, 0xa1, 0x07, + 0x0d, 0x13, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x22, 0x02, 0x00, 0x01, 0x12, 0x04, 0xa1, + 0x07, 0x14, 0x1a, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x22, 0x02, 0x00, 0x03, 0x12, 0x04, + 0xa1, 0x07, 0x1d, 0x1e, 0x0a, 0x0e, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x22, 0x02, 0x01, 0x12, 0x04, + 0xa2, 0x07, 0x04, 0x21, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x22, 0x02, 0x01, 0x04, 0x12, + 0x04, 0xa2, 0x07, 0x04, 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x22, 0x02, 0x01, 0x06, + 0x12, 0x04, 0xa2, 0x07, 0x0d, 0x14, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x22, 0x02, 0x01, + 0x01, 0x12, 0x04, 0xa2, 0x07, 0x15, 0x1c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x22, 0x02, + 0x01, 0x03, 0x12, 0x04, 0xa2, 0x07, 0x1f, 0x20, 0x0a, 0xaf, 0x03, 0x0a, 0x04, 0x04, 0x00, 0x03, + 0x23, 0x12, 0x06, 0xb8, 0x07, 0x02, 0xc5, 0x07, 0x03, 0x1a, 0x9e, 0x03, 0x0a, 0x52, 0x65, 0x74, + 0x75, 0x72, 0x6e, 0x20, 0x61, 0x20, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x20, + 0x66, 0x72, 0x6f, 0x6d, 0x20, 0x61, 0x20, 0x63, 0x72, 0x6f, 0x6e, 0x74, 0x61, 0x62, 0x20, 0x69, + 0x6e, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x0a, 0x0a, 0x5f, 0x2a, 0x2a, + 0x49, 0x6e, 0x70, 0x75, 0x74, 0x2a, 0x2a, 0x5f, 0x3a, 0x20, 0x4e, 0x6f, 0x6e, 0x65, 0x0a, 0x0a, + 0x5f, 0x2a, 0x2a, 0x52, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x73, 0x2a, 0x2a, 0x5f, 0x3a, 0x20, 0x41, + 0x20, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x0a, 0x0a, 0x5f, 0x2a, 0x2a, 0x45, + 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2a, 0x2a, 0x5f, 0x3a, 0x20, 0x52, 0x65, 0x74, 0x75, 0x72, + 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x75, 0x6e, 0x69, 0x78, 0x20, 0x74, 0x69, 0x6d, 0x65, 0x73, + 0x74, 0x61, 0x6d, 0x70, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6f, 0x6e, 0x2d, + 0x63, 0x68, 0x61, 0x69, 0x6e, 0x20, 0x53, 0x59, 0x53, 0x43, 0x4c, 0x4f, 0x43, 0x4b, 0x0a, 0x0a, + 0x60, 0x60, 0x60, 0x6a, 0x73, 0x6f, 0x6e, 0x0a, 0x7b, 0x22, 0x63, 0x72, 0x6f, 0x6e, 0x50, 0x61, + 0x72, 0x73, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x22, 0x3a, 0x7b, 0x22, 0x63, 0x72, 0x6f, 0x6e, 0x50, + 0x61, 0x74, 0x74, 0x65, 0x72, 0x6e, 0x22, 0x3a, 0x22, 0x2a, 0x20, 0x2a, 0x20, 0x2a, 0x20, 0x2a, + 0x20, 0x2a, 0x20, 0x2a, 0x22, 0x2c, 0x22, 0x63, 0x6c, 0x6f, 0x63, 0x6b, 0x4f, 0x66, 0x66, 0x73, + 0x65, 0x74, 0x22, 0x3a, 0x30, 0x2c, 0x22, 0x63, 0x6c, 0x6f, 0x63, 0x6b, 0x22, 0x3a, 0x22, 0x53, + 0x59, 0x53, 0x43, 0x4c, 0x4f, 0x43, 0x4b, 0x22, 0x7d, 0x7d, 0x0a, 0x60, 0x60, 0x60, 0x0a, 0x0a, + 0x5f, 0x2a, 0x2a, 0x45, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2a, 0x2a, 0x5f, 0x3a, 0x20, 0x52, + 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x75, 0x6e, 0x69, 0x78, 0x20, 0x74, + 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x6e, 0x65, 0x78, + 0x74, 0x20, 0x66, 0x72, 0x69, 0x64, 0x61, 0x79, 0x20, 0x61, 0x74, 0x20, 0x35, 0x70, 0x6d, 0x20, + 0x55, 0x54, 0x43, 0x0a, 0x0a, 0x60, 0x60, 0x60, 0x6a, 0x73, 0x6f, 0x6e, 0x0a, 0x7b, 0x22, 0x63, + 0x72, 0x6f, 0x6e, 0x50, 0x61, 0x72, 0x73, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x22, 0x3a, 0x7b, 0x22, + 0x63, 0x72, 0x6f, 0x6e, 0x50, 0x61, 0x74, 0x74, 0x65, 0x72, 0x6e, 0x22, 0x3a, 0x22, 0x30, 0x20, + 0x31, 0x37, 0x20, 0x2a, 0x20, 0x2a, 0x20, 0x35, 0x22, 0x2c, 0x22, 0x63, 0x6c, 0x6f, 0x63, 0x6b, + 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x22, 0x3a, 0x30, 0x2c, 0x22, 0x63, 0x6c, 0x6f, 0x63, 0x6b, + 0x22, 0x3a, 0x30, 0x7d, 0x7d, 0x0a, 0x60, 0x60, 0x60, 0x0a, 0x0a, 0x0d, 0x0a, 0x05, 0x04, 0x00, + 0x03, 0x23, 0x01, 0x12, 0x04, 0xb8, 0x07, 0x0a, 0x17, 0x0a, 0x2d, 0x0a, 0x06, 0x04, 0x00, 0x03, + 0x23, 0x02, 0x00, 0x12, 0x04, 0xba, 0x07, 0x04, 0x25, 0x1a, 0x1d, 0x2f, 0x20, 0x54, 0x68, 0x65, + 0x20, 0x63, 0x72, 0x6f, 0x6e, 0x20, 0x70, 0x61, 0x74, 0x74, 0x65, 0x72, 0x6e, 0x20, 0x74, 0x6f, + 0x20, 0x70, 0x61, 0x72, 0x73, 0x65, 0x2e, 0x0a, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x23, + 0x02, 0x00, 0x04, 0x12, 0x04, 0xba, 0x07, 0x04, 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, + 0x23, 0x02, 0x00, 0x05, 0x12, 0x04, 0xba, 0x07, 0x0d, 0x13, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, + 0x03, 0x23, 0x02, 0x00, 0x01, 0x12, 0x04, 0xba, 0x07, 0x14, 0x20, 0x0a, 0x0f, 0x0a, 0x07, 0x04, + 0x00, 0x03, 0x23, 0x02, 0x00, 0x03, 0x12, 0x04, 0xba, 0x07, 0x23, 0x24, 0x0a, 0x42, 0x0a, 0x06, + 0x04, 0x00, 0x03, 0x23, 0x02, 0x01, 0x12, 0x04, 0xbc, 0x07, 0x04, 0x24, 0x1a, 0x32, 0x2f, 0x20, + 0x54, 0x68, 0x65, 0x20, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x20, 0x6f, 0x66, + 0x66, 0x73, 0x65, 0x74, 0x20, 0x74, 0x6f, 0x20, 0x63, 0x61, 0x6c, 0x63, 0x75, 0x6c, 0x61, 0x74, + 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6e, 0x65, 0x78, 0x74, 0x20, 0x72, 0x75, 0x6e, 0x2e, 0x0a, + 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x23, 0x02, 0x01, 0x04, 0x12, 0x04, 0xbc, 0x07, 0x04, + 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x23, 0x02, 0x01, 0x05, 0x12, 0x04, 0xbc, 0x07, + 0x0d, 0x12, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x23, 0x02, 0x01, 0x01, 0x12, 0x04, 0xbc, + 0x07, 0x13, 0x1f, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x23, 0x02, 0x01, 0x03, 0x12, 0x04, + 0xbc, 0x07, 0x22, 0x23, 0x0a, 0x10, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x23, 0x04, 0x00, 0x12, 0x06, + 0xbd, 0x07, 0x04, 0xc2, 0x07, 0x05, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x23, 0x04, 0x00, + 0x01, 0x12, 0x04, 0xbd, 0x07, 0x09, 0x12, 0x0a, 0x4b, 0x0a, 0x08, 0x04, 0x00, 0x03, 0x23, 0x04, + 0x00, 0x02, 0x00, 0x12, 0x04, 0xbf, 0x07, 0x06, 0x11, 0x1a, 0x39, 0x2f, 0x20, 0x55, 0x73, 0x65, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x54, 0x61, 0x73, 0x6b, 0x52, 0x75, 0x6e, 0x6e, 0x65, 0x72, 0x73, + 0x20, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x20, 0x63, 0x6c, 0x6f, 0x63, 0x6b, 0x20, 0x66, 0x6f, + 0x72, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x20, 0x74, 0x69, + 0x6d, 0x65, 0x2e, 0x0a, 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x23, 0x04, 0x00, 0x02, 0x00, + 0x01, 0x12, 0x04, 0xbf, 0x07, 0x06, 0x0c, 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x23, 0x04, + 0x00, 0x02, 0x00, 0x02, 0x12, 0x04, 0xbf, 0x07, 0x0f, 0x10, 0x0a, 0x44, 0x0a, 0x08, 0x04, 0x00, + 0x03, 0x23, 0x04, 0x00, 0x02, 0x01, 0x12, 0x04, 0xc1, 0x07, 0x06, 0x13, 0x1a, 0x32, 0x2f, 0x20, + 0x55, 0x73, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6f, 0x6e, 0x2d, 0x63, 0x68, 0x61, 0x69, 0x6e, + 0x20, 0x53, 0x59, 0x53, 0x43, 0x4c, 0x4f, 0x43, 0x4b, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x20, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x0a, + 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x23, 0x04, 0x00, 0x02, 0x01, 0x01, 0x12, 0x04, 0xc1, + 0x07, 0x06, 0x0e, 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x23, 0x04, 0x00, 0x02, 0x01, 0x02, + 0x12, 0x04, 0xc1, 0x07, 0x11, 0x12, 0x0a, 0x47, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x23, 0x02, 0x02, + 0x12, 0x04, 0xc4, 0x07, 0x04, 0x21, 0x1a, 0x37, 0x2f, 0x20, 0x55, 0x73, 0x65, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x54, 0x61, 0x73, 0x6b, 0x52, 0x75, 0x6e, 0x6e, 0x65, 0x72, 0x27, 0x73, 0x20, 0x63, + 0x6c, 0x6f, 0x63, 0x6b, 0x20, 0x6f, 0x72, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6f, 0x6e, 0x2d, 0x63, + 0x68, 0x61, 0x69, 0x6e, 0x20, 0x53, 0x59, 0x53, 0x43, 0x4c, 0x4f, 0x43, 0x4b, 0x2e, 0x0a, 0x0a, + 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x23, 0x02, 0x02, 0x04, 0x12, 0x04, 0xc4, 0x07, 0x04, 0x0c, + 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x23, 0x02, 0x02, 0x06, 0x12, 0x04, 0xc4, 0x07, 0x0d, + 0x16, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x23, 0x02, 0x02, 0x01, 0x12, 0x04, 0xc4, 0x07, + 0x17, 0x1c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x23, 0x02, 0x02, 0x03, 0x12, 0x04, 0xc4, + 0x07, 0x1f, 0x20, 0x0a, 0x4b, 0x0a, 0x04, 0x04, 0x00, 0x03, 0x24, 0x12, 0x06, 0xc8, 0x07, 0x02, + 0xf3, 0x07, 0x03, 0x1a, 0x3b, 0x2f, 0x20, 0x52, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x64, 0x65, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x20, 0x76, + 0x61, 0x6c, 0x75, 0x65, 0x20, 0x66, 0x72, 0x6f, 0x6d, 0x20, 0x61, 0x20, 0x73, 0x74, 0x72, 0x69, + 0x6e, 0x67, 0x69, 0x66, 0x69, 0x65, 0x64, 0x20, 0x62, 0x75, 0x66, 0x66, 0x65, 0x72, 0x2e, 0x0a, + 0x0a, 0x0d, 0x0a, 0x05, 0x04, 0x00, 0x03, 0x24, 0x01, 0x12, 0x04, 0xc8, 0x07, 0x0a, 0x1f, 0x0a, + 0x41, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x24, 0x02, 0x00, 0x12, 0x04, 0xca, 0x07, 0x04, 0x1f, 0x1a, + 0x31, 0x2f, 0x20, 0x54, 0x68, 0x65, 0x20, 0x62, 0x75, 0x66, 0x66, 0x65, 0x72, 0x20, 0x6f, 0x66, + 0x66, 0x73, 0x65, 0x74, 0x20, 0x74, 0x6f, 0x20, 0x73, 0x74, 0x61, 0x72, 0x74, 0x20, 0x64, 0x65, + 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x69, 0x6e, 0x67, 0x20, 0x66, 0x72, 0x6f, 0x6d, + 0x2e, 0x0a, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x24, 0x02, 0x00, 0x04, 0x12, 0x04, 0xca, + 0x07, 0x04, 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x24, 0x02, 0x00, 0x05, 0x12, 0x04, + 0xca, 0x07, 0x0d, 0x13, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x24, 0x02, 0x00, 0x01, 0x12, + 0x04, 0xca, 0x07, 0x14, 0x1a, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x24, 0x02, 0x00, 0x03, + 0x12, 0x04, 0xca, 0x07, 0x1d, 0x1e, 0x0a, 0x10, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x24, 0x04, 0x00, + 0x12, 0x06, 0xcb, 0x07, 0x04, 0xd0, 0x07, 0x05, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x24, + 0x04, 0x00, 0x01, 0x12, 0x04, 0xcb, 0x07, 0x09, 0x0f, 0x0a, 0x31, 0x0a, 0x08, 0x04, 0x00, 0x03, + 0x24, 0x04, 0x00, 0x02, 0x00, 0x12, 0x04, 0xcd, 0x07, 0x06, 0x18, 0x1a, 0x1f, 0x20, 0x55, 0x73, + 0x65, 0x20, 0x6c, 0x69, 0x74, 0x74, 0x6c, 0x65, 0x20, 0x65, 0x6e, 0x64, 0x69, 0x61, 0x6e, 0x20, + 0x62, 0x79, 0x74, 0x65, 0x20, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x2e, 0x0a, 0x0a, 0x11, 0x0a, 0x09, + 0x04, 0x00, 0x03, 0x24, 0x04, 0x00, 0x02, 0x00, 0x01, 0x12, 0x04, 0xcd, 0x07, 0x06, 0x13, 0x0a, + 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x24, 0x04, 0x00, 0x02, 0x00, 0x02, 0x12, 0x04, 0xcd, 0x07, + 0x16, 0x17, 0x0a, 0x2e, 0x0a, 0x08, 0x04, 0x00, 0x03, 0x24, 0x04, 0x00, 0x02, 0x01, 0x12, 0x04, + 0xcf, 0x07, 0x06, 0x15, 0x1a, 0x1c, 0x20, 0x55, 0x73, 0x65, 0x20, 0x62, 0x69, 0x67, 0x20, 0x65, + 0x6e, 0x64, 0x69, 0x61, 0x6e, 0x20, 0x62, 0x79, 0x74, 0x65, 0x20, 0x6f, 0x72, 0x64, 0x65, 0x72, + 0x2e, 0x0a, 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x24, 0x04, 0x00, 0x02, 0x01, 0x01, 0x12, + 0x04, 0xcf, 0x07, 0x06, 0x10, 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x24, 0x04, 0x00, 0x02, + 0x01, 0x02, 0x12, 0x04, 0xcf, 0x07, 0x13, 0x14, 0x0a, 0x36, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x24, + 0x02, 0x01, 0x12, 0x04, 0xd2, 0x07, 0x04, 0x1f, 0x1a, 0x26, 0x2f, 0x20, 0x54, 0x68, 0x65, 0x20, + 0x65, 0x6e, 0x64, 0x69, 0x61, 0x6e, 0x6e, 0x65, 0x73, 0x73, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x64, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x2e, 0x0a, + 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x24, 0x02, 0x01, 0x04, 0x12, 0x04, 0xd2, 0x07, 0x04, + 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x24, 0x02, 0x01, 0x06, 0x12, 0x04, 0xd2, 0x07, + 0x0d, 0x13, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x24, 0x02, 0x01, 0x01, 0x12, 0x04, 0xd2, + 0x07, 0x14, 0x1a, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x24, 0x02, 0x01, 0x03, 0x12, 0x04, + 0xd2, 0x07, 0x1d, 0x1e, 0x0a, 0x10, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x24, 0x04, 0x01, 0x12, 0x06, + 0xd3, 0x07, 0x04, 0xf0, 0x07, 0x05, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x24, 0x04, 0x01, + 0x01, 0x12, 0x04, 0xd3, 0x07, 0x09, 0x18, 0x0a, 0x22, 0x0a, 0x08, 0x04, 0x00, 0x03, 0x24, 0x04, + 0x01, 0x02, 0x00, 0x12, 0x04, 0xd5, 0x07, 0x06, 0x11, 0x1a, 0x10, 0x2f, 0x20, 0x41, 0x20, 0x70, + 0x75, 0x62, 0x6c, 0x69, 0x63, 0x20, 0x6b, 0x65, 0x79, 0x2e, 0x0a, 0x0a, 0x11, 0x0a, 0x09, 0x04, + 0x00, 0x03, 0x24, 0x04, 0x01, 0x02, 0x00, 0x01, 0x12, 0x04, 0xd5, 0x07, 0x06, 0x0c, 0x0a, 0x11, + 0x0a, 0x09, 0x04, 0x00, 0x03, 0x24, 0x04, 0x01, 0x02, 0x00, 0x02, 0x12, 0x04, 0xd5, 0x07, 0x0f, + 0x10, 0x0a, 0x1f, 0x0a, 0x08, 0x04, 0x00, 0x03, 0x24, 0x04, 0x01, 0x02, 0x01, 0x12, 0x04, 0xd7, + 0x07, 0x06, 0x0f, 0x1a, 0x0d, 0x2f, 0x20, 0x41, 0x20, 0x62, 0x6f, 0x6f, 0x6c, 0x65, 0x61, 0x6e, + 0x2e, 0x0a, 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x24, 0x04, 0x01, 0x02, 0x01, 0x01, 0x12, + 0x04, 0xd7, 0x07, 0x06, 0x0a, 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x24, 0x04, 0x01, 0x02, + 0x01, 0x02, 0x12, 0x04, 0xd7, 0x07, 0x0d, 0x0e, 0x0a, 0x2d, 0x0a, 0x08, 0x04, 0x00, 0x03, 0x24, + 0x04, 0x01, 0x02, 0x02, 0x12, 0x04, 0xd9, 0x07, 0x06, 0x0d, 0x1a, 0x1b, 0x2f, 0x20, 0x41, 0x6e, + 0x20, 0x38, 0x2d, 0x62, 0x69, 0x74, 0x20, 0x75, 0x6e, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x20, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x2e, 0x0a, 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x24, 0x04, + 0x01, 0x02, 0x02, 0x01, 0x12, 0x04, 0xd9, 0x07, 0x06, 0x08, 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, + 0x03, 0x24, 0x04, 0x01, 0x02, 0x02, 0x02, 0x12, 0x04, 0xd9, 0x07, 0x0b, 0x0c, 0x0a, 0x2b, 0x0a, + 0x08, 0x04, 0x00, 0x03, 0x24, 0x04, 0x01, 0x02, 0x03, 0x12, 0x04, 0xdb, 0x07, 0x06, 0x0d, 0x1a, + 0x19, 0x2f, 0x20, 0x41, 0x6e, 0x20, 0x38, 0x2d, 0x62, 0x69, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6e, + 0x65, 0x64, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x2e, 0x0a, 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, + 0x03, 0x24, 0x04, 0x01, 0x02, 0x03, 0x01, 0x12, 0x04, 0xdb, 0x07, 0x06, 0x08, 0x0a, 0x11, 0x0a, + 0x09, 0x04, 0x00, 0x03, 0x24, 0x04, 0x01, 0x02, 0x03, 0x02, 0x12, 0x04, 0xdb, 0x07, 0x0b, 0x0c, + 0x0a, 0x2d, 0x0a, 0x08, 0x04, 0x00, 0x03, 0x24, 0x04, 0x01, 0x02, 0x04, 0x12, 0x04, 0xdd, 0x07, + 0x06, 0x0e, 0x1a, 0x1b, 0x2f, 0x20, 0x41, 0x20, 0x31, 0x36, 0x2d, 0x62, 0x69, 0x74, 0x20, 0x75, + 0x6e, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x2e, 0x0a, 0x0a, + 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x24, 0x04, 0x01, 0x02, 0x04, 0x01, 0x12, 0x04, 0xdd, 0x07, + 0x06, 0x09, 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x24, 0x04, 0x01, 0x02, 0x04, 0x02, 0x12, + 0x04, 0xdd, 0x07, 0x0c, 0x0d, 0x0a, 0x2b, 0x0a, 0x08, 0x04, 0x00, 0x03, 0x24, 0x04, 0x01, 0x02, + 0x05, 0x12, 0x04, 0xdf, 0x07, 0x06, 0x0e, 0x1a, 0x19, 0x2f, 0x20, 0x41, 0x20, 0x31, 0x36, 0x2d, + 0x62, 0x69, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, + 0x2e, 0x0a, 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x24, 0x04, 0x01, 0x02, 0x05, 0x01, 0x12, + 0x04, 0xdf, 0x07, 0x06, 0x09, 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x24, 0x04, 0x01, 0x02, + 0x05, 0x02, 0x12, 0x04, 0xdf, 0x07, 0x0c, 0x0d, 0x0a, 0x2d, 0x0a, 0x08, 0x04, 0x00, 0x03, 0x24, + 0x04, 0x01, 0x02, 0x06, 0x12, 0x04, 0xe1, 0x07, 0x06, 0x0e, 0x1a, 0x1b, 0x2f, 0x20, 0x41, 0x20, + 0x33, 0x32, 0x2d, 0x62, 0x69, 0x74, 0x20, 0x75, 0x6e, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x20, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x2e, 0x0a, 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x24, 0x04, + 0x01, 0x02, 0x06, 0x01, 0x12, 0x04, 0xe1, 0x07, 0x06, 0x09, 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, + 0x03, 0x24, 0x04, 0x01, 0x02, 0x06, 0x02, 0x12, 0x04, 0xe1, 0x07, 0x0c, 0x0d, 0x0a, 0x2b, 0x0a, + 0x08, 0x04, 0x00, 0x03, 0x24, 0x04, 0x01, 0x02, 0x07, 0x12, 0x04, 0xe3, 0x07, 0x06, 0x0e, 0x1a, + 0x19, 0x2f, 0x20, 0x41, 0x20, 0x33, 0x32, 0x2d, 0x62, 0x69, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6e, + 0x65, 0x64, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x2e, 0x0a, 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, + 0x03, 0x24, 0x04, 0x01, 0x02, 0x07, 0x01, 0x12, 0x04, 0xe3, 0x07, 0x06, 0x09, 0x0a, 0x11, 0x0a, + 0x09, 0x04, 0x00, 0x03, 0x24, 0x04, 0x01, 0x02, 0x07, 0x02, 0x12, 0x04, 0xe3, 0x07, 0x0c, 0x0d, + 0x0a, 0x38, 0x0a, 0x08, 0x04, 0x00, 0x03, 0x24, 0x04, 0x01, 0x02, 0x08, 0x12, 0x04, 0xe5, 0x07, + 0x06, 0x0e, 0x1a, 0x26, 0x2f, 0x20, 0x41, 0x20, 0x33, 0x32, 0x2d, 0x62, 0x69, 0x74, 0x20, 0x49, + 0x45, 0x45, 0x45, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x20, 0x70, 0x6f, 0x69, + 0x6e, 0x74, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x2e, 0x0a, 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, + 0x03, 0x24, 0x04, 0x01, 0x02, 0x08, 0x01, 0x12, 0x04, 0xe5, 0x07, 0x06, 0x09, 0x0a, 0x11, 0x0a, + 0x09, 0x04, 0x00, 0x03, 0x24, 0x04, 0x01, 0x02, 0x08, 0x02, 0x12, 0x04, 0xe5, 0x07, 0x0c, 0x0d, + 0x0a, 0x2d, 0x0a, 0x08, 0x04, 0x00, 0x03, 0x24, 0x04, 0x01, 0x02, 0x09, 0x12, 0x04, 0xe7, 0x07, + 0x06, 0x0f, 0x1a, 0x1b, 0x2f, 0x20, 0x41, 0x20, 0x36, 0x34, 0x2d, 0x62, 0x69, 0x74, 0x20, 0x75, + 0x6e, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x2e, 0x0a, 0x0a, + 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x24, 0x04, 0x01, 0x02, 0x09, 0x01, 0x12, 0x04, 0xe7, 0x07, + 0x06, 0x09, 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x24, 0x04, 0x01, 0x02, 0x09, 0x02, 0x12, + 0x04, 0xe7, 0x07, 0x0c, 0x0e, 0x0a, 0x2b, 0x0a, 0x08, 0x04, 0x00, 0x03, 0x24, 0x04, 0x01, 0x02, + 0x0a, 0x12, 0x04, 0xe9, 0x07, 0x06, 0x0f, 0x1a, 0x19, 0x2f, 0x20, 0x41, 0x20, 0x36, 0x34, 0x2d, + 0x62, 0x69, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, + 0x2e, 0x0a, 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x24, 0x04, 0x01, 0x02, 0x0a, 0x01, 0x12, + 0x04, 0xe9, 0x07, 0x06, 0x09, 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x24, 0x04, 0x01, 0x02, + 0x0a, 0x02, 0x12, 0x04, 0xe9, 0x07, 0x0c, 0x0e, 0x0a, 0x38, 0x0a, 0x08, 0x04, 0x00, 0x03, 0x24, + 0x04, 0x01, 0x02, 0x0b, 0x12, 0x04, 0xeb, 0x07, 0x06, 0x0f, 0x1a, 0x26, 0x2f, 0x20, 0x41, 0x20, + 0x36, 0x34, 0x2d, 0x62, 0x69, 0x74, 0x20, 0x49, 0x45, 0x45, 0x45, 0x20, 0x66, 0x6c, 0x6f, 0x61, + 0x74, 0x69, 0x6e, 0x67, 0x20, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, + 0x2e, 0x0a, 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x24, 0x04, 0x01, 0x02, 0x0b, 0x01, 0x12, + 0x04, 0xeb, 0x07, 0x06, 0x09, 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x24, 0x04, 0x01, 0x02, + 0x0b, 0x02, 0x12, 0x04, 0xeb, 0x07, 0x0c, 0x0e, 0x0a, 0x2e, 0x0a, 0x08, 0x04, 0x00, 0x03, 0x24, + 0x04, 0x01, 0x02, 0x0c, 0x12, 0x04, 0xed, 0x07, 0x06, 0x10, 0x1a, 0x1c, 0x2f, 0x20, 0x41, 0x20, + 0x31, 0x32, 0x38, 0x2d, 0x62, 0x69, 0x74, 0x20, 0x75, 0x6e, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, + 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x2e, 0x0a, 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x24, + 0x04, 0x01, 0x02, 0x0c, 0x01, 0x12, 0x04, 0xed, 0x07, 0x06, 0x0a, 0x0a, 0x11, 0x0a, 0x09, 0x04, + 0x00, 0x03, 0x24, 0x04, 0x01, 0x02, 0x0c, 0x02, 0x12, 0x04, 0xed, 0x07, 0x0d, 0x0f, 0x0a, 0x2c, + 0x0a, 0x08, 0x04, 0x00, 0x03, 0x24, 0x04, 0x01, 0x02, 0x0d, 0x12, 0x04, 0xef, 0x07, 0x06, 0x10, + 0x1a, 0x1a, 0x2f, 0x20, 0x41, 0x20, 0x31, 0x32, 0x38, 0x2d, 0x62, 0x69, 0x74, 0x20, 0x73, 0x69, + 0x67, 0x6e, 0x65, 0x64, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x2e, 0x0a, 0x0a, 0x11, 0x0a, 0x09, + 0x04, 0x00, 0x03, 0x24, 0x04, 0x01, 0x02, 0x0d, 0x01, 0x12, 0x04, 0xef, 0x07, 0x06, 0x0a, 0x0a, + 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x24, 0x04, 0x01, 0x02, 0x0d, 0x02, 0x12, 0x04, 0xef, 0x07, + 0x0d, 0x0f, 0x0a, 0x34, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x24, 0x02, 0x02, 0x12, 0x04, 0xf2, 0x07, + 0x04, 0x26, 0x1a, 0x24, 0x2f, 0x20, 0x54, 0x68, 0x65, 0x20, 0x74, 0x79, 0x70, 0x65, 0x20, 0x6f, + 0x66, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x20, 0x74, 0x6f, 0x20, 0x64, 0x65, 0x73, 0x65, 0x72, + 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x2e, 0x0a, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x24, + 0x02, 0x02, 0x04, 0x12, 0x04, 0xf2, 0x07, 0x04, 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, + 0x24, 0x02, 0x02, 0x06, 0x12, 0x04, 0xf2, 0x07, 0x0d, 0x1c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, + 0x03, 0x24, 0x02, 0x02, 0x01, 0x12, 0x04, 0xf2, 0x07, 0x1d, 0x21, 0x0a, 0x0f, 0x0a, 0x07, 0x04, + 0x00, 0x03, 0x24, 0x02, 0x02, 0x03, 0x12, 0x04, 0xf2, 0x07, 0x24, 0x25, 0x0a, 0x0e, 0x0a, 0x04, + 0x04, 0x00, 0x03, 0x25, 0x12, 0x06, 0xf5, 0x07, 0x02, 0xfe, 0x07, 0x03, 0x0a, 0x0d, 0x0a, 0x05, + 0x04, 0x00, 0x03, 0x25, 0x01, 0x12, 0x04, 0xf5, 0x07, 0x0a, 0x1d, 0x0a, 0x10, 0x0a, 0x06, 0x04, + 0x00, 0x03, 0x25, 0x04, 0x00, 0x12, 0x06, 0xf6, 0x07, 0x04, 0xfa, 0x07, 0x05, 0x0a, 0x0f, 0x0a, + 0x07, 0x04, 0x00, 0x03, 0x25, 0x04, 0x00, 0x01, 0x12, 0x04, 0xf6, 0x07, 0x09, 0x0f, 0x0a, 0x10, + 0x0a, 0x08, 0x04, 0x00, 0x03, 0x25, 0x04, 0x00, 0x02, 0x00, 0x12, 0x04, 0xf8, 0x07, 0x06, 0x15, + 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x25, 0x04, 0x00, 0x02, 0x00, 0x01, 0x12, 0x04, 0xf8, + 0x07, 0x06, 0x10, 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x25, 0x04, 0x00, 0x02, 0x00, 0x02, + 0x12, 0x04, 0xf8, 0x07, 0x13, 0x14, 0x0a, 0x10, 0x0a, 0x08, 0x04, 0x00, 0x03, 0x25, 0x04, 0x00, + 0x02, 0x01, 0x12, 0x04, 0xf9, 0x07, 0x06, 0x15, 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x25, + 0x04, 0x00, 0x02, 0x01, 0x01, 0x12, 0x04, 0xf9, 0x07, 0x06, 0x10, 0x0a, 0x11, 0x0a, 0x09, 0x04, + 0x00, 0x03, 0x25, 0x04, 0x00, 0x02, 0x01, 0x02, 0x12, 0x04, 0xf9, 0x07, 0x13, 0x14, 0x0a, 0x0e, + 0x0a, 0x06, 0x04, 0x00, 0x03, 0x25, 0x02, 0x00, 0x12, 0x04, 0xfb, 0x07, 0x04, 0x1f, 0x0a, 0x0f, + 0x0a, 0x07, 0x04, 0x00, 0x03, 0x25, 0x02, 0x00, 0x04, 0x12, 0x04, 0xfb, 0x07, 0x04, 0x0c, 0x0a, + 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x25, 0x02, 0x00, 0x06, 0x12, 0x04, 0xfb, 0x07, 0x0d, 0x13, + 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x25, 0x02, 0x00, 0x01, 0x12, 0x04, 0xfb, 0x07, 0x14, + 0x1a, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x25, 0x02, 0x00, 0x03, 0x12, 0x04, 0xfb, 0x07, + 0x1d, 0x1e, 0x0a, 0x0e, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x25, 0x02, 0x01, 0x12, 0x04, 0xfc, 0x07, + 0x04, 0x2b, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x25, 0x02, 0x01, 0x04, 0x12, 0x04, 0xfc, + 0x07, 0x04, 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x25, 0x02, 0x01, 0x05, 0x12, 0x04, + 0xfc, 0x07, 0x0d, 0x13, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x25, 0x02, 0x01, 0x01, 0x12, + 0x04, 0xfc, 0x07, 0x14, 0x26, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x25, 0x02, 0x01, 0x03, + 0x12, 0x04, 0xfc, 0x07, 0x29, 0x2a, 0x0a, 0x0e, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x25, 0x02, 0x02, + 0x12, 0x04, 0xfd, 0x07, 0x04, 0x1f, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x25, 0x02, 0x02, + 0x04, 0x12, 0x04, 0xfd, 0x07, 0x04, 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x25, 0x02, + 0x02, 0x05, 0x12, 0x04, 0xfd, 0x07, 0x0d, 0x13, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x25, + 0x02, 0x02, 0x01, 0x12, 0x04, 0xfd, 0x07, 0x14, 0x1a, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, + 0x25, 0x02, 0x02, 0x03, 0x12, 0x04, 0xfd, 0x07, 0x1d, 0x1e, 0x0a, 0x0e, 0x0a, 0x04, 0x04, 0x00, + 0x03, 0x26, 0x12, 0x06, 0x80, 0x08, 0x02, 0x84, 0x08, 0x03, 0x0a, 0x0d, 0x0a, 0x05, 0x04, 0x00, + 0x03, 0x26, 0x01, 0x12, 0x04, 0x80, 0x08, 0x0a, 0x12, 0x0a, 0x0e, 0x0a, 0x06, 0x04, 0x00, 0x03, + 0x26, 0x02, 0x00, 0x12, 0x04, 0x81, 0x08, 0x04, 0x31, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, + 0x26, 0x02, 0x00, 0x04, 0x12, 0x04, 0x81, 0x08, 0x04, 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, + 0x03, 0x26, 0x02, 0x00, 0x05, 0x12, 0x04, 0x81, 0x08, 0x0d, 0x13, 0x0a, 0x0f, 0x0a, 0x07, 0x04, + 0x00, 0x03, 0x26, 0x02, 0x00, 0x01, 0x12, 0x04, 0x81, 0x08, 0x14, 0x2c, 0x0a, 0x0f, 0x0a, 0x07, + 0x04, 0x00, 0x03, 0x26, 0x02, 0x00, 0x03, 0x12, 0x04, 0x81, 0x08, 0x2f, 0x30, 0x0a, 0x0e, 0x0a, + 0x06, 0x04, 0x00, 0x03, 0x26, 0x02, 0x01, 0x12, 0x04, 0x82, 0x08, 0x04, 0x32, 0x0a, 0x0f, 0x0a, + 0x07, 0x04, 0x00, 0x03, 0x26, 0x02, 0x01, 0x04, 0x12, 0x04, 0x82, 0x08, 0x04, 0x0c, 0x0a, 0x0f, + 0x0a, 0x07, 0x04, 0x00, 0x03, 0x26, 0x02, 0x01, 0x05, 0x12, 0x04, 0x82, 0x08, 0x0d, 0x13, 0x0a, + 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x26, 0x02, 0x01, 0x01, 0x12, 0x04, 0x82, 0x08, 0x14, 0x2d, + 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x26, 0x02, 0x01, 0x03, 0x12, 0x04, 0x82, 0x08, 0x30, + 0x31, 0x0a, 0x0e, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x26, 0x02, 0x02, 0x12, 0x04, 0x83, 0x08, 0x04, + 0x1f, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x26, 0x02, 0x02, 0x04, 0x12, 0x04, 0x83, 0x08, + 0x04, 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x26, 0x02, 0x02, 0x05, 0x12, 0x04, 0x83, + 0x08, 0x0d, 0x13, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x26, 0x02, 0x02, 0x01, 0x12, 0x04, + 0x83, 0x08, 0x14, 0x1a, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x26, 0x02, 0x02, 0x03, 0x12, + 0x04, 0x83, 0x08, 0x1d, 0x1e, 0x0a, 0x0e, 0x0a, 0x04, 0x04, 0x00, 0x03, 0x27, 0x12, 0x06, 0x86, + 0x08, 0x02, 0x8a, 0x08, 0x03, 0x0a, 0x0d, 0x0a, 0x05, 0x04, 0x00, 0x03, 0x27, 0x01, 0x12, 0x04, + 0x86, 0x08, 0x0a, 0x12, 0x0a, 0x0e, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x27, 0x02, 0x00, 0x12, 0x04, + 0x87, 0x08, 0x04, 0x2b, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x27, 0x02, 0x00, 0x04, 0x12, + 0x04, 0x87, 0x08, 0x04, 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x27, 0x02, 0x00, 0x05, + 0x12, 0x04, 0x87, 0x08, 0x0d, 0x13, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x27, 0x02, 0x00, + 0x01, 0x12, 0x04, 0x87, 0x08, 0x14, 0x26, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x27, 0x02, + 0x00, 0x03, 0x12, 0x04, 0x87, 0x08, 0x29, 0x2a, 0x0a, 0x0e, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x27, + 0x02, 0x01, 0x12, 0x04, 0x88, 0x08, 0x04, 0x1e, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x27, + 0x02, 0x01, 0x04, 0x12, 0x04, 0x88, 0x08, 0x04, 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, + 0x27, 0x02, 0x01, 0x05, 0x12, 0x04, 0x88, 0x08, 0x0d, 0x12, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, + 0x03, 0x27, 0x02, 0x01, 0x01, 0x12, 0x04, 0x88, 0x08, 0x13, 0x19, 0x0a, 0x0f, 0x0a, 0x07, 0x04, + 0x00, 0x03, 0x27, 0x02, 0x01, 0x03, 0x12, 0x04, 0x88, 0x08, 0x1c, 0x1d, 0x0a, 0x0e, 0x0a, 0x06, + 0x04, 0x00, 0x03, 0x27, 0x02, 0x02, 0x12, 0x04, 0x89, 0x08, 0x04, 0x1f, 0x0a, 0x0f, 0x0a, 0x07, + 0x04, 0x00, 0x03, 0x27, 0x02, 0x02, 0x04, 0x12, 0x04, 0x89, 0x08, 0x04, 0x0c, 0x0a, 0x0f, 0x0a, + 0x07, 0x04, 0x00, 0x03, 0x27, 0x02, 0x02, 0x05, 0x12, 0x04, 0x89, 0x08, 0x0d, 0x13, 0x0a, 0x0f, + 0x0a, 0x07, 0x04, 0x00, 0x03, 0x27, 0x02, 0x02, 0x01, 0x12, 0x04, 0x89, 0x08, 0x14, 0x1a, 0x0a, + 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x27, 0x02, 0x02, 0x03, 0x12, 0x04, 0x89, 0x08, 0x1d, 0x1e, + 0x0a, 0x0e, 0x0a, 0x04, 0x04, 0x00, 0x03, 0x28, 0x12, 0x06, 0x8c, 0x08, 0x02, 0xaf, 0x08, 0x03, + 0x0a, 0x0d, 0x0a, 0x05, 0x04, 0x00, 0x03, 0x28, 0x01, 0x12, 0x04, 0x8c, 0x08, 0x0a, 0x18, 0x0a, + 0x10, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x28, 0x04, 0x00, 0x12, 0x06, 0x8d, 0x08, 0x04, 0x94, 0x08, + 0x05, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x28, 0x04, 0x00, 0x01, 0x12, 0x04, 0x8d, 0x08, + 0x09, 0x12, 0x0a, 0x35, 0x0a, 0x08, 0x04, 0x00, 0x03, 0x28, 0x04, 0x00, 0x02, 0x00, 0x12, 0x04, + 0x8f, 0x08, 0x06, 0x17, 0x1a, 0x23, 0x2f, 0x20, 0x55, 0x73, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x65, 0x71, 0x75, 0x61, 0x6c, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x27, 0x3d, 0x3d, 0x27, 0x20, 0x6f, + 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x2e, 0x0a, 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, + 0x28, 0x04, 0x00, 0x02, 0x00, 0x01, 0x12, 0x04, 0x8f, 0x08, 0x06, 0x12, 0x0a, 0x11, 0x0a, 0x09, + 0x04, 0x00, 0x03, 0x28, 0x04, 0x00, 0x02, 0x00, 0x02, 0x12, 0x04, 0x8f, 0x08, 0x15, 0x16, 0x0a, + 0x37, 0x0a, 0x08, 0x04, 0x00, 0x03, 0x28, 0x04, 0x00, 0x02, 0x01, 0x12, 0x04, 0x91, 0x08, 0x06, + 0x17, 0x1a, 0x25, 0x2f, 0x20, 0x55, 0x73, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x67, 0x72, 0x65, + 0x61, 0x74, 0x65, 0x72, 0x20, 0x74, 0x68, 0x61, 0x6e, 0x20, 0x27, 0x3e, 0x27, 0x20, 0x6f, 0x70, + 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x2e, 0x0a, 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x28, + 0x04, 0x00, 0x02, 0x01, 0x01, 0x12, 0x04, 0x91, 0x08, 0x06, 0x12, 0x0a, 0x11, 0x0a, 0x09, 0x04, + 0x00, 0x03, 0x28, 0x04, 0x00, 0x02, 0x01, 0x02, 0x12, 0x04, 0x91, 0x08, 0x15, 0x16, 0x0a, 0x34, + 0x0a, 0x08, 0x04, 0x00, 0x03, 0x28, 0x04, 0x00, 0x02, 0x02, 0x12, 0x04, 0x93, 0x08, 0x06, 0x17, + 0x1a, 0x22, 0x2f, 0x20, 0x55, 0x73, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6c, 0x65, 0x73, 0x73, + 0x20, 0x74, 0x68, 0x61, 0x6e, 0x20, 0x27, 0x3c, 0x27, 0x20, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, + 0x6f, 0x72, 0x2e, 0x0a, 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x28, 0x04, 0x00, 0x02, 0x02, + 0x01, 0x12, 0x04, 0x93, 0x08, 0x06, 0x12, 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x28, 0x04, + 0x00, 0x02, 0x02, 0x02, 0x12, 0x04, 0x93, 0x08, 0x15, 0x16, 0x0a, 0x59, 0x0a, 0x06, 0x04, 0x00, + 0x03, 0x28, 0x02, 0x00, 0x12, 0x04, 0x96, 0x08, 0x04, 0x1e, 0x1a, 0x49, 0x2f, 0x20, 0x54, 0x68, + 0x65, 0x20, 0x74, 0x79, 0x70, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, + 0x6f, 0x72, 0x20, 0x74, 0x6f, 0x20, 0x75, 0x73, 0x65, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x6c, 0x65, 0x66, 0x74, 0x20, 0x28, 0x6c, 0x68, 0x73, 0x29, 0x20, 0x61, 0x6e, 0x64, 0x20, + 0x72, 0x69, 0x67, 0x68, 0x74, 0x20, 0x28, 0x72, 0x68, 0x73, 0x29, 0x20, 0x6f, 0x70, 0x65, 0x72, + 0x61, 0x6e, 0x64, 0x2e, 0x0a, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x28, 0x02, 0x00, 0x04, + 0x12, 0x04, 0x96, 0x08, 0x04, 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x28, 0x02, 0x00, + 0x06, 0x12, 0x04, 0x96, 0x08, 0x0d, 0x16, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x28, 0x02, + 0x00, 0x01, 0x12, 0x04, 0x96, 0x08, 0x17, 0x19, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x28, + 0x02, 0x00, 0x03, 0x12, 0x04, 0x96, 0x08, 0x1c, 0x1d, 0x0a, 0x10, 0x0a, 0x06, 0x04, 0x00, 0x03, + 0x28, 0x08, 0x00, 0x12, 0x06, 0x97, 0x08, 0x04, 0x9c, 0x08, 0x05, 0x0a, 0x0f, 0x0a, 0x07, 0x04, + 0x00, 0x03, 0x28, 0x08, 0x00, 0x01, 0x12, 0x04, 0x97, 0x08, 0x0a, 0x0d, 0x0a, 0x5e, 0x0a, 0x06, + 0x04, 0x00, 0x03, 0x28, 0x02, 0x01, 0x12, 0x04, 0x99, 0x08, 0x06, 0x18, 0x1a, 0x4e, 0x2f, 0x20, + 0x4f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x4a, 0x6f, 0x62, 0x20, 0x77, 0x68, 0x65, 0x72, 0x65, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x64, 0x20, 0x72, 0x65, 0x73, + 0x75, 0x6c, 0x74, 0x20, 0x69, 0x73, 0x20, 0x65, 0x71, 0x75, 0x61, 0x6c, 0x20, 0x74, 0x6f, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x6c, 0x65, 0x66, 0x74, 0x20, 0x68, 0x61, 0x6e, 0x64, 0x20, 0x73, 0x69, + 0x64, 0x65, 0x20, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x6e, 0x64, 0x2e, 0x0a, 0x0a, 0x0f, 0x0a, 0x07, + 0x04, 0x00, 0x03, 0x28, 0x02, 0x01, 0x06, 0x12, 0x04, 0x99, 0x08, 0x06, 0x0f, 0x0a, 0x0f, 0x0a, + 0x07, 0x04, 0x00, 0x03, 0x28, 0x02, 0x01, 0x01, 0x12, 0x04, 0x99, 0x08, 0x10, 0x13, 0x0a, 0x0f, + 0x0a, 0x07, 0x04, 0x00, 0x03, 0x28, 0x02, 0x01, 0x03, 0x12, 0x04, 0x99, 0x08, 0x16, 0x17, 0x0a, + 0x54, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x28, 0x02, 0x02, 0x12, 0x04, 0x9b, 0x08, 0x06, 0x1b, 0x1a, + 0x44, 0x2f, 0x20, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x20, 0x6f, 0x72, 0x20, 0x60, 0x24, 0x7b, + 0x43, 0x41, 0x43, 0x48, 0x45, 0x5f, 0x4b, 0x45, 0x59, 0x7d, 0x60, 0x20, 0x72, 0x65, 0x70, 0x72, + 0x65, 0x73, 0x65, 0x6e, 0x74, 0x69, 0x6e, 0x67, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6c, 0x65, 0x66, + 0x74, 0x20, 0x68, 0x61, 0x6e, 0x64, 0x20, 0x73, 0x69, 0x64, 0x65, 0x20, 0x6f, 0x70, 0x65, 0x72, + 0x61, 0x6e, 0x64, 0x2e, 0x0a, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x28, 0x02, 0x02, 0x05, + 0x12, 0x04, 0x9b, 0x08, 0x06, 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x28, 0x02, 0x02, + 0x01, 0x12, 0x04, 0x9b, 0x08, 0x0d, 0x16, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x28, 0x02, + 0x02, 0x03, 0x12, 0x04, 0x9b, 0x08, 0x19, 0x1a, 0x0a, 0x10, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x28, + 0x08, 0x01, 0x12, 0x06, 0x9d, 0x08, 0x04, 0xa2, 0x08, 0x05, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, + 0x03, 0x28, 0x08, 0x01, 0x01, 0x12, 0x04, 0x9d, 0x08, 0x0a, 0x0d, 0x0a, 0x5f, 0x0a, 0x06, 0x04, + 0x00, 0x03, 0x28, 0x02, 0x03, 0x12, 0x04, 0x9f, 0x08, 0x06, 0x18, 0x1a, 0x4f, 0x2f, 0x20, 0x4f, + 0x72, 0x61, 0x63, 0x6c, 0x65, 0x4a, 0x6f, 0x62, 0x20, 0x77, 0x68, 0x65, 0x72, 0x65, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x64, 0x20, 0x72, 0x65, 0x73, 0x75, + 0x6c, 0x74, 0x20, 0x69, 0x73, 0x20, 0x65, 0x71, 0x75, 0x61, 0x6c, 0x20, 0x74, 0x6f, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x72, 0x69, 0x67, 0x68, 0x74, 0x20, 0x68, 0x61, 0x6e, 0x64, 0x20, 0x73, 0x69, + 0x64, 0x65, 0x20, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x6e, 0x64, 0x2e, 0x0a, 0x0a, 0x0f, 0x0a, 0x07, + 0x04, 0x00, 0x03, 0x28, 0x02, 0x03, 0x06, 0x12, 0x04, 0x9f, 0x08, 0x06, 0x0f, 0x0a, 0x0f, 0x0a, + 0x07, 0x04, 0x00, 0x03, 0x28, 0x02, 0x03, 0x01, 0x12, 0x04, 0x9f, 0x08, 0x10, 0x13, 0x0a, 0x0f, + 0x0a, 0x07, 0x04, 0x00, 0x03, 0x28, 0x02, 0x03, 0x03, 0x12, 0x04, 0x9f, 0x08, 0x16, 0x17, 0x0a, + 0x55, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x28, 0x02, 0x04, 0x12, 0x04, 0xa1, 0x08, 0x06, 0x1b, 0x1a, + 0x45, 0x2f, 0x20, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x20, 0x6f, 0x72, 0x20, 0x60, 0x24, 0x7b, + 0x43, 0x41, 0x43, 0x48, 0x45, 0x5f, 0x4b, 0x45, 0x59, 0x7d, 0x60, 0x20, 0x72, 0x65, 0x70, 0x72, + 0x65, 0x73, 0x65, 0x6e, 0x74, 0x69, 0x6e, 0x67, 0x20, 0x74, 0x68, 0x65, 0x20, 0x72, 0x69, 0x67, + 0x68, 0x74, 0x20, 0x68, 0x61, 0x6e, 0x64, 0x20, 0x73, 0x69, 0x64, 0x65, 0x20, 0x6f, 0x70, 0x65, + 0x72, 0x61, 0x6e, 0x64, 0x2e, 0x0a, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x28, 0x02, 0x04, + 0x05, 0x12, 0x04, 0xa1, 0x08, 0x06, 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x28, 0x02, + 0x04, 0x01, 0x12, 0x04, 0xa1, 0x08, 0x0d, 0x16, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x28, + 0x02, 0x04, 0x03, 0x12, 0x04, 0xa1, 0x08, 0x19, 0x1a, 0x0a, 0x4f, 0x0a, 0x06, 0x04, 0x00, 0x03, + 0x28, 0x02, 0x05, 0x12, 0x04, 0xa4, 0x08, 0x04, 0x23, 0x1a, 0x3f, 0x2f, 0x20, 0x54, 0x68, 0x65, + 0x20, 0x4f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x4a, 0x6f, 0x62, 0x20, 0x74, 0x6f, 0x20, 0x65, 0x78, + 0x65, 0x63, 0x75, 0x74, 0x65, 0x20, 0x69, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6f, 0x6e, + 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x65, 0x76, 0x61, 0x6c, 0x75, 0x61, 0x74, 0x65, 0x73, + 0x20, 0x74, 0x6f, 0x20, 0x74, 0x72, 0x75, 0x65, 0x2e, 0x0a, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, + 0x03, 0x28, 0x02, 0x05, 0x04, 0x12, 0x04, 0xa4, 0x08, 0x04, 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, + 0x00, 0x03, 0x28, 0x02, 0x05, 0x06, 0x12, 0x04, 0xa4, 0x08, 0x0d, 0x16, 0x0a, 0x0f, 0x0a, 0x07, + 0x04, 0x00, 0x03, 0x28, 0x02, 0x05, 0x01, 0x12, 0x04, 0xa4, 0x08, 0x17, 0x1e, 0x0a, 0x0f, 0x0a, + 0x07, 0x04, 0x00, 0x03, 0x28, 0x02, 0x05, 0x03, 0x12, 0x04, 0xa4, 0x08, 0x21, 0x22, 0x0a, 0x68, + 0x0a, 0x06, 0x04, 0x00, 0x03, 0x28, 0x02, 0x06, 0x12, 0x04, 0xa6, 0x08, 0x04, 0x26, 0x1a, 0x58, + 0x2f, 0x20, 0x54, 0x68, 0x65, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x20, 0x74, 0x6f, 0x20, + 0x75, 0x73, 0x65, 0x20, 0x69, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6f, 0x6e, 0x64, 0x69, + 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x65, 0x76, 0x61, 0x6c, 0x75, 0x61, 0x74, 0x65, 0x73, 0x20, 0x74, + 0x6f, 0x20, 0x74, 0x72, 0x75, 0x65, 0x2e, 0x20, 0x43, 0x61, 0x6e, 0x20, 0x62, 0x65, 0x20, 0x73, + 0x65, 0x74, 0x20, 0x74, 0x6f, 0x20, 0x61, 0x20, 0x60, 0x24, 0x7b, 0x43, 0x41, 0x43, 0x48, 0x45, + 0x5f, 0x4b, 0x45, 0x59, 0x7d, 0x60, 0x2e, 0x0a, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x28, + 0x02, 0x06, 0x04, 0x12, 0x04, 0xa6, 0x08, 0x04, 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, + 0x28, 0x02, 0x06, 0x05, 0x12, 0x04, 0xa6, 0x08, 0x0d, 0x13, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, + 0x03, 0x28, 0x02, 0x06, 0x01, 0x12, 0x04, 0xa6, 0x08, 0x14, 0x21, 0x0a, 0x0f, 0x0a, 0x07, 0x04, + 0x00, 0x03, 0x28, 0x02, 0x06, 0x03, 0x12, 0x04, 0xa6, 0x08, 0x24, 0x25, 0x0a, 0x50, 0x0a, 0x06, + 0x04, 0x00, 0x03, 0x28, 0x02, 0x07, 0x12, 0x04, 0xa8, 0x08, 0x04, 0x24, 0x1a, 0x40, 0x2f, 0x20, + 0x54, 0x68, 0x65, 0x20, 0x4f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x4a, 0x6f, 0x62, 0x20, 0x74, 0x6f, + 0x20, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x20, 0x69, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x65, 0x76, 0x61, 0x6c, 0x75, 0x61, + 0x74, 0x65, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x2e, 0x0a, 0x0a, 0x0f, + 0x0a, 0x07, 0x04, 0x00, 0x03, 0x28, 0x02, 0x07, 0x04, 0x12, 0x04, 0xa8, 0x08, 0x04, 0x0c, 0x0a, + 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x28, 0x02, 0x07, 0x06, 0x12, 0x04, 0xa8, 0x08, 0x0d, 0x16, + 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x28, 0x02, 0x07, 0x01, 0x12, 0x04, 0xa8, 0x08, 0x17, + 0x1f, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x28, 0x02, 0x07, 0x03, 0x12, 0x04, 0xa8, 0x08, + 0x22, 0x23, 0x0a, 0x69, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x28, 0x02, 0x08, 0x12, 0x04, 0xaa, 0x08, + 0x04, 0x27, 0x1a, 0x59, 0x2f, 0x20, 0x54, 0x68, 0x65, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, + 0x20, 0x74, 0x6f, 0x20, 0x75, 0x73, 0x65, 0x20, 0x69, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, + 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x65, 0x76, 0x61, 0x6c, 0x75, 0x61, 0x74, + 0x65, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x2e, 0x20, 0x43, 0x61, 0x6e, + 0x20, 0x62, 0x65, 0x20, 0x73, 0x65, 0x74, 0x20, 0x74, 0x6f, 0x20, 0x61, 0x20, 0x60, 0x24, 0x7b, + 0x43, 0x41, 0x43, 0x48, 0x45, 0x5f, 0x4b, 0x45, 0x59, 0x7d, 0x60, 0x2e, 0x0a, 0x0a, 0x0f, 0x0a, + 0x07, 0x04, 0x00, 0x03, 0x28, 0x02, 0x08, 0x04, 0x12, 0x04, 0xaa, 0x08, 0x04, 0x0c, 0x0a, 0x0f, + 0x0a, 0x07, 0x04, 0x00, 0x03, 0x28, 0x02, 0x08, 0x05, 0x12, 0x04, 0xaa, 0x08, 0x0d, 0x13, 0x0a, + 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x28, 0x02, 0x08, 0x01, 0x12, 0x04, 0xaa, 0x08, 0x14, 0x22, + 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x28, 0x02, 0x08, 0x03, 0x12, 0x04, 0xaa, 0x08, 0x25, + 0x26, 0x0a, 0x4f, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x28, 0x02, 0x09, 0x12, 0x04, 0xac, 0x08, 0x04, + 0x27, 0x1a, 0x3f, 0x2f, 0x20, 0x54, 0x68, 0x65, 0x20, 0x4f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x4a, + 0x6f, 0x62, 0x20, 0x74, 0x6f, 0x20, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x20, 0x69, 0x66, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x66, + 0x61, 0x69, 0x6c, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x65, 0x76, 0x61, 0x6c, 0x75, 0x61, 0x74, 0x65, + 0x2e, 0x0a, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x28, 0x02, 0x09, 0x04, 0x12, 0x04, 0xac, + 0x08, 0x04, 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x28, 0x02, 0x09, 0x06, 0x12, 0x04, + 0xac, 0x08, 0x0d, 0x16, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x28, 0x02, 0x09, 0x01, 0x12, + 0x04, 0xac, 0x08, 0x17, 0x21, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x28, 0x02, 0x09, 0x03, + 0x12, 0x04, 0xac, 0x08, 0x24, 0x26, 0x0a, 0x68, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x28, 0x02, 0x0a, + 0x12, 0x04, 0xae, 0x08, 0x04, 0x2a, 0x1a, 0x58, 0x2f, 0x20, 0x54, 0x68, 0x65, 0x20, 0x72, 0x65, + 0x73, 0x75, 0x6c, 0x74, 0x20, 0x74, 0x6f, 0x20, 0x75, 0x73, 0x65, 0x20, 0x69, 0x66, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x66, 0x61, 0x69, + 0x6c, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x65, 0x76, 0x61, 0x6c, 0x75, 0x61, 0x74, 0x65, 0x2e, 0x20, + 0x43, 0x61, 0x6e, 0x20, 0x62, 0x65, 0x20, 0x73, 0x65, 0x74, 0x20, 0x74, 0x6f, 0x20, 0x61, 0x20, + 0x60, 0x24, 0x7b, 0x43, 0x41, 0x43, 0x48, 0x45, 0x5f, 0x4b, 0x45, 0x59, 0x7d, 0x60, 0x2e, 0x0a, + 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x28, 0x02, 0x0a, 0x04, 0x12, 0x04, 0xae, 0x08, 0x04, + 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x28, 0x02, 0x0a, 0x05, 0x12, 0x04, 0xae, 0x08, + 0x0d, 0x13, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x28, 0x02, 0x0a, 0x01, 0x12, 0x04, 0xae, + 0x08, 0x14, 0x24, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x28, 0x02, 0x0a, 0x03, 0x12, 0x04, + 0xae, 0x08, 0x27, 0x29, 0x0a, 0xe8, 0x02, 0x0a, 0x04, 0x04, 0x00, 0x03, 0x29, 0x12, 0x06, 0xbe, + 0x08, 0x02, 0xc9, 0x08, 0x03, 0x1a, 0xd7, 0x02, 0x0a, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x20, 0x72, 0x75, 0x6e, 0x6e, 0x69, + 0x6e, 0x67, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x20, 0x74, 0x6f, 0x20, 0x61, 0x20, 0x73, + 0x65, 0x74, 0x20, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x20, 0x6f, 0x66, 0x20, 0x64, 0x65, 0x63, + 0x69, 0x6d, 0x61, 0x6c, 0x20, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x73, 0x2e, 0x0a, 0x0a, 0x5f, 0x2a, + 0x2a, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x2a, 0x2a, 0x5f, 0x3a, 0x20, 0x54, 0x68, 0x65, 0x20, 0x63, + 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x20, 0x72, 0x75, 0x6e, 0x6e, 0x69, 0x6e, 0x67, 0x20, 0x6e, + 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x6c, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x2e, + 0x0a, 0x0a, 0x5f, 0x2a, 0x2a, 0x52, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x73, 0x2a, 0x2a, 0x5f, 0x3a, + 0x20, 0x54, 0x68, 0x65, 0x20, 0x72, 0x75, 0x6e, 0x6e, 0x69, 0x6e, 0x67, 0x20, 0x72, 0x65, 0x73, + 0x75, 0x6c, 0x74, 0x20, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x65, 0x64, 0x20, 0x74, 0x6f, 0x20, 0x61, + 0x20, 0x73, 0x65, 0x74, 0x20, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x20, 0x6f, 0x66, 0x20, 0x64, + 0x65, 0x63, 0x69, 0x6d, 0x61, 0x6c, 0x20, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x73, 0x2e, 0x0a, 0x0a, + 0x5f, 0x2a, 0x2a, 0x45, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2a, 0x2a, 0x5f, 0x3a, 0x20, 0x52, + 0x6f, 0x75, 0x6e, 0x64, 0x20, 0x64, 0x6f, 0x77, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x72, 0x75, + 0x6e, 0x6e, 0x69, 0x6e, 0x67, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x20, 0x74, 0x6f, 0x20, 0x38, + 0x20, 0x64, 0x65, 0x63, 0x69, 0x6d, 0x61, 0x6c, 0x20, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x73, 0x0a, + 0x0a, 0x60, 0x60, 0x60, 0x6a, 0x73, 0x6f, 0x6e, 0x0a, 0x7b, 0x20, 0x22, 0x72, 0x6f, 0x75, 0x6e, + 0x64, 0x54, 0x61, 0x73, 0x6b, 0x22, 0x3a, 0x20, 0x7b, 0x20, 0x22, 0x6d, 0x65, 0x74, 0x68, 0x6f, + 0x64, 0x22, 0x3a, 0x20, 0x22, 0x4d, 0x45, 0x54, 0x48, 0x4f, 0x44, 0x5f, 0x52, 0x4f, 0x55, 0x4e, + 0x44, 0x5f, 0x44, 0x4f, 0x57, 0x4e, 0x22, 0x2c, 0x20, 0x22, 0x64, 0x65, 0x63, 0x69, 0x6d, 0x61, + 0x6c, 0x73, 0x22, 0x3a, 0x20, 0x38, 0x20, 0x7d, 0x20, 0x7d, 0x0a, 0x60, 0x60, 0x60, 0x0a, 0x0a, + 0x0d, 0x0a, 0x05, 0x04, 0x00, 0x03, 0x29, 0x01, 0x12, 0x04, 0xbe, 0x08, 0x0a, 0x13, 0x0a, 0x10, + 0x0a, 0x06, 0x04, 0x00, 0x03, 0x29, 0x04, 0x00, 0x12, 0x06, 0xbf, 0x08, 0x04, 0xc4, 0x08, 0x05, + 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x29, 0x04, 0x00, 0x01, 0x12, 0x04, 0xbf, 0x08, 0x09, + 0x0f, 0x0a, 0x2b, 0x0a, 0x08, 0x04, 0x00, 0x03, 0x29, 0x04, 0x00, 0x02, 0x00, 0x12, 0x04, 0xc1, + 0x08, 0x06, 0x1a, 0x1a, 0x19, 0x2f, 0x20, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x20, 0x64, 0x6f, 0x77, 0x6e, 0x2e, 0x0a, 0x0a, 0x11, + 0x0a, 0x09, 0x04, 0x00, 0x03, 0x29, 0x04, 0x00, 0x02, 0x00, 0x01, 0x12, 0x04, 0xc1, 0x08, 0x06, + 0x15, 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x29, 0x04, 0x00, 0x02, 0x00, 0x02, 0x12, 0x04, + 0xc1, 0x08, 0x18, 0x19, 0x0a, 0x29, 0x0a, 0x08, 0x04, 0x00, 0x03, 0x29, 0x04, 0x00, 0x02, 0x01, + 0x12, 0x04, 0xc3, 0x08, 0x06, 0x1c, 0x1a, 0x17, 0x2f, 0x20, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x20, 0x75, 0x70, 0x2e, 0x0a, 0x0a, + 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x29, 0x04, 0x00, 0x02, 0x01, 0x01, 0x12, 0x04, 0xc3, 0x08, + 0x06, 0x17, 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x29, 0x04, 0x00, 0x02, 0x01, 0x02, 0x12, + 0x04, 0xc3, 0x08, 0x1a, 0x1b, 0x0a, 0x2e, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x29, 0x02, 0x00, 0x12, + 0x04, 0xc6, 0x08, 0x04, 0x1f, 0x1a, 0x1e, 0x2f, 0x20, 0x54, 0x68, 0x65, 0x20, 0x72, 0x6f, 0x75, + 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x20, 0x74, 0x6f, 0x20, + 0x75, 0x73, 0x65, 0x2e, 0x0a, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x29, 0x02, 0x00, 0x04, + 0x12, 0x04, 0xc6, 0x08, 0x04, 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x29, 0x02, 0x00, + 0x06, 0x12, 0x04, 0xc6, 0x08, 0x0d, 0x13, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x29, 0x02, + 0x00, 0x01, 0x12, 0x04, 0xc6, 0x08, 0x14, 0x1a, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x29, + 0x02, 0x00, 0x03, 0x12, 0x04, 0xc6, 0x08, 0x1d, 0x1e, 0x0a, 0x36, 0x0a, 0x06, 0x04, 0x00, 0x03, + 0x29, 0x02, 0x01, 0x12, 0x04, 0xc8, 0x08, 0x04, 0x20, 0x1a, 0x26, 0x2f, 0x20, 0x54, 0x68, 0x65, + 0x20, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x20, 0x6f, 0x66, 0x20, 0x64, 0x65, 0x63, 0x69, 0x6d, + 0x61, 0x6c, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x20, 0x74, 0x6f, 0x2e, + 0x0a, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x29, 0x02, 0x01, 0x04, 0x12, 0x04, 0xc8, 0x08, + 0x04, 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x29, 0x02, 0x01, 0x05, 0x12, 0x04, 0xc8, + 0x08, 0x0d, 0x12, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x29, 0x02, 0x01, 0x01, 0x12, 0x04, + 0xc8, 0x08, 0x13, 0x1b, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x29, 0x02, 0x01, 0x03, 0x12, + 0x04, 0xc8, 0x08, 0x1e, 0x1f, 0x0a, 0xf6, 0x03, 0x0a, 0x04, 0x04, 0x00, 0x03, 0x2a, 0x12, 0x06, + 0xd8, 0x08, 0x02, 0xe9, 0x08, 0x03, 0x1a, 0xe5, 0x03, 0x0a, 0x42, 0x6f, 0x75, 0x6e, 0x64, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x72, 0x75, 0x6e, 0x6e, 0x69, 0x6e, 0x67, 0x20, 0x72, 0x65, 0x73, 0x75, + 0x6c, 0x74, 0x20, 0x74, 0x6f, 0x20, 0x61, 0x6e, 0x20, 0x75, 0x70, 0x70, 0x65, 0x72, 0x2f, 0x6c, + 0x6f, 0x77, 0x65, 0x72, 0x20, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x2e, 0x20, 0x54, 0x68, 0x69, 0x73, + 0x20, 0x69, 0x73, 0x20, 0x74, 0x79, 0x70, 0x69, 0x63, 0x61, 0x6c, 0x6c, 0x79, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x6c, 0x61, 0x73, 0x74, 0x20, 0x74, 0x61, 0x73, 0x6b, 0x20, 0x69, 0x6e, 0x20, 0x61, + 0x6e, 0x20, 0x4f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x4a, 0x6f, 0x62, 0x2e, 0x0a, 0x0a, 0x5f, 0x2a, + 0x2a, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x2a, 0x2a, 0x5f, 0x3a, 0x20, 0x54, 0x68, 0x65, 0x20, 0x63, + 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x20, 0x72, 0x75, 0x6e, 0x6e, 0x69, 0x6e, 0x67, 0x20, 0x6e, + 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x6c, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x2e, + 0x0a, 0x0a, 0x5f, 0x2a, 0x2a, 0x52, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x73, 0x2a, 0x2a, 0x5f, 0x3a, + 0x20, 0x54, 0x68, 0x65, 0x20, 0x72, 0x75, 0x6e, 0x6e, 0x69, 0x6e, 0x67, 0x20, 0x72, 0x65, 0x73, + 0x75, 0x6c, 0x74, 0x20, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x65, 0x64, 0x20, 0x74, 0x6f, 0x20, 0x61, + 0x6e, 0x20, 0x75, 0x70, 0x70, 0x65, 0x72, 0x20, 0x6f, 0x72, 0x20, 0x6c, 0x6f, 0x77, 0x65, 0x72, + 0x20, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x20, 0x69, 0x66, 0x20, 0x69, 0x74, 0x20, 0x65, 0x78, 0x63, + 0x65, 0x65, 0x64, 0x73, 0x20, 0x61, 0x20, 0x67, 0x69, 0x76, 0x65, 0x6e, 0x20, 0x74, 0x68, 0x72, + 0x65, 0x73, 0x68, 0x6f, 0x6c, 0x64, 0x2e, 0x0a, 0x0a, 0x5f, 0x2a, 0x2a, 0x45, 0x78, 0x61, 0x6d, + 0x70, 0x6c, 0x65, 0x2a, 0x2a, 0x5f, 0x3a, 0x20, 0x42, 0x6f, 0x75, 0x6e, 0x64, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x72, 0x75, 0x6e, 0x6e, 0x69, 0x6e, 0x67, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, + 0x20, 0x74, 0x6f, 0x20, 0x61, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x20, 0x62, 0x65, 0x74, 0x77, + 0x65, 0x65, 0x6e, 0x20, 0x30, 0x2e, 0x39, 0x30, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x31, 0x2e, 0x31, + 0x30, 0x0a, 0x0a, 0x60, 0x60, 0x60, 0x6a, 0x73, 0x6f, 0x6e, 0x0a, 0x7b, 0x20, 0x22, 0x62, 0x6f, + 0x75, 0x6e, 0x64, 0x54, 0x61, 0x73, 0x6b, 0x22, 0x3a, 0x20, 0x7b, 0x20, 0x22, 0x6c, 0x6f, 0x77, + 0x65, 0x72, 0x42, 0x6f, 0x75, 0x6e, 0x64, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x3a, 0x20, 0x22, + 0x30, 0x2e, 0x39, 0x30, 0x22, 0x2c, 0x22, 0x6f, 0x6e, 0x45, 0x78, 0x63, 0x65, 0x65, 0x64, 0x73, + 0x4c, 0x6f, 0x77, 0x65, 0x72, 0x42, 0x6f, 0x75, 0x6e, 0x64, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x22, + 0x3a, 0x20, 0x22, 0x30, 0x2e, 0x39, 0x30, 0x22, 0x2c, 0x22, 0x75, 0x70, 0x70, 0x65, 0x72, 0x42, + 0x6f, 0x75, 0x6e, 0x64, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x3a, 0x20, 0x22, 0x31, 0x2e, 0x31, + 0x30, 0x22, 0x2c, 0x22, 0x6f, 0x6e, 0x45, 0x78, 0x63, 0x65, 0x65, 0x64, 0x73, 0x55, 0x70, 0x70, + 0x65, 0x72, 0x42, 0x6f, 0x75, 0x6e, 0x64, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x3a, 0x20, 0x22, + 0x31, 0x2e, 0x31, 0x30, 0x22, 0x20, 0x7d, 0x20, 0x7d, 0x0a, 0x60, 0x60, 0x60, 0x0a, 0x0a, 0x0d, + 0x0a, 0x05, 0x04, 0x00, 0x03, 0x2a, 0x01, 0x12, 0x04, 0xd8, 0x08, 0x0a, 0x13, 0x0a, 0x46, 0x0a, + 0x06, 0x04, 0x00, 0x03, 0x2a, 0x02, 0x00, 0x12, 0x04, 0xda, 0x08, 0x04, 0x27, 0x1a, 0x36, 0x2f, + 0x20, 0x54, 0x68, 0x65, 0x20, 0x4f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x4a, 0x6f, 0x62, 0x20, 0x74, + 0x6f, 0x20, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x6c, 0x6f, 0x77, 0x65, 0x72, 0x20, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x20, 0x76, 0x61, + 0x6c, 0x75, 0x65, 0x2e, 0x0a, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x2a, 0x02, 0x00, 0x04, + 0x12, 0x04, 0xda, 0x08, 0x04, 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x2a, 0x02, 0x00, + 0x06, 0x12, 0x04, 0xda, 0x08, 0x0d, 0x16, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x2a, 0x02, + 0x00, 0x01, 0x12, 0x04, 0xda, 0x08, 0x17, 0x22, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x2a, + 0x02, 0x00, 0x03, 0x12, 0x04, 0xda, 0x08, 0x25, 0x26, 0x0a, 0x58, 0x0a, 0x06, 0x04, 0x00, 0x03, + 0x2a, 0x02, 0x01, 0x12, 0x04, 0xdc, 0x08, 0x04, 0x2a, 0x1a, 0x48, 0x2f, 0x20, 0x54, 0x68, 0x65, + 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x20, 0x74, 0x6f, 0x20, 0x75, 0x73, 0x65, 0x20, 0x66, 0x6f, + 0x72, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6c, 0x6f, 0x77, 0x65, 0x72, 0x20, 0x62, 0x6f, 0x75, 0x6e, + 0x64, 0x2e, 0x20, 0x43, 0x61, 0x6e, 0x20, 0x62, 0x65, 0x20, 0x73, 0x65, 0x74, 0x20, 0x74, 0x6f, + 0x20, 0x61, 0x20, 0x60, 0x24, 0x7b, 0x43, 0x41, 0x43, 0x48, 0x45, 0x5f, 0x4b, 0x45, 0x59, 0x7d, + 0x60, 0x2e, 0x0a, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x2a, 0x02, 0x01, 0x04, 0x12, 0x04, + 0xdc, 0x08, 0x04, 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x2a, 0x02, 0x01, 0x05, 0x12, + 0x04, 0xdc, 0x08, 0x0d, 0x13, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x2a, 0x02, 0x01, 0x01, + 0x12, 0x04, 0xdc, 0x08, 0x14, 0x25, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x2a, 0x02, 0x01, + 0x03, 0x12, 0x04, 0xdc, 0x08, 0x28, 0x29, 0x0a, 0x46, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x2a, 0x02, + 0x02, 0x12, 0x04, 0xde, 0x08, 0x04, 0x27, 0x1a, 0x36, 0x2f, 0x20, 0x54, 0x68, 0x65, 0x20, 0x4f, + 0x72, 0x61, 0x63, 0x6c, 0x65, 0x4a, 0x6f, 0x62, 0x20, 0x74, 0x6f, 0x20, 0x65, 0x78, 0x65, 0x63, + 0x75, 0x74, 0x65, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x74, 0x68, 0x65, 0x20, 0x75, 0x70, 0x70, 0x65, + 0x72, 0x20, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x2e, 0x0a, 0x0a, + 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x2a, 0x02, 0x02, 0x04, 0x12, 0x04, 0xde, 0x08, 0x04, 0x0c, + 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x2a, 0x02, 0x02, 0x06, 0x12, 0x04, 0xde, 0x08, 0x0d, + 0x16, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x2a, 0x02, 0x02, 0x01, 0x12, 0x04, 0xde, 0x08, + 0x17, 0x22, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x2a, 0x02, 0x02, 0x03, 0x12, 0x04, 0xde, + 0x08, 0x25, 0x26, 0x0a, 0x58, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x2a, 0x02, 0x03, 0x12, 0x04, 0xe0, + 0x08, 0x04, 0x2a, 0x1a, 0x48, 0x2f, 0x20, 0x54, 0x68, 0x65, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, + 0x20, 0x74, 0x6f, 0x20, 0x75, 0x73, 0x65, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x75, 0x70, 0x70, 0x65, 0x72, 0x20, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x2e, 0x20, 0x43, 0x61, 0x6e, + 0x20, 0x62, 0x65, 0x20, 0x73, 0x65, 0x74, 0x20, 0x74, 0x6f, 0x20, 0x61, 0x20, 0x60, 0x24, 0x7b, + 0x43, 0x41, 0x43, 0x48, 0x45, 0x5f, 0x4b, 0x45, 0x59, 0x7d, 0x60, 0x2e, 0x0a, 0x0a, 0x0f, 0x0a, + 0x07, 0x04, 0x00, 0x03, 0x2a, 0x02, 0x03, 0x04, 0x12, 0x04, 0xe0, 0x08, 0x04, 0x0c, 0x0a, 0x0f, + 0x0a, 0x07, 0x04, 0x00, 0x03, 0x2a, 0x02, 0x03, 0x05, 0x12, 0x04, 0xe0, 0x08, 0x0d, 0x13, 0x0a, + 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x2a, 0x02, 0x03, 0x01, 0x12, 0x04, 0xe0, 0x08, 0x14, 0x25, + 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x2a, 0x02, 0x03, 0x03, 0x12, 0x04, 0xe0, 0x08, 0x28, + 0x29, 0x0a, 0x4b, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x2a, 0x02, 0x04, 0x12, 0x04, 0xe2, 0x08, 0x04, + 0x32, 0x1a, 0x3b, 0x2f, 0x20, 0x54, 0x68, 0x65, 0x20, 0x4f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x4a, + 0x6f, 0x62, 0x20, 0x74, 0x6f, 0x20, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x20, 0x69, 0x66, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x75, 0x70, 0x70, 0x65, 0x72, 0x20, 0x62, 0x6f, 0x75, 0x6e, 0x64, + 0x20, 0x69, 0x73, 0x20, 0x65, 0x78, 0x63, 0x65, 0x65, 0x64, 0x65, 0x64, 0x2e, 0x0a, 0x0a, 0x0f, + 0x0a, 0x07, 0x04, 0x00, 0x03, 0x2a, 0x02, 0x04, 0x04, 0x12, 0x04, 0xe2, 0x08, 0x04, 0x0c, 0x0a, + 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x2a, 0x02, 0x04, 0x06, 0x12, 0x04, 0xe2, 0x08, 0x0d, 0x16, + 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x2a, 0x02, 0x04, 0x01, 0x12, 0x04, 0xe2, 0x08, 0x17, + 0x2d, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x2a, 0x02, 0x04, 0x03, 0x12, 0x04, 0xe2, 0x08, + 0x30, 0x31, 0x0a, 0x63, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x2a, 0x02, 0x05, 0x12, 0x04, 0xe4, 0x08, + 0x04, 0x35, 0x1a, 0x53, 0x2f, 0x20, 0x54, 0x68, 0x65, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x20, + 0x74, 0x6f, 0x20, 0x75, 0x73, 0x65, 0x20, 0x69, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x75, 0x70, + 0x70, 0x65, 0x72, 0x20, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x20, 0x69, 0x73, 0x20, 0x65, 0x78, 0x63, + 0x65, 0x65, 0x64, 0x65, 0x64, 0x2e, 0x20, 0x43, 0x61, 0x6e, 0x20, 0x62, 0x65, 0x20, 0x73, 0x65, + 0x74, 0x20, 0x74, 0x6f, 0x20, 0x61, 0x20, 0x60, 0x24, 0x7b, 0x43, 0x41, 0x43, 0x48, 0x45, 0x5f, + 0x4b, 0x45, 0x59, 0x7d, 0x60, 0x2e, 0x0a, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x2a, 0x02, + 0x05, 0x04, 0x12, 0x04, 0xe4, 0x08, 0x04, 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x2a, + 0x02, 0x05, 0x05, 0x12, 0x04, 0xe4, 0x08, 0x0d, 0x13, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, + 0x2a, 0x02, 0x05, 0x01, 0x12, 0x04, 0xe4, 0x08, 0x14, 0x30, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, + 0x03, 0x2a, 0x02, 0x05, 0x03, 0x12, 0x04, 0xe4, 0x08, 0x33, 0x34, 0x0a, 0x4b, 0x0a, 0x06, 0x04, + 0x00, 0x03, 0x2a, 0x02, 0x06, 0x12, 0x04, 0xe6, 0x08, 0x04, 0x32, 0x1a, 0x3b, 0x2f, 0x20, 0x54, + 0x68, 0x65, 0x20, 0x4f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x4a, 0x6f, 0x62, 0x20, 0x74, 0x6f, 0x20, + 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x20, 0x69, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6c, + 0x6f, 0x77, 0x65, 0x72, 0x20, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x20, 0x69, 0x73, 0x20, 0x65, 0x78, + 0x63, 0x65, 0x65, 0x64, 0x65, 0x64, 0x2e, 0x0a, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x2a, + 0x02, 0x06, 0x04, 0x12, 0x04, 0xe6, 0x08, 0x04, 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, + 0x2a, 0x02, 0x06, 0x06, 0x12, 0x04, 0xe6, 0x08, 0x0d, 0x16, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, + 0x03, 0x2a, 0x02, 0x06, 0x01, 0x12, 0x04, 0xe6, 0x08, 0x17, 0x2d, 0x0a, 0x0f, 0x0a, 0x07, 0x04, + 0x00, 0x03, 0x2a, 0x02, 0x06, 0x03, 0x12, 0x04, 0xe6, 0x08, 0x30, 0x31, 0x0a, 0x63, 0x0a, 0x06, + 0x04, 0x00, 0x03, 0x2a, 0x02, 0x07, 0x12, 0x04, 0xe8, 0x08, 0x04, 0x35, 0x1a, 0x53, 0x2f, 0x20, + 0x54, 0x68, 0x65, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x20, 0x74, 0x6f, 0x20, 0x75, 0x73, 0x65, + 0x20, 0x69, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6c, 0x6f, 0x77, 0x65, 0x72, 0x20, 0x62, 0x6f, + 0x75, 0x6e, 0x64, 0x20, 0x69, 0x73, 0x20, 0x65, 0x78, 0x63, 0x65, 0x65, 0x64, 0x65, 0x64, 0x2e, + 0x20, 0x43, 0x61, 0x6e, 0x20, 0x62, 0x65, 0x20, 0x73, 0x65, 0x74, 0x20, 0x74, 0x6f, 0x20, 0x61, + 0x20, 0x60, 0x24, 0x7b, 0x43, 0x41, 0x43, 0x48, 0x45, 0x5f, 0x4b, 0x45, 0x59, 0x7d, 0x60, 0x2e, + 0x0a, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x2a, 0x02, 0x07, 0x04, 0x12, 0x04, 0xe8, 0x08, + 0x04, 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x2a, 0x02, 0x07, 0x05, 0x12, 0x04, 0xe8, + 0x08, 0x0d, 0x13, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x2a, 0x02, 0x07, 0x01, 0x12, 0x04, + 0xe8, 0x08, 0x14, 0x30, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x2a, 0x02, 0x07, 0x03, 0x12, + 0x04, 0xe8, 0x08, 0x33, 0x34, 0x0a, 0x8c, 0x03, 0x0a, 0x04, 0x04, 0x00, 0x03, 0x2b, 0x12, 0x06, + 0xf8, 0x08, 0x02, 0xfd, 0x08, 0x03, 0x1a, 0xfb, 0x02, 0x0a, 0x53, 0x65, 0x63, 0x75, 0x72, 0x65, + 0x6c, 0x79, 0x20, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x20, 0x73, 0x65, 0x63, 0x72, 0x65, + 0x74, 0x73, 0x20, 0x66, 0x72, 0x6f, 0x6d, 0x20, 0x61, 0x20, 0x53, 0x77, 0x69, 0x74, 0x63, 0x68, + 0x62, 0x6f, 0x61, 0x72, 0x64, 0x20, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x73, 0x53, 0x65, 0x72, + 0x76, 0x65, 0x72, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x61, 0x72, 0x65, 0x20, 0x6f, 0x77, 0x6e, + 0x65, 0x64, 0x20, 0x62, 0x79, 0x20, 0x61, 0x20, 0x73, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, + 0x20, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x2e, 0x20, 0x41, 0x6e, 0x79, 0x20, + 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x73, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x61, 0x72, 0x65, + 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x65, 0x64, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x20, 0x66, 0x65, 0x65, 0x64, 0x20, 0x77, + 0x69, 0x6c, 0x6c, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x62, 0x65, 0x20, 0x75, 0x6e, 0x77, 0x72, + 0x61, 0x70, 0x70, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x74, 0x6f, 0x20, 0x76, 0x61, 0x72, 0x69, 0x61, + 0x62, 0x6c, 0x65, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x62, 0x65, 0x20, 0x61, 0x63, 0x63, 0x65, 0x73, + 0x73, 0x65, 0x64, 0x20, 0x6c, 0x61, 0x74, 0x65, 0x72, 0x2e, 0x0a, 0x0a, 0x5f, 0x2a, 0x2a, 0x49, + 0x6e, 0x70, 0x75, 0x74, 0x2a, 0x2a, 0x5f, 0x3a, 0x20, 0x4e, 0x6f, 0x6e, 0x65, 0x0a, 0x0a, 0x5f, + 0x2a, 0x2a, 0x52, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x73, 0x2a, 0x2a, 0x5f, 0x3a, 0x20, 0x54, 0x68, + 0x65, 0x20, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x0a, 0x0a, 0x5f, 0x2a, 0x2a, 0x45, 0x78, 0x61, 0x6d, + 0x70, 0x6c, 0x65, 0x2a, 0x2a, 0x5f, 0x3a, 0x20, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x73, 0x54, + 0x61, 0x73, 0x6b, 0x0a, 0x0a, 0x60, 0x60, 0x60, 0x6a, 0x73, 0x6f, 0x6e, 0x0a, 0x7b, 0x20, 0x22, + 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x73, 0x54, 0x61, 0x73, 0x6b, 0x22, 0x3a, 0x20, 0x7b, 0x20, + 0x22, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x22, 0x3a, 0x20, 0x22, 0x41, 0x63, + 0x63, 0x62, 0x32, 0x31, 0x74, 0x55, 0x43, 0x57, 0x6f, 0x63, 0x4a, 0x65, 0x61, 0x36, 0x55, 0x6b, + 0x33, 0x44, 0x67, 0x72, 0x4e, 0x5a, 0x61, 0x77, 0x67, 0x6d, 0x4b, 0x65, 0x67, 0x44, 0x56, 0x65, + 0x48, 0x77, 0x38, 0x63, 0x47, 0x4d, 0x44, 0x50, 0x69, 0x35, 0x22, 0x20, 0x7d, 0x20, 0x7d, 0x0a, + 0x60, 0x60, 0x60, 0x0a, 0x0a, 0x0d, 0x0a, 0x05, 0x04, 0x00, 0x03, 0x2b, 0x01, 0x12, 0x04, 0xf8, + 0x08, 0x0a, 0x15, 0x0a, 0x49, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x2b, 0x02, 0x00, 0x12, 0x04, 0xfa, + 0x08, 0x04, 0x22, 0x1a, 0x39, 0x2f, 0x20, 0x54, 0x68, 0x65, 0x20, 0x61, 0x75, 0x74, 0x68, 0x6f, + 0x72, 0x69, 0x74, 0x79, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x63, 0x72, + 0x65, 0x74, 0x73, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x61, 0x72, 0x65, 0x20, 0x74, 0x6f, 0x20, + 0x62, 0x65, 0x20, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x65, 0x64, 0x2e, 0x0a, 0x0a, 0x0f, + 0x0a, 0x07, 0x04, 0x00, 0x03, 0x2b, 0x02, 0x00, 0x04, 0x12, 0x04, 0xfa, 0x08, 0x04, 0x0c, 0x0a, + 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x2b, 0x02, 0x00, 0x05, 0x12, 0x04, 0xfa, 0x08, 0x0d, 0x13, + 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x2b, 0x02, 0x00, 0x01, 0x12, 0x04, 0xfa, 0x08, 0x14, + 0x1d, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x2b, 0x02, 0x00, 0x03, 0x12, 0x04, 0xfa, 0x08, + 0x20, 0x21, 0x0a, 0x75, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x2b, 0x02, 0x01, 0x12, 0x04, 0xfc, 0x08, + 0x04, 0x1c, 0x1a, 0x65, 0x2f, 0x20, 0x54, 0x68, 0x65, 0x20, 0x75, 0x72, 0x6c, 0x20, 0x6f, 0x66, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x74, 0x6f, 0x20, 0x72, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x20, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x73, 0x20, 0x66, + 0x72, 0x6f, 0x6d, 0x2e, 0x20, 0x54, 0x68, 0x65, 0x20, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, + 0x20, 0x69, 0x73, 0x20, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x61, 0x70, 0x69, 0x2e, + 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x73, 0x2e, 0x73, 0x77, 0x69, 0x74, 0x63, 0x68, 0x62, 0x6f, + 0x61, 0x72, 0x64, 0x2e, 0x78, 0x79, 0x7a, 0x2e, 0x0a, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, + 0x2b, 0x02, 0x01, 0x04, 0x12, 0x04, 0xfc, 0x08, 0x04, 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, + 0x03, 0x2b, 0x02, 0x01, 0x05, 0x12, 0x04, 0xfc, 0x08, 0x0d, 0x13, 0x0a, 0x0f, 0x0a, 0x07, 0x04, + 0x00, 0x03, 0x2b, 0x02, 0x01, 0x01, 0x12, 0x04, 0xfc, 0x08, 0x14, 0x17, 0x0a, 0x0f, 0x0a, 0x07, + 0x04, 0x00, 0x03, 0x2b, 0x02, 0x01, 0x03, 0x12, 0x04, 0xfc, 0x08, 0x1a, 0x1b, 0x0a, 0x44, 0x0a, + 0x04, 0x04, 0x00, 0x03, 0x2c, 0x12, 0x06, 0x80, 0x09, 0x02, 0x88, 0x09, 0x03, 0x1a, 0x34, 0x2f, + 0x20, 0x47, 0x72, 0x61, 0x62, 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x72, 0x69, 0x63, 0x65, 0x20, + 0x6f, 0x66, 0x20, 0x61, 0x6e, 0x20, 0x53, 0x61, 0x6e, 0x63, 0x74, 0x75, 0x6d, 0x20, 0x4c, 0x53, + 0x54, 0x20, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x76, 0x65, 0x20, 0x74, 0x6f, 0x20, 0x53, 0x4f, + 0x4c, 0x2e, 0x0a, 0x0a, 0x0d, 0x0a, 0x05, 0x04, 0x00, 0x03, 0x2c, 0x01, 0x12, 0x04, 0x80, 0x09, + 0x0a, 0x1d, 0x0a, 0x6b, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x2c, 0x02, 0x00, 0x12, 0x04, 0x84, 0x09, + 0x04, 0x21, 0x1a, 0x5b, 0x2f, 0x20, 0x54, 0x68, 0x65, 0x20, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, + 0x73, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x4c, 0x53, 0x54, 0x20, 0x6d, 0x69, 0x6e, + 0x74, 0x2e, 0x0a, 0x2f, 0x0a, 0x2f, 0x20, 0x65, 0x2e, 0x67, 0x2e, 0x20, 0x49, 0x4e, 0x46, 0x20, + 0x2d, 0x20, 0x35, 0x6f, 0x56, 0x4e, 0x42, 0x65, 0x45, 0x45, 0x51, 0x76, 0x59, 0x69, 0x31, 0x63, + 0x58, 0x33, 0x69, 0x72, 0x38, 0x44, 0x78, 0x35, 0x6e, 0x31, 0x50, 0x37, 0x70, 0x64, 0x78, 0x79, + 0x64, 0x62, 0x47, 0x46, 0x32, 0x58, 0x34, 0x54, 0x78, 0x56, 0x75, 0x73, 0x4a, 0x6d, 0x0a, 0x0a, + 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x2c, 0x02, 0x00, 0x04, 0x12, 0x04, 0x84, 0x09, 0x04, 0x0c, + 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x2c, 0x02, 0x00, 0x05, 0x12, 0x04, 0x84, 0x09, 0x0d, + 0x13, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x2c, 0x02, 0x00, 0x01, 0x12, 0x04, 0x84, 0x09, + 0x14, 0x1c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x2c, 0x02, 0x00, 0x03, 0x12, 0x04, 0x84, + 0x09, 0x1f, 0x20, 0x0a, 0x65, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x2c, 0x02, 0x01, 0x12, 0x04, 0x87, + 0x09, 0x04, 0x27, 0x1a, 0x55, 0x2f, 0x20, 0x41, 0x6c, 0x6c, 0x6f, 0x77, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x20, 0x74, 0x6f, 0x20, 0x73, 0x65, 0x65, 0x20, 0x69, 0x66, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x4c, 0x53, 0x54, 0x20, 0x77, 0x61, 0x73, 0x20, 0x63, 0x72, 0x61, + 0x6e, 0x6b, 0x65, 0x64, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x75, 0x72, + 0x72, 0x65, 0x6e, 0x74, 0x20, 0x65, 0x70, 0x6f, 0x63, 0x68, 0x20, 0x74, 0x6f, 0x20, 0x62, 0x65, + 0x20, 0x73, 0x6b, 0x69, 0x70, 0x70, 0x65, 0x64, 0x2e, 0x0a, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, + 0x03, 0x2c, 0x02, 0x01, 0x04, 0x12, 0x04, 0x87, 0x09, 0x04, 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, + 0x00, 0x03, 0x2c, 0x02, 0x01, 0x05, 0x12, 0x04, 0x87, 0x09, 0x0d, 0x11, 0x0a, 0x0f, 0x0a, 0x07, + 0x04, 0x00, 0x03, 0x2c, 0x02, 0x01, 0x01, 0x12, 0x04, 0x87, 0x09, 0x12, 0x22, 0x0a, 0x0f, 0x0a, + 0x07, 0x04, 0x00, 0x03, 0x2c, 0x02, 0x01, 0x03, 0x12, 0x04, 0x87, 0x09, 0x25, 0x26, 0x0a, 0x7f, + 0x0a, 0x04, 0x04, 0x00, 0x03, 0x2d, 0x12, 0x06, 0x8c, 0x09, 0x02, 0x97, 0x09, 0x03, 0x1a, 0x6f, + 0x2f, 0x20, 0x4f, 0x6e, 0x64, 0x6f, 0x55, 0x73, 0x64, 0x79, 0x54, 0x61, 0x73, 0x6b, 0x20, 0x72, + 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x73, 0x20, 0x61, 0x20, 0x74, 0x61, 0x73, 0x6b, + 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x63, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x73, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x70, 0x72, 0x69, 0x63, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x55, 0x53, 0x44, 0x59, + 0x20, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x76, 0x65, 0x20, 0x74, 0x6f, 0x20, 0x55, 0x53, 0x44, + 0x20, 0x75, 0x73, 0x69, 0x6e, 0x67, 0x20, 0x61, 0x0a, 0x2f, 0x20, 0x73, 0x70, 0x65, 0x63, 0x69, + 0x66, 0x69, 0x65, 0x64, 0x20, 0x73, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x2e, 0x0a, 0x0a, + 0x0d, 0x0a, 0x05, 0x04, 0x00, 0x03, 0x2d, 0x01, 0x12, 0x04, 0x8c, 0x09, 0x0a, 0x16, 0x0a, 0xe4, + 0x01, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x2d, 0x04, 0x00, 0x12, 0x06, 0x91, 0x09, 0x04, 0x94, 0x09, + 0x05, 0x1a, 0xd1, 0x01, 0x2f, 0x20, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x20, 0x73, + 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x65, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6d, 0x65, 0x74, + 0x68, 0x6f, 0x64, 0x20, 0x75, 0x73, 0x65, 0x64, 0x20, 0x74, 0x6f, 0x20, 0x64, 0x65, 0x74, 0x65, + 0x72, 0x6d, 0x69, 0x6e, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x72, 0x69, 0x63, 0x65, 0x20, + 0x6f, 0x66, 0x20, 0x55, 0x53, 0x44, 0x59, 0x2e, 0x0a, 0x2f, 0x0a, 0x2f, 0x20, 0x2d, 0x20, 0x53, + 0x54, 0x52, 0x41, 0x54, 0x45, 0x47, 0x59, 0x5f, 0x46, 0x41, 0x49, 0x52, 0x5f, 0x56, 0x41, 0x4c, + 0x55, 0x45, 0x3a, 0x20, 0x43, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x73, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x70, 0x72, 0x69, 0x63, 0x65, 0x20, 0x62, 0x61, 0x73, 0x65, 0x64, 0x20, 0x6f, 0x6e, 0x20, + 0x61, 0x20, 0x66, 0x61, 0x69, 0x72, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x20, 0x6d, 0x6f, 0x64, + 0x65, 0x6c, 0x2e, 0x0a, 0x2f, 0x20, 0x2d, 0x20, 0x53, 0x54, 0x52, 0x41, 0x54, 0x45, 0x47, 0x59, + 0x5f, 0x4d, 0x41, 0x52, 0x4b, 0x45, 0x54, 0x3a, 0x20, 0x46, 0x65, 0x74, 0x63, 0x68, 0x65, 0x73, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x72, 0x69, 0x63, 0x65, 0x20, 0x64, 0x69, 0x72, 0x65, 0x63, + 0x74, 0x6c, 0x79, 0x20, 0x66, 0x72, 0x6f, 0x6d, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6d, 0x61, 0x72, + 0x6b, 0x65, 0x74, 0x2e, 0x0a, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x2d, 0x04, 0x00, 0x01, + 0x12, 0x04, 0x91, 0x09, 0x09, 0x11, 0x0a, 0x10, 0x0a, 0x08, 0x04, 0x00, 0x03, 0x2d, 0x04, 0x00, + 0x02, 0x00, 0x12, 0x04, 0x92, 0x09, 0x06, 0x1e, 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x2d, + 0x04, 0x00, 0x02, 0x00, 0x01, 0x12, 0x04, 0x92, 0x09, 0x06, 0x19, 0x0a, 0x11, 0x0a, 0x09, 0x04, + 0x00, 0x03, 0x2d, 0x04, 0x00, 0x02, 0x00, 0x02, 0x12, 0x04, 0x92, 0x09, 0x1c, 0x1d, 0x0a, 0x10, + 0x0a, 0x08, 0x04, 0x00, 0x03, 0x2d, 0x04, 0x00, 0x02, 0x01, 0x12, 0x04, 0x93, 0x09, 0x06, 0x1a, + 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x2d, 0x04, 0x00, 0x02, 0x01, 0x01, 0x12, 0x04, 0x93, + 0x09, 0x06, 0x15, 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x2d, 0x04, 0x00, 0x02, 0x01, 0x02, + 0x12, 0x04, 0x93, 0x09, 0x18, 0x19, 0x0a, 0x44, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x2d, 0x02, 0x00, + 0x12, 0x04, 0x96, 0x09, 0x04, 0x23, 0x1a, 0x34, 0x2f, 0x20, 0x54, 0x68, 0x65, 0x20, 0x73, 0x74, + 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x20, 0x75, 0x73, 0x65, 0x64, 0x20, 0x74, 0x6f, 0x20, 0x64, + 0x65, 0x74, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x72, 0x69, + 0x63, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x55, 0x53, 0x44, 0x59, 0x2e, 0x0a, 0x0a, 0x0f, 0x0a, 0x07, + 0x04, 0x00, 0x03, 0x2d, 0x02, 0x00, 0x04, 0x12, 0x04, 0x96, 0x09, 0x04, 0x0c, 0x0a, 0x0f, 0x0a, + 0x07, 0x04, 0x00, 0x03, 0x2d, 0x02, 0x00, 0x06, 0x12, 0x04, 0x96, 0x09, 0x0d, 0x15, 0x0a, 0x0f, + 0x0a, 0x07, 0x04, 0x00, 0x03, 0x2d, 0x02, 0x00, 0x01, 0x12, 0x04, 0x96, 0x09, 0x16, 0x1e, 0x0a, + 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x2d, 0x02, 0x00, 0x03, 0x12, 0x04, 0x96, 0x09, 0x21, 0x22, + 0x0a, 0x3b, 0x0a, 0x04, 0x04, 0x00, 0x03, 0x2e, 0x12, 0x06, 0x9a, 0x09, 0x02, 0xa3, 0x09, 0x03, + 0x1a, 0x2b, 0x2f, 0x20, 0x47, 0x72, 0x61, 0x62, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x77, 0x61, + 0x70, 0x20, 0x70, 0x72, 0x69, 0x63, 0x65, 0x20, 0x66, 0x72, 0x6f, 0x6d, 0x20, 0x61, 0x20, 0x4d, + 0x65, 0x74, 0x65, 0x6f, 0x72, 0x61, 0x20, 0x70, 0x6f, 0x6f, 0x6c, 0x2e, 0x0a, 0x0a, 0x0d, 0x0a, + 0x05, 0x04, 0x00, 0x03, 0x2e, 0x01, 0x12, 0x04, 0x9a, 0x09, 0x0a, 0x19, 0x0a, 0x10, 0x0a, 0x06, + 0x04, 0x00, 0x03, 0x2e, 0x04, 0x00, 0x12, 0x06, 0x9b, 0x09, 0x04, 0x9e, 0x09, 0x05, 0x0a, 0x0f, + 0x0a, 0x07, 0x04, 0x00, 0x03, 0x2e, 0x04, 0x00, 0x01, 0x12, 0x04, 0x9b, 0x09, 0x09, 0x0d, 0x0a, + 0x10, 0x0a, 0x08, 0x04, 0x00, 0x03, 0x2e, 0x04, 0x00, 0x02, 0x00, 0x12, 0x04, 0x9c, 0x09, 0x06, + 0x14, 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x2e, 0x04, 0x00, 0x02, 0x00, 0x01, 0x12, 0x04, + 0x9c, 0x09, 0x06, 0x0f, 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x2e, 0x04, 0x00, 0x02, 0x00, + 0x02, 0x12, 0x04, 0x9c, 0x09, 0x12, 0x13, 0x0a, 0x10, 0x0a, 0x08, 0x04, 0x00, 0x03, 0x2e, 0x04, + 0x00, 0x02, 0x01, 0x12, 0x04, 0x9d, 0x09, 0x06, 0x18, 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, + 0x2e, 0x04, 0x00, 0x02, 0x01, 0x01, 0x12, 0x04, 0x9d, 0x09, 0x06, 0x13, 0x0a, 0x11, 0x0a, 0x09, + 0x04, 0x00, 0x03, 0x2e, 0x04, 0x00, 0x02, 0x01, 0x02, 0x12, 0x04, 0x9d, 0x09, 0x16, 0x17, 0x0a, + 0x2b, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x2e, 0x02, 0x00, 0x12, 0x04, 0xa0, 0x09, 0x04, 0x1d, 0x1a, + 0x1b, 0x2f, 0x20, 0x54, 0x68, 0x65, 0x20, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x20, 0x6f, + 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x6f, 0x6f, 0x6c, 0x2e, 0x0a, 0x0a, 0x0f, 0x0a, 0x07, + 0x04, 0x00, 0x03, 0x2e, 0x02, 0x00, 0x04, 0x12, 0x04, 0xa0, 0x09, 0x04, 0x0c, 0x0a, 0x0f, 0x0a, + 0x07, 0x04, 0x00, 0x03, 0x2e, 0x02, 0x00, 0x05, 0x12, 0x04, 0xa0, 0x09, 0x0d, 0x13, 0x0a, 0x0f, + 0x0a, 0x07, 0x04, 0x00, 0x03, 0x2e, 0x02, 0x00, 0x01, 0x12, 0x04, 0xa0, 0x09, 0x14, 0x18, 0x0a, + 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x2e, 0x02, 0x00, 0x03, 0x12, 0x04, 0xa0, 0x09, 0x1b, 0x1c, + 0x0a, 0x21, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x2e, 0x02, 0x01, 0x12, 0x04, 0xa2, 0x09, 0x04, 0x1b, + 0x1a, 0x11, 0x2f, 0x20, 0x54, 0x68, 0x65, 0x20, 0x70, 0x6f, 0x6f, 0x6c, 0x20, 0x74, 0x79, 0x70, + 0x65, 0x2e, 0x0a, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x2e, 0x02, 0x01, 0x04, 0x12, 0x04, + 0xa2, 0x09, 0x04, 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x2e, 0x02, 0x01, 0x06, 0x12, + 0x04, 0xa2, 0x09, 0x0d, 0x11, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x2e, 0x02, 0x01, 0x01, + 0x12, 0x04, 0xa2, 0x09, 0x12, 0x16, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x2e, 0x02, 0x01, + 0x03, 0x12, 0x04, 0xa2, 0x09, 0x19, 0x1a, 0x0a, 0x40, 0x0a, 0x04, 0x04, 0x00, 0x03, 0x2f, 0x12, + 0x06, 0xa6, 0x09, 0x02, 0xa9, 0x09, 0x03, 0x1a, 0x30, 0x2f, 0x20, 0x47, 0x65, 0x74, 0x20, 0x63, + 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x20, 0x74, 0x69, 0x6d, 0x65, 0x20, 0x69, 0x6e, 0x20, 0x73, + 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x20, 0x73, 0x69, 0x6e, 0x63, 0x65, 0x20, 0x55, 0x6e, 0x69, + 0x78, 0x20, 0x65, 0x70, 0x6f, 0x63, 0x68, 0x2e, 0x0a, 0x0a, 0x0d, 0x0a, 0x05, 0x04, 0x00, 0x03, + 0x2f, 0x01, 0x12, 0x04, 0xa6, 0x09, 0x0a, 0x16, 0x0a, 0x40, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x2f, + 0x02, 0x00, 0x12, 0x04, 0xa8, 0x09, 0x04, 0x1e, 0x1a, 0x30, 0x2f, 0x20, 0x54, 0x68, 0x65, 0x20, + 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x20, 0x74, 0x6f, 0x20, 0x73, 0x75, 0x62, 0x74, 0x72, 0x61, + 0x63, 0x74, 0x20, 0x66, 0x72, 0x6f, 0x6d, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x75, 0x72, 0x72, + 0x65, 0x6e, 0x74, 0x20, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x0a, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, + 0x03, 0x2f, 0x02, 0x00, 0x04, 0x12, 0x04, 0xa8, 0x09, 0x04, 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, + 0x00, 0x03, 0x2f, 0x02, 0x00, 0x05, 0x12, 0x04, 0xa8, 0x09, 0x0d, 0x12, 0x0a, 0x0f, 0x0a, 0x07, + 0x04, 0x00, 0x03, 0x2f, 0x02, 0x00, 0x01, 0x12, 0x04, 0xa8, 0x09, 0x13, 0x19, 0x0a, 0x0f, 0x0a, + 0x07, 0x04, 0x00, 0x03, 0x2f, 0x02, 0x00, 0x03, 0x12, 0x04, 0xa8, 0x09, 0x1c, 0x1d, 0x0a, 0xb9, + 0x02, 0x0a, 0x04, 0x04, 0x00, 0x03, 0x30, 0x12, 0x06, 0xb8, 0x09, 0x02, 0xc0, 0x09, 0x03, 0x1a, + 0xa8, 0x02, 0x0a, 0x46, 0x65, 0x74, 0x63, 0x68, 0x20, 0x70, 0x72, 0x69, 0x63, 0x69, 0x6e, 0x67, + 0x20, 0x69, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x66, 0x6f, 0x72, + 0x20, 0x4d, 0x61, 0x70, 0x6c, 0x65, 0x20, 0x46, 0x69, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x20, 0x61, + 0x73, 0x73, 0x65, 0x74, 0x73, 0x2e, 0x0a, 0x0a, 0x5f, 0x2a, 0x2a, 0x49, 0x6e, 0x70, 0x75, 0x74, + 0x2a, 0x2a, 0x5f, 0x3a, 0x20, 0x4e, 0x6f, 0x6e, 0x65, 0x0a, 0x0a, 0x5f, 0x2a, 0x2a, 0x52, 0x65, + 0x74, 0x75, 0x72, 0x6e, 0x73, 0x2a, 0x2a, 0x5f, 0x3a, 0x20, 0x54, 0x68, 0x65, 0x20, 0x72, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x65, 0x64, 0x20, 0x70, 0x72, 0x69, 0x63, 0x65, 0x20, 0x6f, 0x72, + 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x20, 0x62, 0x61, 0x73, 0x65, 0x64, 0x20, 0x6f, 0x6e, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x73, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x65, 0x64, 0x20, 0x6d, 0x65, + 0x74, 0x68, 0x6f, 0x64, 0x2e, 0x0a, 0x0a, 0x5f, 0x2a, 0x2a, 0x45, 0x78, 0x61, 0x6d, 0x70, 0x6c, + 0x65, 0x2a, 0x2a, 0x5f, 0x3a, 0x20, 0x46, 0x65, 0x74, 0x63, 0x68, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x73, 0x79, 0x72, 0x75, 0x70, 0x55, 0x53, 0x44, 0x43, 0x20, 0x66, 0x61, 0x69, 0x72, 0x20, 0x70, + 0x72, 0x69, 0x63, 0x65, 0x20, 0x66, 0x72, 0x6f, 0x6d, 0x20, 0x4d, 0x61, 0x70, 0x6c, 0x65, 0x20, + 0x46, 0x69, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x0a, 0x0a, 0x60, 0x60, 0x60, 0x6a, 0x73, 0x6f, 0x6e, + 0x0a, 0x7b, 0x20, 0x22, 0x6d, 0x61, 0x70, 0x6c, 0x65, 0x46, 0x69, 0x6e, 0x61, 0x6e, 0x63, 0x65, + 0x54, 0x61, 0x73, 0x6b, 0x22, 0x3a, 0x20, 0x7b, 0x20, 0x22, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, + 0x22, 0x3a, 0x20, 0x22, 0x4d, 0x45, 0x54, 0x48, 0x4f, 0x44, 0x5f, 0x53, 0x59, 0x52, 0x55, 0x50, + 0x5f, 0x55, 0x53, 0x44, 0x43, 0x5f, 0x46, 0x41, 0x49, 0x52, 0x5f, 0x50, 0x52, 0x49, 0x43, 0x45, + 0x22, 0x20, 0x7d, 0x20, 0x7d, 0x0a, 0x60, 0x60, 0x60, 0x0a, 0x0a, 0x0d, 0x0a, 0x05, 0x04, 0x00, + 0x03, 0x30, 0x01, 0x12, 0x04, 0xb8, 0x09, 0x0a, 0x1a, 0x0a, 0x51, 0x0a, 0x06, 0x04, 0x00, 0x03, + 0x30, 0x04, 0x00, 0x12, 0x06, 0xba, 0x09, 0x04, 0xbd, 0x09, 0x05, 0x1a, 0x3f, 0x2f, 0x20, 0x53, + 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x65, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6d, 0x65, 0x74, + 0x68, 0x6f, 0x64, 0x20, 0x74, 0x6f, 0x20, 0x75, 0x73, 0x65, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x66, + 0x65, 0x74, 0x63, 0x68, 0x69, 0x6e, 0x67, 0x20, 0x4d, 0x61, 0x70, 0x6c, 0x65, 0x20, 0x46, 0x69, + 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x20, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x0a, 0x0a, 0x0f, 0x0a, 0x07, + 0x04, 0x00, 0x03, 0x30, 0x04, 0x00, 0x01, 0x12, 0x04, 0xba, 0x09, 0x09, 0x0f, 0x0a, 0x56, 0x0a, + 0x08, 0x04, 0x00, 0x03, 0x30, 0x04, 0x00, 0x02, 0x00, 0x12, 0x04, 0xbc, 0x09, 0x06, 0x27, 0x1a, + 0x44, 0x2f, 0x20, 0x46, 0x65, 0x74, 0x63, 0x68, 0x20, 0x74, 0x68, 0x65, 0x20, 0x66, 0x61, 0x69, + 0x72, 0x20, 0x70, 0x72, 0x69, 0x63, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x73, 0x79, 0x72, 0x75, 0x70, + 0x55, 0x53, 0x44, 0x43, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x4d, 0x61, 0x70, 0x6c, + 0x65, 0x20, 0x46, 0x69, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x20, 0x65, 0x63, 0x6f, 0x73, 0x79, 0x73, + 0x74, 0x65, 0x6d, 0x2e, 0x0a, 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x30, 0x04, 0x00, 0x02, + 0x00, 0x01, 0x12, 0x04, 0xbc, 0x09, 0x06, 0x22, 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x30, + 0x04, 0x00, 0x02, 0x00, 0x02, 0x12, 0x04, 0xbc, 0x09, 0x25, 0x26, 0x0a, 0x3c, 0x0a, 0x06, 0x04, + 0x00, 0x03, 0x30, 0x02, 0x00, 0x12, 0x04, 0xbf, 0x09, 0x04, 0x1f, 0x1a, 0x2c, 0x2f, 0x20, 0x54, + 0x68, 0x65, 0x20, 0x73, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x20, 0x6d, 0x65, 0x74, 0x68, + 0x6f, 0x64, 0x20, 0x74, 0x6f, 0x20, 0x75, 0x73, 0x65, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x74, 0x68, + 0x69, 0x73, 0x20, 0x74, 0x61, 0x73, 0x6b, 0x2e, 0x0a, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, + 0x30, 0x02, 0x00, 0x04, 0x12, 0x04, 0xbf, 0x09, 0x04, 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, + 0x03, 0x30, 0x02, 0x00, 0x06, 0x12, 0x04, 0xbf, 0x09, 0x0d, 0x13, 0x0a, 0x0f, 0x0a, 0x07, 0x04, + 0x00, 0x03, 0x30, 0x02, 0x00, 0x01, 0x12, 0x04, 0xbf, 0x09, 0x14, 0x1a, 0x0a, 0x0f, 0x0a, 0x07, + 0x04, 0x00, 0x03, 0x30, 0x02, 0x00, 0x03, 0x12, 0x04, 0xbf, 0x09, 0x1d, 0x1e, 0x0a, 0x0e, 0x0a, + 0x04, 0x04, 0x00, 0x03, 0x31, 0x12, 0x06, 0xc2, 0x09, 0x02, 0xc5, 0x09, 0x03, 0x0a, 0x0d, 0x0a, + 0x05, 0x04, 0x00, 0x03, 0x31, 0x01, 0x12, 0x04, 0xc2, 0x09, 0x0a, 0x13, 0x0a, 0x0e, 0x0a, 0x06, + 0x04, 0x00, 0x03, 0x31, 0x02, 0x00, 0x12, 0x04, 0xc3, 0x09, 0x04, 0x25, 0x0a, 0x0f, 0x0a, 0x07, + 0x04, 0x00, 0x03, 0x31, 0x02, 0x00, 0x04, 0x12, 0x04, 0xc3, 0x09, 0x04, 0x0c, 0x0a, 0x0f, 0x0a, + 0x07, 0x04, 0x00, 0x03, 0x31, 0x02, 0x00, 0x05, 0x12, 0x04, 0xc3, 0x09, 0x0d, 0x13, 0x0a, 0x0f, + 0x0a, 0x07, 0x04, 0x00, 0x03, 0x31, 0x02, 0x00, 0x01, 0x12, 0x04, 0xc3, 0x09, 0x14, 0x20, 0x0a, + 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x31, 0x02, 0x00, 0x03, 0x12, 0x04, 0xc3, 0x09, 0x23, 0x24, + 0x0a, 0x0e, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x31, 0x02, 0x01, 0x12, 0x04, 0xc4, 0x09, 0x04, 0x23, + 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x31, 0x02, 0x01, 0x04, 0x12, 0x04, 0xc4, 0x09, 0x04, + 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x31, 0x02, 0x01, 0x05, 0x12, 0x04, 0xc4, 0x09, + 0x0d, 0x11, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x31, 0x02, 0x01, 0x01, 0x12, 0x04, 0xc4, + 0x09, 0x12, 0x1e, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x31, 0x02, 0x01, 0x03, 0x12, 0x04, + 0xc4, 0x09, 0x21, 0x22, 0x0a, 0x0e, 0x0a, 0x04, 0x04, 0x00, 0x03, 0x32, 0x12, 0x06, 0xc7, 0x09, + 0x02, 0xcb, 0x09, 0x03, 0x0a, 0x0d, 0x0a, 0x05, 0x04, 0x00, 0x03, 0x32, 0x01, 0x12, 0x04, 0xc7, + 0x09, 0x0a, 0x13, 0x0a, 0x0e, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x32, 0x02, 0x00, 0x12, 0x04, 0xc8, + 0x09, 0x04, 0x21, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x32, 0x02, 0x00, 0x04, 0x12, 0x04, + 0xc8, 0x09, 0x04, 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x32, 0x02, 0x00, 0x05, 0x12, + 0x04, 0xc8, 0x09, 0x0d, 0x13, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x32, 0x02, 0x00, 0x01, + 0x12, 0x04, 0xc8, 0x09, 0x14, 0x1c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x32, 0x02, 0x00, + 0x03, 0x12, 0x04, 0xc8, 0x09, 0x1f, 0x20, 0x0a, 0x0e, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x32, 0x02, + 0x01, 0x12, 0x04, 0xc9, 0x09, 0x04, 0x22, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x32, 0x02, + 0x01, 0x04, 0x12, 0x04, 0xc9, 0x09, 0x04, 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x32, + 0x02, 0x01, 0x05, 0x12, 0x04, 0xc9, 0x09, 0x0d, 0x13, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, + 0x32, 0x02, 0x01, 0x01, 0x12, 0x04, 0xc9, 0x09, 0x14, 0x1d, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, + 0x03, 0x32, 0x02, 0x01, 0x03, 0x12, 0x04, 0xc9, 0x09, 0x20, 0x21, 0x0a, 0x0e, 0x0a, 0x06, 0x04, + 0x00, 0x03, 0x32, 0x02, 0x02, 0x12, 0x04, 0xca, 0x09, 0x04, 0x21, 0x0a, 0x0f, 0x0a, 0x07, 0x04, + 0x00, 0x03, 0x32, 0x02, 0x02, 0x04, 0x12, 0x04, 0xca, 0x09, 0x04, 0x0c, 0x0a, 0x0f, 0x0a, 0x07, + 0x04, 0x00, 0x03, 0x32, 0x02, 0x02, 0x05, 0x12, 0x04, 0xca, 0x09, 0x0d, 0x13, 0x0a, 0x0f, 0x0a, + 0x07, 0x04, 0x00, 0x03, 0x32, 0x02, 0x02, 0x01, 0x12, 0x04, 0xca, 0x09, 0x14, 0x1c, 0x0a, 0x0f, + 0x0a, 0x07, 0x04, 0x00, 0x03, 0x32, 0x02, 0x02, 0x03, 0x12, 0x04, 0xca, 0x09, 0x1f, 0x20, 0x0a, + 0x0e, 0x0a, 0x04, 0x04, 0x00, 0x03, 0x33, 0x12, 0x06, 0xcd, 0x09, 0x02, 0xd2, 0x09, 0x03, 0x0a, + 0x0d, 0x0a, 0x05, 0x04, 0x00, 0x03, 0x33, 0x01, 0x12, 0x04, 0xcd, 0x09, 0x0a, 0x17, 0x0a, 0x0e, + 0x0a, 0x06, 0x04, 0x00, 0x03, 0x33, 0x02, 0x00, 0x12, 0x04, 0xce, 0x09, 0x04, 0x25, 0x0a, 0x0f, + 0x0a, 0x07, 0x04, 0x00, 0x03, 0x33, 0x02, 0x00, 0x04, 0x12, 0x04, 0xce, 0x09, 0x04, 0x0c, 0x0a, + 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x33, 0x02, 0x00, 0x05, 0x12, 0x04, 0xce, 0x09, 0x0d, 0x13, + 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x33, 0x02, 0x00, 0x01, 0x12, 0x04, 0xce, 0x09, 0x14, + 0x20, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x33, 0x02, 0x00, 0x03, 0x12, 0x04, 0xce, 0x09, + 0x23, 0x24, 0x0a, 0x0e, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x33, 0x02, 0x01, 0x12, 0x04, 0xcf, 0x09, + 0x04, 0x22, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x33, 0x02, 0x01, 0x04, 0x12, 0x04, 0xcf, + 0x09, 0x04, 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x33, 0x02, 0x01, 0x05, 0x12, 0x04, + 0xcf, 0x09, 0x0d, 0x13, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x33, 0x02, 0x01, 0x01, 0x12, + 0x04, 0xcf, 0x09, 0x14, 0x1d, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x33, 0x02, 0x01, 0x03, + 0x12, 0x04, 0xcf, 0x09, 0x20, 0x21, 0x0a, 0x0e, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x33, 0x02, 0x02, + 0x12, 0x04, 0xd0, 0x09, 0x04, 0x25, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x33, 0x02, 0x02, + 0x04, 0x12, 0x04, 0xd0, 0x09, 0x04, 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x33, 0x02, + 0x02, 0x05, 0x12, 0x04, 0xd0, 0x09, 0x0d, 0x13, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x33, + 0x02, 0x02, 0x01, 0x12, 0x04, 0xd0, 0x09, 0x14, 0x20, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, + 0x33, 0x02, 0x02, 0x03, 0x12, 0x04, 0xd0, 0x09, 0x23, 0x24, 0x0a, 0x0e, 0x0a, 0x06, 0x04, 0x00, + 0x03, 0x33, 0x02, 0x03, 0x12, 0x04, 0xd1, 0x09, 0x04, 0x26, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, + 0x03, 0x33, 0x02, 0x03, 0x04, 0x12, 0x04, 0xd1, 0x09, 0x04, 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, + 0x00, 0x03, 0x33, 0x02, 0x03, 0x05, 0x12, 0x04, 0xd1, 0x09, 0x0d, 0x13, 0x0a, 0x0f, 0x0a, 0x07, + 0x04, 0x00, 0x03, 0x33, 0x02, 0x03, 0x01, 0x12, 0x04, 0xd1, 0x09, 0x14, 0x21, 0x0a, 0x0f, 0x0a, + 0x07, 0x04, 0x00, 0x03, 0x33, 0x02, 0x03, 0x03, 0x12, 0x04, 0xd1, 0x09, 0x24, 0x25, 0x0a, 0xd6, + 0x03, 0x0a, 0x04, 0x04, 0x00, 0x03, 0x34, 0x12, 0x06, 0xeb, 0x09, 0x02, 0x86, 0x0a, 0x03, 0x1a, + 0xc5, 0x03, 0x0a, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x61, 0x63, 0x74, 0x73, 0x20, 0x77, 0x69, 0x74, + 0x68, 0x20, 0x61, 0x20, 0x4c, 0x61, 0x72, 0x67, 0x65, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x75, 0x61, + 0x67, 0x65, 0x20, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x20, 0x28, 0x4c, 0x4c, 0x4d, 0x29, 0x20, 0x74, + 0x6f, 0x20, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x20, 0x61, 0x20, 0x74, 0x65, 0x78, + 0x74, 0x20, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x20, 0x62, 0x61, 0x73, 0x65, 0x64, + 0x20, 0x6f, 0x6e, 0x20, 0x61, 0x20, 0x75, 0x73, 0x65, 0x72, 0x2d, 0x70, 0x72, 0x6f, 0x76, 0x69, + 0x64, 0x65, 0x64, 0x20, 0x70, 0x72, 0x6f, 0x6d, 0x70, 0x74, 0x2e, 0x0a, 0x0a, 0x5f, 0x2a, 0x2a, + 0x49, 0x6e, 0x70, 0x75, 0x74, 0x2a, 0x2a, 0x5f, 0x3a, 0x20, 0x4e, 0x6f, 0x6e, 0x65, 0x0a, 0x0a, + 0x5f, 0x2a, 0x2a, 0x52, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x73, 0x2a, 0x2a, 0x5f, 0x3a, 0x20, 0x54, + 0x65, 0x78, 0x74, 0x20, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x20, 0x62, 0x79, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x4c, 0x4c, 0x4d, 0x20, 0x62, 0x61, 0x73, 0x65, 0x64, 0x20, 0x6f, + 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x64, 0x20, 0x70, + 0x72, 0x6f, 0x6d, 0x70, 0x74, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, + 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x0a, 0x0a, 0x5f, 0x2a, 0x2a, 0x45, 0x78, 0x61, + 0x6d, 0x70, 0x6c, 0x65, 0x2a, 0x2a, 0x5f, 0x3a, 0x20, 0x55, 0x73, 0x69, 0x6e, 0x67, 0x20, 0x4f, + 0x70, 0x65, 0x6e, 0x41, 0x49, 0x27, 0x73, 0x20, 0x47, 0x50, 0x54, 0x2d, 0x34, 0x20, 0x6d, 0x6f, + 0x64, 0x65, 0x6c, 0x20, 0x74, 0x6f, 0x20, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x20, + 0x61, 0x20, 0x6a, 0x6f, 0x6b, 0x65, 0x2e, 0x0a, 0x0a, 0x60, 0x60, 0x60, 0x6a, 0x73, 0x6f, 0x6e, + 0x0a, 0x7b, 0x0a, 0x22, 0x6c, 0x6c, 0x6d, 0x54, 0x61, 0x73, 0x6b, 0x22, 0x3a, 0x20, 0x7b, 0x0a, + 0x22, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22, + 0x3a, 0x20, 0x7b, 0x0a, 0x22, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x69, 0x22, 0x3a, 0x20, 0x7b, 0x0a, + 0x22, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x22, 0x3a, 0x20, 0x22, 0x67, 0x70, 0x74, 0x2d, 0x34, 0x22, + 0x2c, 0x0a, 0x22, 0x75, 0x73, 0x65, 0x72, 0x50, 0x72, 0x6f, 0x6d, 0x70, 0x74, 0x22, 0x3a, 0x20, + 0x22, 0x54, 0x65, 0x6c, 0x6c, 0x20, 0x6d, 0x65, 0x20, 0x61, 0x20, 0x6a, 0x6f, 0x6b, 0x65, 0x2e, + 0x22, 0x2c, 0x0a, 0x22, 0x74, 0x65, 0x6d, 0x70, 0x65, 0x72, 0x61, 0x74, 0x75, 0x72, 0x65, 0x22, + 0x3a, 0x20, 0x30, 0x2e, 0x37, 0x2c, 0x0a, 0x22, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x4e, 0x61, + 0x6d, 0x65, 0x41, 0x70, 0x69, 0x4b, 0x65, 0x79, 0x22, 0x3a, 0x20, 0x22, 0x24, 0x7b, 0x4f, 0x50, + 0x45, 0x4e, 0x41, 0x49, 0x5f, 0x41, 0x50, 0x49, 0x5f, 0x4b, 0x45, 0x59, 0x7d, 0x22, 0x0a, 0x7d, + 0x0a, 0x7d, 0x0a, 0x7d, 0x0a, 0x7d, 0x0a, 0x0a, 0x0d, 0x0a, 0x05, 0x04, 0x00, 0x03, 0x34, 0x01, + 0x12, 0x04, 0xeb, 0x09, 0x0a, 0x11, 0x0a, 0x10, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x34, 0x03, 0x00, + 0x12, 0x06, 0xec, 0x09, 0x04, 0xf1, 0x09, 0x05, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x34, + 0x03, 0x00, 0x01, 0x12, 0x04, 0xec, 0x09, 0x0c, 0x18, 0x0a, 0x10, 0x0a, 0x08, 0x04, 0x00, 0x03, + 0x34, 0x03, 0x00, 0x02, 0x00, 0x12, 0x04, 0xed, 0x09, 0x06, 0x20, 0x0a, 0x11, 0x0a, 0x09, 0x04, + 0x00, 0x03, 0x34, 0x03, 0x00, 0x02, 0x00, 0x04, 0x12, 0x04, 0xed, 0x09, 0x06, 0x0e, 0x0a, 0x11, + 0x0a, 0x09, 0x04, 0x00, 0x03, 0x34, 0x03, 0x00, 0x02, 0x00, 0x05, 0x12, 0x04, 0xed, 0x09, 0x0f, + 0x15, 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x34, 0x03, 0x00, 0x02, 0x00, 0x01, 0x12, 0x04, + 0xed, 0x09, 0x16, 0x1b, 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x34, 0x03, 0x00, 0x02, 0x00, + 0x03, 0x12, 0x04, 0xed, 0x09, 0x1e, 0x1f, 0x0a, 0x10, 0x0a, 0x08, 0x04, 0x00, 0x03, 0x34, 0x03, + 0x00, 0x02, 0x01, 0x12, 0x04, 0xee, 0x09, 0x06, 0x26, 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, + 0x34, 0x03, 0x00, 0x02, 0x01, 0x04, 0x12, 0x04, 0xee, 0x09, 0x06, 0x0e, 0x0a, 0x11, 0x0a, 0x09, + 0x04, 0x00, 0x03, 0x34, 0x03, 0x00, 0x02, 0x01, 0x05, 0x12, 0x04, 0xee, 0x09, 0x0f, 0x15, 0x0a, + 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x34, 0x03, 0x00, 0x02, 0x01, 0x01, 0x12, 0x04, 0xee, 0x09, + 0x16, 0x21, 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x34, 0x03, 0x00, 0x02, 0x01, 0x03, 0x12, + 0x04, 0xee, 0x09, 0x24, 0x25, 0x0a, 0x10, 0x0a, 0x08, 0x04, 0x00, 0x03, 0x34, 0x03, 0x00, 0x02, + 0x02, 0x12, 0x04, 0xef, 0x09, 0x06, 0x26, 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x34, 0x03, + 0x00, 0x02, 0x02, 0x04, 0x12, 0x04, 0xef, 0x09, 0x06, 0x0e, 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, + 0x03, 0x34, 0x03, 0x00, 0x02, 0x02, 0x05, 0x12, 0x04, 0xef, 0x09, 0x0f, 0x15, 0x0a, 0x11, 0x0a, + 0x09, 0x04, 0x00, 0x03, 0x34, 0x03, 0x00, 0x02, 0x02, 0x01, 0x12, 0x04, 0xef, 0x09, 0x16, 0x21, + 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x34, 0x03, 0x00, 0x02, 0x02, 0x03, 0x12, 0x04, 0xef, + 0x09, 0x24, 0x25, 0x0a, 0x10, 0x0a, 0x08, 0x04, 0x00, 0x03, 0x34, 0x03, 0x00, 0x02, 0x03, 0x12, + 0x04, 0xf0, 0x09, 0x06, 0x2e, 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x34, 0x03, 0x00, 0x02, + 0x03, 0x04, 0x12, 0x04, 0xf0, 0x09, 0x06, 0x0e, 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x34, + 0x03, 0x00, 0x02, 0x03, 0x05, 0x12, 0x04, 0xf0, 0x09, 0x0f, 0x15, 0x0a, 0x11, 0x0a, 0x09, 0x04, + 0x00, 0x03, 0x34, 0x03, 0x00, 0x02, 0x03, 0x01, 0x12, 0x04, 0xf0, 0x09, 0x16, 0x29, 0x0a, 0x11, + 0x0a, 0x09, 0x04, 0x00, 0x03, 0x34, 0x03, 0x00, 0x02, 0x03, 0x03, 0x12, 0x04, 0xf0, 0x09, 0x2c, + 0x2d, 0x0a, 0x10, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x34, 0x03, 0x01, 0x12, 0x06, 0xf3, 0x09, 0x04, + 0xf8, 0x09, 0x05, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x34, 0x03, 0x01, 0x01, 0x12, 0x04, + 0xf3, 0x09, 0x0c, 0x16, 0x0a, 0x10, 0x0a, 0x08, 0x04, 0x00, 0x03, 0x34, 0x03, 0x01, 0x02, 0x00, + 0x12, 0x04, 0xf4, 0x09, 0x06, 0x20, 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x34, 0x03, 0x01, + 0x02, 0x00, 0x04, 0x12, 0x04, 0xf4, 0x09, 0x06, 0x0e, 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, + 0x34, 0x03, 0x01, 0x02, 0x00, 0x05, 0x12, 0x04, 0xf4, 0x09, 0x0f, 0x15, 0x0a, 0x11, 0x0a, 0x09, + 0x04, 0x00, 0x03, 0x34, 0x03, 0x01, 0x02, 0x00, 0x01, 0x12, 0x04, 0xf4, 0x09, 0x16, 0x1b, 0x0a, + 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x34, 0x03, 0x01, 0x02, 0x00, 0x03, 0x12, 0x04, 0xf4, 0x09, + 0x1e, 0x1f, 0x0a, 0x10, 0x0a, 0x08, 0x04, 0x00, 0x03, 0x34, 0x03, 0x01, 0x02, 0x01, 0x12, 0x04, + 0xf5, 0x09, 0x06, 0x26, 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x34, 0x03, 0x01, 0x02, 0x01, + 0x04, 0x12, 0x04, 0xf5, 0x09, 0x06, 0x0e, 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x34, 0x03, + 0x01, 0x02, 0x01, 0x05, 0x12, 0x04, 0xf5, 0x09, 0x0f, 0x15, 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, + 0x03, 0x34, 0x03, 0x01, 0x02, 0x01, 0x01, 0x12, 0x04, 0xf5, 0x09, 0x16, 0x21, 0x0a, 0x11, 0x0a, + 0x09, 0x04, 0x00, 0x03, 0x34, 0x03, 0x01, 0x02, 0x01, 0x03, 0x12, 0x04, 0xf5, 0x09, 0x24, 0x25, + 0x0a, 0x10, 0x0a, 0x08, 0x04, 0x00, 0x03, 0x34, 0x03, 0x01, 0x02, 0x02, 0x12, 0x04, 0xf6, 0x09, + 0x06, 0x26, 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x34, 0x03, 0x01, 0x02, 0x02, 0x04, 0x12, + 0x04, 0xf6, 0x09, 0x06, 0x0e, 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x34, 0x03, 0x01, 0x02, + 0x02, 0x05, 0x12, 0x04, 0xf6, 0x09, 0x0f, 0x15, 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x34, + 0x03, 0x01, 0x02, 0x02, 0x01, 0x12, 0x04, 0xf6, 0x09, 0x16, 0x21, 0x0a, 0x11, 0x0a, 0x09, 0x04, + 0x00, 0x03, 0x34, 0x03, 0x01, 0x02, 0x02, 0x03, 0x12, 0x04, 0xf6, 0x09, 0x24, 0x25, 0x0a, 0x10, + 0x0a, 0x08, 0x04, 0x00, 0x03, 0x34, 0x03, 0x01, 0x02, 0x03, 0x12, 0x04, 0xf7, 0x09, 0x06, 0x2e, + 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x34, 0x03, 0x01, 0x02, 0x03, 0x04, 0x12, 0x04, 0xf7, + 0x09, 0x06, 0x0e, 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x34, 0x03, 0x01, 0x02, 0x03, 0x05, + 0x12, 0x04, 0xf7, 0x09, 0x0f, 0x15, 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x34, 0x03, 0x01, + 0x02, 0x03, 0x01, 0x12, 0x04, 0xf7, 0x09, 0x16, 0x29, 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, + 0x34, 0x03, 0x01, 0x02, 0x03, 0x03, 0x12, 0x04, 0xf7, 0x09, 0x2c, 0x2d, 0x0a, 0x10, 0x0a, 0x06, + 0x04, 0x00, 0x03, 0x34, 0x03, 0x02, 0x12, 0x06, 0xfa, 0x09, 0x04, 0xff, 0x09, 0x05, 0x0a, 0x0f, + 0x0a, 0x07, 0x04, 0x00, 0x03, 0x34, 0x03, 0x02, 0x01, 0x12, 0x04, 0xfa, 0x09, 0x0c, 0x19, 0x0a, + 0x10, 0x0a, 0x08, 0x04, 0x00, 0x03, 0x34, 0x03, 0x02, 0x02, 0x00, 0x12, 0x04, 0xfb, 0x09, 0x06, + 0x20, 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x34, 0x03, 0x02, 0x02, 0x00, 0x04, 0x12, 0x04, + 0xfb, 0x09, 0x06, 0x0e, 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x34, 0x03, 0x02, 0x02, 0x00, + 0x05, 0x12, 0x04, 0xfb, 0x09, 0x0f, 0x15, 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x34, 0x03, + 0x02, 0x02, 0x00, 0x01, 0x12, 0x04, 0xfb, 0x09, 0x16, 0x1b, 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, + 0x03, 0x34, 0x03, 0x02, 0x02, 0x00, 0x03, 0x12, 0x04, 0xfb, 0x09, 0x1e, 0x1f, 0x0a, 0x10, 0x0a, + 0x08, 0x04, 0x00, 0x03, 0x34, 0x03, 0x02, 0x02, 0x01, 0x12, 0x04, 0xfc, 0x09, 0x06, 0x26, 0x0a, + 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x34, 0x03, 0x02, 0x02, 0x01, 0x04, 0x12, 0x04, 0xfc, 0x09, + 0x06, 0x0e, 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x34, 0x03, 0x02, 0x02, 0x01, 0x05, 0x12, + 0x04, 0xfc, 0x09, 0x0f, 0x15, 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x34, 0x03, 0x02, 0x02, + 0x01, 0x01, 0x12, 0x04, 0xfc, 0x09, 0x16, 0x21, 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x34, + 0x03, 0x02, 0x02, 0x01, 0x03, 0x12, 0x04, 0xfc, 0x09, 0x24, 0x25, 0x0a, 0x10, 0x0a, 0x08, 0x04, + 0x00, 0x03, 0x34, 0x03, 0x02, 0x02, 0x02, 0x12, 0x04, 0xfd, 0x09, 0x06, 0x26, 0x0a, 0x11, 0x0a, + 0x09, 0x04, 0x00, 0x03, 0x34, 0x03, 0x02, 0x02, 0x02, 0x04, 0x12, 0x04, 0xfd, 0x09, 0x06, 0x0e, + 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x34, 0x03, 0x02, 0x02, 0x02, 0x05, 0x12, 0x04, 0xfd, + 0x09, 0x0f, 0x15, 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x34, 0x03, 0x02, 0x02, 0x02, 0x01, + 0x12, 0x04, 0xfd, 0x09, 0x16, 0x21, 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x34, 0x03, 0x02, + 0x02, 0x02, 0x03, 0x12, 0x04, 0xfd, 0x09, 0x24, 0x25, 0x0a, 0x10, 0x0a, 0x08, 0x04, 0x00, 0x03, + 0x34, 0x03, 0x02, 0x02, 0x03, 0x12, 0x04, 0xfe, 0x09, 0x06, 0x2e, 0x0a, 0x11, 0x0a, 0x09, 0x04, + 0x00, 0x03, 0x34, 0x03, 0x02, 0x02, 0x03, 0x04, 0x12, 0x04, 0xfe, 0x09, 0x06, 0x0e, 0x0a, 0x11, + 0x0a, 0x09, 0x04, 0x00, 0x03, 0x34, 0x03, 0x02, 0x02, 0x03, 0x05, 0x12, 0x04, 0xfe, 0x09, 0x0f, + 0x15, 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x34, 0x03, 0x02, 0x02, 0x03, 0x01, 0x12, 0x04, + 0xfe, 0x09, 0x16, 0x29, 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x34, 0x03, 0x02, 0x02, 0x03, + 0x03, 0x12, 0x04, 0xfe, 0x09, 0x2c, 0x2d, 0x0a, 0x10, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x34, 0x08, + 0x00, 0x12, 0x06, 0x81, 0x0a, 0x04, 0x85, 0x0a, 0x05, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, + 0x34, 0x08, 0x00, 0x01, 0x12, 0x04, 0x81, 0x0a, 0x0a, 0x19, 0x0a, 0x0e, 0x0a, 0x06, 0x04, 0x00, + 0x03, 0x34, 0x02, 0x00, 0x12, 0x04, 0x82, 0x0a, 0x06, 0x1e, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, + 0x03, 0x34, 0x02, 0x00, 0x06, 0x12, 0x04, 0x82, 0x0a, 0x06, 0x12, 0x0a, 0x0f, 0x0a, 0x07, 0x04, + 0x00, 0x03, 0x34, 0x02, 0x00, 0x01, 0x12, 0x04, 0x82, 0x0a, 0x13, 0x19, 0x0a, 0x0f, 0x0a, 0x07, + 0x04, 0x00, 0x03, 0x34, 0x02, 0x00, 0x03, 0x12, 0x04, 0x82, 0x0a, 0x1c, 0x1d, 0x0a, 0x0e, 0x0a, + 0x06, 0x04, 0x00, 0x03, 0x34, 0x02, 0x01, 0x12, 0x04, 0x83, 0x0a, 0x06, 0x1a, 0x0a, 0x0f, 0x0a, + 0x07, 0x04, 0x00, 0x03, 0x34, 0x02, 0x01, 0x06, 0x12, 0x04, 0x83, 0x0a, 0x06, 0x10, 0x0a, 0x0f, + 0x0a, 0x07, 0x04, 0x00, 0x03, 0x34, 0x02, 0x01, 0x01, 0x12, 0x04, 0x83, 0x0a, 0x11, 0x15, 0x0a, + 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x34, 0x02, 0x01, 0x03, 0x12, 0x04, 0x83, 0x0a, 0x18, 0x19, + 0x0a, 0x0e, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x34, 0x02, 0x02, 0x12, 0x04, 0x84, 0x0a, 0x06, 0x20, + 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x34, 0x02, 0x02, 0x06, 0x12, 0x04, 0x84, 0x0a, 0x06, + 0x13, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x34, 0x02, 0x02, 0x01, 0x12, 0x04, 0x84, 0x0a, + 0x14, 0x1b, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x34, 0x02, 0x02, 0x03, 0x12, 0x04, 0x84, + 0x0a, 0x1e, 0x1f, 0x0a, 0xa8, 0x02, 0x0a, 0x04, 0x04, 0x00, 0x03, 0x35, 0x12, 0x04, 0x95, 0x0a, + 0x02, 0x1c, 0x1a, 0x99, 0x02, 0x0a, 0x46, 0x65, 0x74, 0x63, 0x68, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x20, 0x70, 0x72, 0x69, 0x63, 0x65, 0x20, 0x6f, 0x66, + 0x20, 0x53, 0x6f, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x27, 0x73, 0x20, 0x73, 0x55, 0x53, 0x44, 0x20, + 0x73, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x63, 0x6f, 0x69, 0x6e, 0x20, 0x62, 0x79, 0x20, 0x72, 0x65, + 0x61, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x69, 0x74, 0x73, 0x20, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x65, + 0x73, 0x74, 0x2d, 0x62, 0x65, 0x61, 0x72, 0x69, 0x6e, 0x67, 0x20, 0x6d, 0x69, 0x6e, 0x74, 0x20, + 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x0a, 0x0a, + 0x5f, 0x2a, 0x2a, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x2a, 0x2a, 0x5f, 0x3a, 0x20, 0x4e, 0x6f, 0x6e, + 0x65, 0x0a, 0x0a, 0x5f, 0x2a, 0x2a, 0x52, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x73, 0x2a, 0x2a, 0x5f, + 0x3a, 0x20, 0x54, 0x68, 0x65, 0x20, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x20, 0x70, 0x72, + 0x69, 0x63, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x73, 0x55, 0x53, 0x44, 0x20, 0x72, 0x65, 0x6c, 0x61, + 0x74, 0x69, 0x76, 0x65, 0x20, 0x74, 0x6f, 0x20, 0x55, 0x53, 0x44, 0x20, 0x28, 0x31, 0x2e, 0x30, + 0x20, 0x3d, 0x20, 0x24, 0x31, 0x2e, 0x30, 0x30, 0x29, 0x0a, 0x0a, 0x5f, 0x2a, 0x2a, 0x45, 0x78, + 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2a, 0x2a, 0x5f, 0x3a, 0x20, 0x46, 0x65, 0x74, 0x63, 0x68, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x20, 0x73, 0x55, 0x53, 0x44, + 0x20, 0x70, 0x72, 0x69, 0x63, 0x65, 0x0a, 0x0a, 0x60, 0x60, 0x60, 0x6a, 0x73, 0x6f, 0x6e, 0x0a, + 0x7b, 0x20, 0x22, 0x73, 0x6f, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x53, 0x75, 0x73, 0x64, 0x54, 0x61, + 0x73, 0x6b, 0x22, 0x3a, 0x20, 0x7b, 0x7d, 0x20, 0x7d, 0x0a, 0x60, 0x60, 0x60, 0x0a, 0x0a, 0x0d, + 0x0a, 0x05, 0x04, 0x00, 0x03, 0x35, 0x01, 0x12, 0x04, 0x95, 0x0a, 0x0a, 0x19, 0x0a, 0x89, 0x05, + 0x0a, 0x04, 0x04, 0x00, 0x03, 0x36, 0x12, 0x06, 0xb7, 0x0a, 0x02, 0xc4, 0x0a, 0x03, 0x1a, 0xf8, + 0x04, 0x0a, 0x46, 0x65, 0x74, 0x63, 0x68, 0x20, 0x70, 0x72, 0x69, 0x63, 0x69, 0x6e, 0x67, 0x20, + 0x69, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x66, 0x72, 0x6f, 0x6d, + 0x20, 0x43, 0x75, 0x72, 0x76, 0x65, 0x20, 0x46, 0x69, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x20, 0x70, + 0x6f, 0x6f, 0x6c, 0x73, 0x2e, 0x0a, 0x0a, 0x5f, 0x2a, 0x2a, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x2a, + 0x2a, 0x5f, 0x3a, 0x20, 0x4e, 0x6f, 0x6e, 0x65, 0x0a, 0x0a, 0x5f, 0x2a, 0x2a, 0x52, 0x65, 0x74, + 0x75, 0x72, 0x6e, 0x73, 0x2a, 0x2a, 0x5f, 0x3a, 0x20, 0x54, 0x68, 0x65, 0x20, 0x63, 0x75, 0x72, + 0x72, 0x65, 0x6e, 0x74, 0x20, 0x70, 0x72, 0x69, 0x63, 0x65, 0x2f, 0x65, 0x78, 0x63, 0x68, 0x61, + 0x6e, 0x67, 0x65, 0x20, 0x72, 0x61, 0x74, 0x65, 0x20, 0x66, 0x72, 0x6f, 0x6d, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x73, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x65, 0x64, 0x20, 0x43, 0x75, 0x72, 0x76, + 0x65, 0x20, 0x70, 0x6f, 0x6f, 0x6c, 0x2e, 0x0a, 0x0a, 0x5f, 0x2a, 0x2a, 0x45, 0x78, 0x61, 0x6d, + 0x70, 0x6c, 0x65, 0x2a, 0x2a, 0x5f, 0x3a, 0x20, 0x46, 0x65, 0x74, 0x63, 0x68, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x70, 0x72, 0x69, 0x63, 0x65, 0x20, 0x66, 0x72, 0x6f, 0x6d, 0x20, 0x61, 0x20, 0x43, + 0x75, 0x72, 0x76, 0x65, 0x20, 0x70, 0x6f, 0x6f, 0x6c, 0x20, 0x6f, 0x6e, 0x20, 0x45, 0x74, 0x68, + 0x65, 0x72, 0x65, 0x75, 0x6d, 0x0a, 0x0a, 0x60, 0x60, 0x60, 0x6a, 0x73, 0x6f, 0x6e, 0x0a, 0x7b, + 0x0a, 0x22, 0x63, 0x75, 0x72, 0x76, 0x65, 0x46, 0x69, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x54, 0x61, + 0x73, 0x6b, 0x22, 0x3a, 0x20, 0x7b, 0x0a, 0x22, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x22, 0x3a, 0x20, + 0x22, 0x43, 0x48, 0x41, 0x49, 0x4e, 0x5f, 0x45, 0x54, 0x48, 0x45, 0x52, 0x45, 0x55, 0x4d, 0x22, + 0x2c, 0x0a, 0x22, 0x70, 0x6f, 0x6f, 0x6c, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x22, 0x3a, + 0x20, 0x22, 0x30, 0x78, 0x62, 0x65, 0x62, 0x63, 0x34, 0x34, 0x37, 0x38, 0x32, 0x63, 0x37, 0x64, + 0x62, 0x30, 0x61, 0x31, 0x61, 0x36, 0x30, 0x63, 0x62, 0x36, 0x66, 0x65, 0x39, 0x37, 0x64, 0x30, + 0x62, 0x34, 0x38, 0x33, 0x30, 0x33, 0x32, 0x66, 0x66, 0x31, 0x63, 0x37, 0x22, 0x2c, 0x0a, 0x22, + 0x6f, 0x75, 0x74, 0x44, 0x65, 0x63, 0x69, 0x6d, 0x61, 0x6c, 0x73, 0x22, 0x3a, 0x20, 0x31, 0x38, + 0x0a, 0x7d, 0x0a, 0x7d, 0x0a, 0x60, 0x60, 0x60, 0x0a, 0x0a, 0x5f, 0x2a, 0x2a, 0x45, 0x78, 0x61, + 0x6d, 0x70, 0x6c, 0x65, 0x2a, 0x2a, 0x5f, 0x3a, 0x20, 0x46, 0x65, 0x74, 0x63, 0x68, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x70, 0x72, 0x69, 0x63, 0x65, 0x20, 0x75, 0x73, 0x69, 0x6e, 0x67, 0x20, 0x61, + 0x20, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x20, 0x52, 0x50, 0x43, 0x20, 0x70, 0x72, 0x6f, 0x76, + 0x69, 0x64, 0x65, 0x72, 0x0a, 0x0a, 0x60, 0x60, 0x60, 0x6a, 0x73, 0x6f, 0x6e, 0x0a, 0x7b, 0x0a, + 0x22, 0x63, 0x75, 0x72, 0x76, 0x65, 0x46, 0x69, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x54, 0x61, 0x73, + 0x6b, 0x22, 0x3a, 0x20, 0x7b, 0x0a, 0x22, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x22, 0x3a, 0x20, 0x22, + 0x43, 0x48, 0x41, 0x49, 0x4e, 0x5f, 0x45, 0x54, 0x48, 0x45, 0x52, 0x45, 0x55, 0x4d, 0x22, 0x2c, + 0x0a, 0x22, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x22, 0x3a, 0x20, 0x22, 0x68, 0x74, + 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x65, 0x74, 0x68, 0x2d, 0x6d, 0x61, 0x69, 0x6e, 0x6e, 0x65, + 0x74, 0x2e, 0x67, 0x2e, 0x61, 0x6c, 0x63, 0x68, 0x65, 0x6d, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, + 0x76, 0x32, 0x2f, 0x59, 0x4f, 0x55, 0x52, 0x2d, 0x41, 0x50, 0x49, 0x2d, 0x4b, 0x45, 0x59, 0x22, + 0x2c, 0x0a, 0x22, 0x70, 0x6f, 0x6f, 0x6c, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x22, 0x3a, + 0x20, 0x22, 0x30, 0x78, 0x62, 0x65, 0x62, 0x63, 0x34, 0x34, 0x37, 0x38, 0x32, 0x63, 0x37, 0x64, + 0x62, 0x30, 0x61, 0x31, 0x61, 0x36, 0x30, 0x63, 0x62, 0x36, 0x66, 0x65, 0x39, 0x37, 0x64, 0x30, + 0x62, 0x34, 0x38, 0x33, 0x30, 0x33, 0x32, 0x66, 0x66, 0x31, 0x63, 0x37, 0x22, 0x2c, 0x0a, 0x22, + 0x6f, 0x75, 0x74, 0x44, 0x65, 0x63, 0x69, 0x6d, 0x61, 0x6c, 0x73, 0x22, 0x3a, 0x20, 0x31, 0x38, + 0x0a, 0x7d, 0x0a, 0x7d, 0x0a, 0x60, 0x60, 0x60, 0x0a, 0x0a, 0x0d, 0x0a, 0x05, 0x04, 0x00, 0x03, + 0x36, 0x01, 0x12, 0x04, 0xb7, 0x0a, 0x0a, 0x1a, 0x0a, 0x10, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x36, + 0x04, 0x00, 0x12, 0x06, 0xb8, 0x0a, 0x04, 0xbb, 0x0a, 0x05, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, + 0x03, 0x36, 0x04, 0x00, 0x01, 0x12, 0x04, 0xb8, 0x0a, 0x09, 0x0e, 0x0a, 0x50, 0x0a, 0x08, 0x04, + 0x00, 0x03, 0x36, 0x04, 0x00, 0x02, 0x00, 0x12, 0x04, 0xba, 0x0a, 0x06, 0x19, 0x1a, 0x3e, 0x2f, + 0x20, 0x55, 0x73, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x45, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, + 0x6d, 0x20, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x20, 0x66, 0x6f, 0x72, + 0x20, 0x66, 0x65, 0x74, 0x63, 0x68, 0x69, 0x6e, 0x67, 0x20, 0x43, 0x75, 0x72, 0x76, 0x65, 0x20, + 0x46, 0x69, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x20, 0x64, 0x61, 0x74, 0x61, 0x0a, 0x0a, 0x11, 0x0a, + 0x09, 0x04, 0x00, 0x03, 0x36, 0x04, 0x00, 0x02, 0x00, 0x01, 0x12, 0x04, 0xba, 0x0a, 0x06, 0x14, + 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x36, 0x04, 0x00, 0x02, 0x00, 0x02, 0x12, 0x04, 0xba, + 0x0a, 0x17, 0x18, 0x0a, 0x6b, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x36, 0x02, 0x00, 0x12, 0x04, 0xbd, + 0x0a, 0x04, 0x1d, 0x1a, 0x5b, 0x2f, 0x20, 0x52, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x2e, + 0x20, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x65, 0x73, 0x20, 0x77, 0x68, 0x69, 0x63, 0x68, + 0x20, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x20, 0x74, 0x6f, 0x20, 0x75, + 0x73, 0x65, 0x20, 0x77, 0x68, 0x65, 0x6e, 0x20, 0x72, 0x65, 0x61, 0x64, 0x69, 0x6e, 0x67, 0x20, + 0x69, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x66, 0x72, 0x6f, 0x6d, + 0x20, 0x43, 0x75, 0x72, 0x76, 0x65, 0x20, 0x46, 0x69, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x2e, 0x0a, + 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x36, 0x02, 0x00, 0x04, 0x12, 0x04, 0xbd, 0x0a, 0x04, + 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x36, 0x02, 0x00, 0x06, 0x12, 0x04, 0xbd, 0x0a, + 0x0d, 0x12, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x36, 0x02, 0x00, 0x01, 0x12, 0x04, 0xbd, + 0x0a, 0x13, 0x18, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x36, 0x02, 0x00, 0x03, 0x12, 0x04, + 0xbd, 0x0a, 0x1b, 0x1c, 0x0a, 0x97, 0x01, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x36, 0x02, 0x01, 0x12, + 0x04, 0xbf, 0x0a, 0x04, 0x21, 0x1a, 0x86, 0x01, 0x2f, 0x20, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, + 0x61, 0x6c, 0x2e, 0x20, 0x54, 0x68, 0x65, 0x20, 0x52, 0x50, 0x43, 0x20, 0x65, 0x6e, 0x64, 0x70, + 0x6f, 0x69, 0x6e, 0x74, 0x20, 0x74, 0x6f, 0x20, 0x75, 0x73, 0x65, 0x20, 0x66, 0x6f, 0x72, 0x20, + 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x20, 0x72, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x73, 0x2e, 0x20, 0x49, 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x73, 0x70, 0x65, 0x63, + 0x69, 0x66, 0x69, 0x65, 0x64, 0x2c, 0x20, 0x61, 0x20, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, + 0x20, 0x52, 0x50, 0x43, 0x20, 0x77, 0x69, 0x6c, 0x6c, 0x20, 0x62, 0x65, 0x20, 0x75, 0x73, 0x65, + 0x64, 0x20, 0x77, 0x68, 0x69, 0x63, 0x68, 0x20, 0x6d, 0x61, 0x79, 0x20, 0x68, 0x61, 0x76, 0x65, + 0x20, 0x72, 0x61, 0x74, 0x65, 0x20, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x73, 0x2e, 0x0a, 0x0a, 0x0f, + 0x0a, 0x07, 0x04, 0x00, 0x03, 0x36, 0x02, 0x01, 0x04, 0x12, 0x04, 0xbf, 0x0a, 0x04, 0x0c, 0x0a, + 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x36, 0x02, 0x01, 0x05, 0x12, 0x04, 0xbf, 0x0a, 0x0d, 0x13, + 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x36, 0x02, 0x01, 0x01, 0x12, 0x04, 0xbf, 0x0a, 0x14, + 0x1c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x36, 0x02, 0x01, 0x03, 0x12, 0x04, 0xbf, 0x0a, + 0x1f, 0x20, 0x0a, 0x5d, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x36, 0x02, 0x02, 0x12, 0x04, 0xc1, 0x0a, + 0x04, 0x25, 0x1a, 0x4d, 0x2f, 0x20, 0x54, 0x68, 0x65, 0x20, 0x6f, 0x6e, 0x2d, 0x63, 0x68, 0x61, + 0x69, 0x6e, 0x20, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x43, 0x75, 0x72, 0x76, 0x65, 0x20, 0x46, 0x69, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x20, + 0x70, 0x6f, 0x6f, 0x6c, 0x20, 0x74, 0x6f, 0x20, 0x66, 0x65, 0x74, 0x63, 0x68, 0x20, 0x70, 0x72, + 0x69, 0x63, 0x69, 0x6e, 0x67, 0x20, 0x64, 0x61, 0x74, 0x61, 0x20, 0x66, 0x72, 0x6f, 0x6d, 0x2e, + 0x0a, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x36, 0x02, 0x02, 0x04, 0x12, 0x04, 0xc1, 0x0a, + 0x04, 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x36, 0x02, 0x02, 0x05, 0x12, 0x04, 0xc1, + 0x0a, 0x0d, 0x13, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x36, 0x02, 0x02, 0x01, 0x12, 0x04, + 0xc1, 0x0a, 0x14, 0x20, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x36, 0x02, 0x02, 0x03, 0x12, + 0x04, 0xc1, 0x0a, 0x23, 0x24, 0x0a, 0x57, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x36, 0x02, 0x03, 0x12, + 0x04, 0xc3, 0x0a, 0x04, 0x25, 0x1a, 0x47, 0x2f, 0x20, 0x54, 0x68, 0x65, 0x20, 0x6e, 0x75, 0x6d, + 0x62, 0x65, 0x72, 0x20, 0x6f, 0x66, 0x20, 0x64, 0x65, 0x63, 0x69, 0x6d, 0x61, 0x6c, 0x20, 0x70, + 0x6c, 0x61, 0x63, 0x65, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, + 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x65, 0x64, + 0x20, 0x70, 0x72, 0x69, 0x63, 0x65, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x2e, 0x0a, 0x0a, 0x0f, + 0x0a, 0x07, 0x04, 0x00, 0x03, 0x36, 0x02, 0x03, 0x04, 0x12, 0x04, 0xc3, 0x0a, 0x04, 0x0c, 0x0a, + 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x36, 0x02, 0x03, 0x05, 0x12, 0x04, 0xc3, 0x0a, 0x0d, 0x13, + 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x36, 0x02, 0x03, 0x01, 0x12, 0x04, 0xc3, 0x0a, 0x14, + 0x20, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x36, 0x02, 0x03, 0x03, 0x12, 0x04, 0xc3, 0x0a, + 0x23, 0x24, 0x0a, 0x33, 0x0a, 0x04, 0x04, 0x00, 0x03, 0x37, 0x12, 0x06, 0xc9, 0x0a, 0x02, 0xcb, + 0x0a, 0x03, 0x1a, 0x23, 0x0a, 0x46, 0x65, 0x74, 0x63, 0x68, 0x65, 0x73, 0x20, 0x74, 0x45, 0x54, + 0x48, 0x2f, 0x57, 0x45, 0x54, 0x48, 0x20, 0x72, 0x65, 0x64, 0x65, 0x6d, 0x70, 0x74, 0x69, 0x6f, + 0x6e, 0x20, 0x72, 0x61, 0x74, 0x65, 0x0a, 0x0a, 0x0d, 0x0a, 0x05, 0x04, 0x00, 0x03, 0x37, 0x01, + 0x12, 0x04, 0xc9, 0x0a, 0x0a, 0x24, 0x0a, 0x0e, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x37, 0x02, 0x00, + 0x12, 0x04, 0xca, 0x0a, 0x04, 0x21, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x37, 0x02, 0x00, + 0x04, 0x12, 0x04, 0xca, 0x0a, 0x04, 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x37, 0x02, + 0x00, 0x05, 0x12, 0x04, 0xca, 0x0a, 0x0d, 0x13, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x37, + 0x02, 0x00, 0x01, 0x12, 0x04, 0xca, 0x0a, 0x14, 0x1c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, + 0x37, 0x02, 0x00, 0x03, 0x12, 0x04, 0xca, 0x0a, 0x1f, 0x20, 0x0a, 0xea, 0x03, 0x0a, 0x04, 0x04, + 0x00, 0x03, 0x38, 0x12, 0x06, 0xe1, 0x0a, 0x02, 0xea, 0x0a, 0x03, 0x1a, 0xd9, 0x03, 0x0a, 0x46, + 0x65, 0x74, 0x63, 0x68, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, + 0x20, 0x73, 0x77, 0x61, 0x70, 0x20, 0x70, 0x72, 0x69, 0x63, 0x65, 0x20, 0x66, 0x72, 0x6f, 0x6d, + 0x20, 0x61, 0x20, 0x42, 0x69, 0x74, 0x46, 0x6c, 0x75, 0x78, 0x20, 0x70, 0x6f, 0x6f, 0x6c, 0x2e, + 0x0a, 0x0a, 0x5f, 0x2a, 0x2a, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x2a, 0x2a, 0x5f, 0x3a, 0x20, 0x4e, + 0x6f, 0x6e, 0x65, 0x0a, 0x0a, 0x5f, 0x2a, 0x2a, 0x52, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x73, 0x2a, + 0x2a, 0x5f, 0x3a, 0x20, 0x54, 0x68, 0x65, 0x20, 0x73, 0x77, 0x61, 0x70, 0x20, 0x70, 0x72, 0x69, + 0x63, 0x65, 0x20, 0x62, 0x65, 0x74, 0x77, 0x65, 0x65, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, + 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x20, 0x61, + 0x6e, 0x64, 0x20, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x20, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x73, + 0x2e, 0x0a, 0x0a, 0x5f, 0x2a, 0x2a, 0x45, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2a, 0x2a, 0x5f, + 0x3a, 0x20, 0x46, 0x65, 0x74, 0x63, 0x68, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x77, 0x61, 0x70, + 0x20, 0x70, 0x72, 0x69, 0x63, 0x65, 0x20, 0x75, 0x73, 0x69, 0x6e, 0x67, 0x20, 0x61, 0x20, 0x63, + 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x20, 0x52, 0x50, 0x43, 0x20, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, + 0x65, 0x72, 0x0a, 0x0a, 0x60, 0x60, 0x60, 0x6a, 0x73, 0x6f, 0x6e, 0x0a, 0x7b, 0x0a, 0x22, 0x62, + 0x69, 0x74, 0x46, 0x6c, 0x75, 0x78, 0x54, 0x61, 0x73, 0x6b, 0x22, 0x3a, 0x20, 0x7b, 0x0a, 0x22, + 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x22, 0x3a, 0x20, 0x22, 0x68, 0x74, 0x74, 0x70, + 0x73, 0x3a, 0x2f, 0x2f, 0x6d, 0x79, 0x2d, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x2d, 0x72, 0x70, + 0x63, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x22, 0x2c, 0x0a, + 0x22, 0x70, 0x6f, 0x6f, 0x6c, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x22, 0x3a, 0x20, 0x22, + 0x30, 0x78, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x22, 0x2c, 0x0a, 0x22, 0x69, 0x6e, + 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x3a, 0x20, 0x22, 0x30, 0x78, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x22, 0x2c, 0x0a, 0x22, 0x6f, 0x75, 0x74, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x22, + 0x3a, 0x20, 0x22, 0x30, 0x78, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x22, 0x0a, 0x7d, + 0x0a, 0x7d, 0x0a, 0x60, 0x60, 0x60, 0x0a, 0x0a, 0x0d, 0x0a, 0x05, 0x04, 0x00, 0x03, 0x38, 0x01, + 0x12, 0x04, 0xe1, 0x0a, 0x0a, 0x15, 0x0a, 0x70, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x38, 0x02, 0x00, + 0x12, 0x04, 0xe3, 0x0a, 0x04, 0x21, 0x1a, 0x60, 0x2f, 0x20, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, + 0x61, 0x6c, 0x2e, 0x20, 0x54, 0x68, 0x65, 0x20, 0x52, 0x50, 0x43, 0x20, 0x65, 0x6e, 0x64, 0x70, + 0x6f, 0x69, 0x6e, 0x74, 0x20, 0x74, 0x6f, 0x20, 0x75, 0x73, 0x65, 0x20, 0x66, 0x6f, 0x72, 0x20, + 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x2e, 0x20, 0x49, 0x66, 0x20, 0x6e, 0x6f, 0x74, + 0x20, 0x73, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x65, 0x64, 0x2c, 0x20, 0x61, 0x20, 0x64, 0x65, + 0x66, 0x61, 0x75, 0x6c, 0x74, 0x20, 0x52, 0x50, 0x43, 0x20, 0x77, 0x69, 0x6c, 0x6c, 0x20, 0x62, + 0x65, 0x20, 0x75, 0x73, 0x65, 0x64, 0x2e, 0x0a, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x38, + 0x02, 0x00, 0x04, 0x12, 0x04, 0xe3, 0x0a, 0x04, 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, + 0x38, 0x02, 0x00, 0x05, 0x12, 0x04, 0xe3, 0x0a, 0x0d, 0x13, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, + 0x03, 0x38, 0x02, 0x00, 0x01, 0x12, 0x04, 0xe3, 0x0a, 0x14, 0x1c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, + 0x00, 0x03, 0x38, 0x02, 0x00, 0x03, 0x12, 0x04, 0xe3, 0x0a, 0x1f, 0x20, 0x0a, 0x33, 0x0a, 0x06, + 0x04, 0x00, 0x03, 0x38, 0x02, 0x01, 0x12, 0x04, 0xe5, 0x0a, 0x04, 0x25, 0x1a, 0x23, 0x2f, 0x20, + 0x54, 0x68, 0x65, 0x20, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x20, 0x6f, 0x66, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x42, 0x69, 0x74, 0x46, 0x6c, 0x75, 0x78, 0x20, 0x70, 0x6f, 0x6f, 0x6c, 0x2e, + 0x0a, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x38, 0x02, 0x01, 0x04, 0x12, 0x04, 0xe5, 0x0a, + 0x04, 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x38, 0x02, 0x01, 0x05, 0x12, 0x04, 0xe5, + 0x0a, 0x0d, 0x13, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x38, 0x02, 0x01, 0x01, 0x12, 0x04, + 0xe5, 0x0a, 0x14, 0x20, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x38, 0x02, 0x01, 0x03, 0x12, + 0x04, 0xe5, 0x0a, 0x23, 0x24, 0x0a, 0x32, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x38, 0x02, 0x02, 0x12, + 0x04, 0xe7, 0x0a, 0x04, 0x21, 0x1a, 0x22, 0x2f, 0x20, 0x54, 0x68, 0x65, 0x20, 0x61, 0x64, 0x64, + 0x72, 0x65, 0x73, 0x73, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x69, 0x6e, 0x70, 0x75, + 0x74, 0x20, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x2e, 0x0a, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, + 0x38, 0x02, 0x02, 0x04, 0x12, 0x04, 0xe7, 0x0a, 0x04, 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, + 0x03, 0x38, 0x02, 0x02, 0x05, 0x12, 0x04, 0xe7, 0x0a, 0x0d, 0x13, 0x0a, 0x0f, 0x0a, 0x07, 0x04, + 0x00, 0x03, 0x38, 0x02, 0x02, 0x01, 0x12, 0x04, 0xe7, 0x0a, 0x14, 0x1c, 0x0a, 0x0f, 0x0a, 0x07, + 0x04, 0x00, 0x03, 0x38, 0x02, 0x02, 0x03, 0x12, 0x04, 0xe7, 0x0a, 0x1f, 0x20, 0x0a, 0x33, 0x0a, + 0x06, 0x04, 0x00, 0x03, 0x38, 0x02, 0x03, 0x12, 0x04, 0xe9, 0x0a, 0x04, 0x22, 0x1a, 0x23, 0x2f, + 0x20, 0x54, 0x68, 0x65, 0x20, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x20, 0x6f, 0x66, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x20, 0x74, 0x6f, 0x6b, 0x65, 0x6e, + 0x2e, 0x0a, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x38, 0x02, 0x03, 0x04, 0x12, 0x04, 0xe9, + 0x0a, 0x04, 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x38, 0x02, 0x03, 0x05, 0x12, 0x04, + 0xe9, 0x0a, 0x0d, 0x13, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x38, 0x02, 0x03, 0x01, 0x12, + 0x04, 0xe9, 0x0a, 0x14, 0x1d, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x38, 0x02, 0x03, 0x03, + 0x12, 0x04, 0xe9, 0x0a, 0x20, 0x21, 0x0a, 0xb6, 0x02, 0x0a, 0x04, 0x04, 0x00, 0x03, 0x39, 0x12, + 0x06, 0xf8, 0x0a, 0x02, 0x81, 0x0b, 0x03, 0x1a, 0xa5, 0x02, 0x0a, 0x46, 0x65, 0x74, 0x63, 0x68, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x20, 0x70, 0x72, 0x69, + 0x63, 0x65, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x46, 0x72, 0x61, 0x67, 0x6d, 0x65, 0x74, 0x72, 0x69, + 0x63, 0x20, 0x6c, 0x69, 0x71, 0x75, 0x69, 0x64, 0x20, 0x72, 0x65, 0x73, 0x74, 0x61, 0x6b, 0x69, + 0x6e, 0x67, 0x20, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x2e, 0x0a, 0x0a, 0x5f, 0x2a, 0x2a, 0x49, + 0x6e, 0x70, 0x75, 0x74, 0x2a, 0x2a, 0x5f, 0x3a, 0x20, 0x4e, 0x6f, 0x6e, 0x65, 0x0a, 0x0a, 0x5f, + 0x2a, 0x2a, 0x52, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x73, 0x2a, 0x2a, 0x5f, 0x3a, 0x20, 0x54, 0x68, + 0x65, 0x20, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x20, 0x70, 0x72, 0x69, 0x63, 0x65, 0x20, + 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x65, 0x64, + 0x20, 0x46, 0x72, 0x61, 0x67, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x20, 0x74, 0x6f, 0x6b, 0x65, + 0x6e, 0x20, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x76, 0x65, 0x20, 0x74, 0x6f, 0x20, 0x53, 0x4f, + 0x4c, 0x20, 0x28, 0x31, 0x2e, 0x30, 0x20, 0x3d, 0x20, 0x31, 0x20, 0x53, 0x4f, 0x4c, 0x29, 0x0a, + 0x0a, 0x5f, 0x2a, 0x2a, 0x45, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2a, 0x2a, 0x5f, 0x3a, 0x20, + 0x46, 0x65, 0x74, 0x63, 0x68, 0x20, 0x74, 0x68, 0x65, 0x20, 0x66, 0x72, 0x61, 0x67, 0x53, 0x4f, + 0x4c, 0x20, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x20, 0x70, 0x72, 0x69, 0x63, 0x65, 0x0a, 0x0a, 0x60, + 0x60, 0x60, 0x6a, 0x73, 0x6f, 0x6e, 0x0a, 0x7b, 0x20, 0x22, 0x66, 0x72, 0x61, 0x67, 0x6d, 0x65, + 0x74, 0x72, 0x69, 0x63, 0x54, 0x61, 0x73, 0x6b, 0x22, 0x3a, 0x20, 0x7b, 0x20, 0x22, 0x74, 0x6f, + 0x6b, 0x65, 0x6e, 0x22, 0x3a, 0x20, 0x22, 0x54, 0x4f, 0x4b, 0x45, 0x4e, 0x5f, 0x46, 0x52, 0x41, + 0x47, 0x5f, 0x53, 0x4f, 0x4c, 0x22, 0x20, 0x7d, 0x20, 0x7d, 0x0a, 0x60, 0x60, 0x60, 0x0a, 0x0a, + 0x0d, 0x0a, 0x05, 0x04, 0x00, 0x03, 0x39, 0x01, 0x12, 0x04, 0xf8, 0x0a, 0x0a, 0x18, 0x0a, 0x10, + 0x0a, 0x06, 0x04, 0x00, 0x03, 0x39, 0x04, 0x00, 0x12, 0x06, 0xf9, 0x0a, 0x04, 0xfe, 0x0a, 0x05, + 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x39, 0x04, 0x00, 0x01, 0x12, 0x04, 0xf9, 0x0a, 0x09, + 0x0e, 0x0a, 0x42, 0x0a, 0x08, 0x04, 0x00, 0x03, 0x39, 0x04, 0x00, 0x02, 0x00, 0x12, 0x04, 0xfb, + 0x0a, 0x06, 0x19, 0x1a, 0x30, 0x2f, 0x20, 0x46, 0x72, 0x61, 0x67, 0x6d, 0x65, 0x74, 0x72, 0x69, + 0x63, 0x27, 0x73, 0x20, 0x6c, 0x69, 0x71, 0x75, 0x69, 0x64, 0x20, 0x72, 0x65, 0x73, 0x74, 0x61, + 0x6b, 0x69, 0x6e, 0x67, 0x20, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x20, 0x28, 0x66, 0x72, 0x61, 0x67, + 0x53, 0x4f, 0x4c, 0x29, 0x0a, 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x39, 0x04, 0x00, 0x02, + 0x00, 0x01, 0x12, 0x04, 0xfb, 0x0a, 0x06, 0x14, 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x39, + 0x04, 0x00, 0x02, 0x00, 0x02, 0x12, 0x04, 0xfb, 0x0a, 0x17, 0x18, 0x0a, 0x3d, 0x0a, 0x08, 0x04, + 0x00, 0x03, 0x39, 0x04, 0x00, 0x02, 0x01, 0x12, 0x04, 0xfd, 0x0a, 0x06, 0x16, 0x1a, 0x2b, 0x2f, + 0x20, 0x46, 0x72, 0x61, 0x67, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x27, 0x73, 0x20, 0x6e, 0x61, + 0x74, 0x69, 0x76, 0x65, 0x20, 0x73, 0x74, 0x61, 0x6b, 0x69, 0x6e, 0x67, 0x20, 0x74, 0x6f, 0x6b, + 0x65, 0x6e, 0x20, 0x28, 0x6e, 0x53, 0x4f, 0x4c, 0x29, 0x0a, 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, + 0x03, 0x39, 0x04, 0x00, 0x02, 0x01, 0x01, 0x12, 0x04, 0xfd, 0x0a, 0x06, 0x11, 0x0a, 0x11, 0x0a, + 0x09, 0x04, 0x00, 0x03, 0x39, 0x04, 0x00, 0x02, 0x01, 0x02, 0x12, 0x04, 0xfd, 0x0a, 0x14, 0x15, + 0x0a, 0x3e, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x39, 0x02, 0x00, 0x12, 0x04, 0x80, 0x0b, 0x04, 0x1d, + 0x1a, 0x2e, 0x2f, 0x20, 0x54, 0x68, 0x65, 0x20, 0x46, 0x72, 0x61, 0x67, 0x6d, 0x65, 0x74, 0x72, + 0x69, 0x63, 0x20, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x20, 0x74, 0x6f, 0x20, 0x66, 0x65, 0x74, 0x63, + 0x68, 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x72, 0x69, 0x63, 0x65, 0x20, 0x66, 0x6f, 0x72, 0x0a, + 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x39, 0x02, 0x00, 0x04, 0x12, 0x04, 0x80, 0x0b, 0x04, + 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x39, 0x02, 0x00, 0x06, 0x12, 0x04, 0x80, 0x0b, + 0x0d, 0x12, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x39, 0x02, 0x00, 0x01, 0x12, 0x04, 0x80, + 0x0b, 0x13, 0x18, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x39, 0x02, 0x00, 0x03, 0x12, 0x04, + 0x80, 0x0b, 0x1b, 0x1c, 0x0a, 0x0e, 0x0a, 0x04, 0x04, 0x00, 0x03, 0x3a, 0x12, 0x06, 0x83, 0x0b, + 0x02, 0x8c, 0x0b, 0x03, 0x0a, 0x0d, 0x0a, 0x05, 0x04, 0x00, 0x03, 0x3a, 0x01, 0x12, 0x04, 0x83, + 0x0b, 0x0a, 0x17, 0x0a, 0x10, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x3a, 0x04, 0x00, 0x12, 0x06, 0x84, + 0x0b, 0x04, 0x8a, 0x0b, 0x05, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x3a, 0x04, 0x00, 0x01, + 0x12, 0x04, 0x84, 0x0b, 0x09, 0x0e, 0x0a, 0x10, 0x0a, 0x08, 0x04, 0x00, 0x03, 0x3a, 0x04, 0x00, + 0x02, 0x00, 0x12, 0x04, 0x85, 0x0b, 0x06, 0x18, 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x3a, + 0x04, 0x00, 0x02, 0x00, 0x01, 0x12, 0x04, 0x85, 0x0b, 0x06, 0x11, 0x0a, 0x11, 0x0a, 0x09, 0x04, + 0x00, 0x03, 0x3a, 0x04, 0x00, 0x02, 0x00, 0x02, 0x12, 0x04, 0x85, 0x0b, 0x16, 0x17, 0x0a, 0x10, + 0x0a, 0x08, 0x04, 0x00, 0x03, 0x3a, 0x04, 0x00, 0x02, 0x01, 0x12, 0x04, 0x86, 0x0b, 0x06, 0x18, + 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x3a, 0x04, 0x00, 0x02, 0x01, 0x01, 0x12, 0x04, 0x86, + 0x0b, 0x06, 0x11, 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x3a, 0x04, 0x00, 0x02, 0x01, 0x02, + 0x12, 0x04, 0x86, 0x0b, 0x16, 0x17, 0x0a, 0x10, 0x0a, 0x08, 0x04, 0x00, 0x03, 0x3a, 0x04, 0x00, + 0x02, 0x02, 0x12, 0x04, 0x87, 0x0b, 0x06, 0x18, 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x3a, + 0x04, 0x00, 0x02, 0x02, 0x01, 0x12, 0x04, 0x87, 0x0b, 0x06, 0x11, 0x0a, 0x11, 0x0a, 0x09, 0x04, + 0x00, 0x03, 0x3a, 0x04, 0x00, 0x02, 0x02, 0x02, 0x12, 0x04, 0x87, 0x0b, 0x16, 0x17, 0x0a, 0x10, + 0x0a, 0x08, 0x04, 0x00, 0x03, 0x3a, 0x04, 0x00, 0x02, 0x03, 0x12, 0x04, 0x88, 0x0b, 0x06, 0x18, + 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x3a, 0x04, 0x00, 0x02, 0x03, 0x01, 0x12, 0x04, 0x88, + 0x0b, 0x06, 0x13, 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x3a, 0x04, 0x00, 0x02, 0x03, 0x02, + 0x12, 0x04, 0x88, 0x0b, 0x16, 0x17, 0x0a, 0x10, 0x0a, 0x08, 0x04, 0x00, 0x03, 0x3a, 0x04, 0x00, + 0x02, 0x04, 0x12, 0x04, 0x89, 0x0b, 0x06, 0x18, 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x3a, + 0x04, 0x00, 0x02, 0x04, 0x01, 0x12, 0x04, 0x89, 0x0b, 0x06, 0x11, 0x0a, 0x11, 0x0a, 0x09, 0x04, + 0x00, 0x03, 0x3a, 0x04, 0x00, 0x02, 0x04, 0x02, 0x12, 0x04, 0x89, 0x0b, 0x16, 0x17, 0x0a, 0x0e, + 0x0a, 0x06, 0x04, 0x00, 0x03, 0x3a, 0x02, 0x00, 0x12, 0x04, 0x8b, 0x0b, 0x04, 0x1d, 0x0a, 0x0f, + 0x0a, 0x07, 0x04, 0x00, 0x03, 0x3a, 0x02, 0x00, 0x04, 0x12, 0x04, 0x8b, 0x0b, 0x04, 0x0c, 0x0a, + 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x3a, 0x02, 0x00, 0x06, 0x12, 0x04, 0x8b, 0x0b, 0x0d, 0x12, + 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x3a, 0x02, 0x00, 0x01, 0x12, 0x04, 0x8b, 0x0b, 0x13, + 0x18, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x3a, 0x02, 0x00, 0x03, 0x12, 0x04, 0x8b, 0x0b, + 0x1b, 0x1c, 0x0a, 0x9a, 0x04, 0x0a, 0x04, 0x04, 0x00, 0x03, 0x3b, 0x12, 0x06, 0xa1, 0x0b, 0x02, + 0xb1, 0x0b, 0x03, 0x1a, 0x89, 0x04, 0x0a, 0x51, 0x75, 0x65, 0x72, 0x79, 0x20, 0x68, 0x69, 0x73, + 0x74, 0x6f, 0x72, 0x69, 0x63, 0x61, 0x6c, 0x20, 0x79, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x64, 0x61, + 0x74, 0x61, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x61, 0x20, 0x67, 0x69, 0x76, 0x65, 0x6e, 0x20, 0x4c, + 0x69, 0x71, 0x75, 0x69, 0x64, 0x20, 0x53, 0x74, 0x61, 0x6b, 0x69, 0x6e, 0x67, 0x20, 0x54, 0x6f, + 0x6b, 0x65, 0x6e, 0x20, 0x28, 0x4c, 0x53, 0x54, 0x29, 0x0a, 0x61, 0x6e, 0x64, 0x20, 0x70, 0x65, + 0x72, 0x66, 0x6f, 0x72, 0x6d, 0x20, 0x61, 0x20, 0x73, 0x74, 0x61, 0x74, 0x69, 0x73, 0x74, 0x69, + 0x63, 0x61, 0x6c, 0x20, 0x72, 0x65, 0x64, 0x75, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6f, 0x70, + 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6f, 0x76, 0x65, 0x72, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x64, 0x61, 0x74, 0x61, 0x73, 0x65, 0x74, 0x2e, 0x0a, 0x0a, 0x5f, 0x2a, 0x2a, 0x49, 0x6e, + 0x70, 0x75, 0x74, 0x2a, 0x2a, 0x5f, 0x3a, 0x20, 0x4c, 0x53, 0x54, 0x20, 0x6d, 0x69, 0x6e, 0x74, + 0x20, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x2c, 0x20, 0x72, 0x65, 0x64, 0x75, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x20, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x74, 0x79, + 0x70, 0x65, 0x2c, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x20, 0x6f, + 0x66, 0x20, 0x65, 0x70, 0x6f, 0x63, 0x68, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x73, 0x61, 0x6d, 0x70, + 0x6c, 0x65, 0x2e, 0x0a, 0x0a, 0x5f, 0x2a, 0x2a, 0x52, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x73, 0x2a, + 0x2a, 0x5f, 0x3a, 0x20, 0x54, 0x68, 0x65, 0x20, 0x63, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x64, + 0x20, 0x79, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x20, 0x62, 0x61, 0x73, + 0x65, 0x64, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x70, 0x65, 0x63, 0x69, 0x66, + 0x69, 0x65, 0x64, 0x20, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x0a, 0x0a, + 0x5f, 0x2a, 0x2a, 0x45, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2a, 0x2a, 0x5f, 0x3a, 0x20, 0x43, + 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6d, 0x65, 0x64, 0x69, 0x61, + 0x6e, 0x20, 0x41, 0x50, 0x59, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x61, 0x6e, 0x20, 0x4c, 0x53, 0x54, + 0x20, 0x6f, 0x76, 0x65, 0x72, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6c, 0x61, 0x73, 0x74, 0x20, 0x31, + 0x30, 0x30, 0x20, 0x65, 0x70, 0x6f, 0x63, 0x68, 0x73, 0x0a, 0x0a, 0x60, 0x60, 0x60, 0x6a, 0x73, + 0x6f, 0x6e, 0x0a, 0x7b, 0x0a, 0x22, 0x6c, 0x73, 0x74, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x69, + 0x63, 0x61, 0x6c, 0x59, 0x69, 0x65, 0x6c, 0x64, 0x54, 0x61, 0x73, 0x6b, 0x22, 0x3a, 0x20, 0x7b, + 0x0a, 0x22, 0x6c, 0x73, 0x74, 0x4d, 0x69, 0x6e, 0x74, 0x22, 0x3a, 0x20, 0x22, 0x4a, 0x31, 0x74, + 0x6f, 0x73, 0x6f, 0x31, 0x75, 0x43, 0x6b, 0x33, 0x52, 0x4c, 0x6d, 0x6a, 0x6f, 0x72, 0x68, 0x54, + 0x74, 0x72, 0x56, 0x77, 0x59, 0x39, 0x48, 0x4a, 0x37, 0x58, 0x38, 0x56, 0x39, 0x79, 0x59, 0x61, + 0x63, 0x36, 0x59, 0x37, 0x6b, 0x47, 0x43, 0x50, 0x6e, 0x22, 0x2c, 0x0a, 0x22, 0x6f, 0x70, 0x65, + 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x3a, 0x20, 0x22, 0x4f, 0x50, 0x45, 0x52, 0x41, 0x54, + 0x49, 0x4f, 0x4e, 0x5f, 0x4d, 0x45, 0x44, 0x49, 0x41, 0x4e, 0x22, 0x2c, 0x0a, 0x22, 0x65, 0x70, + 0x6f, 0x63, 0x68, 0x73, 0x22, 0x3a, 0x20, 0x31, 0x30, 0x30, 0x0a, 0x7d, 0x0a, 0x7d, 0x0a, 0x0a, + 0x0d, 0x0a, 0x05, 0x04, 0x00, 0x03, 0x3b, 0x01, 0x12, 0x04, 0xa1, 0x0b, 0x0a, 0x20, 0x0a, 0x10, + 0x0a, 0x06, 0x04, 0x00, 0x03, 0x3b, 0x04, 0x00, 0x12, 0x06, 0xa2, 0x0b, 0x04, 0xa7, 0x0b, 0x05, + 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x3b, 0x04, 0x00, 0x01, 0x12, 0x04, 0xa2, 0x0b, 0x09, + 0x12, 0x0a, 0x10, 0x0a, 0x08, 0x04, 0x00, 0x03, 0x3b, 0x04, 0x00, 0x02, 0x00, 0x12, 0x04, 0xa3, + 0x0b, 0x06, 0x1b, 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x3b, 0x04, 0x00, 0x02, 0x00, 0x01, + 0x12, 0x04, 0xa3, 0x0b, 0x06, 0x16, 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x3b, 0x04, 0x00, + 0x02, 0x00, 0x02, 0x12, 0x04, 0xa3, 0x0b, 0x19, 0x1a, 0x0a, 0x10, 0x0a, 0x08, 0x04, 0x00, 0x03, + 0x3b, 0x04, 0x00, 0x02, 0x01, 0x12, 0x04, 0xa4, 0x0b, 0x06, 0x19, 0x0a, 0x11, 0x0a, 0x09, 0x04, + 0x00, 0x03, 0x3b, 0x04, 0x00, 0x02, 0x01, 0x01, 0x12, 0x04, 0xa4, 0x0b, 0x06, 0x14, 0x0a, 0x11, + 0x0a, 0x09, 0x04, 0x00, 0x03, 0x3b, 0x04, 0x00, 0x02, 0x01, 0x02, 0x12, 0x04, 0xa4, 0x0b, 0x17, + 0x18, 0x0a, 0x10, 0x0a, 0x08, 0x04, 0x00, 0x03, 0x3b, 0x04, 0x00, 0x02, 0x02, 0x12, 0x04, 0xa5, + 0x0b, 0x06, 0x18, 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x3b, 0x04, 0x00, 0x02, 0x02, 0x01, + 0x12, 0x04, 0xa5, 0x0b, 0x06, 0x13, 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x3b, 0x04, 0x00, + 0x02, 0x02, 0x02, 0x12, 0x04, 0xa5, 0x0b, 0x16, 0x17, 0x0a, 0x10, 0x0a, 0x08, 0x04, 0x00, 0x03, + 0x3b, 0x04, 0x00, 0x02, 0x03, 0x12, 0x04, 0xa6, 0x0b, 0x06, 0x18, 0x0a, 0x11, 0x0a, 0x09, 0x04, + 0x00, 0x03, 0x3b, 0x04, 0x00, 0x02, 0x03, 0x01, 0x12, 0x04, 0xa6, 0x0b, 0x06, 0x13, 0x0a, 0x11, + 0x0a, 0x09, 0x04, 0x00, 0x03, 0x3b, 0x04, 0x00, 0x02, 0x03, 0x02, 0x12, 0x04, 0xa6, 0x0b, 0x16, + 0x17, 0x0a, 0x5d, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x3b, 0x02, 0x00, 0x12, 0x04, 0xaa, 0x0b, 0x04, + 0x21, 0x1a, 0x4d, 0x2f, 0x20, 0x52, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x2e, 0x20, 0x54, + 0x68, 0x65, 0x20, 0x4c, 0x53, 0x54, 0x20, 0x6d, 0x69, 0x6e, 0x74, 0x20, 0x61, 0x64, 0x64, 0x72, + 0x65, 0x73, 0x73, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x77, 0x68, 0x69, 0x63, 0x68, 0x20, 0x68, 0x69, + 0x73, 0x74, 0x6f, 0x72, 0x69, 0x63, 0x61, 0x6c, 0x20, 0x79, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x64, + 0x61, 0x74, 0x61, 0x20, 0x69, 0x73, 0x20, 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, 0x64, 0x2e, 0x0a, + 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x3b, 0x02, 0x00, 0x04, 0x12, 0x04, 0xaa, 0x0b, 0x04, + 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x3b, 0x02, 0x00, 0x05, 0x12, 0x04, 0xaa, 0x0b, + 0x0d, 0x13, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x3b, 0x02, 0x00, 0x01, 0x12, 0x04, 0xaa, + 0x0b, 0x14, 0x1c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x3b, 0x02, 0x00, 0x03, 0x12, 0x04, + 0xaa, 0x0b, 0x1f, 0x20, 0x0a, 0x60, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x3b, 0x02, 0x01, 0x12, 0x04, + 0xac, 0x0b, 0x04, 0x25, 0x1a, 0x50, 0x2f, 0x20, 0x52, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, + 0x2e, 0x20, 0x54, 0x68, 0x65, 0x20, 0x73, 0x74, 0x61, 0x74, 0x69, 0x73, 0x74, 0x69, 0x63, 0x61, + 0x6c, 0x20, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x74, 0x6f, 0x20, 0x61, + 0x70, 0x70, 0x6c, 0x79, 0x20, 0x74, 0x6f, 0x20, 0x74, 0x68, 0x65, 0x20, 0x68, 0x69, 0x73, 0x74, + 0x6f, 0x72, 0x69, 0x63, 0x61, 0x6c, 0x20, 0x79, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x64, 0x61, 0x74, + 0x61, 0x73, 0x65, 0x74, 0x2e, 0x0a, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x3b, 0x02, 0x01, + 0x04, 0x12, 0x04, 0xac, 0x0b, 0x04, 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x3b, 0x02, + 0x01, 0x06, 0x12, 0x04, 0xac, 0x0b, 0x0d, 0x16, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x3b, + 0x02, 0x01, 0x01, 0x12, 0x04, 0xac, 0x0b, 0x17, 0x20, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, + 0x3b, 0x02, 0x01, 0x03, 0x12, 0x04, 0xac, 0x0b, 0x23, 0x24, 0x0a, 0xd8, 0x01, 0x0a, 0x06, 0x04, + 0x00, 0x03, 0x3b, 0x02, 0x02, 0x12, 0x04, 0xb0, 0x0b, 0x04, 0x1e, 0x1a, 0xc7, 0x01, 0x2f, 0x20, + 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x2e, 0x20, 0x54, 0x68, 0x65, 0x20, 0x6e, 0x75, + 0x6d, 0x62, 0x65, 0x72, 0x20, 0x6f, 0x66, 0x20, 0x65, 0x70, 0x6f, 0x63, 0x68, 0x73, 0x20, 0x74, + 0x6f, 0x20, 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x63, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x0a, 0x2f, 0x20, + 0x2d, 0x20, 0x49, 0x66, 0x20, 0x60, 0x65, 0x70, 0x6f, 0x63, 0x68, 0x73, 0x20, 0x3d, 0x20, 0x30, + 0x60, 0x2c, 0x20, 0x61, 0x6c, 0x6c, 0x20, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, + 0x20, 0x68, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x69, 0x63, 0x61, 0x6c, 0x20, 0x64, 0x61, 0x74, 0x61, + 0x20, 0x77, 0x69, 0x6c, 0x6c, 0x20, 0x62, 0x65, 0x20, 0x75, 0x73, 0x65, 0x64, 0x2e, 0x0a, 0x2f, + 0x20, 0x2d, 0x20, 0x49, 0x66, 0x20, 0x60, 0x65, 0x70, 0x6f, 0x63, 0x68, 0x73, 0x20, 0x3e, 0x20, + 0x30, 0x60, 0x2c, 0x20, 0x6f, 0x6e, 0x6c, 0x79, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6c, 0x61, 0x73, + 0x74, 0x20, 0x60, 0x65, 0x70, 0x6f, 0x63, 0x68, 0x73, 0x60, 0x20, 0x65, 0x6e, 0x74, 0x72, 0x69, + 0x65, 0x73, 0x20, 0x77, 0x69, 0x6c, 0x6c, 0x20, 0x62, 0x65, 0x20, 0x69, 0x6e, 0x63, 0x6c, 0x75, + 0x64, 0x65, 0x64, 0x2e, 0x0a, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x3b, 0x02, 0x02, 0x04, + 0x12, 0x04, 0xb0, 0x0b, 0x04, 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x3b, 0x02, 0x02, + 0x05, 0x12, 0x04, 0xb0, 0x0b, 0x0d, 0x12, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x3b, 0x02, + 0x02, 0x01, 0x12, 0x04, 0xb0, 0x0b, 0x13, 0x19, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x3b, + 0x02, 0x02, 0x03, 0x12, 0x04, 0xb0, 0x0b, 0x1c, 0x1d, 0x0a, 0xec, 0x03, 0x0a, 0x04, 0x04, 0x00, + 0x03, 0x3c, 0x12, 0x06, 0xc6, 0x0b, 0x02, 0xd9, 0x0b, 0x03, 0x1a, 0xdb, 0x03, 0x0a, 0x45, 0x78, + 0x65, 0x63, 0x75, 0x74, 0x65, 0x20, 0x61, 0x20, 0x73, 0x77, 0x61, 0x70, 0x20, 0x74, 0x61, 0x73, + 0x6b, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x50, 0x75, 0x6d, 0x70, 0x20, 0x41, 0x4d, + 0x4d, 0x20, 0x62, 0x61, 0x73, 0x65, 0x64, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x67, + 0x69, 0x76, 0x65, 0x6e, 0x20, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x2e, + 0x0a, 0x0a, 0x5f, 0x2a, 0x2a, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x2a, 0x2a, 0x5f, 0x3a, 0x20, 0x50, + 0x6f, 0x6f, 0x6c, 0x20, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x2c, 0x20, 0x69, 0x6e, 0x70, + 0x75, 0x74, 0x20, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x20, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x2c, + 0x20, 0x6d, 0x61, 0x78, 0x20, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x65, 0x64, 0x20, 0x73, 0x6c, 0x69, + 0x70, 0x70, 0x61, 0x67, 0x65, 0x2c, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x73, 0x77, 0x61, 0x70, 0x20, + 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x0a, 0x0a, 0x5f, 0x2a, 0x2a, 0x52, + 0x65, 0x74, 0x75, 0x72, 0x6e, 0x73, 0x2a, 0x2a, 0x5f, 0x3a, 0x20, 0x45, 0x78, 0x65, 0x63, 0x75, + 0x74, 0x65, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x77, 0x61, 0x70, 0x20, 0x6f, 0x70, 0x65, + 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x50, 0x75, + 0x6d, 0x70, 0x20, 0x41, 0x4d, 0x4d, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x67, 0x69, 0x76, 0x65, 0x6e, 0x20, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, + 0x2e, 0x0a, 0x0a, 0x5f, 0x2a, 0x2a, 0x45, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2a, 0x2a, 0x5f, + 0x3a, 0x20, 0x53, 0x77, 0x61, 0x70, 0x20, 0x31, 0x30, 0x20, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x73, + 0x20, 0x66, 0x72, 0x6f, 0x6d, 0x20, 0x58, 0x20, 0x74, 0x6f, 0x20, 0x59, 0x20, 0x77, 0x69, 0x74, + 0x68, 0x20, 0x61, 0x20, 0x6d, 0x61, 0x78, 0x69, 0x6d, 0x75, 0x6d, 0x20, 0x73, 0x6c, 0x69, 0x70, + 0x70, 0x61, 0x67, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x30, 0x2e, 0x35, 0x25, 0x0a, 0x0a, 0x60, 0x60, + 0x60, 0x6a, 0x73, 0x6f, 0x6e, 0x0a, 0x7b, 0x0a, 0x22, 0x70, 0x75, 0x6d, 0x70, 0x41, 0x6d, 0x6d, + 0x54, 0x61, 0x73, 0x6b, 0x22, 0x3a, 0x20, 0x7b, 0x0a, 0x22, 0x70, 0x6f, 0x6f, 0x6c, 0x5f, 0x61, + 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x22, 0x3a, 0x20, 0x22, 0x47, 0x66, 0x37, 0x73, 0x58, 0x4d, + 0x6f, 0x50, 0x38, 0x69, 0x52, 0x77, 0x34, 0x69, 0x69, 0x58, 0x6d, 0x4a, 0x31, 0x6e, 0x71, 0x34, + 0x76, 0x78, 0x63, 0x52, 0x79, 0x63, 0x62, 0x47, 0x58, 0x79, 0x35, 0x52, 0x4c, 0x38, 0x61, 0x38, + 0x4c, 0x6e, 0x54, 0x64, 0x33, 0x76, 0x22, 0x2c, 0x0a, 0x22, 0x69, 0x6e, 0x5f, 0x61, 0x6d, 0x6f, + 0x75, 0x6e, 0x74, 0x22, 0x3a, 0x20, 0x22, 0x31, 0x30, 0x22, 0x2c, 0x0a, 0x22, 0x6d, 0x61, 0x78, + 0x5f, 0x73, 0x6c, 0x69, 0x70, 0x70, 0x61, 0x67, 0x65, 0x22, 0x3a, 0x20, 0x30, 0x2e, 0x35, 0x2c, + 0x0a, 0x22, 0x69, 0x73, 0x5f, 0x78, 0x5f, 0x66, 0x6f, 0x72, 0x5f, 0x79, 0x22, 0x3a, 0x20, 0x74, + 0x72, 0x75, 0x65, 0x0a, 0x7d, 0x0a, 0x7d, 0x0a, 0x0a, 0x0d, 0x0a, 0x05, 0x04, 0x00, 0x03, 0x3c, + 0x01, 0x12, 0x04, 0xc6, 0x0b, 0x0a, 0x15, 0x0a, 0x4f, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x3c, 0x02, + 0x00, 0x12, 0x04, 0xc8, 0x0b, 0x04, 0x25, 0x1a, 0x3f, 0x2f, 0x20, 0x52, 0x65, 0x71, 0x75, 0x69, + 0x72, 0x65, 0x64, 0x2e, 0x20, 0x54, 0x68, 0x65, 0x20, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, + 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6c, 0x69, 0x71, 0x75, 0x69, 0x64, 0x69, 0x74, + 0x79, 0x20, 0x70, 0x6f, 0x6f, 0x6c, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x50, 0x75, + 0x6d, 0x70, 0x20, 0x41, 0x4d, 0x4d, 0x2e, 0x0a, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x3c, + 0x02, 0x00, 0x04, 0x12, 0x04, 0xc8, 0x0b, 0x04, 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, + 0x3c, 0x02, 0x00, 0x05, 0x12, 0x04, 0xc8, 0x0b, 0x0d, 0x13, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, + 0x03, 0x3c, 0x02, 0x00, 0x01, 0x12, 0x04, 0xc8, 0x0b, 0x14, 0x20, 0x0a, 0x0f, 0x0a, 0x07, 0x04, + 0x00, 0x03, 0x3c, 0x02, 0x00, 0x03, 0x12, 0x04, 0xc8, 0x0b, 0x23, 0x24, 0x0a, 0xa6, 0x01, 0x0a, + 0x06, 0x04, 0x00, 0x03, 0x3c, 0x02, 0x01, 0x12, 0x04, 0xcd, 0x0b, 0x04, 0x22, 0x1a, 0x95, 0x01, + 0x2f, 0x20, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x2e, 0x20, 0x54, 0x68, 0x65, 0x20, + 0x69, 0x6e, 0x70, 0x75, 0x74, 0x20, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x20, 0x61, 0x6d, 0x6f, 0x75, + 0x6e, 0x74, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x77, 0x61, 0x70, 0x2e, + 0x0a, 0x2f, 0x20, 0x2d, 0x20, 0x54, 0x68, 0x69, 0x73, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x20, + 0x73, 0x68, 0x6f, 0x75, 0x6c, 0x64, 0x20, 0x69, 0x6e, 0x20, 0x66, 0x75, 0x6c, 0x6c, 0x20, 0x75, + 0x6e, 0x69, 0x74, 0x73, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x69, 0x6e, 0x70, 0x75, + 0x74, 0x20, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x2e, 0x0a, 0x2f, 0x20, 0x2d, 0x20, 0x44, 0x65, 0x66, + 0x61, 0x75, 0x6c, 0x74, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x20, 0x60, 0x31, 0x60, 0x20, + 0x28, 0x53, 0x77, 0x61, 0x70, 0x20, 0x31, 0x20, 0x66, 0x75, 0x6c, 0x6c, 0x20, 0x74, 0x6f, 0x6b, + 0x65, 0x6e, 0x29, 0x2e, 0x0a, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x3c, 0x02, 0x01, 0x04, + 0x12, 0x04, 0xcd, 0x0b, 0x04, 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x3c, 0x02, 0x01, + 0x05, 0x12, 0x04, 0xcd, 0x0b, 0x0d, 0x13, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x3c, 0x02, + 0x01, 0x01, 0x12, 0x04, 0xcd, 0x0b, 0x14, 0x1d, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x3c, + 0x02, 0x01, 0x03, 0x12, 0x04, 0xcd, 0x0b, 0x20, 0x21, 0x0a, 0xca, 0x01, 0x0a, 0x06, 0x04, 0x00, + 0x03, 0x3c, 0x02, 0x02, 0x12, 0x04, 0xd2, 0x0b, 0x04, 0x25, 0x1a, 0xb9, 0x01, 0x2f, 0x20, 0x4f, + 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x2e, 0x20, 0x54, 0x68, 0x65, 0x20, 0x6d, 0x61, 0x78, + 0x69, 0x6d, 0x75, 0x6d, 0x20, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x65, 0x64, 0x20, 0x73, 0x6c, 0x69, + 0x70, 0x70, 0x61, 0x67, 0x65, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x77, + 0x61, 0x70, 0x2c, 0x20, 0x65, 0x78, 0x70, 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x20, 0x61, 0x73, + 0x20, 0x61, 0x20, 0x70, 0x65, 0x72, 0x63, 0x65, 0x6e, 0x74, 0x61, 0x67, 0x65, 0x2e, 0x0a, 0x2f, + 0x20, 0x2d, 0x20, 0x45, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x3a, 0x20, 0x60, 0x30, 0x2e, 0x35, + 0x60, 0x20, 0x72, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x73, 0x20, 0x30, 0x2e, 0x35, + 0x25, 0x20, 0x73, 0x6c, 0x69, 0x70, 0x70, 0x61, 0x67, 0x65, 0x20, 0x74, 0x6f, 0x6c, 0x65, 0x72, + 0x61, 0x6e, 0x63, 0x65, 0x2e, 0x0a, 0x2f, 0x20, 0x2d, 0x20, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, + 0x74, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x20, 0x60, 0x33, 0x60, 0x20, 0x28, 0x33, 0x25, + 0x20, 0x73, 0x6c, 0x69, 0x70, 0x70, 0x61, 0x67, 0x65, 0x20, 0x74, 0x6f, 0x6c, 0x65, 0x72, 0x61, + 0x6e, 0x63, 0x65, 0x29, 0x2e, 0x0a, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x3c, 0x02, 0x02, + 0x04, 0x12, 0x04, 0xd2, 0x0b, 0x04, 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x3c, 0x02, + 0x02, 0x05, 0x12, 0x04, 0xd2, 0x0b, 0x0d, 0x13, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x3c, + 0x02, 0x02, 0x01, 0x12, 0x04, 0xd2, 0x0b, 0x14, 0x20, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, + 0x3c, 0x02, 0x02, 0x03, 0x12, 0x04, 0xd2, 0x0b, 0x23, 0x24, 0x0a, 0xab, 0x01, 0x0a, 0x06, 0x04, + 0x00, 0x03, 0x3c, 0x02, 0x03, 0x12, 0x04, 0xd8, 0x0b, 0x04, 0x21, 0x1a, 0x9a, 0x01, 0x2f, 0x20, + 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x2e, 0x20, 0x49, 0x6e, 0x64, 0x69, 0x63, 0x61, + 0x74, 0x65, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x77, 0x61, 0x70, 0x20, 0x64, 0x69, 0x72, + 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x0a, 0x2f, 0x20, 0x2d, 0x20, 0x60, 0x74, 0x72, 0x75, + 0x65, 0x60, 0x3a, 0x20, 0x53, 0x77, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x20, 0x74, 0x6f, 0x6b, + 0x65, 0x6e, 0x20, 0x58, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x20, 0x59, + 0x2e, 0x0a, 0x2f, 0x20, 0x2d, 0x20, 0x60, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x60, 0x3a, 0x20, 0x53, + 0x77, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x20, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x20, 0x59, 0x20, + 0x66, 0x6f, 0x72, 0x20, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x20, 0x58, 0x2e, 0x0a, 0x2f, 0x20, 0x2d, + 0x20, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x20, + 0x60, 0x74, 0x72, 0x75, 0x65, 0x60, 0x2e, 0x0a, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x3c, + 0x02, 0x03, 0x04, 0x12, 0x04, 0xd8, 0x0b, 0x04, 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, + 0x3c, 0x02, 0x03, 0x05, 0x12, 0x04, 0xd8, 0x0b, 0x0d, 0x11, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, + 0x03, 0x3c, 0x02, 0x03, 0x01, 0x12, 0x04, 0xd8, 0x0b, 0x12, 0x1c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, + 0x00, 0x03, 0x3c, 0x02, 0x03, 0x03, 0x12, 0x04, 0xd8, 0x0b, 0x1f, 0x20, 0x0a, 0xcf, 0x04, 0x0a, + 0x04, 0x04, 0x00, 0x03, 0x3d, 0x12, 0x06, 0xf3, 0x0b, 0x02, 0xfa, 0x0b, 0x03, 0x1a, 0xbe, 0x04, + 0x0a, 0x20, 0x44, 0x65, 0x72, 0x69, 0x76, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x66, 0x61, 0x69, + 0x72, 0x20, 0x4c, 0x50, 0x20, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x20, 0x70, 0x72, 0x69, 0x63, 0x65, + 0x20, 0x66, 0x6f, 0x72, 0x20, 0x61, 0x20, 0x67, 0x69, 0x76, 0x65, 0x6e, 0x20, 0x50, 0x75, 0x6d, + 0x70, 0x20, 0x41, 0x4d, 0x4d, 0x20, 0x6c, 0x69, 0x71, 0x75, 0x69, 0x64, 0x69, 0x74, 0x79, 0x20, + 0x70, 0x6f, 0x6f, 0x6c, 0x2e, 0x0a, 0x0a, 0x20, 0x5f, 0x2a, 0x2a, 0x49, 0x6e, 0x70, 0x75, 0x74, + 0x2a, 0x2a, 0x5f, 0x3a, 0x20, 0x50, 0x6f, 0x6f, 0x6c, 0x20, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, + 0x73, 0x2c, 0x20, 0x58, 0x20, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x20, 0x70, 0x72, 0x69, 0x63, 0x65, + 0x20, 0x6a, 0x6f, 0x62, 0x2c, 0x20, 0x59, 0x20, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x20, 0x70, 0x72, + 0x69, 0x63, 0x65, 0x20, 0x6a, 0x6f, 0x62, 0x2e, 0x0a, 0x20, 0x5f, 0x2a, 0x2a, 0x52, 0x65, 0x74, + 0x75, 0x72, 0x6e, 0x73, 0x2a, 0x2a, 0x5f, 0x3a, 0x20, 0x54, 0x68, 0x65, 0x20, 0x66, 0x61, 0x69, + 0x72, 0x20, 0x4c, 0x50, 0x20, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x20, 0x70, 0x72, 0x69, 0x63, 0x65, + 0x20, 0x66, 0x6f, 0x72, 0x20, 0x74, 0x68, 0x65, 0x20, 0x67, 0x69, 0x76, 0x65, 0x6e, 0x20, 0x50, + 0x75, 0x6d, 0x70, 0x20, 0x41, 0x4d, 0x4d, 0x20, 0x6c, 0x69, 0x71, 0x75, 0x69, 0x64, 0x69, 0x74, + 0x79, 0x20, 0x70, 0x6f, 0x6f, 0x6c, 0x2e, 0x0a, 0x20, 0x5f, 0x2a, 0x2a, 0x45, 0x78, 0x61, 0x6d, + 0x70, 0x6c, 0x65, 0x2a, 0x2a, 0x5f, 0x3a, 0x20, 0x44, 0x65, 0x72, 0x69, 0x76, 0x65, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x66, 0x61, 0x69, 0x72, 0x20, 0x4c, 0x50, 0x20, 0x74, 0x6f, 0x6b, 0x65, 0x6e, + 0x20, 0x70, 0x72, 0x69, 0x63, 0x65, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x61, 0x20, 0x67, 0x69, 0x76, + 0x65, 0x6e, 0x20, 0x50, 0x75, 0x6d, 0x70, 0x20, 0x41, 0x4d, 0x4d, 0x20, 0x6c, 0x69, 0x71, 0x75, + 0x69, 0x64, 0x69, 0x74, 0x79, 0x20, 0x70, 0x6f, 0x6f, 0x6c, 0x2e, 0x0a, 0x20, 0x60, 0x60, 0x60, + 0x6a, 0x73, 0x6f, 0x6e, 0x0a, 0x7b, 0x0a, 0x22, 0x70, 0x75, 0x6d, 0x70, 0x41, 0x6d, 0x6d, 0x4c, + 0x70, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x50, 0x72, 0x69, 0x63, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x22, + 0x3a, 0x20, 0x7b, 0x0a, 0x22, 0x70, 0x6f, 0x6f, 0x6c, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, + 0x73, 0x22, 0x3a, 0x20, 0x22, 0x47, 0x66, 0x37, 0x73, 0x58, 0x4d, 0x6f, 0x50, 0x38, 0x69, 0x52, + 0x77, 0x34, 0x69, 0x69, 0x58, 0x6d, 0x4a, 0x31, 0x6e, 0x71, 0x34, 0x76, 0x78, 0x63, 0x52, 0x79, + 0x63, 0x62, 0x47, 0x58, 0x79, 0x35, 0x52, 0x4c, 0x38, 0x61, 0x38, 0x4c, 0x6e, 0x54, 0x64, 0x33, + 0x76, 0x22, 0x2c, 0x20, 0x2f, 0x2f, 0x20, 0x55, 0x53, 0x44, 0x43, 0x2f, 0x53, 0x4f, 0x4c, 0x0a, + 0x22, 0x78, 0x5f, 0x70, 0x72, 0x69, 0x63, 0x65, 0x5f, 0x6a, 0x6f, 0x62, 0x22, 0x3a, 0x20, 0x7b, + 0x0a, 0x22, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x22, 0x3a, 0x20, 0x7b, + 0x0a, 0x22, 0x73, 0x77, 0x69, 0x74, 0x63, 0x68, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x41, 0x64, 0x64, + 0x72, 0x65, 0x73, 0x73, 0x22, 0x3a, 0x20, 0x22, 0x2e, 0x2e, 0x2e, 0x22, 0x20, 0x2f, 0x2f, 0x20, + 0x55, 0x53, 0x44, 0x43, 0x2f, 0x55, 0x53, 0x44, 0x0a, 0x7d, 0x0a, 0x7d, 0x2c, 0x0a, 0x22, 0x79, + 0x5f, 0x70, 0x72, 0x69, 0x63, 0x65, 0x5f, 0x6a, 0x6f, 0x62, 0x22, 0x3a, 0x20, 0x7b, 0x0a, 0x22, + 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x22, 0x3a, 0x20, 0x7b, 0x0a, 0x22, + 0x73, 0x77, 0x69, 0x74, 0x63, 0x68, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x41, 0x64, 0x64, 0x72, 0x65, + 0x73, 0x73, 0x22, 0x3a, 0x20, 0x22, 0x2e, 0x2e, 0x2e, 0x22, 0x20, 0x2f, 0x2f, 0x20, 0x53, 0x4f, + 0x4c, 0x2f, 0x55, 0x53, 0x44, 0x0a, 0x7d, 0x0a, 0x7d, 0x0a, 0x7d, 0x0a, 0x7d, 0x0a, 0x0a, 0x0d, + 0x0a, 0x05, 0x04, 0x00, 0x03, 0x3d, 0x01, 0x12, 0x04, 0xf3, 0x0b, 0x0a, 0x21, 0x0a, 0x4f, 0x0a, + 0x06, 0x04, 0x00, 0x03, 0x3d, 0x02, 0x00, 0x12, 0x04, 0xf5, 0x0b, 0x04, 0x25, 0x1a, 0x3f, 0x2f, + 0x20, 0x52, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x2e, 0x20, 0x54, 0x68, 0x65, 0x20, 0x61, + 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6c, 0x69, + 0x71, 0x75, 0x69, 0x64, 0x69, 0x74, 0x79, 0x20, 0x70, 0x6f, 0x6f, 0x6c, 0x20, 0x69, 0x6e, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x50, 0x75, 0x6d, 0x70, 0x20, 0x41, 0x4d, 0x4d, 0x2e, 0x0a, 0x0a, 0x0f, + 0x0a, 0x07, 0x04, 0x00, 0x03, 0x3d, 0x02, 0x00, 0x04, 0x12, 0x04, 0xf5, 0x0b, 0x04, 0x0c, 0x0a, + 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x3d, 0x02, 0x00, 0x05, 0x12, 0x04, 0xf5, 0x0b, 0x0d, 0x13, + 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x3d, 0x02, 0x00, 0x01, 0x12, 0x04, 0xf5, 0x0b, 0x14, + 0x20, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x3d, 0x02, 0x00, 0x03, 0x12, 0x04, 0xf5, 0x0b, + 0x23, 0x24, 0x0a, 0x56, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x3d, 0x02, 0x01, 0x12, 0x04, 0xf7, 0x0b, + 0x04, 0x27, 0x1a, 0x46, 0x2f, 0x20, 0x52, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x2e, 0x20, + 0x54, 0x68, 0x65, 0x20, 0x6a, 0x6f, 0x62, 0x20, 0x74, 0x6f, 0x20, 0x65, 0x78, 0x65, 0x63, 0x75, + 0x74, 0x65, 0x20, 0x74, 0x6f, 0x20, 0x66, 0x65, 0x74, 0x63, 0x68, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x70, 0x72, 0x69, 0x63, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x6f, 0x6f, + 0x6c, 0x20, 0x78, 0x20, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x0a, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, + 0x03, 0x3d, 0x02, 0x01, 0x04, 0x12, 0x04, 0xf7, 0x0b, 0x04, 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, + 0x00, 0x03, 0x3d, 0x02, 0x01, 0x06, 0x12, 0x04, 0xf7, 0x0b, 0x0d, 0x16, 0x0a, 0x0f, 0x0a, 0x07, + 0x04, 0x00, 0x03, 0x3d, 0x02, 0x01, 0x01, 0x12, 0x04, 0xf7, 0x0b, 0x17, 0x22, 0x0a, 0x0f, 0x0a, + 0x07, 0x04, 0x00, 0x03, 0x3d, 0x02, 0x01, 0x03, 0x12, 0x04, 0xf7, 0x0b, 0x25, 0x26, 0x0a, 0x2f, + 0x0a, 0x06, 0x04, 0x00, 0x03, 0x3d, 0x02, 0x02, 0x12, 0x04, 0xf9, 0x0b, 0x04, 0x27, 0x1a, 0x1f, + 0x2f, 0x20, 0x52, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x2e, 0x20, 0x54, 0x68, 0x65, 0x20, + 0x6a, 0x6f, 0x62, 0x20, 0x74, 0x6f, 0x20, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x0a, 0x0a, + 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x3d, 0x02, 0x02, 0x04, 0x12, 0x04, 0xf9, 0x0b, 0x04, 0x0c, + 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x3d, 0x02, 0x02, 0x06, 0x12, 0x04, 0xf9, 0x0b, 0x0d, + 0x16, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x3d, 0x02, 0x02, 0x01, 0x12, 0x04, 0xf9, 0x0b, + 0x17, 0x22, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x3d, 0x02, 0x02, 0x03, 0x12, 0x04, 0xf9, + 0x0b, 0x25, 0x26, 0x0a, 0x99, 0x03, 0x0a, 0x04, 0x04, 0x00, 0x03, 0x3e, 0x12, 0x06, 0x8b, 0x0c, + 0x02, 0x8d, 0x0c, 0x03, 0x1a, 0x88, 0x03, 0x0a, 0x20, 0x47, 0x65, 0x74, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x65, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x20, 0x72, 0x61, 0x74, 0x65, 0x20, 0x62, + 0x65, 0x74, 0x77, 0x65, 0x65, 0x6e, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x45, 0x78, 0x70, 0x6f, 0x6e, + 0x65, 0x6e, 0x74, 0x20, 0x76, 0x61, 0x75, 0x6c, 0x74, 0x20, 0x70, 0x72, 0x69, 0x63, 0x69, 0x70, + 0x61, 0x6c, 0x20, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x20, 0x61, 0x6e, 0x64, 0x0a, 0x20, 0x75, 0x6e, + 0x64, 0x65, 0x72, 0x6c, 0x79, 0x69, 0x6e, 0x67, 0x20, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x2e, 0x0a, + 0x20, 0x5f, 0x2a, 0x2a, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x2a, 0x2a, 0x5f, 0x3a, 0x20, 0x56, 0x61, + 0x75, 0x6c, 0x74, 0x20, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x0a, 0x20, 0x5f, 0x2a, 0x2a, + 0x52, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x73, 0x2a, 0x2a, 0x5f, 0x3a, 0x20, 0x54, 0x68, 0x65, 0x20, + 0x65, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x20, 0x72, 0x61, 0x74, 0x65, 0x20, 0x62, 0x65, + 0x74, 0x77, 0x65, 0x65, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x76, 0x61, 0x75, 0x6c, 0x74, 0x20, + 0x70, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, 0x20, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x20, + 0x61, 0x6e, 0x64, 0x0a, 0x20, 0x75, 0x6e, 0x64, 0x65, 0x72, 0x6c, 0x79, 0x69, 0x6e, 0x67, 0x20, + 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x2e, 0x0a, 0x20, 0x5f, 0x2a, 0x2a, 0x45, 0x78, 0x61, 0x6d, 0x70, + 0x6c, 0x65, 0x2a, 0x2a, 0x5f, 0x3a, 0x20, 0x47, 0x65, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x65, + 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x20, 0x72, 0x61, 0x74, 0x65, 0x20, 0x62, 0x65, 0x74, + 0x77, 0x65, 0x65, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x76, 0x61, 0x75, 0x6c, 0x74, 0x20, 0x70, + 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, 0x20, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x20, 0x61, + 0x6e, 0x64, 0x0a, 0x20, 0x75, 0x6e, 0x64, 0x65, 0x72, 0x6c, 0x79, 0x69, 0x6e, 0x67, 0x20, 0x74, + 0x6f, 0x6b, 0x65, 0x6e, 0x2e, 0x0a, 0x20, 0x60, 0x60, 0x60, 0x6a, 0x73, 0x6f, 0x6e, 0x0a, 0x7b, + 0x0a, 0x22, 0x65, 0x78, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x54, 0x61, 0x73, 0x6b, 0x22, 0x3a, + 0x20, 0x7b, 0x0a, 0x22, 0x76, 0x61, 0x75, 0x6c, 0x74, 0x22, 0x3a, 0x20, 0x22, 0x39, 0x59, 0x62, + 0x61, 0x69, 0x63, 0x4d, 0x73, 0x58, 0x72, 0x74, 0x75, 0x70, 0x6b, 0x70, 0x44, 0x37, 0x32, 0x70, + 0x64, 0x57, 0x42, 0x66, 0x55, 0x36, 0x52, 0x37, 0x45, 0x4a, 0x66, 0x53, 0x42, 0x79, 0x77, 0x37, + 0x35, 0x73, 0x45, 0x70, 0x44, 0x4d, 0x31, 0x75, 0x48, 0x22, 0x0a, 0x7d, 0x0a, 0x7d, 0x0a, 0x0a, + 0x0d, 0x0a, 0x05, 0x04, 0x00, 0x03, 0x3e, 0x01, 0x12, 0x04, 0x8b, 0x0c, 0x0a, 0x16, 0x0a, 0x0e, + 0x0a, 0x06, 0x04, 0x00, 0x03, 0x3e, 0x02, 0x00, 0x12, 0x04, 0x8c, 0x0c, 0x04, 0x1e, 0x0a, 0x0f, + 0x0a, 0x07, 0x04, 0x00, 0x03, 0x3e, 0x02, 0x00, 0x04, 0x12, 0x04, 0x8c, 0x0c, 0x04, 0x0c, 0x0a, + 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x3e, 0x02, 0x00, 0x05, 0x12, 0x04, 0x8c, 0x0c, 0x0d, 0x13, + 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x3e, 0x02, 0x00, 0x01, 0x12, 0x04, 0x8c, 0x0c, 0x14, + 0x19, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x3e, 0x02, 0x00, 0x03, 0x12, 0x04, 0x8c, 0x0c, + 0x1c, 0x1d, 0x0a, 0x0e, 0x0a, 0x04, 0x04, 0x00, 0x03, 0x3f, 0x12, 0x06, 0x8f, 0x0c, 0x02, 0x92, + 0x0c, 0x03, 0x0a, 0x0d, 0x0a, 0x05, 0x04, 0x00, 0x03, 0x3f, 0x01, 0x12, 0x04, 0x8f, 0x0c, 0x0a, + 0x25, 0x0a, 0x0e, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x3f, 0x02, 0x00, 0x12, 0x04, 0x90, 0x0c, 0x04, + 0x1e, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x3f, 0x02, 0x00, 0x04, 0x12, 0x04, 0x90, 0x0c, + 0x04, 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x3f, 0x02, 0x00, 0x05, 0x12, 0x04, 0x90, + 0x0c, 0x0d, 0x13, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x3f, 0x02, 0x00, 0x01, 0x12, 0x04, + 0x90, 0x0c, 0x14, 0x19, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x3f, 0x02, 0x00, 0x03, 0x12, + 0x04, 0x90, 0x0c, 0x1c, 0x1d, 0x0a, 0x0e, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x3f, 0x02, 0x01, 0x12, + 0x04, 0x91, 0x0c, 0x04, 0x24, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x3f, 0x02, 0x01, 0x04, + 0x12, 0x04, 0x91, 0x0c, 0x04, 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x3f, 0x02, 0x01, + 0x05, 0x12, 0x04, 0x91, 0x0c, 0x0d, 0x13, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x3f, 0x02, + 0x01, 0x01, 0x12, 0x04, 0x91, 0x0c, 0x14, 0x1f, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x3f, + 0x02, 0x01, 0x03, 0x12, 0x04, 0x91, 0x0c, 0x22, 0x23, 0x0a, 0xbd, 0x01, 0x0a, 0x04, 0x04, 0x00, + 0x03, 0x40, 0x12, 0x06, 0x99, 0x0c, 0x02, 0x9f, 0x0c, 0x03, 0x1a, 0xac, 0x01, 0x0a, 0x20, 0x41, + 0x70, 0x70, 0x6c, 0x79, 0x20, 0x53, 0x6f, 0x6c, 0x61, 0x6e, 0x61, 0x20, 0x54, 0x6f, 0x6b, 0x65, + 0x6e, 0x20, 0x32, 0x30, 0x32, 0x32, 0x20, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, + 0x20, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x61, 0x20, + 0x66, 0x65, 0x65, 0x64, 0x2e, 0x0a, 0x20, 0x5f, 0x2a, 0x2a, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x2a, + 0x2a, 0x5f, 0x3a, 0x20, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x20, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, + 0x73, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x20, + 0x74, 0x79, 0x70, 0x65, 0x2e, 0x0a, 0x20, 0x5f, 0x2a, 0x2a, 0x52, 0x65, 0x74, 0x75, 0x72, 0x6e, + 0x73, 0x2a, 0x2a, 0x5f, 0x3a, 0x20, 0x54, 0x68, 0x65, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x20, + 0x61, 0x73, 0x73, 0x6f, 0x63, 0x69, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x32, 0x30, 0x32, 0x32, 0x20, 0x65, 0x78, + 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x2e, 0x0a, 0x0a, 0x0d, 0x0a, 0x05, 0x04, 0x00, 0x03, + 0x40, 0x01, 0x12, 0x04, 0x99, 0x0c, 0x0a, 0x26, 0x0a, 0x10, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x40, + 0x04, 0x00, 0x12, 0x06, 0x9a, 0x0c, 0x04, 0x9c, 0x0c, 0x05, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, + 0x03, 0x40, 0x04, 0x00, 0x01, 0x12, 0x04, 0x9a, 0x0c, 0x09, 0x1b, 0x0a, 0x10, 0x0a, 0x08, 0x04, + 0x00, 0x03, 0x40, 0x04, 0x00, 0x02, 0x00, 0x12, 0x04, 0x9b, 0x0c, 0x06, 0x2a, 0x0a, 0x11, 0x0a, + 0x09, 0x04, 0x00, 0x03, 0x40, 0x04, 0x00, 0x02, 0x00, 0x01, 0x12, 0x04, 0x9b, 0x0c, 0x06, 0x25, + 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x40, 0x04, 0x00, 0x02, 0x00, 0x02, 0x12, 0x04, 0x9b, + 0x0c, 0x28, 0x29, 0x0a, 0x0e, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x40, 0x02, 0x00, 0x12, 0x04, 0x9d, + 0x0c, 0x04, 0x1d, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x40, 0x02, 0x00, 0x04, 0x12, 0x04, + 0x9d, 0x0c, 0x04, 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x40, 0x02, 0x00, 0x05, 0x12, + 0x04, 0x9d, 0x0c, 0x0d, 0x13, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x40, 0x02, 0x00, 0x01, + 0x12, 0x04, 0x9d, 0x0c, 0x14, 0x18, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x40, 0x02, 0x00, + 0x03, 0x12, 0x04, 0x9d, 0x0c, 0x1b, 0x1c, 0x0a, 0x0e, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x40, 0x02, + 0x01, 0x12, 0x04, 0x9e, 0x0c, 0x04, 0x2e, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x40, 0x02, + 0x01, 0x04, 0x12, 0x04, 0x9e, 0x0c, 0x04, 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x40, + 0x02, 0x01, 0x06, 0x12, 0x04, 0x9e, 0x0c, 0x0d, 0x1f, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, + 0x40, 0x02, 0x01, 0x01, 0x12, 0x04, 0x9e, 0x0c, 0x20, 0x29, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, + 0x03, 0x40, 0x02, 0x01, 0x03, 0x12, 0x04, 0x9e, 0x0c, 0x2c, 0x2d, 0x0a, 0xc7, 0x0b, 0x0a, 0x04, + 0x04, 0x00, 0x03, 0x41, 0x12, 0x06, 0xcf, 0x0c, 0x02, 0xdb, 0x0c, 0x03, 0x1a, 0xb6, 0x0b, 0x0a, + 0x20, 0x46, 0x65, 0x74, 0x63, 0x68, 0x20, 0x61, 0x20, 0x2a, 0x6c, 0x69, 0x76, 0x65, 0x2a, 0x20, + 0x73, 0x70, 0x6f, 0x74, 0x20, 0x70, 0x72, 0x69, 0x63, 0x65, 0x20, 0x73, 0x74, 0x72, 0x61, 0x69, + 0x67, 0x68, 0x74, 0x20, 0x6f, 0x75, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x67, + 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x20, 0x2a, 0x2a, 0x53, 0x75, 0x72, 0x67, 0x65, 0x2a, 0x2a, 0x20, + 0x77, 0x65, 0x62, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x0a, 0x20, 0x63, 0x61, 0x63, 0x68, 0x65, + 0x20, 0xe2, 0x80, 0x93, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x61, 0x6d, 0x65, 0x20, 0x63, 0x61, + 0x63, 0x68, 0x65, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x73, 0x20, + 0x6f, 0x75, 0x72, 0x20, 0x68, 0x69, 0x67, 0x68, 0x2d, 0x73, 0x70, 0x65, 0x65, 0x64, 0x20, 0x6f, + 0x6e, 0x2d, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x20, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x73, 0x2e, + 0x0a, 0x0a, 0x20, 0x5f, 0x2a, 0x2a, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x2a, 0x2a, 0x5f, 0x0a, 0x20, + 0xe2, 0x80, 0xa2, 0x20, 0x60, 0x73, 0x79, 0x6d, 0x62, 0x6f, 0x6c, 0x60, 0x20, 0xe2, 0x80, 0x93, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x72, 0x61, 0x64, 0x69, 0x6e, 0x67, 0x2d, 0x70, 0x61, 0x69, + 0x72, 0x20, 0x73, 0x79, 0x6d, 0x62, 0x6f, 0x6c, 0x20, 0x61, 0x73, 0x20, 0x69, 0x74, 0x20, 0x61, + 0x70, 0x70, 0x65, 0x61, 0x72, 0x73, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x65, 0x78, + 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x0a, 0x20, 0xe2, 0x80, 0xa2, 0x20, 0x60, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x60, 0x20, 0xe2, 0x80, 0x93, 0x20, 0x77, 0x68, 0x69, 0x63, 0x68, 0x20, 0x65, + 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0xe2, 0x80, 0x99, 0x73, 0x20, 0x73, 0x74, 0x72, 0x65, + 0x61, 0x6d, 0x20, 0x74, 0x6f, 0x20, 0x72, 0x65, 0x61, 0x64, 0x20, 0x66, 0x72, 0x6f, 0x6d, 0x0a, + 0x20, 0x20, 0x20, 0xe2, 0x80, 0xa2, 0x20, 0x60, 0x42, 0x49, 0x4e, 0x41, 0x4e, 0x43, 0x45, 0x60, + 0x20, 0x20, 0x20, 0x28, 0x77, 0x65, 0x69, 0x67, 0x68, 0x74, 0x20, 0x33, 0x29, 0x0a, 0x20, 0x20, + 0x20, 0xe2, 0x80, 0xa2, 0x20, 0x60, 0x42, 0x59, 0x42, 0x49, 0x54, 0x60, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x28, 0x77, 0x65, 0x69, 0x67, 0x68, 0x74, 0x20, 0x32, 0x29, 0x0a, 0x20, 0x20, 0x20, 0xe2, + 0x80, 0xa2, 0x20, 0x60, 0x4f, 0x4b, 0x58, 0x60, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x28, + 0x77, 0x65, 0x69, 0x67, 0x68, 0x74, 0x20, 0x32, 0x29, 0x0a, 0x20, 0x20, 0x20, 0xe2, 0x80, 0xa2, + 0x20, 0x60, 0x43, 0x4f, 0x49, 0x4e, 0x42, 0x41, 0x53, 0x45, 0x60, 0x20, 0x20, 0x28, 0x77, 0x65, + 0x69, 0x67, 0x68, 0x74, 0x20, 0x31, 0x29, 0x0a, 0x20, 0x20, 0x20, 0xe2, 0x80, 0xa2, 0x20, 0x60, + 0x57, 0x45, 0x49, 0x47, 0x48, 0x54, 0x45, 0x44, 0x60, 0x20, 0x20, 0x28, 0x64, 0x65, 0x66, 0x61, + 0x75, 0x6c, 0x74, 0x29, 0x20, 0xe2, 0x80, 0x93, 0x20, 0x75, 0x73, 0x65, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x2a, 0x77, 0x65, 0x69, 0x67, 0x68, 0x74, 0x65, 0x64, 0x20, 0x6d, 0x65, 0x64, 0x69, 0x61, + 0x6e, 0x2a, 0x20, 0x6f, 0x66, 0x20, 0x61, 0x6c, 0x6c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x66, + 0x72, 0x65, 0x73, 0x68, 0x20, 0x71, 0x75, 0x6f, 0x74, 0x65, 0x73, 0x20, 0x28, 0x3c, 0x3d, 0x20, + 0x35, 0x20, 0x73, 0x20, 0x6f, 0x6c, 0x64, 0x29, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x77, 0x65, 0x69, 0x67, 0x68, 0x74, 0x73, 0x20, 0x73, 0x68, 0x6f, 0x77, 0x6e, 0x20, + 0x61, 0x62, 0x6f, 0x76, 0x65, 0x2e, 0x0a, 0x0a, 0x20, 0x5f, 0x2a, 0x2a, 0x52, 0x65, 0x74, 0x75, + 0x72, 0x6e, 0x73, 0x2a, 0x2a, 0x5f, 0x0a, 0x20, 0x54, 0x68, 0x65, 0x20, 0x6d, 0x6f, 0x73, 0x74, + 0x20, 0x72, 0x65, 0x63, 0x65, 0x6e, 0x74, 0x20, 0x70, 0x72, 0x69, 0x63, 0x65, 0x20, 0x61, 0x76, + 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x66, 0x72, 0x6f, 0x6d, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x63, 0x68, 0x6f, 0x73, 0x65, 0x6e, 0x20, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x0a, + 0x20, 0x54, 0x68, 0x65, 0x20, 0x74, 0x61, 0x73, 0x6b, 0x20, 0x66, 0x61, 0x69, 0x6c, 0x73, 0x20, + 0x69, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x61, 0x63, 0x68, 0x65, 0x64, 0x20, 0x74, 0x69, + 0x63, 0x6b, 0x20, 0x69, 0x73, 0x20, 0x6f, 0x6c, 0x64, 0x65, 0x72, 0x20, 0x74, 0x68, 0x61, 0x6e, + 0x20, 0x2a, 0x2a, 0x35, 0x20, 0x73, 0x2a, 0x2a, 0x2e, 0x0a, 0x0a, 0x20, 0x5f, 0x2a, 0x2a, 0x45, + 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2a, 0x2a, 0x5f, 0x3a, 0x20, 0x50, 0x75, 0x6c, 0x6c, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x42, 0x69, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x20, 0x70, 0x72, 0x69, 0x63, + 0x65, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x42, 0x54, 0x43, 0x20, 0x2f, 0x20, 0x55, 0x53, 0x44, 0x54, + 0x0a, 0x20, 0x60, 0x60, 0x60, 0x6a, 0x73, 0x6f, 0x6e, 0x0a, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, + 0x22, 0x73, 0x77, 0x69, 0x74, 0x63, 0x68, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x53, 0x75, 0x72, 0x67, + 0x65, 0x54, 0x61, 0x73, 0x6b, 0x22, 0x3a, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x22, 0x3a, 0x20, 0x22, 0x42, 0x49, 0x4e, 0x41, 0x4e, 0x43, + 0x45, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x73, 0x79, 0x6d, 0x62, 0x6f, 0x6c, + 0x22, 0x3a, 0x20, 0x22, 0x42, 0x54, 0x43, 0x55, 0x53, 0x44, 0x54, 0x22, 0x0a, 0x20, 0x20, 0x20, + 0x7d, 0x0a, 0x20, 0x7d, 0x0a, 0x20, 0x60, 0x60, 0x60, 0x0a, 0x0a, 0x20, 0x5f, 0x2a, 0x2a, 0x45, + 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2a, 0x2a, 0x5f, 0x3a, 0x20, 0x55, 0x73, 0x65, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x77, 0x65, 0x69, 0x67, 0x68, 0x74, 0x65, 0x64, 0x2d, 0x6d, 0x65, 0x64, 0x69, + 0x61, 0x6e, 0x20, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x42, 0x54, + 0x43, 0x20, 0x2f, 0x20, 0x55, 0x53, 0x44, 0x54, 0x0a, 0x20, 0x60, 0x60, 0x60, 0x6a, 0x73, 0x6f, + 0x6e, 0x0a, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x22, 0x73, 0x77, 0x69, 0x74, 0x63, 0x68, 0x62, + 0x6f, 0x61, 0x72, 0x64, 0x53, 0x75, 0x72, 0x67, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x22, 0x3a, 0x20, + 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x22, 0x3a, + 0x20, 0x22, 0x57, 0x45, 0x49, 0x47, 0x48, 0x54, 0x45, 0x44, 0x22, 0x2c, 0x20, 0x20, 0x20, 0x2f, + 0x2f, 0x20, 0x6f, 0x72, 0x20, 0x6f, 0x6d, 0x69, 0x74, 0x20, 0xe2, 0x80, 0x94, 0x20, 0x57, 0x45, + 0x49, 0x47, 0x48, 0x54, 0x45, 0x44, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x64, 0x65, + 0x66, 0x61, 0x75, 0x6c, 0x74, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x73, 0x79, 0x6d, 0x62, + 0x6f, 0x6c, 0x22, 0x3a, 0x20, 0x22, 0x42, 0x54, 0x43, 0x55, 0x53, 0x44, 0x54, 0x22, 0x0a, 0x20, + 0x20, 0x20, 0x7d, 0x0a, 0x20, 0x7d, 0x0a, 0x20, 0x60, 0x60, 0x60, 0x0a, 0x0a, 0x20, 0x5f, 0x2a, + 0x2a, 0x4e, 0x6f, 0x74, 0x65, 0x73, 0x2a, 0x2a, 0x5f, 0x0a, 0x20, 0xe2, 0x80, 0xa2, 0x20, 0x53, + 0x79, 0x6d, 0x62, 0x6f, 0x6c, 0x73, 0x20, 0x61, 0x72, 0x65, 0x20, 0x61, 0x75, 0x74, 0x6f, 0x2d, + 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x69, 0x73, 0x65, 0x64, 0x20, 0x28, 0x63, 0x61, 0x73, 0x65, + 0x2d, 0x69, 0x6e, 0x73, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x2c, 0x20, 0x70, 0x75, + 0x6e, 0x63, 0x74, 0x75, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, + 0x64, 0x29, 0x2e, 0x0a, 0x20, 0xe2, 0x80, 0xa2, 0x20, 0x49, 0x66, 0x20, 0x61, 0x20, 0x76, 0x65, + 0x6e, 0x75, 0x65, 0xe2, 0x80, 0x99, 0x73, 0x20, 0x70, 0x72, 0x69, 0x63, 0x65, 0x20, 0x69, 0x73, + 0x20, 0x73, 0x74, 0x61, 0x6c, 0x65, 0x20, 0x28, 0x3e, 0x20, 0x35, 0x20, 0x73, 0x29, 0x20, 0x69, + 0x74, 0x20, 0x69, 0x73, 0x20, 0x69, 0x67, 0x6e, 0x6f, 0x72, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x57, 0x45, 0x49, 0x47, 0x48, 0x54, 0x45, 0x44, 0x0a, 0x20, 0x20, 0x20, + 0x63, 0x61, 0x6c, 0x63, 0x75, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x20, 0x20, 0x54, 0x68, + 0x65, 0x20, 0x74, 0x61, 0x73, 0x6b, 0x20, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x73, 0x20, 0x69, 0x66, + 0x20, 0x2a, 0x2a, 0x6e, 0x6f, 0x2a, 0x2a, 0x20, 0x66, 0x72, 0x65, 0x73, 0x68, 0x20, 0x70, 0x72, + 0x69, 0x63, 0x65, 0x20, 0x72, 0x65, 0x6d, 0x61, 0x69, 0x6e, 0x73, 0x2e, 0x0a, 0x20, 0xe2, 0x80, + 0xa2, 0x20, 0x54, 0x68, 0x65, 0x20, 0x77, 0x65, 0x69, 0x67, 0x68, 0x74, 0x65, 0x64, 0x2d, 0x6d, + 0x65, 0x64, 0x69, 0x61, 0x6e, 0x20, 0x61, 0x6c, 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x20, + 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x61, 0x6d, 0x65, 0x20, 0x6f, 0x6e, 0x65, 0x20, + 0x48, 0x79, 0x70, 0x65, 0x72, 0x6c, 0x69, 0x71, 0x75, 0x69, 0x64, 0x20, 0x75, 0x73, 0x65, 0x73, + 0x20, 0x69, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x3a, 0x20, 0x63, 0x75, 0x6d, 0x75, 0x6c, 0x61, 0x74, 0x69, 0x76, 0x65, 0x20, 0x77, 0x65, + 0x69, 0x67, 0x68, 0x74, 0x73, 0x20, 0x33, 0x20, 0x2f, 0x20, 0x32, 0x20, 0x2f, 0x20, 0x32, 0x20, + 0x2f, 0x20, 0x31, 0x20, 0x2f, 0x20, 0x31, 0x20, 0x2f, 0x20, 0x31, 0x20, 0x2f, 0x20, 0x31, 0x20, + 0x2f, 0x20, 0x31, 0x20, 0x61, 0x63, 0x72, 0x6f, 0x73, 0x73, 0x20, 0x74, 0x68, 0x65, 0x0a, 0x20, + 0x20, 0x20, 0x65, 0x69, 0x67, 0x68, 0x74, 0x20, 0x76, 0x65, 0x6e, 0x75, 0x65, 0x73, 0x20, 0x28, + 0x77, 0x65, 0x20, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x6c, 0x79, 0x20, 0x73, 0x74, 0x72, + 0x65, 0x61, 0x6d, 0x20, 0x74, 0x68, 0x65, 0x20, 0x66, 0x69, 0x72, 0x73, 0x74, 0x20, 0x66, 0x6f, + 0x75, 0x72, 0x29, 0x2e, 0x0a, 0x0a, 0x0d, 0x0a, 0x05, 0x04, 0x00, 0x03, 0x41, 0x01, 0x12, 0x04, + 0xcf, 0x0c, 0x0a, 0x1e, 0x0a, 0x10, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x41, 0x04, 0x00, 0x12, 0x06, + 0xd0, 0x0c, 0x04, 0xd6, 0x0c, 0x05, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x41, 0x04, 0x00, + 0x01, 0x12, 0x04, 0xd0, 0x0c, 0x09, 0x0f, 0x0a, 0x10, 0x0a, 0x08, 0x04, 0x00, 0x03, 0x41, 0x04, + 0x00, 0x02, 0x00, 0x12, 0x04, 0xd1, 0x0c, 0x06, 0x14, 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, + 0x41, 0x04, 0x00, 0x02, 0x00, 0x01, 0x12, 0x04, 0xd1, 0x0c, 0x06, 0x0e, 0x0a, 0x11, 0x0a, 0x09, + 0x04, 0x00, 0x03, 0x41, 0x04, 0x00, 0x02, 0x00, 0x02, 0x12, 0x04, 0xd1, 0x0c, 0x12, 0x13, 0x0a, + 0x10, 0x0a, 0x08, 0x04, 0x00, 0x03, 0x41, 0x04, 0x00, 0x02, 0x01, 0x12, 0x04, 0xd2, 0x0c, 0x06, + 0x14, 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x41, 0x04, 0x00, 0x02, 0x01, 0x01, 0x12, 0x04, + 0xd2, 0x0c, 0x06, 0x0d, 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x41, 0x04, 0x00, 0x02, 0x01, + 0x02, 0x12, 0x04, 0xd2, 0x0c, 0x12, 0x13, 0x0a, 0x10, 0x0a, 0x08, 0x04, 0x00, 0x03, 0x41, 0x04, + 0x00, 0x02, 0x02, 0x12, 0x04, 0xd3, 0x0c, 0x06, 0x14, 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, + 0x41, 0x04, 0x00, 0x02, 0x02, 0x01, 0x12, 0x04, 0xd3, 0x0c, 0x06, 0x09, 0x0a, 0x11, 0x0a, 0x09, + 0x04, 0x00, 0x03, 0x41, 0x04, 0x00, 0x02, 0x02, 0x02, 0x12, 0x04, 0xd3, 0x0c, 0x12, 0x13, 0x0a, + 0x10, 0x0a, 0x08, 0x04, 0x00, 0x03, 0x41, 0x04, 0x00, 0x02, 0x03, 0x12, 0x04, 0xd4, 0x0c, 0x06, + 0x14, 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x41, 0x04, 0x00, 0x02, 0x03, 0x01, 0x12, 0x04, + 0xd4, 0x0c, 0x06, 0x0b, 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, 0x41, 0x04, 0x00, 0x02, 0x03, + 0x02, 0x12, 0x04, 0xd4, 0x0c, 0x12, 0x13, 0x0a, 0x10, 0x0a, 0x08, 0x04, 0x00, 0x03, 0x41, 0x04, + 0x00, 0x02, 0x04, 0x12, 0x04, 0xd5, 0x0c, 0x06, 0x14, 0x0a, 0x11, 0x0a, 0x09, 0x04, 0x00, 0x03, + 0x41, 0x04, 0x00, 0x02, 0x04, 0x01, 0x12, 0x04, 0xd5, 0x0c, 0x06, 0x0e, 0x0a, 0x11, 0x0a, 0x09, + 0x04, 0x00, 0x03, 0x41, 0x04, 0x00, 0x02, 0x04, 0x02, 0x12, 0x04, 0xd5, 0x0c, 0x12, 0x13, 0x0a, + 0x72, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x41, 0x02, 0x00, 0x12, 0x04, 0xd9, 0x0c, 0x04, 0x1f, 0x1a, + 0x62, 0x20, 0x44, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x65, 0x73, 0x20, 0x77, 0x68, 0x69, + 0x63, 0x68, 0x20, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x20, 0x77, 0x69, 0x6c, 0x6c, 0x20, 0x62, + 0x65, 0x20, 0x75, 0x73, 0x65, 0x64, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x70, 0x72, 0x69, 0x63, 0x69, + 0x6e, 0x67, 0x2e, 0x0a, 0x20, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x3a, 0x20, 0x57, 0x45, + 0x49, 0x47, 0x48, 0x54, 0x45, 0x44, 0x20, 0x61, 0x76, 0x65, 0x72, 0x61, 0x67, 0x65, 0x20, 0x61, + 0x63, 0x72, 0x6f, 0x73, 0x73, 0x20, 0x61, 0x6c, 0x6c, 0x20, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, + 0x73, 0x2e, 0x0a, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x41, 0x02, 0x00, 0x04, 0x12, 0x04, + 0xd9, 0x0c, 0x04, 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x41, 0x02, 0x00, 0x06, 0x12, + 0x04, 0xd9, 0x0c, 0x0d, 0x13, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x41, 0x02, 0x00, 0x01, + 0x12, 0x04, 0xd9, 0x0c, 0x14, 0x1a, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x41, 0x02, 0x00, + 0x03, 0x12, 0x04, 0xd9, 0x0c, 0x1d, 0x1e, 0x0a, 0x0e, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x41, 0x02, + 0x01, 0x12, 0x04, 0xda, 0x0c, 0x04, 0x1f, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x41, 0x02, + 0x01, 0x04, 0x12, 0x04, 0xda, 0x0c, 0x04, 0x0c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x41, + 0x02, 0x01, 0x05, 0x12, 0x04, 0xda, 0x0c, 0x0d, 0x13, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, + 0x41, 0x02, 0x01, 0x01, 0x12, 0x04, 0xda, 0x0c, 0x14, 0x1a, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, + 0x03, 0x41, 0x02, 0x01, 0x03, 0x12, 0x04, 0xda, 0x0c, 0x1d, 0x1e, 0x0a, 0x70, 0x0a, 0x04, 0x04, + 0x00, 0x03, 0x42, 0x12, 0x06, 0xde, 0x0c, 0x02, 0xab, 0x0d, 0x03, 0x1a, 0x60, 0x2f, 0x20, 0x52, + 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x73, 0x20, 0x61, 0x20, 0x73, 0x69, 0x6e, 0x67, + 0x75, 0x6c, 0x61, 0x72, 0x20, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x70, + 0x65, 0x72, 0x66, 0x6f, 0x72, 0x6d, 0x65, 0x64, 0x20, 0x62, 0x79, 0x20, 0x61, 0x6e, 0x20, 0x6f, + 0x72, 0x61, 0x63, 0x6c, 0x65, 0x20, 0x74, 0x6f, 0x20, 0x79, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x61, + 0x6e, 0x20, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x75, 0x61, 0x6c, 0x20, 0x6e, 0x75, 0x6d, 0x65, 0x72, + 0x69, 0x63, 0x61, 0x6c, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x2e, 0x0a, 0x0a, 0x0d, 0x0a, + 0x05, 0x04, 0x00, 0x03, 0x42, 0x01, 0x12, 0x04, 0xde, 0x0c, 0x0a, 0x0e, 0x0a, 0x3c, 0x0a, 0x05, + 0x04, 0x00, 0x03, 0x42, 0x09, 0x12, 0x04, 0xe0, 0x0c, 0x04, 0x10, 0x1a, 0x2d, 0x20, 0x52, 0x65, + 0x73, 0x65, 0x72, 0x76, 0x65, 0x20, 0x6f, 0x62, 0x73, 0x6f, 0x6c, 0x65, 0x74, 0x65, 0x20, 0x74, + 0x61, 0x73, 0x6b, 0x20, 0x6b, 0x65, 0x79, 0x73, 0x20, 0x2f, 0x20, 0x66, 0x69, 0x65, 0x6c, 0x64, + 0x20, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x2e, 0x0a, 0x0a, 0x0e, 0x0a, 0x06, 0x04, 0x00, + 0x03, 0x42, 0x09, 0x00, 0x12, 0x04, 0xe0, 0x0c, 0x0d, 0x0f, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, + 0x03, 0x42, 0x09, 0x00, 0x01, 0x12, 0x04, 0xe0, 0x0c, 0x0d, 0x0f, 0x0a, 0x0f, 0x0a, 0x07, 0x04, + 0x00, 0x03, 0x42, 0x09, 0x00, 0x02, 0x12, 0x04, 0xe0, 0x0c, 0x0d, 0x0f, 0x0a, 0x0d, 0x0a, 0x05, + 0x04, 0x00, 0x03, 0x42, 0x0a, 0x12, 0x04, 0xe1, 0x0c, 0x04, 0x22, 0x0a, 0x0e, 0x0a, 0x06, 0x04, + 0x00, 0x03, 0x42, 0x0a, 0x00, 0x12, 0x04, 0xe1, 0x0c, 0x0d, 0x21, 0x0a, 0x0d, 0x0a, 0x05, 0x04, + 0x00, 0x03, 0x42, 0x09, 0x12, 0x04, 0xe2, 0x0c, 0x04, 0x10, 0x0a, 0x0e, 0x0a, 0x06, 0x04, 0x00, + 0x03, 0x42, 0x09, 0x01, 0x12, 0x04, 0xe2, 0x0c, 0x0d, 0x0f, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, + 0x03, 0x42, 0x09, 0x01, 0x01, 0x12, 0x04, 0xe2, 0x0c, 0x0d, 0x0f, 0x0a, 0x0f, 0x0a, 0x07, 0x04, + 0x00, 0x03, 0x42, 0x09, 0x01, 0x02, 0x12, 0x04, 0xe2, 0x0c, 0x0d, 0x0f, 0x0a, 0x0d, 0x0a, 0x05, + 0x04, 0x00, 0x03, 0x42, 0x0a, 0x12, 0x04, 0xe3, 0x0c, 0x04, 0x18, 0x0a, 0x0e, 0x0a, 0x06, 0x04, + 0x00, 0x03, 0x42, 0x0a, 0x01, 0x12, 0x04, 0xe3, 0x0c, 0x0d, 0x17, 0x0a, 0x0d, 0x0a, 0x05, 0x04, + 0x00, 0x03, 0x42, 0x09, 0x12, 0x04, 0xe4, 0x0c, 0x04, 0x10, 0x0a, 0x0e, 0x0a, 0x06, 0x04, 0x00, + 0x03, 0x42, 0x09, 0x02, 0x12, 0x04, 0xe4, 0x0c, 0x0d, 0x0f, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, + 0x03, 0x42, 0x09, 0x02, 0x01, 0x12, 0x04, 0xe4, 0x0c, 0x0d, 0x0f, 0x0a, 0x0f, 0x0a, 0x07, 0x04, + 0x00, 0x03, 0x42, 0x09, 0x02, 0x02, 0x12, 0x04, 0xe4, 0x0c, 0x0d, 0x0f, 0x0a, 0x0d, 0x0a, 0x05, + 0x04, 0x00, 0x03, 0x42, 0x0a, 0x12, 0x04, 0xe5, 0x0c, 0x04, 0x1d, 0x0a, 0x0e, 0x0a, 0x06, 0x04, + 0x00, 0x03, 0x42, 0x0a, 0x02, 0x12, 0x04, 0xe5, 0x0c, 0x0d, 0x1c, 0x0a, 0x10, 0x0a, 0x06, 0x04, + 0x00, 0x03, 0x42, 0x08, 0x00, 0x12, 0x06, 0xe7, 0x0c, 0x04, 0xaa, 0x0d, 0x05, 0x0a, 0x0f, 0x0a, + 0x07, 0x04, 0x00, 0x03, 0x42, 0x08, 0x00, 0x01, 0x12, 0x04, 0xe7, 0x0c, 0x0a, 0x0e, 0x0a, 0x0e, + 0x0a, 0x06, 0x04, 0x00, 0x03, 0x42, 0x02, 0x00, 0x12, 0x04, 0xe8, 0x0c, 0x06, 0x1d, 0x0a, 0x0f, + 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, 0x00, 0x06, 0x12, 0x04, 0xe8, 0x0c, 0x06, 0x0e, 0x0a, + 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, 0x00, 0x01, 0x12, 0x04, 0xe8, 0x0c, 0x0f, 0x18, + 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, 0x00, 0x03, 0x12, 0x04, 0xe8, 0x0c, 0x1b, + 0x1c, 0x0a, 0x0e, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x42, 0x02, 0x01, 0x12, 0x04, 0xe9, 0x0c, 0x06, + 0x28, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, 0x01, 0x06, 0x12, 0x04, 0xe9, 0x0c, + 0x06, 0x13, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, 0x01, 0x01, 0x12, 0x04, 0xe9, + 0x0c, 0x14, 0x23, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, 0x01, 0x03, 0x12, 0x04, + 0xe9, 0x0c, 0x26, 0x27, 0x0a, 0x0e, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x42, 0x02, 0x02, 0x12, 0x04, + 0xea, 0x0c, 0x06, 0x21, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, 0x02, 0x06, 0x12, + 0x04, 0xea, 0x0c, 0x06, 0x10, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, 0x02, 0x01, + 0x12, 0x04, 0xea, 0x0c, 0x11, 0x1c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, 0x02, + 0x03, 0x12, 0x04, 0xea, 0x0c, 0x1f, 0x20, 0x0a, 0x0e, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x42, 0x02, + 0x03, 0x12, 0x04, 0xeb, 0x0c, 0x06, 0x1d, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, + 0x03, 0x06, 0x12, 0x04, 0xeb, 0x0c, 0x06, 0x0e, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, + 0x02, 0x03, 0x01, 0x12, 0x04, 0xeb, 0x0c, 0x0f, 0x18, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, + 0x42, 0x02, 0x03, 0x03, 0x12, 0x04, 0xeb, 0x0c, 0x1b, 0x1c, 0x0a, 0x0e, 0x0a, 0x06, 0x04, 0x00, + 0x03, 0x42, 0x02, 0x04, 0x12, 0x04, 0xec, 0x0c, 0x06, 0x27, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, + 0x03, 0x42, 0x02, 0x04, 0x06, 0x12, 0x04, 0xec, 0x0c, 0x06, 0x13, 0x0a, 0x0f, 0x0a, 0x07, 0x04, + 0x00, 0x03, 0x42, 0x02, 0x04, 0x01, 0x12, 0x04, 0xec, 0x0c, 0x14, 0x22, 0x0a, 0x0f, 0x0a, 0x07, + 0x04, 0x00, 0x03, 0x42, 0x02, 0x04, 0x03, 0x12, 0x04, 0xec, 0x0c, 0x25, 0x26, 0x0a, 0x0e, 0x0a, + 0x06, 0x04, 0x00, 0x03, 0x42, 0x02, 0x05, 0x12, 0x04, 0xed, 0x0c, 0x06, 0x21, 0x0a, 0x0f, 0x0a, + 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, 0x05, 0x06, 0x12, 0x04, 0xed, 0x0c, 0x06, 0x10, 0x0a, 0x0f, + 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, 0x05, 0x01, 0x12, 0x04, 0xed, 0x0c, 0x11, 0x1c, 0x0a, + 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, 0x05, 0x03, 0x12, 0x04, 0xed, 0x0c, 0x1f, 0x20, + 0x0a, 0x0e, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x42, 0x02, 0x06, 0x12, 0x04, 0xee, 0x0c, 0x06, 0x25, + 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, 0x06, 0x06, 0x12, 0x04, 0xee, 0x0c, 0x06, + 0x12, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, 0x06, 0x01, 0x12, 0x04, 0xee, 0x0c, + 0x13, 0x20, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, 0x06, 0x03, 0x12, 0x04, 0xee, + 0x0c, 0x23, 0x24, 0x0a, 0x0e, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x42, 0x02, 0x07, 0x12, 0x04, 0xef, + 0x0c, 0x06, 0x2f, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, 0x07, 0x06, 0x12, 0x04, + 0xef, 0x0c, 0x06, 0x16, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, 0x07, 0x01, 0x12, + 0x04, 0xef, 0x0c, 0x17, 0x2a, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, 0x07, 0x03, + 0x12, 0x04, 0xef, 0x0c, 0x2d, 0x2e, 0x0a, 0x0e, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x42, 0x02, 0x08, + 0x12, 0x04, 0xf0, 0x0c, 0x06, 0x34, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, 0x08, + 0x06, 0x12, 0x04, 0xf0, 0x0c, 0x06, 0x18, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, + 0x08, 0x01, 0x12, 0x04, 0xf0, 0x0c, 0x19, 0x2e, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, + 0x02, 0x08, 0x03, 0x12, 0x04, 0xf0, 0x0c, 0x31, 0x33, 0x0a, 0x0e, 0x0a, 0x06, 0x04, 0x00, 0x03, + 0x42, 0x02, 0x09, 0x12, 0x04, 0xf1, 0x0c, 0x06, 0x2c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, + 0x42, 0x02, 0x09, 0x06, 0x12, 0x04, 0xf1, 0x0c, 0x06, 0x15, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, + 0x03, 0x42, 0x02, 0x09, 0x01, 0x12, 0x04, 0xf1, 0x0c, 0x16, 0x26, 0x0a, 0x0f, 0x0a, 0x07, 0x04, + 0x00, 0x03, 0x42, 0x02, 0x09, 0x03, 0x12, 0x04, 0xf1, 0x0c, 0x29, 0x2b, 0x0a, 0x0e, 0x0a, 0x06, + 0x04, 0x00, 0x03, 0x42, 0x02, 0x0a, 0x12, 0x04, 0xf2, 0x0c, 0x06, 0x20, 0x0a, 0x0f, 0x0a, 0x07, + 0x04, 0x00, 0x03, 0x42, 0x02, 0x0a, 0x06, 0x12, 0x04, 0xf2, 0x0c, 0x06, 0x0f, 0x0a, 0x0f, 0x0a, + 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, 0x0a, 0x01, 0x12, 0x04, 0xf2, 0x0c, 0x10, 0x1a, 0x0a, 0x0f, + 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, 0x0a, 0x03, 0x12, 0x04, 0xf2, 0x0c, 0x1d, 0x1f, 0x0a, + 0x0e, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x42, 0x02, 0x0b, 0x12, 0x04, 0xf3, 0x0c, 0x06, 0x1c, 0x0a, + 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, 0x0b, 0x06, 0x12, 0x04, 0xf3, 0x0c, 0x06, 0x0d, + 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, 0x0b, 0x01, 0x12, 0x04, 0xf3, 0x0c, 0x0e, + 0x16, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, 0x0b, 0x03, 0x12, 0x04, 0xf3, 0x0c, + 0x19, 0x1b, 0x0a, 0x0e, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x42, 0x02, 0x0c, 0x12, 0x04, 0xf4, 0x0c, + 0x06, 0x2f, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, 0x0c, 0x06, 0x12, 0x04, 0xf4, + 0x0c, 0x06, 0x16, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, 0x0c, 0x01, 0x12, 0x04, + 0xf4, 0x0c, 0x17, 0x29, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, 0x0c, 0x03, 0x12, + 0x04, 0xf4, 0x0c, 0x2c, 0x2e, 0x0a, 0x0e, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x42, 0x02, 0x0d, 0x12, + 0x04, 0xf5, 0x0c, 0x06, 0x2b, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, 0x0d, 0x06, + 0x12, 0x04, 0xf5, 0x0c, 0x06, 0x14, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, 0x0d, + 0x01, 0x12, 0x04, 0xf5, 0x0c, 0x15, 0x25, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, + 0x0d, 0x03, 0x12, 0x04, 0xf5, 0x0c, 0x28, 0x2a, 0x0a, 0x0e, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x42, + 0x02, 0x0e, 0x12, 0x04, 0xf6, 0x0c, 0x06, 0x1c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, + 0x02, 0x0e, 0x06, 0x12, 0x04, 0xf6, 0x0c, 0x06, 0x0d, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, + 0x42, 0x02, 0x0e, 0x01, 0x12, 0x04, 0xf6, 0x0c, 0x0e, 0x16, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, + 0x03, 0x42, 0x02, 0x0e, 0x03, 0x12, 0x04, 0xf6, 0x0c, 0x19, 0x1b, 0x0a, 0x0e, 0x0a, 0x06, 0x04, + 0x00, 0x03, 0x42, 0x02, 0x0f, 0x12, 0x04, 0xf7, 0x0c, 0x06, 0x26, 0x0a, 0x0f, 0x0a, 0x07, 0x04, + 0x00, 0x03, 0x42, 0x02, 0x0f, 0x06, 0x12, 0x04, 0xf7, 0x0c, 0x06, 0x12, 0x0a, 0x0f, 0x0a, 0x07, + 0x04, 0x00, 0x03, 0x42, 0x02, 0x0f, 0x01, 0x12, 0x04, 0xf7, 0x0c, 0x13, 0x20, 0x0a, 0x0f, 0x0a, + 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, 0x0f, 0x03, 0x12, 0x04, 0xf7, 0x0c, 0x23, 0x25, 0x0a, 0x0e, + 0x0a, 0x06, 0x04, 0x00, 0x03, 0x42, 0x02, 0x10, 0x12, 0x04, 0xf8, 0x0c, 0x06, 0x1e, 0x0a, 0x0f, + 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, 0x10, 0x06, 0x12, 0x04, 0xf8, 0x0c, 0x06, 0x0e, 0x0a, + 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, 0x10, 0x01, 0x12, 0x04, 0xf8, 0x0c, 0x0f, 0x18, + 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, 0x10, 0x03, 0x12, 0x04, 0xf8, 0x0c, 0x1b, + 0x1d, 0x0a, 0x0e, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x42, 0x02, 0x11, 0x12, 0x04, 0xf9, 0x0c, 0x06, + 0x29, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, 0x11, 0x06, 0x12, 0x04, 0xf9, 0x0c, + 0x06, 0x13, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, 0x11, 0x01, 0x12, 0x04, 0xf9, + 0x0c, 0x14, 0x23, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, 0x11, 0x03, 0x12, 0x04, + 0xf9, 0x0c, 0x26, 0x28, 0x0a, 0x0e, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x42, 0x02, 0x12, 0x12, 0x04, + 0xfa, 0x0c, 0x06, 0x1c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, 0x12, 0x06, 0x12, + 0x04, 0xfa, 0x0c, 0x06, 0x0d, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, 0x12, 0x01, + 0x12, 0x04, 0xfa, 0x0c, 0x0e, 0x16, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, 0x12, + 0x03, 0x12, 0x04, 0xfa, 0x0c, 0x19, 0x1b, 0x0a, 0x0e, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x42, 0x02, + 0x13, 0x12, 0x04, 0xfb, 0x0c, 0x06, 0x2d, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, + 0x13, 0x06, 0x12, 0x04, 0xfb, 0x0c, 0x06, 0x15, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, + 0x02, 0x13, 0x01, 0x12, 0x04, 0xfb, 0x0c, 0x16, 0x27, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, + 0x42, 0x02, 0x13, 0x03, 0x12, 0x04, 0xfb, 0x0c, 0x2a, 0x2c, 0x0a, 0x0e, 0x0a, 0x06, 0x04, 0x00, + 0x03, 0x42, 0x02, 0x14, 0x12, 0x04, 0xfc, 0x0c, 0x06, 0x36, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, + 0x03, 0x42, 0x02, 0x14, 0x06, 0x12, 0x04, 0xfc, 0x0c, 0x06, 0x19, 0x0a, 0x0f, 0x0a, 0x07, 0x04, + 0x00, 0x03, 0x42, 0x02, 0x14, 0x01, 0x12, 0x04, 0xfc, 0x0c, 0x1a, 0x30, 0x0a, 0x0f, 0x0a, 0x07, + 0x04, 0x00, 0x03, 0x42, 0x02, 0x14, 0x03, 0x12, 0x04, 0xfc, 0x0c, 0x33, 0x35, 0x0a, 0x0e, 0x0a, + 0x06, 0x04, 0x00, 0x03, 0x42, 0x02, 0x15, 0x12, 0x04, 0xfd, 0x0c, 0x06, 0x2d, 0x0a, 0x0f, 0x0a, + 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, 0x15, 0x06, 0x12, 0x04, 0xfd, 0x0c, 0x06, 0x15, 0x0a, 0x0f, + 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, 0x15, 0x01, 0x12, 0x04, 0xfd, 0x0c, 0x16, 0x27, 0x0a, + 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, 0x15, 0x03, 0x12, 0x04, 0xfd, 0x0c, 0x2a, 0x2c, + 0x0a, 0x0e, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x42, 0x02, 0x16, 0x12, 0x04, 0xfe, 0x0c, 0x06, 0x2b, + 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, 0x16, 0x06, 0x12, 0x04, 0xfe, 0x0c, 0x06, + 0x14, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, 0x16, 0x01, 0x12, 0x04, 0xfe, 0x0c, + 0x15, 0x25, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, 0x16, 0x03, 0x12, 0x04, 0xfe, + 0x0c, 0x28, 0x2a, 0x0a, 0x0e, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x42, 0x02, 0x17, 0x12, 0x04, 0xff, + 0x0c, 0x06, 0x22, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, 0x17, 0x06, 0x12, 0x04, + 0xff, 0x0c, 0x06, 0x10, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, 0x17, 0x01, 0x12, + 0x04, 0xff, 0x0c, 0x11, 0x1c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, 0x17, 0x03, + 0x12, 0x04, 0xff, 0x0c, 0x1f, 0x21, 0x0a, 0x0e, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x42, 0x02, 0x18, + 0x12, 0x04, 0x80, 0x0d, 0x06, 0x2d, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, 0x18, + 0x06, 0x12, 0x04, 0x80, 0x0d, 0x06, 0x15, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, + 0x18, 0x01, 0x12, 0x04, 0x80, 0x0d, 0x16, 0x27, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, + 0x02, 0x18, 0x03, 0x12, 0x04, 0x80, 0x0d, 0x2a, 0x2c, 0x0a, 0x0e, 0x0a, 0x06, 0x04, 0x00, 0x03, + 0x42, 0x02, 0x19, 0x12, 0x04, 0x81, 0x0d, 0x06, 0x30, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, + 0x42, 0x02, 0x19, 0x06, 0x12, 0x04, 0x81, 0x0d, 0x06, 0x16, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, + 0x03, 0x42, 0x02, 0x19, 0x01, 0x12, 0x04, 0x81, 0x0d, 0x17, 0x2a, 0x0a, 0x0f, 0x0a, 0x07, 0x04, + 0x00, 0x03, 0x42, 0x02, 0x19, 0x03, 0x12, 0x04, 0x81, 0x0d, 0x2d, 0x2f, 0x0a, 0x0e, 0x0a, 0x06, + 0x04, 0x00, 0x03, 0x42, 0x02, 0x1a, 0x12, 0x04, 0x82, 0x0d, 0x06, 0x32, 0x0a, 0x0f, 0x0a, 0x07, + 0x04, 0x00, 0x03, 0x42, 0x02, 0x1a, 0x06, 0x12, 0x04, 0x82, 0x0d, 0x06, 0x17, 0x0a, 0x0f, 0x0a, + 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, 0x1a, 0x01, 0x12, 0x04, 0x82, 0x0d, 0x18, 0x2c, 0x0a, 0x0f, + 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, 0x1a, 0x03, 0x12, 0x04, 0x82, 0x0d, 0x2f, 0x31, 0x0a, + 0x0e, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x42, 0x02, 0x1b, 0x12, 0x04, 0x83, 0x0d, 0x06, 0x3e, 0x0a, + 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, 0x1b, 0x06, 0x12, 0x04, 0x83, 0x0d, 0x06, 0x1d, + 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, 0x1b, 0x01, 0x12, 0x04, 0x83, 0x0d, 0x1e, + 0x38, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, 0x1b, 0x03, 0x12, 0x04, 0x83, 0x0d, + 0x3b, 0x3d, 0x0a, 0x0e, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x42, 0x02, 0x1c, 0x12, 0x04, 0x84, 0x0d, + 0x06, 0x42, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, 0x1c, 0x06, 0x12, 0x04, 0x84, + 0x0d, 0x06, 0x1f, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, 0x1c, 0x01, 0x12, 0x04, + 0x84, 0x0d, 0x20, 0x3c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, 0x1c, 0x03, 0x12, + 0x04, 0x84, 0x0d, 0x3f, 0x41, 0x0a, 0x0e, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x42, 0x02, 0x1d, 0x12, + 0x04, 0x85, 0x0d, 0x06, 0x46, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, 0x1d, 0x06, + 0x12, 0x04, 0x85, 0x0d, 0x06, 0x21, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, 0x1d, + 0x01, 0x12, 0x04, 0x85, 0x0d, 0x22, 0x40, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, + 0x1d, 0x03, 0x12, 0x04, 0x85, 0x0d, 0x43, 0x45, 0x0a, 0x0e, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x42, + 0x02, 0x1e, 0x12, 0x04, 0x86, 0x0d, 0x06, 0x20, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, + 0x02, 0x1e, 0x06, 0x12, 0x04, 0x86, 0x0d, 0x06, 0x0f, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, + 0x42, 0x02, 0x1e, 0x01, 0x12, 0x04, 0x86, 0x0d, 0x10, 0x1a, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, + 0x03, 0x42, 0x02, 0x1e, 0x03, 0x12, 0x04, 0x86, 0x0d, 0x1d, 0x1f, 0x0a, 0x0e, 0x0a, 0x06, 0x04, + 0x00, 0x03, 0x42, 0x02, 0x1f, 0x12, 0x04, 0x87, 0x0d, 0x06, 0x33, 0x0a, 0x0f, 0x0a, 0x07, 0x04, + 0x00, 0x03, 0x42, 0x02, 0x1f, 0x06, 0x12, 0x04, 0x87, 0x0d, 0x06, 0x18, 0x0a, 0x0f, 0x0a, 0x07, + 0x04, 0x00, 0x03, 0x42, 0x02, 0x1f, 0x01, 0x12, 0x04, 0x87, 0x0d, 0x19, 0x2d, 0x0a, 0x0f, 0x0a, + 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, 0x1f, 0x03, 0x12, 0x04, 0x87, 0x0d, 0x30, 0x32, 0x0a, 0x0e, + 0x0a, 0x06, 0x04, 0x00, 0x03, 0x42, 0x02, 0x20, 0x12, 0x04, 0x88, 0x0d, 0x06, 0x31, 0x0a, 0x0f, + 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, 0x20, 0x06, 0x12, 0x04, 0x88, 0x0d, 0x06, 0x17, 0x0a, + 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, 0x20, 0x01, 0x12, 0x04, 0x88, 0x0d, 0x18, 0x2b, + 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, 0x20, 0x03, 0x12, 0x04, 0x88, 0x0d, 0x2e, + 0x30, 0x0a, 0x0e, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x42, 0x02, 0x21, 0x12, 0x04, 0x89, 0x0d, 0x06, + 0x45, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, 0x21, 0x06, 0x12, 0x04, 0x89, 0x0d, + 0x06, 0x20, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, 0x21, 0x01, 0x12, 0x04, 0x89, + 0x0d, 0x21, 0x3f, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, 0x21, 0x03, 0x12, 0x04, + 0x89, 0x0d, 0x42, 0x44, 0x0a, 0x0e, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x42, 0x02, 0x22, 0x12, 0x04, + 0x8a, 0x0d, 0x06, 0x3a, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, 0x22, 0x06, 0x12, + 0x04, 0x8a, 0x0d, 0x06, 0x1b, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, 0x22, 0x01, + 0x12, 0x04, 0x8a, 0x0d, 0x1c, 0x34, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, 0x22, + 0x03, 0x12, 0x04, 0x8a, 0x0d, 0x37, 0x39, 0x0a, 0x0e, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x42, 0x02, + 0x23, 0x12, 0x04, 0x8b, 0x0d, 0x06, 0x29, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, + 0x23, 0x06, 0x12, 0x04, 0x8b, 0x0d, 0x06, 0x13, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, + 0x02, 0x23, 0x01, 0x12, 0x04, 0x8b, 0x0d, 0x14, 0x23, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, + 0x42, 0x02, 0x23, 0x03, 0x12, 0x04, 0x8b, 0x0d, 0x26, 0x28, 0x0a, 0x0e, 0x0a, 0x06, 0x04, 0x00, + 0x03, 0x42, 0x02, 0x24, 0x12, 0x04, 0x8c, 0x0d, 0x06, 0x1c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, + 0x03, 0x42, 0x02, 0x24, 0x06, 0x12, 0x04, 0x8c, 0x0d, 0x06, 0x0d, 0x0a, 0x0f, 0x0a, 0x07, 0x04, + 0x00, 0x03, 0x42, 0x02, 0x24, 0x01, 0x12, 0x04, 0x8c, 0x0d, 0x0e, 0x16, 0x0a, 0x0f, 0x0a, 0x07, + 0x04, 0x00, 0x03, 0x42, 0x02, 0x24, 0x03, 0x12, 0x04, 0x8c, 0x0d, 0x19, 0x1b, 0x0a, 0x0e, 0x0a, + 0x06, 0x04, 0x00, 0x03, 0x42, 0x02, 0x25, 0x12, 0x04, 0x8d, 0x0d, 0x06, 0x35, 0x0a, 0x0f, 0x0a, + 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, 0x25, 0x06, 0x12, 0x04, 0x8d, 0x0d, 0x06, 0x19, 0x0a, 0x0f, + 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, 0x25, 0x01, 0x12, 0x04, 0x8d, 0x0d, 0x1a, 0x2f, 0x0a, + 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, 0x25, 0x03, 0x12, 0x04, 0x8d, 0x0d, 0x32, 0x34, + 0x0a, 0x0e, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x42, 0x02, 0x26, 0x12, 0x04, 0x8e, 0x0d, 0x06, 0x1e, + 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, 0x26, 0x06, 0x12, 0x04, 0x8e, 0x0d, 0x06, + 0x0e, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, 0x26, 0x01, 0x12, 0x04, 0x8e, 0x0d, + 0x0f, 0x18, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, 0x26, 0x03, 0x12, 0x04, 0x8e, + 0x0d, 0x1b, 0x1d, 0x0a, 0x0e, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x42, 0x02, 0x27, 0x12, 0x04, 0x8f, + 0x0d, 0x06, 0x1e, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, 0x27, 0x06, 0x12, 0x04, + 0x8f, 0x0d, 0x06, 0x0e, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, 0x27, 0x01, 0x12, + 0x04, 0x8f, 0x0d, 0x0f, 0x18, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, 0x27, 0x03, + 0x12, 0x04, 0x8f, 0x0d, 0x1b, 0x1d, 0x0a, 0x0e, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x42, 0x02, 0x28, + 0x12, 0x04, 0x90, 0x0d, 0x06, 0x2a, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, 0x28, + 0x06, 0x12, 0x04, 0x90, 0x0d, 0x06, 0x14, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, + 0x28, 0x01, 0x12, 0x04, 0x90, 0x0d, 0x15, 0x24, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, + 0x02, 0x28, 0x03, 0x12, 0x04, 0x90, 0x0d, 0x27, 0x29, 0x0a, 0x0e, 0x0a, 0x06, 0x04, 0x00, 0x03, + 0x42, 0x02, 0x29, 0x12, 0x04, 0x91, 0x0d, 0x06, 0x20, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, + 0x42, 0x02, 0x29, 0x06, 0x12, 0x04, 0x91, 0x0d, 0x06, 0x0f, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, + 0x03, 0x42, 0x02, 0x29, 0x01, 0x12, 0x04, 0x91, 0x0d, 0x10, 0x1a, 0x0a, 0x0f, 0x0a, 0x07, 0x04, + 0x00, 0x03, 0x42, 0x02, 0x29, 0x03, 0x12, 0x04, 0x91, 0x0d, 0x1d, 0x1f, 0x0a, 0x0e, 0x0a, 0x06, + 0x04, 0x00, 0x03, 0x42, 0x02, 0x2a, 0x12, 0x04, 0x92, 0x0d, 0x06, 0x20, 0x0a, 0x0f, 0x0a, 0x07, + 0x04, 0x00, 0x03, 0x42, 0x02, 0x2a, 0x06, 0x12, 0x04, 0x92, 0x0d, 0x06, 0x0f, 0x0a, 0x0f, 0x0a, + 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, 0x2a, 0x01, 0x12, 0x04, 0x92, 0x0d, 0x10, 0x1a, 0x0a, 0x0f, + 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, 0x2a, 0x03, 0x12, 0x04, 0x92, 0x0d, 0x1d, 0x1f, 0x0a, + 0x0e, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x42, 0x02, 0x2b, 0x12, 0x04, 0x93, 0x0d, 0x06, 0x24, 0x0a, + 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, 0x2b, 0x06, 0x12, 0x04, 0x93, 0x0d, 0x06, 0x11, + 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, 0x2b, 0x01, 0x12, 0x04, 0x93, 0x0d, 0x12, + 0x1e, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, 0x2b, 0x03, 0x12, 0x04, 0x93, 0x0d, + 0x21, 0x23, 0x0a, 0x0e, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x42, 0x02, 0x2c, 0x12, 0x04, 0x94, 0x0d, + 0x06, 0x36, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, 0x2c, 0x06, 0x12, 0x04, 0x94, + 0x0d, 0x06, 0x19, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, 0x2c, 0x01, 0x12, 0x04, + 0x94, 0x0d, 0x1a, 0x30, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, 0x2c, 0x03, 0x12, + 0x04, 0x94, 0x0d, 0x33, 0x35, 0x0a, 0x0e, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x42, 0x02, 0x2d, 0x12, + 0x04, 0x95, 0x0d, 0x06, 0x27, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, 0x2d, 0x06, + 0x12, 0x04, 0x95, 0x0d, 0x06, 0x12, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, 0x2d, + 0x01, 0x12, 0x04, 0x95, 0x0d, 0x13, 0x21, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, + 0x2d, 0x03, 0x12, 0x04, 0x95, 0x0d, 0x24, 0x26, 0x0a, 0x0e, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x42, + 0x02, 0x2e, 0x12, 0x04, 0x96, 0x0d, 0x06, 0x2d, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, + 0x02, 0x2e, 0x06, 0x12, 0x04, 0x96, 0x0d, 0x06, 0x15, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, + 0x42, 0x02, 0x2e, 0x01, 0x12, 0x04, 0x96, 0x0d, 0x16, 0x27, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, + 0x03, 0x42, 0x02, 0x2e, 0x03, 0x12, 0x04, 0x96, 0x0d, 0x2a, 0x2c, 0x0a, 0x0e, 0x0a, 0x06, 0x04, + 0x00, 0x03, 0x42, 0x02, 0x2f, 0x12, 0x04, 0x97, 0x0d, 0x06, 0x27, 0x0a, 0x0f, 0x0a, 0x07, 0x04, + 0x00, 0x03, 0x42, 0x02, 0x2f, 0x06, 0x12, 0x04, 0x97, 0x0d, 0x06, 0x12, 0x0a, 0x0f, 0x0a, 0x07, + 0x04, 0x00, 0x03, 0x42, 0x02, 0x2f, 0x01, 0x12, 0x04, 0x97, 0x0d, 0x13, 0x21, 0x0a, 0x0f, 0x0a, + 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, 0x2f, 0x03, 0x12, 0x04, 0x97, 0x0d, 0x24, 0x26, 0x0a, 0x0e, + 0x0a, 0x06, 0x04, 0x00, 0x03, 0x42, 0x02, 0x30, 0x12, 0x04, 0x98, 0x0d, 0x06, 0x2f, 0x0a, 0x0f, + 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, 0x30, 0x06, 0x12, 0x04, 0x98, 0x0d, 0x06, 0x16, 0x0a, + 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, 0x30, 0x01, 0x12, 0x04, 0x98, 0x0d, 0x17, 0x29, + 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, 0x30, 0x03, 0x12, 0x04, 0x98, 0x0d, 0x2c, + 0x2e, 0x0a, 0x0e, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x42, 0x02, 0x31, 0x12, 0x04, 0x99, 0x0d, 0x06, + 0x20, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, 0x31, 0x06, 0x12, 0x04, 0x99, 0x0d, + 0x06, 0x0f, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, 0x31, 0x01, 0x12, 0x04, 0x99, + 0x0d, 0x10, 0x1a, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, 0x31, 0x03, 0x12, 0x04, + 0x99, 0x0d, 0x1d, 0x1f, 0x0a, 0x0e, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x42, 0x02, 0x32, 0x12, 0x04, + 0x9a, 0x0d, 0x06, 0x20, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, 0x32, 0x06, 0x12, + 0x04, 0x9a, 0x0d, 0x06, 0x0f, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, 0x32, 0x01, + 0x12, 0x04, 0x9a, 0x0d, 0x10, 0x1a, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, 0x32, + 0x03, 0x12, 0x04, 0x9a, 0x0d, 0x1d, 0x1f, 0x0a, 0x0e, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x42, 0x02, + 0x33, 0x12, 0x04, 0x9b, 0x0d, 0x06, 0x1c, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, + 0x33, 0x06, 0x12, 0x04, 0x9b, 0x0d, 0x06, 0x0d, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, + 0x02, 0x33, 0x01, 0x12, 0x04, 0x9b, 0x0d, 0x0e, 0x16, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, + 0x42, 0x02, 0x33, 0x03, 0x12, 0x04, 0x9b, 0x0d, 0x19, 0x1b, 0x0a, 0x0e, 0x0a, 0x06, 0x04, 0x00, + 0x03, 0x42, 0x02, 0x34, 0x12, 0x04, 0x9c, 0x0d, 0x06, 0x2d, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, + 0x03, 0x42, 0x02, 0x34, 0x06, 0x12, 0x04, 0x9c, 0x0d, 0x06, 0x15, 0x0a, 0x0f, 0x0a, 0x07, 0x04, + 0x00, 0x03, 0x42, 0x02, 0x34, 0x01, 0x12, 0x04, 0x9c, 0x0d, 0x16, 0x27, 0x0a, 0x0f, 0x0a, 0x07, + 0x04, 0x00, 0x03, 0x42, 0x02, 0x34, 0x03, 0x12, 0x04, 0x9c, 0x0d, 0x2a, 0x2c, 0x0a, 0x0e, 0x0a, + 0x06, 0x04, 0x00, 0x03, 0x42, 0x02, 0x35, 0x12, 0x04, 0x9d, 0x0d, 0x06, 0x2f, 0x0a, 0x0f, 0x0a, + 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, 0x35, 0x06, 0x12, 0x04, 0x9d, 0x0d, 0x06, 0x16, 0x0a, 0x0f, + 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, 0x35, 0x01, 0x12, 0x04, 0x9d, 0x0d, 0x17, 0x29, 0x0a, + 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, 0x35, 0x03, 0x12, 0x04, 0x9d, 0x0d, 0x2c, 0x2e, + 0x0a, 0x0e, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x42, 0x02, 0x36, 0x12, 0x04, 0x9e, 0x0d, 0x06, 0x45, + 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, 0x36, 0x06, 0x12, 0x04, 0x9e, 0x0d, 0x06, + 0x20, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, 0x36, 0x01, 0x12, 0x04, 0x9e, 0x0d, + 0x21, 0x3f, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, 0x36, 0x03, 0x12, 0x04, 0x9e, + 0x0d, 0x42, 0x44, 0x0a, 0x0e, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x42, 0x02, 0x37, 0x12, 0x04, 0x9f, + 0x0d, 0x06, 0x25, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, 0x37, 0x06, 0x12, 0x04, + 0x9f, 0x0d, 0x06, 0x11, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, 0x37, 0x01, 0x12, + 0x04, 0x9f, 0x0d, 0x12, 0x1f, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, 0x37, 0x03, + 0x12, 0x04, 0x9f, 0x0d, 0x22, 0x24, 0x0a, 0x0e, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x42, 0x02, 0x38, + 0x12, 0x04, 0xa0, 0x0d, 0x06, 0x2a, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, 0x38, + 0x06, 0x12, 0x04, 0xa0, 0x0d, 0x06, 0x14, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, + 0x38, 0x01, 0x12, 0x04, 0xa0, 0x0d, 0x15, 0x24, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, + 0x02, 0x38, 0x03, 0x12, 0x04, 0xa0, 0x0d, 0x27, 0x29, 0x0a, 0x0e, 0x0a, 0x06, 0x04, 0x00, 0x03, + 0x42, 0x02, 0x39, 0x12, 0x04, 0xa1, 0x0d, 0x06, 0x28, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, + 0x42, 0x02, 0x39, 0x06, 0x12, 0x04, 0xa1, 0x0d, 0x06, 0x13, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, + 0x03, 0x42, 0x02, 0x39, 0x01, 0x12, 0x04, 0xa1, 0x0d, 0x14, 0x22, 0x0a, 0x0f, 0x0a, 0x07, 0x04, + 0x00, 0x03, 0x42, 0x02, 0x39, 0x03, 0x12, 0x04, 0xa1, 0x0d, 0x25, 0x27, 0x0a, 0x0e, 0x0a, 0x06, + 0x04, 0x00, 0x03, 0x42, 0x02, 0x3a, 0x12, 0x04, 0xa2, 0x0d, 0x06, 0x28, 0x0a, 0x0f, 0x0a, 0x07, + 0x04, 0x00, 0x03, 0x42, 0x02, 0x3a, 0x06, 0x12, 0x04, 0xa2, 0x0d, 0x06, 0x13, 0x0a, 0x0f, 0x0a, + 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, 0x3a, 0x01, 0x12, 0x04, 0xa2, 0x0d, 0x14, 0x22, 0x0a, 0x0f, + 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, 0x3a, 0x03, 0x12, 0x04, 0xa2, 0x0d, 0x25, 0x27, 0x0a, + 0x0e, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x42, 0x02, 0x3b, 0x12, 0x04, 0xa3, 0x0d, 0x06, 0x3c, 0x0a, + 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, 0x3b, 0x06, 0x12, 0x04, 0xa3, 0x0d, 0x06, 0x1c, + 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, 0x3b, 0x01, 0x12, 0x04, 0xa3, 0x0d, 0x1d, + 0x36, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, 0x3b, 0x03, 0x12, 0x04, 0xa3, 0x0d, + 0x39, 0x3b, 0x0a, 0x0e, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x42, 0x02, 0x3c, 0x12, 0x04, 0xa4, 0x0d, + 0x06, 0x25, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, 0x3c, 0x06, 0x12, 0x04, 0xa4, + 0x0d, 0x06, 0x11, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, 0x3c, 0x01, 0x12, 0x04, + 0xa4, 0x0d, 0x12, 0x1f, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, 0x3c, 0x03, 0x12, + 0x04, 0xa4, 0x0d, 0x22, 0x24, 0x0a, 0x0e, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x42, 0x02, 0x3d, 0x12, + 0x04, 0xa5, 0x0d, 0x06, 0x40, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, 0x3d, 0x06, + 0x12, 0x04, 0xa5, 0x0d, 0x06, 0x1d, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, 0x3d, + 0x01, 0x12, 0x04, 0xa5, 0x0d, 0x1e, 0x3a, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, + 0x3d, 0x03, 0x12, 0x04, 0xa5, 0x0d, 0x3d, 0x3f, 0x0a, 0x0e, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x42, + 0x02, 0x3e, 0x12, 0x04, 0xa6, 0x0d, 0x06, 0x26, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, + 0x02, 0x3e, 0x06, 0x12, 0x04, 0xa6, 0x0d, 0x06, 0x12, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, + 0x42, 0x02, 0x3e, 0x01, 0x12, 0x04, 0xa6, 0x0d, 0x13, 0x20, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, + 0x03, 0x42, 0x02, 0x3e, 0x03, 0x12, 0x04, 0xa6, 0x0d, 0x23, 0x25, 0x0a, 0x0e, 0x0a, 0x06, 0x04, + 0x00, 0x03, 0x42, 0x02, 0x3f, 0x12, 0x04, 0xa7, 0x0d, 0x06, 0x47, 0x0a, 0x0f, 0x0a, 0x07, 0x04, + 0x00, 0x03, 0x42, 0x02, 0x3f, 0x06, 0x12, 0x04, 0xa7, 0x0d, 0x06, 0x21, 0x0a, 0x0f, 0x0a, 0x07, + 0x04, 0x00, 0x03, 0x42, 0x02, 0x3f, 0x01, 0x12, 0x04, 0xa7, 0x0d, 0x22, 0x41, 0x0a, 0x0f, 0x0a, + 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, 0x3f, 0x03, 0x12, 0x04, 0xa7, 0x0d, 0x44, 0x46, 0x0a, 0x0e, + 0x0a, 0x06, 0x04, 0x00, 0x03, 0x42, 0x02, 0x40, 0x12, 0x04, 0xa8, 0x0d, 0x06, 0x49, 0x0a, 0x0f, + 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, 0x40, 0x06, 0x12, 0x04, 0xa8, 0x0d, 0x06, 0x22, 0x0a, + 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, 0x40, 0x01, 0x12, 0x04, 0xa8, 0x0d, 0x23, 0x43, + 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, 0x40, 0x03, 0x12, 0x04, 0xa8, 0x0d, 0x46, + 0x48, 0x0a, 0x0e, 0x0a, 0x06, 0x04, 0x00, 0x03, 0x42, 0x02, 0x41, 0x12, 0x04, 0xa9, 0x0d, 0x06, + 0x37, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, 0x41, 0x06, 0x12, 0x04, 0xa9, 0x0d, + 0x06, 0x1a, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, 0x41, 0x01, 0x12, 0x04, 0xa9, + 0x0d, 0x1b, 0x31, 0x0a, 0x0f, 0x0a, 0x07, 0x04, 0x00, 0x03, 0x42, 0x02, 0x41, 0x03, 0x12, 0x04, + 0xa9, 0x0d, 0x34, 0x36, 0x0a, 0x42, 0x0a, 0x04, 0x04, 0x00, 0x02, 0x00, 0x12, 0x04, 0xad, 0x0d, + 0x02, 0x1a, 0x1a, 0x34, 0x2f, 0x20, 0x54, 0x68, 0x65, 0x20, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x20, + 0x6f, 0x66, 0x20, 0x74, 0x61, 0x73, 0x6b, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x70, 0x65, 0x72, 0x66, + 0x6f, 0x72, 0x6d, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x4f, 0x72, 0x61, + 0x63, 0x6c, 0x65, 0x4a, 0x6f, 0x62, 0x2e, 0x0a, 0x0a, 0x0d, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x00, + 0x04, 0x12, 0x04, 0xad, 0x0d, 0x02, 0x0a, 0x0a, 0x0d, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x00, 0x06, + 0x12, 0x04, 0xad, 0x0d, 0x0b, 0x0f, 0x0a, 0x0d, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x00, 0x01, 0x12, + 0x04, 0xad, 0x0d, 0x10, 0x15, 0x0a, 0x0d, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x00, 0x03, 0x12, 0x04, + 0xad, 0x0d, 0x18, 0x19, 0x0a, 0xf5, 0x01, 0x0a, 0x04, 0x04, 0x00, 0x02, 0x01, 0x12, 0x04, 0xb2, + 0x0d, 0x02, 0x2b, 0x1a, 0xe6, 0x01, 0x2f, 0x20, 0x54, 0x68, 0x65, 0x20, 0x77, 0x65, 0x69, 0x67, + 0x68, 0x74, 0x20, 0x74, 0x6f, 0x20, 0x61, 0x73, 0x73, 0x69, 0x67, 0x6e, 0x20, 0x74, 0x6f, 0x20, + 0x74, 0x68, 0x69, 0x73, 0x20, 0x6a, 0x6f, 0x62, 0x27, 0x73, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, + 0x74, 0x20, 0x77, 0x68, 0x65, 0x6e, 0x20, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x69, + 0x6e, 0x67, 0x20, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x20, 0x6a, 0x6f, 0x62, 0x20, + 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x2e, 0x20, 0x41, 0x20, 0x68, 0x69, 0x67, 0x68, 0x65, + 0x72, 0x0a, 0x2f, 0x20, 0x77, 0x65, 0x69, 0x67, 0x68, 0x74, 0x20, 0x6d, 0x65, 0x61, 0x6e, 0x73, + 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x6a, 0x6f, 0x62, 0x27, 0x73, 0x20, 0x72, 0x65, 0x73, 0x75, + 0x6c, 0x74, 0x20, 0x77, 0x69, 0x6c, 0x6c, 0x20, 0x68, 0x61, 0x76, 0x65, 0x20, 0x6d, 0x6f, 0x72, + 0x65, 0x20, 0x69, 0x6e, 0x66, 0x6c, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x20, 0x6f, 0x6e, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x66, 0x69, 0x6e, 0x61, 0x6c, 0x20, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, + 0x74, 0x65, 0x64, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x2e, 0x20, 0x54, 0x68, 0x69, 0x73, 0x0a, + 0x2f, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x20, 0x6d, 0x75, 0x73, 0x74, 0x20, 0x62, 0x65, 0x20, + 0x67, 0x72, 0x65, 0x61, 0x74, 0x65, 0x72, 0x20, 0x74, 0x68, 0x61, 0x6e, 0x20, 0x6f, 0x72, 0x20, + 0x65, 0x71, 0x75, 0x61, 0x6c, 0x20, 0x74, 0x6f, 0x20, 0x30, 0x2e, 0x0a, 0x0a, 0x0d, 0x0a, 0x05, + 0x04, 0x00, 0x02, 0x01, 0x04, 0x12, 0x04, 0xb2, 0x0d, 0x02, 0x0a, 0x0a, 0x0d, 0x0a, 0x05, 0x04, + 0x00, 0x02, 0x01, 0x05, 0x12, 0x04, 0xb2, 0x0d, 0x0b, 0x11, 0x0a, 0x0d, 0x0a, 0x05, 0x04, 0x00, + 0x02, 0x01, 0x01, 0x12, 0x04, 0xb2, 0x0d, 0x12, 0x18, 0x0a, 0x0d, 0x0a, 0x05, 0x04, 0x00, 0x02, + 0x01, 0x03, 0x12, 0x04, 0xb2, 0x0d, 0x1b, 0x1c, 0x0a, 0x0d, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x01, + 0x08, 0x12, 0x04, 0xb2, 0x0d, 0x1d, 0x2a, 0x0a, 0x0d, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x01, 0x07, + 0x12, 0x04, 0xb2, 0x0d, 0x1e, 0x29, 0x0a, 0x0c, 0x0a, 0x04, 0x04, 0x00, 0x02, 0x02, 0x12, 0x04, + 0xb3, 0x0d, 0x02, 0x24, 0x0a, 0x0d, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x02, 0x04, 0x12, 0x04, 0xb3, + 0x0d, 0x02, 0x0a, 0x0a, 0x0d, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x02, 0x05, 0x12, 0x04, 0xb3, 0x0d, + 0x0b, 0x11, 0x0a, 0x0d, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x02, 0x01, 0x12, 0x04, 0xb3, 0x0d, 0x12, + 0x1f, 0x0a, 0x0d, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x02, 0x03, 0x12, 0x04, 0xb3, 0x0d, 0x22, 0x23, + 0x0a, 0x0c, 0x0a, 0x04, 0x04, 0x00, 0x02, 0x03, 0x12, 0x04, 0xb4, 0x0d, 0x02, 0x22, 0x0a, 0x0d, + 0x0a, 0x05, 0x04, 0x00, 0x02, 0x03, 0x04, 0x12, 0x04, 0xb4, 0x0d, 0x02, 0x0a, 0x0a, 0x0d, 0x0a, + 0x05, 0x04, 0x00, 0x02, 0x03, 0x05, 0x12, 0x04, 0xb4, 0x0d, 0x0b, 0x11, 0x0a, 0x0d, 0x0a, 0x05, + 0x04, 0x00, 0x02, 0x03, 0x01, 0x12, 0x04, 0xb4, 0x0d, 0x12, 0x1d, 0x0a, 0x0d, 0x0a, 0x05, 0x04, + 0x00, 0x02, 0x03, 0x03, 0x12, 0x04, 0xb4, 0x0d, 0x20, 0x21, 0x0a, 0x0c, 0x0a, 0x04, 0x04, 0x00, + 0x02, 0x04, 0x12, 0x04, 0xb5, 0x0d, 0x02, 0x23, 0x0a, 0x0d, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x04, + 0x04, 0x12, 0x04, 0xb5, 0x0d, 0x02, 0x0a, 0x0a, 0x0d, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x04, 0x05, + 0x12, 0x04, 0xb5, 0x0d, 0x0b, 0x11, 0x0a, 0x0d, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x04, 0x01, 0x12, + 0x04, 0xb5, 0x0d, 0x12, 0x1e, 0x0a, 0x0d, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x04, 0x03, 0x12, 0x04, + 0xb5, 0x0d, 0x21, 0x22, 0x0a, 0x0c, 0x0a, 0x04, 0x04, 0x00, 0x02, 0x05, 0x12, 0x04, 0xb6, 0x0d, + 0x02, 0x1b, 0x0a, 0x0d, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x05, 0x04, 0x12, 0x04, 0xb6, 0x0d, 0x02, + 0x0a, 0x0a, 0x0d, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x05, 0x05, 0x12, 0x04, 0xb6, 0x0d, 0x0b, 0x11, + 0x0a, 0x0d, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x05, 0x01, 0x12, 0x04, 0xb6, 0x0d, 0x12, 0x16, 0x0a, + 0x0d, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x05, 0x03, 0x12, 0x04, 0xb6, 0x0d, 0x19, 0x1a, 0x0a, 0x0c, + 0x0a, 0x04, 0x04, 0x00, 0x02, 0x06, 0x12, 0x04, 0xb7, 0x0d, 0x02, 0x1c, 0x0a, 0x0d, 0x0a, 0x05, + 0x04, 0x00, 0x02, 0x06, 0x04, 0x12, 0x04, 0xb7, 0x0d, 0x02, 0x0a, 0x0a, 0x0d, 0x0a, 0x05, 0x04, + 0x00, 0x02, 0x06, 0x05, 0x12, 0x04, 0xb7, 0x0d, 0x0b, 0x11, 0x0a, 0x0d, 0x0a, 0x05, 0x04, 0x00, + 0x02, 0x06, 0x01, 0x12, 0x04, 0xb7, 0x0d, 0x12, 0x17, 0x0a, 0x0d, 0x0a, 0x05, 0x04, 0x00, 0x02, + 0x06, 0x03, 0x12, 0x04, 0xb7, 0x0d, 0x1a, 0x1b, +]; +include!("oracle_job.serde.rs"); +// @@protoc_insertion_point(module) diff --git a/programs/switchboard-on-demand/src/client/oracle_job.serde.rs b/programs/switchboard-on-demand/src/client/oracle_job.serde.rs new file mode 100644 index 0000000000..d16628e918 --- /dev/null +++ b/programs/switchboard-on-demand/src/client/oracle_job.serde.rs @@ -0,0 +1,12677 @@ +// @generated +impl serde::Serialize for OracleJob { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + use serde::ser::SerializeStruct; + let mut len = 0; + if !self.tasks.is_empty() { + len += 1; + } + if self.weight.is_some() { + len += 1; + } + if self.min_responses.is_some() { + len += 1; + } + if self.min_samples.is_some() { + len += 1; + } + if self.max_variance.is_some() { + len += 1; + } + if self.name.is_some() { + len += 1; + } + if self.queue.is_some() { + len += 1; + } + let mut struct_ser = serializer.serialize_struct("oracle_job.OracleJob", len)?; + if !self.tasks.is_empty() { + struct_ser.serialize_field("tasks", &self.tasks)?; + } + if let Some(v) = self.weight.as_ref() { + struct_ser.serialize_field("weight", v)?; + } + if let Some(v) = self.min_responses.as_ref() { + struct_ser.serialize_field("minResponses", v)?; + } + if let Some(v) = self.min_samples.as_ref() { + struct_ser.serialize_field("minSamples", v)?; + } + if let Some(v) = self.max_variance.as_ref() { + #[allow(clippy::needless_borrow)] + struct_ser.serialize_field("maxVariance", ToString::to_string(&v).as_str())?; + } + if let Some(v) = self.name.as_ref() { + struct_ser.serialize_field("name", v)?; + } + if let Some(v) = self.queue.as_ref() { + struct_ser.serialize_field("queue", v)?; + } + struct_ser.end() + } +} +impl<'de> serde::Deserialize<'de> for OracleJob { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &[ + "tasks", + "weight", + "min_responses", + "minResponses", + "min_samples", + "minSamples", + "max_variance", + "maxVariance", + "name", + "queue", + ]; + + #[allow(clippy::enum_variant_names)] + enum GeneratedField { + Tasks, + Weight, + MinResponses, + MinSamples, + MaxVariance, + Name, + Queue, + } + 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 { + "tasks" => Ok(GeneratedField::Tasks), + "weight" => Ok(GeneratedField::Weight), + "minResponses" | "min_responses" => Ok(GeneratedField::MinResponses), + "minSamples" | "min_samples" => Ok(GeneratedField::MinSamples), + "maxVariance" | "max_variance" => Ok(GeneratedField::MaxVariance), + "name" => Ok(GeneratedField::Name), + "queue" => Ok(GeneratedField::Queue), + _ => Err(serde::de::Error::unknown_field(value, FIELDS)), + } + } + } + deserializer.deserialize_identifier(GeneratedVisitor) + } + } + struct GeneratedVisitor; + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = OracleJob; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("struct oracle_job.OracleJob") + } + + fn visit_map(self, mut map_: V) -> std::result::Result + where + V: serde::de::MapAccess<'de>, + { + let mut tasks__ = None; + let mut weight__ = None; + let mut min_responses__ = None; + let mut min_samples__ = None; + let mut max_variance__ = None; + let mut name__ = None; + let mut queue__ = None; + while let Some(k) = map_.next_key()? { + match k { + GeneratedField::Tasks => { + if tasks__.is_some() { + return Err(serde::de::Error::duplicate_field("tasks")); + } + tasks__ = Some(map_.next_value()?); + } + GeneratedField::Weight => { + if weight__.is_some() { + return Err(serde::de::Error::duplicate_field("weight")); + } + weight__ = + map_.next_value::<::std::option::Option<::pbjson::private::NumberDeserialize<_>>>()?.map(|x| x.0) + ; + } + GeneratedField::MinResponses => { + if min_responses__.is_some() { + return Err(serde::de::Error::duplicate_field("minResponses")); + } + min_responses__ = + map_.next_value::<::std::option::Option<::pbjson::private::NumberDeserialize<_>>>()?.map(|x| x.0) + ; + } + GeneratedField::MinSamples => { + if min_samples__.is_some() { + return Err(serde::de::Error::duplicate_field("minSamples")); + } + min_samples__ = + map_.next_value::<::std::option::Option<::pbjson::private::NumberDeserialize<_>>>()?.map(|x| x.0) + ; + } + GeneratedField::MaxVariance => { + if max_variance__.is_some() { + return Err(serde::de::Error::duplicate_field("maxVariance")); + } + max_variance__ = + map_.next_value::<::std::option::Option<::pbjson::private::NumberDeserialize<_>>>()?.map(|x| x.0) + ; + } + GeneratedField::Name => { + if name__.is_some() { + return Err(serde::de::Error::duplicate_field("name")); + } + name__ = map_.next_value()?; + } + GeneratedField::Queue => { + if queue__.is_some() { + return Err(serde::de::Error::duplicate_field("queue")); + } + queue__ = map_.next_value()?; + } + } + } + Ok(OracleJob { + tasks: tasks__.unwrap_or_default(), + weight: weight__, + min_responses: min_responses__, + min_samples: min_samples__, + max_variance: max_variance__, + name: name__, + queue: queue__, + }) + } + } + deserializer.deserialize_struct("oracle_job.OracleJob", FIELDS, GeneratedVisitor) + } +} +impl serde::Serialize for oracle_job::AddTask { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + use serde::ser::SerializeStruct; + let mut len = 0; + if self.addition.is_some() { + len += 1; + } + let mut struct_ser = serializer.serialize_struct("oracle_job.OracleJob.AddTask", len)?; + if let Some(v) = self.addition.as_ref() { + match v { + oracle_job::add_task::Addition::Scalar(v) => { + struct_ser.serialize_field("scalar", v)?; + } + oracle_job::add_task::Addition::AggregatorPubkey(v) => { + struct_ser.serialize_field("aggregatorPubkey", v)?; + } + oracle_job::add_task::Addition::Job(v) => { + struct_ser.serialize_field("job", v)?; + } + oracle_job::add_task::Addition::Big(v) => { + struct_ser.serialize_field("big", v)?; + } + } + } + struct_ser.end() + } +} +impl<'de> serde::Deserialize<'de> for oracle_job::AddTask { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &[ + "scalar", + "aggregator_pubkey", + "aggregatorPubkey", + "job", + "big", + ]; + + #[allow(clippy::enum_variant_names)] + enum GeneratedField { + Scalar, + AggregatorPubkey, + Job, + Big, + } + 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 { + "scalar" => Ok(GeneratedField::Scalar), + "aggregatorPubkey" | "aggregator_pubkey" => Ok(GeneratedField::AggregatorPubkey), + "job" => Ok(GeneratedField::Job), + "big" => Ok(GeneratedField::Big), + _ => Err(serde::de::Error::unknown_field(value, FIELDS)), + } + } + } + deserializer.deserialize_identifier(GeneratedVisitor) + } + } + struct GeneratedVisitor; + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = oracle_job::AddTask; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("struct oracle_job.OracleJob.AddTask") + } + + fn visit_map(self, mut map_: V) -> std::result::Result + where + V: serde::de::MapAccess<'de>, + { + let mut addition__ = None; + while let Some(k) = map_.next_key()? { + match k { + GeneratedField::Scalar => { + if addition__.is_some() { + return Err(serde::de::Error::duplicate_field("scalar")); + } + addition__ = map_.next_value::<::std::option::Option<::pbjson::private::NumberDeserialize<_>>>()?.map(|x| oracle_job::add_task::Addition::Scalar(x.0)); + } + GeneratedField::AggregatorPubkey => { + if addition__.is_some() { + return Err(serde::de::Error::duplicate_field("aggregatorPubkey")); + } + addition__ = map_.next_value::<::std::option::Option<_>>()?.map(oracle_job::add_task::Addition::AggregatorPubkey); + } + GeneratedField::Job => { + if addition__.is_some() { + return Err(serde::de::Error::duplicate_field("job")); + } + addition__ = map_.next_value::<::std::option::Option<_>>()?.map(oracle_job::add_task::Addition::Job) +; + } + GeneratedField::Big => { + if addition__.is_some() { + return Err(serde::de::Error::duplicate_field("big")); + } + addition__ = map_.next_value::<::std::option::Option<_>>()?.map(oracle_job::add_task::Addition::Big); + } + } + } + Ok(oracle_job::AddTask { + addition: addition__, + }) + } + } + deserializer.deserialize_struct("oracle_job.OracleJob.AddTask", FIELDS, GeneratedVisitor) + } +} +impl serde::Serialize for oracle_job::AftermathTask { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + use serde::ser::SerializeStruct; + let mut len = 0; + if self.pool_address.is_some() { + len += 1; + } + if self.in_amount.is_some() { + len += 1; + } + if self.in_coin_type.is_some() { + len += 1; + } + if self.out_coin_type.is_some() { + len += 1; + } + let mut struct_ser = serializer.serialize_struct("oracle_job.OracleJob.AftermathTask", len)?; + if let Some(v) = self.pool_address.as_ref() { + struct_ser.serialize_field("poolAddress", v)?; + } + if let Some(v) = self.in_amount.as_ref() { + struct_ser.serialize_field("inAmount", v)?; + } + if let Some(v) = self.in_coin_type.as_ref() { + struct_ser.serialize_field("inCoinType", v)?; + } + if let Some(v) = self.out_coin_type.as_ref() { + struct_ser.serialize_field("outCoinType", v)?; + } + struct_ser.end() + } +} +impl<'de> serde::Deserialize<'de> for oracle_job::AftermathTask { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &[ + "pool_address", + "poolAddress", + "in_amount", + "inAmount", + "in_coin_type", + "inCoinType", + "out_coin_type", + "outCoinType", + ]; + + #[allow(clippy::enum_variant_names)] + enum GeneratedField { + PoolAddress, + InAmount, + InCoinType, + OutCoinType, + } + 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 { + "poolAddress" | "pool_address" => Ok(GeneratedField::PoolAddress), + "inAmount" | "in_amount" => Ok(GeneratedField::InAmount), + "inCoinType" | "in_coin_type" => Ok(GeneratedField::InCoinType), + "outCoinType" | "out_coin_type" => Ok(GeneratedField::OutCoinType), + _ => Err(serde::de::Error::unknown_field(value, FIELDS)), + } + } + } + deserializer.deserialize_identifier(GeneratedVisitor) + } + } + struct GeneratedVisitor; + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = oracle_job::AftermathTask; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("struct oracle_job.OracleJob.AftermathTask") + } + + fn visit_map(self, mut map_: V) -> std::result::Result + where + V: serde::de::MapAccess<'de>, + { + let mut pool_address__ = None; + let mut in_amount__ = None; + let mut in_coin_type__ = None; + let mut out_coin_type__ = None; + while let Some(k) = map_.next_key()? { + match k { + GeneratedField::PoolAddress => { + if pool_address__.is_some() { + return Err(serde::de::Error::duplicate_field("poolAddress")); + } + pool_address__ = map_.next_value()?; + } + GeneratedField::InAmount => { + if in_amount__.is_some() { + return Err(serde::de::Error::duplicate_field("inAmount")); + } + in_amount__ = + map_.next_value::<::std::option::Option<::pbjson::private::NumberDeserialize<_>>>()?.map(|x| x.0) + ; + } + GeneratedField::InCoinType => { + if in_coin_type__.is_some() { + return Err(serde::de::Error::duplicate_field("inCoinType")); + } + in_coin_type__ = map_.next_value()?; + } + GeneratedField::OutCoinType => { + if out_coin_type__.is_some() { + return Err(serde::de::Error::duplicate_field("outCoinType")); + } + out_coin_type__ = map_.next_value()?; + } + } + } + Ok(oracle_job::AftermathTask { + pool_address: pool_address__, + in_amount: in_amount__, + in_coin_type: in_coin_type__, + out_coin_type: out_coin_type__, + }) + } + } + deserializer.deserialize_struct("oracle_job.OracleJob.AftermathTask", FIELDS, GeneratedVisitor) + } +} +impl serde::Serialize for oracle_job::AnchorFetchTask { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + use serde::ser::SerializeStruct; + let mut len = 0; + if self.program_id.is_some() { + len += 1; + } + if self.account_address.is_some() { + len += 1; + } + let mut struct_ser = serializer.serialize_struct("oracle_job.OracleJob.AnchorFetchTask", len)?; + if let Some(v) = self.program_id.as_ref() { + struct_ser.serialize_field("programId", v)?; + } + if let Some(v) = self.account_address.as_ref() { + struct_ser.serialize_field("accountAddress", v)?; + } + struct_ser.end() + } +} +impl<'de> serde::Deserialize<'de> for oracle_job::AnchorFetchTask { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &[ + "program_id", + "programId", + "account_address", + "accountAddress", + ]; + + #[allow(clippy::enum_variant_names)] + enum GeneratedField { + ProgramId, + AccountAddress, + } + 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 { + "programId" | "program_id" => Ok(GeneratedField::ProgramId), + "accountAddress" | "account_address" => Ok(GeneratedField::AccountAddress), + _ => Err(serde::de::Error::unknown_field(value, FIELDS)), + } + } + } + deserializer.deserialize_identifier(GeneratedVisitor) + } + } + struct GeneratedVisitor; + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = oracle_job::AnchorFetchTask; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("struct oracle_job.OracleJob.AnchorFetchTask") + } + + fn visit_map(self, mut map_: V) -> std::result::Result + where + V: serde::de::MapAccess<'de>, + { + let mut program_id__ = None; + let mut account_address__ = None; + while let Some(k) = map_.next_key()? { + match k { + GeneratedField::ProgramId => { + if program_id__.is_some() { + return Err(serde::de::Error::duplicate_field("programId")); + } + program_id__ = map_.next_value()?; + } + GeneratedField::AccountAddress => { + if account_address__.is_some() { + return Err(serde::de::Error::duplicate_field("accountAddress")); + } + account_address__ = map_.next_value()?; + } + } + } + Ok(oracle_job::AnchorFetchTask { + program_id: program_id__, + account_address: account_address__, + }) + } + } + deserializer.deserialize_struct("oracle_job.OracleJob.AnchorFetchTask", FIELDS, GeneratedVisitor) + } +} +impl serde::Serialize for oracle_job::BitFluxTask { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + use serde::ser::SerializeStruct; + let mut len = 0; + if self.provider.is_some() { + len += 1; + } + if self.pool_address.is_some() { + len += 1; + } + if self.in_token.is_some() { + len += 1; + } + if self.out_token.is_some() { + len += 1; + } + let mut struct_ser = serializer.serialize_struct("oracle_job.OracleJob.BitFluxTask", len)?; + if let Some(v) = self.provider.as_ref() { + struct_ser.serialize_field("provider", v)?; + } + if let Some(v) = self.pool_address.as_ref() { + struct_ser.serialize_field("poolAddress", v)?; + } + if let Some(v) = self.in_token.as_ref() { + struct_ser.serialize_field("inToken", v)?; + } + if let Some(v) = self.out_token.as_ref() { + struct_ser.serialize_field("outToken", v)?; + } + struct_ser.end() + } +} +impl<'de> serde::Deserialize<'de> for oracle_job::BitFluxTask { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &[ + "provider", + "pool_address", + "poolAddress", + "in_token", + "inToken", + "out_token", + "outToken", + ]; + + #[allow(clippy::enum_variant_names)] + enum GeneratedField { + Provider, + PoolAddress, + InToken, + OutToken, + } + 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 { + "provider" => Ok(GeneratedField::Provider), + "poolAddress" | "pool_address" => Ok(GeneratedField::PoolAddress), + "inToken" | "in_token" => Ok(GeneratedField::InToken), + "outToken" | "out_token" => Ok(GeneratedField::OutToken), + _ => Err(serde::de::Error::unknown_field(value, FIELDS)), + } + } + } + deserializer.deserialize_identifier(GeneratedVisitor) + } + } + struct GeneratedVisitor; + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = oracle_job::BitFluxTask; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("struct oracle_job.OracleJob.BitFluxTask") + } + + fn visit_map(self, mut map_: V) -> std::result::Result + where + V: serde::de::MapAccess<'de>, + { + let mut provider__ = None; + let mut pool_address__ = None; + let mut in_token__ = None; + let mut out_token__ = None; + while let Some(k) = map_.next_key()? { + match k { + GeneratedField::Provider => { + if provider__.is_some() { + return Err(serde::de::Error::duplicate_field("provider")); + } + provider__ = map_.next_value()?; + } + GeneratedField::PoolAddress => { + if pool_address__.is_some() { + return Err(serde::de::Error::duplicate_field("poolAddress")); + } + pool_address__ = map_.next_value()?; + } + GeneratedField::InToken => { + if in_token__.is_some() { + return Err(serde::de::Error::duplicate_field("inToken")); + } + in_token__ = map_.next_value()?; + } + GeneratedField::OutToken => { + if out_token__.is_some() { + return Err(serde::de::Error::duplicate_field("outToken")); + } + out_token__ = map_.next_value()?; + } + } + } + Ok(oracle_job::BitFluxTask { + provider: provider__, + pool_address: pool_address__, + in_token: in_token__, + out_token: out_token__, + }) + } + } + deserializer.deserialize_struct("oracle_job.OracleJob.BitFluxTask", FIELDS, GeneratedVisitor) + } +} +impl serde::Serialize for oracle_job::BoundTask { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + use serde::ser::SerializeStruct; + let mut len = 0; + if self.lower_bound.is_some() { + len += 1; + } + if self.lower_bound_value.is_some() { + len += 1; + } + if self.upper_bound.is_some() { + len += 1; + } + if self.upper_bound_value.is_some() { + len += 1; + } + if self.on_exceeds_upper_bound.is_some() { + len += 1; + } + if self.on_exceeds_upper_bound_value.is_some() { + len += 1; + } + if self.on_exceeds_lower_bound.is_some() { + len += 1; + } + if self.on_exceeds_lower_bound_value.is_some() { + len += 1; + } + let mut struct_ser = serializer.serialize_struct("oracle_job.OracleJob.BoundTask", len)?; + if let Some(v) = self.lower_bound.as_ref() { + struct_ser.serialize_field("lowerBound", v)?; + } + if let Some(v) = self.lower_bound_value.as_ref() { + struct_ser.serialize_field("lowerBoundValue", v)?; + } + if let Some(v) = self.upper_bound.as_ref() { + struct_ser.serialize_field("upperBound", v)?; + } + if let Some(v) = self.upper_bound_value.as_ref() { + struct_ser.serialize_field("upperBoundValue", v)?; + } + if let Some(v) = self.on_exceeds_upper_bound.as_ref() { + struct_ser.serialize_field("onExceedsUpperBound", v)?; + } + if let Some(v) = self.on_exceeds_upper_bound_value.as_ref() { + struct_ser.serialize_field("onExceedsUpperBoundValue", v)?; + } + if let Some(v) = self.on_exceeds_lower_bound.as_ref() { + struct_ser.serialize_field("onExceedsLowerBound", v)?; + } + if let Some(v) = self.on_exceeds_lower_bound_value.as_ref() { + struct_ser.serialize_field("onExceedsLowerBoundValue", v)?; + } + struct_ser.end() + } +} +impl<'de> serde::Deserialize<'de> for oracle_job::BoundTask { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &[ + "lower_bound", + "lowerBound", + "lower_bound_value", + "lowerBoundValue", + "upper_bound", + "upperBound", + "upper_bound_value", + "upperBoundValue", + "on_exceeds_upper_bound", + "onExceedsUpperBound", + "on_exceeds_upper_bound_value", + "onExceedsUpperBoundValue", + "on_exceeds_lower_bound", + "onExceedsLowerBound", + "on_exceeds_lower_bound_value", + "onExceedsLowerBoundValue", + ]; + + #[allow(clippy::enum_variant_names)] + enum GeneratedField { + LowerBound, + LowerBoundValue, + UpperBound, + UpperBoundValue, + OnExceedsUpperBound, + OnExceedsUpperBoundValue, + OnExceedsLowerBound, + OnExceedsLowerBoundValue, + } + 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 { + "lowerBound" | "lower_bound" => Ok(GeneratedField::LowerBound), + "lowerBoundValue" | "lower_bound_value" => Ok(GeneratedField::LowerBoundValue), + "upperBound" | "upper_bound" => Ok(GeneratedField::UpperBound), + "upperBoundValue" | "upper_bound_value" => Ok(GeneratedField::UpperBoundValue), + "onExceedsUpperBound" | "on_exceeds_upper_bound" => Ok(GeneratedField::OnExceedsUpperBound), + "onExceedsUpperBoundValue" | "on_exceeds_upper_bound_value" => Ok(GeneratedField::OnExceedsUpperBoundValue), + "onExceedsLowerBound" | "on_exceeds_lower_bound" => Ok(GeneratedField::OnExceedsLowerBound), + "onExceedsLowerBoundValue" | "on_exceeds_lower_bound_value" => Ok(GeneratedField::OnExceedsLowerBoundValue), + _ => Err(serde::de::Error::unknown_field(value, FIELDS)), + } + } + } + deserializer.deserialize_identifier(GeneratedVisitor) + } + } + struct GeneratedVisitor; + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = oracle_job::BoundTask; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("struct oracle_job.OracleJob.BoundTask") + } + + fn visit_map(self, mut map_: V) -> std::result::Result + where + V: serde::de::MapAccess<'de>, + { + let mut lower_bound__ = None; + let mut lower_bound_value__ = None; + let mut upper_bound__ = None; + let mut upper_bound_value__ = None; + let mut on_exceeds_upper_bound__ = None; + let mut on_exceeds_upper_bound_value__ = None; + let mut on_exceeds_lower_bound__ = None; + let mut on_exceeds_lower_bound_value__ = None; + while let Some(k) = map_.next_key()? { + match k { + GeneratedField::LowerBound => { + if lower_bound__.is_some() { + return Err(serde::de::Error::duplicate_field("lowerBound")); + } + lower_bound__ = map_.next_value()?; + } + GeneratedField::LowerBoundValue => { + if lower_bound_value__.is_some() { + return Err(serde::de::Error::duplicate_field("lowerBoundValue")); + } + lower_bound_value__ = map_.next_value()?; + } + GeneratedField::UpperBound => { + if upper_bound__.is_some() { + return Err(serde::de::Error::duplicate_field("upperBound")); + } + upper_bound__ = map_.next_value()?; + } + GeneratedField::UpperBoundValue => { + if upper_bound_value__.is_some() { + return Err(serde::de::Error::duplicate_field("upperBoundValue")); + } + upper_bound_value__ = map_.next_value()?; + } + GeneratedField::OnExceedsUpperBound => { + if on_exceeds_upper_bound__.is_some() { + return Err(serde::de::Error::duplicate_field("onExceedsUpperBound")); + } + on_exceeds_upper_bound__ = map_.next_value()?; + } + GeneratedField::OnExceedsUpperBoundValue => { + if on_exceeds_upper_bound_value__.is_some() { + return Err(serde::de::Error::duplicate_field("onExceedsUpperBoundValue")); + } + on_exceeds_upper_bound_value__ = map_.next_value()?; + } + GeneratedField::OnExceedsLowerBound => { + if on_exceeds_lower_bound__.is_some() { + return Err(serde::de::Error::duplicate_field("onExceedsLowerBound")); + } + on_exceeds_lower_bound__ = map_.next_value()?; + } + GeneratedField::OnExceedsLowerBoundValue => { + if on_exceeds_lower_bound_value__.is_some() { + return Err(serde::de::Error::duplicate_field("onExceedsLowerBoundValue")); + } + on_exceeds_lower_bound_value__ = map_.next_value()?; + } + } + } + Ok(oracle_job::BoundTask { + lower_bound: lower_bound__, + lower_bound_value: lower_bound_value__, + upper_bound: upper_bound__, + upper_bound_value: upper_bound_value__, + on_exceeds_upper_bound: on_exceeds_upper_bound__, + on_exceeds_upper_bound_value: on_exceeds_upper_bound_value__, + on_exceeds_lower_bound: on_exceeds_lower_bound__, + on_exceeds_lower_bound_value: on_exceeds_lower_bound_value__, + }) + } + } + deserializer.deserialize_struct("oracle_job.OracleJob.BoundTask", FIELDS, GeneratedVisitor) + } +} +impl serde::Serialize for oracle_job::BufferLayoutParseTask { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + use serde::ser::SerializeStruct; + let mut len = 0; + if self.offset.is_some() { + len += 1; + } + if self.endian.is_some() { + len += 1; + } + if self.r#type.is_some() { + len += 1; + } + let mut struct_ser = serializer.serialize_struct("oracle_job.OracleJob.BufferLayoutParseTask", len)?; + if let Some(v) = self.offset.as_ref() { + struct_ser.serialize_field("offset", v)?; + } + if let Some(v) = self.endian.as_ref() { + let v = oracle_job::buffer_layout_parse_task::Endian::try_from(*v) + .map_err(|_| serde::ser::Error::custom(format!("Invalid variant {}", *v)))?; + struct_ser.serialize_field("endian", &v)?; + } + if let Some(v) = self.r#type.as_ref() { + let v = oracle_job::buffer_layout_parse_task::BufferParseType::try_from(*v) + .map_err(|_| serde::ser::Error::custom(format!("Invalid variant {}", *v)))?; + struct_ser.serialize_field("type", &v)?; + } + struct_ser.end() + } +} +impl<'de> serde::Deserialize<'de> for oracle_job::BufferLayoutParseTask { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &[ + "offset", + "endian", + "type", + ]; + + #[allow(clippy::enum_variant_names)] + enum GeneratedField { + Offset, + Endian, + Type, + } + 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 { + "offset" => Ok(GeneratedField::Offset), + "endian" => Ok(GeneratedField::Endian), + "type" => Ok(GeneratedField::Type), + _ => Err(serde::de::Error::unknown_field(value, FIELDS)), + } + } + } + deserializer.deserialize_identifier(GeneratedVisitor) + } + } + struct GeneratedVisitor; + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = oracle_job::BufferLayoutParseTask; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("struct oracle_job.OracleJob.BufferLayoutParseTask") + } + + fn visit_map(self, mut map_: V) -> std::result::Result + where + V: serde::de::MapAccess<'de>, + { + let mut offset__ = None; + let mut endian__ = None; + let mut r#type__ = None; + while let Some(k) = map_.next_key()? { + match k { + GeneratedField::Offset => { + if offset__.is_some() { + return Err(serde::de::Error::duplicate_field("offset")); + } + offset__ = + map_.next_value::<::std::option::Option<::pbjson::private::NumberDeserialize<_>>>()?.map(|x| x.0) + ; + } + GeneratedField::Endian => { + if endian__.is_some() { + return Err(serde::de::Error::duplicate_field("endian")); + } + endian__ = map_.next_value::<::std::option::Option>()?.map(|x| x as i32); + } + GeneratedField::Type => { + if r#type__.is_some() { + return Err(serde::de::Error::duplicate_field("type")); + } + r#type__ = map_.next_value::<::std::option::Option>()?.map(|x| x as i32); + } + } + } + Ok(oracle_job::BufferLayoutParseTask { + offset: offset__, + endian: endian__, + r#type: r#type__, + }) + } + } + deserializer.deserialize_struct("oracle_job.OracleJob.BufferLayoutParseTask", FIELDS, GeneratedVisitor) + } +} +impl serde::Serialize for oracle_job::buffer_layout_parse_task::BufferParseType { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + let variant = match self { + Self::Pubkey => "pubkey", + Self::Bool => "bool", + Self::U8 => "u8", + Self::I8 => "i8", + Self::U16 => "u16", + Self::I16 => "i16", + Self::U32 => "u32", + Self::I32 => "i32", + Self::F32 => "f32", + Self::U64 => "u64", + Self::I64 => "i64", + Self::F64 => "f64", + Self::U128 => "u128", + Self::I128 => "i128", + }; + serializer.serialize_str(variant) + } +} +impl<'de> serde::Deserialize<'de> for oracle_job::buffer_layout_parse_task::BufferParseType { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &[ + "pubkey", + "bool", + "u8", + "i8", + "u16", + "i16", + "u32", + "i32", + "f32", + "u64", + "i64", + "f64", + "u128", + "i128", + ]; + + struct GeneratedVisitor; + + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = oracle_job::buffer_layout_parse_task::BufferParseType; + + 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 { + "pubkey" => Ok(oracle_job::buffer_layout_parse_task::BufferParseType::Pubkey), + "bool" => Ok(oracle_job::buffer_layout_parse_task::BufferParseType::Bool), + "u8" => Ok(oracle_job::buffer_layout_parse_task::BufferParseType::U8), + "i8" => Ok(oracle_job::buffer_layout_parse_task::BufferParseType::I8), + "u16" => Ok(oracle_job::buffer_layout_parse_task::BufferParseType::U16), + "i16" => Ok(oracle_job::buffer_layout_parse_task::BufferParseType::I16), + "u32" => Ok(oracle_job::buffer_layout_parse_task::BufferParseType::U32), + "i32" => Ok(oracle_job::buffer_layout_parse_task::BufferParseType::I32), + "f32" => Ok(oracle_job::buffer_layout_parse_task::BufferParseType::F32), + "u64" => Ok(oracle_job::buffer_layout_parse_task::BufferParseType::U64), + "i64" => Ok(oracle_job::buffer_layout_parse_task::BufferParseType::I64), + "f64" => Ok(oracle_job::buffer_layout_parse_task::BufferParseType::F64), + "u128" => Ok(oracle_job::buffer_layout_parse_task::BufferParseType::U128), + "i128" => Ok(oracle_job::buffer_layout_parse_task::BufferParseType::I128), + _ => Err(serde::de::Error::unknown_variant(value, FIELDS)), + } + } + } + deserializer.deserialize_any(GeneratedVisitor) + } +} +impl serde::Serialize for oracle_job::buffer_layout_parse_task::Endian { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + let variant = match self { + Self::LittleEndian => "LITTLE_ENDIAN", + Self::BigEndian => "BIG_ENDIAN", + }; + serializer.serialize_str(variant) + } +} +impl<'de> serde::Deserialize<'de> for oracle_job::buffer_layout_parse_task::Endian { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &[ + "LITTLE_ENDIAN", + "BIG_ENDIAN", + ]; + + struct GeneratedVisitor; + + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = oracle_job::buffer_layout_parse_task::Endian; + + 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 { + "LITTLE_ENDIAN" => Ok(oracle_job::buffer_layout_parse_task::Endian::LittleEndian), + "BIG_ENDIAN" => Ok(oracle_job::buffer_layout_parse_task::Endian::BigEndian), + _ => Err(serde::de::Error::unknown_variant(value, FIELDS)), + } + } + } + deserializer.deserialize_any(GeneratedVisitor) + } +} +impl serde::Serialize for oracle_job::CacheTask { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + use serde::ser::SerializeStruct; + let mut len = 0; + if !self.cache_items.is_empty() { + len += 1; + } + let mut struct_ser = serializer.serialize_struct("oracle_job.OracleJob.CacheTask", len)?; + if !self.cache_items.is_empty() { + struct_ser.serialize_field("cacheItems", &self.cache_items)?; + } + struct_ser.end() + } +} +impl<'de> serde::Deserialize<'de> for oracle_job::CacheTask { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &[ + "cache_items", + "cacheItems", + ]; + + #[allow(clippy::enum_variant_names)] + enum GeneratedField { + CacheItems, + } + 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 { + "cacheItems" | "cache_items" => Ok(GeneratedField::CacheItems), + _ => Err(serde::de::Error::unknown_field(value, FIELDS)), + } + } + } + deserializer.deserialize_identifier(GeneratedVisitor) + } + } + struct GeneratedVisitor; + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = oracle_job::CacheTask; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("struct oracle_job.OracleJob.CacheTask") + } + + fn visit_map(self, mut map_: V) -> std::result::Result + where + V: serde::de::MapAccess<'de>, + { + let mut cache_items__ = None; + while let Some(k) = map_.next_key()? { + match k { + GeneratedField::CacheItems => { + if cache_items__.is_some() { + return Err(serde::de::Error::duplicate_field("cacheItems")); + } + cache_items__ = Some(map_.next_value()?); + } + } + } + Ok(oracle_job::CacheTask { + cache_items: cache_items__.unwrap_or_default(), + }) + } + } + deserializer.deserialize_struct("oracle_job.OracleJob.CacheTask", FIELDS, GeneratedVisitor) + } +} +impl serde::Serialize for oracle_job::cache_task::CacheItem { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + use serde::ser::SerializeStruct; + let mut len = 0; + if self.variable_name.is_some() { + len += 1; + } + if self.job.is_some() { + len += 1; + } + let mut struct_ser = serializer.serialize_struct("oracle_job.OracleJob.CacheTask.CacheItem", len)?; + if let Some(v) = self.variable_name.as_ref() { + struct_ser.serialize_field("variableName", v)?; + } + if let Some(v) = self.job.as_ref() { + struct_ser.serialize_field("job", v)?; + } + struct_ser.end() + } +} +impl<'de> serde::Deserialize<'de> for oracle_job::cache_task::CacheItem { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &[ + "variable_name", + "variableName", + "job", + ]; + + #[allow(clippy::enum_variant_names)] + enum GeneratedField { + VariableName, + Job, + } + 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 { + "variableName" | "variable_name" => Ok(GeneratedField::VariableName), + "job" => Ok(GeneratedField::Job), + _ => Err(serde::de::Error::unknown_field(value, FIELDS)), + } + } + } + deserializer.deserialize_identifier(GeneratedVisitor) + } + } + struct GeneratedVisitor; + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = oracle_job::cache_task::CacheItem; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("struct oracle_job.OracleJob.CacheTask.CacheItem") + } + + fn visit_map(self, mut map_: V) -> std::result::Result + where + V: serde::de::MapAccess<'de>, + { + let mut variable_name__ = None; + let mut job__ = None; + while let Some(k) = map_.next_key()? { + match k { + GeneratedField::VariableName => { + if variable_name__.is_some() { + return Err(serde::de::Error::duplicate_field("variableName")); + } + variable_name__ = map_.next_value()?; + } + GeneratedField::Job => { + if job__.is_some() { + return Err(serde::de::Error::duplicate_field("job")); + } + job__ = map_.next_value()?; + } + } + } + Ok(oracle_job::cache_task::CacheItem { + variable_name: variable_name__, + job: job__, + }) + } + } + deserializer.deserialize_struct("oracle_job.OracleJob.CacheTask.CacheItem", FIELDS, GeneratedVisitor) + } +} +impl serde::Serialize for oracle_job::ComparisonTask { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + use serde::ser::SerializeStruct; + let mut len = 0; + if self.op.is_some() { + len += 1; + } + if self.on_true.is_some() { + len += 1; + } + if self.on_true_value.is_some() { + len += 1; + } + if self.on_false.is_some() { + len += 1; + } + if self.on_false_value.is_some() { + len += 1; + } + if self.on_failure.is_some() { + len += 1; + } + if self.on_failure_value.is_some() { + len += 1; + } + if self.lhs.is_some() { + len += 1; + } + if self.rhs.is_some() { + len += 1; + } + let mut struct_ser = serializer.serialize_struct("oracle_job.OracleJob.ComparisonTask", len)?; + if let Some(v) = self.op.as_ref() { + let v = oracle_job::comparison_task::Operation::try_from(*v) + .map_err(|_| serde::ser::Error::custom(format!("Invalid variant {}", *v)))?; + struct_ser.serialize_field("op", &v)?; + } + if let Some(v) = self.on_true.as_ref() { + struct_ser.serialize_field("onTrue", v)?; + } + if let Some(v) = self.on_true_value.as_ref() { + struct_ser.serialize_field("onTrueValue", v)?; + } + if let Some(v) = self.on_false.as_ref() { + struct_ser.serialize_field("onFalse", v)?; + } + if let Some(v) = self.on_false_value.as_ref() { + struct_ser.serialize_field("onFalseValue", v)?; + } + if let Some(v) = self.on_failure.as_ref() { + struct_ser.serialize_field("onFailure", v)?; + } + if let Some(v) = self.on_failure_value.as_ref() { + struct_ser.serialize_field("onFailureValue", v)?; + } + if let Some(v) = self.lhs.as_ref() { + match v { + oracle_job::comparison_task::Lhs::Lhs(v) => { + struct_ser.serialize_field("lhs", v)?; + } + oracle_job::comparison_task::Lhs::LhsValue(v) => { + struct_ser.serialize_field("lhsValue", v)?; + } + } + } + if let Some(v) = self.rhs.as_ref() { + match v { + oracle_job::comparison_task::Rhs::Rhs(v) => { + struct_ser.serialize_field("rhs", v)?; + } + oracle_job::comparison_task::Rhs::RhsValue(v) => { + struct_ser.serialize_field("rhsValue", v)?; + } + } + } + struct_ser.end() + } +} +impl<'de> serde::Deserialize<'de> for oracle_job::ComparisonTask { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &[ + "op", + "on_true", + "onTrue", + "on_true_value", + "onTrueValue", + "on_false", + "onFalse", + "on_false_value", + "onFalseValue", + "on_failure", + "onFailure", + "on_failure_value", + "onFailureValue", + "lhs", + "lhs_value", + "lhsValue", + "rhs", + "rhs_value", + "rhsValue", + ]; + + #[allow(clippy::enum_variant_names)] + enum GeneratedField { + Op, + OnTrue, + OnTrueValue, + OnFalse, + OnFalseValue, + OnFailure, + OnFailureValue, + Lhs, + LhsValue, + Rhs, + RhsValue, + } + 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 { + "op" => Ok(GeneratedField::Op), + "onTrue" | "on_true" => Ok(GeneratedField::OnTrue), + "onTrueValue" | "on_true_value" => Ok(GeneratedField::OnTrueValue), + "onFalse" | "on_false" => Ok(GeneratedField::OnFalse), + "onFalseValue" | "on_false_value" => Ok(GeneratedField::OnFalseValue), + "onFailure" | "on_failure" => Ok(GeneratedField::OnFailure), + "onFailureValue" | "on_failure_value" => Ok(GeneratedField::OnFailureValue), + "lhs" => Ok(GeneratedField::Lhs), + "lhsValue" | "lhs_value" => Ok(GeneratedField::LhsValue), + "rhs" => Ok(GeneratedField::Rhs), + "rhsValue" | "rhs_value" => Ok(GeneratedField::RhsValue), + _ => Err(serde::de::Error::unknown_field(value, FIELDS)), + } + } + } + deserializer.deserialize_identifier(GeneratedVisitor) + } + } + struct GeneratedVisitor; + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = oracle_job::ComparisonTask; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("struct oracle_job.OracleJob.ComparisonTask") + } + + fn visit_map(self, mut map_: V) -> std::result::Result + where + V: serde::de::MapAccess<'de>, + { + let mut op__ = None; + let mut on_true__ = None; + let mut on_true_value__ = None; + let mut on_false__ = None; + let mut on_false_value__ = None; + let mut on_failure__ = None; + let mut on_failure_value__ = None; + let mut lhs__ = None; + let mut rhs__ = None; + while let Some(k) = map_.next_key()? { + match k { + GeneratedField::Op => { + if op__.is_some() { + return Err(serde::de::Error::duplicate_field("op")); + } + op__ = map_.next_value::<::std::option::Option>()?.map(|x| x as i32); + } + GeneratedField::OnTrue => { + if on_true__.is_some() { + return Err(serde::de::Error::duplicate_field("onTrue")); + } + on_true__ = map_.next_value()?; + } + GeneratedField::OnTrueValue => { + if on_true_value__.is_some() { + return Err(serde::de::Error::duplicate_field("onTrueValue")); + } + on_true_value__ = map_.next_value()?; + } + GeneratedField::OnFalse => { + if on_false__.is_some() { + return Err(serde::de::Error::duplicate_field("onFalse")); + } + on_false__ = map_.next_value()?; + } + GeneratedField::OnFalseValue => { + if on_false_value__.is_some() { + return Err(serde::de::Error::duplicate_field("onFalseValue")); + } + on_false_value__ = map_.next_value()?; + } + GeneratedField::OnFailure => { + if on_failure__.is_some() { + return Err(serde::de::Error::duplicate_field("onFailure")); + } + on_failure__ = map_.next_value()?; + } + GeneratedField::OnFailureValue => { + if on_failure_value__.is_some() { + return Err(serde::de::Error::duplicate_field("onFailureValue")); + } + on_failure_value__ = map_.next_value()?; + } + GeneratedField::Lhs => { + if lhs__.is_some() { + return Err(serde::de::Error::duplicate_field("lhs")); + } + lhs__ = map_.next_value::<::std::option::Option<_>>()?.map(oracle_job::comparison_task::Lhs::Lhs) +; + } + GeneratedField::LhsValue => { + if lhs__.is_some() { + return Err(serde::de::Error::duplicate_field("lhsValue")); + } + lhs__ = map_.next_value::<::std::option::Option<_>>()?.map(oracle_job::comparison_task::Lhs::LhsValue); + } + GeneratedField::Rhs => { + if rhs__.is_some() { + return Err(serde::de::Error::duplicate_field("rhs")); + } + rhs__ = map_.next_value::<::std::option::Option<_>>()?.map(oracle_job::comparison_task::Rhs::Rhs) +; + } + GeneratedField::RhsValue => { + if rhs__.is_some() { + return Err(serde::de::Error::duplicate_field("rhsValue")); + } + rhs__ = map_.next_value::<::std::option::Option<_>>()?.map(oracle_job::comparison_task::Rhs::RhsValue); + } + } + } + Ok(oracle_job::ComparisonTask { + op: op__, + on_true: on_true__, + on_true_value: on_true_value__, + on_false: on_false__, + on_false_value: on_false_value__, + on_failure: on_failure__, + on_failure_value: on_failure_value__, + lhs: lhs__, + rhs: rhs__, + }) + } + } + deserializer.deserialize_struct("oracle_job.OracleJob.ComparisonTask", FIELDS, GeneratedVisitor) + } +} +impl serde::Serialize for oracle_job::comparison_task::Operation { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + let variant = match self { + Self::Eq => "OPERATION_EQ", + Self::Gt => "OPERATION_GT", + Self::Lt => "OPERATION_LT", + }; + serializer.serialize_str(variant) + } +} +impl<'de> serde::Deserialize<'de> for oracle_job::comparison_task::Operation { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &[ + "OPERATION_EQ", + "OPERATION_GT", + "OPERATION_LT", + ]; + + struct GeneratedVisitor; + + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = oracle_job::comparison_task::Operation; + + 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 { + "OPERATION_EQ" => Ok(oracle_job::comparison_task::Operation::Eq), + "OPERATION_GT" => Ok(oracle_job::comparison_task::Operation::Gt), + "OPERATION_LT" => Ok(oracle_job::comparison_task::Operation::Lt), + _ => Err(serde::de::Error::unknown_variant(value, FIELDS)), + } + } + } + deserializer.deserialize_any(GeneratedVisitor) + } +} +impl serde::Serialize for oracle_job::ConditionalTask { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + use serde::ser::SerializeStruct; + let mut len = 0; + if !self.attempt.is_empty() { + len += 1; + } + if !self.on_failure.is_empty() { + len += 1; + } + let mut struct_ser = serializer.serialize_struct("oracle_job.OracleJob.ConditionalTask", len)?; + if !self.attempt.is_empty() { + struct_ser.serialize_field("attempt", &self.attempt)?; + } + if !self.on_failure.is_empty() { + struct_ser.serialize_field("onFailure", &self.on_failure)?; + } + struct_ser.end() + } +} +impl<'de> serde::Deserialize<'de> for oracle_job::ConditionalTask { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &[ + "attempt", + "on_failure", + "onFailure", + ]; + + #[allow(clippy::enum_variant_names)] + enum GeneratedField { + Attempt, + OnFailure, + } + 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 { + "attempt" => Ok(GeneratedField::Attempt), + "onFailure" | "on_failure" => Ok(GeneratedField::OnFailure), + _ => Err(serde::de::Error::unknown_field(value, FIELDS)), + } + } + } + deserializer.deserialize_identifier(GeneratedVisitor) + } + } + struct GeneratedVisitor; + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = oracle_job::ConditionalTask; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("struct oracle_job.OracleJob.ConditionalTask") + } + + fn visit_map(self, mut map_: V) -> std::result::Result + where + V: serde::de::MapAccess<'de>, + { + let mut attempt__ = None; + let mut on_failure__ = None; + while let Some(k) = map_.next_key()? { + match k { + GeneratedField::Attempt => { + if attempt__.is_some() { + return Err(serde::de::Error::duplicate_field("attempt")); + } + attempt__ = Some(map_.next_value()?); + } + GeneratedField::OnFailure => { + if on_failure__.is_some() { + return Err(serde::de::Error::duplicate_field("onFailure")); + } + on_failure__ = Some(map_.next_value()?); + } + } + } + Ok(oracle_job::ConditionalTask { + attempt: attempt__.unwrap_or_default(), + on_failure: on_failure__.unwrap_or_default(), + }) + } + } + deserializer.deserialize_struct("oracle_job.OracleJob.ConditionalTask", FIELDS, GeneratedVisitor) + } +} +impl serde::Serialize for oracle_job::CorexTask { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + use serde::ser::SerializeStruct; + let mut len = 0; + if self.in_token.is_some() { + len += 1; + } + if self.out_token.is_some() { + len += 1; + } + if self.slippage.is_some() { + len += 1; + } + let mut struct_ser = serializer.serialize_struct("oracle_job.OracleJob.CorexTask", len)?; + if let Some(v) = self.in_token.as_ref() { + struct_ser.serialize_field("inToken", v)?; + } + if let Some(v) = self.out_token.as_ref() { + struct_ser.serialize_field("outToken", v)?; + } + if let Some(v) = self.slippage.as_ref() { + struct_ser.serialize_field("slippage", v)?; + } + struct_ser.end() + } +} +impl<'de> serde::Deserialize<'de> for oracle_job::CorexTask { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &[ + "in_token", + "inToken", + "out_token", + "outToken", + "slippage", + ]; + + #[allow(clippy::enum_variant_names)] + enum GeneratedField { + InToken, + OutToken, + Slippage, + } + 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 { + "inToken" | "in_token" => Ok(GeneratedField::InToken), + "outToken" | "out_token" => Ok(GeneratedField::OutToken), + "slippage" => Ok(GeneratedField::Slippage), + _ => Err(serde::de::Error::unknown_field(value, FIELDS)), + } + } + } + deserializer.deserialize_identifier(GeneratedVisitor) + } + } + struct GeneratedVisitor; + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = oracle_job::CorexTask; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("struct oracle_job.OracleJob.CorexTask") + } + + fn visit_map(self, mut map_: V) -> std::result::Result + where + V: serde::de::MapAccess<'de>, + { + let mut in_token__ = None; + let mut out_token__ = None; + let mut slippage__ = None; + while let Some(k) = map_.next_key()? { + match k { + GeneratedField::InToken => { + if in_token__.is_some() { + return Err(serde::de::Error::duplicate_field("inToken")); + } + in_token__ = map_.next_value()?; + } + GeneratedField::OutToken => { + if out_token__.is_some() { + return Err(serde::de::Error::duplicate_field("outToken")); + } + out_token__ = map_.next_value()?; + } + GeneratedField::Slippage => { + if slippage__.is_some() { + return Err(serde::de::Error::duplicate_field("slippage")); + } + slippage__ = + map_.next_value::<::std::option::Option<::pbjson::private::NumberDeserialize<_>>>()?.map(|x| x.0) + ; + } + } + } + Ok(oracle_job::CorexTask { + in_token: in_token__, + out_token: out_token__, + slippage: slippage__, + }) + } + } + deserializer.deserialize_struct("oracle_job.OracleJob.CorexTask", FIELDS, GeneratedVisitor) + } +} +impl serde::Serialize for oracle_job::CronParseTask { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + use serde::ser::SerializeStruct; + let mut len = 0; + if self.cron_pattern.is_some() { + len += 1; + } + if self.clock_offset.is_some() { + len += 1; + } + if self.clock.is_some() { + len += 1; + } + let mut struct_ser = serializer.serialize_struct("oracle_job.OracleJob.CronParseTask", len)?; + if let Some(v) = self.cron_pattern.as_ref() { + struct_ser.serialize_field("cronPattern", v)?; + } + if let Some(v) = self.clock_offset.as_ref() { + struct_ser.serialize_field("clockOffset", v)?; + } + if let Some(v) = self.clock.as_ref() { + let v = oracle_job::cron_parse_task::ClockType::try_from(*v) + .map_err(|_| serde::ser::Error::custom(format!("Invalid variant {}", *v)))?; + struct_ser.serialize_field("clock", &v)?; + } + struct_ser.end() + } +} +impl<'de> serde::Deserialize<'de> for oracle_job::CronParseTask { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &[ + "cron_pattern", + "cronPattern", + "clock_offset", + "clockOffset", + "clock", + ]; + + #[allow(clippy::enum_variant_names)] + enum GeneratedField { + CronPattern, + ClockOffset, + Clock, + } + 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 { + "cronPattern" | "cron_pattern" => Ok(GeneratedField::CronPattern), + "clockOffset" | "clock_offset" => Ok(GeneratedField::ClockOffset), + "clock" => Ok(GeneratedField::Clock), + _ => Err(serde::de::Error::unknown_field(value, FIELDS)), + } + } + } + deserializer.deserialize_identifier(GeneratedVisitor) + } + } + struct GeneratedVisitor; + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = oracle_job::CronParseTask; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("struct oracle_job.OracleJob.CronParseTask") + } + + fn visit_map(self, mut map_: V) -> std::result::Result + where + V: serde::de::MapAccess<'de>, + { + let mut cron_pattern__ = None; + let mut clock_offset__ = None; + let mut clock__ = None; + while let Some(k) = map_.next_key()? { + match k { + GeneratedField::CronPattern => { + if cron_pattern__.is_some() { + return Err(serde::de::Error::duplicate_field("cronPattern")); + } + cron_pattern__ = map_.next_value()?; + } + GeneratedField::ClockOffset => { + if clock_offset__.is_some() { + return Err(serde::de::Error::duplicate_field("clockOffset")); + } + clock_offset__ = + map_.next_value::<::std::option::Option<::pbjson::private::NumberDeserialize<_>>>()?.map(|x| x.0) + ; + } + GeneratedField::Clock => { + if clock__.is_some() { + return Err(serde::de::Error::duplicate_field("clock")); + } + clock__ = map_.next_value::<::std::option::Option>()?.map(|x| x as i32); + } + } + } + Ok(oracle_job::CronParseTask { + cron_pattern: cron_pattern__, + clock_offset: clock_offset__, + clock: clock__, + }) + } + } + deserializer.deserialize_struct("oracle_job.OracleJob.CronParseTask", FIELDS, GeneratedVisitor) + } +} +impl serde::Serialize for oracle_job::cron_parse_task::ClockType { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + let variant = match self { + Self::Oracle => "ORACLE", + Self::Sysclock => "SYSCLOCK", + }; + serializer.serialize_str(variant) + } +} +impl<'de> serde::Deserialize<'de> for oracle_job::cron_parse_task::ClockType { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &[ + "ORACLE", + "SYSCLOCK", + ]; + + struct GeneratedVisitor; + + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = oracle_job::cron_parse_task::ClockType; + + 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 { + "ORACLE" => Ok(oracle_job::cron_parse_task::ClockType::Oracle), + "SYSCLOCK" => Ok(oracle_job::cron_parse_task::ClockType::Sysclock), + _ => Err(serde::de::Error::unknown_variant(value, FIELDS)), + } + } + } + deserializer.deserialize_any(GeneratedVisitor) + } +} +impl serde::Serialize for oracle_job::CurveFinanceTask { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + use serde::ser::SerializeStruct; + let mut len = 0; + if self.chain.is_some() { + len += 1; + } + if self.provider.is_some() { + len += 1; + } + if self.pool_address.is_some() { + len += 1; + } + if self.out_decimals.is_some() { + len += 1; + } + let mut struct_ser = serializer.serialize_struct("oracle_job.OracleJob.CurveFinanceTask", len)?; + if let Some(v) = self.chain.as_ref() { + let v = oracle_job::curve_finance_task::Chain::try_from(*v) + .map_err(|_| serde::ser::Error::custom(format!("Invalid variant {}", *v)))?; + struct_ser.serialize_field("chain", &v)?; + } + if let Some(v) = self.provider.as_ref() { + struct_ser.serialize_field("provider", v)?; + } + if let Some(v) = self.pool_address.as_ref() { + struct_ser.serialize_field("poolAddress", v)?; + } + if let Some(v) = self.out_decimals.as_ref() { + struct_ser.serialize_field("outDecimals", v)?; + } + struct_ser.end() + } +} +impl<'de> serde::Deserialize<'de> for oracle_job::CurveFinanceTask { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &[ + "chain", + "provider", + "pool_address", + "poolAddress", + "out_decimals", + "outDecimals", + ]; + + #[allow(clippy::enum_variant_names)] + enum GeneratedField { + Chain, + Provider, + PoolAddress, + OutDecimals, + } + 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 { + "chain" => Ok(GeneratedField::Chain), + "provider" => Ok(GeneratedField::Provider), + "poolAddress" | "pool_address" => Ok(GeneratedField::PoolAddress), + "outDecimals" | "out_decimals" => Ok(GeneratedField::OutDecimals), + _ => Err(serde::de::Error::unknown_field(value, FIELDS)), + } + } + } + deserializer.deserialize_identifier(GeneratedVisitor) + } + } + struct GeneratedVisitor; + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = oracle_job::CurveFinanceTask; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("struct oracle_job.OracleJob.CurveFinanceTask") + } + + fn visit_map(self, mut map_: V) -> std::result::Result + where + V: serde::de::MapAccess<'de>, + { + let mut chain__ = None; + let mut provider__ = None; + let mut pool_address__ = None; + let mut out_decimals__ = None; + while let Some(k) = map_.next_key()? { + match k { + GeneratedField::Chain => { + if chain__.is_some() { + return Err(serde::de::Error::duplicate_field("chain")); + } + chain__ = map_.next_value::<::std::option::Option>()?.map(|x| x as i32); + } + GeneratedField::Provider => { + if provider__.is_some() { + return Err(serde::de::Error::duplicate_field("provider")); + } + provider__ = map_.next_value()?; + } + GeneratedField::PoolAddress => { + if pool_address__.is_some() { + return Err(serde::de::Error::duplicate_field("poolAddress")); + } + pool_address__ = map_.next_value()?; + } + GeneratedField::OutDecimals => { + if out_decimals__.is_some() { + return Err(serde::de::Error::duplicate_field("outDecimals")); + } + out_decimals__ = + map_.next_value::<::std::option::Option<::pbjson::private::NumberDeserialize<_>>>()?.map(|x| x.0) + ; + } + } + } + Ok(oracle_job::CurveFinanceTask { + chain: chain__, + provider: provider__, + pool_address: pool_address__, + out_decimals: out_decimals__, + }) + } + } + deserializer.deserialize_struct("oracle_job.OracleJob.CurveFinanceTask", FIELDS, GeneratedVisitor) + } +} +impl serde::Serialize for oracle_job::curve_finance_task::Chain { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + let variant = match self { + Self::Ethereum => "CHAIN_ETHEREUM", + }; + serializer.serialize_str(variant) + } +} +impl<'de> serde::Deserialize<'de> for oracle_job::curve_finance_task::Chain { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &[ + "CHAIN_ETHEREUM", + ]; + + struct GeneratedVisitor; + + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = oracle_job::curve_finance_task::Chain; + + 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 { + "CHAIN_ETHEREUM" => Ok(oracle_job::curve_finance_task::Chain::Ethereum), + _ => Err(serde::de::Error::unknown_variant(value, FIELDS)), + } + } + } + deserializer.deserialize_any(GeneratedVisitor) + } +} +impl serde::Serialize for oracle_job::DivideTask { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + use serde::ser::SerializeStruct; + let mut len = 0; + if self.denominator.is_some() { + len += 1; + } + let mut struct_ser = serializer.serialize_struct("oracle_job.OracleJob.DivideTask", len)?; + if let Some(v) = self.denominator.as_ref() { + match v { + oracle_job::divide_task::Denominator::Scalar(v) => { + struct_ser.serialize_field("scalar", v)?; + } + oracle_job::divide_task::Denominator::AggregatorPubkey(v) => { + struct_ser.serialize_field("aggregatorPubkey", v)?; + } + oracle_job::divide_task::Denominator::Job(v) => { + struct_ser.serialize_field("job", v)?; + } + oracle_job::divide_task::Denominator::Big(v) => { + struct_ser.serialize_field("big", v)?; + } + } + } + struct_ser.end() + } +} +impl<'de> serde::Deserialize<'de> for oracle_job::DivideTask { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &[ + "scalar", + "aggregator_pubkey", + "aggregatorPubkey", + "job", + "big", + ]; + + #[allow(clippy::enum_variant_names)] + enum GeneratedField { + Scalar, + AggregatorPubkey, + Job, + Big, + } + 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 { + "scalar" => Ok(GeneratedField::Scalar), + "aggregatorPubkey" | "aggregator_pubkey" => Ok(GeneratedField::AggregatorPubkey), + "job" => Ok(GeneratedField::Job), + "big" => Ok(GeneratedField::Big), + _ => Err(serde::de::Error::unknown_field(value, FIELDS)), + } + } + } + deserializer.deserialize_identifier(GeneratedVisitor) + } + } + struct GeneratedVisitor; + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = oracle_job::DivideTask; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("struct oracle_job.OracleJob.DivideTask") + } + + fn visit_map(self, mut map_: V) -> std::result::Result + where + V: serde::de::MapAccess<'de>, + { + let mut denominator__ = None; + while let Some(k) = map_.next_key()? { + match k { + GeneratedField::Scalar => { + if denominator__.is_some() { + return Err(serde::de::Error::duplicate_field("scalar")); + } + denominator__ = map_.next_value::<::std::option::Option<::pbjson::private::NumberDeserialize<_>>>()?.map(|x| oracle_job::divide_task::Denominator::Scalar(x.0)); + } + GeneratedField::AggregatorPubkey => { + if denominator__.is_some() { + return Err(serde::de::Error::duplicate_field("aggregatorPubkey")); + } + denominator__ = map_.next_value::<::std::option::Option<_>>()?.map(oracle_job::divide_task::Denominator::AggregatorPubkey); + } + GeneratedField::Job => { + if denominator__.is_some() { + return Err(serde::de::Error::duplicate_field("job")); + } + denominator__ = map_.next_value::<::std::option::Option<_>>()?.map(oracle_job::divide_task::Denominator::Job) +; + } + GeneratedField::Big => { + if denominator__.is_some() { + return Err(serde::de::Error::duplicate_field("big")); + } + denominator__ = map_.next_value::<::std::option::Option<_>>()?.map(oracle_job::divide_task::Denominator::Big); + } + } + } + Ok(oracle_job::DivideTask { + denominator: denominator__, + }) + } + } + deserializer.deserialize_struct("oracle_job.OracleJob.DivideTask", FIELDS, GeneratedVisitor) + } +} +impl serde::Serialize for oracle_job::EtherfuseTask { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + use serde::ser::SerializeStruct; + let mut len = 0; + if self.token.is_some() { + len += 1; + } + let mut struct_ser = serializer.serialize_struct("oracle_job.OracleJob.EtherfuseTask", len)?; + if let Some(v) = self.token.as_ref() { + let v = oracle_job::etherfuse_task::Token::try_from(*v) + .map_err(|_| serde::ser::Error::custom(format!("Invalid variant {}", *v)))?; + struct_ser.serialize_field("token", &v)?; + } + struct_ser.end() + } +} +impl<'de> serde::Deserialize<'de> for oracle_job::EtherfuseTask { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &[ + "token", + ]; + + #[allow(clippy::enum_variant_names)] + enum GeneratedField { + Token, + } + 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 { + "token" => Ok(GeneratedField::Token), + _ => Err(serde::de::Error::unknown_field(value, FIELDS)), + } + } + } + deserializer.deserialize_identifier(GeneratedVisitor) + } + } + struct GeneratedVisitor; + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = oracle_job::EtherfuseTask; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("struct oracle_job.OracleJob.EtherfuseTask") + } + + fn visit_map(self, mut map_: V) -> std::result::Result + where + V: serde::de::MapAccess<'de>, + { + let mut token__ = None; + while let Some(k) = map_.next_key()? { + match k { + GeneratedField::Token => { + if token__.is_some() { + return Err(serde::de::Error::duplicate_field("token")); + } + token__ = map_.next_value::<::std::option::Option>()?.map(|x| x as i32); + } + } + } + Ok(oracle_job::EtherfuseTask { + token: token__, + }) + } + } + deserializer.deserialize_struct("oracle_job.OracleJob.EtherfuseTask", FIELDS, GeneratedVisitor) + } +} +impl serde::Serialize for oracle_job::etherfuse_task::Token { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + let variant = match self { + Self::Cetes => "TOKEN_CETES", + Self::Ustry => "TOKEN_USTRY", + Self::Eurob => "TOKEN_EUROB", + Self::Tesouro => "TOKEN_TESOURO", + Self::Gilts => "TOKEN_GILTS", + }; + serializer.serialize_str(variant) + } +} +impl<'de> serde::Deserialize<'de> for oracle_job::etherfuse_task::Token { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &[ + "TOKEN_CETES", + "TOKEN_USTRY", + "TOKEN_EUROB", + "TOKEN_TESOURO", + "TOKEN_GILTS", + ]; + + struct GeneratedVisitor; + + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = oracle_job::etherfuse_task::Token; + + 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 { + "TOKEN_CETES" => Ok(oracle_job::etherfuse_task::Token::Cetes), + "TOKEN_USTRY" => Ok(oracle_job::etherfuse_task::Token::Ustry), + "TOKEN_EUROB" => Ok(oracle_job::etherfuse_task::Token::Eurob), + "TOKEN_TESOURO" => Ok(oracle_job::etherfuse_task::Token::Tesouro), + "TOKEN_GILTS" => Ok(oracle_job::etherfuse_task::Token::Gilts), + _ => Err(serde::de::Error::unknown_variant(value, FIELDS)), + } + } + } + deserializer.deserialize_any(GeneratedVisitor) + } +} +impl serde::Serialize for oracle_job::EwmaTask { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + use serde::ser::SerializeStruct; + let mut len = 0; + if self.aggregator_address.is_some() { + len += 1; + } + if self.period.is_some() { + len += 1; + } + if self.lambda.is_some() { + len += 1; + } + let mut struct_ser = serializer.serialize_struct("oracle_job.OracleJob.EwmaTask", len)?; + if let Some(v) = self.aggregator_address.as_ref() { + struct_ser.serialize_field("aggregatorAddress", v)?; + } + if let Some(v) = self.period.as_ref() { + struct_ser.serialize_field("period", v)?; + } + if let Some(v) = self.lambda.as_ref() { + struct_ser.serialize_field("lambda", v)?; + } + struct_ser.end() + } +} +impl<'de> serde::Deserialize<'de> for oracle_job::EwmaTask { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &[ + "aggregator_address", + "aggregatorAddress", + "period", + "lambda", + ]; + + #[allow(clippy::enum_variant_names)] + enum GeneratedField { + AggregatorAddress, + Period, + Lambda, + } + 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 { + "aggregatorAddress" | "aggregator_address" => Ok(GeneratedField::AggregatorAddress), + "period" => Ok(GeneratedField::Period), + "lambda" => Ok(GeneratedField::Lambda), + _ => Err(serde::de::Error::unknown_field(value, FIELDS)), + } + } + } + deserializer.deserialize_identifier(GeneratedVisitor) + } + } + struct GeneratedVisitor; + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = oracle_job::EwmaTask; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("struct oracle_job.OracleJob.EwmaTask") + } + + fn visit_map(self, mut map_: V) -> std::result::Result + where + V: serde::de::MapAccess<'de>, + { + let mut aggregator_address__ = None; + let mut period__ = None; + let mut lambda__ = None; + while let Some(k) = map_.next_key()? { + match k { + GeneratedField::AggregatorAddress => { + if aggregator_address__.is_some() { + return Err(serde::de::Error::duplicate_field("aggregatorAddress")); + } + aggregator_address__ = map_.next_value()?; + } + GeneratedField::Period => { + if period__.is_some() { + return Err(serde::de::Error::duplicate_field("period")); + } + period__ = + map_.next_value::<::std::option::Option<::pbjson::private::NumberDeserialize<_>>>()?.map(|x| x.0) + ; + } + GeneratedField::Lambda => { + if lambda__.is_some() { + return Err(serde::de::Error::duplicate_field("lambda")); + } + lambda__ = + map_.next_value::<::std::option::Option<::pbjson::private::NumberDeserialize<_>>>()?.map(|x| x.0) + ; + } + } + } + Ok(oracle_job::EwmaTask { + aggregator_address: aggregator_address__, + period: period__, + lambda: lambda__, + }) + } + } + deserializer.deserialize_struct("oracle_job.OracleJob.EwmaTask", FIELDS, GeneratedVisitor) + } +} +impl serde::Serialize for oracle_job::ExponentPtLinearPricingTask { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + use serde::ser::SerializeStruct; + let mut len = 0; + if self.vault.is_some() { + len += 1; + } + if self.start_price.is_some() { + len += 1; + } + let mut struct_ser = serializer.serialize_struct("oracle_job.OracleJob.ExponentPTLinearPricingTask", len)?; + if let Some(v) = self.vault.as_ref() { + struct_ser.serialize_field("vault", v)?; + } + if let Some(v) = self.start_price.as_ref() { + struct_ser.serialize_field("startPrice", v)?; + } + struct_ser.end() + } +} +impl<'de> serde::Deserialize<'de> for oracle_job::ExponentPtLinearPricingTask { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &[ + "vault", + "start_price", + "startPrice", + ]; + + #[allow(clippy::enum_variant_names)] + enum GeneratedField { + Vault, + StartPrice, + } + 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 { + "vault" => Ok(GeneratedField::Vault), + "startPrice" | "start_price" => Ok(GeneratedField::StartPrice), + _ => Err(serde::de::Error::unknown_field(value, FIELDS)), + } + } + } + deserializer.deserialize_identifier(GeneratedVisitor) + } + } + struct GeneratedVisitor; + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = oracle_job::ExponentPtLinearPricingTask; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("struct oracle_job.OracleJob.ExponentPTLinearPricingTask") + } + + fn visit_map(self, mut map_: V) -> std::result::Result + where + V: serde::de::MapAccess<'de>, + { + let mut vault__ = None; + let mut start_price__ = None; + while let Some(k) = map_.next_key()? { + match k { + GeneratedField::Vault => { + if vault__.is_some() { + return Err(serde::de::Error::duplicate_field("vault")); + } + vault__ = map_.next_value()?; + } + GeneratedField::StartPrice => { + if start_price__.is_some() { + return Err(serde::de::Error::duplicate_field("startPrice")); + } + start_price__ = + map_.next_value::<::std::option::Option<::pbjson::private::NumberDeserialize<_>>>()?.map(|x| x.0) + ; + } + } + } + Ok(oracle_job::ExponentPtLinearPricingTask { + vault: vault__, + start_price: start_price__, + }) + } + } + deserializer.deserialize_struct("oracle_job.OracleJob.ExponentPTLinearPricingTask", FIELDS, GeneratedVisitor) + } +} +impl serde::Serialize for oracle_job::ExponentTask { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + use serde::ser::SerializeStruct; + let mut len = 0; + if self.vault.is_some() { + len += 1; + } + let mut struct_ser = serializer.serialize_struct("oracle_job.OracleJob.ExponentTask", len)?; + if let Some(v) = self.vault.as_ref() { + struct_ser.serialize_field("vault", v)?; + } + struct_ser.end() + } +} +impl<'de> serde::Deserialize<'de> for oracle_job::ExponentTask { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &[ + "vault", + ]; + + #[allow(clippy::enum_variant_names)] + enum GeneratedField { + Vault, + } + 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 { + "vault" => Ok(GeneratedField::Vault), + _ => Err(serde::de::Error::unknown_field(value, FIELDS)), + } + } + } + deserializer.deserialize_identifier(GeneratedVisitor) + } + } + struct GeneratedVisitor; + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = oracle_job::ExponentTask; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("struct oracle_job.OracleJob.ExponentTask") + } + + fn visit_map(self, mut map_: V) -> std::result::Result + where + V: serde::de::MapAccess<'de>, + { + let mut vault__ = None; + while let Some(k) = map_.next_key()? { + match k { + GeneratedField::Vault => { + if vault__.is_some() { + return Err(serde::de::Error::duplicate_field("vault")); + } + vault__ = map_.next_value()?; + } + } + } + Ok(oracle_job::ExponentTask { + vault: vault__, + }) + } + } + deserializer.deserialize_struct("oracle_job.OracleJob.ExponentTask", FIELDS, GeneratedVisitor) + } +} +impl serde::Serialize for oracle_job::FragmetricTask { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + use serde::ser::SerializeStruct; + let mut len = 0; + if self.token.is_some() { + len += 1; + } + let mut struct_ser = serializer.serialize_struct("oracle_job.OracleJob.FragmetricTask", len)?; + if let Some(v) = self.token.as_ref() { + let v = oracle_job::fragmetric_task::Token::try_from(*v) + .map_err(|_| serde::ser::Error::custom(format!("Invalid variant {}", *v)))?; + struct_ser.serialize_field("token", &v)?; + } + struct_ser.end() + } +} +impl<'de> serde::Deserialize<'de> for oracle_job::FragmetricTask { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &[ + "token", + ]; + + #[allow(clippy::enum_variant_names)] + enum GeneratedField { + Token, + } + 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 { + "token" => Ok(GeneratedField::Token), + _ => Err(serde::de::Error::unknown_field(value, FIELDS)), + } + } + } + deserializer.deserialize_identifier(GeneratedVisitor) + } + } + struct GeneratedVisitor; + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = oracle_job::FragmetricTask; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("struct oracle_job.OracleJob.FragmetricTask") + } + + fn visit_map(self, mut map_: V) -> std::result::Result + where + V: serde::de::MapAccess<'de>, + { + let mut token__ = None; + while let Some(k) = map_.next_key()? { + match k { + GeneratedField::Token => { + if token__.is_some() { + return Err(serde::de::Error::duplicate_field("token")); + } + token__ = map_.next_value::<::std::option::Option>()?.map(|x| x as i32); + } + } + } + Ok(oracle_job::FragmetricTask { + token: token__, + }) + } + } + deserializer.deserialize_struct("oracle_job.OracleJob.FragmetricTask", FIELDS, GeneratedVisitor) + } +} +impl serde::Serialize for oracle_job::fragmetric_task::Token { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + let variant = match self { + Self::FragSol => "TOKEN_FRAG_SOL", + Self::NSol => "TOKEN_N_SOL", + }; + serializer.serialize_str(variant) + } +} +impl<'de> serde::Deserialize<'de> for oracle_job::fragmetric_task::Token { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &[ + "TOKEN_FRAG_SOL", + "TOKEN_N_SOL", + ]; + + struct GeneratedVisitor; + + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = oracle_job::fragmetric_task::Token; + + 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 { + "TOKEN_FRAG_SOL" => Ok(oracle_job::fragmetric_task::Token::FragSol), + "TOKEN_N_SOL" => Ok(oracle_job::fragmetric_task::Token::NSol), + _ => Err(serde::de::Error::unknown_variant(value, FIELDS)), + } + } + } + deserializer.deserialize_any(GeneratedVisitor) + } +} +impl serde::Serialize for oracle_job::GlyphTask { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + use serde::ser::SerializeStruct; + let mut len = 0; + if self.pool_address.is_some() { + len += 1; + } + if self.zero_for_one.is_some() { + len += 1; + } + let mut struct_ser = serializer.serialize_struct("oracle_job.OracleJob.GlyphTask", len)?; + if let Some(v) = self.pool_address.as_ref() { + struct_ser.serialize_field("poolAddress", v)?; + } + if let Some(v) = self.zero_for_one.as_ref() { + struct_ser.serialize_field("zeroForOne", v)?; + } + struct_ser.end() + } +} +impl<'de> serde::Deserialize<'de> for oracle_job::GlyphTask { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &[ + "pool_address", + "poolAddress", + "zero_for_one", + "zeroForOne", + ]; + + #[allow(clippy::enum_variant_names)] + enum GeneratedField { + PoolAddress, + ZeroForOne, + } + 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 { + "poolAddress" | "pool_address" => Ok(GeneratedField::PoolAddress), + "zeroForOne" | "zero_for_one" => Ok(GeneratedField::ZeroForOne), + _ => Err(serde::de::Error::unknown_field(value, FIELDS)), + } + } + } + deserializer.deserialize_identifier(GeneratedVisitor) + } + } + struct GeneratedVisitor; + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = oracle_job::GlyphTask; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("struct oracle_job.OracleJob.GlyphTask") + } + + fn visit_map(self, mut map_: V) -> std::result::Result + where + V: serde::de::MapAccess<'de>, + { + let mut pool_address__ = None; + let mut zero_for_one__ = None; + while let Some(k) = map_.next_key()? { + match k { + GeneratedField::PoolAddress => { + if pool_address__.is_some() { + return Err(serde::de::Error::duplicate_field("poolAddress")); + } + pool_address__ = map_.next_value()?; + } + GeneratedField::ZeroForOne => { + if zero_for_one__.is_some() { + return Err(serde::de::Error::duplicate_field("zeroForOne")); + } + zero_for_one__ = map_.next_value()?; + } + } + } + Ok(oracle_job::GlyphTask { + pool_address: pool_address__, + zero_for_one: zero_for_one__, + }) + } + } + deserializer.deserialize_struct("oracle_job.OracleJob.GlyphTask", FIELDS, GeneratedVisitor) + } +} +impl serde::Serialize for oracle_job::HistoryFunctionTask { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + use serde::ser::SerializeStruct; + let mut len = 0; + if self.method.is_some() { + len += 1; + } + if self.aggregator_address.is_some() { + len += 1; + } + if self.period.is_some() { + len += 1; + } + let mut struct_ser = serializer.serialize_struct("oracle_job.OracleJob.HistoryFunctionTask", len)?; + if let Some(v) = self.method.as_ref() { + let v = oracle_job::history_function_task::Method::try_from(*v) + .map_err(|_| serde::ser::Error::custom(format!("Invalid variant {}", *v)))?; + struct_ser.serialize_field("method", &v)?; + } + if let Some(v) = self.aggregator_address.as_ref() { + struct_ser.serialize_field("aggregatorAddress", v)?; + } + if let Some(v) = self.period.as_ref() { + struct_ser.serialize_field("period", v)?; + } + struct_ser.end() + } +} +impl<'de> serde::Deserialize<'de> for oracle_job::HistoryFunctionTask { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &[ + "method", + "aggregator_address", + "aggregatorAddress", + "period", + ]; + + #[allow(clippy::enum_variant_names)] + enum GeneratedField { + Method, + AggregatorAddress, + Period, + } + 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 { + "method" => Ok(GeneratedField::Method), + "aggregatorAddress" | "aggregator_address" => Ok(GeneratedField::AggregatorAddress), + "period" => Ok(GeneratedField::Period), + _ => Err(serde::de::Error::unknown_field(value, FIELDS)), + } + } + } + deserializer.deserialize_identifier(GeneratedVisitor) + } + } + struct GeneratedVisitor; + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = oracle_job::HistoryFunctionTask; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("struct oracle_job.OracleJob.HistoryFunctionTask") + } + + fn visit_map(self, mut map_: V) -> std::result::Result + where + V: serde::de::MapAccess<'de>, + { + let mut method__ = None; + let mut aggregator_address__ = None; + let mut period__ = None; + while let Some(k) = map_.next_key()? { + match k { + GeneratedField::Method => { + if method__.is_some() { + return Err(serde::de::Error::duplicate_field("method")); + } + method__ = map_.next_value::<::std::option::Option>()?.map(|x| x as i32); + } + GeneratedField::AggregatorAddress => { + if aggregator_address__.is_some() { + return Err(serde::de::Error::duplicate_field("aggregatorAddress")); + } + aggregator_address__ = map_.next_value()?; + } + GeneratedField::Period => { + if period__.is_some() { + return Err(serde::de::Error::duplicate_field("period")); + } + period__ = + map_.next_value::<::std::option::Option<::pbjson::private::NumberDeserialize<_>>>()?.map(|x| x.0) + ; + } + } + } + Ok(oracle_job::HistoryFunctionTask { + method: method__, + aggregator_address: aggregator_address__, + period: period__, + }) + } + } + deserializer.deserialize_struct("oracle_job.OracleJob.HistoryFunctionTask", FIELDS, GeneratedVisitor) + } +} +impl serde::Serialize for oracle_job::history_function_task::Method { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + let variant = match self { + Self::Min => "METHOD_MIN", + Self::Max => "METHOD_MAX", + }; + serializer.serialize_str(variant) + } +} +impl<'de> serde::Deserialize<'de> for oracle_job::history_function_task::Method { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &[ + "METHOD_MIN", + "METHOD_MAX", + ]; + + struct GeneratedVisitor; + + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = oracle_job::history_function_task::Method; + + 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 { + "METHOD_MIN" => Ok(oracle_job::history_function_task::Method::Min), + "METHOD_MAX" => Ok(oracle_job::history_function_task::Method::Max), + _ => Err(serde::de::Error::unknown_variant(value, FIELDS)), + } + } + } + deserializer.deserialize_any(GeneratedVisitor) + } +} +impl serde::Serialize for oracle_job::HttpTask { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + use serde::ser::SerializeStruct; + let mut len = 0; + if self.url.is_some() { + len += 1; + } + if self.method.is_some() { + len += 1; + } + if !self.headers.is_empty() { + len += 1; + } + if self.body.is_some() { + len += 1; + } + let mut struct_ser = serializer.serialize_struct("oracle_job.OracleJob.HttpTask", len)?; + if let Some(v) = self.url.as_ref() { + struct_ser.serialize_field("url", v)?; + } + if let Some(v) = self.method.as_ref() { + let v = oracle_job::http_task::Method::try_from(*v) + .map_err(|_| serde::ser::Error::custom(format!("Invalid variant {}", *v)))?; + struct_ser.serialize_field("method", &v)?; + } + if !self.headers.is_empty() { + struct_ser.serialize_field("headers", &self.headers)?; + } + if let Some(v) = self.body.as_ref() { + struct_ser.serialize_field("body", v)?; + } + struct_ser.end() + } +} +impl<'de> serde::Deserialize<'de> for oracle_job::HttpTask { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &[ + "url", + "method", + "headers", + "body", + ]; + + #[allow(clippy::enum_variant_names)] + enum GeneratedField { + Url, + Method, + Headers, + Body, + } + 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 { + "url" => Ok(GeneratedField::Url), + "method" => Ok(GeneratedField::Method), + "headers" => Ok(GeneratedField::Headers), + "body" => Ok(GeneratedField::Body), + _ => Err(serde::de::Error::unknown_field(value, FIELDS)), + } + } + } + deserializer.deserialize_identifier(GeneratedVisitor) + } + } + struct GeneratedVisitor; + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = oracle_job::HttpTask; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("struct oracle_job.OracleJob.HttpTask") + } + + fn visit_map(self, mut map_: V) -> std::result::Result + where + V: serde::de::MapAccess<'de>, + { + let mut url__ = None; + let mut method__ = None; + let mut headers__ = None; + let mut body__ = None; + while let Some(k) = map_.next_key()? { + match k { + GeneratedField::Url => { + if url__.is_some() { + return Err(serde::de::Error::duplicate_field("url")); + } + url__ = map_.next_value()?; + } + GeneratedField::Method => { + if method__.is_some() { + return Err(serde::de::Error::duplicate_field("method")); + } + method__ = map_.next_value::<::std::option::Option>()?.map(|x| x as i32); + } + GeneratedField::Headers => { + if headers__.is_some() { + return Err(serde::de::Error::duplicate_field("headers")); + } + headers__ = Some(map_.next_value()?); + } + GeneratedField::Body => { + if body__.is_some() { + return Err(serde::de::Error::duplicate_field("body")); + } + body__ = map_.next_value()?; + } + } + } + Ok(oracle_job::HttpTask { + url: url__, + method: method__, + headers: headers__.unwrap_or_default(), + body: body__, + }) + } + } + deserializer.deserialize_struct("oracle_job.OracleJob.HttpTask", FIELDS, GeneratedVisitor) + } +} +impl serde::Serialize for oracle_job::http_task::Header { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + use serde::ser::SerializeStruct; + let mut len = 0; + if self.key.is_some() { + len += 1; + } + if self.value.is_some() { + len += 1; + } + let mut struct_ser = serializer.serialize_struct("oracle_job.OracleJob.HttpTask.Header", len)?; + if let Some(v) = self.key.as_ref() { + struct_ser.serialize_field("key", v)?; + } + if let Some(v) = self.value.as_ref() { + struct_ser.serialize_field("value", v)?; + } + struct_ser.end() + } +} +impl<'de> serde::Deserialize<'de> for oracle_job::http_task::Header { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &[ + "key", + "value", + ]; + + #[allow(clippy::enum_variant_names)] + enum GeneratedField { + Key, + Value, + } + 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 { + "key" => Ok(GeneratedField::Key), + "value" => Ok(GeneratedField::Value), + _ => Err(serde::de::Error::unknown_field(value, FIELDS)), + } + } + } + deserializer.deserialize_identifier(GeneratedVisitor) + } + } + struct GeneratedVisitor; + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = oracle_job::http_task::Header; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("struct oracle_job.OracleJob.HttpTask.Header") + } + + fn visit_map(self, mut map_: V) -> std::result::Result + where + V: serde::de::MapAccess<'de>, + { + let mut key__ = None; + let mut value__ = None; + while let Some(k) = map_.next_key()? { + match k { + GeneratedField::Key => { + if key__.is_some() { + return Err(serde::de::Error::duplicate_field("key")); + } + key__ = map_.next_value()?; + } + GeneratedField::Value => { + if value__.is_some() { + return Err(serde::de::Error::duplicate_field("value")); + } + value__ = map_.next_value()?; + } + } + } + Ok(oracle_job::http_task::Header { + key: key__, + value: value__, + }) + } + } + deserializer.deserialize_struct("oracle_job.OracleJob.HttpTask.Header", FIELDS, GeneratedVisitor) + } +} +impl serde::Serialize for oracle_job::http_task::Method { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + let variant = match self { + Self::Unkown => "METHOD_UNKOWN", + Self::Get => "METHOD_GET", + Self::Post => "METHOD_POST", + }; + serializer.serialize_str(variant) + } +} +impl<'de> serde::Deserialize<'de> for oracle_job::http_task::Method { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &[ + "METHOD_UNKOWN", + "METHOD_GET", + "METHOD_POST", + ]; + + struct GeneratedVisitor; + + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = oracle_job::http_task::Method; + + 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 { + "METHOD_UNKOWN" => Ok(oracle_job::http_task::Method::Unkown), + "METHOD_GET" => Ok(oracle_job::http_task::Method::Get), + "METHOD_POST" => Ok(oracle_job::http_task::Method::Post), + _ => Err(serde::de::Error::unknown_variant(value, FIELDS)), + } + } + } + deserializer.deserialize_any(GeneratedVisitor) + } +} +impl serde::Serialize for oracle_job::JsonParseTask { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + use serde::ser::SerializeStruct; + let mut len = 0; + if self.path.is_some() { + len += 1; + } + if self.aggregation_method.is_some() { + len += 1; + } + let mut struct_ser = serializer.serialize_struct("oracle_job.OracleJob.JsonParseTask", len)?; + if let Some(v) = self.path.as_ref() { + struct_ser.serialize_field("path", v)?; + } + if let Some(v) = self.aggregation_method.as_ref() { + let v = oracle_job::json_parse_task::AggregationMethod::try_from(*v) + .map_err(|_| serde::ser::Error::custom(format!("Invalid variant {}", *v)))?; + struct_ser.serialize_field("aggregationMethod", &v)?; + } + struct_ser.end() + } +} +impl<'de> serde::Deserialize<'de> for oracle_job::JsonParseTask { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &[ + "path", + "aggregation_method", + "aggregationMethod", + ]; + + #[allow(clippy::enum_variant_names)] + enum GeneratedField { + Path, + AggregationMethod, + } + 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 { + "path" => Ok(GeneratedField::Path), + "aggregationMethod" | "aggregation_method" => Ok(GeneratedField::AggregationMethod), + _ => Err(serde::de::Error::unknown_field(value, FIELDS)), + } + } + } + deserializer.deserialize_identifier(GeneratedVisitor) + } + } + struct GeneratedVisitor; + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = oracle_job::JsonParseTask; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("struct oracle_job.OracleJob.JsonParseTask") + } + + fn visit_map(self, mut map_: V) -> std::result::Result + where + V: serde::de::MapAccess<'de>, + { + let mut path__ = None; + let mut aggregation_method__ = None; + while let Some(k) = map_.next_key()? { + match k { + GeneratedField::Path => { + if path__.is_some() { + return Err(serde::de::Error::duplicate_field("path")); + } + path__ = map_.next_value()?; + } + GeneratedField::AggregationMethod => { + if aggregation_method__.is_some() { + return Err(serde::de::Error::duplicate_field("aggregationMethod")); + } + aggregation_method__ = map_.next_value::<::std::option::Option>()?.map(|x| x as i32); + } + } + } + Ok(oracle_job::JsonParseTask { + path: path__, + aggregation_method: aggregation_method__, + }) + } + } + deserializer.deserialize_struct("oracle_job.OracleJob.JsonParseTask", FIELDS, GeneratedVisitor) + } +} +impl serde::Serialize for oracle_job::json_parse_task::AggregationMethod { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + let variant = match self { + Self::None => "NONE", + Self::Min => "MIN", + Self::Max => "MAX", + Self::Sum => "SUM", + Self::Mean => "MEAN", + Self::Median => "MEDIAN", + }; + serializer.serialize_str(variant) + } +} +impl<'de> serde::Deserialize<'de> for oracle_job::json_parse_task::AggregationMethod { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &[ + "NONE", + "MIN", + "MAX", + "SUM", + "MEAN", + "MEDIAN", + ]; + + struct GeneratedVisitor; + + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = oracle_job::json_parse_task::AggregationMethod; + + 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 { + "NONE" => Ok(oracle_job::json_parse_task::AggregationMethod::None), + "MIN" => Ok(oracle_job::json_parse_task::AggregationMethod::Min), + "MAX" => Ok(oracle_job::json_parse_task::AggregationMethod::Max), + "SUM" => Ok(oracle_job::json_parse_task::AggregationMethod::Sum), + "MEAN" => Ok(oracle_job::json_parse_task::AggregationMethod::Mean), + "MEDIAN" => Ok(oracle_job::json_parse_task::AggregationMethod::Median), + _ => Err(serde::de::Error::unknown_variant(value, FIELDS)), + } + } + } + deserializer.deserialize_any(GeneratedVisitor) + } +} +impl serde::Serialize for oracle_job::JupiterSwapTask { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + use serde::ser::SerializeStruct; + let mut len = 0; + if self.in_token_address.is_some() { + len += 1; + } + if self.out_token_address.is_some() { + len += 1; + } + if self.slippage.is_some() { + len += 1; + } + if self.version.is_some() { + len += 1; + } + if self.routes_filters.is_some() { + len += 1; + } + if self.swap_amount.is_some() { + len += 1; + } + let mut struct_ser = serializer.serialize_struct("oracle_job.OracleJob.JupiterSwapTask", len)?; + if let Some(v) = self.in_token_address.as_ref() { + struct_ser.serialize_field("inTokenAddress", v)?; + } + if let Some(v) = self.out_token_address.as_ref() { + struct_ser.serialize_field("outTokenAddress", v)?; + } + if let Some(v) = self.slippage.as_ref() { + struct_ser.serialize_field("slippage", v)?; + } + if let Some(v) = self.version.as_ref() { + let v = oracle_job::jupiter_swap_task::Version::try_from(*v) + .map_err(|_| serde::ser::Error::custom(format!("Invalid variant {}", *v)))?; + struct_ser.serialize_field("version", &v)?; + } + if let Some(v) = self.routes_filters.as_ref() { + match v { + oracle_job::jupiter_swap_task::RoutesFilters::AllowList(v) => { + struct_ser.serialize_field("allowList", v)?; + } + oracle_job::jupiter_swap_task::RoutesFilters::DenyList(v) => { + struct_ser.serialize_field("denyList", v)?; + } + } + } + if let Some(v) = self.swap_amount.as_ref() { + match v { + oracle_job::jupiter_swap_task::SwapAmount::BaseAmount(v) => { + struct_ser.serialize_field("baseAmount", v)?; + } + oracle_job::jupiter_swap_task::SwapAmount::QuoteAmount(v) => { + struct_ser.serialize_field("quoteAmount", v)?; + } + oracle_job::jupiter_swap_task::SwapAmount::BaseAmountString(v) => { + struct_ser.serialize_field("baseAmountString", v)?; + } + oracle_job::jupiter_swap_task::SwapAmount::QuoteAmountString(v) => { + struct_ser.serialize_field("quoteAmountString", v)?; + } + } + } + struct_ser.end() + } +} +impl<'de> serde::Deserialize<'de> for oracle_job::JupiterSwapTask { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &[ + "in_token_address", + "inTokenAddress", + "out_token_address", + "outTokenAddress", + "slippage", + "version", + "allow_list", + "allowList", + "deny_list", + "denyList", + "base_amount", + "baseAmount", + "quote_amount", + "quoteAmount", + "base_amount_string", + "baseAmountString", + "quote_amount_string", + "quoteAmountString", + ]; + + #[allow(clippy::enum_variant_names)] + enum GeneratedField { + InTokenAddress, + OutTokenAddress, + Slippage, + Version, + AllowList, + DenyList, + BaseAmount, + QuoteAmount, + BaseAmountString, + QuoteAmountString, + } + 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 { + "inTokenAddress" | "in_token_address" => Ok(GeneratedField::InTokenAddress), + "outTokenAddress" | "out_token_address" => Ok(GeneratedField::OutTokenAddress), + "slippage" => Ok(GeneratedField::Slippage), + "version" => Ok(GeneratedField::Version), + "allowList" | "allow_list" => Ok(GeneratedField::AllowList), + "denyList" | "deny_list" => Ok(GeneratedField::DenyList), + "baseAmount" | "base_amount" => Ok(GeneratedField::BaseAmount), + "quoteAmount" | "quote_amount" => Ok(GeneratedField::QuoteAmount), + "baseAmountString" | "base_amount_string" => Ok(GeneratedField::BaseAmountString), + "quoteAmountString" | "quote_amount_string" => Ok(GeneratedField::QuoteAmountString), + _ => Err(serde::de::Error::unknown_field(value, FIELDS)), + } + } + } + deserializer.deserialize_identifier(GeneratedVisitor) + } + } + struct GeneratedVisitor; + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = oracle_job::JupiterSwapTask; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("struct oracle_job.OracleJob.JupiterSwapTask") + } + + fn visit_map(self, mut map_: V) -> std::result::Result + where + V: serde::de::MapAccess<'de>, + { + let mut in_token_address__ = None; + let mut out_token_address__ = None; + let mut slippage__ = None; + let mut version__ = None; + let mut routes_filters__ = None; + let mut swap_amount__ = None; + while let Some(k) = map_.next_key()? { + match k { + GeneratedField::InTokenAddress => { + if in_token_address__.is_some() { + return Err(serde::de::Error::duplicate_field("inTokenAddress")); + } + in_token_address__ = map_.next_value()?; + } + GeneratedField::OutTokenAddress => { + if out_token_address__.is_some() { + return Err(serde::de::Error::duplicate_field("outTokenAddress")); + } + out_token_address__ = map_.next_value()?; + } + GeneratedField::Slippage => { + if slippage__.is_some() { + return Err(serde::de::Error::duplicate_field("slippage")); + } + slippage__ = + map_.next_value::<::std::option::Option<::pbjson::private::NumberDeserialize<_>>>()?.map(|x| x.0) + ; + } + GeneratedField::Version => { + if version__.is_some() { + return Err(serde::de::Error::duplicate_field("version")); + } + version__ = map_.next_value::<::std::option::Option>()?.map(|x| x as i32); + } + GeneratedField::AllowList => { + if routes_filters__.is_some() { + return Err(serde::de::Error::duplicate_field("allowList")); + } + routes_filters__ = map_.next_value::<::std::option::Option<_>>()?.map(oracle_job::jupiter_swap_task::RoutesFilters::AllowList) +; + } + GeneratedField::DenyList => { + if routes_filters__.is_some() { + return Err(serde::de::Error::duplicate_field("denyList")); + } + routes_filters__ = map_.next_value::<::std::option::Option<_>>()?.map(oracle_job::jupiter_swap_task::RoutesFilters::DenyList) +; + } + GeneratedField::BaseAmount => { + if swap_amount__.is_some() { + return Err(serde::de::Error::duplicate_field("baseAmount")); + } + swap_amount__ = map_.next_value::<::std::option::Option<::pbjson::private::NumberDeserialize<_>>>()?.map(|x| oracle_job::jupiter_swap_task::SwapAmount::BaseAmount(x.0)); + } + GeneratedField::QuoteAmount => { + if swap_amount__.is_some() { + return Err(serde::de::Error::duplicate_field("quoteAmount")); + } + swap_amount__ = map_.next_value::<::std::option::Option<::pbjson::private::NumberDeserialize<_>>>()?.map(|x| oracle_job::jupiter_swap_task::SwapAmount::QuoteAmount(x.0)); + } + GeneratedField::BaseAmountString => { + if swap_amount__.is_some() { + return Err(serde::de::Error::duplicate_field("baseAmountString")); + } + swap_amount__ = map_.next_value::<::std::option::Option<_>>()?.map(oracle_job::jupiter_swap_task::SwapAmount::BaseAmountString); + } + GeneratedField::QuoteAmountString => { + if swap_amount__.is_some() { + return Err(serde::de::Error::duplicate_field("quoteAmountString")); + } + swap_amount__ = map_.next_value::<::std::option::Option<_>>()?.map(oracle_job::jupiter_swap_task::SwapAmount::QuoteAmountString); + } + } + } + Ok(oracle_job::JupiterSwapTask { + in_token_address: in_token_address__, + out_token_address: out_token_address__, + slippage: slippage__, + version: version__, + routes_filters: routes_filters__, + swap_amount: swap_amount__, + }) + } + } + deserializer.deserialize_struct("oracle_job.OracleJob.JupiterSwapTask", FIELDS, GeneratedVisitor) + } +} +impl serde::Serialize for oracle_job::jupiter_swap_task::FilterList { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + use serde::ser::SerializeStruct; + let mut len = 0; + if !self.labels.is_empty() { + len += 1; + } + let mut struct_ser = serializer.serialize_struct("oracle_job.OracleJob.JupiterSwapTask.FilterList", len)?; + if !self.labels.is_empty() { + struct_ser.serialize_field("labels", &self.labels)?; + } + struct_ser.end() + } +} +impl<'de> serde::Deserialize<'de> for oracle_job::jupiter_swap_task::FilterList { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &[ + "labels", + ]; + + #[allow(clippy::enum_variant_names)] + enum GeneratedField { + Labels, + } + 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 { + "labels" => Ok(GeneratedField::Labels), + _ => Err(serde::de::Error::unknown_field(value, FIELDS)), + } + } + } + deserializer.deserialize_identifier(GeneratedVisitor) + } + } + struct GeneratedVisitor; + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = oracle_job::jupiter_swap_task::FilterList; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("struct oracle_job.OracleJob.JupiterSwapTask.FilterList") + } + + fn visit_map(self, mut map_: V) -> std::result::Result + where + V: serde::de::MapAccess<'de>, + { + let mut labels__ = None; + while let Some(k) = map_.next_key()? { + match k { + GeneratedField::Labels => { + if labels__.is_some() { + return Err(serde::de::Error::duplicate_field("labels")); + } + labels__ = Some(map_.next_value()?); + } + } + } + Ok(oracle_job::jupiter_swap_task::FilterList { + labels: labels__.unwrap_or_default(), + }) + } + } + deserializer.deserialize_struct("oracle_job.OracleJob.JupiterSwapTask.FilterList", FIELDS, GeneratedVisitor) + } +} +impl serde::Serialize for oracle_job::jupiter_swap_task::Version { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + let variant = match self { + Self::V1 => "VERSION_V1", + Self::V2 => "VERSION_V2", + }; + serializer.serialize_str(variant) + } +} +impl<'de> serde::Deserialize<'de> for oracle_job::jupiter_swap_task::Version { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &[ + "VERSION_V1", + "VERSION_V2", + ]; + + struct GeneratedVisitor; + + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = oracle_job::jupiter_swap_task::Version; + + 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 { + "VERSION_V1" => Ok(oracle_job::jupiter_swap_task::Version::V1), + "VERSION_V2" => Ok(oracle_job::jupiter_swap_task::Version::V2), + _ => Err(serde::de::Error::unknown_variant(value, FIELDS)), + } + } + } + deserializer.deserialize_any(GeneratedVisitor) + } +} +impl serde::Serialize for oracle_job::LendingRateTask { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + use serde::ser::SerializeStruct; + let mut len = 0; + if self.protocol.is_some() { + len += 1; + } + if self.asset_mint.is_some() { + len += 1; + } + if self.field.is_some() { + len += 1; + } + let mut struct_ser = serializer.serialize_struct("oracle_job.OracleJob.LendingRateTask", len)?; + if let Some(v) = self.protocol.as_ref() { + struct_ser.serialize_field("protocol", v)?; + } + if let Some(v) = self.asset_mint.as_ref() { + struct_ser.serialize_field("assetMint", v)?; + } + if let Some(v) = self.field.as_ref() { + let v = oracle_job::lending_rate_task::Field::try_from(*v) + .map_err(|_| serde::ser::Error::custom(format!("Invalid variant {}", *v)))?; + struct_ser.serialize_field("field", &v)?; + } + struct_ser.end() + } +} +impl<'de> serde::Deserialize<'de> for oracle_job::LendingRateTask { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &[ + "protocol", + "asset_mint", + "assetMint", + "field", + ]; + + #[allow(clippy::enum_variant_names)] + enum GeneratedField { + Protocol, + AssetMint, + Field, + } + 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 { + "protocol" => Ok(GeneratedField::Protocol), + "assetMint" | "asset_mint" => Ok(GeneratedField::AssetMint), + "field" => Ok(GeneratedField::Field), + _ => Err(serde::de::Error::unknown_field(value, FIELDS)), + } + } + } + deserializer.deserialize_identifier(GeneratedVisitor) + } + } + struct GeneratedVisitor; + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = oracle_job::LendingRateTask; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("struct oracle_job.OracleJob.LendingRateTask") + } + + fn visit_map(self, mut map_: V) -> std::result::Result + where + V: serde::de::MapAccess<'de>, + { + let mut protocol__ = None; + let mut asset_mint__ = None; + let mut field__ = None; + while let Some(k) = map_.next_key()? { + match k { + GeneratedField::Protocol => { + if protocol__.is_some() { + return Err(serde::de::Error::duplicate_field("protocol")); + } + protocol__ = map_.next_value()?; + } + GeneratedField::AssetMint => { + if asset_mint__.is_some() { + return Err(serde::de::Error::duplicate_field("assetMint")); + } + asset_mint__ = map_.next_value()?; + } + GeneratedField::Field => { + if field__.is_some() { + return Err(serde::de::Error::duplicate_field("field")); + } + field__ = map_.next_value::<::std::option::Option>()?.map(|x| x as i32); + } + } + } + Ok(oracle_job::LendingRateTask { + protocol: protocol__, + asset_mint: asset_mint__, + field: field__, + }) + } + } + deserializer.deserialize_struct("oracle_job.OracleJob.LendingRateTask", FIELDS, GeneratedVisitor) + } +} +impl serde::Serialize for oracle_job::lending_rate_task::Field { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + let variant = match self { + Self::DepositRate => "FIELD_DEPOSIT_RATE", + Self::BorrowRate => "FIELD_BORROW_RATE", + }; + serializer.serialize_str(variant) + } +} +impl<'de> serde::Deserialize<'de> for oracle_job::lending_rate_task::Field { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &[ + "FIELD_DEPOSIT_RATE", + "FIELD_BORROW_RATE", + ]; + + struct GeneratedVisitor; + + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = oracle_job::lending_rate_task::Field; + + 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 { + "FIELD_DEPOSIT_RATE" => Ok(oracle_job::lending_rate_task::Field::DepositRate), + "FIELD_BORROW_RATE" => Ok(oracle_job::lending_rate_task::Field::BorrowRate), + _ => Err(serde::de::Error::unknown_variant(value, FIELDS)), + } + } + } + deserializer.deserialize_any(GeneratedVisitor) + } +} +impl serde::Serialize for oracle_job::LlmTask { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + use serde::ser::SerializeStruct; + let mut len = 0; + if self.provider_config.is_some() { + len += 1; + } + let mut struct_ser = serializer.serialize_struct("oracle_job.OracleJob.LlmTask", len)?; + if let Some(v) = self.provider_config.as_ref() { + match v { + oracle_job::llm_task::ProviderConfig::Openai(v) => { + struct_ser.serialize_field("openai", v)?; + } + oracle_job::llm_task::ProviderConfig::Groq(v) => { + struct_ser.serialize_field("groq", v)?; + } + oracle_job::llm_task::ProviderConfig::Grokxai(v) => { + struct_ser.serialize_field("grokxai", v)?; + } + } + } + struct_ser.end() + } +} +impl<'de> serde::Deserialize<'de> for oracle_job::LlmTask { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &[ + "openai", + "groq", + "grokxai", + ]; + + #[allow(clippy::enum_variant_names)] + enum GeneratedField { + Openai, + Groq, + Grokxai, + } + 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 { + "openai" => Ok(GeneratedField::Openai), + "groq" => Ok(GeneratedField::Groq), + "grokxai" => Ok(GeneratedField::Grokxai), + _ => Err(serde::de::Error::unknown_field(value, FIELDS)), + } + } + } + deserializer.deserialize_identifier(GeneratedVisitor) + } + } + struct GeneratedVisitor; + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = oracle_job::LlmTask; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("struct oracle_job.OracleJob.LlmTask") + } + + fn visit_map(self, mut map_: V) -> std::result::Result + where + V: serde::de::MapAccess<'de>, + { + let mut provider_config__ = None; + while let Some(k) = map_.next_key()? { + match k { + GeneratedField::Openai => { + if provider_config__.is_some() { + return Err(serde::de::Error::duplicate_field("openai")); + } + provider_config__ = map_.next_value::<::std::option::Option<_>>()?.map(oracle_job::llm_task::ProviderConfig::Openai) +; + } + GeneratedField::Groq => { + if provider_config__.is_some() { + return Err(serde::de::Error::duplicate_field("groq")); + } + provider_config__ = map_.next_value::<::std::option::Option<_>>()?.map(oracle_job::llm_task::ProviderConfig::Groq) +; + } + GeneratedField::Grokxai => { + if provider_config__.is_some() { + return Err(serde::de::Error::duplicate_field("grokxai")); + } + provider_config__ = map_.next_value::<::std::option::Option<_>>()?.map(oracle_job::llm_task::ProviderConfig::Grokxai) +; + } + } + } + Ok(oracle_job::LlmTask { + provider_config: provider_config__, + }) + } + } + deserializer.deserialize_struct("oracle_job.OracleJob.LlmTask", FIELDS, GeneratedVisitor) + } +} +impl serde::Serialize for oracle_job::llm_task::GrokXaiConfig { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + use serde::ser::SerializeStruct; + let mut len = 0; + if self.model.is_some() { + len += 1; + } + if self.user_prompt.is_some() { + len += 1; + } + if self.temperature.is_some() { + len += 1; + } + if self.secret_name_api_key.is_some() { + len += 1; + } + let mut struct_ser = serializer.serialize_struct("oracle_job.OracleJob.LlmTask.GrokXAIConfig", len)?; + if let Some(v) = self.model.as_ref() { + struct_ser.serialize_field("model", v)?; + } + if let Some(v) = self.user_prompt.as_ref() { + struct_ser.serialize_field("userPrompt", v)?; + } + if let Some(v) = self.temperature.as_ref() { + struct_ser.serialize_field("temperature", v)?; + } + if let Some(v) = self.secret_name_api_key.as_ref() { + struct_ser.serialize_field("secretNameApiKey", v)?; + } + struct_ser.end() + } +} +impl<'de> serde::Deserialize<'de> for oracle_job::llm_task::GrokXaiConfig { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &[ + "model", + "user_prompt", + "userPrompt", + "temperature", + "secret_name_api_key", + "secretNameApiKey", + ]; + + #[allow(clippy::enum_variant_names)] + enum GeneratedField { + Model, + UserPrompt, + Temperature, + SecretNameApiKey, + } + 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 { + "model" => Ok(GeneratedField::Model), + "userPrompt" | "user_prompt" => Ok(GeneratedField::UserPrompt), + "temperature" => Ok(GeneratedField::Temperature), + "secretNameApiKey" | "secret_name_api_key" => Ok(GeneratedField::SecretNameApiKey), + _ => Err(serde::de::Error::unknown_field(value, FIELDS)), + } + } + } + deserializer.deserialize_identifier(GeneratedVisitor) + } + } + struct GeneratedVisitor; + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = oracle_job::llm_task::GrokXaiConfig; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("struct oracle_job.OracleJob.LlmTask.GrokXAIConfig") + } + + fn visit_map(self, mut map_: V) -> std::result::Result + where + V: serde::de::MapAccess<'de>, + { + let mut model__ = None; + let mut user_prompt__ = None; + let mut temperature__ = None; + let mut secret_name_api_key__ = None; + while let Some(k) = map_.next_key()? { + match k { + GeneratedField::Model => { + if model__.is_some() { + return Err(serde::de::Error::duplicate_field("model")); + } + model__ = map_.next_value()?; + } + GeneratedField::UserPrompt => { + if user_prompt__.is_some() { + return Err(serde::de::Error::duplicate_field("userPrompt")); + } + user_prompt__ = map_.next_value()?; + } + GeneratedField::Temperature => { + if temperature__.is_some() { + return Err(serde::de::Error::duplicate_field("temperature")); + } + temperature__ = + map_.next_value::<::std::option::Option<::pbjson::private::NumberDeserialize<_>>>()?.map(|x| x.0) + ; + } + GeneratedField::SecretNameApiKey => { + if secret_name_api_key__.is_some() { + return Err(serde::de::Error::duplicate_field("secretNameApiKey")); + } + secret_name_api_key__ = map_.next_value()?; + } + } + } + Ok(oracle_job::llm_task::GrokXaiConfig { + model: model__, + user_prompt: user_prompt__, + temperature: temperature__, + secret_name_api_key: secret_name_api_key__, + }) + } + } + deserializer.deserialize_struct("oracle_job.OracleJob.LlmTask.GrokXAIConfig", FIELDS, GeneratedVisitor) + } +} +impl serde::Serialize for oracle_job::llm_task::GroqConfig { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + use serde::ser::SerializeStruct; + let mut len = 0; + if self.model.is_some() { + len += 1; + } + if self.user_prompt.is_some() { + len += 1; + } + if self.temperature.is_some() { + len += 1; + } + if self.secret_name_api_key.is_some() { + len += 1; + } + let mut struct_ser = serializer.serialize_struct("oracle_job.OracleJob.LlmTask.GroqConfig", len)?; + if let Some(v) = self.model.as_ref() { + struct_ser.serialize_field("model", v)?; + } + if let Some(v) = self.user_prompt.as_ref() { + struct_ser.serialize_field("userPrompt", v)?; + } + if let Some(v) = self.temperature.as_ref() { + struct_ser.serialize_field("temperature", v)?; + } + if let Some(v) = self.secret_name_api_key.as_ref() { + struct_ser.serialize_field("secretNameApiKey", v)?; + } + struct_ser.end() + } +} +impl<'de> serde::Deserialize<'de> for oracle_job::llm_task::GroqConfig { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &[ + "model", + "user_prompt", + "userPrompt", + "temperature", + "secret_name_api_key", + "secretNameApiKey", + ]; + + #[allow(clippy::enum_variant_names)] + enum GeneratedField { + Model, + UserPrompt, + Temperature, + SecretNameApiKey, + } + 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 { + "model" => Ok(GeneratedField::Model), + "userPrompt" | "user_prompt" => Ok(GeneratedField::UserPrompt), + "temperature" => Ok(GeneratedField::Temperature), + "secretNameApiKey" | "secret_name_api_key" => Ok(GeneratedField::SecretNameApiKey), + _ => Err(serde::de::Error::unknown_field(value, FIELDS)), + } + } + } + deserializer.deserialize_identifier(GeneratedVisitor) + } + } + struct GeneratedVisitor; + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = oracle_job::llm_task::GroqConfig; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("struct oracle_job.OracleJob.LlmTask.GroqConfig") + } + + fn visit_map(self, mut map_: V) -> std::result::Result + where + V: serde::de::MapAccess<'de>, + { + let mut model__ = None; + let mut user_prompt__ = None; + let mut temperature__ = None; + let mut secret_name_api_key__ = None; + while let Some(k) = map_.next_key()? { + match k { + GeneratedField::Model => { + if model__.is_some() { + return Err(serde::de::Error::duplicate_field("model")); + } + model__ = map_.next_value()?; + } + GeneratedField::UserPrompt => { + if user_prompt__.is_some() { + return Err(serde::de::Error::duplicate_field("userPrompt")); + } + user_prompt__ = map_.next_value()?; + } + GeneratedField::Temperature => { + if temperature__.is_some() { + return Err(serde::de::Error::duplicate_field("temperature")); + } + temperature__ = + map_.next_value::<::std::option::Option<::pbjson::private::NumberDeserialize<_>>>()?.map(|x| x.0) + ; + } + GeneratedField::SecretNameApiKey => { + if secret_name_api_key__.is_some() { + return Err(serde::de::Error::duplicate_field("secretNameApiKey")); + } + secret_name_api_key__ = map_.next_value()?; + } + } + } + Ok(oracle_job::llm_task::GroqConfig { + model: model__, + user_prompt: user_prompt__, + temperature: temperature__, + secret_name_api_key: secret_name_api_key__, + }) + } + } + deserializer.deserialize_struct("oracle_job.OracleJob.LlmTask.GroqConfig", FIELDS, GeneratedVisitor) + } +} +impl serde::Serialize for oracle_job::llm_task::OpenAiConfig { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + use serde::ser::SerializeStruct; + let mut len = 0; + if self.model.is_some() { + len += 1; + } + if self.user_prompt.is_some() { + len += 1; + } + if self.temperature.is_some() { + len += 1; + } + if self.secret_name_api_key.is_some() { + len += 1; + } + let mut struct_ser = serializer.serialize_struct("oracle_job.OracleJob.LlmTask.OpenAIConfig", len)?; + if let Some(v) = self.model.as_ref() { + struct_ser.serialize_field("model", v)?; + } + if let Some(v) = self.user_prompt.as_ref() { + struct_ser.serialize_field("userPrompt", v)?; + } + if let Some(v) = self.temperature.as_ref() { + struct_ser.serialize_field("temperature", v)?; + } + if let Some(v) = self.secret_name_api_key.as_ref() { + struct_ser.serialize_field("secretNameApiKey", v)?; + } + struct_ser.end() + } +} +impl<'de> serde::Deserialize<'de> for oracle_job::llm_task::OpenAiConfig { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &[ + "model", + "user_prompt", + "userPrompt", + "temperature", + "secret_name_api_key", + "secretNameApiKey", + ]; + + #[allow(clippy::enum_variant_names)] + enum GeneratedField { + Model, + UserPrompt, + Temperature, + SecretNameApiKey, + } + 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 { + "model" => Ok(GeneratedField::Model), + "userPrompt" | "user_prompt" => Ok(GeneratedField::UserPrompt), + "temperature" => Ok(GeneratedField::Temperature), + "secretNameApiKey" | "secret_name_api_key" => Ok(GeneratedField::SecretNameApiKey), + _ => Err(serde::de::Error::unknown_field(value, FIELDS)), + } + } + } + deserializer.deserialize_identifier(GeneratedVisitor) + } + } + struct GeneratedVisitor; + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = oracle_job::llm_task::OpenAiConfig; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("struct oracle_job.OracleJob.LlmTask.OpenAIConfig") + } + + fn visit_map(self, mut map_: V) -> std::result::Result + where + V: serde::de::MapAccess<'de>, + { + let mut model__ = None; + let mut user_prompt__ = None; + let mut temperature__ = None; + let mut secret_name_api_key__ = None; + while let Some(k) = map_.next_key()? { + match k { + GeneratedField::Model => { + if model__.is_some() { + return Err(serde::de::Error::duplicate_field("model")); + } + model__ = map_.next_value()?; + } + GeneratedField::UserPrompt => { + if user_prompt__.is_some() { + return Err(serde::de::Error::duplicate_field("userPrompt")); + } + user_prompt__ = map_.next_value()?; + } + GeneratedField::Temperature => { + if temperature__.is_some() { + return Err(serde::de::Error::duplicate_field("temperature")); + } + temperature__ = + map_.next_value::<::std::option::Option<::pbjson::private::NumberDeserialize<_>>>()?.map(|x| x.0) + ; + } + GeneratedField::SecretNameApiKey => { + if secret_name_api_key__.is_some() { + return Err(serde::de::Error::duplicate_field("secretNameApiKey")); + } + secret_name_api_key__ = map_.next_value()?; + } + } + } + Ok(oracle_job::llm_task::OpenAiConfig { + model: model__, + user_prompt: user_prompt__, + temperature: temperature__, + secret_name_api_key: secret_name_api_key__, + }) + } + } + deserializer.deserialize_struct("oracle_job.OracleJob.LlmTask.OpenAIConfig", FIELDS, GeneratedVisitor) + } +} +impl serde::Serialize for oracle_job::LpExchangeRateTask { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + use serde::ser::SerializeStruct; + let mut len = 0; + if self.in_token_address.is_some() { + len += 1; + } + if self.out_token_address.is_some() { + len += 1; + } + if self.chain.is_some() { + len += 1; + } + if self.pool_address.is_some() { + len += 1; + } + let mut struct_ser = serializer.serialize_struct("oracle_job.OracleJob.LpExchangeRateTask", len)?; + if let Some(v) = self.in_token_address.as_ref() { + struct_ser.serialize_field("inTokenAddress", v)?; + } + if let Some(v) = self.out_token_address.as_ref() { + struct_ser.serialize_field("outTokenAddress", v)?; + } + if let Some(v) = self.chain.as_ref() { + let v = oracle_job::lp_exchange_rate_task::Chain::try_from(*v) + .map_err(|_| serde::ser::Error::custom(format!("Invalid variant {}", *v)))?; + struct_ser.serialize_field("chain", &v)?; + } + if let Some(v) = self.pool_address.as_ref() { + match v { + oracle_job::lp_exchange_rate_task::PoolAddress::MercurialPoolAddress(v) => { + struct_ser.serialize_field("mercurialPoolAddress", v)?; + } + oracle_job::lp_exchange_rate_task::PoolAddress::SaberPoolAddress(v) => { + struct_ser.serialize_field("saberPoolAddress", v)?; + } + oracle_job::lp_exchange_rate_task::PoolAddress::OrcaPoolTokenMintAddress(v) => { + struct_ser.serialize_field("orcaPoolTokenMintAddress", v)?; + } + oracle_job::lp_exchange_rate_task::PoolAddress::RaydiumPoolAddress(v) => { + struct_ser.serialize_field("raydiumPoolAddress", v)?; + } + oracle_job::lp_exchange_rate_task::PoolAddress::OrcaPoolAddress(v) => { + struct_ser.serialize_field("orcaPoolAddress", v)?; + } + oracle_job::lp_exchange_rate_task::PoolAddress::PortReserveAddress(v) => { + struct_ser.serialize_field("portReserveAddress", v)?; + } + } + } + struct_ser.end() + } +} +impl<'de> serde::Deserialize<'de> for oracle_job::LpExchangeRateTask { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &[ + "in_token_address", + "inTokenAddress", + "out_token_address", + "outTokenAddress", + "chain", + "mercurial_pool_address", + "mercurialPoolAddress", + "saber_pool_address", + "saberPoolAddress", + "orca_pool_token_mint_address", + "orcaPoolTokenMintAddress", + "raydium_pool_address", + "raydiumPoolAddress", + "orca_pool_address", + "orcaPoolAddress", + "port_reserve_address", + "portReserveAddress", + ]; + + #[allow(clippy::enum_variant_names)] + enum GeneratedField { + InTokenAddress, + OutTokenAddress, + Chain, + MercurialPoolAddress, + SaberPoolAddress, + OrcaPoolTokenMintAddress, + RaydiumPoolAddress, + OrcaPoolAddress, + PortReserveAddress, + } + 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 { + "inTokenAddress" | "in_token_address" => Ok(GeneratedField::InTokenAddress), + "outTokenAddress" | "out_token_address" => Ok(GeneratedField::OutTokenAddress), + "chain" => Ok(GeneratedField::Chain), + "mercurialPoolAddress" | "mercurial_pool_address" => Ok(GeneratedField::MercurialPoolAddress), + "saberPoolAddress" | "saber_pool_address" => Ok(GeneratedField::SaberPoolAddress), + "orcaPoolTokenMintAddress" | "orca_pool_token_mint_address" => Ok(GeneratedField::OrcaPoolTokenMintAddress), + "raydiumPoolAddress" | "raydium_pool_address" => Ok(GeneratedField::RaydiumPoolAddress), + "orcaPoolAddress" | "orca_pool_address" => Ok(GeneratedField::OrcaPoolAddress), + "portReserveAddress" | "port_reserve_address" => Ok(GeneratedField::PortReserveAddress), + _ => Err(serde::de::Error::unknown_field(value, FIELDS)), + } + } + } + deserializer.deserialize_identifier(GeneratedVisitor) + } + } + struct GeneratedVisitor; + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = oracle_job::LpExchangeRateTask; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("struct oracle_job.OracleJob.LpExchangeRateTask") + } + + fn visit_map(self, mut map_: V) -> std::result::Result + where + V: serde::de::MapAccess<'de>, + { + let mut in_token_address__ = None; + let mut out_token_address__ = None; + let mut chain__ = None; + let mut pool_address__ = None; + while let Some(k) = map_.next_key()? { + match k { + GeneratedField::InTokenAddress => { + if in_token_address__.is_some() { + return Err(serde::de::Error::duplicate_field("inTokenAddress")); + } + in_token_address__ = map_.next_value()?; + } + GeneratedField::OutTokenAddress => { + if out_token_address__.is_some() { + return Err(serde::de::Error::duplicate_field("outTokenAddress")); + } + out_token_address__ = map_.next_value()?; + } + GeneratedField::Chain => { + if chain__.is_some() { + return Err(serde::de::Error::duplicate_field("chain")); + } + chain__ = map_.next_value::<::std::option::Option>()?.map(|x| x as i32); + } + GeneratedField::MercurialPoolAddress => { + if pool_address__.is_some() { + return Err(serde::de::Error::duplicate_field("mercurialPoolAddress")); + } + pool_address__ = map_.next_value::<::std::option::Option<_>>()?.map(oracle_job::lp_exchange_rate_task::PoolAddress::MercurialPoolAddress); + } + GeneratedField::SaberPoolAddress => { + if pool_address__.is_some() { + return Err(serde::de::Error::duplicate_field("saberPoolAddress")); + } + pool_address__ = map_.next_value::<::std::option::Option<_>>()?.map(oracle_job::lp_exchange_rate_task::PoolAddress::SaberPoolAddress); + } + GeneratedField::OrcaPoolTokenMintAddress => { + if pool_address__.is_some() { + return Err(serde::de::Error::duplicate_field("orcaPoolTokenMintAddress")); + } + pool_address__ = map_.next_value::<::std::option::Option<_>>()?.map(oracle_job::lp_exchange_rate_task::PoolAddress::OrcaPoolTokenMintAddress); + } + GeneratedField::RaydiumPoolAddress => { + if pool_address__.is_some() { + return Err(serde::de::Error::duplicate_field("raydiumPoolAddress")); + } + pool_address__ = map_.next_value::<::std::option::Option<_>>()?.map(oracle_job::lp_exchange_rate_task::PoolAddress::RaydiumPoolAddress); + } + GeneratedField::OrcaPoolAddress => { + if pool_address__.is_some() { + return Err(serde::de::Error::duplicate_field("orcaPoolAddress")); + } + pool_address__ = map_.next_value::<::std::option::Option<_>>()?.map(oracle_job::lp_exchange_rate_task::PoolAddress::OrcaPoolAddress); + } + GeneratedField::PortReserveAddress => { + if pool_address__.is_some() { + return Err(serde::de::Error::duplicate_field("portReserveAddress")); + } + pool_address__ = map_.next_value::<::std::option::Option<_>>()?.map(oracle_job::lp_exchange_rate_task::PoolAddress::PortReserveAddress); + } + } + } + Ok(oracle_job::LpExchangeRateTask { + in_token_address: in_token_address__, + out_token_address: out_token_address__, + chain: chain__, + pool_address: pool_address__, + }) + } + } + deserializer.deserialize_struct("oracle_job.OracleJob.LpExchangeRateTask", FIELDS, GeneratedVisitor) + } +} +impl serde::Serialize for oracle_job::lp_exchange_rate_task::Chain { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + let variant = match self { + Self::Solana => "SOLANA", + Self::Eclipse => "ECLIPSE", + }; + serializer.serialize_str(variant) + } +} +impl<'de> serde::Deserialize<'de> for oracle_job::lp_exchange_rate_task::Chain { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &[ + "SOLANA", + "ECLIPSE", + ]; + + struct GeneratedVisitor; + + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = oracle_job::lp_exchange_rate_task::Chain; + + 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 { + "SOLANA" => Ok(oracle_job::lp_exchange_rate_task::Chain::Solana), + "ECLIPSE" => Ok(oracle_job::lp_exchange_rate_task::Chain::Eclipse), + _ => Err(serde::de::Error::unknown_variant(value, FIELDS)), + } + } + } + deserializer.deserialize_any(GeneratedVisitor) + } +} +impl serde::Serialize for oracle_job::LpTokenPriceTask { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + use serde::ser::SerializeStruct; + let mut len = 0; + if !self.price_feed_addresses.is_empty() { + len += 1; + } + if !self.price_feed_jobs.is_empty() { + len += 1; + } + if self.use_fair_price.is_some() { + len += 1; + } + if self.pool_address.is_some() { + len += 1; + } + let mut struct_ser = serializer.serialize_struct("oracle_job.OracleJob.LpTokenPriceTask", len)?; + if !self.price_feed_addresses.is_empty() { + struct_ser.serialize_field("priceFeedAddresses", &self.price_feed_addresses)?; + } + if !self.price_feed_jobs.is_empty() { + struct_ser.serialize_field("priceFeedJobs", &self.price_feed_jobs)?; + } + if let Some(v) = self.use_fair_price.as_ref() { + struct_ser.serialize_field("useFairPrice", v)?; + } + if let Some(v) = self.pool_address.as_ref() { + match v { + oracle_job::lp_token_price_task::PoolAddress::MercurialPoolAddress(v) => { + struct_ser.serialize_field("mercurialPoolAddress", v)?; + } + oracle_job::lp_token_price_task::PoolAddress::SaberPoolAddress(v) => { + struct_ser.serialize_field("saberPoolAddress", v)?; + } + oracle_job::lp_token_price_task::PoolAddress::OrcaPoolAddress(v) => { + struct_ser.serialize_field("orcaPoolAddress", v)?; + } + oracle_job::lp_token_price_task::PoolAddress::RaydiumPoolAddress(v) => { + struct_ser.serialize_field("raydiumPoolAddress", v)?; + } + } + } + struct_ser.end() + } +} +impl<'de> serde::Deserialize<'de> for oracle_job::LpTokenPriceTask { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &[ + "price_feed_addresses", + "priceFeedAddresses", + "price_feed_jobs", + "priceFeedJobs", + "use_fair_price", + "useFairPrice", + "mercurial_pool_address", + "mercurialPoolAddress", + "saber_pool_address", + "saberPoolAddress", + "orca_pool_address", + "orcaPoolAddress", + "raydium_pool_address", + "raydiumPoolAddress", + ]; + + #[allow(clippy::enum_variant_names)] + enum GeneratedField { + PriceFeedAddresses, + PriceFeedJobs, + UseFairPrice, + MercurialPoolAddress, + SaberPoolAddress, + OrcaPoolAddress, + RaydiumPoolAddress, + } + 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 { + "priceFeedAddresses" | "price_feed_addresses" => Ok(GeneratedField::PriceFeedAddresses), + "priceFeedJobs" | "price_feed_jobs" => Ok(GeneratedField::PriceFeedJobs), + "useFairPrice" | "use_fair_price" => Ok(GeneratedField::UseFairPrice), + "mercurialPoolAddress" | "mercurial_pool_address" => Ok(GeneratedField::MercurialPoolAddress), + "saberPoolAddress" | "saber_pool_address" => Ok(GeneratedField::SaberPoolAddress), + "orcaPoolAddress" | "orca_pool_address" => Ok(GeneratedField::OrcaPoolAddress), + "raydiumPoolAddress" | "raydium_pool_address" => Ok(GeneratedField::RaydiumPoolAddress), + _ => Err(serde::de::Error::unknown_field(value, FIELDS)), + } + } + } + deserializer.deserialize_identifier(GeneratedVisitor) + } + } + struct GeneratedVisitor; + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = oracle_job::LpTokenPriceTask; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("struct oracle_job.OracleJob.LpTokenPriceTask") + } + + fn visit_map(self, mut map_: V) -> std::result::Result + where + V: serde::de::MapAccess<'de>, + { + let mut price_feed_addresses__ = None; + let mut price_feed_jobs__ = None; + let mut use_fair_price__ = None; + let mut pool_address__ = None; + while let Some(k) = map_.next_key()? { + match k { + GeneratedField::PriceFeedAddresses => { + if price_feed_addresses__.is_some() { + return Err(serde::de::Error::duplicate_field("priceFeedAddresses")); + } + price_feed_addresses__ = Some(map_.next_value()?); + } + GeneratedField::PriceFeedJobs => { + if price_feed_jobs__.is_some() { + return Err(serde::de::Error::duplicate_field("priceFeedJobs")); + } + price_feed_jobs__ = Some(map_.next_value()?); + } + GeneratedField::UseFairPrice => { + if use_fair_price__.is_some() { + return Err(serde::de::Error::duplicate_field("useFairPrice")); + } + use_fair_price__ = map_.next_value()?; + } + GeneratedField::MercurialPoolAddress => { + if pool_address__.is_some() { + return Err(serde::de::Error::duplicate_field("mercurialPoolAddress")); + } + pool_address__ = map_.next_value::<::std::option::Option<_>>()?.map(oracle_job::lp_token_price_task::PoolAddress::MercurialPoolAddress); + } + GeneratedField::SaberPoolAddress => { + if pool_address__.is_some() { + return Err(serde::de::Error::duplicate_field("saberPoolAddress")); + } + pool_address__ = map_.next_value::<::std::option::Option<_>>()?.map(oracle_job::lp_token_price_task::PoolAddress::SaberPoolAddress); + } + GeneratedField::OrcaPoolAddress => { + if pool_address__.is_some() { + return Err(serde::de::Error::duplicate_field("orcaPoolAddress")); + } + pool_address__ = map_.next_value::<::std::option::Option<_>>()?.map(oracle_job::lp_token_price_task::PoolAddress::OrcaPoolAddress); + } + GeneratedField::RaydiumPoolAddress => { + if pool_address__.is_some() { + return Err(serde::de::Error::duplicate_field("raydiumPoolAddress")); + } + pool_address__ = map_.next_value::<::std::option::Option<_>>()?.map(oracle_job::lp_token_price_task::PoolAddress::RaydiumPoolAddress); + } + } + } + Ok(oracle_job::LpTokenPriceTask { + price_feed_addresses: price_feed_addresses__.unwrap_or_default(), + price_feed_jobs: price_feed_jobs__.unwrap_or_default(), + use_fair_price: use_fair_price__, + pool_address: pool_address__, + }) + } + } + deserializer.deserialize_struct("oracle_job.OracleJob.LpTokenPriceTask", FIELDS, GeneratedVisitor) + } +} +impl serde::Serialize for oracle_job::LstHistoricalYieldTask { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + use serde::ser::SerializeStruct; + let mut len = 0; + if self.lst_mint.is_some() { + len += 1; + } + if self.operation.is_some() { + len += 1; + } + if self.epochs.is_some() { + len += 1; + } + let mut struct_ser = serializer.serialize_struct("oracle_job.OracleJob.LstHistoricalYieldTask", len)?; + if let Some(v) = self.lst_mint.as_ref() { + struct_ser.serialize_field("lstMint", v)?; + } + if let Some(v) = self.operation.as_ref() { + let v = oracle_job::lst_historical_yield_task::Operation::try_from(*v) + .map_err(|_| serde::ser::Error::custom(format!("Invalid variant {}", *v)))?; + struct_ser.serialize_field("operation", &v)?; + } + if let Some(v) = self.epochs.as_ref() { + struct_ser.serialize_field("epochs", v)?; + } + struct_ser.end() + } +} +impl<'de> serde::Deserialize<'de> for oracle_job::LstHistoricalYieldTask { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &[ + "lst_mint", + "lstMint", + "operation", + "epochs", + ]; + + #[allow(clippy::enum_variant_names)] + enum GeneratedField { + LstMint, + Operation, + Epochs, + } + 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 { + "lstMint" | "lst_mint" => Ok(GeneratedField::LstMint), + "operation" => Ok(GeneratedField::Operation), + "epochs" => Ok(GeneratedField::Epochs), + _ => Err(serde::de::Error::unknown_field(value, FIELDS)), + } + } + } + deserializer.deserialize_identifier(GeneratedVisitor) + } + } + struct GeneratedVisitor; + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = oracle_job::LstHistoricalYieldTask; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("struct oracle_job.OracleJob.LstHistoricalYieldTask") + } + + fn visit_map(self, mut map_: V) -> std::result::Result + where + V: serde::de::MapAccess<'de>, + { + let mut lst_mint__ = None; + let mut operation__ = None; + let mut epochs__ = None; + while let Some(k) = map_.next_key()? { + match k { + GeneratedField::LstMint => { + if lst_mint__.is_some() { + return Err(serde::de::Error::duplicate_field("lstMint")); + } + lst_mint__ = map_.next_value()?; + } + GeneratedField::Operation => { + if operation__.is_some() { + return Err(serde::de::Error::duplicate_field("operation")); + } + operation__ = map_.next_value::<::std::option::Option>()?.map(|x| x as i32); + } + GeneratedField::Epochs => { + if epochs__.is_some() { + return Err(serde::de::Error::duplicate_field("epochs")); + } + epochs__ = + map_.next_value::<::std::option::Option<::pbjson::private::NumberDeserialize<_>>>()?.map(|x| x.0) + ; + } + } + } + Ok(oracle_job::LstHistoricalYieldTask { + lst_mint: lst_mint__, + operation: operation__, + epochs: epochs__, + }) + } + } + deserializer.deserialize_struct("oracle_job.OracleJob.LstHistoricalYieldTask", FIELDS, GeneratedVisitor) + } +} +impl serde::Serialize for oracle_job::lst_historical_yield_task::Operation { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + let variant = match self { + Self::Median => "OPERATION_MEDIAN", + Self::Mean => "OPERATION_MEAN", + Self::Min => "OPERATION_MIN", + Self::Max => "OPERATION_MAX", + }; + serializer.serialize_str(variant) + } +} +impl<'de> serde::Deserialize<'de> for oracle_job::lst_historical_yield_task::Operation { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &[ + "OPERATION_MEDIAN", + "OPERATION_MEAN", + "OPERATION_MIN", + "OPERATION_MAX", + ]; + + struct GeneratedVisitor; + + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = oracle_job::lst_historical_yield_task::Operation; + + 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 { + "OPERATION_MEDIAN" => Ok(oracle_job::lst_historical_yield_task::Operation::Median), + "OPERATION_MEAN" => Ok(oracle_job::lst_historical_yield_task::Operation::Mean), + "OPERATION_MIN" => Ok(oracle_job::lst_historical_yield_task::Operation::Min), + "OPERATION_MAX" => Ok(oracle_job::lst_historical_yield_task::Operation::Max), + _ => Err(serde::de::Error::unknown_variant(value, FIELDS)), + } + } + } + deserializer.deserialize_any(GeneratedVisitor) + } +} +impl serde::Serialize for oracle_job::MangoPerpMarketTask { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + use serde::ser::SerializeStruct; + let mut len = 0; + if self.perp_market_address.is_some() { + len += 1; + } + let mut struct_ser = serializer.serialize_struct("oracle_job.OracleJob.MangoPerpMarketTask", len)?; + if let Some(v) = self.perp_market_address.as_ref() { + struct_ser.serialize_field("perpMarketAddress", v)?; + } + struct_ser.end() + } +} +impl<'de> serde::Deserialize<'de> for oracle_job::MangoPerpMarketTask { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &[ + "perp_market_address", + "perpMarketAddress", + ]; + + #[allow(clippy::enum_variant_names)] + enum GeneratedField { + PerpMarketAddress, + } + 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 { + "perpMarketAddress" | "perp_market_address" => Ok(GeneratedField::PerpMarketAddress), + _ => Err(serde::de::Error::unknown_field(value, FIELDS)), + } + } + } + deserializer.deserialize_identifier(GeneratedVisitor) + } + } + struct GeneratedVisitor; + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = oracle_job::MangoPerpMarketTask; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("struct oracle_job.OracleJob.MangoPerpMarketTask") + } + + fn visit_map(self, mut map_: V) -> std::result::Result + where + V: serde::de::MapAccess<'de>, + { + let mut perp_market_address__ = None; + while let Some(k) = map_.next_key()? { + match k { + GeneratedField::PerpMarketAddress => { + if perp_market_address__.is_some() { + return Err(serde::de::Error::duplicate_field("perpMarketAddress")); + } + perp_market_address__ = map_.next_value()?; + } + } + } + Ok(oracle_job::MangoPerpMarketTask { + perp_market_address: perp_market_address__, + }) + } + } + deserializer.deserialize_struct("oracle_job.OracleJob.MangoPerpMarketTask", FIELDS, GeneratedVisitor) + } +} +impl serde::Serialize for oracle_job::MapleFinanceTask { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + use serde::ser::SerializeStruct; + let mut len = 0; + if self.method.is_some() { + len += 1; + } + let mut struct_ser = serializer.serialize_struct("oracle_job.OracleJob.MapleFinanceTask", len)?; + if let Some(v) = self.method.as_ref() { + let v = oracle_job::maple_finance_task::Method::try_from(*v) + .map_err(|_| serde::ser::Error::custom(format!("Invalid variant {}", *v)))?; + struct_ser.serialize_field("method", &v)?; + } + struct_ser.end() + } +} +impl<'de> serde::Deserialize<'de> for oracle_job::MapleFinanceTask { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &[ + "method", + ]; + + #[allow(clippy::enum_variant_names)] + enum GeneratedField { + Method, + } + 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 { + "method" => Ok(GeneratedField::Method), + _ => Err(serde::de::Error::unknown_field(value, FIELDS)), + } + } + } + deserializer.deserialize_identifier(GeneratedVisitor) + } + } + struct GeneratedVisitor; + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = oracle_job::MapleFinanceTask; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("struct oracle_job.OracleJob.MapleFinanceTask") + } + + fn visit_map(self, mut map_: V) -> std::result::Result + where + V: serde::de::MapAccess<'de>, + { + let mut method__ = None; + while let Some(k) = map_.next_key()? { + match k { + GeneratedField::Method => { + if method__.is_some() { + return Err(serde::de::Error::duplicate_field("method")); + } + method__ = map_.next_value::<::std::option::Option>()?.map(|x| x as i32); + } + } + } + Ok(oracle_job::MapleFinanceTask { + method: method__, + }) + } + } + deserializer.deserialize_struct("oracle_job.OracleJob.MapleFinanceTask", FIELDS, GeneratedVisitor) + } +} +impl serde::Serialize for oracle_job::maple_finance_task::Method { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + let variant = match self { + Self::SyrupUsdcFairPrice => "METHOD_SYRUP_USDC_FAIR_PRICE", + }; + serializer.serialize_str(variant) + } +} +impl<'de> serde::Deserialize<'de> for oracle_job::maple_finance_task::Method { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &[ + "METHOD_SYRUP_USDC_FAIR_PRICE", + ]; + + struct GeneratedVisitor; + + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = oracle_job::maple_finance_task::Method; + + 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 { + "METHOD_SYRUP_USDC_FAIR_PRICE" => Ok(oracle_job::maple_finance_task::Method::SyrupUsdcFairPrice), + _ => Err(serde::de::Error::unknown_variant(value, FIELDS)), + } + } + } + deserializer.deserialize_any(GeneratedVisitor) + } +} +impl serde::Serialize for oracle_job::MarinadeStateTask { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + use serde::ser::SerializeStruct; + let len = 0; + let struct_ser = serializer.serialize_struct("oracle_job.OracleJob.MarinadeStateTask", len)?; + struct_ser.end() + } +} +impl<'de> serde::Deserialize<'de> for oracle_job::MarinadeStateTask { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &[ + ]; + + #[allow(clippy::enum_variant_names)] + enum GeneratedField { + } + 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, + { + Err(serde::de::Error::unknown_field(value, FIELDS)) + } + } + deserializer.deserialize_identifier(GeneratedVisitor) + } + } + struct GeneratedVisitor; + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = oracle_job::MarinadeStateTask; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("struct oracle_job.OracleJob.MarinadeStateTask") + } + + fn visit_map(self, mut map_: V) -> std::result::Result + where + V: serde::de::MapAccess<'de>, + { + while map_.next_key::()?.is_some() { + let _ = map_.next_value::()?; + } + Ok(oracle_job::MarinadeStateTask { + }) + } + } + deserializer.deserialize_struct("oracle_job.OracleJob.MarinadeStateTask", FIELDS, GeneratedVisitor) + } +} +impl serde::Serialize for oracle_job::MaxTask { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + use serde::ser::SerializeStruct; + let mut len = 0; + if !self.tasks.is_empty() { + len += 1; + } + if !self.jobs.is_empty() { + len += 1; + } + let mut struct_ser = serializer.serialize_struct("oracle_job.OracleJob.MaxTask", len)?; + if !self.tasks.is_empty() { + struct_ser.serialize_field("tasks", &self.tasks)?; + } + if !self.jobs.is_empty() { + struct_ser.serialize_field("jobs", &self.jobs)?; + } + struct_ser.end() + } +} +impl<'de> serde::Deserialize<'de> for oracle_job::MaxTask { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &[ + "tasks", + "jobs", + ]; + + #[allow(clippy::enum_variant_names)] + enum GeneratedField { + Tasks, + Jobs, + } + 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 { + "tasks" => Ok(GeneratedField::Tasks), + "jobs" => Ok(GeneratedField::Jobs), + _ => Err(serde::de::Error::unknown_field(value, FIELDS)), + } + } + } + deserializer.deserialize_identifier(GeneratedVisitor) + } + } + struct GeneratedVisitor; + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = oracle_job::MaxTask; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("struct oracle_job.OracleJob.MaxTask") + } + + fn visit_map(self, mut map_: V) -> std::result::Result + where + V: serde::de::MapAccess<'de>, + { + let mut tasks__ = None; + let mut jobs__ = None; + while let Some(k) = map_.next_key()? { + match k { + GeneratedField::Tasks => { + if tasks__.is_some() { + return Err(serde::de::Error::duplicate_field("tasks")); + } + tasks__ = Some(map_.next_value()?); + } + GeneratedField::Jobs => { + if jobs__.is_some() { + return Err(serde::de::Error::duplicate_field("jobs")); + } + jobs__ = Some(map_.next_value()?); + } + } + } + Ok(oracle_job::MaxTask { + tasks: tasks__.unwrap_or_default(), + jobs: jobs__.unwrap_or_default(), + }) + } + } + deserializer.deserialize_struct("oracle_job.OracleJob.MaxTask", FIELDS, GeneratedVisitor) + } +} +impl serde::Serialize for oracle_job::MeanTask { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + use serde::ser::SerializeStruct; + let mut len = 0; + if !self.tasks.is_empty() { + len += 1; + } + if !self.jobs.is_empty() { + len += 1; + } + let mut struct_ser = serializer.serialize_struct("oracle_job.OracleJob.MeanTask", len)?; + if !self.tasks.is_empty() { + struct_ser.serialize_field("tasks", &self.tasks)?; + } + if !self.jobs.is_empty() { + struct_ser.serialize_field("jobs", &self.jobs)?; + } + struct_ser.end() + } +} +impl<'de> serde::Deserialize<'de> for oracle_job::MeanTask { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &[ + "tasks", + "jobs", + ]; + + #[allow(clippy::enum_variant_names)] + enum GeneratedField { + Tasks, + Jobs, + } + 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 { + "tasks" => Ok(GeneratedField::Tasks), + "jobs" => Ok(GeneratedField::Jobs), + _ => Err(serde::de::Error::unknown_field(value, FIELDS)), + } + } + } + deserializer.deserialize_identifier(GeneratedVisitor) + } + } + struct GeneratedVisitor; + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = oracle_job::MeanTask; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("struct oracle_job.OracleJob.MeanTask") + } + + fn visit_map(self, mut map_: V) -> std::result::Result + where + V: serde::de::MapAccess<'de>, + { + let mut tasks__ = None; + let mut jobs__ = None; + while let Some(k) = map_.next_key()? { + match k { + GeneratedField::Tasks => { + if tasks__.is_some() { + return Err(serde::de::Error::duplicate_field("tasks")); + } + tasks__ = Some(map_.next_value()?); + } + GeneratedField::Jobs => { + if jobs__.is_some() { + return Err(serde::de::Error::duplicate_field("jobs")); + } + jobs__ = Some(map_.next_value()?); + } + } + } + Ok(oracle_job::MeanTask { + tasks: tasks__.unwrap_or_default(), + jobs: jobs__.unwrap_or_default(), + }) + } + } + deserializer.deserialize_struct("oracle_job.OracleJob.MeanTask", FIELDS, GeneratedVisitor) + } +} +impl serde::Serialize for oracle_job::MedianTask { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + use serde::ser::SerializeStruct; + let mut len = 0; + if !self.tasks.is_empty() { + len += 1; + } + if !self.jobs.is_empty() { + len += 1; + } + if self.min_successful_required.is_some() { + len += 1; + } + if self.max_range_percent.is_some() { + len += 1; + } + let mut struct_ser = serializer.serialize_struct("oracle_job.OracleJob.MedianTask", len)?; + if !self.tasks.is_empty() { + struct_ser.serialize_field("tasks", &self.tasks)?; + } + if !self.jobs.is_empty() { + struct_ser.serialize_field("jobs", &self.jobs)?; + } + if let Some(v) = self.min_successful_required.as_ref() { + struct_ser.serialize_field("minSuccessfulRequired", v)?; + } + if let Some(v) = self.max_range_percent.as_ref() { + struct_ser.serialize_field("maxRangePercent", v)?; + } + struct_ser.end() + } +} +impl<'de> serde::Deserialize<'de> for oracle_job::MedianTask { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &[ + "tasks", + "jobs", + "min_successful_required", + "minSuccessfulRequired", + "max_range_percent", + "maxRangePercent", + ]; + + #[allow(clippy::enum_variant_names)] + enum GeneratedField { + Tasks, + Jobs, + MinSuccessfulRequired, + MaxRangePercent, + } + 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 { + "tasks" => Ok(GeneratedField::Tasks), + "jobs" => Ok(GeneratedField::Jobs), + "minSuccessfulRequired" | "min_successful_required" => Ok(GeneratedField::MinSuccessfulRequired), + "maxRangePercent" | "max_range_percent" => Ok(GeneratedField::MaxRangePercent), + _ => Err(serde::de::Error::unknown_field(value, FIELDS)), + } + } + } + deserializer.deserialize_identifier(GeneratedVisitor) + } + } + struct GeneratedVisitor; + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = oracle_job::MedianTask; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("struct oracle_job.OracleJob.MedianTask") + } + + fn visit_map(self, mut map_: V) -> std::result::Result + where + V: serde::de::MapAccess<'de>, + { + let mut tasks__ = None; + let mut jobs__ = None; + let mut min_successful_required__ = None; + let mut max_range_percent__ = None; + while let Some(k) = map_.next_key()? { + match k { + GeneratedField::Tasks => { + if tasks__.is_some() { + return Err(serde::de::Error::duplicate_field("tasks")); + } + tasks__ = Some(map_.next_value()?); + } + GeneratedField::Jobs => { + if jobs__.is_some() { + return Err(serde::de::Error::duplicate_field("jobs")); + } + jobs__ = Some(map_.next_value()?); + } + GeneratedField::MinSuccessfulRequired => { + if min_successful_required__.is_some() { + return Err(serde::de::Error::duplicate_field("minSuccessfulRequired")); + } + min_successful_required__ = + map_.next_value::<::std::option::Option<::pbjson::private::NumberDeserialize<_>>>()?.map(|x| x.0) + ; + } + GeneratedField::MaxRangePercent => { + if max_range_percent__.is_some() { + return Err(serde::de::Error::duplicate_field("maxRangePercent")); + } + max_range_percent__ = map_.next_value()?; + } + } + } + Ok(oracle_job::MedianTask { + tasks: tasks__.unwrap_or_default(), + jobs: jobs__.unwrap_or_default(), + min_successful_required: min_successful_required__, + max_range_percent: max_range_percent__, + }) + } + } + deserializer.deserialize_struct("oracle_job.OracleJob.MedianTask", FIELDS, GeneratedVisitor) + } +} +impl serde::Serialize for oracle_job::MeteoraSwapTask { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + use serde::ser::SerializeStruct; + let mut len = 0; + if self.pool.is_some() { + len += 1; + } + if self.r#type.is_some() { + len += 1; + } + let mut struct_ser = serializer.serialize_struct("oracle_job.OracleJob.MeteoraSwapTask", len)?; + if let Some(v) = self.pool.as_ref() { + struct_ser.serialize_field("pool", v)?; + } + if let Some(v) = self.r#type.as_ref() { + let v = oracle_job::meteora_swap_task::Type::try_from(*v) + .map_err(|_| serde::ser::Error::custom(format!("Invalid variant {}", *v)))?; + struct_ser.serialize_field("type", &v)?; + } + struct_ser.end() + } +} +impl<'de> serde::Deserialize<'de> for oracle_job::MeteoraSwapTask { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &[ + "pool", + "type", + ]; + + #[allow(clippy::enum_variant_names)] + enum GeneratedField { + Pool, + Type, + } + 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 { + "pool" => Ok(GeneratedField::Pool), + "type" => Ok(GeneratedField::Type), + _ => Err(serde::de::Error::unknown_field(value, FIELDS)), + } + } + } + deserializer.deserialize_identifier(GeneratedVisitor) + } + } + struct GeneratedVisitor; + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = oracle_job::MeteoraSwapTask; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("struct oracle_job.OracleJob.MeteoraSwapTask") + } + + fn visit_map(self, mut map_: V) -> std::result::Result + where + V: serde::de::MapAccess<'de>, + { + let mut pool__ = None; + let mut r#type__ = None; + while let Some(k) = map_.next_key()? { + match k { + GeneratedField::Pool => { + if pool__.is_some() { + return Err(serde::de::Error::duplicate_field("pool")); + } + pool__ = map_.next_value()?; + } + GeneratedField::Type => { + if r#type__.is_some() { + return Err(serde::de::Error::duplicate_field("type")); + } + r#type__ = map_.next_value::<::std::option::Option>()?.map(|x| x as i32); + } + } + } + Ok(oracle_job::MeteoraSwapTask { + pool: pool__, + r#type: r#type__, + }) + } + } + deserializer.deserialize_struct("oracle_job.OracleJob.MeteoraSwapTask", FIELDS, GeneratedVisitor) + } +} +impl serde::Serialize for oracle_job::meteora_swap_task::Type { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + let variant = match self { + Self::Dlmm => "TYPE_DLMM", + Self::Standard => "TYPE_STANDARD", + }; + serializer.serialize_str(variant) + } +} +impl<'de> serde::Deserialize<'de> for oracle_job::meteora_swap_task::Type { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &[ + "TYPE_DLMM", + "TYPE_STANDARD", + ]; + + struct GeneratedVisitor; + + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = oracle_job::meteora_swap_task::Type; + + 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 { + "TYPE_DLMM" => Ok(oracle_job::meteora_swap_task::Type::Dlmm), + "TYPE_STANDARD" => Ok(oracle_job::meteora_swap_task::Type::Standard), + _ => Err(serde::de::Error::unknown_variant(value, FIELDS)), + } + } + } + deserializer.deserialize_any(GeneratedVisitor) + } +} +impl serde::Serialize for oracle_job::MinTask { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + use serde::ser::SerializeStruct; + let mut len = 0; + if !self.tasks.is_empty() { + len += 1; + } + if !self.jobs.is_empty() { + len += 1; + } + let mut struct_ser = serializer.serialize_struct("oracle_job.OracleJob.MinTask", len)?; + if !self.tasks.is_empty() { + struct_ser.serialize_field("tasks", &self.tasks)?; + } + if !self.jobs.is_empty() { + struct_ser.serialize_field("jobs", &self.jobs)?; + } + struct_ser.end() + } +} +impl<'de> serde::Deserialize<'de> for oracle_job::MinTask { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &[ + "tasks", + "jobs", + ]; + + #[allow(clippy::enum_variant_names)] + enum GeneratedField { + Tasks, + Jobs, + } + 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 { + "tasks" => Ok(GeneratedField::Tasks), + "jobs" => Ok(GeneratedField::Jobs), + _ => Err(serde::de::Error::unknown_field(value, FIELDS)), + } + } + } + deserializer.deserialize_identifier(GeneratedVisitor) + } + } + struct GeneratedVisitor; + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = oracle_job::MinTask; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("struct oracle_job.OracleJob.MinTask") + } + + fn visit_map(self, mut map_: V) -> std::result::Result + where + V: serde::de::MapAccess<'de>, + { + let mut tasks__ = None; + let mut jobs__ = None; + while let Some(k) = map_.next_key()? { + match k { + GeneratedField::Tasks => { + if tasks__.is_some() { + return Err(serde::de::Error::duplicate_field("tasks")); + } + tasks__ = Some(map_.next_value()?); + } + GeneratedField::Jobs => { + if jobs__.is_some() { + return Err(serde::de::Error::duplicate_field("jobs")); + } + jobs__ = Some(map_.next_value()?); + } + } + } + Ok(oracle_job::MinTask { + tasks: tasks__.unwrap_or_default(), + jobs: jobs__.unwrap_or_default(), + }) + } + } + deserializer.deserialize_struct("oracle_job.OracleJob.MinTask", FIELDS, GeneratedVisitor) + } +} +impl serde::Serialize for oracle_job::MultiplyTask { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + use serde::ser::SerializeStruct; + let mut len = 0; + if self.multiple.is_some() { + len += 1; + } + let mut struct_ser = serializer.serialize_struct("oracle_job.OracleJob.MultiplyTask", len)?; + if let Some(v) = self.multiple.as_ref() { + match v { + oracle_job::multiply_task::Multiple::Scalar(v) => { + struct_ser.serialize_field("scalar", v)?; + } + oracle_job::multiply_task::Multiple::AggregatorPubkey(v) => { + struct_ser.serialize_field("aggregatorPubkey", v)?; + } + oracle_job::multiply_task::Multiple::Job(v) => { + struct_ser.serialize_field("job", v)?; + } + oracle_job::multiply_task::Multiple::Big(v) => { + struct_ser.serialize_field("big", v)?; + } + } + } + struct_ser.end() + } +} +impl<'de> serde::Deserialize<'de> for oracle_job::MultiplyTask { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &[ + "scalar", + "aggregator_pubkey", + "aggregatorPubkey", + "job", + "big", + ]; + + #[allow(clippy::enum_variant_names)] + enum GeneratedField { + Scalar, + AggregatorPubkey, + Job, + Big, + } + 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 { + "scalar" => Ok(GeneratedField::Scalar), + "aggregatorPubkey" | "aggregator_pubkey" => Ok(GeneratedField::AggregatorPubkey), + "job" => Ok(GeneratedField::Job), + "big" => Ok(GeneratedField::Big), + _ => Err(serde::de::Error::unknown_field(value, FIELDS)), + } + } + } + deserializer.deserialize_identifier(GeneratedVisitor) + } + } + struct GeneratedVisitor; + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = oracle_job::MultiplyTask; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("struct oracle_job.OracleJob.MultiplyTask") + } + + fn visit_map(self, mut map_: V) -> std::result::Result + where + V: serde::de::MapAccess<'de>, + { + let mut multiple__ = None; + while let Some(k) = map_.next_key()? { + match k { + GeneratedField::Scalar => { + if multiple__.is_some() { + return Err(serde::de::Error::duplicate_field("scalar")); + } + multiple__ = map_.next_value::<::std::option::Option<::pbjson::private::NumberDeserialize<_>>>()?.map(|x| oracle_job::multiply_task::Multiple::Scalar(x.0)); + } + GeneratedField::AggregatorPubkey => { + if multiple__.is_some() { + return Err(serde::de::Error::duplicate_field("aggregatorPubkey")); + } + multiple__ = map_.next_value::<::std::option::Option<_>>()?.map(oracle_job::multiply_task::Multiple::AggregatorPubkey); + } + GeneratedField::Job => { + if multiple__.is_some() { + return Err(serde::de::Error::duplicate_field("job")); + } + multiple__ = map_.next_value::<::std::option::Option<_>>()?.map(oracle_job::multiply_task::Multiple::Job) +; + } + GeneratedField::Big => { + if multiple__.is_some() { + return Err(serde::de::Error::duplicate_field("big")); + } + multiple__ = map_.next_value::<::std::option::Option<_>>()?.map(oracle_job::multiply_task::Multiple::Big); + } + } + } + Ok(oracle_job::MultiplyTask { + multiple: multiple__, + }) + } + } + deserializer.deserialize_struct("oracle_job.OracleJob.MultiplyTask", FIELDS, GeneratedVisitor) + } +} +impl serde::Serialize for oracle_job::OndoUsdyTask { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + use serde::ser::SerializeStruct; + let mut len = 0; + if self.strategy.is_some() { + len += 1; + } + let mut struct_ser = serializer.serialize_struct("oracle_job.OracleJob.OndoUsdyTask", len)?; + if let Some(v) = self.strategy.as_ref() { + let v = oracle_job::ondo_usdy_task::Strategy::try_from(*v) + .map_err(|_| serde::ser::Error::custom(format!("Invalid variant {}", *v)))?; + struct_ser.serialize_field("strategy", &v)?; + } + struct_ser.end() + } +} +impl<'de> serde::Deserialize<'de> for oracle_job::OndoUsdyTask { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &[ + "strategy", + ]; + + #[allow(clippy::enum_variant_names)] + enum GeneratedField { + Strategy, + } + 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 { + "strategy" => Ok(GeneratedField::Strategy), + _ => Err(serde::de::Error::unknown_field(value, FIELDS)), + } + } + } + deserializer.deserialize_identifier(GeneratedVisitor) + } + } + struct GeneratedVisitor; + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = oracle_job::OndoUsdyTask; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("struct oracle_job.OracleJob.OndoUsdyTask") + } + + fn visit_map(self, mut map_: V) -> std::result::Result + where + V: serde::de::MapAccess<'de>, + { + let mut strategy__ = None; + while let Some(k) = map_.next_key()? { + match k { + GeneratedField::Strategy => { + if strategy__.is_some() { + return Err(serde::de::Error::duplicate_field("strategy")); + } + strategy__ = map_.next_value::<::std::option::Option>()?.map(|x| x as i32); + } + } + } + Ok(oracle_job::OndoUsdyTask { + strategy: strategy__, + }) + } + } + deserializer.deserialize_struct("oracle_job.OracleJob.OndoUsdyTask", FIELDS, GeneratedVisitor) + } +} +impl serde::Serialize for oracle_job::ondo_usdy_task::Strategy { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + let variant = match self { + Self::FairValue => "STRATEGY_FAIR_VALUE", + Self::Market => "STRATEGY_MARKET", + }; + serializer.serialize_str(variant) + } +} +impl<'de> serde::Deserialize<'de> for oracle_job::ondo_usdy_task::Strategy { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &[ + "STRATEGY_FAIR_VALUE", + "STRATEGY_MARKET", + ]; + + struct GeneratedVisitor; + + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = oracle_job::ondo_usdy_task::Strategy; + + 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 { + "STRATEGY_FAIR_VALUE" => Ok(oracle_job::ondo_usdy_task::Strategy::FairValue), + "STRATEGY_MARKET" => Ok(oracle_job::ondo_usdy_task::Strategy::Market), + _ => Err(serde::de::Error::unknown_variant(value, FIELDS)), + } + } + } + deserializer.deserialize_any(GeneratedVisitor) + } +} +impl serde::Serialize for oracle_job::OracleTask { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + use serde::ser::SerializeStruct; + let mut len = 0; + if self.pyth_allowed_confidence_interval.is_some() { + len += 1; + } + if self.chainlink_configs.is_some() { + len += 1; + } + if self.pyth_configs.is_some() { + len += 1; + } + if self.switchboard_configs.is_some() { + len += 1; + } + if self.edge_configs.is_some() { + len += 1; + } + if self.redstone_configs.is_some() { + len += 1; + } + if self.aggregator_address.is_some() { + len += 1; + } + let mut struct_ser = serializer.serialize_struct("oracle_job.OracleJob.OracleTask", len)?; + if let Some(v) = self.pyth_allowed_confidence_interval.as_ref() { + struct_ser.serialize_field("pythAllowedConfidenceInterval", v)?; + } + if let Some(v) = self.chainlink_configs.as_ref() { + struct_ser.serialize_field("chainlinkConfigs", v)?; + } + if let Some(v) = self.pyth_configs.as_ref() { + struct_ser.serialize_field("pythConfigs", v)?; + } + if let Some(v) = self.switchboard_configs.as_ref() { + struct_ser.serialize_field("switchboardConfigs", v)?; + } + if let Some(v) = self.edge_configs.as_ref() { + struct_ser.serialize_field("edgeConfigs", v)?; + } + if let Some(v) = self.redstone_configs.as_ref() { + struct_ser.serialize_field("redstoneConfigs", v)?; + } + if let Some(v) = self.aggregator_address.as_ref() { + match v { + oracle_job::oracle_task::AggregatorAddress::SwitchboardAddress(v) => { + struct_ser.serialize_field("switchboardAddress", v)?; + } + oracle_job::oracle_task::AggregatorAddress::PythAddress(v) => { + struct_ser.serialize_field("pythAddress", v)?; + } + oracle_job::oracle_task::AggregatorAddress::ChainlinkAddress(v) => { + struct_ser.serialize_field("chainlinkAddress", v)?; + } + oracle_job::oracle_task::AggregatorAddress::EdgeId(v) => { + struct_ser.serialize_field("edgeId", v)?; + } + oracle_job::oracle_task::AggregatorAddress::RedstoneId(v) => { + struct_ser.serialize_field("redstoneId", v)?; + } + } + } + struct_ser.end() + } +} +impl<'de> serde::Deserialize<'de> for oracle_job::OracleTask { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &[ + "pyth_allowed_confidence_interval", + "pythAllowedConfidenceInterval", + "chainlink_configs", + "chainlinkConfigs", + "pyth_configs", + "pythConfigs", + "switchboard_configs", + "switchboardConfigs", + "edge_configs", + "edgeConfigs", + "redstone_configs", + "redstoneConfigs", + "switchboard_address", + "switchboardAddress", + "pyth_address", + "pythAddress", + "chainlink_address", + "chainlinkAddress", + "edge_id", + "edgeId", + "redstone_id", + "redstoneId", + ]; + + #[allow(clippy::enum_variant_names)] + enum GeneratedField { + PythAllowedConfidenceInterval, + ChainlinkConfigs, + PythConfigs, + SwitchboardConfigs, + EdgeConfigs, + RedstoneConfigs, + SwitchboardAddress, + PythAddress, + ChainlinkAddress, + EdgeId, + RedstoneId, + } + 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 { + "pythAllowedConfidenceInterval" | "pyth_allowed_confidence_interval" => Ok(GeneratedField::PythAllowedConfidenceInterval), + "chainlinkConfigs" | "chainlink_configs" => Ok(GeneratedField::ChainlinkConfigs), + "pythConfigs" | "pyth_configs" => Ok(GeneratedField::PythConfigs), + "switchboardConfigs" | "switchboard_configs" => Ok(GeneratedField::SwitchboardConfigs), + "edgeConfigs" | "edge_configs" => Ok(GeneratedField::EdgeConfigs), + "redstoneConfigs" | "redstone_configs" => Ok(GeneratedField::RedstoneConfigs), + "switchboardAddress" | "switchboard_address" => Ok(GeneratedField::SwitchboardAddress), + "pythAddress" | "pyth_address" => Ok(GeneratedField::PythAddress), + "chainlinkAddress" | "chainlink_address" => Ok(GeneratedField::ChainlinkAddress), + "edgeId" | "edge_id" => Ok(GeneratedField::EdgeId), + "redstoneId" | "redstone_id" => Ok(GeneratedField::RedstoneId), + _ => Err(serde::de::Error::unknown_field(value, FIELDS)), + } + } + } + deserializer.deserialize_identifier(GeneratedVisitor) + } + } + struct GeneratedVisitor; + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = oracle_job::OracleTask; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("struct oracle_job.OracleJob.OracleTask") + } + + fn visit_map(self, mut map_: V) -> std::result::Result + where + V: serde::de::MapAccess<'de>, + { + let mut pyth_allowed_confidence_interval__ = None; + let mut chainlink_configs__ = None; + let mut pyth_configs__ = None; + let mut switchboard_configs__ = None; + let mut edge_configs__ = None; + let mut redstone_configs__ = None; + let mut aggregator_address__ = None; + while let Some(k) = map_.next_key()? { + match k { + GeneratedField::PythAllowedConfidenceInterval => { + if pyth_allowed_confidence_interval__.is_some() { + return Err(serde::de::Error::duplicate_field("pythAllowedConfidenceInterval")); + } + pyth_allowed_confidence_interval__ = + map_.next_value::<::std::option::Option<::pbjson::private::NumberDeserialize<_>>>()?.map(|x| x.0) + ; + } + GeneratedField::ChainlinkConfigs => { + if chainlink_configs__.is_some() { + return Err(serde::de::Error::duplicate_field("chainlinkConfigs")); + } + chainlink_configs__ = map_.next_value()?; + } + GeneratedField::PythConfigs => { + if pyth_configs__.is_some() { + return Err(serde::de::Error::duplicate_field("pythConfigs")); + } + pyth_configs__ = map_.next_value()?; + } + GeneratedField::SwitchboardConfigs => { + if switchboard_configs__.is_some() { + return Err(serde::de::Error::duplicate_field("switchboardConfigs")); + } + switchboard_configs__ = map_.next_value()?; + } + GeneratedField::EdgeConfigs => { + if edge_configs__.is_some() { + return Err(serde::de::Error::duplicate_field("edgeConfigs")); + } + edge_configs__ = map_.next_value()?; + } + GeneratedField::RedstoneConfigs => { + if redstone_configs__.is_some() { + return Err(serde::de::Error::duplicate_field("redstoneConfigs")); + } + redstone_configs__ = map_.next_value()?; + } + GeneratedField::SwitchboardAddress => { + if aggregator_address__.is_some() { + return Err(serde::de::Error::duplicate_field("switchboardAddress")); + } + aggregator_address__ = map_.next_value::<::std::option::Option<_>>()?.map(oracle_job::oracle_task::AggregatorAddress::SwitchboardAddress); + } + GeneratedField::PythAddress => { + if aggregator_address__.is_some() { + return Err(serde::de::Error::duplicate_field("pythAddress")); + } + aggregator_address__ = map_.next_value::<::std::option::Option<_>>()?.map(oracle_job::oracle_task::AggregatorAddress::PythAddress); + } + GeneratedField::ChainlinkAddress => { + if aggregator_address__.is_some() { + return Err(serde::de::Error::duplicate_field("chainlinkAddress")); + } + aggregator_address__ = map_.next_value::<::std::option::Option<_>>()?.map(oracle_job::oracle_task::AggregatorAddress::ChainlinkAddress); + } + GeneratedField::EdgeId => { + if aggregator_address__.is_some() { + return Err(serde::de::Error::duplicate_field("edgeId")); + } + aggregator_address__ = map_.next_value::<::std::option::Option<_>>()?.map(oracle_job::oracle_task::AggregatorAddress::EdgeId); + } + GeneratedField::RedstoneId => { + if aggregator_address__.is_some() { + return Err(serde::de::Error::duplicate_field("redstoneId")); + } + aggregator_address__ = map_.next_value::<::std::option::Option<_>>()?.map(oracle_job::oracle_task::AggregatorAddress::RedstoneId); + } + } + } + Ok(oracle_job::OracleTask { + pyth_allowed_confidence_interval: pyth_allowed_confidence_interval__, + chainlink_configs: chainlink_configs__, + pyth_configs: pyth_configs__, + switchboard_configs: switchboard_configs__, + edge_configs: edge_configs__, + redstone_configs: redstone_configs__, + aggregator_address: aggregator_address__, + }) + } + } + deserializer.deserialize_struct("oracle_job.OracleJob.OracleTask", FIELDS, GeneratedVisitor) + } +} +impl serde::Serialize for oracle_job::oracle_task::ChainlinkConfigs { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + use serde::ser::SerializeStruct; + let mut len = 0; + if self.provider.is_some() { + len += 1; + } + let mut struct_ser = serializer.serialize_struct("oracle_job.OracleJob.OracleTask.ChainlinkConfigs", len)?; + if let Some(v) = self.provider.as_ref() { + struct_ser.serialize_field("provider", v)?; + } + struct_ser.end() + } +} +impl<'de> serde::Deserialize<'de> for oracle_job::oracle_task::ChainlinkConfigs { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &[ + "provider", + ]; + + #[allow(clippy::enum_variant_names)] + enum GeneratedField { + Provider, + } + 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 { + "provider" => Ok(GeneratedField::Provider), + _ => Err(serde::de::Error::unknown_field(value, FIELDS)), + } + } + } + deserializer.deserialize_identifier(GeneratedVisitor) + } + } + struct GeneratedVisitor; + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = oracle_job::oracle_task::ChainlinkConfigs; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("struct oracle_job.OracleJob.OracleTask.ChainlinkConfigs") + } + + fn visit_map(self, mut map_: V) -> std::result::Result + where + V: serde::de::MapAccess<'de>, + { + let mut provider__ = None; + while let Some(k) = map_.next_key()? { + match k { + GeneratedField::Provider => { + if provider__.is_some() { + return Err(serde::de::Error::duplicate_field("provider")); + } + provider__ = map_.next_value()?; + } + } + } + Ok(oracle_job::oracle_task::ChainlinkConfigs { + provider: provider__, + }) + } + } + deserializer.deserialize_struct("oracle_job.OracleJob.OracleTask.ChainlinkConfigs", FIELDS, GeneratedVisitor) + } +} +impl serde::Serialize for oracle_job::oracle_task::EdgeConfigs { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + use serde::ser::SerializeStruct; + let len = 0; + let struct_ser = serializer.serialize_struct("oracle_job.OracleJob.OracleTask.EdgeConfigs", len)?; + struct_ser.end() + } +} +impl<'de> serde::Deserialize<'de> for oracle_job::oracle_task::EdgeConfigs { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &[ + ]; + + #[allow(clippy::enum_variant_names)] + enum GeneratedField { + } + 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, + { + Err(serde::de::Error::unknown_field(value, FIELDS)) + } + } + deserializer.deserialize_identifier(GeneratedVisitor) + } + } + struct GeneratedVisitor; + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = oracle_job::oracle_task::EdgeConfigs; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("struct oracle_job.OracleJob.OracleTask.EdgeConfigs") + } + + fn visit_map(self, mut map_: V) -> std::result::Result + where + V: serde::de::MapAccess<'de>, + { + while map_.next_key::()?.is_some() { + let _ = map_.next_value::()?; + } + Ok(oracle_job::oracle_task::EdgeConfigs { + }) + } + } + deserializer.deserialize_struct("oracle_job.OracleJob.OracleTask.EdgeConfigs", FIELDS, GeneratedVisitor) + } +} +impl serde::Serialize for oracle_job::oracle_task::PythConfigs { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + use serde::ser::SerializeStruct; + let mut len = 0; + if self.hermes_url.is_some() { + len += 1; + } + if self.pyth_allowed_confidence_interval.is_some() { + len += 1; + } + if self.max_stale_seconds.is_some() { + len += 1; + } + let mut struct_ser = serializer.serialize_struct("oracle_job.OracleJob.OracleTask.PythConfigs", len)?; + if let Some(v) = self.hermes_url.as_ref() { + struct_ser.serialize_field("hermesUrl", v)?; + } + if let Some(v) = self.pyth_allowed_confidence_interval.as_ref() { + struct_ser.serialize_field("pythAllowedConfidenceInterval", v)?; + } + if let Some(v) = self.max_stale_seconds.as_ref() { + struct_ser.serialize_field("maxStaleSeconds", v)?; + } + struct_ser.end() + } +} +impl<'de> serde::Deserialize<'de> for oracle_job::oracle_task::PythConfigs { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &[ + "hermes_url", + "hermesUrl", + "pyth_allowed_confidence_interval", + "pythAllowedConfidenceInterval", + "max_stale_seconds", + "maxStaleSeconds", + ]; + + #[allow(clippy::enum_variant_names)] + enum GeneratedField { + HermesUrl, + PythAllowedConfidenceInterval, + MaxStaleSeconds, + } + 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 { + "hermesUrl" | "hermes_url" => Ok(GeneratedField::HermesUrl), + "pythAllowedConfidenceInterval" | "pyth_allowed_confidence_interval" => Ok(GeneratedField::PythAllowedConfidenceInterval), + "maxStaleSeconds" | "max_stale_seconds" => Ok(GeneratedField::MaxStaleSeconds), + _ => Err(serde::de::Error::unknown_field(value, FIELDS)), + } + } + } + deserializer.deserialize_identifier(GeneratedVisitor) + } + } + struct GeneratedVisitor; + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = oracle_job::oracle_task::PythConfigs; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("struct oracle_job.OracleJob.OracleTask.PythConfigs") + } + + fn visit_map(self, mut map_: V) -> std::result::Result + where + V: serde::de::MapAccess<'de>, + { + let mut hermes_url__ = None; + let mut pyth_allowed_confidence_interval__ = None; + let mut max_stale_seconds__ = None; + while let Some(k) = map_.next_key()? { + match k { + GeneratedField::HermesUrl => { + if hermes_url__.is_some() { + return Err(serde::de::Error::duplicate_field("hermesUrl")); + } + hermes_url__ = map_.next_value()?; + } + GeneratedField::PythAllowedConfidenceInterval => { + if pyth_allowed_confidence_interval__.is_some() { + return Err(serde::de::Error::duplicate_field("pythAllowedConfidenceInterval")); + } + pyth_allowed_confidence_interval__ = + map_.next_value::<::std::option::Option<::pbjson::private::NumberDeserialize<_>>>()?.map(|x| x.0) + ; + } + GeneratedField::MaxStaleSeconds => { + if max_stale_seconds__.is_some() { + return Err(serde::de::Error::duplicate_field("maxStaleSeconds")); + } + max_stale_seconds__ = + map_.next_value::<::std::option::Option<::pbjson::private::NumberDeserialize<_>>>()?.map(|x| x.0) + ; + } + } + } + Ok(oracle_job::oracle_task::PythConfigs { + hermes_url: hermes_url__, + pyth_allowed_confidence_interval: pyth_allowed_confidence_interval__, + max_stale_seconds: max_stale_seconds__, + }) + } + } + deserializer.deserialize_struct("oracle_job.OracleJob.OracleTask.PythConfigs", FIELDS, GeneratedVisitor) + } +} +impl serde::Serialize for oracle_job::oracle_task::RedstoneConfigs { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + use serde::ser::SerializeStruct; + let len = 0; + let struct_ser = serializer.serialize_struct("oracle_job.OracleJob.OracleTask.RedstoneConfigs", len)?; + struct_ser.end() + } +} +impl<'de> serde::Deserialize<'de> for oracle_job::oracle_task::RedstoneConfigs { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &[ + ]; + + #[allow(clippy::enum_variant_names)] + enum GeneratedField { + } + 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, + { + Err(serde::de::Error::unknown_field(value, FIELDS)) + } + } + deserializer.deserialize_identifier(GeneratedVisitor) + } + } + struct GeneratedVisitor; + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = oracle_job::oracle_task::RedstoneConfigs; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("struct oracle_job.OracleJob.OracleTask.RedstoneConfigs") + } + + fn visit_map(self, mut map_: V) -> std::result::Result + where + V: serde::de::MapAccess<'de>, + { + while map_.next_key::()?.is_some() { + let _ = map_.next_value::()?; + } + Ok(oracle_job::oracle_task::RedstoneConfigs { + }) + } + } + deserializer.deserialize_struct("oracle_job.OracleJob.OracleTask.RedstoneConfigs", FIELDS, GeneratedVisitor) + } +} +impl serde::Serialize for oracle_job::oracle_task::SwitchboardConfigs { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + use serde::ser::SerializeStruct; + let mut len = 0; + if self.version.is_some() { + len += 1; + } + if !self.jobs.is_empty() { + len += 1; + } + let mut struct_ser = serializer.serialize_struct("oracle_job.OracleJob.OracleTask.SwitchboardConfigs", len)?; + if let Some(v) = self.version.as_ref() { + struct_ser.serialize_field("version", v)?; + } + if !self.jobs.is_empty() { + struct_ser.serialize_field("jobs", &self.jobs)?; + } + struct_ser.end() + } +} +impl<'de> serde::Deserialize<'de> for oracle_job::oracle_task::SwitchboardConfigs { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &[ + "version", + "jobs", + ]; + + #[allow(clippy::enum_variant_names)] + enum GeneratedField { + Version, + Jobs, + } + 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 { + "version" => Ok(GeneratedField::Version), + "jobs" => Ok(GeneratedField::Jobs), + _ => Err(serde::de::Error::unknown_field(value, FIELDS)), + } + } + } + deserializer.deserialize_identifier(GeneratedVisitor) + } + } + struct GeneratedVisitor; + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = oracle_job::oracle_task::SwitchboardConfigs; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("struct oracle_job.OracleJob.OracleTask.SwitchboardConfigs") + } + + fn visit_map(self, mut map_: V) -> std::result::Result + where + V: serde::de::MapAccess<'de>, + { + let mut version__ = None; + let mut jobs__ = None; + while let Some(k) = map_.next_key()? { + match k { + GeneratedField::Version => { + if version__.is_some() { + return Err(serde::de::Error::duplicate_field("version")); + } + version__ = + map_.next_value::<::std::option::Option<::pbjson::private::NumberDeserialize<_>>>()?.map(|x| x.0) + ; + } + GeneratedField::Jobs => { + if jobs__.is_some() { + return Err(serde::de::Error::duplicate_field("jobs")); + } + jobs__ = Some(map_.next_value()?); + } + } + } + Ok(oracle_job::oracle_task::SwitchboardConfigs { + version: version__, + jobs: jobs__.unwrap_or_default(), + }) + } + } + deserializer.deserialize_struct("oracle_job.OracleJob.OracleTask.SwitchboardConfigs", FIELDS, GeneratedVisitor) + } +} +impl serde::Serialize for oracle_job::PancakeswapExchangeRateTask { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + use serde::ser::SerializeStruct; + let mut len = 0; + if self.in_token_address.is_some() { + len += 1; + } + if self.out_token_address.is_some() { + len += 1; + } + if self.in_token_amount.is_some() { + len += 1; + } + if self.slippage.is_some() { + len += 1; + } + if self.provider.is_some() { + len += 1; + } + let mut struct_ser = serializer.serialize_struct("oracle_job.OracleJob.PancakeswapExchangeRateTask", len)?; + if let Some(v) = self.in_token_address.as_ref() { + struct_ser.serialize_field("inTokenAddress", v)?; + } + if let Some(v) = self.out_token_address.as_ref() { + struct_ser.serialize_field("outTokenAddress", v)?; + } + if let Some(v) = self.in_token_amount.as_ref() { + struct_ser.serialize_field("inTokenAmount", v)?; + } + if let Some(v) = self.slippage.as_ref() { + struct_ser.serialize_field("slippage", v)?; + } + if let Some(v) = self.provider.as_ref() { + struct_ser.serialize_field("provider", v)?; + } + struct_ser.end() + } +} +impl<'de> serde::Deserialize<'de> for oracle_job::PancakeswapExchangeRateTask { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &[ + "in_token_address", + "inTokenAddress", + "out_token_address", + "outTokenAddress", + "in_token_amount", + "inTokenAmount", + "slippage", + "provider", + ]; + + #[allow(clippy::enum_variant_names)] + enum GeneratedField { + InTokenAddress, + OutTokenAddress, + InTokenAmount, + Slippage, + Provider, + } + 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 { + "inTokenAddress" | "in_token_address" => Ok(GeneratedField::InTokenAddress), + "outTokenAddress" | "out_token_address" => Ok(GeneratedField::OutTokenAddress), + "inTokenAmount" | "in_token_amount" => Ok(GeneratedField::InTokenAmount), + "slippage" => Ok(GeneratedField::Slippage), + "provider" => Ok(GeneratedField::Provider), + _ => Err(serde::de::Error::unknown_field(value, FIELDS)), + } + } + } + deserializer.deserialize_identifier(GeneratedVisitor) + } + } + struct GeneratedVisitor; + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = oracle_job::PancakeswapExchangeRateTask; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("struct oracle_job.OracleJob.PancakeswapExchangeRateTask") + } + + fn visit_map(self, mut map_: V) -> std::result::Result + where + V: serde::de::MapAccess<'de>, + { + let mut in_token_address__ = None; + let mut out_token_address__ = None; + let mut in_token_amount__ = None; + let mut slippage__ = None; + let mut provider__ = None; + while let Some(k) = map_.next_key()? { + match k { + GeneratedField::InTokenAddress => { + if in_token_address__.is_some() { + return Err(serde::de::Error::duplicate_field("inTokenAddress")); + } + in_token_address__ = map_.next_value()?; + } + GeneratedField::OutTokenAddress => { + if out_token_address__.is_some() { + return Err(serde::de::Error::duplicate_field("outTokenAddress")); + } + out_token_address__ = map_.next_value()?; + } + GeneratedField::InTokenAmount => { + if in_token_amount__.is_some() { + return Err(serde::de::Error::duplicate_field("inTokenAmount")); + } + in_token_amount__ = + map_.next_value::<::std::option::Option<::pbjson::private::NumberDeserialize<_>>>()?.map(|x| x.0) + ; + } + GeneratedField::Slippage => { + if slippage__.is_some() { + return Err(serde::de::Error::duplicate_field("slippage")); + } + slippage__ = + map_.next_value::<::std::option::Option<::pbjson::private::NumberDeserialize<_>>>()?.map(|x| x.0) + ; + } + GeneratedField::Provider => { + if provider__.is_some() { + return Err(serde::de::Error::duplicate_field("provider")); + } + provider__ = map_.next_value()?; + } + } + } + Ok(oracle_job::PancakeswapExchangeRateTask { + in_token_address: in_token_address__, + out_token_address: out_token_address__, + in_token_amount: in_token_amount__, + slippage: slippage__, + provider: provider__, + }) + } + } + deserializer.deserialize_struct("oracle_job.OracleJob.PancakeswapExchangeRateTask", FIELDS, GeneratedVisitor) + } +} +impl serde::Serialize for oracle_job::PerpMarketTask { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + use serde::ser::SerializeStruct; + let mut len = 0; + if self.market_address.is_some() { + len += 1; + } + let mut struct_ser = serializer.serialize_struct("oracle_job.OracleJob.PerpMarketTask", len)?; + if let Some(v) = self.market_address.as_ref() { + match v { + oracle_job::perp_market_task::MarketAddress::MangoMarketAddress(v) => { + struct_ser.serialize_field("mangoMarketAddress", v)?; + } + oracle_job::perp_market_task::MarketAddress::DriftMarketAddress(v) => { + struct_ser.serialize_field("driftMarketAddress", v)?; + } + oracle_job::perp_market_task::MarketAddress::ZetaMarketAddress(v) => { + struct_ser.serialize_field("zetaMarketAddress", v)?; + } + oracle_job::perp_market_task::MarketAddress::ZoMarketAddress(v) => { + struct_ser.serialize_field("zoMarketAddress", v)?; + } + } + } + struct_ser.end() + } +} +impl<'de> serde::Deserialize<'de> for oracle_job::PerpMarketTask { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &[ + "mango_market_address", + "mangoMarketAddress", + "drift_market_address", + "driftMarketAddress", + "zeta_market_address", + "zetaMarketAddress", + "zo_market_address", + "zoMarketAddress", + ]; + + #[allow(clippy::enum_variant_names)] + enum GeneratedField { + MangoMarketAddress, + DriftMarketAddress, + ZetaMarketAddress, + ZoMarketAddress, + } + 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 { + "mangoMarketAddress" | "mango_market_address" => Ok(GeneratedField::MangoMarketAddress), + "driftMarketAddress" | "drift_market_address" => Ok(GeneratedField::DriftMarketAddress), + "zetaMarketAddress" | "zeta_market_address" => Ok(GeneratedField::ZetaMarketAddress), + "zoMarketAddress" | "zo_market_address" => Ok(GeneratedField::ZoMarketAddress), + _ => Err(serde::de::Error::unknown_field(value, FIELDS)), + } + } + } + deserializer.deserialize_identifier(GeneratedVisitor) + } + } + struct GeneratedVisitor; + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = oracle_job::PerpMarketTask; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("struct oracle_job.OracleJob.PerpMarketTask") + } + + fn visit_map(self, mut map_: V) -> std::result::Result + where + V: serde::de::MapAccess<'de>, + { + let mut market_address__ = None; + while let Some(k) = map_.next_key()? { + match k { + GeneratedField::MangoMarketAddress => { + if market_address__.is_some() { + return Err(serde::de::Error::duplicate_field("mangoMarketAddress")); + } + market_address__ = map_.next_value::<::std::option::Option<_>>()?.map(oracle_job::perp_market_task::MarketAddress::MangoMarketAddress); + } + GeneratedField::DriftMarketAddress => { + if market_address__.is_some() { + return Err(serde::de::Error::duplicate_field("driftMarketAddress")); + } + market_address__ = map_.next_value::<::std::option::Option<_>>()?.map(oracle_job::perp_market_task::MarketAddress::DriftMarketAddress); + } + GeneratedField::ZetaMarketAddress => { + if market_address__.is_some() { + return Err(serde::de::Error::duplicate_field("zetaMarketAddress")); + } + market_address__ = map_.next_value::<::std::option::Option<_>>()?.map(oracle_job::perp_market_task::MarketAddress::ZetaMarketAddress); + } + GeneratedField::ZoMarketAddress => { + if market_address__.is_some() { + return Err(serde::de::Error::duplicate_field("zoMarketAddress")); + } + market_address__ = map_.next_value::<::std::option::Option<_>>()?.map(oracle_job::perp_market_task::MarketAddress::ZoMarketAddress); + } + } + } + Ok(oracle_job::PerpMarketTask { + market_address: market_address__, + }) + } + } + deserializer.deserialize_struct("oracle_job.OracleJob.PerpMarketTask", FIELDS, GeneratedVisitor) + } +} +impl serde::Serialize for oracle_job::PowTask { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + use serde::ser::SerializeStruct; + let mut len = 0; + if self.exponent.is_some() { + len += 1; + } + let mut struct_ser = serializer.serialize_struct("oracle_job.OracleJob.PowTask", len)?; + if let Some(v) = self.exponent.as_ref() { + match v { + oracle_job::pow_task::Exponent::Scalar(v) => { + struct_ser.serialize_field("scalar", v)?; + } + oracle_job::pow_task::Exponent::AggregatorPubkey(v) => { + struct_ser.serialize_field("aggregatorPubkey", v)?; + } + oracle_job::pow_task::Exponent::Big(v) => { + struct_ser.serialize_field("big", v)?; + } + } + } + struct_ser.end() + } +} +impl<'de> serde::Deserialize<'de> for oracle_job::PowTask { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &[ + "scalar", + "aggregator_pubkey", + "aggregatorPubkey", + "big", + ]; + + #[allow(clippy::enum_variant_names)] + enum GeneratedField { + Scalar, + AggregatorPubkey, + Big, + } + 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 { + "scalar" => Ok(GeneratedField::Scalar), + "aggregatorPubkey" | "aggregator_pubkey" => Ok(GeneratedField::AggregatorPubkey), + "big" => Ok(GeneratedField::Big), + _ => Err(serde::de::Error::unknown_field(value, FIELDS)), + } + } + } + deserializer.deserialize_identifier(GeneratedVisitor) + } + } + struct GeneratedVisitor; + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = oracle_job::PowTask; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("struct oracle_job.OracleJob.PowTask") + } + + fn visit_map(self, mut map_: V) -> std::result::Result + where + V: serde::de::MapAccess<'de>, + { + let mut exponent__ = None; + while let Some(k) = map_.next_key()? { + match k { + GeneratedField::Scalar => { + if exponent__.is_some() { + return Err(serde::de::Error::duplicate_field("scalar")); + } + exponent__ = map_.next_value::<::std::option::Option<::pbjson::private::NumberDeserialize<_>>>()?.map(|x| oracle_job::pow_task::Exponent::Scalar(x.0)); + } + GeneratedField::AggregatorPubkey => { + if exponent__.is_some() { + return Err(serde::de::Error::duplicate_field("aggregatorPubkey")); + } + exponent__ = map_.next_value::<::std::option::Option<_>>()?.map(oracle_job::pow_task::Exponent::AggregatorPubkey); + } + GeneratedField::Big => { + if exponent__.is_some() { + return Err(serde::de::Error::duplicate_field("big")); + } + exponent__ = map_.next_value::<::std::option::Option<_>>()?.map(oracle_job::pow_task::Exponent::Big); + } + } + } + Ok(oracle_job::PowTask { + exponent: exponent__, + }) + } + } + deserializer.deserialize_struct("oracle_job.OracleJob.PowTask", FIELDS, GeneratedVisitor) + } +} +impl serde::Serialize for oracle_job::PumpAmmLpTokenPriceTask { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + use serde::ser::SerializeStruct; + let mut len = 0; + if self.pool_address.is_some() { + len += 1; + } + if self.x_price_job.is_some() { + len += 1; + } + if self.y_price_job.is_some() { + len += 1; + } + let mut struct_ser = serializer.serialize_struct("oracle_job.OracleJob.PumpAmmLpTokenPriceTask", len)?; + if let Some(v) = self.pool_address.as_ref() { + struct_ser.serialize_field("poolAddress", v)?; + } + if let Some(v) = self.x_price_job.as_ref() { + struct_ser.serialize_field("xPriceJob", v)?; + } + if let Some(v) = self.y_price_job.as_ref() { + struct_ser.serialize_field("yPriceJob", v)?; + } + struct_ser.end() + } +} +impl<'de> serde::Deserialize<'de> for oracle_job::PumpAmmLpTokenPriceTask { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &[ + "pool_address", + "poolAddress", + "x_price_job", + "xPriceJob", + "y_price_job", + "yPriceJob", + ]; + + #[allow(clippy::enum_variant_names)] + enum GeneratedField { + PoolAddress, + XPriceJob, + YPriceJob, + } + 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 { + "poolAddress" | "pool_address" => Ok(GeneratedField::PoolAddress), + "xPriceJob" | "x_price_job" => Ok(GeneratedField::XPriceJob), + "yPriceJob" | "y_price_job" => Ok(GeneratedField::YPriceJob), + _ => Err(serde::de::Error::unknown_field(value, FIELDS)), + } + } + } + deserializer.deserialize_identifier(GeneratedVisitor) + } + } + struct GeneratedVisitor; + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = oracle_job::PumpAmmLpTokenPriceTask; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("struct oracle_job.OracleJob.PumpAmmLpTokenPriceTask") + } + + fn visit_map(self, mut map_: V) -> std::result::Result + where + V: serde::de::MapAccess<'de>, + { + let mut pool_address__ = None; + let mut x_price_job__ = None; + let mut y_price_job__ = None; + while let Some(k) = map_.next_key()? { + match k { + GeneratedField::PoolAddress => { + if pool_address__.is_some() { + return Err(serde::de::Error::duplicate_field("poolAddress")); + } + pool_address__ = map_.next_value()?; + } + GeneratedField::XPriceJob => { + if x_price_job__.is_some() { + return Err(serde::de::Error::duplicate_field("xPriceJob")); + } + x_price_job__ = map_.next_value()?; + } + GeneratedField::YPriceJob => { + if y_price_job__.is_some() { + return Err(serde::de::Error::duplicate_field("yPriceJob")); + } + y_price_job__ = map_.next_value()?; + } + } + } + Ok(oracle_job::PumpAmmLpTokenPriceTask { + pool_address: pool_address__, + x_price_job: x_price_job__, + y_price_job: y_price_job__, + }) + } + } + deserializer.deserialize_struct("oracle_job.OracleJob.PumpAmmLpTokenPriceTask", FIELDS, GeneratedVisitor) + } +} +impl serde::Serialize for oracle_job::PumpAmmTask { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + use serde::ser::SerializeStruct; + let mut len = 0; + if self.pool_address.is_some() { + len += 1; + } + if self.in_amount.is_some() { + len += 1; + } + if self.max_slippage.is_some() { + len += 1; + } + if self.is_x_for_y.is_some() { + len += 1; + } + let mut struct_ser = serializer.serialize_struct("oracle_job.OracleJob.PumpAmmTask", len)?; + if let Some(v) = self.pool_address.as_ref() { + struct_ser.serialize_field("poolAddress", v)?; + } + if let Some(v) = self.in_amount.as_ref() { + struct_ser.serialize_field("inAmount", v)?; + } + if let Some(v) = self.max_slippage.as_ref() { + struct_ser.serialize_field("maxSlippage", v)?; + } + if let Some(v) = self.is_x_for_y.as_ref() { + struct_ser.serialize_field("isXForY", v)?; + } + struct_ser.end() + } +} +impl<'de> serde::Deserialize<'de> for oracle_job::PumpAmmTask { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &[ + "pool_address", + "poolAddress", + "in_amount", + "inAmount", + "max_slippage", + "maxSlippage", + "is_x_for_y", + "isXForY", + ]; + + #[allow(clippy::enum_variant_names)] + enum GeneratedField { + PoolAddress, + InAmount, + MaxSlippage, + IsXForY, + } + 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 { + "poolAddress" | "pool_address" => Ok(GeneratedField::PoolAddress), + "inAmount" | "in_amount" => Ok(GeneratedField::InAmount), + "maxSlippage" | "max_slippage" => Ok(GeneratedField::MaxSlippage), + "isXForY" | "is_x_for_y" => Ok(GeneratedField::IsXForY), + _ => Err(serde::de::Error::unknown_field(value, FIELDS)), + } + } + } + deserializer.deserialize_identifier(GeneratedVisitor) + } + } + struct GeneratedVisitor; + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = oracle_job::PumpAmmTask; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("struct oracle_job.OracleJob.PumpAmmTask") + } + + fn visit_map(self, mut map_: V) -> std::result::Result + where + V: serde::de::MapAccess<'de>, + { + let mut pool_address__ = None; + let mut in_amount__ = None; + let mut max_slippage__ = None; + let mut is_x_for_y__ = None; + while let Some(k) = map_.next_key()? { + match k { + GeneratedField::PoolAddress => { + if pool_address__.is_some() { + return Err(serde::de::Error::duplicate_field("poolAddress")); + } + pool_address__ = map_.next_value()?; + } + GeneratedField::InAmount => { + if in_amount__.is_some() { + return Err(serde::de::Error::duplicate_field("inAmount")); + } + in_amount__ = + map_.next_value::<::std::option::Option<::pbjson::private::NumberDeserialize<_>>>()?.map(|x| x.0) + ; + } + GeneratedField::MaxSlippage => { + if max_slippage__.is_some() { + return Err(serde::de::Error::duplicate_field("maxSlippage")); + } + max_slippage__ = + map_.next_value::<::std::option::Option<::pbjson::private::NumberDeserialize<_>>>()?.map(|x| x.0) + ; + } + GeneratedField::IsXForY => { + if is_x_for_y__.is_some() { + return Err(serde::de::Error::duplicate_field("isXForY")); + } + is_x_for_y__ = map_.next_value()?; + } + } + } + Ok(oracle_job::PumpAmmTask { + pool_address: pool_address__, + in_amount: in_amount__, + max_slippage: max_slippage__, + is_x_for_y: is_x_for_y__, + }) + } + } + deserializer.deserialize_struct("oracle_job.OracleJob.PumpAmmTask", FIELDS, GeneratedVisitor) + } +} +impl serde::Serialize for oracle_job::RegexExtractTask { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + use serde::ser::SerializeStruct; + let mut len = 0; + if self.pattern.is_some() { + len += 1; + } + if self.group_number.is_some() { + len += 1; + } + let mut struct_ser = serializer.serialize_struct("oracle_job.OracleJob.RegexExtractTask", len)?; + if let Some(v) = self.pattern.as_ref() { + struct_ser.serialize_field("pattern", v)?; + } + if let Some(v) = self.group_number.as_ref() { + struct_ser.serialize_field("groupNumber", v)?; + } + struct_ser.end() + } +} +impl<'de> serde::Deserialize<'de> for oracle_job::RegexExtractTask { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &[ + "pattern", + "group_number", + "groupNumber", + ]; + + #[allow(clippy::enum_variant_names)] + enum GeneratedField { + Pattern, + GroupNumber, + } + 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 { + "pattern" => Ok(GeneratedField::Pattern), + "groupNumber" | "group_number" => Ok(GeneratedField::GroupNumber), + _ => Err(serde::de::Error::unknown_field(value, FIELDS)), + } + } + } + deserializer.deserialize_identifier(GeneratedVisitor) + } + } + struct GeneratedVisitor; + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = oracle_job::RegexExtractTask; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("struct oracle_job.OracleJob.RegexExtractTask") + } + + fn visit_map(self, mut map_: V) -> std::result::Result + where + V: serde::de::MapAccess<'de>, + { + let mut pattern__ = None; + let mut group_number__ = None; + while let Some(k) = map_.next_key()? { + match k { + GeneratedField::Pattern => { + if pattern__.is_some() { + return Err(serde::de::Error::duplicate_field("pattern")); + } + pattern__ = map_.next_value()?; + } + GeneratedField::GroupNumber => { + if group_number__.is_some() { + return Err(serde::de::Error::duplicate_field("groupNumber")); + } + group_number__ = + map_.next_value::<::std::option::Option<::pbjson::private::NumberDeserialize<_>>>()?.map(|x| x.0) + ; + } + } + } + Ok(oracle_job::RegexExtractTask { + pattern: pattern__, + group_number: group_number__, + }) + } + } + deserializer.deserialize_struct("oracle_job.OracleJob.RegexExtractTask", FIELDS, GeneratedVisitor) + } +} +impl serde::Serialize for oracle_job::RoundTask { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + use serde::ser::SerializeStruct; + let mut len = 0; + if self.method.is_some() { + len += 1; + } + if self.decimals.is_some() { + len += 1; + } + let mut struct_ser = serializer.serialize_struct("oracle_job.OracleJob.RoundTask", len)?; + if let Some(v) = self.method.as_ref() { + let v = oracle_job::round_task::Method::try_from(*v) + .map_err(|_| serde::ser::Error::custom(format!("Invalid variant {}", *v)))?; + struct_ser.serialize_field("method", &v)?; + } + if let Some(v) = self.decimals.as_ref() { + struct_ser.serialize_field("decimals", v)?; + } + struct_ser.end() + } +} +impl<'de> serde::Deserialize<'de> for oracle_job::RoundTask { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &[ + "method", + "decimals", + ]; + + #[allow(clippy::enum_variant_names)] + enum GeneratedField { + Method, + Decimals, + } + 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 { + "method" => Ok(GeneratedField::Method), + "decimals" => Ok(GeneratedField::Decimals), + _ => Err(serde::de::Error::unknown_field(value, FIELDS)), + } + } + } + deserializer.deserialize_identifier(GeneratedVisitor) + } + } + struct GeneratedVisitor; + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = oracle_job::RoundTask; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("struct oracle_job.OracleJob.RoundTask") + } + + fn visit_map(self, mut map_: V) -> std::result::Result + where + V: serde::de::MapAccess<'de>, + { + let mut method__ = None; + let mut decimals__ = None; + while let Some(k) = map_.next_key()? { + match k { + GeneratedField::Method => { + if method__.is_some() { + return Err(serde::de::Error::duplicate_field("method")); + } + method__ = map_.next_value::<::std::option::Option>()?.map(|x| x as i32); + } + GeneratedField::Decimals => { + if decimals__.is_some() { + return Err(serde::de::Error::duplicate_field("decimals")); + } + decimals__ = + map_.next_value::<::std::option::Option<::pbjson::private::NumberDeserialize<_>>>()?.map(|x| x.0) + ; + } + } + } + Ok(oracle_job::RoundTask { + method: method__, + decimals: decimals__, + }) + } + } + deserializer.deserialize_struct("oracle_job.OracleJob.RoundTask", FIELDS, GeneratedVisitor) + } +} +impl serde::Serialize for oracle_job::round_task::Method { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + let variant = match self { + Self::RoundUp => "METHOD_ROUND_UP", + Self::RoundDown => "METHOD_ROUND_DOWN", + }; + serializer.serialize_str(variant) + } +} +impl<'de> serde::Deserialize<'de> for oracle_job::round_task::Method { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &[ + "METHOD_ROUND_UP", + "METHOD_ROUND_DOWN", + ]; + + struct GeneratedVisitor; + + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = oracle_job::round_task::Method; + + 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 { + "METHOD_ROUND_UP" => Ok(oracle_job::round_task::Method::RoundUp), + "METHOD_ROUND_DOWN" => Ok(oracle_job::round_task::Method::RoundDown), + _ => Err(serde::de::Error::unknown_variant(value, FIELDS)), + } + } + } + deserializer.deserialize_any(GeneratedVisitor) + } +} +impl serde::Serialize for oracle_job::SanctumLstPriceTask { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + use serde::ser::SerializeStruct; + let mut len = 0; + if self.lst_mint.is_some() { + len += 1; + } + if self.skip_epoch_check.is_some() { + len += 1; + } + let mut struct_ser = serializer.serialize_struct("oracle_job.OracleJob.SanctumLstPriceTask", len)?; + if let Some(v) = self.lst_mint.as_ref() { + struct_ser.serialize_field("lstMint", v)?; + } + if let Some(v) = self.skip_epoch_check.as_ref() { + struct_ser.serialize_field("skipEpochCheck", v)?; + } + struct_ser.end() + } +} +impl<'de> serde::Deserialize<'de> for oracle_job::SanctumLstPriceTask { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &[ + "lst_mint", + "lstMint", + "skip_epoch_check", + "skipEpochCheck", + ]; + + #[allow(clippy::enum_variant_names)] + enum GeneratedField { + LstMint, + SkipEpochCheck, + } + 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 { + "lstMint" | "lst_mint" => Ok(GeneratedField::LstMint), + "skipEpochCheck" | "skip_epoch_check" => Ok(GeneratedField::SkipEpochCheck), + _ => Err(serde::de::Error::unknown_field(value, FIELDS)), + } + } + } + deserializer.deserialize_identifier(GeneratedVisitor) + } + } + struct GeneratedVisitor; + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = oracle_job::SanctumLstPriceTask; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("struct oracle_job.OracleJob.SanctumLstPriceTask") + } + + fn visit_map(self, mut map_: V) -> std::result::Result + where + V: serde::de::MapAccess<'de>, + { + let mut lst_mint__ = None; + let mut skip_epoch_check__ = None; + while let Some(k) = map_.next_key()? { + match k { + GeneratedField::LstMint => { + if lst_mint__.is_some() { + return Err(serde::de::Error::duplicate_field("lstMint")); + } + lst_mint__ = map_.next_value()?; + } + GeneratedField::SkipEpochCheck => { + if skip_epoch_check__.is_some() { + return Err(serde::de::Error::duplicate_field("skipEpochCheck")); + } + skip_epoch_check__ = map_.next_value()?; + } + } + } + Ok(oracle_job::SanctumLstPriceTask { + lst_mint: lst_mint__, + skip_epoch_check: skip_epoch_check__, + }) + } + } + deserializer.deserialize_struct("oracle_job.OracleJob.SanctumLstPriceTask", FIELDS, GeneratedVisitor) + } +} +impl serde::Serialize for oracle_job::SecretsTask { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + use serde::ser::SerializeStruct; + let mut len = 0; + if self.authority.is_some() { + len += 1; + } + if self.url.is_some() { + len += 1; + } + let mut struct_ser = serializer.serialize_struct("oracle_job.OracleJob.SecretsTask", len)?; + if let Some(v) = self.authority.as_ref() { + struct_ser.serialize_field("authority", v)?; + } + if let Some(v) = self.url.as_ref() { + struct_ser.serialize_field("url", v)?; + } + struct_ser.end() + } +} +impl<'de> serde::Deserialize<'de> for oracle_job::SecretsTask { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &[ + "authority", + "url", + ]; + + #[allow(clippy::enum_variant_names)] + enum GeneratedField { + Authority, + Url, + } + 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 { + "authority" => Ok(GeneratedField::Authority), + "url" => Ok(GeneratedField::Url), + _ => Err(serde::de::Error::unknown_field(value, FIELDS)), + } + } + } + deserializer.deserialize_identifier(GeneratedVisitor) + } + } + struct GeneratedVisitor; + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = oracle_job::SecretsTask; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("struct oracle_job.OracleJob.SecretsTask") + } + + fn visit_map(self, mut map_: V) -> std::result::Result + where + V: serde::de::MapAccess<'de>, + { + let mut authority__ = None; + let mut url__ = None; + while let Some(k) = map_.next_key()? { + match k { + GeneratedField::Authority => { + if authority__.is_some() { + return Err(serde::de::Error::duplicate_field("authority")); + } + authority__ = map_.next_value()?; + } + GeneratedField::Url => { + if url__.is_some() { + return Err(serde::de::Error::duplicate_field("url")); + } + url__ = map_.next_value()?; + } + } + } + Ok(oracle_job::SecretsTask { + authority: authority__, + url: url__, + }) + } + } + deserializer.deserialize_struct("oracle_job.OracleJob.SecretsTask", FIELDS, GeneratedVisitor) + } +} +impl serde::Serialize for oracle_job::SerumSwapTask { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + use serde::ser::SerializeStruct; + let mut len = 0; + if self.serum_pool_address.is_some() { + len += 1; + } + let mut struct_ser = serializer.serialize_struct("oracle_job.OracleJob.SerumSwapTask", len)?; + if let Some(v) = self.serum_pool_address.as_ref() { + struct_ser.serialize_field("serumPoolAddress", v)?; + } + struct_ser.end() + } +} +impl<'de> serde::Deserialize<'de> for oracle_job::SerumSwapTask { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &[ + "serum_pool_address", + "serumPoolAddress", + ]; + + #[allow(clippy::enum_variant_names)] + enum GeneratedField { + SerumPoolAddress, + } + 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 { + "serumPoolAddress" | "serum_pool_address" => Ok(GeneratedField::SerumPoolAddress), + _ => Err(serde::de::Error::unknown_field(value, FIELDS)), + } + } + } + deserializer.deserialize_identifier(GeneratedVisitor) + } + } + struct GeneratedVisitor; + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = oracle_job::SerumSwapTask; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("struct oracle_job.OracleJob.SerumSwapTask") + } + + fn visit_map(self, mut map_: V) -> std::result::Result + where + V: serde::de::MapAccess<'de>, + { + let mut serum_pool_address__ = None; + while let Some(k) = map_.next_key()? { + match k { + GeneratedField::SerumPoolAddress => { + if serum_pool_address__.is_some() { + return Err(serde::de::Error::duplicate_field("serumPoolAddress")); + } + serum_pool_address__ = map_.next_value()?; + } + } + } + Ok(oracle_job::SerumSwapTask { + serum_pool_address: serum_pool_address__, + }) + } + } + deserializer.deserialize_struct("oracle_job.OracleJob.SerumSwapTask", FIELDS, GeneratedVisitor) + } +} +impl serde::Serialize for oracle_job::SolanaAccountDataFetchTask { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + use serde::ser::SerializeStruct; + let mut len = 0; + if self.pubkey.is_some() { + len += 1; + } + if self.network.is_some() { + len += 1; + } + let mut struct_ser = serializer.serialize_struct("oracle_job.OracleJob.SolanaAccountDataFetchTask", len)?; + if let Some(v) = self.pubkey.as_ref() { + struct_ser.serialize_field("pubkey", v)?; + } + if let Some(v) = self.network.as_ref() { + let v = oracle_job::solana_account_data_fetch_task::Network::try_from(*v) + .map_err(|_| serde::ser::Error::custom(format!("Invalid variant {}", *v)))?; + struct_ser.serialize_field("network", &v)?; + } + struct_ser.end() + } +} +impl<'de> serde::Deserialize<'de> for oracle_job::SolanaAccountDataFetchTask { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &[ + "pubkey", + "network", + ]; + + #[allow(clippy::enum_variant_names)] + enum GeneratedField { + Pubkey, + Network, + } + 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 { + "pubkey" => Ok(GeneratedField::Pubkey), + "network" => Ok(GeneratedField::Network), + _ => Err(serde::de::Error::unknown_field(value, FIELDS)), + } + } + } + deserializer.deserialize_identifier(GeneratedVisitor) + } + } + struct GeneratedVisitor; + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = oracle_job::SolanaAccountDataFetchTask; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("struct oracle_job.OracleJob.SolanaAccountDataFetchTask") + } + + fn visit_map(self, mut map_: V) -> std::result::Result + where + V: serde::de::MapAccess<'de>, + { + let mut pubkey__ = None; + let mut network__ = None; + while let Some(k) = map_.next_key()? { + match k { + GeneratedField::Pubkey => { + if pubkey__.is_some() { + return Err(serde::de::Error::duplicate_field("pubkey")); + } + pubkey__ = map_.next_value()?; + } + GeneratedField::Network => { + if network__.is_some() { + return Err(serde::de::Error::duplicate_field("network")); + } + network__ = map_.next_value::<::std::option::Option>()?.map(|x| x as i32); + } + } + } + Ok(oracle_job::SolanaAccountDataFetchTask { + pubkey: pubkey__, + network: network__, + }) + } + } + deserializer.deserialize_struct("oracle_job.OracleJob.SolanaAccountDataFetchTask", FIELDS, GeneratedVisitor) + } +} +impl serde::Serialize for oracle_job::solana_account_data_fetch_task::Network { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + let variant = match self { + Self::Mainnet => "NETWORK_MAINNET", + Self::Testnet => "NETWORK_TESTNET", + Self::Devnet => "NETWORK_DEVNET", + }; + serializer.serialize_str(variant) + } +} +impl<'de> serde::Deserialize<'de> for oracle_job::solana_account_data_fetch_task::Network { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &[ + "NETWORK_MAINNET", + "NETWORK_TESTNET", + "NETWORK_DEVNET", + ]; + + struct GeneratedVisitor; + + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = oracle_job::solana_account_data_fetch_task::Network; + + 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 { + "NETWORK_MAINNET" => Ok(oracle_job::solana_account_data_fetch_task::Network::Mainnet), + "NETWORK_TESTNET" => Ok(oracle_job::solana_account_data_fetch_task::Network::Testnet), + "NETWORK_DEVNET" => Ok(oracle_job::solana_account_data_fetch_task::Network::Devnet), + _ => Err(serde::de::Error::unknown_variant(value, FIELDS)), + } + } + } + deserializer.deserialize_any(GeneratedVisitor) + } +} +impl serde::Serialize for oracle_job::SolanaToken2022ExtensionTask { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + use serde::ser::SerializeStruct; + let mut len = 0; + if self.mint.is_some() { + len += 1; + } + if self.extension.is_some() { + len += 1; + } + let mut struct_ser = serializer.serialize_struct("oracle_job.OracleJob.SolanaToken2022ExtensionTask", len)?; + if let Some(v) = self.mint.as_ref() { + struct_ser.serialize_field("mint", v)?; + } + if let Some(v) = self.extension.as_ref() { + let v = oracle_job::solana_token2022_extension_task::Token2022Extension::try_from(*v) + .map_err(|_| serde::ser::Error::custom(format!("Invalid variant {}", *v)))?; + struct_ser.serialize_field("extension", &v)?; + } + struct_ser.end() + } +} +impl<'de> serde::Deserialize<'de> for oracle_job::SolanaToken2022ExtensionTask { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &[ + "mint", + "extension", + ]; + + #[allow(clippy::enum_variant_names)] + enum GeneratedField { + Mint, + Extension, + } + 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 { + "mint" => Ok(GeneratedField::Mint), + "extension" => Ok(GeneratedField::Extension), + _ => Err(serde::de::Error::unknown_field(value, FIELDS)), + } + } + } + deserializer.deserialize_identifier(GeneratedVisitor) + } + } + struct GeneratedVisitor; + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = oracle_job::SolanaToken2022ExtensionTask; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("struct oracle_job.OracleJob.SolanaToken2022ExtensionTask") + } + + fn visit_map(self, mut map_: V) -> std::result::Result + where + V: serde::de::MapAccess<'de>, + { + let mut mint__ = None; + let mut extension__ = None; + while let Some(k) = map_.next_key()? { + match k { + GeneratedField::Mint => { + if mint__.is_some() { + return Err(serde::de::Error::duplicate_field("mint")); + } + mint__ = map_.next_value()?; + } + GeneratedField::Extension => { + if extension__.is_some() { + return Err(serde::de::Error::duplicate_field("extension")); + } + extension__ = map_.next_value::<::std::option::Option>()?.map(|x| x as i32); + } + } + } + Ok(oracle_job::SolanaToken2022ExtensionTask { + mint: mint__, + extension: extension__, + }) + } + } + deserializer.deserialize_struct("oracle_job.OracleJob.SolanaToken2022ExtensionTask", FIELDS, GeneratedVisitor) + } +} +impl serde::Serialize for oracle_job::solana_token2022_extension_task::Token2022Extension { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + let variant = match self { + Self::Token2022ScaledAmountFactor => "TOKEN_2022_SCALED_AMOUNT_FACTOR", + }; + serializer.serialize_str(variant) + } +} +impl<'de> serde::Deserialize<'de> for oracle_job::solana_token2022_extension_task::Token2022Extension { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &[ + "TOKEN_2022_SCALED_AMOUNT_FACTOR", + ]; + + struct GeneratedVisitor; + + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = oracle_job::solana_token2022_extension_task::Token2022Extension; + + 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 { + "TOKEN_2022_SCALED_AMOUNT_FACTOR" => Ok(oracle_job::solana_token2022_extension_task::Token2022Extension::Token2022ScaledAmountFactor), + _ => Err(serde::de::Error::unknown_variant(value, FIELDS)), + } + } + } + deserializer.deserialize_any(GeneratedVisitor) + } +} +impl serde::Serialize for oracle_job::SolayerSusdTask { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + use serde::ser::SerializeStruct; + let len = 0; + let struct_ser = serializer.serialize_struct("oracle_job.OracleJob.SolayerSusdTask", len)?; + struct_ser.end() + } +} +impl<'de> serde::Deserialize<'de> for oracle_job::SolayerSusdTask { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &[ + ]; + + #[allow(clippy::enum_variant_names)] + enum GeneratedField { + } + 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, + { + Err(serde::de::Error::unknown_field(value, FIELDS)) + } + } + deserializer.deserialize_identifier(GeneratedVisitor) + } + } + struct GeneratedVisitor; + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = oracle_job::SolayerSusdTask; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("struct oracle_job.OracleJob.SolayerSusdTask") + } + + fn visit_map(self, mut map_: V) -> std::result::Result + where + V: serde::de::MapAccess<'de>, + { + while map_.next_key::()?.is_some() { + let _ = map_.next_value::()?; + } + Ok(oracle_job::SolayerSusdTask { + }) + } + } + deserializer.deserialize_struct("oracle_job.OracleJob.SolayerSusdTask", FIELDS, GeneratedVisitor) + } +} +impl serde::Serialize for oracle_job::SplStakePoolTask { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + use serde::ser::SerializeStruct; + let mut len = 0; + if self.pubkey.is_some() { + len += 1; + } + let mut struct_ser = serializer.serialize_struct("oracle_job.OracleJob.SplStakePoolTask", len)?; + if let Some(v) = self.pubkey.as_ref() { + struct_ser.serialize_field("pubkey", v)?; + } + struct_ser.end() + } +} +impl<'de> serde::Deserialize<'de> for oracle_job::SplStakePoolTask { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &[ + "pubkey", + ]; + + #[allow(clippy::enum_variant_names)] + enum GeneratedField { + Pubkey, + } + 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 { + "pubkey" => Ok(GeneratedField::Pubkey), + _ => Err(serde::de::Error::unknown_field(value, FIELDS)), + } + } + } + deserializer.deserialize_identifier(GeneratedVisitor) + } + } + struct GeneratedVisitor; + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = oracle_job::SplStakePoolTask; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("struct oracle_job.OracleJob.SplStakePoolTask") + } + + fn visit_map(self, mut map_: V) -> std::result::Result + where + V: serde::de::MapAccess<'de>, + { + let mut pubkey__ = None; + while let Some(k) = map_.next_key()? { + match k { + GeneratedField::Pubkey => { + if pubkey__.is_some() { + return Err(serde::de::Error::duplicate_field("pubkey")); + } + pubkey__ = map_.next_value()?; + } + } + } + Ok(oracle_job::SplStakePoolTask { + pubkey: pubkey__, + }) + } + } + deserializer.deserialize_struct("oracle_job.OracleJob.SplStakePoolTask", FIELDS, GeneratedVisitor) + } +} +impl serde::Serialize for oracle_job::SplTokenParseTask { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + use serde::ser::SerializeStruct; + let mut len = 0; + if self.account_address.is_some() { + len += 1; + } + let mut struct_ser = serializer.serialize_struct("oracle_job.OracleJob.SplTokenParseTask", len)?; + if let Some(v) = self.account_address.as_ref() { + match v { + oracle_job::spl_token_parse_task::AccountAddress::TokenAccountAddress(v) => { + struct_ser.serialize_field("tokenAccountAddress", v)?; + } + oracle_job::spl_token_parse_task::AccountAddress::MintAddress(v) => { + struct_ser.serialize_field("mintAddress", v)?; + } + } + } + struct_ser.end() + } +} +impl<'de> serde::Deserialize<'de> for oracle_job::SplTokenParseTask { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &[ + "token_account_address", + "tokenAccountAddress", + "mint_address", + "mintAddress", + ]; + + #[allow(clippy::enum_variant_names)] + enum GeneratedField { + TokenAccountAddress, + MintAddress, + } + 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 { + "tokenAccountAddress" | "token_account_address" => Ok(GeneratedField::TokenAccountAddress), + "mintAddress" | "mint_address" => Ok(GeneratedField::MintAddress), + _ => Err(serde::de::Error::unknown_field(value, FIELDS)), + } + } + } + deserializer.deserialize_identifier(GeneratedVisitor) + } + } + struct GeneratedVisitor; + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = oracle_job::SplTokenParseTask; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("struct oracle_job.OracleJob.SplTokenParseTask") + } + + fn visit_map(self, mut map_: V) -> std::result::Result + where + V: serde::de::MapAccess<'de>, + { + let mut account_address__ = None; + while let Some(k) = map_.next_key()? { + match k { + GeneratedField::TokenAccountAddress => { + if account_address__.is_some() { + return Err(serde::de::Error::duplicate_field("tokenAccountAddress")); + } + account_address__ = map_.next_value::<::std::option::Option<_>>()?.map(oracle_job::spl_token_parse_task::AccountAddress::TokenAccountAddress); + } + GeneratedField::MintAddress => { + if account_address__.is_some() { + return Err(serde::de::Error::duplicate_field("mintAddress")); + } + account_address__ = map_.next_value::<::std::option::Option<_>>()?.map(oracle_job::spl_token_parse_task::AccountAddress::MintAddress); + } + } + } + Ok(oracle_job::SplTokenParseTask { + account_address: account_address__, + }) + } + } + deserializer.deserialize_struct("oracle_job.OracleJob.SplTokenParseTask", FIELDS, GeneratedVisitor) + } +} +impl serde::Serialize for oracle_job::SubtractTask { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + use serde::ser::SerializeStruct; + let mut len = 0; + if self.subtraction.is_some() { + len += 1; + } + let mut struct_ser = serializer.serialize_struct("oracle_job.OracleJob.SubtractTask", len)?; + if let Some(v) = self.subtraction.as_ref() { + match v { + oracle_job::subtract_task::Subtraction::Scalar(v) => { + struct_ser.serialize_field("scalar", v)?; + } + oracle_job::subtract_task::Subtraction::AggregatorPubkey(v) => { + struct_ser.serialize_field("aggregatorPubkey", v)?; + } + oracle_job::subtract_task::Subtraction::Job(v) => { + struct_ser.serialize_field("job", v)?; + } + oracle_job::subtract_task::Subtraction::Big(v) => { + struct_ser.serialize_field("big", v)?; + } + } + } + struct_ser.end() + } +} +impl<'de> serde::Deserialize<'de> for oracle_job::SubtractTask { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &[ + "scalar", + "aggregator_pubkey", + "aggregatorPubkey", + "job", + "big", + ]; + + #[allow(clippy::enum_variant_names)] + enum GeneratedField { + Scalar, + AggregatorPubkey, + Job, + Big, + } + 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 { + "scalar" => Ok(GeneratedField::Scalar), + "aggregatorPubkey" | "aggregator_pubkey" => Ok(GeneratedField::AggregatorPubkey), + "job" => Ok(GeneratedField::Job), + "big" => Ok(GeneratedField::Big), + _ => Err(serde::de::Error::unknown_field(value, FIELDS)), + } + } + } + deserializer.deserialize_identifier(GeneratedVisitor) + } + } + struct GeneratedVisitor; + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = oracle_job::SubtractTask; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("struct oracle_job.OracleJob.SubtractTask") + } + + fn visit_map(self, mut map_: V) -> std::result::Result + where + V: serde::de::MapAccess<'de>, + { + let mut subtraction__ = None; + while let Some(k) = map_.next_key()? { + match k { + GeneratedField::Scalar => { + if subtraction__.is_some() { + return Err(serde::de::Error::duplicate_field("scalar")); + } + subtraction__ = map_.next_value::<::std::option::Option<::pbjson::private::NumberDeserialize<_>>>()?.map(|x| oracle_job::subtract_task::Subtraction::Scalar(x.0)); + } + GeneratedField::AggregatorPubkey => { + if subtraction__.is_some() { + return Err(serde::de::Error::duplicate_field("aggregatorPubkey")); + } + subtraction__ = map_.next_value::<::std::option::Option<_>>()?.map(oracle_job::subtract_task::Subtraction::AggregatorPubkey); + } + GeneratedField::Job => { + if subtraction__.is_some() { + return Err(serde::de::Error::duplicate_field("job")); + } + subtraction__ = map_.next_value::<::std::option::Option<_>>()?.map(oracle_job::subtract_task::Subtraction::Job) +; + } + GeneratedField::Big => { + if subtraction__.is_some() { + return Err(serde::de::Error::duplicate_field("big")); + } + subtraction__ = map_.next_value::<::std::option::Option<_>>()?.map(oracle_job::subtract_task::Subtraction::Big); + } + } + } + Ok(oracle_job::SubtractTask { + subtraction: subtraction__, + }) + } + } + deserializer.deserialize_struct("oracle_job.OracleJob.SubtractTask", FIELDS, GeneratedVisitor) + } +} +impl serde::Serialize for oracle_job::SushiswapExchangeRateTask { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + use serde::ser::SerializeStruct; + let mut len = 0; + if self.in_token_address.is_some() { + len += 1; + } + if self.out_token_address.is_some() { + len += 1; + } + if self.in_token_amount.is_some() { + len += 1; + } + if self.slippage.is_some() { + len += 1; + } + if self.provider.is_some() { + len += 1; + } + let mut struct_ser = serializer.serialize_struct("oracle_job.OracleJob.SushiswapExchangeRateTask", len)?; + if let Some(v) = self.in_token_address.as_ref() { + struct_ser.serialize_field("inTokenAddress", v)?; + } + if let Some(v) = self.out_token_address.as_ref() { + struct_ser.serialize_field("outTokenAddress", v)?; + } + if let Some(v) = self.in_token_amount.as_ref() { + struct_ser.serialize_field("inTokenAmount", v)?; + } + if let Some(v) = self.slippage.as_ref() { + struct_ser.serialize_field("slippage", v)?; + } + if let Some(v) = self.provider.as_ref() { + struct_ser.serialize_field("provider", v)?; + } + struct_ser.end() + } +} +impl<'de> serde::Deserialize<'de> for oracle_job::SushiswapExchangeRateTask { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &[ + "in_token_address", + "inTokenAddress", + "out_token_address", + "outTokenAddress", + "in_token_amount", + "inTokenAmount", + "slippage", + "provider", + ]; + + #[allow(clippy::enum_variant_names)] + enum GeneratedField { + InTokenAddress, + OutTokenAddress, + InTokenAmount, + Slippage, + Provider, + } + 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 { + "inTokenAddress" | "in_token_address" => Ok(GeneratedField::InTokenAddress), + "outTokenAddress" | "out_token_address" => Ok(GeneratedField::OutTokenAddress), + "inTokenAmount" | "in_token_amount" => Ok(GeneratedField::InTokenAmount), + "slippage" => Ok(GeneratedField::Slippage), + "provider" => Ok(GeneratedField::Provider), + _ => Err(serde::de::Error::unknown_field(value, FIELDS)), + } + } + } + deserializer.deserialize_identifier(GeneratedVisitor) + } + } + struct GeneratedVisitor; + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = oracle_job::SushiswapExchangeRateTask; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("struct oracle_job.OracleJob.SushiswapExchangeRateTask") + } + + fn visit_map(self, mut map_: V) -> std::result::Result + where + V: serde::de::MapAccess<'de>, + { + let mut in_token_address__ = None; + let mut out_token_address__ = None; + let mut in_token_amount__ = None; + let mut slippage__ = None; + let mut provider__ = None; + while let Some(k) = map_.next_key()? { + match k { + GeneratedField::InTokenAddress => { + if in_token_address__.is_some() { + return Err(serde::de::Error::duplicate_field("inTokenAddress")); + } + in_token_address__ = map_.next_value()?; + } + GeneratedField::OutTokenAddress => { + if out_token_address__.is_some() { + return Err(serde::de::Error::duplicate_field("outTokenAddress")); + } + out_token_address__ = map_.next_value()?; + } + GeneratedField::InTokenAmount => { + if in_token_amount__.is_some() { + return Err(serde::de::Error::duplicate_field("inTokenAmount")); + } + in_token_amount__ = + map_.next_value::<::std::option::Option<::pbjson::private::NumberDeserialize<_>>>()?.map(|x| x.0) + ; + } + GeneratedField::Slippage => { + if slippage__.is_some() { + return Err(serde::de::Error::duplicate_field("slippage")); + } + slippage__ = + map_.next_value::<::std::option::Option<::pbjson::private::NumberDeserialize<_>>>()?.map(|x| x.0) + ; + } + GeneratedField::Provider => { + if provider__.is_some() { + return Err(serde::de::Error::duplicate_field("provider")); + } + provider__ = map_.next_value()?; + } + } + } + Ok(oracle_job::SushiswapExchangeRateTask { + in_token_address: in_token_address__, + out_token_address: out_token_address__, + in_token_amount: in_token_amount__, + slippage: slippage__, + provider: provider__, + }) + } + } + deserializer.deserialize_struct("oracle_job.OracleJob.SushiswapExchangeRateTask", FIELDS, GeneratedVisitor) + } +} +impl serde::Serialize for oracle_job::SwitchboardSurgeTask { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + use serde::ser::SerializeStruct; + let mut len = 0; + if self.source.is_some() { + len += 1; + } + if self.symbol.is_some() { + len += 1; + } + let mut struct_ser = serializer.serialize_struct("oracle_job.OracleJob.SwitchboardSurgeTask", len)?; + if let Some(v) = self.source.as_ref() { + let v = oracle_job::switchboard_surge_task::Source::try_from(*v) + .map_err(|_| serde::ser::Error::custom(format!("Invalid variant {}", *v)))?; + struct_ser.serialize_field("source", &v)?; + } + if let Some(v) = self.symbol.as_ref() { + struct_ser.serialize_field("symbol", v)?; + } + struct_ser.end() + } +} +impl<'de> serde::Deserialize<'de> for oracle_job::SwitchboardSurgeTask { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &[ + "source", + "symbol", + ]; + + #[allow(clippy::enum_variant_names)] + enum GeneratedField { + Source, + Symbol, + } + 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 { + "source" => Ok(GeneratedField::Source), + "symbol" => Ok(GeneratedField::Symbol), + _ => Err(serde::de::Error::unknown_field(value, FIELDS)), + } + } + } + deserializer.deserialize_identifier(GeneratedVisitor) + } + } + struct GeneratedVisitor; + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = oracle_job::SwitchboardSurgeTask; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("struct oracle_job.OracleJob.SwitchboardSurgeTask") + } + + fn visit_map(self, mut map_: V) -> std::result::Result + where + V: serde::de::MapAccess<'de>, + { + let mut source__ = None; + let mut symbol__ = None; + while let Some(k) = map_.next_key()? { + match k { + GeneratedField::Source => { + if source__.is_some() { + return Err(serde::de::Error::duplicate_field("source")); + } + source__ = map_.next_value::<::std::option::Option>()?.map(|x| x as i32); + } + GeneratedField::Symbol => { + if symbol__.is_some() { + return Err(serde::de::Error::duplicate_field("symbol")); + } + symbol__ = map_.next_value()?; + } + } + } + Ok(oracle_job::SwitchboardSurgeTask { + source: source__, + symbol: symbol__, + }) + } + } + deserializer.deserialize_struct("oracle_job.OracleJob.SwitchboardSurgeTask", FIELDS, GeneratedVisitor) + } +} +impl serde::Serialize for oracle_job::switchboard_surge_task::Source { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + let variant = match self { + Self::Weighted => "WEIGHTED", + Self::Binance => "BINANCE", + Self::Okx => "OKX", + Self::Bybit => "BYBIT", + Self::Coinbase => "COINBASE", + }; + serializer.serialize_str(variant) + } +} +impl<'de> serde::Deserialize<'de> for oracle_job::switchboard_surge_task::Source { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &[ + "WEIGHTED", + "BINANCE", + "OKX", + "BYBIT", + "COINBASE", + ]; + + struct GeneratedVisitor; + + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = oracle_job::switchboard_surge_task::Source; + + 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 { + "WEIGHTED" => Ok(oracle_job::switchboard_surge_task::Source::Weighted), + "BINANCE" => Ok(oracle_job::switchboard_surge_task::Source::Binance), + "OKX" => Ok(oracle_job::switchboard_surge_task::Source::Okx), + "BYBIT" => Ok(oracle_job::switchboard_surge_task::Source::Bybit), + "COINBASE" => Ok(oracle_job::switchboard_surge_task::Source::Coinbase), + _ => Err(serde::de::Error::unknown_variant(value, FIELDS)), + } + } + } + deserializer.deserialize_any(GeneratedVisitor) + } +} +impl serde::Serialize for oracle_job::SysclockOffsetTask { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + use serde::ser::SerializeStruct; + let len = 0; + let struct_ser = serializer.serialize_struct("oracle_job.OracleJob.SysclockOffsetTask", len)?; + struct_ser.end() + } +} +impl<'de> serde::Deserialize<'de> for oracle_job::SysclockOffsetTask { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &[ + ]; + + #[allow(clippy::enum_variant_names)] + enum GeneratedField { + } + 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, + { + Err(serde::de::Error::unknown_field(value, FIELDS)) + } + } + deserializer.deserialize_identifier(GeneratedVisitor) + } + } + struct GeneratedVisitor; + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = oracle_job::SysclockOffsetTask; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("struct oracle_job.OracleJob.SysclockOffsetTask") + } + + fn visit_map(self, mut map_: V) -> std::result::Result + where + V: serde::de::MapAccess<'de>, + { + while map_.next_key::()?.is_some() { + let _ = map_.next_value::()?; + } + Ok(oracle_job::SysclockOffsetTask { + }) + } + } + deserializer.deserialize_struct("oracle_job.OracleJob.SysclockOffsetTask", FIELDS, GeneratedVisitor) + } +} +impl serde::Serialize for oracle_job::Task { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + use serde::ser::SerializeStruct; + let mut len = 0; + if self.task.is_some() { + len += 1; + } + let mut struct_ser = serializer.serialize_struct("oracle_job.OracleJob.Task", len)?; + if let Some(v) = self.task.as_ref() { + match v { + oracle_job::task::Task::HttpTask(v) => { + struct_ser.serialize_field("httpTask", v)?; + } + oracle_job::task::Task::JsonParseTask(v) => { + struct_ser.serialize_field("jsonParseTask", v)?; + } + oracle_job::task::Task::MedianTask(v) => { + struct_ser.serialize_field("medianTask", v)?; + } + oracle_job::task::Task::MeanTask(v) => { + struct_ser.serialize_field("meanTask", v)?; + } + oracle_job::task::Task::WebsocketTask(v) => { + struct_ser.serialize_field("websocketTask", v)?; + } + oracle_job::task::Task::DivideTask(v) => { + struct_ser.serialize_field("divideTask", v)?; + } + oracle_job::task::Task::MultiplyTask(v) => { + struct_ser.serialize_field("multiplyTask", v)?; + } + oracle_job::task::Task::LpTokenPriceTask(v) => { + struct_ser.serialize_field("lpTokenPriceTask", v)?; + } + oracle_job::task::Task::LpExchangeRateTask(v) => { + struct_ser.serialize_field("lpExchangeRateTask", v)?; + } + oracle_job::task::Task::ConditionalTask(v) => { + struct_ser.serialize_field("conditionalTask", v)?; + } + oracle_job::task::Task::ValueTask(v) => { + struct_ser.serialize_field("valueTask", v)?; + } + oracle_job::task::Task::MaxTask(v) => { + struct_ser.serialize_field("maxTask", v)?; + } + oracle_job::task::Task::RegexExtractTask(v) => { + struct_ser.serialize_field("regexExtractTask", v)?; + } + oracle_job::task::Task::XstepPriceTask(v) => { + struct_ser.serialize_field("xstepPriceTask", v)?; + } + oracle_job::task::Task::AddTask(v) => { + struct_ser.serialize_field("addTask", v)?; + } + oracle_job::task::Task::SubtractTask(v) => { + struct_ser.serialize_field("subtractTask", v)?; + } + oracle_job::task::Task::TwapTask(v) => { + struct_ser.serialize_field("twapTask", v)?; + } + oracle_job::task::Task::SerumSwapTask(v) => { + struct_ser.serialize_field("serumSwapTask", v)?; + } + oracle_job::task::Task::PowTask(v) => { + struct_ser.serialize_field("powTask", v)?; + } + oracle_job::task::Task::LendingRateTask(v) => { + struct_ser.serialize_field("lendingRateTask", v)?; + } + oracle_job::task::Task::MangoPerpMarketTask(v) => { + struct_ser.serialize_field("mangoPerpMarketTask", v)?; + } + oracle_job::task::Task::JupiterSwapTask(v) => { + struct_ser.serialize_field("jupiterSwapTask", v)?; + } + oracle_job::task::Task::PerpMarketTask(v) => { + struct_ser.serialize_field("perpMarketTask", v)?; + } + oracle_job::task::Task::OracleTask(v) => { + struct_ser.serialize_field("oracleTask", v)?; + } + oracle_job::task::Task::AnchorFetchTask(v) => { + struct_ser.serialize_field("anchorFetchTask", v)?; + } + oracle_job::task::Task::SplStakePoolTask(v) => { + struct_ser.serialize_field("splStakePoolTask", v)?; + } + oracle_job::task::Task::SplTokenParseTask(v) => { + struct_ser.serialize_field("splTokenParseTask", v)?; + } + oracle_job::task::Task::UniswapExchangeRateTask(v) => { + struct_ser.serialize_field("uniswapExchangeRateTask", v)?; + } + oracle_job::task::Task::SushiswapExchangeRateTask(v) => { + struct_ser.serialize_field("sushiswapExchangeRateTask", v)?; + } + oracle_job::task::Task::PancakeswapExchangeRateTask(v) => { + struct_ser.serialize_field("pancakeswapExchangeRateTask", v)?; + } + oracle_job::task::Task::CacheTask(v) => { + struct_ser.serialize_field("cacheTask", v)?; + } + oracle_job::task::Task::SysclockOffsetTask(v) => { + struct_ser.serialize_field("sysclockOffsetTask", v)?; + } + oracle_job::task::Task::MarinadeStateTask(v) => { + struct_ser.serialize_field("marinadeStateTask", v)?; + } + oracle_job::task::Task::SolanaAccountDataFetchTask(v) => { + struct_ser.serialize_field("solanaAccountDataFetchTask", v)?; + } + oracle_job::task::Task::BufferLayoutParseTask(v) => { + struct_ser.serialize_field("bufferLayoutParseTask", v)?; + } + oracle_job::task::Task::CronParseTask(v) => { + struct_ser.serialize_field("cronParseTask", v)?; + } + oracle_job::task::Task::MinTask(v) => { + struct_ser.serialize_field("minTask", v)?; + } + oracle_job::task::Task::HistoryFunctionTask(v) => { + struct_ser.serialize_field("historyFunctionTask", v)?; + } + oracle_job::task::Task::VwapTask(v) => { + struct_ser.serialize_field("vwapTask", v)?; + } + oracle_job::task::Task::EwmaTask(v) => { + struct_ser.serialize_field("ewmaTask", v)?; + } + oracle_job::task::Task::ComparisonTask(v) => { + struct_ser.serialize_field("comparisonTask", v)?; + } + oracle_job::task::Task::RoundTask(v) => { + struct_ser.serialize_field("roundTask", v)?; + } + oracle_job::task::Task::BoundTask(v) => { + struct_ser.serialize_field("boundTask", v)?; + } + oracle_job::task::Task::SecretsTask(v) => { + struct_ser.serialize_field("secretsTask", v)?; + } + oracle_job::task::Task::SanctumLstPriceTask(v) => { + struct_ser.serialize_field("sanctumLstPriceTask", v)?; + } + oracle_job::task::Task::OndoUsdyTask(v) => { + struct_ser.serialize_field("ondoUsdyTask", v)?; + } + oracle_job::task::Task::MeteoraSwapTask(v) => { + struct_ser.serialize_field("meteoraSwapTask", v)?; + } + oracle_job::task::Task::UnixTimeTask(v) => { + struct_ser.serialize_field("unixTimeTask", v)?; + } + oracle_job::task::Task::MapleFinanceTask(v) => { + struct_ser.serialize_field("mapleFinanceTask", v)?; + } + oracle_job::task::Task::GlyphTask(v) => { + struct_ser.serialize_field("glyphTask", v)?; + } + oracle_job::task::Task::CorexTask(v) => { + struct_ser.serialize_field("corexTask", v)?; + } + oracle_job::task::Task::LlmTask(v) => { + struct_ser.serialize_field("llmTask", v)?; + } + oracle_job::task::Task::SolayerSusdTask(v) => { + struct_ser.serialize_field("solayerSusdTask", v)?; + } + oracle_job::task::Task::CurveFinanceTask(v) => { + struct_ser.serialize_field("curveFinanceTask", v)?; + } + oracle_job::task::Task::TurboEthRedemptionRateTask(v) => { + struct_ser.serialize_field("turboEthRedemptionRateTask", v)?; + } + oracle_job::task::Task::BitFluxTask(v) => { + struct_ser.serialize_field("bitFluxTask", v)?; + } + oracle_job::task::Task::FragmetricTask(v) => { + struct_ser.serialize_field("fragmetricTask", v)?; + } + oracle_job::task::Task::AftermathTask(v) => { + struct_ser.serialize_field("aftermathTask", v)?; + } + oracle_job::task::Task::EtherfuseTask(v) => { + struct_ser.serialize_field("etherfuseTask", v)?; + } + oracle_job::task::Task::LstHistoricalYieldTask(v) => { + struct_ser.serialize_field("lstHistoricalYieldTask", v)?; + } + oracle_job::task::Task::PumpAmmTask(v) => { + struct_ser.serialize_field("pumpAmmTask", v)?; + } + oracle_job::task::Task::PumpAmmLpTokenPriceTask(v) => { + struct_ser.serialize_field("pumpAmmLpTokenPriceTask", v)?; + } + oracle_job::task::Task::ExponentTask(v) => { + struct_ser.serialize_field("exponentTask", v)?; + } + oracle_job::task::Task::ExponentPtLinearPricingTask(v) => { + struct_ser.serialize_field("exponentPtLinearPricingTask", v)?; + } + oracle_job::task::Task::SolanaToken2022ExtensionTask(v) => { + struct_ser.serialize_field("solanaToken2022ExtensionTask", v)?; + } + oracle_job::task::Task::SwitchboardSurgeTask(v) => { + struct_ser.serialize_field("switchboardSurgeTask", v)?; + } + } + } + struct_ser.end() + } +} +impl<'de> serde::Deserialize<'de> for oracle_job::Task { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &[ + "http_task", + "httpTask", + "json_parse_task", + "jsonParseTask", + "median_task", + "medianTask", + "mean_task", + "meanTask", + "websocket_task", + "websocketTask", + "divide_task", + "divideTask", + "multiply_task", + "multiplyTask", + "lp_token_price_task", + "lpTokenPriceTask", + "lp_exchange_rate_task", + "lpExchangeRateTask", + "conditional_task", + "conditionalTask", + "value_task", + "valueTask", + "max_task", + "maxTask", + "regex_extract_task", + "regexExtractTask", + "xstep_price_task", + "xstepPriceTask", + "add_task", + "addTask", + "subtract_task", + "subtractTask", + "twap_task", + "twapTask", + "serum_swap_task", + "serumSwapTask", + "pow_task", + "powTask", + "lending_rate_task", + "lendingRateTask", + "mango_perp_market_task", + "mangoPerpMarketTask", + "jupiter_swap_task", + "jupiterSwapTask", + "perp_market_task", + "perpMarketTask", + "oracle_task", + "oracleTask", + "anchor_fetch_task", + "anchorFetchTask", + "spl_stake_pool_task", + "splStakePoolTask", + "spl_token_parse_task", + "splTokenParseTask", + "uniswap_exchange_rate_task", + "uniswapExchangeRateTask", + "sushiswap_exchange_rate_task", + "sushiswapExchangeRateTask", + "pancakeswap_exchange_rate_task", + "pancakeswapExchangeRateTask", + "cache_task", + "cacheTask", + "sysclock_offset_task", + "sysclockOffsetTask", + "marinade_state_task", + "marinadeStateTask", + "solana_account_data_fetch_task", + "solanaAccountDataFetchTask", + "buffer_layout_parse_task", + "bufferLayoutParseTask", + "cron_parse_task", + "cronParseTask", + "min_task", + "minTask", + "history_function_task", + "historyFunctionTask", + "vwap_task", + "vwapTask", + "ewma_task", + "ewmaTask", + "comparison_task", + "comparisonTask", + "round_task", + "roundTask", + "bound_task", + "boundTask", + "secrets_task", + "secretsTask", + "sanctum_lst_price_task", + "sanctumLstPriceTask", + "ondo_usdy_task", + "ondoUsdyTask", + "meteora_swap_task", + "meteoraSwapTask", + "unix_time_task", + "unixTimeTask", + "maple_finance_task", + "mapleFinanceTask", + "glyph_task", + "glyphTask", + "corex_task", + "corexTask", + "llm_task", + "llmTask", + "solayer_susd_task", + "solayerSusdTask", + "curve_finance_task", + "curveFinanceTask", + "turbo_eth_redemption_rate_task", + "turboEthRedemptionRateTask", + "bit_flux_task", + "bitFluxTask", + "fragmetric_task", + "fragmetricTask", + "aftermath_task", + "aftermathTask", + "etherfuse_task", + "etherfuseTask", + "lst_historical_yield_task", + "lstHistoricalYieldTask", + "pump_amm_task", + "pumpAmmTask", + "pump_amm_lp_token_price_task", + "pumpAmmLpTokenPriceTask", + "exponent_task", + "exponentTask", + "exponent_pt_linear_pricing_task", + "exponentPtLinearPricingTask", + "solana_token_2022_extension_task", + "solanaToken2022ExtensionTask", + "switchboard_surge_task", + "switchboardSurgeTask", + ]; + + #[allow(clippy::enum_variant_names)] + enum GeneratedField { + HttpTask, + JsonParseTask, + MedianTask, + MeanTask, + WebsocketTask, + DivideTask, + MultiplyTask, + LpTokenPriceTask, + LpExchangeRateTask, + ConditionalTask, + ValueTask, + MaxTask, + RegexExtractTask, + XstepPriceTask, + AddTask, + SubtractTask, + TwapTask, + SerumSwapTask, + PowTask, + LendingRateTask, + MangoPerpMarketTask, + JupiterSwapTask, + PerpMarketTask, + OracleTask, + AnchorFetchTask, + SplStakePoolTask, + SplTokenParseTask, + UniswapExchangeRateTask, + SushiswapExchangeRateTask, + PancakeswapExchangeRateTask, + CacheTask, + SysclockOffsetTask, + MarinadeStateTask, + SolanaAccountDataFetchTask, + BufferLayoutParseTask, + CronParseTask, + MinTask, + HistoryFunctionTask, + VwapTask, + EwmaTask, + ComparisonTask, + RoundTask, + BoundTask, + SecretsTask, + SanctumLstPriceTask, + OndoUsdyTask, + MeteoraSwapTask, + UnixTimeTask, + MapleFinanceTask, + GlyphTask, + CorexTask, + LlmTask, + SolayerSusdTask, + CurveFinanceTask, + TurboEthRedemptionRateTask, + BitFluxTask, + FragmetricTask, + AftermathTask, + EtherfuseTask, + LstHistoricalYieldTask, + PumpAmmTask, + PumpAmmLpTokenPriceTask, + ExponentTask, + ExponentPtLinearPricingTask, + SolanaToken2022ExtensionTask, + SwitchboardSurgeTask, + } + 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 { + "httpTask" | "http_task" => Ok(GeneratedField::HttpTask), + "jsonParseTask" | "json_parse_task" => Ok(GeneratedField::JsonParseTask), + "medianTask" | "median_task" => Ok(GeneratedField::MedianTask), + "meanTask" | "mean_task" => Ok(GeneratedField::MeanTask), + "websocketTask" | "websocket_task" => Ok(GeneratedField::WebsocketTask), + "divideTask" | "divide_task" => Ok(GeneratedField::DivideTask), + "multiplyTask" | "multiply_task" => Ok(GeneratedField::MultiplyTask), + "lpTokenPriceTask" | "lp_token_price_task" => Ok(GeneratedField::LpTokenPriceTask), + "lpExchangeRateTask" | "lp_exchange_rate_task" => Ok(GeneratedField::LpExchangeRateTask), + "conditionalTask" | "conditional_task" => Ok(GeneratedField::ConditionalTask), + "valueTask" | "value_task" => Ok(GeneratedField::ValueTask), + "maxTask" | "max_task" => Ok(GeneratedField::MaxTask), + "regexExtractTask" | "regex_extract_task" => Ok(GeneratedField::RegexExtractTask), + "xstepPriceTask" | "xstep_price_task" => Ok(GeneratedField::XstepPriceTask), + "addTask" | "add_task" => Ok(GeneratedField::AddTask), + "subtractTask" | "subtract_task" => Ok(GeneratedField::SubtractTask), + "twapTask" | "twap_task" => Ok(GeneratedField::TwapTask), + "serumSwapTask" | "serum_swap_task" => Ok(GeneratedField::SerumSwapTask), + "powTask" | "pow_task" => Ok(GeneratedField::PowTask), + "lendingRateTask" | "lending_rate_task" => Ok(GeneratedField::LendingRateTask), + "mangoPerpMarketTask" | "mango_perp_market_task" => Ok(GeneratedField::MangoPerpMarketTask), + "jupiterSwapTask" | "jupiter_swap_task" => Ok(GeneratedField::JupiterSwapTask), + "perpMarketTask" | "perp_market_task" => Ok(GeneratedField::PerpMarketTask), + "oracleTask" | "oracle_task" => Ok(GeneratedField::OracleTask), + "anchorFetchTask" | "anchor_fetch_task" => Ok(GeneratedField::AnchorFetchTask), + "splStakePoolTask" | "spl_stake_pool_task" => Ok(GeneratedField::SplStakePoolTask), + "splTokenParseTask" | "spl_token_parse_task" => Ok(GeneratedField::SplTokenParseTask), + "uniswapExchangeRateTask" | "uniswap_exchange_rate_task" => Ok(GeneratedField::UniswapExchangeRateTask), + "sushiswapExchangeRateTask" | "sushiswap_exchange_rate_task" => Ok(GeneratedField::SushiswapExchangeRateTask), + "pancakeswapExchangeRateTask" | "pancakeswap_exchange_rate_task" => Ok(GeneratedField::PancakeswapExchangeRateTask), + "cacheTask" | "cache_task" => Ok(GeneratedField::CacheTask), + "sysclockOffsetTask" | "sysclock_offset_task" => Ok(GeneratedField::SysclockOffsetTask), + "marinadeStateTask" | "marinade_state_task" => Ok(GeneratedField::MarinadeStateTask), + "solanaAccountDataFetchTask" | "solana_account_data_fetch_task" => Ok(GeneratedField::SolanaAccountDataFetchTask), + "bufferLayoutParseTask" | "buffer_layout_parse_task" => Ok(GeneratedField::BufferLayoutParseTask), + "cronParseTask" | "cron_parse_task" => Ok(GeneratedField::CronParseTask), + "minTask" | "min_task" => Ok(GeneratedField::MinTask), + "historyFunctionTask" | "history_function_task" => Ok(GeneratedField::HistoryFunctionTask), + "vwapTask" | "vwap_task" => Ok(GeneratedField::VwapTask), + "ewmaTask" | "ewma_task" => Ok(GeneratedField::EwmaTask), + "comparisonTask" | "comparison_task" => Ok(GeneratedField::ComparisonTask), + "roundTask" | "round_task" => Ok(GeneratedField::RoundTask), + "boundTask" | "bound_task" => Ok(GeneratedField::BoundTask), + "secretsTask" | "secrets_task" => Ok(GeneratedField::SecretsTask), + "sanctumLstPriceTask" | "sanctum_lst_price_task" => Ok(GeneratedField::SanctumLstPriceTask), + "ondoUsdyTask" | "ondo_usdy_task" => Ok(GeneratedField::OndoUsdyTask), + "meteoraSwapTask" | "meteora_swap_task" => Ok(GeneratedField::MeteoraSwapTask), + "unixTimeTask" | "unix_time_task" => Ok(GeneratedField::UnixTimeTask), + "mapleFinanceTask" | "maple_finance_task" => Ok(GeneratedField::MapleFinanceTask), + "glyphTask" | "glyph_task" => Ok(GeneratedField::GlyphTask), + "corexTask" | "corex_task" => Ok(GeneratedField::CorexTask), + "llmTask" | "llm_task" => Ok(GeneratedField::LlmTask), + "solayerSusdTask" | "solayer_susd_task" => Ok(GeneratedField::SolayerSusdTask), + "curveFinanceTask" | "curve_finance_task" => Ok(GeneratedField::CurveFinanceTask), + "turboEthRedemptionRateTask" | "turbo_eth_redemption_rate_task" => Ok(GeneratedField::TurboEthRedemptionRateTask), + "bitFluxTask" | "bit_flux_task" => Ok(GeneratedField::BitFluxTask), + "fragmetricTask" | "fragmetric_task" => Ok(GeneratedField::FragmetricTask), + "aftermathTask" | "aftermath_task" => Ok(GeneratedField::AftermathTask), + "etherfuseTask" | "etherfuse_task" => Ok(GeneratedField::EtherfuseTask), + "lstHistoricalYieldTask" | "lst_historical_yield_task" => Ok(GeneratedField::LstHistoricalYieldTask), + "pumpAmmTask" | "pump_amm_task" => Ok(GeneratedField::PumpAmmTask), + "pumpAmmLpTokenPriceTask" | "pump_amm_lp_token_price_task" => Ok(GeneratedField::PumpAmmLpTokenPriceTask), + "exponentTask" | "exponent_task" => Ok(GeneratedField::ExponentTask), + "exponentPtLinearPricingTask" | "exponent_pt_linear_pricing_task" => Ok(GeneratedField::ExponentPtLinearPricingTask), + "solanaToken2022ExtensionTask" | "solana_token_2022_extension_task" => Ok(GeneratedField::SolanaToken2022ExtensionTask), + "switchboardSurgeTask" | "switchboard_surge_task" => Ok(GeneratedField::SwitchboardSurgeTask), + _ => Err(serde::de::Error::unknown_field(value, FIELDS)), + } + } + } + deserializer.deserialize_identifier(GeneratedVisitor) + } + } + struct GeneratedVisitor; + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = oracle_job::Task; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("struct oracle_job.OracleJob.Task") + } + + fn visit_map(self, mut map_: V) -> std::result::Result + where + V: serde::de::MapAccess<'de>, + { + let mut task__ = None; + while let Some(k) = map_.next_key()? { + match k { + GeneratedField::HttpTask => { + if task__.is_some() { + return Err(serde::de::Error::duplicate_field("httpTask")); + } + task__ = map_.next_value::<::std::option::Option<_>>()?.map(oracle_job::task::Task::HttpTask) +; + } + GeneratedField::JsonParseTask => { + if task__.is_some() { + return Err(serde::de::Error::duplicate_field("jsonParseTask")); + } + task__ = map_.next_value::<::std::option::Option<_>>()?.map(oracle_job::task::Task::JsonParseTask) +; + } + GeneratedField::MedianTask => { + if task__.is_some() { + return Err(serde::de::Error::duplicate_field("medianTask")); + } + task__ = map_.next_value::<::std::option::Option<_>>()?.map(oracle_job::task::Task::MedianTask) +; + } + GeneratedField::MeanTask => { + if task__.is_some() { + return Err(serde::de::Error::duplicate_field("meanTask")); + } + task__ = map_.next_value::<::std::option::Option<_>>()?.map(oracle_job::task::Task::MeanTask) +; + } + GeneratedField::WebsocketTask => { + if task__.is_some() { + return Err(serde::de::Error::duplicate_field("websocketTask")); + } + task__ = map_.next_value::<::std::option::Option<_>>()?.map(oracle_job::task::Task::WebsocketTask) +; + } + GeneratedField::DivideTask => { + if task__.is_some() { + return Err(serde::de::Error::duplicate_field("divideTask")); + } + task__ = map_.next_value::<::std::option::Option<_>>()?.map(oracle_job::task::Task::DivideTask) +; + } + GeneratedField::MultiplyTask => { + if task__.is_some() { + return Err(serde::de::Error::duplicate_field("multiplyTask")); + } + task__ = map_.next_value::<::std::option::Option<_>>()?.map(oracle_job::task::Task::MultiplyTask) +; + } + GeneratedField::LpTokenPriceTask => { + if task__.is_some() { + return Err(serde::de::Error::duplicate_field("lpTokenPriceTask")); + } + task__ = map_.next_value::<::std::option::Option<_>>()?.map(oracle_job::task::Task::LpTokenPriceTask) +; + } + GeneratedField::LpExchangeRateTask => { + if task__.is_some() { + return Err(serde::de::Error::duplicate_field("lpExchangeRateTask")); + } + task__ = map_.next_value::<::std::option::Option<_>>()?.map(oracle_job::task::Task::LpExchangeRateTask) +; + } + GeneratedField::ConditionalTask => { + if task__.is_some() { + return Err(serde::de::Error::duplicate_field("conditionalTask")); + } + task__ = map_.next_value::<::std::option::Option<_>>()?.map(oracle_job::task::Task::ConditionalTask) +; + } + GeneratedField::ValueTask => { + if task__.is_some() { + return Err(serde::de::Error::duplicate_field("valueTask")); + } + task__ = map_.next_value::<::std::option::Option<_>>()?.map(oracle_job::task::Task::ValueTask) +; + } + GeneratedField::MaxTask => { + if task__.is_some() { + return Err(serde::de::Error::duplicate_field("maxTask")); + } + task__ = map_.next_value::<::std::option::Option<_>>()?.map(oracle_job::task::Task::MaxTask) +; + } + GeneratedField::RegexExtractTask => { + if task__.is_some() { + return Err(serde::de::Error::duplicate_field("regexExtractTask")); + } + task__ = map_.next_value::<::std::option::Option<_>>()?.map(oracle_job::task::Task::RegexExtractTask) +; + } + GeneratedField::XstepPriceTask => { + if task__.is_some() { + return Err(serde::de::Error::duplicate_field("xstepPriceTask")); + } + task__ = map_.next_value::<::std::option::Option<_>>()?.map(oracle_job::task::Task::XstepPriceTask) +; + } + GeneratedField::AddTask => { + if task__.is_some() { + return Err(serde::de::Error::duplicate_field("addTask")); + } + task__ = map_.next_value::<::std::option::Option<_>>()?.map(oracle_job::task::Task::AddTask) +; + } + GeneratedField::SubtractTask => { + if task__.is_some() { + return Err(serde::de::Error::duplicate_field("subtractTask")); + } + task__ = map_.next_value::<::std::option::Option<_>>()?.map(oracle_job::task::Task::SubtractTask) +; + } + GeneratedField::TwapTask => { + if task__.is_some() { + return Err(serde::de::Error::duplicate_field("twapTask")); + } + task__ = map_.next_value::<::std::option::Option<_>>()?.map(oracle_job::task::Task::TwapTask) +; + } + GeneratedField::SerumSwapTask => { + if task__.is_some() { + return Err(serde::de::Error::duplicate_field("serumSwapTask")); + } + task__ = map_.next_value::<::std::option::Option<_>>()?.map(oracle_job::task::Task::SerumSwapTask) +; + } + GeneratedField::PowTask => { + if task__.is_some() { + return Err(serde::de::Error::duplicate_field("powTask")); + } + task__ = map_.next_value::<::std::option::Option<_>>()?.map(oracle_job::task::Task::PowTask) +; + } + GeneratedField::LendingRateTask => { + if task__.is_some() { + return Err(serde::de::Error::duplicate_field("lendingRateTask")); + } + task__ = map_.next_value::<::std::option::Option<_>>()?.map(oracle_job::task::Task::LendingRateTask) +; + } + GeneratedField::MangoPerpMarketTask => { + if task__.is_some() { + return Err(serde::de::Error::duplicate_field("mangoPerpMarketTask")); + } + task__ = map_.next_value::<::std::option::Option<_>>()?.map(oracle_job::task::Task::MangoPerpMarketTask) +; + } + GeneratedField::JupiterSwapTask => { + if task__.is_some() { + return Err(serde::de::Error::duplicate_field("jupiterSwapTask")); + } + task__ = map_.next_value::<::std::option::Option<_>>()?.map(oracle_job::task::Task::JupiterSwapTask) +; + } + GeneratedField::PerpMarketTask => { + if task__.is_some() { + return Err(serde::de::Error::duplicate_field("perpMarketTask")); + } + task__ = map_.next_value::<::std::option::Option<_>>()?.map(oracle_job::task::Task::PerpMarketTask) +; + } + GeneratedField::OracleTask => { + if task__.is_some() { + return Err(serde::de::Error::duplicate_field("oracleTask")); + } + task__ = map_.next_value::<::std::option::Option<_>>()?.map(oracle_job::task::Task::OracleTask) +; + } + GeneratedField::AnchorFetchTask => { + if task__.is_some() { + return Err(serde::de::Error::duplicate_field("anchorFetchTask")); + } + task__ = map_.next_value::<::std::option::Option<_>>()?.map(oracle_job::task::Task::AnchorFetchTask) +; + } + GeneratedField::SplStakePoolTask => { + if task__.is_some() { + return Err(serde::de::Error::duplicate_field("splStakePoolTask")); + } + task__ = map_.next_value::<::std::option::Option<_>>()?.map(oracle_job::task::Task::SplStakePoolTask) +; + } + GeneratedField::SplTokenParseTask => { + if task__.is_some() { + return Err(serde::de::Error::duplicate_field("splTokenParseTask")); + } + task__ = map_.next_value::<::std::option::Option<_>>()?.map(oracle_job::task::Task::SplTokenParseTask) +; + } + GeneratedField::UniswapExchangeRateTask => { + if task__.is_some() { + return Err(serde::de::Error::duplicate_field("uniswapExchangeRateTask")); + } + task__ = map_.next_value::<::std::option::Option<_>>()?.map(oracle_job::task::Task::UniswapExchangeRateTask) +; + } + GeneratedField::SushiswapExchangeRateTask => { + if task__.is_some() { + return Err(serde::de::Error::duplicate_field("sushiswapExchangeRateTask")); + } + task__ = map_.next_value::<::std::option::Option<_>>()?.map(oracle_job::task::Task::SushiswapExchangeRateTask) +; + } + GeneratedField::PancakeswapExchangeRateTask => { + if task__.is_some() { + return Err(serde::de::Error::duplicate_field("pancakeswapExchangeRateTask")); + } + task__ = map_.next_value::<::std::option::Option<_>>()?.map(oracle_job::task::Task::PancakeswapExchangeRateTask) +; + } + GeneratedField::CacheTask => { + if task__.is_some() { + return Err(serde::de::Error::duplicate_field("cacheTask")); + } + task__ = map_.next_value::<::std::option::Option<_>>()?.map(oracle_job::task::Task::CacheTask) +; + } + GeneratedField::SysclockOffsetTask => { + if task__.is_some() { + return Err(serde::de::Error::duplicate_field("sysclockOffsetTask")); + } + task__ = map_.next_value::<::std::option::Option<_>>()?.map(oracle_job::task::Task::SysclockOffsetTask) +; + } + GeneratedField::MarinadeStateTask => { + if task__.is_some() { + return Err(serde::de::Error::duplicate_field("marinadeStateTask")); + } + task__ = map_.next_value::<::std::option::Option<_>>()?.map(oracle_job::task::Task::MarinadeStateTask) +; + } + GeneratedField::SolanaAccountDataFetchTask => { + if task__.is_some() { + return Err(serde::de::Error::duplicate_field("solanaAccountDataFetchTask")); + } + task__ = map_.next_value::<::std::option::Option<_>>()?.map(oracle_job::task::Task::SolanaAccountDataFetchTask) +; + } + GeneratedField::BufferLayoutParseTask => { + if task__.is_some() { + return Err(serde::de::Error::duplicate_field("bufferLayoutParseTask")); + } + task__ = map_.next_value::<::std::option::Option<_>>()?.map(oracle_job::task::Task::BufferLayoutParseTask) +; + } + GeneratedField::CronParseTask => { + if task__.is_some() { + return Err(serde::de::Error::duplicate_field("cronParseTask")); + } + task__ = map_.next_value::<::std::option::Option<_>>()?.map(oracle_job::task::Task::CronParseTask) +; + } + GeneratedField::MinTask => { + if task__.is_some() { + return Err(serde::de::Error::duplicate_field("minTask")); + } + task__ = map_.next_value::<::std::option::Option<_>>()?.map(oracle_job::task::Task::MinTask) +; + } + GeneratedField::HistoryFunctionTask => { + if task__.is_some() { + return Err(serde::de::Error::duplicate_field("historyFunctionTask")); + } + task__ = map_.next_value::<::std::option::Option<_>>()?.map(oracle_job::task::Task::HistoryFunctionTask) +; + } + GeneratedField::VwapTask => { + if task__.is_some() { + return Err(serde::de::Error::duplicate_field("vwapTask")); + } + task__ = map_.next_value::<::std::option::Option<_>>()?.map(oracle_job::task::Task::VwapTask) +; + } + GeneratedField::EwmaTask => { + if task__.is_some() { + return Err(serde::de::Error::duplicate_field("ewmaTask")); + } + task__ = map_.next_value::<::std::option::Option<_>>()?.map(oracle_job::task::Task::EwmaTask) +; + } + GeneratedField::ComparisonTask => { + if task__.is_some() { + return Err(serde::de::Error::duplicate_field("comparisonTask")); + } + task__ = map_.next_value::<::std::option::Option<_>>()?.map(oracle_job::task::Task::ComparisonTask) +; + } + GeneratedField::RoundTask => { + if task__.is_some() { + return Err(serde::de::Error::duplicate_field("roundTask")); + } + task__ = map_.next_value::<::std::option::Option<_>>()?.map(oracle_job::task::Task::RoundTask) +; + } + GeneratedField::BoundTask => { + if task__.is_some() { + return Err(serde::de::Error::duplicate_field("boundTask")); + } + task__ = map_.next_value::<::std::option::Option<_>>()?.map(oracle_job::task::Task::BoundTask) +; + } + GeneratedField::SecretsTask => { + if task__.is_some() { + return Err(serde::de::Error::duplicate_field("secretsTask")); + } + task__ = map_.next_value::<::std::option::Option<_>>()?.map(oracle_job::task::Task::SecretsTask) +; + } + GeneratedField::SanctumLstPriceTask => { + if task__.is_some() { + return Err(serde::de::Error::duplicate_field("sanctumLstPriceTask")); + } + task__ = map_.next_value::<::std::option::Option<_>>()?.map(oracle_job::task::Task::SanctumLstPriceTask) +; + } + GeneratedField::OndoUsdyTask => { + if task__.is_some() { + return Err(serde::de::Error::duplicate_field("ondoUsdyTask")); + } + task__ = map_.next_value::<::std::option::Option<_>>()?.map(oracle_job::task::Task::OndoUsdyTask) +; + } + GeneratedField::MeteoraSwapTask => { + if task__.is_some() { + return Err(serde::de::Error::duplicate_field("meteoraSwapTask")); + } + task__ = map_.next_value::<::std::option::Option<_>>()?.map(oracle_job::task::Task::MeteoraSwapTask) +; + } + GeneratedField::UnixTimeTask => { + if task__.is_some() { + return Err(serde::de::Error::duplicate_field("unixTimeTask")); + } + task__ = map_.next_value::<::std::option::Option<_>>()?.map(oracle_job::task::Task::UnixTimeTask) +; + } + GeneratedField::MapleFinanceTask => { + if task__.is_some() { + return Err(serde::de::Error::duplicate_field("mapleFinanceTask")); + } + task__ = map_.next_value::<::std::option::Option<_>>()?.map(oracle_job::task::Task::MapleFinanceTask) +; + } + GeneratedField::GlyphTask => { + if task__.is_some() { + return Err(serde::de::Error::duplicate_field("glyphTask")); + } + task__ = map_.next_value::<::std::option::Option<_>>()?.map(oracle_job::task::Task::GlyphTask) +; + } + GeneratedField::CorexTask => { + if task__.is_some() { + return Err(serde::de::Error::duplicate_field("corexTask")); + } + task__ = map_.next_value::<::std::option::Option<_>>()?.map(oracle_job::task::Task::CorexTask) +; + } + GeneratedField::LlmTask => { + if task__.is_some() { + return Err(serde::de::Error::duplicate_field("llmTask")); + } + task__ = map_.next_value::<::std::option::Option<_>>()?.map(oracle_job::task::Task::LlmTask) +; + } + GeneratedField::SolayerSusdTask => { + if task__.is_some() { + return Err(serde::de::Error::duplicate_field("solayerSusdTask")); + } + task__ = map_.next_value::<::std::option::Option<_>>()?.map(oracle_job::task::Task::SolayerSusdTask) +; + } + GeneratedField::CurveFinanceTask => { + if task__.is_some() { + return Err(serde::de::Error::duplicate_field("curveFinanceTask")); + } + task__ = map_.next_value::<::std::option::Option<_>>()?.map(oracle_job::task::Task::CurveFinanceTask) +; + } + GeneratedField::TurboEthRedemptionRateTask => { + if task__.is_some() { + return Err(serde::de::Error::duplicate_field("turboEthRedemptionRateTask")); + } + task__ = map_.next_value::<::std::option::Option<_>>()?.map(oracle_job::task::Task::TurboEthRedemptionRateTask) +; + } + GeneratedField::BitFluxTask => { + if task__.is_some() { + return Err(serde::de::Error::duplicate_field("bitFluxTask")); + } + task__ = map_.next_value::<::std::option::Option<_>>()?.map(oracle_job::task::Task::BitFluxTask) +; + } + GeneratedField::FragmetricTask => { + if task__.is_some() { + return Err(serde::de::Error::duplicate_field("fragmetricTask")); + } + task__ = map_.next_value::<::std::option::Option<_>>()?.map(oracle_job::task::Task::FragmetricTask) +; + } + GeneratedField::AftermathTask => { + if task__.is_some() { + return Err(serde::de::Error::duplicate_field("aftermathTask")); + } + task__ = map_.next_value::<::std::option::Option<_>>()?.map(oracle_job::task::Task::AftermathTask) +; + } + GeneratedField::EtherfuseTask => { + if task__.is_some() { + return Err(serde::de::Error::duplicate_field("etherfuseTask")); + } + task__ = map_.next_value::<::std::option::Option<_>>()?.map(oracle_job::task::Task::EtherfuseTask) +; + } + GeneratedField::LstHistoricalYieldTask => { + if task__.is_some() { + return Err(serde::de::Error::duplicate_field("lstHistoricalYieldTask")); + } + task__ = map_.next_value::<::std::option::Option<_>>()?.map(oracle_job::task::Task::LstHistoricalYieldTask) +; + } + GeneratedField::PumpAmmTask => { + if task__.is_some() { + return Err(serde::de::Error::duplicate_field("pumpAmmTask")); + } + task__ = map_.next_value::<::std::option::Option<_>>()?.map(oracle_job::task::Task::PumpAmmTask) +; + } + GeneratedField::PumpAmmLpTokenPriceTask => { + if task__.is_some() { + return Err(serde::de::Error::duplicate_field("pumpAmmLpTokenPriceTask")); + } + task__ = map_.next_value::<::std::option::Option<_>>()?.map(oracle_job::task::Task::PumpAmmLpTokenPriceTask) +; + } + GeneratedField::ExponentTask => { + if task__.is_some() { + return Err(serde::de::Error::duplicate_field("exponentTask")); + } + task__ = map_.next_value::<::std::option::Option<_>>()?.map(oracle_job::task::Task::ExponentTask) +; + } + GeneratedField::ExponentPtLinearPricingTask => { + if task__.is_some() { + return Err(serde::de::Error::duplicate_field("exponentPtLinearPricingTask")); + } + task__ = map_.next_value::<::std::option::Option<_>>()?.map(oracle_job::task::Task::ExponentPtLinearPricingTask) +; + } + GeneratedField::SolanaToken2022ExtensionTask => { + if task__.is_some() { + return Err(serde::de::Error::duplicate_field("solanaToken2022ExtensionTask")); + } + task__ = map_.next_value::<::std::option::Option<_>>()?.map(oracle_job::task::Task::SolanaToken2022ExtensionTask) +; + } + GeneratedField::SwitchboardSurgeTask => { + if task__.is_some() { + return Err(serde::de::Error::duplicate_field("switchboardSurgeTask")); + } + task__ = map_.next_value::<::std::option::Option<_>>()?.map(oracle_job::task::Task::SwitchboardSurgeTask) +; + } + } + } + Ok(oracle_job::Task { + task: task__, + }) + } + } + deserializer.deserialize_struct("oracle_job.OracleJob.Task", FIELDS, GeneratedVisitor) + } +} +impl serde::Serialize for oracle_job::TurboEthRedemptionRateTask { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + use serde::ser::SerializeStruct; + let mut len = 0; + if self.provider.is_some() { + len += 1; + } + let mut struct_ser = serializer.serialize_struct("oracle_job.OracleJob.TurboEthRedemptionRateTask", len)?; + if let Some(v) = self.provider.as_ref() { + struct_ser.serialize_field("provider", v)?; + } + struct_ser.end() + } +} +impl<'de> serde::Deserialize<'de> for oracle_job::TurboEthRedemptionRateTask { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &[ + "provider", + ]; + + #[allow(clippy::enum_variant_names)] + enum GeneratedField { + Provider, + } + 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 { + "provider" => Ok(GeneratedField::Provider), + _ => Err(serde::de::Error::unknown_field(value, FIELDS)), + } + } + } + deserializer.deserialize_identifier(GeneratedVisitor) + } + } + struct GeneratedVisitor; + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = oracle_job::TurboEthRedemptionRateTask; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("struct oracle_job.OracleJob.TurboEthRedemptionRateTask") + } + + fn visit_map(self, mut map_: V) -> std::result::Result + where + V: serde::de::MapAccess<'de>, + { + let mut provider__ = None; + while let Some(k) = map_.next_key()? { + match k { + GeneratedField::Provider => { + if provider__.is_some() { + return Err(serde::de::Error::duplicate_field("provider")); + } + provider__ = map_.next_value()?; + } + } + } + Ok(oracle_job::TurboEthRedemptionRateTask { + provider: provider__, + }) + } + } + deserializer.deserialize_struct("oracle_job.OracleJob.TurboEthRedemptionRateTask", FIELDS, GeneratedVisitor) + } +} +impl serde::Serialize for oracle_job::TwapTask { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + use serde::ser::SerializeStruct; + let mut len = 0; + if self.aggregator_pubkey.is_some() { + len += 1; + } + if self.period.is_some() { + len += 1; + } + if self.weight_by_propagation_time.is_some() { + len += 1; + } + if self.min_samples.is_some() { + len += 1; + } + if self.ending_unix_timestamp.is_some() { + len += 1; + } + if self.ending_unix_timestamp_task.is_some() { + len += 1; + } + let mut struct_ser = serializer.serialize_struct("oracle_job.OracleJob.TwapTask", len)?; + if let Some(v) = self.aggregator_pubkey.as_ref() { + struct_ser.serialize_field("aggregatorPubkey", v)?; + } + if let Some(v) = self.period.as_ref() { + struct_ser.serialize_field("period", v)?; + } + if let Some(v) = self.weight_by_propagation_time.as_ref() { + struct_ser.serialize_field("weightByPropagationTime", v)?; + } + if let Some(v) = self.min_samples.as_ref() { + struct_ser.serialize_field("minSamples", v)?; + } + if let Some(v) = self.ending_unix_timestamp.as_ref() { + struct_ser.serialize_field("endingUnixTimestamp", v)?; + } + if let Some(v) = self.ending_unix_timestamp_task.as_ref() { + struct_ser.serialize_field("endingUnixTimestampTask", v)?; + } + struct_ser.end() + } +} +impl<'de> serde::Deserialize<'de> for oracle_job::TwapTask { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &[ + "aggregator_pubkey", + "aggregatorPubkey", + "period", + "weight_by_propagation_time", + "weightByPropagationTime", + "min_samples", + "minSamples", + "ending_unix_timestamp", + "endingUnixTimestamp", + "ending_unix_timestamp_task", + "endingUnixTimestampTask", + ]; + + #[allow(clippy::enum_variant_names)] + enum GeneratedField { + AggregatorPubkey, + Period, + WeightByPropagationTime, + MinSamples, + EndingUnixTimestamp, + EndingUnixTimestampTask, + } + 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 { + "aggregatorPubkey" | "aggregator_pubkey" => Ok(GeneratedField::AggregatorPubkey), + "period" => Ok(GeneratedField::Period), + "weightByPropagationTime" | "weight_by_propagation_time" => Ok(GeneratedField::WeightByPropagationTime), + "minSamples" | "min_samples" => Ok(GeneratedField::MinSamples), + "endingUnixTimestamp" | "ending_unix_timestamp" => Ok(GeneratedField::EndingUnixTimestamp), + "endingUnixTimestampTask" | "ending_unix_timestamp_task" => Ok(GeneratedField::EndingUnixTimestampTask), + _ => Err(serde::de::Error::unknown_field(value, FIELDS)), + } + } + } + deserializer.deserialize_identifier(GeneratedVisitor) + } + } + struct GeneratedVisitor; + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = oracle_job::TwapTask; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("struct oracle_job.OracleJob.TwapTask") + } + + fn visit_map(self, mut map_: V) -> std::result::Result + where + V: serde::de::MapAccess<'de>, + { + let mut aggregator_pubkey__ = None; + let mut period__ = None; + let mut weight_by_propagation_time__ = None; + let mut min_samples__ = None; + let mut ending_unix_timestamp__ = None; + let mut ending_unix_timestamp_task__ = None; + while let Some(k) = map_.next_key()? { + match k { + GeneratedField::AggregatorPubkey => { + if aggregator_pubkey__.is_some() { + return Err(serde::de::Error::duplicate_field("aggregatorPubkey")); + } + aggregator_pubkey__ = map_.next_value()?; + } + GeneratedField::Period => { + if period__.is_some() { + return Err(serde::de::Error::duplicate_field("period")); + } + period__ = + map_.next_value::<::std::option::Option<::pbjson::private::NumberDeserialize<_>>>()?.map(|x| x.0) + ; + } + GeneratedField::WeightByPropagationTime => { + if weight_by_propagation_time__.is_some() { + return Err(serde::de::Error::duplicate_field("weightByPropagationTime")); + } + weight_by_propagation_time__ = map_.next_value()?; + } + GeneratedField::MinSamples => { + if min_samples__.is_some() { + return Err(serde::de::Error::duplicate_field("minSamples")); + } + min_samples__ = + map_.next_value::<::std::option::Option<::pbjson::private::NumberDeserialize<_>>>()?.map(|x| x.0) + ; + } + GeneratedField::EndingUnixTimestamp => { + if ending_unix_timestamp__.is_some() { + return Err(serde::de::Error::duplicate_field("endingUnixTimestamp")); + } + ending_unix_timestamp__ = + map_.next_value::<::std::option::Option<::pbjson::private::NumberDeserialize<_>>>()?.map(|x| x.0) + ; + } + GeneratedField::EndingUnixTimestampTask => { + if ending_unix_timestamp_task__.is_some() { + return Err(serde::de::Error::duplicate_field("endingUnixTimestampTask")); + } + ending_unix_timestamp_task__ = map_.next_value()?; + } + } + } + Ok(oracle_job::TwapTask { + aggregator_pubkey: aggregator_pubkey__, + period: period__, + weight_by_propagation_time: weight_by_propagation_time__, + min_samples: min_samples__, + ending_unix_timestamp: ending_unix_timestamp__, + ending_unix_timestamp_task: ending_unix_timestamp_task__, + }) + } + } + deserializer.deserialize_struct("oracle_job.OracleJob.TwapTask", FIELDS, GeneratedVisitor) + } +} +impl serde::Serialize for oracle_job::UniswapExchangeRateTask { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + use serde::ser::SerializeStruct; + let mut len = 0; + if self.in_token_address.is_some() { + len += 1; + } + if self.out_token_address.is_some() { + len += 1; + } + if self.in_token_amount.is_some() { + len += 1; + } + if self.slippage.is_some() { + len += 1; + } + if self.provider.is_some() { + len += 1; + } + if self.version.is_some() { + len += 1; + } + if self.router_address.is_some() { + len += 1; + } + if self.factory_address.is_some() { + len += 1; + } + if self.quoter_address.is_some() { + len += 1; + } + let mut struct_ser = serializer.serialize_struct("oracle_job.OracleJob.UniswapExchangeRateTask", len)?; + if let Some(v) = self.in_token_address.as_ref() { + struct_ser.serialize_field("inTokenAddress", v)?; + } + if let Some(v) = self.out_token_address.as_ref() { + struct_ser.serialize_field("outTokenAddress", v)?; + } + if let Some(v) = self.in_token_amount.as_ref() { + struct_ser.serialize_field("inTokenAmount", v)?; + } + if let Some(v) = self.slippage.as_ref() { + struct_ser.serialize_field("slippage", v)?; + } + if let Some(v) = self.provider.as_ref() { + struct_ser.serialize_field("provider", v)?; + } + if let Some(v) = self.version.as_ref() { + let v = oracle_job::uniswap_exchange_rate_task::Version::try_from(*v) + .map_err(|_| serde::ser::Error::custom(format!("Invalid variant {}", *v)))?; + struct_ser.serialize_field("version", &v)?; + } + if let Some(v) = self.router_address.as_ref() { + struct_ser.serialize_field("routerAddress", v)?; + } + if let Some(v) = self.factory_address.as_ref() { + struct_ser.serialize_field("factoryAddress", v)?; + } + if let Some(v) = self.quoter_address.as_ref() { + struct_ser.serialize_field("quoterAddress", v)?; + } + struct_ser.end() + } +} +impl<'de> serde::Deserialize<'de> for oracle_job::UniswapExchangeRateTask { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &[ + "in_token_address", + "inTokenAddress", + "out_token_address", + "outTokenAddress", + "in_token_amount", + "inTokenAmount", + "slippage", + "provider", + "version", + "router_address", + "routerAddress", + "factory_address", + "factoryAddress", + "quoter_address", + "quoterAddress", + ]; + + #[allow(clippy::enum_variant_names)] + enum GeneratedField { + InTokenAddress, + OutTokenAddress, + InTokenAmount, + Slippage, + Provider, + Version, + RouterAddress, + FactoryAddress, + QuoterAddress, + } + 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 { + "inTokenAddress" | "in_token_address" => Ok(GeneratedField::InTokenAddress), + "outTokenAddress" | "out_token_address" => Ok(GeneratedField::OutTokenAddress), + "inTokenAmount" | "in_token_amount" => Ok(GeneratedField::InTokenAmount), + "slippage" => Ok(GeneratedField::Slippage), + "provider" => Ok(GeneratedField::Provider), + "version" => Ok(GeneratedField::Version), + "routerAddress" | "router_address" => Ok(GeneratedField::RouterAddress), + "factoryAddress" | "factory_address" => Ok(GeneratedField::FactoryAddress), + "quoterAddress" | "quoter_address" => Ok(GeneratedField::QuoterAddress), + _ => Err(serde::de::Error::unknown_field(value, FIELDS)), + } + } + } + deserializer.deserialize_identifier(GeneratedVisitor) + } + } + struct GeneratedVisitor; + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = oracle_job::UniswapExchangeRateTask; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("struct oracle_job.OracleJob.UniswapExchangeRateTask") + } + + fn visit_map(self, mut map_: V) -> std::result::Result + where + V: serde::de::MapAccess<'de>, + { + let mut in_token_address__ = None; + let mut out_token_address__ = None; + let mut in_token_amount__ = None; + let mut slippage__ = None; + let mut provider__ = None; + let mut version__ = None; + let mut router_address__ = None; + let mut factory_address__ = None; + let mut quoter_address__ = None; + while let Some(k) = map_.next_key()? { + match k { + GeneratedField::InTokenAddress => { + if in_token_address__.is_some() { + return Err(serde::de::Error::duplicate_field("inTokenAddress")); + } + in_token_address__ = map_.next_value()?; + } + GeneratedField::OutTokenAddress => { + if out_token_address__.is_some() { + return Err(serde::de::Error::duplicate_field("outTokenAddress")); + } + out_token_address__ = map_.next_value()?; + } + GeneratedField::InTokenAmount => { + if in_token_amount__.is_some() { + return Err(serde::de::Error::duplicate_field("inTokenAmount")); + } + in_token_amount__ = + map_.next_value::<::std::option::Option<::pbjson::private::NumberDeserialize<_>>>()?.map(|x| x.0) + ; + } + GeneratedField::Slippage => { + if slippage__.is_some() { + return Err(serde::de::Error::duplicate_field("slippage")); + } + slippage__ = + map_.next_value::<::std::option::Option<::pbjson::private::NumberDeserialize<_>>>()?.map(|x| x.0) + ; + } + GeneratedField::Provider => { + if provider__.is_some() { + return Err(serde::de::Error::duplicate_field("provider")); + } + provider__ = map_.next_value()?; + } + GeneratedField::Version => { + if version__.is_some() { + return Err(serde::de::Error::duplicate_field("version")); + } + version__ = map_.next_value::<::std::option::Option>()?.map(|x| x as i32); + } + GeneratedField::RouterAddress => { + if router_address__.is_some() { + return Err(serde::de::Error::duplicate_field("routerAddress")); + } + router_address__ = map_.next_value()?; + } + GeneratedField::FactoryAddress => { + if factory_address__.is_some() { + return Err(serde::de::Error::duplicate_field("factoryAddress")); + } + factory_address__ = map_.next_value()?; + } + GeneratedField::QuoterAddress => { + if quoter_address__.is_some() { + return Err(serde::de::Error::duplicate_field("quoterAddress")); + } + quoter_address__ = map_.next_value()?; + } + } + } + Ok(oracle_job::UniswapExchangeRateTask { + in_token_address: in_token_address__, + out_token_address: out_token_address__, + in_token_amount: in_token_amount__, + slippage: slippage__, + provider: provider__, + version: version__, + router_address: router_address__, + factory_address: factory_address__, + quoter_address: quoter_address__, + }) + } + } + deserializer.deserialize_struct("oracle_job.OracleJob.UniswapExchangeRateTask", FIELDS, GeneratedVisitor) + } +} +impl serde::Serialize for oracle_job::uniswap_exchange_rate_task::Version { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + let variant = match self { + Self::V2Deprecated => "VERSION_V2_DEPRECATED", + Self::V3Deprecated => "VERSION_V3_DEPRECATED", + Self::V2 => "VERSION_V2", + Self::V3 => "VERSION_V3", + }; + serializer.serialize_str(variant) + } +} +impl<'de> serde::Deserialize<'de> for oracle_job::uniswap_exchange_rate_task::Version { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &[ + "VERSION_V2_DEPRECATED", + "VERSION_V3_DEPRECATED", + "VERSION_V2", + "VERSION_V3", + ]; + + struct GeneratedVisitor; + + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = oracle_job::uniswap_exchange_rate_task::Version; + + 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 { + "VERSION_V2_DEPRECATED" => Ok(oracle_job::uniswap_exchange_rate_task::Version::V2Deprecated), + "VERSION_V3_DEPRECATED" => Ok(oracle_job::uniswap_exchange_rate_task::Version::V3Deprecated), + "VERSION_V2" => Ok(oracle_job::uniswap_exchange_rate_task::Version::V2), + "VERSION_V3" => Ok(oracle_job::uniswap_exchange_rate_task::Version::V3), + _ => Err(serde::de::Error::unknown_variant(value, FIELDS)), + } + } + } + deserializer.deserialize_any(GeneratedVisitor) + } +} +impl serde::Serialize for oracle_job::UnixTimeTask { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + use serde::ser::SerializeStruct; + let mut len = 0; + if self.offset.is_some() { + len += 1; + } + let mut struct_ser = serializer.serialize_struct("oracle_job.OracleJob.UnixTimeTask", len)?; + if let Some(v) = self.offset.as_ref() { + struct_ser.serialize_field("offset", v)?; + } + struct_ser.end() + } +} +impl<'de> serde::Deserialize<'de> for oracle_job::UnixTimeTask { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &[ + "offset", + ]; + + #[allow(clippy::enum_variant_names)] + enum GeneratedField { + Offset, + } + 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 { + "offset" => Ok(GeneratedField::Offset), + _ => Err(serde::de::Error::unknown_field(value, FIELDS)), + } + } + } + deserializer.deserialize_identifier(GeneratedVisitor) + } + } + struct GeneratedVisitor; + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = oracle_job::UnixTimeTask; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("struct oracle_job.OracleJob.UnixTimeTask") + } + + fn visit_map(self, mut map_: V) -> std::result::Result + where + V: serde::de::MapAccess<'de>, + { + let mut offset__ = None; + while let Some(k) = map_.next_key()? { + match k { + GeneratedField::Offset => { + if offset__.is_some() { + return Err(serde::de::Error::duplicate_field("offset")); + } + offset__ = + map_.next_value::<::std::option::Option<::pbjson::private::NumberDeserialize<_>>>()?.map(|x| x.0) + ; + } + } + } + Ok(oracle_job::UnixTimeTask { + offset: offset__, + }) + } + } + deserializer.deserialize_struct("oracle_job.OracleJob.UnixTimeTask", FIELDS, GeneratedVisitor) + } +} +impl serde::Serialize for oracle_job::ValueTask { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + use serde::ser::SerializeStruct; + let mut len = 0; + if self.value.is_some() { + len += 1; + } + let mut struct_ser = serializer.serialize_struct("oracle_job.OracleJob.ValueTask", len)?; + if let Some(v) = self.value.as_ref() { + match v { + oracle_job::value_task::Value::Value(v) => { + struct_ser.serialize_field("value", v)?; + } + oracle_job::value_task::Value::AggregatorPubkey(v) => { + struct_ser.serialize_field("aggregatorPubkey", v)?; + } + oracle_job::value_task::Value::Big(v) => { + struct_ser.serialize_field("big", v)?; + } + oracle_job::value_task::Value::Hex(v) => { + struct_ser.serialize_field("hex", v)?; + } + oracle_job::value_task::Value::Utf8(v) => { + struct_ser.serialize_field("utf8", v)?; + } + } + } + struct_ser.end() + } +} +impl<'de> serde::Deserialize<'de> for oracle_job::ValueTask { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &[ + "value", + "aggregator_pubkey", + "aggregatorPubkey", + "big", + "hex", + "utf8", + ]; + + #[allow(clippy::enum_variant_names)] + enum GeneratedField { + Value, + AggregatorPubkey, + Big, + Hex, + Utf8, + } + 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 { + "value" => Ok(GeneratedField::Value), + "aggregatorPubkey" | "aggregator_pubkey" => Ok(GeneratedField::AggregatorPubkey), + "big" => Ok(GeneratedField::Big), + "hex" => Ok(GeneratedField::Hex), + "utf8" => Ok(GeneratedField::Utf8), + _ => Err(serde::de::Error::unknown_field(value, FIELDS)), + } + } + } + deserializer.deserialize_identifier(GeneratedVisitor) + } + } + struct GeneratedVisitor; + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = oracle_job::ValueTask; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("struct oracle_job.OracleJob.ValueTask") + } + + fn visit_map(self, mut map_: V) -> std::result::Result + where + V: serde::de::MapAccess<'de>, + { + let mut value__ = None; + while let Some(k) = map_.next_key()? { + match k { + GeneratedField::Value => { + if value__.is_some() { + return Err(serde::de::Error::duplicate_field("value")); + } + value__ = map_.next_value::<::std::option::Option<::pbjson::private::NumberDeserialize<_>>>()?.map(|x| oracle_job::value_task::Value::Value(x.0)); + } + GeneratedField::AggregatorPubkey => { + if value__.is_some() { + return Err(serde::de::Error::duplicate_field("aggregatorPubkey")); + } + value__ = map_.next_value::<::std::option::Option<_>>()?.map(oracle_job::value_task::Value::AggregatorPubkey); + } + GeneratedField::Big => { + if value__.is_some() { + return Err(serde::de::Error::duplicate_field("big")); + } + value__ = map_.next_value::<::std::option::Option<_>>()?.map(oracle_job::value_task::Value::Big); + } + GeneratedField::Hex => { + if value__.is_some() { + return Err(serde::de::Error::duplicate_field("hex")); + } + value__ = map_.next_value::<::std::option::Option<_>>()?.map(oracle_job::value_task::Value::Hex); + } + GeneratedField::Utf8 => { + if value__.is_some() { + return Err(serde::de::Error::duplicate_field("utf8")); + } + value__ = map_.next_value::<::std::option::Option<_>>()?.map(oracle_job::value_task::Value::Utf8); + } + } + } + Ok(oracle_job::ValueTask { + value: value__, + }) + } + } + deserializer.deserialize_struct("oracle_job.OracleJob.ValueTask", FIELDS, GeneratedVisitor) + } +} +impl serde::Serialize for oracle_job::VwapTask { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + use serde::ser::SerializeStruct; + let mut len = 0; + if self.price_aggregator_address.is_some() { + len += 1; + } + if self.volume_aggregator_address.is_some() { + len += 1; + } + if self.period.is_some() { + len += 1; + } + let mut struct_ser = serializer.serialize_struct("oracle_job.OracleJob.VwapTask", len)?; + if let Some(v) = self.price_aggregator_address.as_ref() { + struct_ser.serialize_field("priceAggregatorAddress", v)?; + } + if let Some(v) = self.volume_aggregator_address.as_ref() { + struct_ser.serialize_field("volumeAggregatorAddress", v)?; + } + if let Some(v) = self.period.as_ref() { + struct_ser.serialize_field("period", v)?; + } + struct_ser.end() + } +} +impl<'de> serde::Deserialize<'de> for oracle_job::VwapTask { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &[ + "price_aggregator_address", + "priceAggregatorAddress", + "volume_aggregator_address", + "volumeAggregatorAddress", + "period", + ]; + + #[allow(clippy::enum_variant_names)] + enum GeneratedField { + PriceAggregatorAddress, + VolumeAggregatorAddress, + Period, + } + 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 { + "priceAggregatorAddress" | "price_aggregator_address" => Ok(GeneratedField::PriceAggregatorAddress), + "volumeAggregatorAddress" | "volume_aggregator_address" => Ok(GeneratedField::VolumeAggregatorAddress), + "period" => Ok(GeneratedField::Period), + _ => Err(serde::de::Error::unknown_field(value, FIELDS)), + } + } + } + deserializer.deserialize_identifier(GeneratedVisitor) + } + } + struct GeneratedVisitor; + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = oracle_job::VwapTask; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("struct oracle_job.OracleJob.VwapTask") + } + + fn visit_map(self, mut map_: V) -> std::result::Result + where + V: serde::de::MapAccess<'de>, + { + let mut price_aggregator_address__ = None; + let mut volume_aggregator_address__ = None; + let mut period__ = None; + while let Some(k) = map_.next_key()? { + match k { + GeneratedField::PriceAggregatorAddress => { + if price_aggregator_address__.is_some() { + return Err(serde::de::Error::duplicate_field("priceAggregatorAddress")); + } + price_aggregator_address__ = map_.next_value()?; + } + GeneratedField::VolumeAggregatorAddress => { + if volume_aggregator_address__.is_some() { + return Err(serde::de::Error::duplicate_field("volumeAggregatorAddress")); + } + volume_aggregator_address__ = map_.next_value()?; + } + GeneratedField::Period => { + if period__.is_some() { + return Err(serde::de::Error::duplicate_field("period")); + } + period__ = + map_.next_value::<::std::option::Option<::pbjson::private::NumberDeserialize<_>>>()?.map(|x| x.0) + ; + } + } + } + Ok(oracle_job::VwapTask { + price_aggregator_address: price_aggregator_address__, + volume_aggregator_address: volume_aggregator_address__, + period: period__, + }) + } + } + deserializer.deserialize_struct("oracle_job.OracleJob.VwapTask", FIELDS, GeneratedVisitor) + } +} +impl serde::Serialize for oracle_job::WebsocketTask { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + use serde::ser::SerializeStruct; + let mut len = 0; + if self.url.is_some() { + len += 1; + } + if self.subscription.is_some() { + len += 1; + } + if self.max_data_age_seconds.is_some() { + len += 1; + } + if self.filter.is_some() { + len += 1; + } + let mut struct_ser = serializer.serialize_struct("oracle_job.OracleJob.WebsocketTask", len)?; + if let Some(v) = self.url.as_ref() { + struct_ser.serialize_field("url", v)?; + } + if let Some(v) = self.subscription.as_ref() { + struct_ser.serialize_field("subscription", v)?; + } + if let Some(v) = self.max_data_age_seconds.as_ref() { + struct_ser.serialize_field("maxDataAgeSeconds", v)?; + } + if let Some(v) = self.filter.as_ref() { + struct_ser.serialize_field("filter", v)?; + } + struct_ser.end() + } +} +impl<'de> serde::Deserialize<'de> for oracle_job::WebsocketTask { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &[ + "url", + "subscription", + "max_data_age_seconds", + "maxDataAgeSeconds", + "filter", + ]; + + #[allow(clippy::enum_variant_names)] + enum GeneratedField { + Url, + Subscription, + MaxDataAgeSeconds, + Filter, + } + 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 { + "url" => Ok(GeneratedField::Url), + "subscription" => Ok(GeneratedField::Subscription), + "maxDataAgeSeconds" | "max_data_age_seconds" => Ok(GeneratedField::MaxDataAgeSeconds), + "filter" => Ok(GeneratedField::Filter), + _ => Err(serde::de::Error::unknown_field(value, FIELDS)), + } + } + } + deserializer.deserialize_identifier(GeneratedVisitor) + } + } + struct GeneratedVisitor; + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = oracle_job::WebsocketTask; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("struct oracle_job.OracleJob.WebsocketTask") + } + + fn visit_map(self, mut map_: V) -> std::result::Result + where + V: serde::de::MapAccess<'de>, + { + let mut url__ = None; + let mut subscription__ = None; + let mut max_data_age_seconds__ = None; + let mut filter__ = None; + while let Some(k) = map_.next_key()? { + match k { + GeneratedField::Url => { + if url__.is_some() { + return Err(serde::de::Error::duplicate_field("url")); + } + url__ = map_.next_value()?; + } + GeneratedField::Subscription => { + if subscription__.is_some() { + return Err(serde::de::Error::duplicate_field("subscription")); + } + subscription__ = map_.next_value()?; + } + GeneratedField::MaxDataAgeSeconds => { + if max_data_age_seconds__.is_some() { + return Err(serde::de::Error::duplicate_field("maxDataAgeSeconds")); + } + max_data_age_seconds__ = + map_.next_value::<::std::option::Option<::pbjson::private::NumberDeserialize<_>>>()?.map(|x| x.0) + ; + } + GeneratedField::Filter => { + if filter__.is_some() { + return Err(serde::de::Error::duplicate_field("filter")); + } + filter__ = map_.next_value()?; + } + } + } + Ok(oracle_job::WebsocketTask { + url: url__, + subscription: subscription__, + max_data_age_seconds: max_data_age_seconds__, + filter: filter__, + }) + } + } + deserializer.deserialize_struct("oracle_job.OracleJob.WebsocketTask", FIELDS, GeneratedVisitor) + } +} +impl serde::Serialize for oracle_job::XStepPriceTask { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + use serde::ser::SerializeStruct; + let mut len = 0; + if self.step_source.is_some() { + len += 1; + } + let mut struct_ser = serializer.serialize_struct("oracle_job.OracleJob.XStepPriceTask", len)?; + if let Some(v) = self.step_source.as_ref() { + match v { + oracle_job::x_step_price_task::StepSource::StepJob(v) => { + struct_ser.serialize_field("stepJob", v)?; + } + oracle_job::x_step_price_task::StepSource::StepAggregatorPubkey(v) => { + struct_ser.serialize_field("stepAggregatorPubkey", v)?; + } + } + } + struct_ser.end() + } +} +impl<'de> serde::Deserialize<'de> for oracle_job::XStepPriceTask { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &[ + "step_job", + "stepJob", + "step_aggregator_pubkey", + "stepAggregatorPubkey", + ]; + + #[allow(clippy::enum_variant_names)] + enum GeneratedField { + StepJob, + StepAggregatorPubkey, + } + 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 { + "stepJob" | "step_job" => Ok(GeneratedField::StepJob), + "stepAggregatorPubkey" | "step_aggregator_pubkey" => Ok(GeneratedField::StepAggregatorPubkey), + _ => Err(serde::de::Error::unknown_field(value, FIELDS)), + } + } + } + deserializer.deserialize_identifier(GeneratedVisitor) + } + } + struct GeneratedVisitor; + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = oracle_job::XStepPriceTask; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("struct oracle_job.OracleJob.XStepPriceTask") + } + + fn visit_map(self, mut map_: V) -> std::result::Result + where + V: serde::de::MapAccess<'de>, + { + let mut step_source__ = None; + while let Some(k) = map_.next_key()? { + match k { + GeneratedField::StepJob => { + if step_source__.is_some() { + return Err(serde::de::Error::duplicate_field("stepJob")); + } + step_source__ = map_.next_value::<::std::option::Option<_>>()?.map(oracle_job::x_step_price_task::StepSource::StepJob) +; + } + GeneratedField::StepAggregatorPubkey => { + if step_source__.is_some() { + return Err(serde::de::Error::duplicate_field("stepAggregatorPubkey")); + } + step_source__ = map_.next_value::<::std::option::Option<_>>()?.map(oracle_job::x_step_price_task::StepSource::StepAggregatorPubkey); + } + } + } + Ok(oracle_job::XStepPriceTask { + step_source: step_source__, + }) + } + } + deserializer.deserialize_struct("oracle_job.OracleJob.XStepPriceTask", FIELDS, GeneratedVisitor) + } +} diff --git a/programs/switchboard-on-demand/src/client/pull_feed.rs b/programs/switchboard-on-demand/src/client/pull_feed.rs new file mode 100644 index 0000000000..62f4dd569c --- /dev/null +++ b/programs/switchboard-on-demand/src/client/pull_feed.rs @@ -0,0 +1,596 @@ +use super::secp256k1::Secp256k1InstructionUtils; +use super::secp256k1::SecpSignature; +use super::Gateway; +use super::accounts::{OracleAccountData, State, PullFeedAccountData, QueueAccountData}; +use super::lut_owner::{self}; +use super::instructions::*; +use super::crossbar::CrossbarClient; +use super::gateway::{FeedConfig, encode_jobs, FetchSignaturesParams, FetchSignaturesConsensusParams}; +use super::oracle_job::OracleJob; +use super::lut_owner::load_lookup_tables; +use super::recent_slothashes::SlotHashSysvar; +use crate::get_switchboard_on_demand_program_id; +use anyhow::anyhow; +use anyhow::Context; +use anyhow::Error as AnyhowError; +use super::associated_token_account::get_associated_token_address; +use super::associated_token_account::NATIVE_MINT; +use super::associated_token_account::SPL_TOKEN_PROGRAM_ID; +use base64::{engine::general_purpose::STANDARD as base64, Engine as _}; +use bs58; +use bytemuck; +use dashmap::DashMap; +use rust_decimal::Decimal; +use serde::{Deserialize, Serialize}; +use sha2::{Digest, Sha256}; +use crate::solana_compat::solana_client::nonblocking::rpc_client::RpcClient; +use anchor_client::solana_sdk::address_lookup_table::AddressLookupTableAccount; +use anchor_client::solana_sdk::instruction::Instruction; +use crate::{Pubkey, SYSTEM_PROGRAM_ID}; +use std::result::Result; +use std::sync::Arc; +use tokio::join; +use tokio::sync::OnceCell; + +type LutCache = DashMap; +type JobCache = DashMap<[u8; 32], OnceCell>>; +type PullFeedCache = DashMap>; + +pub fn generate_combined_checksum( + queue_key: &[u8; 32], + feeds: &[PullFeedAccountData], + signed_slothash: &[u8; 32], + submission_values: &[i128], +) -> [u8; 32] { + let mut hasher = Sha256::new(); + hasher.update(queue_key); + + for feed in feeds { + hasher.update(feed.feed_hash); + hasher.update(feed.max_variance.to_le_bytes()); + hasher.update(feed.min_responses.to_le_bytes()); + } + + hasher.update(signed_slothash); + for &value in submission_values { + hasher.update(value.to_le_bytes()); + } + + // Finalize and return the hash. + hasher.finalize().into() +} + +pub struct SbContext { + pub lut_cache: LutCache, + pub job_cache: JobCache, + pub pull_feed_cache: PullFeedCache, +} +impl SbContext { + pub fn new() -> Arc { + Arc::new(SbContext { + lut_cache: DashMap::new(), + job_cache: DashMap::new(), + pull_feed_cache: DashMap::new(), + }) + } +} + +pub async fn fetch_and_cache_luts( + client: &RpcClient, + context: Arc, + oracle_keys: &[Pubkey], +) -> Result, AnyhowError> { + let mut luts = Vec::new(); + let mut keys_to_fetch = Vec::new(); + + for &key in oracle_keys { + if let Some(cached_lut) = context.lut_cache.get(&key) { + luts.push(cached_lut.clone()); + } else { + keys_to_fetch.push(key); + } + } + + if !keys_to_fetch.is_empty() { + let fetched_luts = load_lookup_tables::(client, &keys_to_fetch).await?; + for (key, lut) in keys_to_fetch.into_iter().zip(fetched_luts.into_iter()) { + context.lut_cache.insert(key, lut.clone()); + luts.push(lut); + } + } + + Ok(luts) +} + +#[derive(Clone, Debug)] +pub struct OracleResponse { + pub value: Option, + pub error: String, + pub oracle: Pubkey, + pub signature: [u8; 64], + pub recovery_id: u8, +} + +#[derive(Clone, Debug, Default)] +pub struct FetchUpdateParams { + pub feed: Pubkey, + pub payer: Pubkey, + pub gateway: Gateway, + pub crossbar: Option, + pub num_signatures: Option, + pub debug: Option, +} + +#[derive(Clone, Debug, Default)] +pub struct FetchUpdateManyParams { + pub feeds: Vec, + pub payer: Pubkey, + pub gateway: Gateway, + pub crossbar: Option, + pub num_signatures: Option, + pub debug: Option, +} + +#[derive(Clone, Debug, Default)] +pub struct FetchUpdateBatchParams { + pub feeds: Vec, + pub payer: Pubkey, + pub gateway: Gateway, + pub crossbar: Option, + pub num_signatures: Option, + pub debug: Option, +} + +#[derive(Serialize, Deserialize, Clone, Debug)] +pub struct SolanaSubmitSignaturesParams { + pub queue: Pubkey, + pub feed: Pubkey, + pub payer: Pubkey, +} + +pub struct PullFeed; + +impl PullFeed { + pub async fn load_data( + client: &RpcClient, + key: &Pubkey, + ) -> Result { + let account = client + .get_account_data(&key.to_bytes().into()) + .await + .map_err(|_| anyhow!("PullFeed.load_data: Account not found"))?; + let account = account[8..].to_vec(); + let data = bytemuck::try_from_bytes::(&account) + .map_err(|_| anyhow!("PullFeed.load_data: Failed to parse data"))?; + Ok(*data) + } + + fn get_solana_submit_signatures_ix( + slot: u64, + responses: Vec, + params: SolanaSubmitSignaturesParams, + ) -> Result { + let mut submissions = Vec::new(); + for resp in &responses { + let mut value_i128 = i128::MAX; + if let Some(mut val) = resp.value { + val.rescale(18); + value_i128 = val.mantissa(); + } + submissions.push(Submission { + value: value_i128, + signature: resp.signature, + recovery_id: resp.recovery_id, + offset: 0, + }); + } + let mut remaining_accounts = Vec::new(); + for resp in &responses { + remaining_accounts.push(anchor_client::solana_sdk::instruction::AccountMeta::new_readonly(resp.oracle.to_bytes().into(), false)); + } + for resp in responses { + let stats_key = OracleAccountData::stats_key(&resp.oracle); + remaining_accounts.push(anchor_client::solana_sdk::instruction::AccountMeta::new(stats_key.to_bytes().into(), false)); + } + let mut submit_ix = Instruction { + program_id: get_switchboard_on_demand_program_id(), + data: PullFeedSubmitResponseParams { slot, submissions }.data(), + accounts: PullFeedSubmitResponse { + feed: params.feed, + queue: params.queue, + program_state: State::key(), + recent_slothashes: crate::solana_sdk::sysvar::slot_hashes::ID.to_bytes().into(), + payer: params.payer, + system_program: SYSTEM_PROGRAM_ID, + reward_vault: get_associated_token_address(¶ms.queue, &NATIVE_MINT), + token_program: *SPL_TOKEN_PROGRAM_ID, + token_mint: *NATIVE_MINT, + } + .to_account_metas(None) + .into_iter() + .map(|meta| anchor_client::solana_sdk::instruction::AccountMeta { + pubkey: meta.pubkey.to_bytes().into(), + is_signer: meta.is_signer, + is_writable: meta.is_writable, + }) + .collect(), + }; + submit_ix.accounts.extend(remaining_accounts); + Ok(submit_ix) + } + + pub async fn fetch_update_ix( + context: Arc, + client: &RpcClient, + params: FetchUpdateParams, + ) -> Result< + ( + Instruction, + Vec, + usize, + Vec, + ), + AnyhowError, + > { + let latest_slot = SlotHashSysvar::get_latest_slothash(client) + .await + .context("PullFeed.fetchUpdateIx: Failed to fetch latest slot")?; + + let feed_data = *context + .pull_feed_cache + .entry(params.feed) + .or_insert_with(OnceCell::new) + .get_or_try_init(|| PullFeed::load_data(client, ¶ms.feed)) + .await?; + + let feed_hash = feed_data.feed_hash; + let jobs = context + .job_cache + .entry(feed_hash) + .or_insert_with(OnceCell::new) + .get_or_try_init(|| { + let crossbar = params.crossbar.clone().unwrap_or_default(); + async move { + let jobs_data = crossbar + .fetch(&hex::encode(feed_hash)) + .await + .context("PullFeed.fetchUpdateIx: Failed to fetch jobs")?; + + let jobs: Vec = + serde_json::from_value(jobs_data.get("jobs").unwrap().clone()) + .context("PullFeed.fetchUpdateIx: Failed to deserialize jobs")?; + + Ok::, AnyhowError>(jobs) + } + }) + .await? + .clone(); + + let encoded_jobs = encode_jobs(&jobs); + let gateway = params.gateway; + + let num_signatures = if params.num_signatures.is_none() { + (feed_data.min_sample_size as f64 + ((feed_data.min_sample_size as f64) / 3.0).ceil()) + as u32 + } else { + params.num_signatures.unwrap() + }; + + let price_signatures = gateway + .fetch_signatures_from_encoded(FetchSignaturesParams { + recent_hash: Some(bs58::encode(latest_slot.hash).into_string()), + encoded_jobs: encoded_jobs.clone(), + num_signatures, + max_variance: Some((feed_data.max_variance / 1_000_000_000) as u32), + min_responses: Some(feed_data.min_responses), + use_timestamp: Some(false), + }) + .await + .context("PullFeed.fetchUpdateIx: Failed to fetch signatures")?; + + let mut num_successes = 0; + let oracle_responses: Vec = price_signatures + .responses + .iter() + .map(|x| { + let value = x.success_value.parse::().ok(); + let mut formatted_value = None; + if let Some(val) = value { + num_successes += 1; + formatted_value = Some(Decimal::from_i128_with_scale(val, 18)); + } + OracleResponse { + value: formatted_value, + error: x.failure_error.clone(), + oracle: Pubkey::new_from_array( + hex::decode(x.oracle_pubkey.clone()) + .unwrap() + .try_into() + .unwrap(), + ), + recovery_id: x.recovery_id as u8, + signature: base64 + .decode(x.signature.clone()) + .unwrap_or_default() + .try_into() + .unwrap_or([0; 64]), + } + }) + .collect(); + + if params.debug.unwrap_or(false) { + println!("priceSignatures: {:?}", price_signatures); + } + + if num_successes == 0 { + return Err(anyhow::Error::msg( + "PullFeed.fetchUpdateIx Failure: No successful responses".to_string(), + )); + } + + let submit_signatures_ix = PullFeed::get_solana_submit_signatures_ix( + latest_slot.slot, + oracle_responses.clone(), + SolanaSubmitSignaturesParams { + feed: params.feed, + queue: feed_data.queue, + payer: params.payer, + }, + ) + .context("PullFeed.fetchUpdateIx: Failed to create submit signatures instruction")?; + + let oracle_keys: Vec = oracle_responses.iter().map(|x| x.oracle).collect(); + let feed_key = [params.feed]; + let queue_key = [feed_data.queue]; + + let (oracle_luts, pull_feed_lut, queue_lut) = join!( + fetch_and_cache_luts::(client, context.clone(), &oracle_keys), + fetch_and_cache_luts::(client, context.clone(), &feed_key), + fetch_and_cache_luts::(client, context.clone(), &queue_key) + ); + let oracle_luts = oracle_luts?; + let pull_feed_lut = pull_feed_lut?; + let queue_lut = queue_lut?; + + let mut luts = oracle_luts; + luts.extend(pull_feed_lut); + luts.extend(queue_lut); + + Ok((submit_signatures_ix, oracle_responses, num_successes, luts)) + } + + /// Fetch the oracle responses for multiple feeds via the consensus endpoint, + /// build the necessary secp256k1 verification instruction and the feed update instruction, + /// and return these instructions along with the required lookup tables. + /// + /// # Arguments + /// * `context` - Shared context holding caches for feeds, jobs, and lookup tables. + /// * `client` - The RPC client for connecting to the cluster. + /// * `params` - Parameters for fetching updates, including: + /// - `feeds`: A vector of feed public keys. + /// - `payer`: The payer public key. + /// - `gateway`: A Gateway instance for the API calls. + /// - `crossbar`: Optional CrossbarClient instance. + /// - `num_signatures`: Optional override for the number of signatures to fetch. + /// - `debug`: Optional flag to print debug logs. + /// + /// # Returns + /// A tuple containing: + /// 1. A vector of two Instructions (first is secp256k1 verification, second is the feed update). + /// 2. A vector of AddressLookupTableAccount to include in the transaction. + pub async fn fetch_update_consensus_ix( + context: Arc, + client: &RpcClient, + params: FetchUpdateManyParams, + ) -> Result<(Vec, Vec), AnyhowError> { + let gateway = params.gateway; + let mut num_signatures = params.num_signatures.unwrap_or(1); + let mut feed_configs = Vec::new(); + let mut queue = Pubkey::default(); + let mut feed_datas = Vec::new(); + // For each feed, load its on-chain data and build its configuration (jobs, encoded jobs, etc.) + for feed in ¶ms.feeds { + let data = *context + .pull_feed_cache + .entry(*feed) + .or_insert_with(OnceCell::new) + .get_or_try_init(|| PullFeed::load_data(client, feed)) + .await?; + feed_datas.push((feed, data)); + let num_sig_lower_bound = + data.min_sample_size as u32 + ((data.min_sample_size as f64) / 3.0).ceil() as u32; + if num_signatures < num_sig_lower_bound { + num_signatures = num_sig_lower_bound; + } + queue = data.queue; + // Fetch jobs from the crossbar (or use cache) and encode them. + let jobs = context + .job_cache + .entry(data.feed_hash) + .or_insert_with(OnceCell::new) + .get_or_try_init(|| { + let crossbar = params.crossbar.clone().unwrap_or_default(); + async move { + let jobs_data = crossbar + .fetch(&hex::encode(data.feed_hash)) + .await + .context("PullFeed.fetchUpdateIx: Failed to fetch jobs")?; + + let jobs: Vec = + serde_json::from_value(jobs_data.get("jobs").unwrap().clone()) + .context("PullFeed.fetchUpdateIx: Failed to deserialize jobs")?; + + Ok::, AnyhowError>(jobs) + } + }) + .await? + .clone(); + let encoded_jobs = encode_jobs(&jobs); + let max_variance = (data.max_variance / 1_000_000_000) as u32; + let min_responses = data.min_responses; + // Build the feed configuration required by the gateway. + feed_configs.push(FeedConfig { + encoded_jobs, + max_variance: Some(max_variance), + min_responses: Some(min_responses), + }); + } + + // Get the latest slot. + let latest_slot = SlotHashSysvar::get_latest_slothash(client) + .await + .context("PullFeed.fetchUpdateIx: Failed to fetch latest slot")?; + + // Call the gateway consensus endpoint and fetch signatures + let price_signatures = gateway + .fetch_signatures_consensus(FetchSignaturesConsensusParams { + recent_hash: Some(bs58::encode(latest_slot.hash).into_string()), + num_signatures: Some(num_signatures), + feed_configs, + use_timestamp: Some(false), + }) + .await + .context("PullFeed.fetchUpdateIx: fetch signatures consensus failure")?; + if params.debug.unwrap_or(false) { + println!("priceSignatures: {:?}", price_signatures); + } + + // Parse the median responses into i128 values and build the consensus payload. + let consensus_values: Vec = price_signatures + .median_responses + .iter() + .map(|mr| mr.value.parse::().unwrap_or(i128::MAX)) + .collect(); + // Build the consensus Ix data. + let consensus_ix_data = PullFeedSubmitResponseConsensusParams { + slot: latest_slot.slot, + values: consensus_values, + }; + // Extract oracle keys from the gateway responses. + let mut remaining_accounts = Vec::new(); + if price_signatures.oracle_responses.is_empty() { + return Err(anyhow::Error::msg( + "PullFeed.fetchUpdateConsensusIx Failure: No oracle responses".to_string(), + )); + } + if price_signatures.median_responses.is_empty() { + return Err(anyhow::Error::msg( + "PullFeed.fetchUpdateConsensusIx Failure: No success responses found".to_string(), + )); + } + let oracle_keys: Vec = price_signatures + .oracle_responses + .iter() + .map(|x| { + Pubkey::new_from_array( + hex::decode(x.feed_responses.first().unwrap().oracle_pubkey.clone()) + .unwrap_or_default() + .try_into() + .unwrap(), + ) + }) + .collect(); + // Map the gateway oracle responses to our SecpSignature struct. + let secp_signatures: Vec = price_signatures + .oracle_responses + .iter() + .map(|oracle_response| SecpSignature { + eth_address: hex::decode(&oracle_response.eth_address) + .unwrap() + .try_into() + .expect("slice with incorrect length"), + signature: base64 + .decode(&oracle_response.signature) + .unwrap() + .try_into() + .expect("slice with incorrect length"), + message: base64 + .decode(&oracle_response.checksum) + .unwrap() + .try_into() + .expect("slice with incorrect length"), + recovery_id: oracle_response.recovery_id as u8, + }) + .collect(); + + // Build the secp256k1 instruction: + let secp_ix = Secp256k1InstructionUtils::build_secp256k1_instruction(&secp_signatures, 0) + .map_err(|_| { + anyhow!("Feed failed to produce signatures: Failed to build secp256k1 instruction") + })?; + + // Match each median response to its corresponding feed account by comparing feed hashes. + let feed_pubkeys: Vec = price_signatures + .median_responses + .iter() + .map(|median_response| { + let matching = feed_datas.iter().find(|(_, data)| { + let feed_hash_hex = hex::encode(data.feed_hash); + feed_hash_hex == median_response.feed_hash + }); + if let Some((feed, _)) = matching { + **feed + } else { + if params.debug.unwrap_or(false) { + eprintln!("Feed not found for hash: {}", median_response.feed_hash); + } + Pubkey::default() + } + }) + .collect(); + + // Attach feed accounts and oracle accounts (plus their stats accounts) as remaining accounts. + for feed in &feed_pubkeys { + remaining_accounts.push(anchor_client::solana_sdk::instruction::AccountMeta::new(feed.to_bytes().into(), false)); + } + for oracle in oracle_keys.iter() { + remaining_accounts.push(anchor_client::solana_sdk::instruction::AccountMeta::new_readonly(oracle.to_bytes().into(), false)); + let stats_key = OracleAccountData::stats_key(oracle); + remaining_accounts.push(anchor_client::solana_sdk::instruction::AccountMeta::new(stats_key.to_bytes().into(), false)); + } + // Load lookup tables for oracle, feed, and queue accounts concurrently. + let queue_key = [queue]; + let (oracle_luts_result, pull_feed_luts_result, queue_lut_result) = join!( + fetch_and_cache_luts::(client, context.clone(), &oracle_keys), + fetch_and_cache_luts::(client, context.clone(), ¶ms.feeds), + fetch_and_cache_luts::(client, context.clone(), &queue_key) + ); + + // Handle the results after they are all awaited + let oracle_luts = oracle_luts_result?; + let pull_feed_luts = pull_feed_luts_result?; + let queue_lut = queue_lut_result?; + + let mut luts = oracle_luts; + luts.extend(pull_feed_luts); + luts.extend(queue_lut); + + // Construct the instruction that updates the feed consensus using the consensus payload. + let mut submit_ix = Instruction { + program_id: get_switchboard_on_demand_program_id(), + data: consensus_ix_data.data(), + accounts: PullFeedSubmitResponseConsensus { + queue, + program_state: State::key(), + recent_slothashes: crate::solana_sdk::sysvar::slot_hashes::ID.to_bytes().into(), + payer: params.payer, + system_program: SYSTEM_PROGRAM_ID, + reward_vault: get_associated_token_address(&queue, &NATIVE_MINT), + token_program: *SPL_TOKEN_PROGRAM_ID, + token_mint: *NATIVE_MINT, + } + .to_account_metas(None) + .into_iter() + .map(|meta| anchor_client::solana_sdk::instruction::AccountMeta { + pubkey: meta.pubkey.to_bytes().into(), + is_signer: meta.is_signer, + is_writable: meta.is_writable, + }) + .collect(), + }; + submit_ix.accounts.extend(remaining_accounts); + let ixs = vec![secp_ix, submit_ix]; + + Ok((ixs, luts)) + } +} diff --git a/programs/switchboard-on-demand/src/client/recent_slothashes.rs b/programs/switchboard-on-demand/src/client/recent_slothashes.rs new file mode 100644 index 0000000000..8491e6f45d --- /dev/null +++ b/programs/switchboard-on-demand/src/client/recent_slothashes.rs @@ -0,0 +1,47 @@ +use anyhow::Context; +use anyhow::Error as AnyhowError; +use arrayref::array_ref; +use bytemuck; +use crate::solana_compat::solana_client::nonblocking::rpc_client::RpcClient; +use crate::solana_compat::solana_client::rpc_config::RpcAccountInfoConfig; +use crate::solana_compat::solana_sdk::commitment_config::CommitmentConfig; +use std::result::Result; + +#[repr(C)] +#[derive(bytemuck::Pod, bytemuck::Zeroable, Debug, Clone, Copy)] +pub struct SlotHash { + pub slot: u64, + pub hash: [u8; 32], +} + +impl SlotHash { + /// Returns the base58-encoded hash as a `String`. + pub fn to_base58_hash(&self) -> String { + bs58::encode(self.hash).into_string() + } +} + +pub struct SlotHashSysvar; +impl SlotHashSysvar { + pub async fn get_latest_slothash(client: &RpcClient) -> Result { + let slot_hashes_id = anchor_client::solana_sdk::sysvar::slot_hashes::ID; + let config = RpcAccountInfoConfig { + commitment: Some(CommitmentConfig::confirmed()), + ..Default::default() + }; + let slots_data = client + .get_account_with_config( + &slot_hashes_id.to_bytes().into(), + config, + ) + .await + .context("Failed to fetch slot hashes")? + .value + .context("Failed to fetch slot hashes")? + .data; + let slots: &[u8] = array_ref![slots_data, 8, 20_480]; + // 20_480 / 40 = 512 + let slots: &[SlotHash] = bytemuck::cast_slice::(slots); + Ok(slots[0]) + } +} diff --git a/programs/switchboard-on-demand/src/client/secp256k1.rs b/programs/switchboard-on-demand/src/client/secp256k1.rs new file mode 100644 index 0000000000..602c0d377f --- /dev/null +++ b/programs/switchboard-on-demand/src/client/secp256k1.rs @@ -0,0 +1,128 @@ +use anchor_client::solana_sdk::instruction::Instruction; +use anchor_client::solana_sdk::secp256k1_program; + +// Constants per Solana's secp256k1 instruction specification: +const SIGNATURE_SERIALIZED_SIZE: usize = 64; +const HASHED_PUBKEY_SERIALIZED_SIZE: usize = 20; +const SIGNATURE_OFFSETS_SERIALIZED_SIZE: usize = 11; + +/// This struct holds a single secp256k1 signature bundle. +#[derive(Clone)] +pub struct SecpSignature { + pub signature: [u8; SIGNATURE_SERIALIZED_SIZE], + pub recovery_id: u8, + pub eth_address: [u8; HASHED_PUBKEY_SERIALIZED_SIZE], + pub message: Vec, +} + +pub struct Secp256k1InstructionUtils; + +impl Secp256k1InstructionUtils { + /// Builds a secp256k1 verification instruction using the provided signatures. + /// + /// # Arguments + /// + /// * `signatures` - A slice of [`SecpSignature`] which must all share the same message. + /// * `instruction_index` - The instruction index to encode (usually 0). + /// + /// # Returns + /// + /// A [`Result`] with the constructed [`Instruction`] on success. + pub fn build_secp256k1_instruction( + signatures: &[SecpSignature], + instruction_index: u8, + ) -> Result> { + // Use your function to produce the raw instruction data. + let data = make_secp256k1_instruction_data_unique_message(signatures, instruction_index)?; + Ok(Instruction { + program_id: secp256k1_program::ID, + accounts: vec![], + data, + }) + } +} + +/// Constructs secp256k1 instruction data that bundles multiple signatures with a single common message. +pub fn make_secp256k1_instruction_data_unique_message( + signatures: &[SecpSignature], + instruction_index: u8, +) -> std::result::Result, Box> { + if signatures.is_empty() { + return Err("No signatures provided".into()); + } + // Ensure that every signature in the slice has the same message. + let common_message = &signatures[0].message; + for sig in signatures.iter() { + if sig.message != *common_message { + return Err("Not all signatures share the same message".into()); + } + } + let message_size = common_message.len(); + // For each signature block, we now only include: + // - Signature (64 bytes) + // - Recovery ID (1 byte) + // - Ethereum address (20 bytes) + // Total = 85 bytes per signature. + let signature_block_size = SIGNATURE_SERIALIZED_SIZE + 1 + HASHED_PUBKEY_SERIALIZED_SIZE; + let count = signatures.len(); + // The offsets area comes first: 1 byte for count + count * 11 bytes. + let offsets_area_size = 1 + count * SIGNATURE_OFFSETS_SERIALIZED_SIZE; + // The signature blocks will take up count * signature_block_size bytes. + // Then, we append the common message once. + // The message offset (for every signature) will be the same, equal to: + let message_offset = offsets_area_size + count * signature_block_size; + + let mut signature_offsets = Vec::with_capacity(count); + let mut signature_buffer = Vec::new(); + + for sig in signatures { + // For this signature block, compute its starting offset relative to the start of the instruction data. + let current_offset = offsets_area_size + signature_buffer.len(); + let signature_offset = current_offset; // where the 64-byte signature begins + let eth_address_offset = current_offset + SIGNATURE_SERIALIZED_SIZE + 1; // after signature and recovery id + + // The message is stored only once (after all signature blocks). + let message_data_offset = message_offset; + let message_data_size = message_size; // size of the common message + + // Convert to u16 + let signature_offset = u16::try_from(signature_offset)?; + let eth_address_offset = u16::try_from(eth_address_offset)?; + let message_data_offset = u16::try_from(message_data_offset)?; + let message_data_size = u16::try_from(message_data_size)?; + + let mut offsets_bytes = Vec::with_capacity(SIGNATURE_OFFSETS_SERIALIZED_SIZE); + offsets_bytes.extend(&signature_offset.to_le_bytes()); + offsets_bytes.push(instruction_index); // signature_instruction_index + offsets_bytes.extend(ð_address_offset.to_le_bytes()); + offsets_bytes.push(instruction_index); // eth_address_instruction_index + offsets_bytes.extend(&message_data_offset.to_le_bytes()); + offsets_bytes.extend(&message_data_size.to_le_bytes()); + offsets_bytes.push(instruction_index); // message_instruction_index + + if offsets_bytes.len() != SIGNATURE_OFFSETS_SERIALIZED_SIZE { + return Err("Invalid offsets length".into()); + } + signature_offsets.push(offsets_bytes); + + // Append the signature block (without the message) + signature_buffer.extend(&sig.signature); + signature_buffer.push(sig.recovery_id); + signature_buffer.extend(&sig.eth_address); + // Do not append the message here. + } + + // Build the final instruction data: + // 1. Count byte + let mut instr_data = vec![count as u8]; + // 2. Offsets area + for offs in signature_offsets { + instr_data.extend(offs); + } + // 3. Signature blocks + instr_data.extend(signature_buffer); + // 4. Common message (only one copy) + instr_data.extend(common_message); + + Ok(instr_data) +} diff --git a/programs/switchboard-on-demand/src/client/transaction_builder.rs b/programs/switchboard-on-demand/src/client/transaction_builder.rs new file mode 100644 index 0000000000..ac657d0e66 --- /dev/null +++ b/programs/switchboard-on-demand/src/client/transaction_builder.rs @@ -0,0 +1,856 @@ +use crate::*; + +use crate::Pubkey; +use crate::solana_program::instruction::{Instruction, AccountMeta}; +use anchor_client::solana_sdk::address_lookup_table::state::AddressLookupTable; +use anchor_client::solana_client::nonblocking::rpc_client::RpcClient; +use anchor_client::solana_sdk::address_lookup_table::AddressLookupTableAccount; +use crate::solana_program::hash::Hash; +use anchor_client::solana_sdk::compute_budget::ComputeBudgetInstruction; +use anchor_client::solana_sdk::signer::Signer; +use anchor_client::solana_sdk::transaction::VersionedTransaction; +use tokio::sync::RwLockReadGuard; +use std::ops::Deref; +use std::sync::Arc; +use anchor_client::solana_sdk::transaction::Transaction; +pub use anchor_client::solana_sdk::signer::keypair::Keypair; + +/// A trait for types that can act as signers for transactions. +pub trait AsSigner: Send + Sync { + /// Returns a reference to the signer. + fn as_signer(&self) -> &dyn Signer; + + fn signer_pubkey(&self) -> Pubkey { + let anchor_pubkey = self.as_signer().pubkey(); + Pubkey::new_from_array(anchor_pubkey.to_bytes()) + } +} + +pub trait ToKeypair: Send + Sync { + fn keypair(&self) -> &Keypair; +} + +// Implement AsSigner for any type that implements ToKeypair +impl AsSigner for T +where + T: ToKeypair, +{ + fn as_signer(&self) -> &dyn Signer { + // Use the keypair method from the ToKeypair trait to get the Keypair + // and then return a reference to it as a &dyn Signer. + // The Keypair struct already implements the Signer trait. + self.keypair() + } +} + +// Implementations + +impl ToKeypair for Keypair { + fn keypair(&self) -> &Keypair { + self + } +} +impl<'a> ToKeypair for &'a Keypair { + fn keypair(&self) -> &'a Keypair { + self + } +} + +// Arc + +impl ToKeypair for Arc { + fn keypair(&self) -> &Keypair { + self.as_ref() + } +} +impl AsSigner for Arc<&Keypair> { + fn as_signer(&self) -> &dyn Signer { + *self.as_ref() + } +} +impl ToKeypair for &Arc { + fn keypair(&self) -> &Keypair { + self.as_ref() + } +} +impl ToKeypair for Arc> { + fn keypair(&self) -> &Keypair { + self + } +} +impl ToKeypair for Arc>> { + fn keypair(&self) -> &Keypair { + self + } +} + +// Box + +impl ToKeypair for Box +where + T: ToKeypair + ?Sized, +{ + fn keypair(&self) -> &Keypair { + self.as_ref().keypair() + } +} + +// Tokio RwLock + +impl<'a, T> ToKeypair for RwLockReadGuard<'a, T> +where + T: ToKeypair + ?Sized, +{ + fn keypair(&self) -> &Keypair { + self.deref().keypair() + } +} + +impl<'a, T> ToKeypair for Arc> +where + T: ToKeypair + ?Sized, +{ + fn keypair(&self) -> &Keypair { + self.as_ref().keypair() + } +} + +impl<'a> AsSigner for &RwLockReadGuard<'a, Keypair> { + fn as_signer(&self) -> &dyn Signer { + (*self).deref() + } +} +impl<'a> AsSigner for &Arc> { + fn as_signer(&self) -> &dyn Signer { + self.as_ref().deref() + } +} + +/// Represents a transaction object used for building Solana transactions. +/// +/// The `TransactionBuilder` struct provides methods for constructing and manipulating Solana transactions. +/// It allows setting the payer, adding instructions, signers, and other transaction parameters. +/// The transaction can be converted to a legacy transaction format or executed directly using the Solana RPC client. +/// +/// # Examples +/// +/// Creating a new transaction object with a payer: +/// +/// ```rust +/// use anchor_client::solana_sdk::pubkey::Pubkey; +/// use anchor_client::solana_sdk::instruction::Instruction; +/// use std::sync::Arc; +/// +/// let payer = Pubkey::new_unique(); +/// let transaction = TransactionBuilder::new(payer); +/// ``` +/// +/// Adding an instruction to the transaction: +/// +/// ```rust +/// use anchor_client::solana_sdk::pubkey::Pubkey; +/// use anchor_client::solana_sdk::instruction::Instruction; +/// use std::sync::Arc; +/// +/// let payer = Pubkey::new_unique(); +/// let instruction = Instruction::new_with_bincode(program_id, data); +/// let transaction = TransactionBuilder::new(payer) +/// .add_ix(instruction); +/// ``` +/// +/// Converting the transaction object to a legacy transaction: +/// +/// ```rust +/// use anchor_client::solana_sdk::pubkey::Pubkey; +/// use anchor_client::solana_sdk::instruction::Instruction; +/// use std::sync::Arc; +/// +/// let payer = Pubkey::new_unique(); +/// let instruction = Instruction::new_with_bincode(program_id, data); +/// let transaction = TransactionBuilder::new(payer) +/// .add_ix(instruction) +/// .to_legacy_tx(); +/// ``` +#[derive(Default, Clone)] +pub struct TransactionBuilder { + payer: Pubkey, + ixs: Vec, + compute_units: Option, + priority_fees: Option, + recent_blockhash: Option, + min_context_slot: Option, + address_lookup_tables: Vec, + signers: Vec>, +} +impl TransactionBuilder { + pub fn new(payer: Pubkey) -> Self { + Self { + payer, + ..Default::default() + } + } + pub fn new_with_payer(payer: Arc) -> Self { + Self { + payer: payer.signer_pubkey(), + signers: vec![Arc::clone(&payer)], + ..Default::default() + } + } + + pub fn new_with_ixs(payer: Pubkey, ixs: impl IntoIterator) -> Self { + Self { + payer, + ixs: ixs.into_iter().collect::>(), + ..Default::default() + } + } + pub fn new_with_payer_and_ixs( + payer: Arc, + ixs: impl IntoIterator, + ) -> Self { + Self { + payer: payer.signer_pubkey(), + signers: vec![Arc::clone(&payer)], + ixs: ixs.into_iter().collect::>(), + ..Default::default() + } + } + + // Builder methods, consumes self and returns self + pub fn set_compute_units(mut self, compute_units: u32) -> Self { + self.compute_units = Some(compute_units); + self + } + pub fn set_priority_fees(mut self, priority_fees: u64) -> Self { + self.priority_fees = Some(priority_fees); + self + } + pub fn add_ix(mut self, ix: Instruction) -> Self { + self.ixs.push(ix); + self + } + pub fn has_signer(&self, signer: Pubkey) -> bool { + self.signers + .iter() + .any(|s| s.as_signer().pubkey().to_bytes() == signer.to_bytes()) + } + pub fn has_payer(&self) -> bool { + self.has_signer(self.payer) + } + pub fn add_signer(mut self, signer: Arc) -> TransactionBuilder { + let signer_key = signer.as_signer().pubkey(); + if !self + .signers + .iter().any(|s| s.as_signer().pubkey() == signer_key) + { + self.signers.push(Arc::clone(&signer)); + } + + self + } + pub fn add_signers(mut self, signers: Vec>) -> TransactionBuilder { + for signer in signers { + let signer_key = signer.as_signer().pubkey(); + if !self + .signers + .iter().any(|s| s.as_signer().pubkey() == signer_key) + { + self.signers.push(Arc::clone(&signer)); + } + } + + self + } + pub fn set_recent_blockhash(mut self, blockhash: Hash) -> Self { + self.recent_blockhash = Some(blockhash); + self + } + pub fn set_min_context_slot(mut self, min_context_slot: u64) -> Self { + self.min_context_slot = Some(min_context_slot); + self + } + + pub fn add_address_lookup_account( + mut self, + address_lookup_table: AddressLookupTableAccount, + ) -> Self { + self.address_lookup_tables.push(address_lookup_table); + self + } + pub fn add_address_lookup_accounts( + mut self, + address_lookup_tables: &mut Vec, + ) -> Self { + self.address_lookup_tables + .append(address_lookup_tables); + self + } + pub async fn add_address_lookup_table( + mut self, + rpc: &RpcClient, + address_lookup_table_pubkey: Pubkey, + ) -> Self { + if let Ok(address_lookup_table) = + TransactionBuilder::fetch_address_lookup_account(rpc, address_lookup_table_pubkey).await + { + self = self.add_address_lookup_account(address_lookup_table); + } + + self + } + pub async fn add_address_lookup_tables( + mut self, + rpc: &RpcClient, + address_lookup_table_pubkeys: Vec, + ) -> Self { + if let Ok(mut address_lookup_tables) = + TransactionBuilder::fetch_multiple_address_lookup_accounts( + rpc, + address_lookup_table_pubkeys, + ) + .await + { + self = self.add_address_lookup_accounts(&mut address_lookup_tables); + } + + self + } + + // Getters + pub fn payer(&self) -> Pubkey { + self.payer + } + + /// Return a vec of all of the required signers for the transaction. + pub fn required_signers(&self) -> Vec { + let mut signers_required: Vec = vec![]; + for ixn in self.ixs.clone() { + for account in ixn.accounts { + if account.is_signer && !signers_required.contains(&account.pubkey) { + signers_required.push(account.pubkey); + } + } + } + signers_required + } + + /// Returns the stored signers for the transaction, removing any un-needed signers using the provided ixn's AccountMeta's. + pub fn signers(&self) -> Result, OnDemandError> { + let mut signers: Vec<&dyn Signer> = vec![]; + for required_signer in self.required_signers().iter() { + let mut found = false; + + for signer in &self.signers { + let signer_key = signer.as_signer().pubkey(); + if signer_key.to_bytes() == required_signer.to_bytes() { + found = true; + signers.push(signer.as_signer()); + break; + } + } + if !found { + return Err(OnDemandError::SolanaMissingSigner); + } + } + + Ok(signers) + } + fn signers_with_payer<'a, T: AsSigner>( + &'a self, + payer: &'a T, + ) -> Result, OnDemandError> { + let payer_signer = payer.as_signer(); + + if payer_signer.pubkey().to_bytes() != self.payer.to_bytes() { + return Err(OnDemandError::SolanaPayerMismatch); + } + + let mut signers: Vec<&dyn Signer> = vec![]; + for required_signer in self.required_signers().iter() { + if required_signer == &self.payer { + signers.push(payer_signer); + continue; + } + + let mut found = false; + + for signer in self.signers.iter() { + let signer_key = signer.as_signer().pubkey(); + if signer_key.to_bytes() == required_signer.to_bytes() { + found = true; + signers.push(signer.as_signer()); + break; + } + } + if !found { + return Err(OnDemandError::SolanaMissingSigner); + } + } + + Ok(signers) + } + pub fn ixs(&self) -> Result, OnDemandError> { + if self.ixs.is_empty() { + return Err(OnDemandError::SolanaInstructionsEmpty); + } + + let mut pre_ixs = vec![]; + + if let Some(compute_units) = self.compute_units { + pre_ixs.push(ComputeBudgetInstruction::set_compute_unit_limit( + compute_units.clamp(200_000, 1_400_000), + )); + } + // want this first so we unshift last + if let Some(priority_fees) = self.priority_fees { + pre_ixs.push(ComputeBudgetInstruction::set_compute_unit_price( + std::cmp::min(10_000, priority_fees), + )); + } + + // Convert pre_ixs to compatible type + let converted_pre_ixs: Vec = pre_ixs.iter().map(|ix| { + Instruction { + program_id: ix.program_id.to_bytes().into(), + accounts: ix.accounts.iter().map(|acc| AccountMeta { + pubkey: acc.pubkey.to_bytes().into(), + is_signer: acc.is_signer, + is_writable: acc.is_writable, + }).collect(), + data: ix.data.clone(), + } + }).collect(); + + let ixs = [converted_pre_ixs, self.ixs.clone()].concat(); + + if ixs.len() > 10 { + return Err(OnDemandError::SolanaInstructionOverflow); + } + + Ok(ixs) + } + pub fn build_legacy_tx( + payer: Pubkey, + ixs: Vec, + signers: Vec<&dyn Signer>, + recent_blockhash: Hash, + ) -> Result { + // Convert to anchor-client types + let converted_ixs: Vec = ixs.iter().map(|ix| { + anchor_client::solana_sdk::instruction::Instruction { + program_id: ix.program_id.to_bytes().into(), + accounts: ix.accounts.iter().map(|acc| anchor_client::solana_sdk::instruction::AccountMeta { + pubkey: acc.pubkey.to_bytes().into(), + is_signer: acc.is_signer, + is_writable: acc.is_writable, + }).collect(), + data: ix.data.clone(), + } + }).collect(); + let converted_payer: anchor_client::solana_sdk::pubkey::Pubkey = payer.to_bytes().into(); + let converted_blockhash: anchor_client::solana_sdk::hash::Hash = recent_blockhash.to_bytes().into(); + + let mut tx = Transaction::new_with_payer(&converted_ixs, Some(&converted_payer)); + tx.try_sign(&signers, converted_blockhash).map_err(|_| OnDemandError::SolanaSignError)?; + Ok(tx) + } + pub fn to_legacy_tx(&self) -> Result { + if !self.has_payer() { + return Err(OnDemandError::SolanaPayerSignerMissing); + } + + TransactionBuilder::build_legacy_tx( + self.payer, + self.ixs()?, + self.signers()?, + self.recent_blockhash.unwrap_or_default(), + ) + } + pub fn to_legacy_tx_with_payer( + &self, + payer: T, + ) -> Result { + if payer.as_signer().pubkey().to_bytes() != self.payer.to_bytes() { + return Err(OnDemandError::SolanaPayerMismatch); + } + + TransactionBuilder::build_legacy_tx( + self.payer, + self.ixs()?, + self.signers_with_payer(&payer)?, + self.recent_blockhash.unwrap_or_default(), + ) + } + pub fn to_legacy_tx_with_payer_and_blockhash( + &self, + payer: T, + recent_blockhash: Option, + ) -> Result { + if payer.as_signer().pubkey().to_bytes() != self.payer.to_bytes() { + return Err(OnDemandError::SolanaPayerMismatch); + } + + TransactionBuilder::build_legacy_tx( + self.payer, + self.ixs()?, + self.signers_with_payer(&payer)?, + recent_blockhash.unwrap_or(self.recent_blockhash.unwrap_or_default()), + ) + } + pub fn to_legacy_tx_with_blockhash( + &self, + recent_blockhash: Option, + ) -> Result { + TransactionBuilder::build_legacy_tx( + self.payer, + self.ixs()?, + self.signers()?, + self.recent_blockhash + .unwrap_or(recent_blockhash.unwrap_or_default()), + ) + } + + pub async fn fetch_address_lookup_account( + rpc: &RpcClient, + address_lookup_table_pubkey: Pubkey, + ) -> Result { + let converted_pubkey: anchor_client::solana_sdk::pubkey::Pubkey = address_lookup_table_pubkey.to_bytes().into(); + let account = rpc + .get_account(&converted_pubkey) + .await + .map_err(|_e| OnDemandError::NetworkError)?; + let address_lookup_table = + AddressLookupTable::deserialize(&account.data).map_err(|_| OnDemandError::AccountDeserializeError)?; + let address_lookup_table_account = AddressLookupTableAccount { + key: address_lookup_table_pubkey.to_bytes().into(), + addresses: address_lookup_table.addresses.to_vec(), + }; + Ok(address_lookup_table_account) + } + + pub async fn fetch_multiple_address_lookup_accounts( + rpc: &RpcClient, + address_lookup_pubkeys: Vec, + ) -> Result, OnDemandError> { + let address_lookup_accounts: Vec = + if address_lookup_pubkeys.is_empty() { + vec![] + } else { + let converted_pubkeys: Vec = address_lookup_pubkeys.iter().map(|pk| pk.to_bytes().into()).collect(); + let accounts = rpc + .get_multiple_accounts(&converted_pubkeys) + .await + .map_err(|_| OnDemandError::NetworkError)?; + + let mut address_lookup_accounts: Vec = vec![]; + for (i, account) in accounts.iter().enumerate() { + let account = account.as_ref().ok_or(OnDemandError::AccountNotFound)?; + let address_lookup_table = AddressLookupTable::deserialize(&account.data) + .map_err(|_| OnDemandError::AccountDeserializeError)?; + let address_lookup_table_account = AddressLookupTableAccount { + key: address_lookup_pubkeys[i].to_bytes().into(), + addresses: address_lookup_table.addresses.to_vec(), + }; + address_lookup_accounts.push(address_lookup_table_account); + } + + address_lookup_accounts + }; + + Ok(address_lookup_accounts) + } + + pub fn build_v0_tx( + payer: Pubkey, + ixs: Vec, + signers: Vec<&dyn Signer>, + address_lookup_accounts: Vec, + recent_blockhash: Hash, + ) -> Result { + // Convert types directly for solana_sdk compatibility + let converted_payer: anchor_client::solana_sdk::pubkey::Pubkey = payer.to_bytes().into(); + let converted_ixs: Vec = ixs.iter().map(|ix| { + anchor_client::solana_sdk::instruction::Instruction { + program_id: ix.program_id.to_bytes().into(), + accounts: ix.accounts.iter().map(|acc| anchor_client::solana_sdk::instruction::AccountMeta { + pubkey: acc.pubkey.to_bytes().into(), + is_signer: acc.is_signer, + is_writable: acc.is_writable, + }).collect(), + data: ix.data.clone(), + } + }).collect(); + let converted_lookup_accounts: Vec = address_lookup_accounts.iter().map(|lut| { + anchor_client::solana_sdk::message::AddressLookupTableAccount { + key: lut.key.to_bytes().into(), + addresses: lut.addresses.iter().map(|addr| addr.to_bytes().into()).collect(), + } + }).collect(); + let converted_blockhash: anchor_client::solana_sdk::hash::Hash = anchor_client::solana_sdk::hash::Hash::new_from_array(recent_blockhash.to_bytes()); + + let v0_message = anchor_client::solana_sdk::message::v0::Message::try_compile( + &converted_payer, + &converted_ixs, + &converted_lookup_accounts, + converted_blockhash + ).unwrap(); + + let v0_tx = VersionedTransaction::try_new(anchor_client::solana_sdk::message::VersionedMessage::V0(v0_message), &signers) + .unwrap(); + + Ok(v0_tx) + } + + pub fn to_v0_tx(&self) -> Result { + TransactionBuilder::build_v0_tx( + self.payer, + self.ixs()?, + self.signers()?, + self.address_lookup_tables.clone(), + self.recent_blockhash.unwrap_or_default(), + ) + } + + pub fn to_v0_tx_with_payer( + &self, + payer: T, + ) -> Result { + if payer.as_signer().pubkey().to_bytes() != self.payer.to_bytes() { + return Err(OnDemandError::SolanaPayerMismatch); + } + + TransactionBuilder::build_v0_tx( + self.payer, + self.ixs()?, + self.signers_with_payer(&payer)?, + self.address_lookup_tables.clone(), + self.recent_blockhash.unwrap_or_default(), + ) + } +} + +impl TryFrom for Transaction { + type Error = OnDemandError; + + fn try_from(builder: TransactionBuilder) -> Result { + builder.to_legacy_tx() + } +} + +impl TryFrom for VersionedTransaction { + type Error = OnDemandError; + + fn try_from(builder: TransactionBuilder) -> Result { + builder.to_v0_tx() + } +} +// Types for TypeState builder pattern + +// #[derive(Default, Clone)] +// pub struct EmptyIxs; + +// #[derive(Default, Clone)] +// pub struct TransactionIxs(Vec); + +// #[derive(Default, Clone)] +// pub struct TransactionBuilderV0 { +// payer: Pubkey, +// ixs: U, +// compute_units: Option, +// priority_fees: Option, +// recent_blockhash: Option, +// min_context_slot: Option, +// address_lookup_tables: Vec, +// signers: Vec>, +// } +// impl TransactionBuilderV0 { +// pub fn new(payer: Pubkey) -> Self { +// Self { +// payer, +// ..Default::default() +// } +// } + +// pub fn add_ix(&self, ix: Instruction) -> TransactionBuilderV0 { +// TransactionBuilderV0 { +// payer: self.payer, +// ixs: TransactionIxs(vec![ix]), +// compute_units: self.compute_units, +// priority_fees: self.priority_fees, +// recent_blockhash: self.recent_blockhash, +// min_context_slot: self.min_context_slot, +// address_lookup_tables: self.address_lookup_tables.clone(), +// signers: self.signers.clone(), +// } +// } +// } + +#[cfg(test)] +mod tests { + use super::*; + use ::solana_program::instruction::AccountMeta; + use anchor_client::solana_sdk::signer::keypair::Keypair; + use tokio::sync::{OnceCell, RwLock}; + + // #[test] + // fn test_missing_signer() { + // let program_id = Pubkey::new_unique(); + // let payer = Arc::new(Keypair::new()); + // let missing_signer = Arc::new(Keypair::new()); +// + // let ixn = Instruction::new_with_bytes( + // program_id, + // &vec![1u8, 2u8, 3u8, 4u8], + // vec![ + // AccountMeta::new(payer.pubkey(), true), + // AccountMeta::new_readonly(missing_signer.pubkey(), true), // missing signer here + // AccountMeta::new_readonly(Pubkey::new_unique(), false), + // ], + // ); +// + // let mut tx = TransactionBuilder::new(payer.pubkey()).add_ix(ixn); +// + // assert_eq!(tx.ixs().unwrap_or_default().len(), 1); + // assert_eq!(tx.payer(), payer.pubkey()); + // assert!(!tx.has_payer()); +// + // // 1. Should fail with missing payer + // let to_tx_result = tx.to_legacy_tx(); + // assert!(to_tx_result.is_err()); +// + // if let OnDemandError::SolanaPayerSignerMissing(expected_payer) = + // to_tx_result.as_ref().unwrap_err() + // { + // if *expected_payer != payer.pubkey().to_string() { + // panic!("Unexpected error message: {}", to_tx_result.unwrap_err()) + // } + // } else { + // panic!("Unexpected error: {:?}", to_tx_result.unwrap_err()) + // } +// + // // 2. Should fail with missing signer + // let to_tx_result = tx.to_legacy_tx_with_payer(payer.clone()); + // assert!(to_tx_result.is_err()); +// + // if let OnDemandError::SolanaMissingSigner(signer) = to_tx_result.as_ref().unwrap_err() { + // if *signer != missing_signer.pubkey().to_string() { + // panic!("Unexpected error message: {}", to_tx_result.unwrap_err()) + // } + // } else { + // panic!("Unexpected error: {:?}", to_tx_result.unwrap_err()) + // } +// + // // 3. Should succeed with missing signer added + // tx = tx.add_signer(missing_signer); + // let to_tx_result = tx.to_legacy_tx_with_payer(payer.clone()); + // assert!(to_tx_result.is_ok()); + // } + + #[test] + fn test_add_compute_budget_ixs() { + let payer = Arc::new(Keypair::new()); + let payer_pubkey = payer.pubkey(); + let payer_pubkey_converted = ::solana_program::pubkey::Pubkey::new_from_array(payer_pubkey.to_bytes()); + + let tx = TransactionBuilder::new_with_payer(payer.clone()) + .add_ix(Instruction::new_with_bytes( + Pubkey::new_unique(), + &vec![1u8, 2u8, 3u8, 4u8], + vec![ + AccountMeta::new(payer_pubkey_converted, true), + AccountMeta::new_readonly(Pubkey::new_unique(), false), + ], + )) + .set_compute_units(750_000); + assert_eq!(tx.ixs().unwrap_or_default().len(), 2); + + let tx = TransactionBuilder::new_with_payer(payer.clone()) + .add_ix(Instruction::new_with_bytes( + Pubkey::new_unique(), + &vec![1u8, 2u8, 3u8, 4u8], + vec![ + AccountMeta::new(payer_pubkey_converted, true), + AccountMeta::new_readonly(Pubkey::new_unique(), false), + ], + )) + .set_priority_fees(500); + assert_eq!(tx.ixs().unwrap_or_default().len(), 2); + + let tx = TransactionBuilder::new_with_payer(payer.clone()) + .add_ix(Instruction::new_with_bytes( + Pubkey::new_unique(), + &vec![1u8, 2u8, 3u8, 4u8], + vec![ + AccountMeta::new(payer_pubkey_converted, true), + AccountMeta::new_readonly(Pubkey::new_unique(), false), + ], + )) + .set_compute_units(750_000) + .set_priority_fees(500); + assert_eq!(tx.ixs().unwrap_or_default().len(), 3); + } + + #[test] + fn test_transaction_builder_with_arc_payer() { + let payer = Arc::new(Keypair::new()); + + let tx = TransactionBuilder::new_with_payer(payer.clone()) + .add_ix(Instruction::new_with_bytes( + Pubkey::new_unique(), + &vec![1u8, 2u8, 3u8, 4u8], + vec![ + AccountMeta::new(payer.signer_pubkey(), true), + AccountMeta::new_readonly(Pubkey::new_unique(), false), + ], + )) + .set_compute_units(750_000); + + assert_eq!(tx.payer.to_bytes(), payer.pubkey().to_bytes()); + } + + pub static PAYER_KEYPAIR: OnceCell>>> = OnceCell::const_new(); + + async fn get_payer_keypair() -> &'static Arc>> { + PAYER_KEYPAIR + .get_or_init(|| async { Arc::new(RwLock::new(Arc::new(Keypair::new()))) }) + .await + } + + #[tokio::test] + async fn test_transaction_builder_with_rwlock_payer() { + let payer = get_payer_keypair().await; + let payer_arc = payer.read().await.clone(); + + let tx = TransactionBuilder::new_with_payer(payer_arc.clone()) + .add_ix(Instruction::new_with_bytes( + Pubkey::new_unique(), + &vec![1u8, 2u8, 3u8, 4u8], + vec![ + AccountMeta::new(payer_arc.signer_pubkey(), true), + AccountMeta::new_readonly(Pubkey::new_unique(), false), + ], + )) + .set_compute_units(750_000); + + assert_eq!(tx.payer.to_bytes(), payer_arc.pubkey().to_bytes()); + } + + #[tokio::test] + async fn test_transaction_builder_with_arcswap_payer() { + let payer = arc_swap::ArcSwap::new(Arc::new(Keypair::new())); + let payer_arc = payer.load(); + + let tx = TransactionBuilder::new_with_payer(payer_arc.clone()) + .add_ix(Instruction::new_with_bytes( + Pubkey::new_unique(), + &vec![1u8, 2u8, 3u8, 4u8], + vec![ + AccountMeta::new(payer_arc.signer_pubkey(), true), + AccountMeta::new_readonly(Pubkey::new_unique(), false), + ], + )) + .set_compute_units(750_000); + + assert_eq!(tx.payer.to_bytes(), payer_arc.pubkey().to_bytes()); + } +} diff --git a/programs/switchboard-on-demand/src/client/utils.rs b/programs/switchboard-on-demand/src/client/utils.rs new file mode 100644 index 0000000000..1eb2f8c6d4 --- /dev/null +++ b/programs/switchboard-on-demand/src/client/utils.rs @@ -0,0 +1,434 @@ +use crate::prelude::*; +use anyhow::anyhow; +use sha2::{Digest, Sha256}; +use anchor_client::solana_sdk::client::SyncClient; +use anchor_client::solana_sdk::signer::keypair::{keypair_from_seed, read_keypair_file, Keypair}; +use anchor_client::solana_sdk::signer::Signer; +use std::env; +use std::result::Result; +use std::str::FromStr; +use std::sync::Arc; +use tokio::sync::RwLock; +use anchor_client::solana_sdk::transaction::Transaction; +use crate::anchor_traits::*; +use crate::Pubkey; +use anchor_client::anchor_lang::AccountDeserialize; +use anyhow::Error as AnyhowError; +use anchor_client::solana_sdk::message::v0::Message as V0Message; +use anchor_client::solana_sdk::transaction::VersionedTransaction; +use anchor_client::solana_sdk::compute_budget::ComputeBudgetInstruction; +use crate::solana_program::hash::Hash; +use anchor_client::solana_client::nonblocking::rpc_client::RpcClient; +use anchor_client::solana_sdk::address_lookup_table::AddressLookupTableAccount; +use anchor_client::solana_sdk::message::VersionedMessage::V0; + +pub async fn ix_to_tx_v0( + rpc_client: &RpcClient, + ixs: &[Instruction], + signers: &[&Keypair], + blockhash: Hash, + luts: &[AddressLookupTableAccount], +) -> Result { + let payer_original = signers[0].pubkey(); + let payer: anchor_client::solana_sdk::pubkey::Pubkey = payer_original.to_bytes().into(); + + // Auto-detect Compute Unit Limit + let compute_unit_limit = estimate_compute_units(rpc_client, ixs, luts, blockhash, signers).await.unwrap_or(1_400_000); // Default to 1.4M units if estimate fails + + // Add Compute Budget Instruction (Optional but improves execution) + let cus = std::cmp::min((compute_unit_limit as f64 * 1.4) as u32, 1_400_000); + let compute_budget_ix = ComputeBudgetInstruction::set_compute_unit_limit(cus); + // TODO: make dynamic + let priority_fee_ix = ComputeBudgetInstruction::set_compute_unit_price(10_000); + + // Convert SDK instructions to program instructions + let compute_budget_ix_converted = Instruction { + program_id: compute_budget_ix.program_id.to_bytes().into(), + accounts: compute_budget_ix.accounts.iter().map(|acc| AccountMeta { + pubkey: acc.pubkey.to_bytes().into(), + is_signer: acc.is_signer, + is_writable: acc.is_writable, + }).collect(), + data: compute_budget_ix.data.clone(), + }; + + let priority_fee_ix_converted = Instruction { + program_id: priority_fee_ix.program_id.to_bytes().into(), + accounts: priority_fee_ix.accounts.iter().map(|acc| AccountMeta { + pubkey: acc.pubkey.to_bytes().into(), + is_signer: acc.is_signer, + is_writable: acc.is_writable, + }).collect(), + data: priority_fee_ix.data.clone(), + }; + + let mut final_ixs = vec![ + compute_budget_ix_converted, + priority_fee_ix_converted, + ]; + final_ixs.extend_from_slice(ixs); + + // Convert AddressLookupTableAccount types + let converted_luts: Vec = luts.iter().map(|lut| { + anchor_client::solana_sdk::message::AddressLookupTableAccount { + key: lut.key.to_bytes().into(), + addresses: lut.addresses.iter().map(|addr| addr.to_bytes().into()).collect(), + } + }).collect(); + + // Convert instructions to anchor-client types + let converted_ixs: Vec = final_ixs.iter().map(|ix| { + anchor_client::solana_sdk::instruction::Instruction { + program_id: ix.program_id.to_bytes().into(), + accounts: ix.accounts.iter().map(|acc| anchor_client::solana_sdk::instruction::AccountMeta { + pubkey: acc.pubkey.to_bytes().into(), + is_signer: acc.is_signer, + is_writable: acc.is_writable, + }).collect(), + data: ix.data.clone(), + } + }).collect(); + + // Create Message with Address Lookup Tables (ALTs) + let converted_blockhash: anchor_client::solana_sdk::hash::Hash = blockhash.to_bytes().into(); + let message = V0Message::try_compile(&payer, &converted_ixs, &converted_luts, converted_blockhash) + .map_err(|_| OnDemandError::SolanaSignError)?; + + let message = V0(message); + // if message.header().num_required_signatures as usize != signers.len() { + // // Skips all signature validation + // return Ok(VersionedTransaction { + // message: message, + // signatures: vec![], + // }) + // } + // Create Versioned Transaction + let tx = VersionedTransaction::try_new(message, signers) + .map_err(|_| OnDemandError::SolanaSignError)?; + + Ok(tx) +} + +/// Estimates Compute Unit Limit for Instructions +async fn estimate_compute_units(rpc_client: &RpcClient, ixs: &[Instruction], luts: &[AddressLookupTableAccount], blockhash: Hash, signers: &[&Keypair]) -> Result { + let payer_original = signers[0].pubkey(); + let payer: anchor_client::solana_sdk::pubkey::Pubkey = payer_original.to_bytes().into(); + let mut ixs = ixs.to_vec(); + let compute_limit_ix = ComputeBudgetInstruction::set_compute_unit_limit(1_400_000); + let compute_limit_ix_converted = Instruction { + program_id: compute_limit_ix.program_id.to_bytes().into(), + accounts: compute_limit_ix.accounts.iter().map(|acc| AccountMeta { + pubkey: acc.pubkey.to_bytes().into(), + is_signer: acc.is_signer, + is_writable: acc.is_writable, + }).collect(), + data: compute_limit_ix.data.clone(), + }; + ixs.insert(0, compute_limit_ix_converted); + + // Convert AddressLookupTableAccount types for this function too + let converted_luts: Vec = luts.iter().map(|lut| { + anchor_client::solana_sdk::message::AddressLookupTableAccount { + key: lut.key.to_bytes().into(), + addresses: lut.addresses.iter().map(|addr| addr.to_bytes().into()).collect(), + } + }).collect(); + + // Convert instructions to anchor-client types + let converted_ixs: Vec = ixs.iter().map(|ix| { + anchor_client::solana_sdk::instruction::Instruction { + program_id: ix.program_id.to_bytes().into(), + accounts: ix.accounts.iter().map(|acc| anchor_client::solana_sdk::instruction::AccountMeta { + pubkey: acc.pubkey.to_bytes().into(), + is_signer: acc.is_signer, + is_writable: acc.is_writable, + }).collect(), + data: ix.data.clone(), + } + }).collect(); + let converted_blockhash: anchor_client::solana_sdk::hash::Hash = blockhash.to_bytes().into(); + + let message = V0Message::try_compile(&payer, &converted_ixs, &converted_luts, converted_blockhash) + .map_err(|_| OnDemandError::SolanaSignError)?; + + // Create Versioned Transaction + let tx = VersionedTransaction::try_new(V0(message), signers) + .map_err(|_| OnDemandError::SolanaSignError)?; + // Simulate Transaction to Estimate Compute Usage + let sim_result = rpc_client.simulate_transaction(&tx) + .await + .map_err(|_| anyhow!("Failed to simulate transaction"))?; + + if let Some(units) = sim_result.value.units_consumed { + Ok(units as u32) + } else { + Err(anyhow!("Failed to estimate compute units")) + } +} + +pub fn ix_to_tx( + ixs: &[Instruction], + signers: &[&Keypair], + blockhash: crate::solana_program::hash::Hash, +) -> Result { + // Convert instructions to compatible type for solana_sdk + let converted_ixs: Vec = ixs.iter().map(|ix| { + anchor_client::solana_sdk::instruction::Instruction { + program_id: ix.program_id.to_bytes().into(), + accounts: ix.accounts.iter().map(|acc| anchor_client::solana_sdk::instruction::AccountMeta { + pubkey: acc.pubkey.to_bytes().into(), + is_signer: acc.is_signer, + is_writable: acc.is_writable, + }).collect(), + data: ix.data.clone(), + } + }).collect(); + + let converted_msg = anchor_client::solana_sdk::message::Message::new(&converted_ixs, Some(&signers[0].pubkey().to_bytes().into())); + let mut tx = Transaction::new_unsigned(converted_msg); + let converted_blockhash: anchor_client::solana_sdk::hash::Hash = blockhash.to_bytes().into(); + tx.try_sign(&signers.to_vec(), converted_blockhash) + .map_err(|_e| OnDemandError::SolanaSignError)?; + Ok(tx) +} + +pub async fn get_enclave_signer_pubkey( + enclave_signer: &Arc>, +) -> Result, OnDemandError> { + let enclave_signer = enclave_signer.clone(); + let ro_enclave_signer = enclave_signer.read().await; + let pubkey_bytes = ro_enclave_signer.pubkey().to_bytes(); + let pubkey = Arc::new(Pubkey::new_from_array(pubkey_bytes)); + Ok(pubkey) +} + +pub fn load_env_pubkey(key: &str) -> Result { + Pubkey::from_str(&env::var(key).unwrap_or_default()) + .map_err(|_| OnDemandError::EnvVariableMissing) +} + +/// Parse a string into an optional Pubkey. If the string is empty, return None. +pub fn parse_optional_pubkey(var: &str) -> Option { + if var.is_empty() { + None + } else { + match Pubkey::from_str(var) { + Ok(pubkey) => { + if pubkey != Pubkey::default() { + Some(pubkey) + } else { + None + } + } + Err(_) => None, + } + } +} + +/// Generates a keypair from a base seed, secret key, optional additional bytes, and an optional program ID. +/// +/// # Arguments +/// +/// * `base` - The base seed as a string. +/// * `secret_key` - The secret key as a vector of bytes. +/// * `more_bytes` - Optional additional bytes to include in the seed. +/// * `program_id` - Optional program ID to include in the seed. +/// +/// # Returns +/// +/// Returns a `Result` containing an `Arc` if the keypair is successfully derived, or an `OnDemandError` if there is an error. +/// +/// # Errors +/// +/// Returns an `OnDemandError` with the message "InvalidSecretKey" if the length of the secret key is not 32 bytes. +/// Returns an `OnDemandError` with the message "Failed to derive keypair" if there is an error deriving the keypair. +/// +/// # Example +/// +/// ```rust +/// use solana_sdk::pubkey::Pubkey; +/// use solana_sdk::signature::{Keypair, keypair_from_seed}; +/// use solana_sdk::hash::Hash; +/// use sha2::{Digest, Sha256}; +/// use std::sync::Arc; +/// use switchboard_solana::OnDemandError; +/// +/// let base = "base_seed"; +/// let secret_key = vec![0; 32]; +/// let more_bytes = Some(vec![1, 2, 3]); +/// let program_id = Some(Pubkey::new_unique()); +/// +/// let result = switchboard_solana::client::utils::keypair_from_base_seed(base, secret_key, more_bytes, program_id); +/// match result { +/// Ok(keypair) => { +/// // Key pair successfully derived +/// println!("Derived keypair: {:?}", keypair); +/// } +/// Err(error) => { +/// // Error deriving key pair +/// println!("Failed to derive keypair: {:?}", error); +/// } +/// } +/// ``` +pub fn keypair_from_base_seed( + base: &str, + secret_key: Vec, + more_bytes: Option>, + program_id: Option, +) -> Result, OnDemandError> { + if secret_key.len() != 32 { + return Err(OnDemandError::InvalidSecretKey); + } + + let mut seed = base.as_bytes().to_vec(); + seed.extend_from_slice(&secret_key); + + if let Some(bytes) = more_bytes.as_ref() { + seed.extend_from_slice(bytes); + } + + // Optionally, allow the progam ID to be included in the bytes so we + // can create new environments on different program IDs without collisions. + if let Some(program_id) = program_id.as_ref() { + seed.extend_from_slice(program_id.as_ref()); + } else { + seed.extend_from_slice(crate::get_switchboard_on_demand_program_id().as_ref()); + } + + match keypair_from_seed(&Sha256::digest(&seed)) { + Ok(keypair) => Ok(Arc::new(keypair)), + Err(e) => { + if let Some(err) = e.source() { + println!("Failed to derive keypair -- {}", err); + } + + Err(OnDemandError::KeyDerivationFailed) + } + } +} + +pub fn signer_to_pubkey(signer: Arc) -> std::result::Result { + let pubkey_bytes = signer.pubkey().to_bytes(); + Ok(Pubkey::new_from_array(pubkey_bytes)) +} + +pub fn load_keypair_fs(fs_path: &str) -> Result, OnDemandError> { + match read_keypair_file(fs_path) { + Ok(keypair) => Ok(Arc::new(keypair)), + Err(e) => { + if let Some(err) = e.source() { + println!("Failed to read keypair file -- {}", err); + } + + Err(OnDemandError::IoError) + } + } +} + +/// Fetches a zero-copy account from the Solana blockchain. +/// +/// # Arguments +/// +/// * `client` - The Solana RPC client used to interact with the blockchain. +/// * `pubkey` - The public key of the account to fetch. +/// +/// # Returns +/// +/// Returns a result containing the fetched account data as the specified type `T`, or an `OnDemandError` if an error occurs. +/// +/// # Errors +/// +/// This function can return the following errors: +/// +/// * `OnDemandError::AccountNotFound` - If the account with the specified public key is not found. +/// * `OnDemandError::Message("no discriminator found")` - If no discriminator is found in the account data. +/// * `OnDemandError::Message("Discriminator error, check the account type")` - If the discriminator in the account data does not match the expected discriminator for type `T`. +/// * `OnDemandError::Message("AnchorParseError")` - If an error occurs while parsing the account data into type `T`. +pub async fn fetch_zerocopy_account( + client: &crate::RpcClient, + pubkey: Pubkey, +) -> Result { + let data = client + .get_account_data(&pubkey.to_bytes().into()) + .await + .map_err(|_| OnDemandError::AccountNotFound)?; + + if data.len() < T::discriminator().len() { + return Err(OnDemandError::InvalidDiscriminator); + } + + let mut disc_bytes = [0u8; 8]; + disc_bytes.copy_from_slice(&data[..8]); + if disc_bytes != T::discriminator() { + return Err(OnDemandError::InvalidDiscriminator); + } + + Ok(*bytemuck::try_from_bytes::(&data[8..]) + .map_err(|_| OnDemandError::AnchorParseError)?) +} + +/// Fetches the account data synchronously from the Solana blockchain using the provided client. +/// +/// # Arguments +/// +/// * `client` - The client used to interact with the Solana blockchain. +/// * `pubkey` - The public key of the account to fetch. +/// +/// # Generic Parameters +/// +/// * `C` - The type of the client, which must implement the `SyncClient` trait. +/// * `T` - The type of the account data, which must implement the `bytemuck::Pod`, `Discriminator`, and `Owner` traits. +/// +/// # Returns +/// +/// Returns a `Result` containing the fetched account data of type `T` if successful, or an `OnDemandError` if an error occurs. +pub fn fetch_zerocopy_account_sync( + client: &C, + pubkey: Pubkey, +) -> Result { + let data = client + .get_account_data(&pubkey.to_bytes().into()) + .map_err(|_| OnDemandError::AccountNotFound)? + .ok_or(OnDemandError::AccountNotFound)?; + + if data.len() < T::discriminator().len() { + return Err(OnDemandError::InvalidDiscriminator); + } + + let mut disc_bytes = [0u8; 8]; + disc_bytes.copy_from_slice(&data[..8]); + if disc_bytes != T::discriminator() { + return Err(OnDemandError::InvalidDiscriminator); + } + + Ok(*bytemuck::try_from_bytes::(&data[8..]) + .map_err(|_| OnDemandError::AnchorParseError)?) +} + +pub async fn fetch_borsh_account( + client: &crate::RpcClient, + pubkey: Pubkey, +) -> Result { + let account_data = client + .get_account_data(&pubkey.to_bytes().into()) + .await + .map_err(|_| OnDemandError::AccountNotFound)?; + + T::try_deserialize(&mut account_data.as_slice()) + .map_err(|_| OnDemandError::AnchorParseError) +} + +pub fn fetch_borsh_account_sync( + client: &C, + pubkey: Pubkey, +) -> Result { + let data = client + .get_account_data(&pubkey.to_bytes().into()) + .map_err(|_| OnDemandError::AccountNotFound)? + .ok_or(OnDemandError::AccountNotFound)?; + + T::try_deserialize(&mut data.as_slice()).map_err(|_| OnDemandError::AnchorParseError) +} + + +// type GenericError = Box; diff --git a/programs/switchboard-on-demand/src/decimal.rs b/programs/switchboard-on-demand/src/decimal.rs new file mode 100644 index 0000000000..53266409d4 --- /dev/null +++ b/programs/switchboard-on-demand/src/decimal.rs @@ -0,0 +1,230 @@ +// #![allow(unaligned_references)] +use core::cmp::Ordering; + +use borsh::{BorshDeserialize, BorshSerialize}; +use rust_decimal::prelude::FromPrimitive; +use rust_decimal::Decimal; + +use crate::prelude::*; + +/// A decimal number serializable with Borsh +#[derive(Default, Eq, PartialEq, Copy, Clone, BorshSerialize, BorshDeserialize)] +pub struct BorshDecimal { + /// The mantissa (significant digits) of the decimal + pub mantissa: i128, + /// The scale (number of decimal places) + pub scale: u32, +} +impl From for BorshDecimal { + fn from(s: Decimal) -> Self { + Self { + mantissa: s.mantissa(), + scale: s.scale(), + } + } +} +impl From<&Decimal> for BorshDecimal { + fn from(s: &Decimal) -> Self { + Self { + mantissa: s.mantissa(), + scale: s.scale(), + } + } +} +impl From for BorshDecimal { + fn from(s: SwitchboardDecimal) -> Self { + Self { + mantissa: s.mantissa, + scale: s.scale, + } + } +} +impl From for SwitchboardDecimal { + fn from(val: BorshDecimal) -> Self { + SwitchboardDecimal { + mantissa: val.mantissa, + scale: val.scale, + } + } +} +impl TryInto for &BorshDecimal { + type Error = OnDemandError; + fn try_into(self) -> std::result::Result { + Decimal::try_from_i128_with_scale(self.mantissa, self.scale) + .map_err(|_| OnDemandError::DecimalConversionError) + } +} + +impl TryInto for BorshDecimal { + type Error = OnDemandError; + fn try_into(self) -> std::result::Result { + Decimal::try_from_i128_with_scale(self.mantissa, self.scale) + .map_err(|_| OnDemandError::DecimalConversionError) + } +} + +/// Switchboard's internal decimal representation for oracle data +#[repr(packed)] +#[derive(Default, Debug, Eq, PartialEq, BorshDeserialize)] +pub struct SwitchboardDecimal { + /// The part of a floating-point number that represents the significant digits of that number, and that is multiplied by the base, 10, raised to the power of scale to give the actual value of the number. + pub mantissa: i128, + /// The number of decimal places to move to the left to yield the actual value. + pub scale: u32, +} + +impl SwitchboardDecimal { + /// Creates a new SwitchboardDecimal with the given mantissa and scale + pub fn new(mantissa: i128, scale: u32) -> SwitchboardDecimal { + Self { mantissa, scale } + } + /// Converts from rust_decimal::Decimal to SwitchboardDecimal + pub fn from_rust_decimal(d: Decimal) -> SwitchboardDecimal { + Self::new(d.mantissa(), d.scale()) + } + /// Creates a SwitchboardDecimal from a 64-bit floating point number + pub fn from_f64(v: f64) -> SwitchboardDecimal { + let dec = Decimal::from_f64(v).unwrap(); + Self::from_rust_decimal(dec) + } + /// Scales the decimal to a new scale, returning the mantissa + pub fn scale_to(&self, new_scale: u32) -> i128 { + match { self.scale }.cmp(&new_scale) { + std::cmp::Ordering::Greater => self + .mantissa + .checked_div(10_i128.pow(self.scale - new_scale)) + .unwrap(), + std::cmp::Ordering::Less => self + .mantissa + .checked_mul(10_i128.pow(new_scale - self.scale)) + .unwrap(), + std::cmp::Ordering::Equal => self.mantissa, + } + } + /// Returns a new SwitchboardDecimal with the specified scale + pub fn new_with_scale(&self, new_scale: u32) -> Self { + let mantissa = self.scale_to(new_scale); + SwitchboardDecimal { + mantissa, + scale: new_scale, + } + } +} +impl From for SwitchboardDecimal { + fn from(val: Decimal) -> Self { + SwitchboardDecimal::new(val.mantissa(), val.scale()) + } +} +impl TryInto for &SwitchboardDecimal { + type Error = OnDemandError; + fn try_into(self) -> std::result::Result { + Decimal::try_from_i128_with_scale(self.mantissa, self.scale) + .map_err(|_| OnDemandError::DecimalConversionError) + } +} + +impl TryInto for SwitchboardDecimal { + type Error = OnDemandError; + fn try_into(self) -> std::result::Result { + Decimal::try_from_i128_with_scale(self.mantissa, self.scale) + .map_err(|_| OnDemandError::DecimalConversionError) + } +} + +impl Ord for SwitchboardDecimal { + fn cmp(&self, other: &Self) -> Ordering { + let s: Decimal = self.try_into().unwrap(); + let other: Decimal = other.try_into().unwrap(); + s.cmp(&other) + } +} + +impl PartialOrd for SwitchboardDecimal { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } + fn lt(&self, other: &Self) -> bool { + let s: Decimal = self.try_into().unwrap(); + let other: Decimal = other.try_into().unwrap(); + s < other + } + fn le(&self, other: &Self) -> bool { + let s: Decimal = self.try_into().unwrap(); + let other: Decimal = other.try_into().unwrap(); + s <= other + } + fn gt(&self, other: &Self) -> bool { + let s: Decimal = self.try_into().unwrap(); + let other: Decimal = other.try_into().unwrap(); + s > other + } + fn ge(&self, other: &Self) -> bool { + let s: Decimal = self.try_into().unwrap(); + let other: Decimal = other.try_into().unwrap(); + s >= other + } +} + +impl From for bool { + fn from(s: SwitchboardDecimal) -> Self { + let dec: Decimal = (&s).try_into().unwrap(); + dec.round().mantissa() != 0 + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn switchboard_decimal_into_rust_decimal() { + let swb_decimal = &SwitchboardDecimal { + mantissa: 12345, + scale: 2, + }; + let decimal: Decimal = swb_decimal.try_into().unwrap(); + assert_eq!(decimal.mantissa(), 12345); + assert_eq!(decimal.scale(), 2); + } + + #[test] + fn empty_switchboard_decimal_is_false() { + let swb_decimal = SwitchboardDecimal { + mantissa: 0, + scale: 0, + }; + let b: bool = swb_decimal.into(); + assert!(!b); + let swb_decimal_neg = SwitchboardDecimal { + mantissa: -0, + scale: 0, + }; + let b: bool = swb_decimal_neg.into(); + assert!(!b); + } + + // #[test] + // fn switchboard_decimal_to_u64() { + // // 1234.5678 + // let swb_decimal = SwitchboardDecimal { + // mantissa: 12345678, + // scale: 4, + // }; + // let b: u64 = swb_decimal.try_into().unwrap(); + // assert_eq!(b, 1234); + // } + // + // #[test] + // fn switchboard_decimal_to_f64() { + // // 1234.5678 + // let swb_decimal = SwitchboardDecimal { + // mantissa: 12345678, + // scale: 4, + // }; + // let b: f64 = swb_decimal.try_into().unwrap(); + // assert_eq!(b, 1234.5678); + // + // let swb_f64 = SwitchboardDecimal::from_f64(1234.5678); + // assert_eq!(swb_decimal, swb_f64); + // } +} diff --git a/programs/switchboard-on-demand/src/instruction_compat.rs b/programs/switchboard-on-demand/src/instruction_compat.rs new file mode 100644 index 0000000000..7e21121072 --- /dev/null +++ b/programs/switchboard-on-demand/src/instruction_compat.rs @@ -0,0 +1,144 @@ +//! Instruction compatibility layer for mixed Solana SDK versions +//! +//! When both solana-v2 and client features are enabled, this module provides +//! a unified Instruction type that can be used throughout the codebase. + +#[cfg(all(feature = "solana-v2", feature = "client"))] +use anchor_lang::solana_program as v3_program; + +#[cfg(all(feature = "solana-v2", feature = "client"))] +use crate::solana_compat as v2_compat; + +/// When both features are enabled, create wrapper types that can convert between versions +#[cfg(all(feature = "solana-v2", feature = "client"))] +pub mod mixed_version { + use super::*; + + /// Wrapper for instructions that need to work with both SDK versions + pub struct CompatInstruction { + inner_v3: v3_program::instruction::Instruction, + } + + impl CompatInstruction { + /// Create from v3 Instruction (used by build_ix when anchor is enabled) + pub fn from_v3(ix: v3_program::instruction::Instruction) -> Self { + Self { inner_v3: ix } + } + + /// Convert to v2 Instruction for return values + pub fn to_v2(self) -> v2_compat::Instruction { + v2_compat::Instruction { + program_id: v2_compat::Pubkey::from(self.inner_v3.program_id.to_bytes()), + accounts: self + .inner_v3 + .accounts + .into_iter() + .map(|meta| v2_compat::AccountMeta { + pubkey: v2_compat::Pubkey::from(meta.pubkey.to_bytes()), + is_signer: meta.is_signer, + is_writable: meta.is_writable, + }) + .collect(), + data: self.inner_v3.data, + } + } + + /// Access the inner v3 instruction mutably + pub fn inner_mut(&mut self) -> &mut v3_program::instruction::Instruction { + &mut self.inner_v3 + } + + /// Access the inner v3 instruction + pub fn inner(&self) -> &v3_program::instruction::Instruction { + &self.inner_v3 + } + } + + /// Implement From for v3_program path + impl From for CompatInstruction { + fn from(ix: v3_program::instruction::Instruction) -> Self { + Self::from_v3(ix) + } + } + + /// Generic conversion function that works with any Instruction type using unsafe transmute + /// + /// This is safe because all Solana Instruction types (v2, v3, anchor) have identical memory layout: + /// - program_id: Pubkey (32 bytes) + /// - accounts: Vec + /// - data: Vec + /// + /// SAFETY: The caller must ensure the input type has the exact same memory layout as + /// v3_program::instruction::Instruction + pub unsafe fn convert_any_instruction_to_compat_unsafe(ix: T) -> CompatInstruction { + // Transmute to v3 instruction - this is safe because all Solana Instruction types + // have identical memory layout + let v3_ix: v3_program::instruction::Instruction = std::mem::transmute_copy(&ix); + std::mem::forget(ix); // Prevent double-free + CompatInstruction::from_v3(v3_ix) + } + + /// Safe wrapper for trait-based conversion + pub fn convert_any_instruction_to_compat(ix: T) -> CompatInstruction + where + T: IntoInstructionBytes, + { + let (program_id_bytes, accounts_data, data) = ix.into_bytes(); + + // Reconstruct as v3 Instruction + let v3_ix = v3_program::instruction::Instruction { + program_id: v3_program::pubkey::Pubkey::from(program_id_bytes), + accounts: accounts_data + .into_iter() + .map(|(pubkey_bytes, is_signer, is_writable)| { + if is_writable { + if is_signer { + v3_program::instruction::AccountMeta::new( + v3_program::pubkey::Pubkey::from(pubkey_bytes), + true, + ) + } else { + v3_program::instruction::AccountMeta::new( + v3_program::pubkey::Pubkey::from(pubkey_bytes), + false, + ) + } + } else if is_signer { + v3_program::instruction::AccountMeta::new_readonly( + v3_program::pubkey::Pubkey::from(pubkey_bytes), + true, + ) + } else { + v3_program::instruction::AccountMeta::new_readonly( + v3_program::pubkey::Pubkey::from(pubkey_bytes), + false, + ) + } + }) + .collect(), + data, + }; + + CompatInstruction::from_v3(v3_ix) + } + + /// Trait for extracting bytes from any Instruction type + /// + /// This trait is implemented at the crate root (lib.rs) to ensure it's always in scope + pub trait IntoInstructionBytes { + fn into_bytes(self) -> ([u8; 32], Vec<([u8; 32], bool, bool)>, Vec); + } +} + +/// Macro helper to convert any instruction type +#[cfg(all(feature = "solana-v2", feature = "client"))] +#[macro_export] +macro_rules! to_compat_ix { + ($ix:expr) => {{ + $crate::instruction_compat::mixed_version::convert_any_instruction_to_compat($ix) + }}; +} + +/// Re-export for convenience +#[cfg(all(feature = "solana-v2", feature = "client"))] +pub use mixed_version::CompatInstruction; diff --git a/programs/switchboard-on-demand/src/instructions.rs b/programs/switchboard-on-demand/src/instructions.rs new file mode 100644 index 0000000000..088a31d92b --- /dev/null +++ b/programs/switchboard-on-demand/src/instructions.rs @@ -0,0 +1 @@ +pub use crate::on_demand::instructions::*; diff --git a/programs/switchboard-on-demand/src/macros.rs b/programs/switchboard-on-demand/src/macros.rs new file mode 100644 index 0000000000..5e5f9b1fd3 --- /dev/null +++ b/programs/switchboard-on-demand/src/macros.rs @@ -0,0 +1,179 @@ +/// Macro used to include code if the target_os is not 'solana'. +/// This is intended to be used for code that is primarily for off-chain Switchboard Functions. +#[macro_export] +macro_rules! cfg_client { + ($($item:item)*) => { + $( + #[cfg(all(feature = "client"))] + $item + )* + }; +} + +/// Helper macro to conditionally convert instruction types when both solana-v2 and client features are enabled +#[macro_export] +macro_rules! build_ix_compat { + ($program_id:expr, $accounts:expr, $params:expr) => {{ + $crate::utils::build_ix($program_id, $accounts, $params) + }}; +} + +/// Helper macro to wrap the final instruction return with type conversion if needed +/// When both solana-v2 and client features are enabled, code inside cfg_client! blocks +/// uses anchor's v3 types, but must return v2 types for compatibility +/// +/// SAFETY: This uses unsafe transmute internally, which is safe because all Solana +/// Instruction types (v2, v3, anchor) have identical memory layout +#[macro_export] +macro_rules! return_ix_compat { + ($ix:expr) => {{ + #[cfg(all(feature = "solana-v2", feature = "client"))] + { + // SAFETY: All Solana Instruction types have identical memory layout + // (program_id: Pubkey, accounts: Vec, data: Vec) + Ok(unsafe { + $crate::instruction_compat::mixed_version::convert_any_instruction_to_compat_unsafe( + $ix, + ) + } + .to_v2()) + } + #[cfg(not(all(feature = "solana-v2", feature = "client")))] + { + Ok($ix) + } + }}; +} + +/// Macro used to include code if the feature 'secrets' is enabled. +/// This is intended to be used for code that is primarily for off-chain Switchboard Secrets. +#[macro_export] +macro_rules! cfg_secrets { + ($($item:item)*) => { + $( + #[cfg(all(feature = "secrets"))] + $item + )* + }; +} + +/// Macro used to include storage code if the storage feature is enabled. +#[macro_export] +macro_rules! cfg_storage { + ($($item:item)*) => { + $( + #[cfg(all(feature = "storage"))] + $item + )* + }; +} + +/// Retry a given expression a specified number of times with a delay between each attempt. +/// +/// # Arguments +/// +/// * `attempts` - The number of attempts to make. +/// * `delay_ms` - The delay in milliseconds between each attempt. +/// * `expr` - The expression to be retried. +/// +/// # Returns +/// +/// Returns a `Result` containing the value of the expression if it succeeds within the specified number of attempts, +/// or an error if it fails on all attempts. +/// +/// # Examples +/// ``` +/// use switchboard_solana::retry; +/// +/// // Retry a blockhash fetch 3 times with a delay of 500ms in between each failure +/// let blockhash = retry!(3, 500, rpc.get_latest_blockhash().await) +/// .await +/// .map_err(|e| OnDemandError::SolanaBlockhashFetchError(Arc::new(e)))?; +/// ``` +#[macro_export] +macro_rules! retry { + ($attempts:expr, $delay_ms:expr, $expr:expr) => {{ + async { + let mut attempts = $attempts; + loop { + match $expr { + Ok(val) => break Ok(val), + Err(_) if attempts > 1 => { + attempts -= 1; + tokio::time::sleep(tokio::time::Duration::from_millis($delay_ms)).await; + } + Err(e) => break Err(e), + } + } + } + }}; +} + +/// Retry a given expression a specified number of times with a delay between each attempt. +/// This will block the current thread until a value is resolved or the maximum number of attempts is reached. +/// +/// # Arguments +/// +/// * `attempts` - The number of attempts to make. +/// * `delay_ms` - The delay in milliseconds between each attempt. +/// * `expr` - The expression to be retried. +/// +/// # Returns +/// +/// Returns a `Result` containing the value of the expression if it succeeds within the specified number of attempts, +/// or an error if it fails on all attempts. +/// +/// # Examples +/// ``` +/// use switchboard_solana::blocking_retry; +/// +/// // Retry a blockhash fetch 3 times with a delay of 500ms in between each failure +/// let blockhash = blocking_retry!(3, 500, rpc.get_latest_blockhash()) +/// .map_err(|e| OnDemandError::SolanaBlockhashFetchError(Arc::new(e)))?; +/// ``` +#[macro_export] +macro_rules! blocking_retry { + ($attempts:expr, $delay_ms:expr, $expr:expr) => {{ + let mut attempts = $attempts; + loop { + match $expr { + Ok(val) => break Ok(val), + Err(_) if attempts > 1 => { + attempts -= 1; + std::thread::sleep(tokio::time::Duration::from_millis($delay_ms)); + } + Err(e) => break Err(e), + } + } + }}; +} + +/// Implements AccountDeserialize trait for Anchor compatibility +#[macro_export] +macro_rules! impl_account_deserialize { + ($struct_name:ident) => { + use anchor_client; + use anchor_lang::prelude::{Error, ErrorCode}; + + impl anchor_client::anchor_lang::AccountDeserialize for $struct_name { + fn try_deserialize(buf: &mut &[u8]) -> Result { + use $crate::anchor_traits::Discriminator; + if buf.len() < $struct_name::discriminator().len() { + return Err(ErrorCode::AccountDiscriminatorMismatch.into()); + } + let given_disc = &buf[..8]; + if $struct_name::discriminator() != given_disc { + return Err(ErrorCode::AccountDiscriminatorMismatch.into()); + } + Self::try_deserialize_unchecked(buf) + } + + fn try_deserialize_unchecked(buf: &mut &[u8]) -> Result { + let data: &[u8] = &buf[8..]; + bytemuck::try_from_bytes(data) + .map(|r: &Self| *r) + .map_err(|_| ErrorCode::AccountDidNotDeserialize.into()) + } + } + }; +} diff --git a/programs/switchboard-on-demand/src/on_demand/accounts/mod.rs b/programs/switchboard-on-demand/src/on_demand/accounts/mod.rs new file mode 100644 index 0000000000..a638b34df4 --- /dev/null +++ b/programs/switchboard-on-demand/src/on_demand/accounts/mod.rs @@ -0,0 +1,18 @@ +/// Oracle account data and verification +pub mod oracle; +/// Oracle statistics and performance tracking +pub mod oracle_stats; +/// Pull feed data structures and utilities +pub mod pull_feed; +/// Queue account for managing oracle operations +pub mod queue; +/// Randomness account for verifiable random number generation +pub mod randomness; +/// Global state account +pub mod state; +pub use oracle::*; +pub use oracle_stats::*; +pub use pull_feed::*; +pub use queue::*; +pub use randomness::*; +pub use state::*; diff --git a/programs/switchboard-on-demand/src/on_demand/accounts/oracle.rs b/programs/switchboard-on-demand/src/on_demand/accounts/oracle.rs new file mode 100644 index 0000000000..ecf82430e9 --- /dev/null +++ b/programs/switchboard-on-demand/src/on_demand/accounts/oracle.rs @@ -0,0 +1,374 @@ +#[cfg(feature = "pinocchio")] +type Ref<'a, T> = pinocchio::account_info::Ref<'a, T>; + +#[cfg(not(feature = "pinocchio"))] +use std::cell::Ref; + +use solana_program::sysvar::clock::Clock; + +use crate::anchor_traits::*; +#[allow(unused_imports)] +use crate::impl_account_deserialize; +// Use our AccountInfo type alias that conditionally uses pinocchio or anchor/solana-program +use crate::AccountInfo; +use crate::{cfg_client, get_sb_program_id, OnDemandError, Quote}; +cfg_client! { + use crate::address_lookup_table; + use spl_associated_token_account::solana_program::address_lookup_table::AddressLookupTableAccount; + use spl_associated_token_account::solana_program::address_lookup_table::instruction::derive_lookup_table_address; + use crate::find_lut_signer; +} + +use crate::{solana_program, Pubkey}; + +/// Seed for deriving oracle feed statistics PDAs +pub const ORACLE_FEED_STATS_SEED: &[u8; 15] = b"OracleFeedStats"; + +/// Number of slots to keep oracle key rotation alive +pub const KEY_ROTATE_KEEPALIVE_SLOTS: u64 = 1500; + +/// Maximum number of seconds before oracle data is considered stale +pub const MAX_STALE_SECONDS: i64 = 300; + +/// Oracle verification status for TEE attestation +#[repr(u8)] +#[derive(Copy, Clone, Default, Debug, Eq, PartialEq)] +pub enum VerificationStatus { + /// No verification status + #[default] + None = 0, + /// Verification is pending + VerificationPending = 1 << 0, + /// Verification failed + VerificationFailure = 1 << 1, + /// Verification succeeded + VerificationSuccess = 1 << 2, + /// Verification was overridden by authority + VerificationOverride = 1 << 3, +} +impl From for u8 { + fn from(value: VerificationStatus) -> Self { + match value { + VerificationStatus::VerificationPending => 1 << 0, + VerificationStatus::VerificationFailure => 1 << 1, + VerificationStatus::VerificationSuccess => 1 << 2, + VerificationStatus::VerificationOverride => 1 << 3, + _ => 0, + } + } +} +impl From for VerificationStatus { + fn from(value: u8) -> Self { + match value { + 1 => VerificationStatus::VerificationPending, + 2 => VerificationStatus::VerificationFailure, + 4 => VerificationStatus::VerificationSuccess, + 8 => VerificationStatus::VerificationOverride, + _ => VerificationStatus::default(), + } + } +} + +/// Oracle account data containing TEE enclave information and configuration +#[repr(C)] +#[derive(bytemuck::Zeroable, bytemuck::Pod, Debug, Copy, Clone)] +pub struct OracleAccountData { + /// Represents the state of the quote verifiers enclave. + pub enclave: Quote, + + // Accounts Config + /// The authority of the EnclaveAccount which is permitted to make account changes. + pub authority: Pubkey, + /// Queue used for attestation to verify a MRENCLAVE measurement. + pub queue: Pubkey, + + // Metadata Config + /// The unix timestamp when the quote was created. + pub created_at: i64, + + /// The last time the quote heartbeated on-chain. + pub last_heartbeat: i64, + + /// SECP256K1 public key for oracle authority + pub secp_authority: [u8; 64], + + /// URI location of the verifier's gateway. + pub gateway_uri: [u8; 64], + /// Permission flags for oracle operations + pub permissions: u64, + /// Whether the quote is located on the AttestationQueues buffer. + pub is_on_queue: u8, + _padding1: [u8; 7], + /// Slot number for address lookup table + pub lut_slot: u64, + /// Last epoch when oracle received rewards + pub last_reward_epoch: u64, + + /// Public key of the oracle operator + pub operator: Pubkey, + _ebuf3: [u8; 16], + _ebuf2: [u8; 64], + _ebuf1: [u8; 1024], +} + +cfg_client! { + impl_account_deserialize!(OracleAccountData); +} + +impl Discriminator for OracleAccountData { + const DISCRIMINATOR: &'static [u8] = &[128, 30, 16, 241, 170, 73, 55, 54]; +} + +impl Owner for OracleAccountData { + fn owner() -> Pubkey { + if crate::utils::is_devnet() { + get_sb_program_id("devnet") + } else { + get_sb_program_id("mainnet") + } + } +} + +impl OracleAccountData { + /// Returns the total size of an oracle account in bytes + pub fn size() -> usize { + 8 + std::mem::size_of::() + } + + /// Returns the deserialized Switchboard Quote account + /// + /// # Arguments + /// + /// * `quote_account_info` - A Solana AccountInfo referencing an existing Switchboard QuoteAccount + /// + /// # Examples + /// + /// ```ignore + /// use switchboard_on_demand::OracleAccountData; + /// + /// let quote_account = OracleAccountData::new(quote_account_info)?; + /// ``` + pub fn new<'info>( + quote_account_info: &'info AccountInfo, + ) -> Result, OnDemandError> { + let data = quote_account_info + .try_borrow_data() + .map_err(|_| OnDemandError::AccountBorrowError)?; + if data.len() < OracleAccountData::DISCRIMINATOR.len() { + return Err(OnDemandError::InvalidDiscriminator); + } + + let mut disc_bytes = [0u8; 8]; + disc_bytes.copy_from_slice(&data[..8]); + if disc_bytes != *OracleAccountData::DISCRIMINATOR { + return Err(OnDemandError::InvalidDiscriminator); + } + + // Check size before attempting to parse + let expected_size = std::mem::size_of::() + 8; + if data.len() < expected_size { + return Err(OnDemandError::InvalidData); + } + + // Validate the slice can be safely cast before using from_bytes + let slice_to_parse = &data[8..expected_size]; + if slice_to_parse.len() != std::mem::size_of::() { + return Err(OnDemandError::InvalidData); + } + + // Check alignment requirements for bytemuck + match bytemuck::try_from_bytes::(slice_to_parse) { + Ok(_) => { + // If try_from_bytes succeeds, we know from_bytes will also succeed + Ok(Ref::map(data, |data| { + bytemuck::from_bytes::( + &data[8..std::mem::size_of::() + 8], + ) + })) + } + Err(_) => Err(OnDemandError::AccountDeserializeError), + } + } + + /// Returns the deserialized Switchboard Quote account + /// + /// # Arguments + /// + /// * `data` - A Solana AccountInfo's data buffer + /// + /// # Examples + /// + /// ```ignore + /// use switchboard_on_demand::OracleAccountData; + /// + /// let quote_account = OracleAccountData::new(quote_account_info.try_borrow_data()?)?; + /// ``` + pub fn new_from_bytes(data: &[u8]) -> Result<&OracleAccountData, OnDemandError> { + if data.len() < OracleAccountData::DISCRIMINATOR.len() { + return Err(OnDemandError::InvalidDiscriminator); + } + + let mut disc_bytes = [0u8; 8]; + disc_bytes.copy_from_slice(&data[..8]); + if disc_bytes != *OracleAccountData::DISCRIMINATOR { + return Err(OnDemandError::InvalidDiscriminator); + } + + // Check size before attempting to parse + let expected_size = std::mem::size_of::() + 8; + if data.len() < expected_size { + return Err(OnDemandError::InvalidData); + } + + // Validate the slice can be safely cast before using from_bytes + let slice_to_parse = &data[8..expected_size]; + if slice_to_parse.len() != std::mem::size_of::() { + return Err(OnDemandError::InvalidData); + } + + // Use try_from_bytes for safety + match bytemuck::try_from_bytes::(slice_to_parse) { + Ok(oracle_data) => Ok(oracle_data), + Err(_) => Err(OnDemandError::AccountDeserializeError), + } + } + + /// Returns the public key of the oracle's enclave signer + pub fn signer(&self) -> &Pubkey { + &self.enclave.enclave_signer + } + + /// Returns true if the oracle's TEE enclave is verified and valid + pub fn is_verified(&self, clock: &Clock) -> bool { + match self.enclave.verification_status.into() { + VerificationStatus::VerificationOverride => true, + VerificationStatus::VerificationSuccess => { + self.enclave.valid_until > clock.unix_timestamp + } + _ => false, + } + } + + /// Verifies the oracle's enclave status against current clock + pub fn verify(&self, clock: &Clock) -> std::result::Result<(), OnDemandError> { + if !self.is_verified(clock) { + return Err(OnDemandError::InvalidQuote); + } + + Ok(()) + } + + /// Returns the oracle's gateway URI if available + pub fn gateway_uri(&self) -> Option { + let uri = self.gateway_uri; + let uri = String::from_utf8_lossy(&uri); + let uri = uri + .split_at(uri.find('\0').unwrap_or(uri.len())) + .0 + .to_string(); + if uri.is_empty() { + return None; + } + Some(uri) + } + + /// Returns the ED25519 signer public key if set + pub fn ed25519_signer(&self) -> Option { + let key = self.enclave.enclave_signer; + if key == Pubkey::default() { + return None; + } + Some(key) + } + + /// Returns the SECP256K1 authority key if set + pub fn secp_authority(&self) -> Option<[u8; 64]> { + let key = self.secp_authority; + if key == [0u8; 64] { + return None; + } + Some(key) + } + + /// Returns the SECP256K1 signer key if set + pub fn secp256k1_signer(&self) -> Option<[u8; 64]> { + let key = self.enclave.secp256k1_signer; + if key == [0u8; 64] { + return None; + } + Some(key) + } + + /// Returns the SECP256K1 signer as a libsecp256k1::PublicKey + pub fn libsecp256k1_signer(&self) -> Option { + let bytes = self.secp256k1_signer()?; + let tag_full_pubkey: Vec = vec![4u8]; + let bytes = [tag_full_pubkey, bytes.into()].concat().try_into().ok()?; + libsecp256k1::PublicKey::parse(&bytes).ok() + } + + /// Derives the PDA for oracle statistics account + pub fn stats_key(key: &Pubkey) -> Pubkey { + let pid = OracleAccountData::owner(); + let oracle_stats_seed = b"OracleStats"; + let (key, _) = + Pubkey::find_program_address(&[oracle_stats_seed.as_slice(), &key.to_bytes()], &pid); + key + } + + /// Derives the PDA for oracle feed statistics account + pub fn feed_stats_key(feed: &Pubkey, oracle: &Pubkey) -> (Pubkey, u8) { + let pid = OracleAccountData::owner(); + Pubkey::find_program_address( + &Self::feed_stats_seed(&feed.to_bytes(), &oracle.to_bytes(), &[]), + &pid, + ) + } + + /// Returns the seed components for deriving oracle feed stats PDA + pub fn feed_stats_seed<'a>(feed: &'a [u8], oracle: &'a [u8], bump: &'a [u8]) -> [&'a [u8]; 4] { + [ORACLE_FEED_STATS_SEED.as_slice(), feed, oracle, bump] + } + + cfg_client! { + + pub async fn fetch_async( + client: &crate::RpcClient, + pubkey: Pubkey, + ) -> std::result::Result { + let pubkey = pubkey.to_bytes().into(); + crate::client::fetch_zerocopy_account(client, pubkey).await + } + + pub async fn fetch_many( + client: &crate::RpcClient, + oracles: &[Pubkey], + ) -> std::result::Result, crate::OnDemandError> { + let converted_oracles: Vec = oracles.iter().map(|pk| pk.to_bytes().into()).collect(); + Ok(client + .get_multiple_accounts(&converted_oracles) + .await + .map_err(|_e| crate::OnDemandError::NetworkError)? + .into_iter() + .flatten() + .map(|x| x.data.clone()) + .collect::>() + .iter() + .map(|x| OracleAccountData::new_from_bytes(x)) + .filter_map(|x| x.ok()) + .copied() + .collect()) + } + + pub async fn fetch_lut( + &self, + oracle_pubkey: &Pubkey, + client: &crate::RpcClient, + ) -> std::result::Result { + let lut_slot = self.lut_slot; + let lut_signer: Pubkey = find_lut_signer(oracle_pubkey); + let lut = derive_lookup_table_address(&lut_signer.to_bytes().into(), lut_slot).0; + address_lookup_table::fetch(client, &lut.to_bytes().into()).await + } + } +} diff --git a/programs/switchboard-on-demand/src/on_demand/accounts/oracle_stats.rs b/programs/switchboard-on-demand/src/on_demand/accounts/oracle_stats.rs new file mode 100644 index 0000000000..c261365c3a --- /dev/null +++ b/programs/switchboard-on-demand/src/on_demand/accounts/oracle_stats.rs @@ -0,0 +1,95 @@ +#![allow(unused_attributes)] +use switchboard_common::cfg_client; + +use crate::anchor_traits::*; +use crate::{get_sb_program_id, Pubkey}; + +/// Oracle performance information for a specific epoch +#[derive(Default)] +#[repr(C)] +#[derive(bytemuck::Zeroable, bytemuck::Pod, Debug, Copy, Clone)] +pub struct OracleEpochInfo { + /// Unique identifier for this epoch + pub id: u64, + /// Reserved field for future use + pub reserved1: u64, + /// Slot number when this epoch ended + pub slot_end: u64, + /// Penalty score for oracle misbehavior + pub slash_score: u64, + /// Reward score based on oracle performance + pub reward_score: u64, + /// Stake-weighted performance score + pub stake_score: u64, +} + +/// Information about mega-slot performance tracking +#[derive(Default)] +#[repr(C)] +#[derive(bytemuck::Zeroable, bytemuck::Pod, Debug, Copy, Clone)] +pub struct MegaSlotInfo { + /// Reserved field for future use + pub reserved1: u64, + /// Slot number when this mega-slot ended + pub slot_end: u64, + /// Performance target for this period + pub perf_goal: i64, + /// Current count of oracle signatures + pub current_signature_count: i64, +} + +/// Oracle statistics account data for performance tracking +#[repr(C)] +#[derive(bytemuck::Zeroable, bytemuck::Pod, Debug, Copy, Clone)] +pub struct OracleStatsAccountData { + /// Owner of the oracle stats account + pub owner: Pubkey, + /// Oracle public key these stats belong to + pub oracle: Pubkey, + /// The last epoch that has completed. cleared after registered with the + /// staking program. + pub finalized_epoch: OracleEpochInfo, + /// The current epoch info being used by the oracle. for stake. Will moved + /// to finalized_epoch as soon as the epoch is over. + pub current_epoch: OracleEpochInfo, + /// Performance information for mega-slot tracking + pub mega_slot_info: MegaSlotInfo, + /// Slot of the last stake transfer + pub last_transfer_slot: u64, + /// PDA bump seed for this account + pub bump: u8, + /// Padding bytes for alignment + pub padding1: [u8; 7], + /// Reserved. + pub _ebuf: [u8; 1024], +} +impl Owner for OracleStatsAccountData { + fn owner() -> Pubkey { + if crate::utils::is_devnet() { + get_sb_program_id("devnet") + } else { + get_sb_program_id("mainnet") + } + } +} +impl Discriminator for OracleStatsAccountData { + const DISCRIMINATOR: &'static [u8] = &[180, 157, 178, 234, 240, 27, 152, 179]; +} +cfg_client! { + use crate::impl_account_deserialize; + + impl_account_deserialize!(OracleStatsAccountData); +} +impl OracleStatsAccountData { + cfg_client! { + + pub async fn fetch_async( + client: &crate::RpcClient, + pubkey: Pubkey, + ) -> std::result::Result { + let pubkey = pubkey.to_bytes().into(); + crate::client::fetch_zerocopy_account(client, pubkey).await + } + + } +} diff --git a/programs/switchboard-on-demand/src/on_demand/accounts/pull_feed.rs b/programs/switchboard-on-demand/src/on_demand/accounts/pull_feed.rs new file mode 100644 index 0000000000..2b8545ac2f --- /dev/null +++ b/programs/switchboard-on-demand/src/on_demand/accounts/pull_feed.rs @@ -0,0 +1,496 @@ +use std::cell::Ref; + +// Compatibility shim for anchor-lang borsh macros +#[cfg(feature = "anchor")] +mod borsh { + pub use ::borsh::*; + pub mod maybestd { + pub mod io { + pub use std::io::*; + } + } +} +#[cfg(feature = "anchor")] +use anchor_lang::{AnchorDeserialize, AnchorSerialize, Discriminator, Owner, ZeroCopy}; +use bytemuck; +use rust_decimal::Decimal; +use sha2::{Digest, Sha256}; + +#[cfg(not(feature = "anchor"))] +use crate::anchor_traits::{Discriminator, Owner, ZeroCopy}; +use crate::{Pubkey, *}; + +/// Default decimal precision for Switchboard oracle values +pub const PRECISION: u32 = 18; + +/// Returns the Switchboard On-Demand program ID +pub fn sb_pid() -> Pubkey { + let pid = if crate::utils::is_devnet() { + get_sb_program_id("devnet") + } else { + get_sb_program_id("mainnet") + }; + pid.to_bytes().into() +} + +/// Current oracle aggregation result with statistics +#[repr(C)] +#[derive(Clone, Copy, Debug, bytemuck::Pod, bytemuck::Zeroable)] +#[cfg_attr(feature = "anchor", derive(AnchorSerialize, AnchorDeserialize))] +pub struct CurrentResult { + /// The median value of the submissions needed for quorom size + pub value: i128, + /// The standard deviation of the submissions needed for quorom size + pub std_dev: i128, + /// The mean of the submissions needed for quorom size + pub mean: i128, + /// The range of the submissions needed for quorom size + pub range: i128, + /// The minimum value of the submissions needed for quorom size + pub min_value: i128, + /// The maximum value of the submissions needed for quorom size + pub max_value: i128, + /// The number of samples used to calculate this result + pub num_samples: u8, + /// The index of the submission that was used to calculate this result + pub submission_idx: u8, + /// Padding bytes for alignment + pub padding1: [u8; 6], + /// The slot at which this value was signed. + pub slot: u64, + /// The slot at which the first considered submission was made + pub min_slot: u64, + /// The slot at which the last considered submission was made + pub max_slot: u64, +} +impl CurrentResult { + /// Force override result values (debug builds only) + pub fn debug_only_force_override(&mut self, value: i128, slot: u64) { + self.value = value; + self.slot = slot; + self.std_dev = 0; + self.mean = value; + self.range = 0; + self.min_value = value; + self.max_value = value; + self.num_samples = u8::MAX; + self.submission_idx = 0; + self.min_slot = slot; + self.max_slot = slot; + } + + /// The median value of the submissions needed for quorom size + pub fn value(&self) -> Option { + if self.slot == 0 { + return None; + } + Some(Decimal::from_i128_with_scale(self.value, PRECISION)) + } + + /// The standard deviation of the submissions needed for quorom size + pub fn std_dev(&self) -> Option { + if self.slot == 0 { + return None; + } + Some(Decimal::from_i128_with_scale(self.std_dev, PRECISION)) + } + + /// The mean of the submissions needed for quorom size + pub fn mean(&self) -> Option { + if self.slot == 0 { + return None; + } + Some(Decimal::from_i128_with_scale(self.mean, PRECISION)) + } + + /// The range of the submissions needed for quorom size + pub fn range(&self) -> Option { + if self.slot == 0 { + return None; + } + Some(Decimal::from_i128_with_scale(self.range, PRECISION)) + } + + /// The minimum value of the submissions needed for quorom size + pub fn min_value(&self) -> Option { + if self.slot == 0 { + return None; + } + Some(Decimal::from_i128_with_scale(self.min_value, PRECISION)) + } + + /// The maximum value of the submissions needed for quorom size + pub fn max_value(&self) -> Option { + if self.slot == 0 { + return None; + } + Some(Decimal::from_i128_with_scale(self.max_value, PRECISION)) + } + + /// Returns the slot when this result was recorded + pub fn result_slot(&self) -> Option { + if self.slot == 0 { + return None; + } + Some(self.slot) + } + + /// Returns the minimum slot of submissions used in this result + pub fn min_slot(&self) -> Option { + if self.slot == 0 { + return None; + } + Some(self.min_slot) + } + + /// Returns the maximum slot of submissions used in this result + pub fn max_slot(&self) -> Option { + if self.slot == 0 { + return None; + } + Some(self.max_slot) + } +} + +/// Individual oracle submission data +#[repr(C)] +#[derive(Clone, Copy, Debug, bytemuck::Pod, bytemuck::Zeroable)] +#[cfg_attr(feature = "anchor", derive(AnchorSerialize, AnchorDeserialize))] +pub struct OracleSubmission { + /// The public key of the oracle that submitted this value. + pub oracle: Pubkey, + /// The slot at which this value was signed. + pub slot: u64, + /// The slot at which this value was landed on chain. + pub landed_at: u64, + /// The value that was submitted. + pub value: i128, +} + +/// Compact historical oracle result for storage efficiency +#[repr(C)] +#[derive(Clone, Copy, Debug, bytemuck::Pod, bytemuck::Zeroable)] +#[cfg_attr(feature = "anchor", derive(AnchorSerialize, AnchorDeserialize))] +pub struct CompactResult { + /// The standard deviation of the submissions needed for quorom size + pub std_dev: f32, + /// The mean of the submissions needed for quorom size + pub mean: f32, + /// The slot at which this value was signed. + pub slot: u64, +} + +/// A representation of the data in a pull feed account. +#[repr(C)] +#[derive(Copy, Clone, Debug, bytemuck::Pod, bytemuck::Zeroable)] +#[cfg_attr(feature = "anchor", derive(AnchorSerialize, AnchorDeserialize))] +pub struct PullFeedAccountData { + /// The oracle submissions for this feed. + pub submissions: [OracleSubmission; 32], + /// The public key of the authority that can update the feed hash that + /// this account will use for registering updates. + pub authority: Pubkey, + /// The public key of the queue which oracles must be bound to in order to + /// submit data to this feed. + pub queue: Pubkey, + /// SHA-256 hash of the job schema oracles will execute to produce data + /// for this feed. + pub feed_hash: [u8; 32], + /// The slot at which this account was initialized. + pub initialized_at: i64, + /// Permission flags for feed operations + pub permissions: u64, + /// Maximum allowed variance between oracle submissions + pub max_variance: u64, + /// Minimum number of oracle responses required + pub min_responses: u32, + /// Human-readable name for this feed + pub name: [u8; 32], + padding1: [u8; 2], + /// Index for the next historical result entry + pub historical_result_idx: u8, + /// Minimum number of samples required for a valid result + pub min_sample_size: u8, + /// Unix timestamp of the last feed update + pub last_update_timestamp: i64, + /// Slot number for address lookup table + pub lut_slot: u64, + _reserved1: [u8; 32], + /// Current aggregated result from oracle submissions + pub result: CurrentResult, + /// Maximum age in slots before data is considered stale + pub max_staleness: u32, + padding2: [u8; 12], + /// Array of historical oracle results + pub historical_results: [CompactResult; 32], + _ebuf4: [u8; 8], + _ebuf3: [u8; 24], + /// Timestamps of oracle submissions + pub submission_timestamps: [i64; 32], +} + +impl OracleSubmission { + /// Returns true if this submission is empty (uninitialized) + pub fn is_empty(&self) -> bool { + self.slot == 0 + } + + /// Returns the submitted value as a Decimal with standard precision + pub fn value(&self) -> Decimal { + Decimal::from_i128_with_scale(self.value, PRECISION) + } +} + +impl PullFeedAccountData { + /// Returns true if the value in the current result is within + /// staleness threshold + pub fn is_result_vaild(&self, clock_slot: u64) -> bool { + self.result.slot >= clock_slot - self.max_staleness as u64 + } + + /// Returns the oracle submission that was used for the current result + pub fn result_submission(&self) -> &OracleSubmission { + &self.submissions[self.result.submission_idx as usize] + } + + /// Returns the timestamp of the submission used for current result + pub fn result_ts(&self) -> i64 { + let idx = self.result.submission_idx as usize; + self.submission_timestamps[idx] + } + + /// Returns the slot when the current result submission landed on-chain + pub fn result_land_slot(&self) -> u64 { + let submission = self.submissions[self.result.submission_idx as usize]; + submission.landed_at + } + + /// Parses pull feed account data from raw bytes + pub fn parse<'info>(data: Ref<'info, &mut [u8]>) -> Result, OnDemandError> { + if data.len() < Self::DISCRIMINATOR.len() { + return Err(OnDemandError::InvalidDiscriminator); + } + + let mut disc_bytes = [0u8; 8]; + disc_bytes.copy_from_slice(&data[..8]); + if disc_bytes != Self::DISCRIMINATOR { + return Err(OnDemandError::InvalidDiscriminator); + } + + // Check size before attempting to parse + let expected_size = std::mem::size_of::() + 8; + if data.len() < expected_size { + return Err(OnDemandError::InvalidData); + } + + // Validate the slice can be safely cast before using from_bytes + let slice_to_parse = &data[8..expected_size]; + if slice_to_parse.len() != std::mem::size_of::() { + return Err(OnDemandError::InvalidData); + } + + // Check alignment requirements for bytemuck + match bytemuck::try_from_bytes::(slice_to_parse) { + Ok(_) => { + // If try_from_bytes succeeds, we know from_bytes will also succeed + Ok(Ref::map(data, |data: &&mut [u8]| { + bytemuck::from_bytes(&data[8..std::mem::size_of::() + 8]) + })) + } + Err(_) => Err(OnDemandError::AccountDeserializeError), + } + } + + /// Generate a checksum for the given feed hash, result, slothash, max_variance and min_responses + /// This is signed by the oracle and used to verify that the data submitted by the oracles is valid. + pub fn generate_checksum(&self, result: i128, slothash: [u8; 32]) -> [u8; 32] { + Self::generate_checksum_inner( + self.queue, + self.feed_hash, + result, + slothash, + self.max_variance, + self.min_responses, + ) + } + + /// Generate a checksum for the given feed hash, result, slothash, max_variance and min_responses + /// This is signed by the oracle and used to verify that the data submitted by the oracles is valid. + pub fn generate_checksum_inner( + queue: Pubkey, + feed_hash: [u8; 32], + result: i128, + slothash: [u8; 32], + max_variance: u64, + min_responses: u32, + ) -> [u8; 32] { + let mut hasher = Sha256::new(); + hasher.update(queue.to_bytes()); + hasher.update(feed_hash); + hasher.update(result.to_le_bytes()); + hasher.update(slothash); + hasher.update(max_variance.to_le_bytes()); + hasher.update(min_responses.to_le_bytes()); + hasher.finalize().to_vec().try_into().unwrap() + } + + /// Generate a checksum for the given feed hash, result, slothash, max_variance and min_responses + /// This is signed by the oracle and used to verify that the data submitted by the oracles is valid. + pub fn generate_checksum_with_timestamp( + queue: Pubkey, + feed_hash: [u8; 32], + result: i128, + slothash: [u8; 32], + max_variance: u64, + min_responses: u32, + timestamp: u64, + ) -> [u8; 32] { + let mut hasher = Sha256::new(); + hasher.update(queue.to_bytes()); + hasher.update(feed_hash); + hasher.update(result.to_le_bytes()); + hasher.update(slothash); + hasher.update(max_variance.to_le_bytes()); + hasher.update(min_responses.to_le_bytes()); + hasher.update(timestamp.to_le_bytes()); + hasher.finalize().to_vec().try_into().unwrap() + } + + /// **method** + /// get_value + /// Returns the median value of the submissions in the last `max_staleness` slots. + /// If there are fewer than `min_samples` submissions, returns an error. + /// **arguments** + /// * `clock` - the clock to use for the current slot + /// * `max_staleness` - the maximum number of slots to consider + /// * `min_samples` - the minimum number of samples required to return a value + /// **returns** + /// * `Ok(Decimal)` - the median value of the submissions in the last `max_staleness` slots + pub fn get_value( + &self, + clock_slot: u64, + max_staleness: u64, + min_samples: u32, + only_positive: bool, + ) -> Result { + let submissions = self + .submissions + .iter() + .take_while(|s| !s.is_empty()) + .filter(|s| s.slot >= clock_slot - max_staleness) + .collect::>(); + if submissions.len() < min_samples as usize { + return Err(OnDemandError::NotEnoughSamples); + } + let median = + lower_bound_median(&mut submissions.iter().map(|s| s.value).collect::>()) + .ok_or(OnDemandError::NotEnoughSamples)?; + if only_positive && median <= 0 { + return Err(OnDemandError::IllegalFeedValue); + } + + Ok(Decimal::from_i128_with_scale(median, PRECISION)) + } + + /// List of samples that are valid for the current slot + pub fn valid_samples(&self, clock_slot: u64) -> Vec<&OracleSubmission> { + self.submissions + .iter() + .take_while(|s| !s.is_empty()) + .filter(|s| s.slot >= clock_slot - self.max_staleness as u64) + .collect() + } + + /// Gets all the samples used in the current result + pub fn current_result_samples(&self) -> Vec<(usize, &OracleSubmission)> { + let last_update_slot = self.last_update_slot(); + let slot_threshold = last_update_slot - self.max_staleness as u64; + self.submissions + .iter() + .enumerate() + .take_while(|(_, s)| !s.is_empty()) + .filter(|(_, s)| s.slot >= slot_threshold) + .collect() + } + + /// Gets the minimum timestamp of the submissions used in the current result + pub fn current_result_ts_range(&self) -> (i64, i64) { + let samples = self.current_result_samples(); + let timestamps = samples + .iter() + .map(|(idx, _)| self.submission_timestamps[*idx]) + .collect::>(); + let min_ts = *timestamps.iter().min().unwrap_or(&0); + let max_ts = *timestamps.iter().max().unwrap_or(&0); + (min_ts, max_ts) + } + + /// Returns the slot of the most recent submission + pub fn last_update_slot(&self) -> u64 { + self.submissions + .iter() + .map(|s| s.landed_at) + .max() + .unwrap_or(0) + } + + /// The median value of the submissions needed for quorom size + /// Fails if the result is not valid or stale. + pub fn value(&self, clock_slot: u64) -> Result { + if self.result.result_slot().unwrap_or(0) < clock_slot - self.max_staleness as u64 { + return Err(OnDemandError::StaleResult); + } + self.result.value().ok_or(OnDemandError::StaleResult) + } + + /// The standard deviation of the submissions needed for quorom size + pub fn std_dev(&self) -> Option { + self.result.std_dev() + } + + /// The mean of the submissions needed for quorom size + pub fn mean(&self) -> Option { + self.result.mean() + } + + /// The range of the submissions needed for quorom size + pub fn range(&self) -> Option { + self.result.range() + } + + /// The minimum value of the submissions needed for quorom size + pub fn min_value(&self) -> Option { + self.result.min_value() + } + + /// The maximum value of the submissions needed for quorom size + pub fn max_value(&self) -> Option { + self.result.max_value() + } +} + +impl ZeroCopy for PullFeedAccountData {} +impl Owner for PullFeedAccountData { + fn owner() -> Pubkey { + sb_pid().to_bytes().into() + } +} +const DISCRIMINATOR: [u8; 8] = [196, 27, 108, 196, 10, 215, 219, 40]; +impl Discriminator for PullFeedAccountData { + const DISCRIMINATOR: &[u8] = &DISCRIMINATOR; +} + +/// Type alias for PullFeedAccountData for backward compatibility +pub type SbFeed = PullFeedAccountData; + +// takes the rounded down median of a list of numbers +/// Calculates the lower bound median of oracle submission values +pub fn lower_bound_median(numbers: &mut [i128]) -> Option { + numbers.sort(); // Sort the numbers in ascending order. + + let len = numbers.len(); + if len == 0 { + return None; // Return None for an empty list. + } + Some(numbers[len / 2]) +} diff --git a/programs/switchboard-on-demand/src/on_demand/accounts/queue.rs b/programs/switchboard-on-demand/src/on_demand/accounts/queue.rs new file mode 100644 index 0000000000..c9c3ebf6bc --- /dev/null +++ b/programs/switchboard-on-demand/src/on_demand/accounts/queue.rs @@ -0,0 +1,338 @@ +#[cfg(feature = "pinocchio")] +type Ref<'a, T> = pinocchio::account_info::Ref<'a, T>; + +#[cfg(not(feature = "pinocchio"))] +use std::cell::Ref; + +use bytemuck::{Pod, Zeroable}; + +// Always import for macros to work +#[allow(unused_imports)] +use crate::impl_account_deserialize; +// Use our AccountInfo type alias that conditionally uses pinocchio or anchor/solana-program +use crate::AccountInfo; +#[allow(unused_imports)] +use crate::OracleAccountData; +use crate::{cfg_client, get_sb_program_id, OnDemandError}; +cfg_client! { + use spl_associated_token_account::solana_program::address_lookup_table::AddressLookupTableAccount; +} +use crate::Pubkey; + +/// Queue account data containing oracle management and configuration +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct QueueAccountData { + /// The address of the authority which is permitted to add/remove allowed enclave measurements. + pub authority: Pubkey, + /// Allowed enclave measurements. + pub mr_enclaves: [[u8; 32]; 32], + /// The addresses of the quote oracles who have a valid + /// verification status and have heartbeated on-chain recently. + pub oracle_keys: [Pubkey; 78], + reserved1: [u8; 40], + /// SECP256K1 signing keys for oracles + pub secp_oracle_signing_keys: [[u8; 20]; 30], + /// ED25519 signing keys for oracles + pub ed25519_oracle_signing_keys: [Pubkey; 30], + /// The maximum allowable time until a EnclaveAccount needs to be re-verified on-chain. + pub max_quote_verification_age: i64, + /// The unix timestamp when the last quote oracle heartbeated on-chain. + pub last_heartbeat: i64, + /// Timeout period for oracle nodes in seconds + pub node_timeout: i64, + /// The minimum number of lamports a quote oracle needs to lock-up in order to heartbeat and verify other quotes. + pub oracle_min_stake: u64, + /// Time after which authority override is allowed + pub allow_authority_override_after: i64, + + /// The number of allowed enclave measurements. + pub mr_enclaves_len: u32, + /// The length of valid quote oracles for the given attestation queue. + pub oracle_keys_len: u32, + /// The reward paid to quote oracles for attesting on-chain. + pub reward: u32, + /// Incrementer used to track the current quote oracle permitted to run any available functions. + pub curr_idx: u32, + /// Incrementer used to garbage collect and remove stale quote oracles. + pub gc_idx: u32, + + /// Whether authority permission is required for heartbeat + pub require_authority_heartbeat_permission: u8, + /// Whether authority permission is required for verification + pub require_authority_verify_permission: u8, + /// Whether usage permissions are required + pub require_usage_permissions: u8, + /// PDA bump seed for the queue signer + pub signer_bump: u8, + + /// Token mint for queue operations + pub mint: Pubkey, + /// Address lookup table slot + pub lut_slot: u64, + /// Whether subsidies are allowed for oracle operations + pub allow_subsidies: u8, + + _ebuf6: [u8; 15], + /// Network coordination node public key + pub ncn: Pubkey, + _resrved: u64, // only necessary for multiple vaults at once, otherwise we can use the ncn + // tickets + /// Array of vault information for rewards + pub vaults: [VaultInfo; 4], + /// Last epoch when queue rewards were distributed + pub last_reward_epoch: u64, + _ebuf4: [u8; 32], + _ebuf2: [u8; 256], + _ebuf1: [u8; 504], // was 512 change to 504 to make room for new u64 +} +unsafe impl Pod for QueueAccountData {} +unsafe impl Zeroable for QueueAccountData {} + +/// Information about reward vault for oracle incentives +#[repr(C)] +#[derive(PartialEq, Debug, Copy, Clone)] +pub struct VaultInfo { + /// Public key of the vault account + pub vault_key: Pubkey, + /// Last epoch when rewards were distributed + pub last_reward_epoch: u64, +} +unsafe impl Pod for VaultInfo {} +unsafe impl Zeroable for VaultInfo {} + +cfg_client! { + impl_account_deserialize!(QueueAccountData); +} + +/// Anchor discriminator for QueueAccountData +pub const QUEUE_ACCOUNT_DISCRIMINATOR: [u8; 8] = [217, 194, 55, 127, 184, 83, 138, 1]; + +// Always implement internal traits for client functionality +impl crate::anchor_traits::Discriminator for QueueAccountData { + const DISCRIMINATOR: &'static [u8] = &QUEUE_ACCOUNT_DISCRIMINATOR; +} + +impl crate::anchor_traits::Owner for QueueAccountData { + fn owner() -> Pubkey { + let pid = if crate::utils::is_devnet() { + get_sb_program_id("devnet") + } else { + get_sb_program_id("mainnet") + }; + pid.to_bytes().into() + } +} + +impl crate::anchor_traits::ZeroCopy for QueueAccountData {} + +// Implement anchor traits when anchor feature is enabled +#[cfg(feature = "anchor")] +impl anchor_lang::Discriminator for QueueAccountData { + const DISCRIMINATOR: &'static [u8] = &QUEUE_ACCOUNT_DISCRIMINATOR; +} + +#[cfg(feature = "anchor")] +impl anchor_lang::Owner for QueueAccountData { + fn owner() -> Pubkey { + let pid = if crate::utils::is_devnet() { + get_sb_program_id("devnet") + } else { + get_sb_program_id("mainnet") + }; + pid.to_bytes().into() + } +} + +#[cfg(feature = "anchor")] +impl anchor_lang::ZeroCopy for QueueAccountData {} + +#[cfg(feature = "anchor")] +impl anchor_lang::IdlBuild for QueueAccountData {} + +impl QueueAccountData { + /// Returns the total size of a queue account in bytes + pub fn size() -> usize { + 8 + std::mem::size_of::() + } + + /// Returns the deserialized Switchboard AttestationQueue account + /// + /// # Arguments + /// + /// * `attestation_queue_account_info` - A Solana AccountInfo referencing an existing Switchboard AttestationQueue + /// + /// # Examples + /// + /// ```ignore + /// use switchboard_solana::QueueAccountData; + /// + /// let attestation_queue = QueueAccountData::new(attestation_queue_account_info)?; + /// ``` + pub fn new<'info>( + attestation_queue_account_info: &'info AccountInfo, + ) -> Result, OnDemandError> { + let data = attestation_queue_account_info + .try_borrow_data() + .map_err(|_| OnDemandError::AccountBorrowError)?; + if data.len() < QUEUE_ACCOUNT_DISCRIMINATOR.len() { + return Err(OnDemandError::InvalidDiscriminator); + } + + let mut disc_bytes = [0u8; 8]; + disc_bytes.copy_from_slice(&data[..8]); + if disc_bytes != QUEUE_ACCOUNT_DISCRIMINATOR { + return Err(OnDemandError::InvalidDiscriminator); + } + + // Check size before attempting to parse + let expected_size = std::mem::size_of::() + 8; + if data.len() < expected_size { + return Err(OnDemandError::InvalidData); + } + + // Validate the slice can be safely cast before using from_bytes + let slice_to_parse = &data[8..expected_size]; + if slice_to_parse.len() != std::mem::size_of::() { + return Err(OnDemandError::InvalidData); + } + + // Check alignment requirements for bytemuck + match bytemuck::try_from_bytes::(slice_to_parse) { + Ok(_) => { + // If try_from_bytes succeeds, we know from_bytes will also succeed + Ok(Ref::map(data, |data| { + bytemuck::from_bytes::( + &data[8..std::mem::size_of::() + 8], + ) + })) + } + Err(_) => Err(OnDemandError::AccountDeserializeError), + } + } + + /// Returns the deserialized Switchboard AttestationQueue account + /// + /// # Arguments + /// + /// * `data` - A Solana AccountInfo's data buffer + /// + /// # Examples + /// + /// ```ignore + /// use switchboard_solana::QueueAccountData; + /// + /// let attestation_queue = QueueAccountData::new(attestation_queue_account_info.try_borrow_data()?)?; + /// ``` + pub fn new_from_bytes(data: &[u8]) -> Result<&QueueAccountData, OnDemandError> { + if data.len() < QUEUE_ACCOUNT_DISCRIMINATOR.len() { + return Err(OnDemandError::InvalidDiscriminator); + } + + let mut disc_bytes = [0u8; 8]; + disc_bytes.copy_from_slice(&data[..8]); + if disc_bytes != QUEUE_ACCOUNT_DISCRIMINATOR { + return Err(OnDemandError::InvalidDiscriminator); + } + + // Check size before attempting to parse + let expected_size = std::mem::size_of::() + 8; + if data.len() < expected_size { + return Err(OnDemandError::InvalidData); + } + + // Validate the slice can be safely cast before using from_bytes + let slice_to_parse = &data[8..expected_size]; + if slice_to_parse.len() != std::mem::size_of::() { + return Err(OnDemandError::InvalidData); + } + + // Use try_from_bytes for safety + match bytemuck::try_from_bytes::(slice_to_parse) { + Ok(queue_data) => Ok(queue_data), + Err(_) => Err(OnDemandError::AccountDeserializeError), + } + } + + /// Returns true if the given MR_ENCLAVE measurement is permitted + pub fn has_mr_enclave(&self, mr_enclave: &[u8]) -> bool { + self.mr_enclaves[..self.mr_enclaves_len as usize] + .iter() + .any(|x| x.to_vec() == mr_enclave.to_vec()) + } + + /// Returns a vector of all permitted enclave measurements + pub fn permitted_enclaves(&self) -> Vec<[u8; 32]> { + self.mr_enclaves[..self.mr_enclaves_len as usize].to_vec() + } + + /// Returns the garbage collection node public key if set + pub fn garbage_collection_node(&self) -> Option { + let gc_node = self.oracle_keys[self.gc_idx as usize]; + if gc_node != Pubkey::default() { + Some(gc_node) + } else { + None + } + } + + /// Returns the index of an oracle in the queue's oracle list + pub fn idx_of_oracle(&self, oracle: &Pubkey) -> Option { + self.oracle_keys[..self.oracle_keys_len as usize] + .iter() + .position(|x| x == oracle) + } + + /// Returns a vector of all active oracle public keys in the queue + pub fn oracle_keys(&self) -> Vec { + self.oracle_keys[..self.oracle_keys_len as usize].to_vec() + } + + cfg_client! { + + /// Fetches a queue account asynchronously from the Solana network + pub async fn fetch_async( + client: &crate::RpcClient, + pubkey: Pubkey, + ) -> std::result::Result { + let pubkey = pubkey.to_bytes().into(); + crate::client::fetch_zerocopy_account(client, pubkey).await + } + + /// Fetches all oracle accounts associated with this queue + pub async fn fetch_oracles( + &self, + client: &crate::RpcClient, + ) -> std::result::Result, crate::OnDemandError> { + let oracles = &self.oracle_keys[..self.oracle_keys_len as usize]; + let converted_oracles: Vec = oracles.iter().map(|pk| pk.to_bytes().into()).collect(); + let datas: Vec<_> = client + .get_multiple_accounts(&converted_oracles) + .await + .map_err(|_e| crate::OnDemandError::NetworkError)? + .into_iter() + .flatten() + .map(|x| x.data.clone()) + .collect::>() + .iter() + .map(|x| OracleAccountData::new_from_bytes(x)) + .filter_map(|x| x.ok()) + .copied() + .collect(); + Ok(oracles.iter().cloned().zip(datas).collect()) + } + + /// Fetches the address lookup table associated with this queue + pub async fn fetch_lut( + &self, + pubkey: &Pubkey, + client: &crate::RpcClient, + ) -> std::result::Result { + use spl_associated_token_account::solana_program::address_lookup_table::instruction::derive_lookup_table_address; + let lut_slot = self.lut_slot; + let lut_signer: Pubkey = crate::find_lut_signer(pubkey); + let lut = derive_lookup_table_address(&lut_signer.to_bytes().into(), lut_slot).0; + crate::address_lookup_table::fetch(client, &lut.to_bytes().into()).await + } + } +} diff --git a/programs/switchboard-on-demand/src/on_demand/accounts/randomness.rs b/programs/switchboard-on-demand/src/on_demand/accounts/randomness.rs new file mode 100644 index 0000000000..8818d0fbc3 --- /dev/null +++ b/programs/switchboard-on-demand/src/on_demand/accounts/randomness.rs @@ -0,0 +1,112 @@ +use std::cell::Ref; + +use crate::{Pubkey, *}; + +/// Switchboard randomness account for verifiable random number generation +#[derive(Clone, Copy, Debug, bytemuck::Pod, bytemuck::Zeroable)] +#[repr(C)] +pub struct RandomnessAccountData { + /// Authority that can update this randomness account + pub authority: Pubkey, + /// Queue this randomness account belongs to + pub queue: Pubkey, + + /// Slot hash used as randomness seed + pub seed_slothash: [u8; 32], + /// Slot number used as randomness seed + pub seed_slot: u64, + /// Oracle that provided the randomness + pub oracle: Pubkey, + + /// Slot at which randomness was revealed + pub reveal_slot: u64, + /// The random value (32 bytes) + pub value: [u8; 32], + + _ebuf2: [u8; 96], + _ebuf1: [u8; 128], +} +impl Discriminator for RandomnessAccountData { + const DISCRIMINATOR: &'static [u8] = &[10, 66, 229, 135, 220, 239, 217, 114]; +} +impl Owner for RandomnessAccountData { + fn owner() -> Pubkey { + if crate::utils::is_devnet() { + get_sb_program_id("devnet") + } else { + get_sb_program_id("mainnet") + } + } +} + +cfg_client! { + impl_account_deserialize!(RandomnessAccountData); +} +impl RandomnessAccountData { + /// Returns the total size of a randomness account in bytes + pub const fn size() -> usize { + std::mem::size_of::() + 8 + } + + /// Gets the random value if it's current (matches reveal slot) + pub fn get_value(&self, clock_slot: u64) -> std::result::Result<[u8; 32], OnDemandError> { + if clock_slot != self.reveal_slot { + return Err(OnDemandError::SwitchboardRandomnessTooOld); + } + Ok(self.value) + } + + /// Returns true if randomness can be revealed at current slot + pub fn is_revealable(&self, clock_slot: u64) -> bool { + self.seed_slot < clock_slot + } + + /// Parses randomness account data from raw bytes + pub fn parse<'info>( + data: Ref<'info, &mut [u8]>, + ) -> std::result::Result, OnDemandError> { + if data.len() < Self::DISCRIMINATOR.len() { + return Err(OnDemandError::InvalidDiscriminator); + } + + let mut disc_bytes = [0u8; 8]; + disc_bytes.copy_from_slice(&data[..8]); + if disc_bytes != *Self::DISCRIMINATOR { + return Err(OnDemandError::InvalidDiscriminator); + } + + // Check size before attempting to parse + let expected_size = std::mem::size_of::() + 8; + if data.len() < expected_size { + return Err(OnDemandError::InvalidData); + } + + // Validate the slice can be safely cast before using from_bytes + let slice_to_parse = &data[8..expected_size]; + if slice_to_parse.len() != std::mem::size_of::() { + return Err(OnDemandError::InvalidData); + } + + // Check alignment requirements for bytemuck + match bytemuck::try_from_bytes::(slice_to_parse) { + Ok(_) => { + // If try_from_bytes succeeds, we know from_bytes will also succeed + Ok(Ref::map(data, |data: &&mut [u8]| { + bytemuck::from_bytes(&data[8..std::mem::size_of::() + 8]) + })) + } + Err(_) => Err(OnDemandError::AccountDeserializeError), + } + } + + cfg_client! { + /// Fetches a randomness account asynchronously from the Solana network + pub async fn fetch_async( + client: &crate::RpcClient, + pubkey: Pubkey, + ) -> std::result::Result { + let pubkey = pubkey.to_bytes().into(); + crate::client::fetch_zerocopy_account(client, pubkey).await + } + } +} diff --git a/programs/switchboard-on-demand/src/on_demand/accounts/state.rs b/programs/switchboard-on-demand/src/on_demand/accounts/state.rs new file mode 100644 index 0000000000..cfa75e0562 --- /dev/null +++ b/programs/switchboard-on-demand/src/on_demand/accounts/state.rs @@ -0,0 +1,131 @@ +use bytemuck::{Pod, Zeroable}; + +use crate::anchor_traits::*; +#[allow(unused_imports)] +use crate::impl_account_deserialize; +use crate::{cfg_client, get_sb_program_id, Pubkey}; + +const STATE_SEED: &[u8] = b"STATE"; + +/// State epoch information for tracking global epochs +#[derive(Debug, Copy, Clone)] +pub struct StateEpochInfo { + /// Unique identifier for this epoch + pub id: u64, + /// Reserved field for future use + pub reserved1: u64, + /// Slot number when this epoch ends + pub slot_end: u64, +} + +/// Global program state account containing configuration and epoch information +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct State { + /// PDA bump seed for the state account + pub bump: u8, + /// Flag to disable MR_ENCLAVE verification for testing purposes only + pub test_only_disable_mr_enclave_check: u8, + padding1: [u8; 6], + /// Authority pubkey that can modify program state + pub authority: Pubkey, + /// Guardian queue for program security operations + pub guardian_queue: Pubkey, + /// Reserved field for future expansion + pub reserved1: u64, + /// Length of each epoch in slots + pub epoch_length: u64, + /// Information about the current active epoch + pub current_epoch: StateEpochInfo, + /// Information about the next scheduled epoch + pub next_epoch: StateEpochInfo, + /// Information about the most recently finalized epoch + pub finalized_epoch: StateEpochInfo, + /// Stake pool account for staking operations + pub stake_pool: Pubkey, + /// Stake program used for staking operations + pub stake_program: Pubkey, + /// SWITCH token mint address + pub switch_mint: Pubkey, + /// Array of SGX advisory identifiers + pub sgx_advisories: [u16; 32], + /// Number of active SGX advisories in the array + pub advisories_len: u8, + _ebuf4: [u8; 15], + _ebuf3: [u8; 256], + _ebuf2: [u8; 512], + _ebuf1: [u8; 1024], +} +unsafe impl Pod for State {} +unsafe impl Zeroable for State {} + +cfg_client! { + impl_account_deserialize!(State); +} + +impl Discriminator for State { + const DISCRIMINATOR: &'static [u8] = &[216, 146, 107, 94, 104, 75, 182, 177]; +} + +impl Owner for State { + fn owner() -> Pubkey { + if crate::utils::is_devnet() { + get_sb_program_id("devnet") + } else { + get_sb_program_id("mainnet") + } + } +} + +impl State { + /// Returns the total size of the state account in bytes + pub fn size() -> usize { + 8 + std::mem::size_of::() + } + + /// Gets the program-derived address for the global state account + pub fn get_pda() -> Pubkey { + let pid = if crate::utils::is_devnet() { + get_sb_program_id("devnet") + } else { + get_sb_program_id("mainnet") + }; + let (pda_key, _) = Pubkey::find_program_address(&[STATE_SEED], &pid); + pda_key + } + + /// Gets the program-derived address for the state account with optional program ID + pub fn get_program_pda(program_id: Option) -> Pubkey { + let pid = if crate::utils::is_devnet() { + get_sb_program_id("devnet") + } else { + get_sb_program_id("mainnet") + }; + let (pda_key, _) = Pubkey::find_program_address(&[STATE_SEED], &program_id.unwrap_or(pid)); + pda_key + } + + /// Alias for get_pda() for compatibility + pub fn key() -> Pubkey { + Self::get_pda() + } + + /// Gets the program ID for the state account + pub fn pid() -> Pubkey { + if crate::utils::is_devnet() { + get_sb_program_id("devnet") + } else { + get_sb_program_id("mainnet") + } + } + + cfg_client! { + /// Fetches the global state account asynchronously from the Solana network + pub async fn fetch_async( + client: &crate::RpcClient, + ) -> std::result::Result { + let pubkey = State::get_pda().to_bytes().into(); + crate::client::fetch_zerocopy_account(client, pubkey).await + } + } +} diff --git a/programs/switchboard-on-demand/src/on_demand/error.rs b/programs/switchboard-on-demand/src/on_demand/error.rs new file mode 100644 index 0000000000..cbc1db3725 --- /dev/null +++ b/programs/switchboard-on-demand/src/on_demand/error.rs @@ -0,0 +1,178 @@ +#[cfg(not(feature = "anchor"))] +use std::fmt; + +#[cfg(feature = "anchor")] +use anchor_lang::prelude::*; +use serde::ser::StdError; + +/// Error types for Switchboard On-Demand Oracle operations +#[cfg_attr(feature = "anchor", error_code)] +#[cfg_attr(not(feature = "anchor"), derive(Clone, Debug))] +#[cfg_attr(not(feature = "anchor"), repr(u32))] +pub enum OnDemandError { + /// Generic error without specific context + Generic, + /// Failed to borrow account data from RefCell + AccountBorrowError, + /// Oracle account not found or invalid + AccountNotFound, + /// Anchor framework parsing error + AnchorParse, + /// Anchor parsing error with additional context + AnchorParseError, + /// Account size validation failed + CheckSizeError, + /// Failed to convert numeric value to decimal + DecimalConversionError, + /// Decryption operation failed + DecryptError, + /// Event listener background process failed + EventListenerRoutineFailure, + /// Ethereum Virtual Machine error + EvmError, + /// Function result instruction targets wrong blockchain + FunctionResultIxIncorrectTargetChain, + /// Oracle heartbeat process failed + HeartbeatRoutineFailure, + /// Integer arithmetic overflow occurred + IntegerOverflowError, + /// Invalid blockchain or network specified + InvalidChain, + /// Data format is invalid or corrupted + InvalidData, + /// Account discriminator doesn't match expected value + InvalidDiscriminator, + /// Solana instruction format is invalid + InvalidInstructionError, + /// Keypair file format is invalid or corrupted + InvalidKeypairFile, + /// Native SOL mint account is invalid + InvalidNativeMint, + /// Oracle quote data is invalid or corrupted + InvalidQuote, + /// Oracle quote validation failed with additional context + InvalidQuoteError, + /// Oracle signature verification failed + InvalidSignature, + /// Storage network communication error + StorageNetworkError, + /// Failed to parse storage data or response + StorageParseError, + /// Cryptographic key parsing failed + KeyParseError, + /// TEE enclave measurement doesn't match expected value + MrEnclaveMismatch, + /// Network or RPC communication error + NetworkError, + /// General parsing error + ParseError, + /// Program Derived Address derivation failed + PdaDerivationError, + /// Failed to parse oracle quote data + QuoteParseError, + /// Quote Verification Network transaction send failed + QvnTxSendFailure, + /// Intel SGX trusted execution environment error + SgxError, + /// Failed to write to SGX enclave + SgxWriteError, + /// Solana blockhash related error + SolanaBlockhashError, + /// Required Solana transaction signer is missing + SolanaMissingSigner, + /// Transaction payer signer is missing + SolanaPayerSignerMissing, + /// Transaction payer doesn't match expected account + SolanaPayerMismatch, + /// Too many instructions in Solana transaction + SolanaInstructionOverflow, + /// Solana transaction has no instructions + SolanaInstructionsEmpty, + /// Transaction compilation failed + TxCompileErr, + /// Transaction deserialization failed + TxDeserializationError, + /// Transaction execution failed on-chain + TxFailure, + /// Unexpected error condition + Unexpected, + /// Solana transaction signing failed + SolanaSignError, + /// Input/output operation failed + IoError, + /// Cryptographic key derivation failed + KeyDerivationFailed, + /// Secret key format is invalid + InvalidSecretKey, + /// Required environment variable is missing + EnvVariableMissing, + /// Account data deserialization failed + AccountDeserializeError, + /// Insufficient oracle samples for reliable data + NotEnoughSamples, + /// Oracle feed value is outside acceptable bounds + IllegalFeedValue, + /// Switchboard randomness value is too old to use + SwitchboardRandomnessTooOld, + /// Failed to fetch address lookup table + AddressLookupTableFetchError, + /// Failed to deserialize address lookup table + AddressLookupTableDeserializeError, + /// Data size is invalid for the operation + InvalidSize, + /// Oracle data is older than maximum allowed age + StaleResult, +} + +impl StdError for OnDemandError { + fn source(&self) -> Option<&(dyn StdError + 'static)> { + None + } +} +#[cfg(not(feature = "anchor"))] +impl fmt::Display for OnDemandError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + OnDemandError::AccountNotFound => { + write!(f, "Oracle account not found. Ensure the account exists and is properly initialized.") + } + OnDemandError::InvalidDiscriminator => { + write!( + f, + "Invalid account discriminator. This may not be a Switchboard oracle account." + ) + } + OnDemandError::InvalidQuote => { + write!(f, "Invalid oracle quote. The quote may be expired, tampered with, or from an unauthorized oracle.") + } + OnDemandError::NotEnoughSamples => { + write!(f, "Insufficient oracle samples for reliable data. Consider lowering min_samples or waiting for more oracles to respond.") + } + OnDemandError::StaleResult => { + write!(f, "Oracle data is stale. The data is older than the maximum allowed age. Try increasing max_stale_slots or wait for fresh data.") + } + OnDemandError::InvalidSignature => { + write!(f, "Invalid oracle signature. The oracle may not be authorized or the data may be corrupted.") + } + OnDemandError::NetworkError => { + write!(f, "Network error occurred while fetching oracle data. Check your RPC connection and try again.") + } + OnDemandError::AccountDeserializeError => { + write!(f, "Failed to deserialize oracle account data. The account format may be invalid or corrupted.") + } + OnDemandError::DecimalConversionError => { + write!(f, "Failed to convert oracle value to decimal. The numeric value may be out of range or invalid.") + } + OnDemandError::InvalidData => { + write!(f, "Invalid oracle data detected. The data format or content is malformed or corrupted.") + } + OnDemandError::IllegalFeedValue => { + write!(f, "Illegal feed value encountered. The oracle reported a value that is outside acceptable bounds.") + } + OnDemandError::SwitchboardRandomnessTooOld => { + write!(f, "Switchboard randomness is too old. Request fresh randomness for current operations.") + } + _ => write!(f, "Switchboard oracle error: {:#?}", self), + } + } +} diff --git a/programs/switchboard-on-demand/src/on_demand/instructions/guardian_quote_verify.rs b/programs/switchboard-on-demand/src/on_demand/instructions/guardian_quote_verify.rs new file mode 100644 index 0000000000..a9a6f56316 --- /dev/null +++ b/programs/switchboard-on-demand/src/on_demand/instructions/guardian_quote_verify.rs @@ -0,0 +1,149 @@ +use borsh::BorshSerialize; +use solana_program::instruction::{AccountMeta, Instruction}; +use solana_program::sysvar::slot_hashes; + +use crate::anchor_traits::*; +use crate::prelude::*; +use crate::{get_sb_program_id, solana_program, Pubkey}; + +/// Guardian quote verification instruction +pub struct GuardianQuoteVerify {} + +/// Parameters for guardian quote verification instruction +#[derive(Clone, Debug)] +pub struct GuardianQuoteVerifyParams { + /// Unix timestamp of the verification + pub timestamp: i64, + /// MR_ENCLAVE measurement from the trusted execution environment + pub mr_enclave: [u8; 32], + /// Index of the oracle in the queue + pub idx: u32, + /// ED25519 public key for signature verification + pub ed25519_key: Pubkey, + /// SECP256K1 public key (64 bytes) + pub secp256k1_key: [u8; 64], + /// Slot number for this verification + pub slot: u64, + /// ECDSA signature (64 bytes) + pub signature: [u8; 64], + /// Recovery ID for signature verification + pub recovery_id: u8, + /// List of security advisories + pub advisories: Vec, +} + +impl BorshSerialize for GuardianQuoteVerifyParams { + fn serialize(&self, writer: &mut W) -> std::io::Result<()> { + self.timestamp.serialize(writer)?; + self.mr_enclave.serialize(writer)?; + self.idx.serialize(writer)?; + writer.write_all(self.ed25519_key.as_ref())?; + self.secp256k1_key.serialize(writer)?; + self.slot.serialize(writer)?; + self.signature.serialize(writer)?; + self.recovery_id.serialize(writer)?; + self.advisories.serialize(writer)?; + Ok(()) + } +} + +impl InstructionData for GuardianQuoteVerifyParams {} + +impl Discriminator for GuardianQuoteVerifyParams { + const DISCRIMINATOR: &[u8] = GuardianQuoteVerify::DISCRIMINATOR; +} + +const DISCRIMINATOR: &[u8] = &[168, 36, 93, 156, 157, 150, 148, 45]; +impl Discriminator for GuardianQuoteVerify { + const DISCRIMINATOR: &[u8] = DISCRIMINATOR; +} + +/// Arguments for building a guardian quote verification instruction +pub struct GuardianQuoteVerifyArgs { + /// Guardian account public key + pub guardian: Pubkey, + /// Oracle account public key + pub oracle: Pubkey, + /// Authority account public key + pub authority: Pubkey, + /// Guardian queue account public key + pub guardian_queue: Pubkey, + /// Unix timestamp of the verification + pub timestamp: i64, + /// MR_ENCLAVE measurement from the trusted execution environment + pub mr_enclave: [u8; 32], + /// Index of the oracle in the queue + pub idx: u32, + /// ED25519 public key for signature verification + pub ed25519_key: Pubkey, + /// SECP256K1 public key (64 bytes) + pub secp256k1_key: [u8; 64], + /// Slot number for this verification + pub slot: u64, + /// ECDSA signature (64 bytes) + pub signature: [u8; 64], + /// Recovery ID for signature verification + pub recovery_id: u8, + /// List of security advisories + pub advisories: Vec, +} +/// Account metas for guardian quote verification instruction +pub struct GuardianQuoteVerifyAccounts { + /// Guardian account public key + pub guardian: Pubkey, + /// Oracle account public key + pub oracle: Pubkey, + /// Authority account public key + pub authority: Pubkey, + /// Guardian queue account public key + pub guardian_queue: Pubkey, + /// Global state account public key + pub state: Pubkey, + /// Recent slot hashes sysvar account + pub recent_slothashes: Pubkey, +} +impl ToAccountMetas for GuardianQuoteVerifyAccounts { + fn to_account_metas(&self, _: Option) -> Vec { + vec![ + AccountMeta::new(self.guardian, false), + AccountMeta::new(self.oracle, false), + AccountMeta::new_readonly(self.authority, true), + AccountMeta::new(self.guardian_queue, false), + AccountMeta::new_readonly(self.state, false), + AccountMeta::new_readonly(self.recent_slothashes, false), + ] + } +} + +impl GuardianQuoteVerify { + /// Builds a guardian quote verification instruction + pub fn build_ix(args: GuardianQuoteVerifyArgs) -> Result { + let pid = if crate::utils::is_devnet() { + get_sb_program_id("devnet") + } else { + get_sb_program_id("mainnet") + }; + Ok(crate::utils::build_ix( + &pid, + &GuardianQuoteVerifyAccounts { + guardian: args.guardian, + oracle: args.oracle, + authority: args.authority, + guardian_queue: args.guardian_queue, + state: State::get_pda(), + recent_slothashes: slot_hashes::ID, + }, + &GuardianQuoteVerifyParams { + timestamp: args.timestamp, + mr_enclave: args.mr_enclave, + idx: args.idx, + ed25519_key: args.ed25519_key, + secp256k1_key: args.secp256k1_key, + slot: args.slot, + signature: args.signature, + recovery_id: args.recovery_id, + advisories: args.advisories, + }, + )) + } +} diff --git a/programs/switchboard-on-demand/src/on_demand/instructions/mod.rs b/programs/switchboard-on-demand/src/on_demand/instructions/mod.rs new file mode 100644 index 0000000000..d02784fe46 --- /dev/null +++ b/programs/switchboard-on-demand/src/on_demand/instructions/mod.rs @@ -0,0 +1,36 @@ +/// Guardian quote verification instruction +pub mod guardian_quote_verify; +/// Oracle heartbeat instruction +pub mod oracle_heartbeat; +/// Oracle heartbeat instruction version 2 +pub mod oracle_heartbeat_v2; +/// Oracle address lookup table reset instruction +pub mod oracle_reset_lut; +/// Oracle configuration setting instruction +pub mod oracle_set_configs; +/// Oracle address lookup table synchronization instruction +pub mod oracle_sync_lut; +/// Permission setting instruction +pub mod permission_set; +/// Queue garbage collection instruction +pub mod queue_garbage_collect; +/// Queue reward payment instruction +pub mod queue_pay_rewards; +/// Queue subsidy payment instruction +pub mod queue_pay_subsidy; +/// Queue address lookup table reset instruction +pub mod queue_reset_lut; +/// Randomness commitment instruction +pub mod randomness_commit; +pub use guardian_quote_verify::*; +pub use oracle_heartbeat::*; +pub use oracle_heartbeat_v2::*; +pub use oracle_reset_lut::*; +pub use oracle_set_configs::*; +pub use oracle_sync_lut::*; +pub use permission_set::*; +pub use queue_garbage_collect::*; +pub use queue_pay_rewards::*; +pub use queue_pay_subsidy::*; +pub use queue_reset_lut::*; +pub use randomness_commit::*; diff --git a/programs/switchboard-on-demand/src/on_demand/instructions/oracle_heartbeat.rs b/programs/switchboard-on-demand/src/on_demand/instructions/oracle_heartbeat.rs new file mode 100644 index 0000000000..97a4992b9a --- /dev/null +++ b/programs/switchboard-on-demand/src/on_demand/instructions/oracle_heartbeat.rs @@ -0,0 +1,180 @@ +use borsh::BorshSerialize; +use solana_program::instruction::AccountMeta; +use spl_token; + +use crate::anchor_traits::*; +use crate::prelude::*; +use crate::solana_compat::SYSTEM_PROGRAM_ID; +use crate::{cfg_client, solana_program, Pubkey}; + +/// Oracle heartbeat instruction +pub struct OracleHeartbeat {} + +/// Parameters for oracle heartbeat instruction +#[derive(Clone, BorshSerialize, Debug)] +pub struct OracleHeartbeatParams { + /// Optional URI for the oracle endpoint (64 bytes) + pub uri: Option<[u8; 64]>, +} + +impl InstructionData for OracleHeartbeatParams {} + +impl Discriminator for OracleHeartbeat { + const DISCRIMINATOR: &'static [u8] = &[10, 175, 217, 130, 111, 35, 117, 54]; +} +impl Discriminator for OracleHeartbeatParams { + const DISCRIMINATOR: &'static [u8] = OracleHeartbeat::DISCRIMINATOR; +} + +/// Arguments for building an oracle heartbeat instruction +pub struct OracleHeartbeatArgs { + /// Oracle account public key + pub oracle: Pubkey, + /// Oracle signer public key + pub oracle_signer: Pubkey, + /// Queue account public key + pub queue: Pubkey, + /// Queue authority public key + pub queue_authority: Pubkey, + /// Garbage collection node public key + pub gc_node: Pubkey, + /// Optional URI for the oracle endpoint (64 bytes) + pub uri: Option<[u8; 64]>, + /// Feeds or randomness accounts awaiting payment + pub pending_paid_accounts: Vec, + /// Escrow accounts for the pending paid accounts + pub escrows: Vec, + /// Payer account public key + pub payer: Pubkey, +} +/// Account metas for oracle heartbeat instruction +pub struct OracleHeartbeatAccounts { + /// Oracle account public key + pub oracle: Pubkey, + /// Oracle signer public key + pub oracle_signer: Pubkey, + /// Queue account public key + pub queue: Pubkey, + /// Queue authority public key + pub queue_authority: Pubkey, + /// Garbage collection node public key + pub gc_node: Pubkey, + /// Payer account public key + pub payer: Pubkey, + /// Stake program public key + pub stake_program: Pubkey, + /// Delegation pool public key + pub delegation_pool: Pubkey, + /// Delegation group public key + pub delegation_group: Pubkey, + /// SWITCH mint public key + pub switch_mint: Pubkey, +} +impl ToAccountMetas for OracleHeartbeatAccounts { + fn to_account_metas(&self, _: Option) -> Vec { + let state_pubkey = State::get_pda(); + // global subsidy vault + let subsidy_vault = get_associated_token_address( + &state_pubkey.to_bytes().into(), + &self.switch_mint.to_bytes().into(), + ); + let native_mint: Pubkey = spl_token::native_mint::ID.to_bytes().into(); + let queue_escrow = get_associated_token_address(&self.queue, &native_mint); + let (oracle_wsol_reward_pool_escrow, _) = Pubkey::find_program_address( + &[ + b"RewardPool", + &self.delegation_pool.to_bytes(), + &spl_token::native_mint::ID.to_bytes(), + ], + &self.stake_program, + ); + let (oracle_switch_reward_pool_escrow, _) = Pubkey::find_program_address( + &[ + b"RewardPool", + &self.delegation_pool.to_bytes(), + &self.switch_mint.to_bytes(), + ], + &self.stake_program, + ); + vec![ + AccountMeta::new(self.oracle, false), + AccountMeta::new(OracleAccountData::stats_key(&self.oracle), false), + AccountMeta::new_readonly(self.oracle_signer, true), + AccountMeta::new(self.queue, false), + AccountMeta::new(self.gc_node, false), + AccountMeta::new(state_pubkey, false), + AccountMeta::new(self.payer, true), + AccountMeta::new_readonly(SYSTEM_PROGRAM_ID.to_bytes().into(), false), + AccountMeta::new_readonly(spl_token::ID.to_bytes().into(), false), + AccountMeta::new_readonly(native_mint, false), + AccountMeta::new(queue_escrow, false), + AccountMeta::new_readonly(self.stake_program, false), + AccountMeta::new(self.delegation_pool, false), + AccountMeta::new(self.delegation_group, false), + // ======================================== + // Too many for anchor ctx, rest must be passed as remaining accounts + AccountMeta::new(subsidy_vault, false), + AccountMeta::new(oracle_wsol_reward_pool_escrow, false), + AccountMeta::new(oracle_switch_reward_pool_escrow, false), + ] + } +} + +cfg_client! { +use anchor_client::solana_client::nonblocking::rpc_client::RpcClient; +use crate::get_sb_program_id; + +impl OracleHeartbeat { + /// Builds an oracle heartbeat instruction asynchronously + pub async fn build_ix(client: &RpcClient, args: OracleHeartbeatArgs) -> Result { + let state_key = State::get_pda(); + let state = State::fetch_async(client).await?; + let (delegation_pool, _) = Pubkey::find_program_address( + &[ + b"Delegation", + &state_key.to_bytes(), + &OracleAccountData::stats_key(&args.oracle).to_bytes(), + &state.stake_pool.to_bytes(), + ], + &state.stake_program, + ); + let (delegation_group, _) = Pubkey::find_program_address( + &[ + b"Group", + &state_key.to_bytes(), + &state.stake_pool.to_bytes(), + &args.queue.to_bytes(), + ], + &state.stake_program, + ); + let pid = if crate::utils::is_devnet() { + get_sb_program_id("devnet") + } else { + get_sb_program_id("mainnet") + }; + let mut ix = crate::build_ix_compat!( + &pid, + &OracleHeartbeatAccounts { + oracle: args.oracle, + oracle_signer: args.oracle_signer, + queue: args.queue, + queue_authority: args.queue_authority, + gc_node: args.gc_node, + payer: args.payer, + stake_program: state.stake_program, + delegation_pool, + delegation_group, + switch_mint: state.switch_mint, + }, + &OracleHeartbeatParams { uri: args.uri } + ); + for ppa in args.pending_paid_accounts { + ix.accounts.push(AccountMeta::new_readonly(ppa, false)); + } + for escrow in args.escrows { + ix.accounts.push(AccountMeta::new(escrow, false)); + } + crate::return_ix_compat!(ix) + } +} +} diff --git a/programs/switchboard-on-demand/src/on_demand/instructions/oracle_heartbeat_v2.rs b/programs/switchboard-on-demand/src/on_demand/instructions/oracle_heartbeat_v2.rs new file mode 100644 index 0000000000..b3100f5099 --- /dev/null +++ b/programs/switchboard-on-demand/src/on_demand/instructions/oracle_heartbeat_v2.rs @@ -0,0 +1,89 @@ +use borsh::BorshSerialize; +use solana_program::instruction::AccountMeta; + +use crate::anchor_traits::*; +use crate::prelude::*; +use crate::{cfg_client, solana_program, Pubkey}; + +/// Oracle heartbeat instruction version 2 +pub struct OracleHeartbeatV2; + +/// Parameters for oracle heartbeat instruction version 2 +#[derive(Clone, BorshSerialize, Debug)] +pub struct OracleHeartbeatV2Params { + /// Optional URI for the oracle endpoint (64 bytes) + pub uri: Option<[u8; 64]>, +} + +impl InstructionData for OracleHeartbeatV2Params {} + +impl Discriminator for OracleHeartbeatV2 { + const DISCRIMINATOR: &'static [u8] = &[122, 231, 66, 32, 226, 62, 144, 103]; +} +impl Discriminator for OracleHeartbeatV2Params { + const DISCRIMINATOR: &'static [u8] = OracleHeartbeatV2::DISCRIMINATOR; +} + +/// Arguments for building an oracle heartbeat instruction version 2 +pub struct OracleHeartbeatV2Args { + /// Oracle account public key + pub oracle: Pubkey, + /// Oracle signer public key + pub oracle_signer: Pubkey, + /// Garbage collection node public key + pub gc_node: Pubkey, + /// Optional URI for the oracle endpoint (64 bytes) + pub uri: Option<[u8; 64]>, +} +/// Account metas for oracle heartbeat instruction version 2 +pub struct OracleHeartbeatV2Accounts { + /// Oracle account public key + pub oracle: Pubkey, + /// Oracle signer public key + pub oracle_signer: Pubkey, + /// Queue account public key + pub queue: Pubkey, + /// Garbage collection node public key + pub gc_node: Pubkey, +} +impl ToAccountMetas for OracleHeartbeatV2Accounts { + fn to_account_metas(&self, _: Option) -> Vec { + let state_pubkey = State::get_pda(); + let accts = vec![ + AccountMeta::new(self.oracle, false), + AccountMeta::new(OracleAccountData::stats_key(&self.oracle), false), + AccountMeta::new_readonly(self.oracle_signer, true), + AccountMeta::new(self.queue, false), + AccountMeta::new(self.gc_node, false), + AccountMeta::new(state_pubkey, false), + ]; + accts + } +} + +cfg_client! { +use anchor_client::solana_client::nonblocking::rpc_client::RpcClient; +use crate::get_sb_program_id; + +impl OracleHeartbeatV2 { + pub async fn build_ix(client: &RpcClient, args: OracleHeartbeatV2Args) -> Result { + let oracle_data = OracleAccountData::fetch_async(client, args.oracle).await?; + let pid = if crate::utils::is_devnet() { + get_sb_program_id("devnet") + } else { + get_sb_program_id("mainnet") + }; + let ix = crate::utils::build_ix( + &pid, + &OracleHeartbeatV2Accounts { + oracle: args.oracle, + oracle_signer: args.oracle_signer, + queue: oracle_data.queue, + gc_node: args.gc_node, + }, + &OracleHeartbeatV2Params { uri: args.uri }, + ); + crate::return_ix_compat!(ix) + } +} +} diff --git a/programs/switchboard-on-demand/src/on_demand/instructions/oracle_reset_lut.rs b/programs/switchboard-on-demand/src/on_demand/instructions/oracle_reset_lut.rs new file mode 100644 index 0000000000..f58377f2fa --- /dev/null +++ b/programs/switchboard-on-demand/src/on_demand/instructions/oracle_reset_lut.rs @@ -0,0 +1,110 @@ +use borsh::BorshSerialize; +use solana_program::instruction::AccountMeta; + +use crate::anchor_traits::*; +use crate::prelude::*; +use crate::solana_compat::SYSTEM_PROGRAM_ID; +use crate::{cfg_client, solana_program, Pubkey}; + +/// Oracle address lookup table reset instruction +pub struct OracleResetLut {} + +/// Parameters for oracle address lookup table reset instruction +#[derive(Clone, BorshSerialize, Debug)] +pub struct OracleResetLutParams { + /// Recent slot number for the reset + pub recent_slot: u64, +} + +impl InstructionData for OracleResetLutParams {} + +impl Discriminator for OracleResetLut { + const DISCRIMINATOR: &'static [u8] = &[147, 244, 108, 198, 152, 219, 0, 22]; +} +impl Discriminator for OracleResetLutParams { + const DISCRIMINATOR: &'static [u8] = OracleResetLut::DISCRIMINATOR; +} + +/// Arguments for building an oracle address lookup table reset instruction +pub struct OracleResetLutArgs { + /// Oracle account public key + pub oracle: Pubkey, + /// Payer account public key + pub payer: Pubkey, + /// Recent slot number for the reset + pub recent_slot: u64, +} +/// Account metas for oracle address lookup table reset instruction +pub struct OracleResetLutAccounts { + /// Oracle account public key + pub oracle: Pubkey, + /// Authority account public key + pub authority: Pubkey, + /// Payer account public key + pub payer: Pubkey, + /// System program public key + pub system_program: Pubkey, + /// Global state account public key + pub state: Pubkey, + /// Address lookup table signer account + pub lut_signer: Pubkey, + /// Address lookup table account + pub lut: Pubkey, + /// Address lookup table program public key + pub address_lookup_table_program: Pubkey, +} +impl ToAccountMetas for OracleResetLutAccounts { + fn to_account_metas(&self, _: Option) -> Vec { + let state_pubkey = State::get_pda(); + vec![ + AccountMeta::new(self.oracle, false), + AccountMeta::new_readonly(self.authority, true), + AccountMeta::new(self.payer, false), + AccountMeta::new_readonly(SYSTEM_PROGRAM_ID.to_bytes().into(), false), + AccountMeta::new_readonly(state_pubkey, false), + AccountMeta::new_readonly(self.lut_signer, false), + AccountMeta::new(self.lut, false), + AccountMeta::new_readonly(ADDRESS_LOOKUP_TABLE_PROGRAM_ID.to_bytes().into(), false), + ] + } +} + +cfg_client! { +use anchor_client::solana_client::nonblocking::rpc_client::RpcClient; +use spl_associated_token_account::solana_program::address_lookup_table::instruction::derive_lookup_table_address; +use crate::get_sb_program_id; +use crate::find_lut_signer; + +impl OracleResetLut { + pub async fn build_ix(client: &RpcClient, args: OracleResetLutArgs) -> Result { + let oracle_data = OracleAccountData::fetch_async(client, args.oracle).await?; + let authority = oracle_data.authority; + let payer = oracle_data.authority; + let lut_signer: Pubkey = find_lut_signer(&args.oracle); + let lut = derive_lookup_table_address(&lut_signer.to_bytes().into(), args.recent_slot).0; + let address_lookup_table_program = crate::on_demand::ADDRESS_LOOKUP_TABLE_PROGRAM_ID; + let pid = if crate::utils::is_devnet() { + get_sb_program_id("devnet") + } else { + get_sb_program_id("mainnet") + }; + let ix = crate::utils::build_ix( + &pid, + &OracleResetLutAccounts { + oracle: args.oracle, + state: State::get_pda(), + authority, + lut_signer, + lut: lut.to_bytes().into(), + address_lookup_table_program, + payer, + system_program: SYSTEM_PROGRAM_ID.to_bytes().into(), + }, + &OracleResetLutParams { + recent_slot: args.recent_slot, + } + ); + crate::return_ix_compat!(ix) + } +} +} diff --git a/programs/switchboard-on-demand/src/on_demand/instructions/oracle_set_configs.rs b/programs/switchboard-on-demand/src/on_demand/instructions/oracle_set_configs.rs new file mode 100644 index 0000000000..ce45f3f344 --- /dev/null +++ b/programs/switchboard-on-demand/src/on_demand/instructions/oracle_set_configs.rs @@ -0,0 +1,80 @@ +use borsh::BorshSerialize; +use solana_program::instruction::AccountMeta; + +use crate::anchor_traits::*; +#[cfg(feature = "client")] +use crate::prelude::*; +use crate::{cfg_client, solana_program, Pubkey}; + +/// Oracle configuration setting instruction +pub struct OracleSetConfigs {} + +/// Parameters for oracle configuration setting instruction +#[derive(Clone, BorshSerialize, Debug)] +pub struct OracleSetConfigsParams { + /// New authority public key (optional, 32 bytes) + pub new_authority: Option<[u8; 32]>, + /// New SECP256K1 authority key (optional, 64 bytes) + pub new_secp_authority: Option<[u8; 64]>, +} + +impl InstructionData for OracleSetConfigsParams {} + +impl Discriminator for OracleSetConfigs { + const DISCRIMINATOR: &'static [u8] = &[129, 111, 223, 4, 191, 188, 70, 180]; +} +impl Discriminator for OracleSetConfigsParams { + const DISCRIMINATOR: &'static [u8] = OracleSetConfigs::DISCRIMINATOR; +} + +/// Arguments for building an oracle configuration setting instruction +pub struct OracleSetConfigsArgs { + /// Oracle account public key + pub oracle: Pubkey, + /// Authority account public key + pub authority: Pubkey, + /// SECP256K1 authority key (64 bytes) + pub secp_authority: [u8; 64], +} +/// Account metas for oracle configuration setting instruction +pub struct OracleSetConfigsAccounts { + /// Oracle account public key + pub oracle: Pubkey, + /// Authority account public key + pub authority: Pubkey, +} +impl ToAccountMetas for OracleSetConfigsAccounts { + fn to_account_metas(&self, _: Option) -> Vec { + vec![ + AccountMeta::new(self.oracle, false), + AccountMeta::new_readonly(self.authority, true), + ] + } +} + +cfg_client! { +use anchor_client::solana_client::nonblocking::rpc_client::RpcClient; +use crate::get_sb_program_id; + +impl OracleSetConfigs { + pub async fn build_ix(_client: &RpcClient, args: OracleSetConfigsArgs) -> Result { + let pid = if crate::utils::is_devnet() { + get_sb_program_id("devnet") + } else { + get_sb_program_id("mainnet") + }; + let ix = crate::utils::build_ix( + &pid, + &OracleSetConfigsAccounts { + oracle: args.oracle, + authority: args.authority, + }, + &OracleSetConfigsParams { + new_authority: Some(args.authority.to_bytes()), + new_secp_authority: Some(args.secp_authority), + }, + ); + crate::return_ix_compat!(ix) + } +} +} diff --git a/programs/switchboard-on-demand/src/on_demand/instructions/oracle_sync_lut.rs b/programs/switchboard-on-demand/src/on_demand/instructions/oracle_sync_lut.rs new file mode 100644 index 0000000000..8f863b114a --- /dev/null +++ b/programs/switchboard-on-demand/src/on_demand/instructions/oracle_sync_lut.rs @@ -0,0 +1,163 @@ +use borsh::BorshSerialize; +use solana_program::instruction::AccountMeta; + +use crate::anchor_traits::*; +use crate::prelude::*; +use crate::solana_compat::{ADDRESS_LOOKUP_TABLE_PROGRAM_ID, SYSTEM_PROGRAM_ID}; +use crate::{cfg_client, solana_program, Pubkey}; + +/// Oracle address lookup table synchronization instruction +pub struct OracleSyncLut {} + +/// Parameters for oracle address lookup table synchronization instruction +#[derive(Clone, BorshSerialize, Debug)] +pub struct OracleSyncLutParams {} + +impl InstructionData for OracleSyncLutParams {} + +const DISCRIMINATOR: &[u8] = &[138, 99, 12, 59, 18, 170, 171, 45]; +impl Discriminator for OracleSyncLut { + const DISCRIMINATOR: &[u8] = DISCRIMINATOR; +} +impl Discriminator for OracleSyncLutParams { + const DISCRIMINATOR: &[u8] = DISCRIMINATOR; +} + +/// Arguments for building an oracle address lookup table synchronization instruction +pub struct OracleSyncLutArgs { + /// Oracle account public key + pub oracle: Pubkey, + /// Vault account public key + pub vault: Pubkey, + /// Payer account public key + pub payer: Pubkey, +} +/// Account metas for oracle address lookup table synchronization instruction +pub struct OracleSyncLutAccounts { + /// Oracle account public key + pub oracle: Pubkey, + /// Queue account public key + pub queue: Pubkey, + /// Network coordination node public key + pub ncn: Pubkey, + /// Vault account public key + pub vault: Pubkey, + /// Global state account public key + pub state: Pubkey, + /// Authority account public key + pub authority: Pubkey, + /// Operator account public key + pub operator: Pubkey, + /// NCN operator state account public key + pub ncn_operator_state: Pubkey, + /// Operator vault ticket account public key + pub operator_vault_ticket: Pubkey, + /// Vault operator delegation account public key + pub vault_operator_delegation: Pubkey, + /// Address lookup table signer account + pub lut_signer: Pubkey, + /// Address lookup table account + pub lut: Pubkey, + /// Address lookup table program public key + pub address_lookup_table_program: Pubkey, + /// Payer account public key + pub payer: Pubkey, + /// System program public key + pub system_program: Pubkey, +} +impl ToAccountMetas for OracleSyncLutAccounts { + fn to_account_metas(&self, _: Option) -> Vec { + let state_pubkey = State::get_pda(); + vec![ + AccountMeta::new(self.oracle, false), + AccountMeta::new_readonly(self.queue, false), + AccountMeta::new_readonly(self.ncn, false), + AccountMeta::new_readonly(self.vault, false), + AccountMeta::new_readonly(state_pubkey, false), + AccountMeta::new_readonly(self.authority, true), + AccountMeta::new_readonly(self.operator, false), + AccountMeta::new_readonly(self.ncn_operator_state, false), + AccountMeta::new_readonly(self.operator_vault_ticket, false), + AccountMeta::new_readonly(self.vault_operator_delegation, false), + AccountMeta::new_readonly(self.lut_signer, false), + AccountMeta::new(self.lut, false), + AccountMeta::new_readonly(ADDRESS_LOOKUP_TABLE_PROGRAM_ID, false), + AccountMeta::new(self.payer, true), + AccountMeta::new_readonly(SYSTEM_PROGRAM_ID, false), + ] + } +} + +cfg_client! { +use anchor_client::solana_client::nonblocking::rpc_client::RpcClient; +use spl_associated_token_account::solana_program::address_lookup_table::instruction::derive_lookup_table_address; +use crate::get_sb_program_id; +use crate::find_lut_signer; + +const JITO_VAULT_ID: Pubkey = solana_program::pubkey!("Vau1t6sLNxnzB7ZDsef8TLbPLfyZMYXH8WTNqUdm9g8"); +const JITO_RESTAKING_ID: Pubkey = solana_program::pubkey!("RestkWeAVL8fRGgzhfeoqFhsqKRchg6aa1XrcH96z4Q"); + +impl OracleSyncLut { + pub async fn build_ix(client: &RpcClient, args: OracleSyncLutArgs) -> Result { + let oracle_data = OracleAccountData::fetch_async(client, args.oracle).await?; + let queue = oracle_data.queue; + let queue_data = QueueAccountData::fetch_async(client, queue).await?; + let authority = oracle_data.authority; + let operator = oracle_data.operator; + let payer = oracle_data.authority; + let lut_signer: Pubkey = find_lut_signer(&queue); + let lut = derive_lookup_table_address(&lut_signer.to_bytes().into(), queue_data.lut_slot).0; + let ncn_operator_state = Pubkey::find_program_address( + &[ + b"ncn_operator_state", + &queue_data.ncn.to_bytes(), + &operator.to_bytes(), + ], + &JITO_RESTAKING_ID, + ).0; + let operator_vault_ticket = Pubkey::find_program_address( + &[ + b"operator_vault_ticket", + &operator.to_bytes(), + &args.vault.to_bytes(), + ], + &JITO_RESTAKING_ID, + ).0; + let vault_operator_delegation = Pubkey::find_program_address( + &[ + b"vault_operator_delegation", + &args.vault.to_bytes(), + &operator.to_bytes(), + ], + &JITO_VAULT_ID, + ).0; + let pid = if crate::utils::is_devnet() { + get_sb_program_id("devnet") + } else { + get_sb_program_id("mainnet") + }; + let ix = crate::utils::build_ix( + &pid, + &OracleSyncLutAccounts { + oracle: args.oracle, + queue, + ncn: queue_data.ncn, + vault: args.vault, + state: State::get_pda(), + authority, + operator, + ncn_operator_state, + operator_vault_ticket, + vault_operator_delegation, + lut_signer, + lut: lut.to_bytes().into(), + address_lookup_table_program: ADDRESS_LOOKUP_TABLE_PROGRAM_ID, + payer, + system_program: SYSTEM_PROGRAM_ID, + }, + &OracleSyncLutParams { }, + ); + crate::return_ix_compat!(ix) + } +} +} diff --git a/programs/switchboard-on-demand/src/on_demand/instructions/permission_set.rs b/programs/switchboard-on-demand/src/on_demand/instructions/permission_set.rs new file mode 100644 index 0000000000..61c2db7faf --- /dev/null +++ b/programs/switchboard-on-demand/src/on_demand/instructions/permission_set.rs @@ -0,0 +1,89 @@ +use borsh::BorshSerialize; +use solana_program::instruction::{AccountMeta, Instruction}; + +use crate::anchor_traits::*; +use crate::prelude::*; +use crate::{get_sb_program_id, solana_program, Pubkey}; + +/// Switchboard permission types +#[repr(u32)] +#[derive(Copy, Clone)] +pub enum SwitchboardPermission { + /// No permissions granted + None = 0, + /// Permission to send oracle heartbeat + PermitOracleHeartbeat = 1 << 0, + /// Permission to use oracle queue + PermitOracleQueueUsage = 1 << 1, +} + +/// Attestation permission set instruction +pub struct AttestationPermissionSet {} + +/// Parameters for attestation permission set instruction +#[derive(Clone, BorshSerialize, Debug)] +pub struct AttestationPermissionSetParams { + /// Permission type to modify + pub permission: u8, + /// Whether to enable or disable the permission + pub enable: bool, +} + +impl InstructionData for AttestationPermissionSetParams {} + +const DISCRIMINATOR: &[u8] = &[211, 122, 185, 120, 129, 182, 55, 103]; +impl Discriminator for AttestationPermissionSetParams { + const DISCRIMINATOR: &[u8] = DISCRIMINATOR; +} + +impl Discriminator for AttestationPermissionSet { + const DISCRIMINATOR: &[u8] = DISCRIMINATOR; +} + +/// Account metas for attestation permission set instruction +pub struct AttestationPermissionSetAccounts { + /// Authority account public key + pub authority: Pubkey, + /// Granter account public key + pub granter: Pubkey, + /// Grantee account public key + pub grantee: Pubkey, +} +impl ToAccountMetas for AttestationPermissionSetAccounts { + fn to_account_metas(&self, _: Option) -> Vec { + vec![ + AccountMeta::new_readonly(self.authority, true), + AccountMeta::new_readonly(self.granter, false), + AccountMeta::new(self.grantee, false), + ] + } +} + +impl AttestationPermissionSet { + /// Builds an attestation permission set instruction + pub fn build_ix( + granter: Pubkey, + authority: Pubkey, + grantee: Pubkey, + permission: SwitchboardPermission, + enable: bool, + ) -> Result { + let pid = if crate::utils::is_devnet() { + get_sb_program_id("devnet") + } else { + get_sb_program_id("mainnet") + }; + Ok(crate::utils::build_ix( + &pid, + &AttestationPermissionSetAccounts { + authority, + granter, + grantee, + }, + &AttestationPermissionSetParams { + permission: permission as u8, + enable, + }, + )) + } +} diff --git a/programs/switchboard-on-demand/src/on_demand/instructions/queue_garbage_collect.rs b/programs/switchboard-on-demand/src/on_demand/instructions/queue_garbage_collect.rs new file mode 100644 index 0000000000..b5d80b2548 --- /dev/null +++ b/programs/switchboard-on-demand/src/on_demand/instructions/queue_garbage_collect.rs @@ -0,0 +1,69 @@ +use borsh::BorshSerialize; +use solana_program::instruction::{AccountMeta, Instruction}; + +use crate::anchor_traits::*; +use crate::prelude::*; +use crate::{get_sb_program_id, solana_program, Pubkey}; + +/// Queue garbage collection instruction +pub struct QueueGarbageCollect {} + +/// Parameters for queue garbage collection instruction +#[derive(Clone, BorshSerialize, Debug)] +pub struct QueueGarbageCollectParams { + /// Index of the oracle to garbage collect + pub idx: u32, +} + +impl InstructionData for QueueGarbageCollectParams {} +const DISCRIMINATOR: &[u8] = &[187, 208, 104, 247, 16, 91, 96, 98]; +impl Discriminator for QueueGarbageCollect { + const DISCRIMINATOR: &[u8] = DISCRIMINATOR; +} +impl Discriminator for QueueGarbageCollectParams { + const DISCRIMINATOR: &[u8] = DISCRIMINATOR; +} + +/// Arguments for building a queue garbage collection instruction +pub struct QueueGarbageCollectArgs { + /// Queue account public key + pub queue: Pubkey, + /// Oracle account public key + pub oracle: Pubkey, + /// Index of the oracle to garbage collect + pub idx: u32, +} +/// Account metas for queue garbage collection instruction +pub struct QueueGarbageCollectAccounts { + /// Queue account public key + pub queue: Pubkey, + /// Oracle account public key + pub oracle: Pubkey, +} +impl ToAccountMetas for QueueGarbageCollectAccounts { + fn to_account_metas(&self, _: Option) -> Vec { + vec![ + AccountMeta::new(self.queue, false), + AccountMeta::new(self.oracle, false), + ] + } +} + +impl QueueGarbageCollect { + /// Builds a queue garbage collection instruction + pub fn build_ix(args: QueueGarbageCollectArgs) -> Result { + let pid = if crate::utils::is_devnet() { + get_sb_program_id("devnet") + } else { + get_sb_program_id("mainnet") + }; + Ok(crate::utils::build_ix( + &pid, + &QueueGarbageCollectAccounts { + queue: args.queue, + oracle: args.oracle, + }, + &QueueGarbageCollectParams { idx: args.idx }, + )) + } +} diff --git a/programs/switchboard-on-demand/src/on_demand/instructions/queue_pay_rewards.rs b/programs/switchboard-on-demand/src/on_demand/instructions/queue_pay_rewards.rs new file mode 100644 index 0000000000..8ea8ca4f44 --- /dev/null +++ b/programs/switchboard-on-demand/src/on_demand/instructions/queue_pay_rewards.rs @@ -0,0 +1,133 @@ +use borsh::BorshSerialize; +use solana_program::instruction::AccountMeta; +use switchboard_common::cfg_client; + +use crate::anchor_traits::*; +use crate::prelude::*; +use crate::solana_compat::SYSTEM_PROGRAM_ID; +use crate::{solana_program, Pubkey}; + +/// Queue reward payment instruction +pub struct QueuePayReward {} + +/// Parameters for queue reward payment instruction +#[derive(Clone, BorshSerialize, Debug)] +pub struct QueuePayRewardParams {} + +impl InstructionData for QueuePayRewardParams {} +const DISCRIMINATOR: &[u8] = &[42, 168, 3, 251, 144, 57, 105, 201]; +impl Discriminator for QueuePayReward { + const DISCRIMINATOR: &[u8] = DISCRIMINATOR; +} +impl Discriminator for QueuePayRewardParams { + const DISCRIMINATOR: &[u8] = DISCRIMINATOR; +} + +/// Arguments for building a queue reward payment instruction +#[derive(Clone, Debug)] +pub struct QueuePayRewardArgs { + /// Queue account public key + pub queue: Pubkey, + /// Oracle account public key + pub oracle: Pubkey, + /// Payer account public key + pub payer: Pubkey, +} + +/// Account metas for queue reward payment instruction +pub struct QueuePayRewardAccounts { + /// Queue account public key + pub queue: Pubkey, + /// Oracle account public key + pub oracle: Pubkey, + /// SWITCH mint public key + pub switch_mint: Pubkey, + /// Payer account public key + pub payer: Pubkey, + /// Additional account metas required for the instruction + pub remaining_accounts: Vec, +} + +impl ToAccountMetas for QueuePayRewardAccounts { + fn to_account_metas(&self, _: Option) -> Vec { + let program_state = State::get_pda(); + let token_program: Pubkey = spl_token::id().to_bytes().into(); + let associated_token_program = spl_associated_token_account::id(); + let system_program = SYSTEM_PROGRAM_ID; + let wsol_mint: Pubkey = spl_token::native_mint::id().to_bytes().into(); + let oracle_stats = OracleAccountData::stats_key(&self.oracle); + + let mut accounts = vec![ + AccountMeta::new(self.queue, false), + AccountMeta::new_readonly(program_state, false), + AccountMeta::new_readonly(system_program.to_bytes().into(), false), + AccountMeta::new_readonly(self.oracle, false), + AccountMeta::new(oracle_stats, false), + AccountMeta::new_readonly(token_program, false), + AccountMeta::new_readonly(associated_token_program.to_bytes().into(), false), + AccountMeta::new_readonly(wsol_mint, false), + AccountMeta::new_readonly(self.switch_mint, false), + AccountMeta::new(self.payer, true), + ]; + accounts.extend(self.remaining_accounts.clone()); + accounts + } +} + +cfg_client! { +use anchor_client::solana_client::nonblocking::rpc_client::RpcClient; +use crate::get_sb_program_id; +#[cfg(not(feature = "anchor"))] +use spl_associated_token_account::solana_program::address_lookup_table::AddressLookupTableAccount; +#[cfg(feature = "anchor")] +use spl_associated_token_account::solana_program::address_lookup_table::AddressLookupTableAccount; + +impl QueuePayReward { + pub async fn build_ix(client: &RpcClient, args: QueuePayRewardArgs) -> Result { + let state = State::fetch_async(client).await?; + let switch_mint = state.switch_mint; + let pid = if crate::utils::is_devnet() { + get_sb_program_id("devnet") + } else { + get_sb_program_id("mainnet") + }; + + let oracle_data = OracleAccountData::fetch_async(client, args.oracle).await?; + let operator = oracle_data.operator; + let mut remaining_accounts = vec![]; + + if operator != Pubkey::default() { + let operator_reward_wallet = get_associated_token_address(&operator, &switch_mint); + remaining_accounts.push(AccountMeta::new_readonly(operator, false)); + remaining_accounts.push(AccountMeta::new(operator_reward_wallet, false)); + } + + let ix = crate::utils::build_ix( + &pid, + &QueuePayRewardAccounts { + queue: args.queue, + oracle: args.oracle, + switch_mint: state.switch_mint, + remaining_accounts, + payer: args.payer, + }, + &QueuePayRewardParams { }, + ); + crate::return_ix_compat!(ix) + } + + pub async fn fetch_luts(client: &RpcClient, args: QueuePayRewardArgs) -> Result, OnDemandError> { + let queue_data = QueueAccountData::fetch_async(client, args.queue).await?; + let queue_lut = queue_data.fetch_lut(&args.queue, client).await?; + + let oracle_data = OracleAccountData::fetch_async(client, args.oracle).await?; + let mut luts = vec![queue_lut]; + + if let Ok(oracle_lut) = oracle_data.fetch_lut(&args.oracle, client).await { + luts.push(oracle_lut); + } + + Ok(luts) + } +} +} diff --git a/programs/switchboard-on-demand/src/on_demand/instructions/queue_pay_subsidy.rs b/programs/switchboard-on-demand/src/on_demand/instructions/queue_pay_subsidy.rs new file mode 100644 index 0000000000..ac75a16dc5 --- /dev/null +++ b/programs/switchboard-on-demand/src/on_demand/instructions/queue_pay_subsidy.rs @@ -0,0 +1,163 @@ +use borsh::BorshSerialize; +use solana_program::instruction::AccountMeta; +use switchboard_common::cfg_client; + +use crate::anchor_traits::*; +use crate::prelude::*; +use crate::solana_compat::{pubkey, SYSTEM_PROGRAM_ID}; +use crate::{solana_program, Pubkey}; + +/// Jito vault public key constant +pub const JITO_VAULT_ID: Pubkey = pubkey!("Vau1t6sLNxnzB7ZDsef8TLbPLfyZMYXH8WTNqUdm9g8"); + +/// Queue subsidy payment instruction +pub struct QueuePaySubsidy {} + +/// Parameters for queue subsidy payment instruction +#[derive(Clone, BorshSerialize, Debug)] +pub struct QueuePaySubsidyParams {} + +impl InstructionData for QueuePaySubsidyParams {} +const DISCRIMINATOR: &[u8] = &[85, 84, 51, 251, 144, 57, 105, 200]; +impl Discriminator for QueuePaySubsidy { + const DISCRIMINATOR: &[u8] = DISCRIMINATOR; +} +impl Discriminator for QueuePaySubsidyParams { + const DISCRIMINATOR: &[u8] = DISCRIMINATOR; +} + +/// Arguments for building a queue subsidy payment instruction +#[derive(Clone, Debug)] +pub struct QueuePaySubsidyArgs { + /// Queue account public key + pub queue: Pubkey, + /// Vault account public key + pub vault: Pubkey, + /// Payer account public key + pub payer: Pubkey, +} +/// Account metas for queue subsidy payment instruction +pub struct QueuePaySubsidyAccounts { + /// Queue account public key + pub queue: Pubkey, + /// Vault account public key + pub vault: Pubkey, + /// SWITCH mint public key + pub switch_mint: Pubkey, + /// Payer account public key + pub payer: Pubkey, + /// Additional account metas required for the instruction + pub remaining_accounts: Vec, +} +impl ToAccountMetas for QueuePaySubsidyAccounts { + fn to_account_metas(&self, _: Option) -> Vec { + let program_state = State::get_pda(); + let token_program: Pubkey = spl_token::id().to_bytes().into(); + let associated_token_program = spl_associated_token_account::id(); + let system_program = SYSTEM_PROGRAM_ID; + let wsol_mint: Pubkey = spl_token::native_mint::id().to_bytes().into(); + let subsidy_vault = get_associated_token_address( + &program_state.to_bytes().into(), + &self.switch_mint.to_bytes().into(), + ); + let reward_vault = get_associated_token_address( + &self.vault.to_bytes().into(), + &self.switch_mint.to_bytes().into(), + ); + let vault_config = Pubkey::find_program_address(&[b"config"], &JITO_VAULT_ID).0; + + let mut accounts = vec![ + AccountMeta::new(self.queue, false), + AccountMeta::new_readonly(program_state, false), + AccountMeta::new_readonly(system_program.to_bytes().into(), false), + AccountMeta::new_readonly(self.vault, false), + AccountMeta::new(reward_vault, false), + AccountMeta::new(subsidy_vault, false), + AccountMeta::new_readonly(token_program, false), + AccountMeta::new_readonly(associated_token_program.to_bytes().into(), false), + AccountMeta::new_readonly(wsol_mint, false), + AccountMeta::new_readonly(self.switch_mint, false), + AccountMeta::new_readonly(vault_config, false), + AccountMeta::new(self.payer, true), + ]; + accounts.extend(self.remaining_accounts.clone()); + accounts + } +} + +cfg_client! { +use anchor_client::solana_client::nonblocking::rpc_client::RpcClient; +use crate::get_sb_program_id; +use futures::future::join_all; +#[cfg(not(feature = "anchor"))] +use spl_associated_token_account::solana_program::address_lookup_table::AddressLookupTableAccount; +#[cfg(feature = "anchor")] +use spl_associated_token_account::solana_program::address_lookup_table::AddressLookupTableAccount; + +impl QueuePaySubsidy { + pub async fn build_ix(client: &RpcClient, args: QueuePaySubsidyArgs) -> Result { + let state = State::fetch_async(client).await?; + let switch_mint = state.switch_mint; + let pid = if crate::utils::is_devnet() { + get_sb_program_id("devnet") + } else { + get_sb_program_id("mainnet") + }; + let queue_data = QueueAccountData::fetch_async(client, args.queue).await?; + let oracles = queue_data.oracle_keys[..queue_data.oracle_keys_len as usize].to_vec(); + let mut remaining_accounts = vec![]; + for oracle in oracles { + let oracle_stats = OracleAccountData::stats_key(&oracle); + remaining_accounts.push(AccountMeta::new_readonly(oracle, false)); + remaining_accounts.push(AccountMeta::new_readonly(oracle_stats, false)); + let oracle_data = OracleAccountData::fetch_async(client, oracle).await?; + let operator = oracle_data.operator; + if operator == Pubkey::default() { + continue; + } + let oracle_subisidy_wallet = get_associated_token_address(&operator, &switch_mint); + remaining_accounts.push(AccountMeta::new_readonly(operator, false)); + remaining_accounts.push(AccountMeta::new(oracle_subisidy_wallet, false)); + } + let ix = crate::utils::build_ix( + &pid, + &QueuePaySubsidyAccounts { + queue: args.queue, + vault: args.vault, + switch_mint: state.switch_mint, + remaining_accounts, + payer: args.payer, + }, + &QueuePaySubsidyParams { }, + ); + crate::return_ix_compat!(ix) + } + + pub async fn fetch_luts(client: &RpcClient, args: QueuePaySubsidyArgs) -> Result, OnDemandError> { + let queue_data = QueueAccountData::fetch_async(client, args.queue).await?; + let queue_lut = queue_data.fetch_lut(&args.queue, client).await?; + let oracles = queue_data.oracle_keys[..queue_data.oracle_keys_len as usize].to_vec(); + + // Spawn parallel async tasks for fetching LUTs + let lut_futures: Vec<_> = oracles + .into_iter() + .map(|oracle| { + async move { + let oracle_data = OracleAccountData::fetch_async(client, oracle).await.ok()?; + oracle_data.fetch_lut(&oracle, client).await.ok() + } + }) + .collect(); + + // Run all futures in parallel + let mut luts: Vec = join_all(lut_futures) + .await + .into_iter() + .flatten() + .collect(); + luts.push(queue_lut); + + Ok(luts) + } +} +} diff --git a/programs/switchboard-on-demand/src/on_demand/instructions/queue_reset_lut.rs b/programs/switchboard-on-demand/src/on_demand/instructions/queue_reset_lut.rs new file mode 100644 index 0000000000..86e7393b34 --- /dev/null +++ b/programs/switchboard-on-demand/src/on_demand/instructions/queue_reset_lut.rs @@ -0,0 +1,150 @@ +use borsh::BorshSerialize; +use solana_program::instruction::AccountMeta; +use switchboard_common::cfg_client; + +use crate::anchor_traits::*; +use crate::prelude::*; +use crate::solana_compat::SYSTEM_PROGRAM_ID; +use crate::{find_lut_signer, solana_program, Pubkey}; + +/// Queue address lookup table reset instruction +pub struct QueueResetLut {} + +/// Parameters for queue address lookup table reset instruction +#[derive(Clone, BorshSerialize, Debug)] +pub struct QueueResetLutParams { + /// Recent slot number for the reset + pub recent_slot: u64, +} + +impl InstructionData for QueueResetLutParams {} +const DISCRIMINATOR: &[u8] = &[126, 234, 176, 75, 38, 211, 204, 53]; +impl Discriminator for QueueResetLut { + const DISCRIMINATOR: &[u8] = DISCRIMINATOR; +} +impl Discriminator for QueueResetLutParams { + const DISCRIMINATOR: &[u8] = DISCRIMINATOR; +} + +/// Arguments for building a queue address lookup table reset instruction +#[derive(Clone, Debug)] +pub struct QueueResetLutArgs { + /// Queue account public key + pub queue: Pubkey, + /// Authority account public key + pub authority: Pubkey, + /// Payer account public key + pub payer: Pubkey, + /// Recent slot number for the reset + pub recent_slot: u64, +} + +/// Account metas for queue address lookup table reset instruction +pub struct QueueResetLutAccounts { + /// Queue account public key + pub queue: Pubkey, + /// Authority account public key + pub authority: Pubkey, + /// Payer account public key + pub payer: Pubkey, + /// Recent slot number for the reset + pub recent_slot: u64, +} + +impl ToAccountMetas for QueueResetLutAccounts { + fn to_account_metas(&self, _: Option) -> Vec { + let program_state = State::get_pda(); + let system_program = SYSTEM_PROGRAM_ID; + let address_lookup_table_program = ADDRESS_LOOKUP_TABLE_PROGRAM_ID; + let lut_signer = find_lut_signer(&self.queue); + + fn derive_lookup_table_address( + authority_address: &Pubkey, + recent_block_slot: u64, + ) -> (Pubkey, u8) { + Pubkey::find_program_address( + &[authority_address.as_ref(), &recent_block_slot.to_le_bytes()], + &ADDRESS_LOOKUP_TABLE_PROGRAM_ID, + ) + } + + vec![ + AccountMeta::new(self.queue, false), + AccountMeta::new_readonly(self.authority, true), + AccountMeta::new(self.payer, true), + AccountMeta::new_readonly(system_program.to_bytes().into(), false), + AccountMeta::new_readonly(program_state, false), + AccountMeta::new_readonly(lut_signer, false), + AccountMeta::new( + derive_lookup_table_address(&lut_signer, self.recent_slot).0, + false, + ), + AccountMeta::new_readonly(address_lookup_table_program.to_bytes().into(), false), + ] + } +} + +cfg_client! { +use anchor_client::solana_client::nonblocking::rpc_client::RpcClient; +// use crate::get_sb_program_id; // Commented out due to unused import +#[cfg(not(feature = "anchor"))] +use spl_associated_token_account::solana_program::address_lookup_table::AddressLookupTableAccount; +#[cfg(feature = "anchor")] +use spl_associated_token_account::solana_program::address_lookup_table::AddressLookupTableAccount; + +// fn derive_lookup_table_address(authority_address: &Pubkey, recent_block_slot: u64) -> (Pubkey, u8) { +// Pubkey::find_program_address( +// &[authority_address.as_ref(), &recent_block_slot.to_le_bytes()], +// &solana_program::address_lookup_table::program::id(), +// ) +// } + +impl QueueResetLut { + // TODO: Fix serialization errors - commented out due to missing trait implementations + /* + pub async fn build_ix(client: &RpcClient, args: QueueResetLutArgs) -> Result { + let pid = if crate::utils::is_devnet() { + get_sb_program_id("devnet") + } else { + get_sb_program_id("mainnet") + }; + + let lut_signer = find_lut_signer(&args.queue); + let (lut_address, _) = derive_lookup_table_address(&lut_signer, args.recent_slot); + + let program_state = State::get_pda(); + let system_program = SYSTEM_PROGRAM_ID; + let address_lookup_table_program = ADDRESS_LOOKUP_TABLE_PROGRAM_ID; + + let accounts = vec![ + AccountMeta::new(args.queue, false), + AccountMeta::new_readonly(args.authority, true), + AccountMeta::new(args.payer, true), + AccountMeta::new_readonly(system_program.to_bytes().into(), false), + AccountMeta::new_readonly(program_state, false), + AccountMeta::new_readonly(lut_signer, false), + AccountMeta::new(lut_address, false), + AccountMeta::new_readonly(address_lookup_table_program.to_bytes().into(), false), + ]; + + Ok(Instruction { + program_id: pid, + accounts, + data: [ + QueueResetLut::DISCRIMINATOR, + &QueueResetLutParams { + recent_slot: args.recent_slot, + }.try_to_vec().map_err(|_| OnDemandError::SerializationError)? + ].concat(), + }) + } + */ + + pub async fn fetch_luts(client: &RpcClient, args: QueueResetLutArgs) -> Result, OnDemandError> { + let queue_data = QueueAccountData::fetch_async(client, args.queue).await?; + let queue_lut = queue_data.fetch_lut(&args.queue, client).await?; + + Ok(vec![queue_lut]) + } +} +} diff --git a/programs/switchboard-on-demand/src/on_demand/instructions/randomness_commit.rs b/programs/switchboard-on-demand/src/on_demand/instructions/randomness_commit.rs new file mode 100644 index 0000000000..3cce865b2e --- /dev/null +++ b/programs/switchboard-on-demand/src/on_demand/instructions/randomness_commit.rs @@ -0,0 +1,163 @@ +use borsh::BorshSerialize; +use solana_program::instruction::{AccountMeta, Instruction}; +#[cfg(not(feature = "pinocchio"))] +use solana_program::program::invoke_signed; +use solana_program::program_error::ProgramError; +use solana_program::sysvar::slot_hashes; + +use crate::anchor_traits::*; +// Use our AccountInfo type alias that conditionally uses pinocchio or anchor/solana-program +#[cfg(not(feature = "pinocchio"))] +use crate::get_account_key; +use crate::prelude::*; +use crate::{get_sb_program_id, solana_program, AccountInfo, Pubkey}; + +/// Randomness commitment instruction +pub struct RandomnessCommit {} + +/// Parameters for randomness commitment instruction +#[derive(Clone, BorshSerialize, Debug)] +pub struct RandomnessCommitParams {} + +impl InstructionData for RandomnessCommitParams {} + +const DISCRIMINATOR: &[u8] = &[52, 170, 152, 201, 179, 133, 242, 141]; +impl Discriminator for RandomnessCommitParams { + const DISCRIMINATOR: &[u8] = DISCRIMINATOR; +} + +impl Discriminator for RandomnessCommit { + const DISCRIMINATOR: &[u8] = DISCRIMINATOR; +} + +/// Account metas for randomness commitment instruction +pub struct RandomnessCommitAccounts { + /// Randomness account public key + pub randomness: Pubkey, + /// Queue account public key + pub queue: Pubkey, + /// Oracle account public key + pub oracle: Pubkey, + /// Recent slot hashes sysvar account + pub recent_slothashes: Pubkey, + /// Authority account public key + pub authority: Pubkey, +} +impl ToAccountMetas for RandomnessCommitAccounts { + fn to_account_metas(&self, _: Option) -> Vec { + vec![ + AccountMeta::new(self.randomness, false), + AccountMeta::new_readonly(self.queue, false), + AccountMeta::new(self.oracle, false), + AccountMeta::new_readonly(slot_hashes::ID, false), + AccountMeta::new_readonly(self.authority, true), + ] + } +} + +impl RandomnessCommit { + /// Builds a randomness commitment instruction + pub fn build_ix( + randomness: Pubkey, + queue: Pubkey, + oracle: Pubkey, + authority: Pubkey, + ) -> Result { + let pid = if crate::utils::is_devnet() { + get_sb_program_id("devnet") + } else { + get_sb_program_id("mainnet") + }; + Ok(crate::utils::build_ix( + &pid, + &RandomnessCommitAccounts { + randomness, + queue, + oracle, + authority, + recent_slothashes: slot_hashes::ID, + }, + &RandomnessCommitParams {}, + )) + } + + /// Invokes the `randomness_commit` Switchboard CPI call. + /// + /// This call commits a new randomness value to the randomness account. + /// + /// # Requirements + /// + /// - The `authority` must be a signer. + /// + /// # Parameters + /// + /// - **switchboard**: Switchboard program account. + /// - **randomness**: Randomness account. + /// - **queue**: Queue account associated with the randomness account. + /// - **oracle**: Oracle account assigned for the randomness request. + /// - **authority**: Authority of the randomness account. + /// - **recent_slothashes**: Sysvar account to fetch recent slot hashes. + /// - **seeds**: Seeds for the CPI call. + /// + #[cfg(feature = "pinocchio")] + pub fn invoke( + #[allow(unused)] switchboard: AccountInfo, + randomness: AccountInfo, + queue: AccountInfo, + oracle: AccountInfo, + authority: AccountInfo, + recent_slothashes: AccountInfo, + #[allow(unused)] seeds: &[&[&[u8]]], + ) -> Result<(), ProgramError> { + let _accounts = vec![randomness, queue, oracle, recent_slothashes, authority]; + + // TODO: Implement pinocchio-compatible invoke_signed + // This is a complex conversion that requires bridging pinocchio and solana-program types + unimplemented!("pinocchio invoke_signed needs type bridge implementation") + } + + #[cfg(not(feature = "pinocchio"))] + pub fn invoke<'a>( + switchboard: AccountInfo<'a>, + randomness: AccountInfo<'a>, + queue: AccountInfo<'a>, + oracle: AccountInfo<'a>, + authority: AccountInfo<'a>, + recent_slothashes: AccountInfo<'a>, + seeds: &[&[&[u8]]], + ) -> Result<(), ProgramError> { + let accounts = [ + randomness.clone(), + queue.clone(), + oracle.clone(), + recent_slothashes.clone(), + authority.clone(), + ]; + let account_metas = RandomnessCommitAccounts { + randomness: (*get_account_key!(randomness)), + queue: (*get_account_key!(queue)), + oracle: (*get_account_key!(oracle)), + recent_slothashes: (*get_account_key!(recent_slothashes)), + authority: (*get_account_key!(authority)), + } + .to_account_metas(None); + let ix = Instruction { + program_id: (*get_account_key!(switchboard)), + accounts: account_metas, + data: ix_discriminator("randomness_commit").to_vec(), + }; + invoke_signed(&ix, &accounts, seeds) + } +} + +#[cfg(not(feature = "pinocchio"))] +fn ix_discriminator(name: &str) -> [u8; 8] { + let preimage = format!("global:{}", name); + let mut sighash = [0u8; 8]; + #[cfg(not(feature = "anchor"))] + let hash_result = solana_program::hash::hash(preimage.as_bytes()); + #[cfg(feature = "anchor")] + let hash_result = anchor_lang::solana_program::hash::hash(preimage.as_bytes()); + sighash.copy_from_slice(&hash_result.to_bytes()[..8]); + sighash +} diff --git a/programs/switchboard-on-demand/src/on_demand/mod.rs b/programs/switchboard-on-demand/src/on_demand/mod.rs new file mode 100644 index 0000000000..54c64027ef --- /dev/null +++ b/programs/switchboard-on-demand/src/on_demand/mod.rs @@ -0,0 +1,87 @@ +mod error; +pub use error::*; + +/// Switchboard account definitions and parsers +pub mod accounts; +pub use accounts::*; + +/// Switchboard instruction builders +pub mod instructions; +pub use instructions::*; + +/// Oracle quote verification and data extraction +pub mod oracle_quote; +pub use oracle_quote::*; + +/// Common type definitions +pub mod types; +pub use types::*; + +use crate::solana_compat::pubkey; +use crate::Pubkey; + +/// Address Lookup Table program ID +pub const ADDRESS_LOOKUP_TABLE_PROGRAM_ID: Pubkey = + pubkey!("AddressLookupTab1e1111111111111111111111111"); + +/// Derives associated token address and bump seed for given wallet and mint +pub fn get_associated_token_address_and_bump_seed( + wallet_address: &Pubkey, + token_mint_address: &Pubkey, + program_id: &Pubkey, + token_program_id: &Pubkey, +) -> (Pubkey, u8) { + get_associated_token_address_and_bump_seed_internal( + wallet_address, + token_mint_address, + program_id, + token_program_id, + ) +} + +/// Derives the associated token account address for the given wallet address +/// and token mint +pub fn get_associated_token_address( + wallet_address: &Pubkey, + token_mint_address: &Pubkey, +) -> Pubkey { + get_associated_token_address_with_program_id( + wallet_address, + token_mint_address, + &spl_token::ID.to_bytes().into(), + ) +} + +/// Derives the associated token account address for the given wallet address, +/// token mint and token program id +pub fn get_associated_token_address_with_program_id( + wallet_address: &Pubkey, + token_mint_address: &Pubkey, + token_program_id: &Pubkey, +) -> Pubkey { + get_associated_token_address_and_bump_seed( + wallet_address, + token_mint_address, + &pubkey!("ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL") + .to_bytes() + .into(), + token_program_id, + ) + .0 +} + +fn get_associated_token_address_and_bump_seed_internal( + wallet_address: &Pubkey, + token_mint_address: &Pubkey, + program_id: &Pubkey, + token_program_id: &Pubkey, +) -> (Pubkey, u8) { + Pubkey::find_program_address( + &[ + &wallet_address.to_bytes(), + &token_program_id.to_bytes(), + &token_mint_address.to_bytes(), + ], + program_id, + ) +} diff --git a/programs/switchboard-on-demand/src/on_demand/oracle_quote/feed_info.rs b/programs/switchboard-on-demand/src/on_demand/oracle_quote/feed_info.rs new file mode 100644 index 0000000000..0587d0ec37 --- /dev/null +++ b/programs/switchboard-on-demand/src/on_demand/oracle_quote/feed_info.rs @@ -0,0 +1,132 @@ +//! Packed feed information data structures for oracle quotes +//! +//! This module defines zero-copy data structures for efficiently storing and accessing +//! oracle feed data within quotes. The structures use `#[repr(packed)]` to ensure +//! consistent memory layout across platforms and minimize space usage. + +use faster_hex::hex_string; +use rust_decimal::prelude::*; + +use crate::prelude::*; + +/// Packed quote header containing the signed slot hash +/// +/// This header is signed by all oracles in the quote and contains the slot hash +/// that is used to validate the quote's freshness against the slot hash sysvar. +/// +/// Size: 32 bytes +#[derive(Copy, Clone, Debug)] +#[repr(packed)] +pub struct PackedQuoteHeader { + /// The 32-byte slot hash that was signed by all oracles in the quote + pub signed_slothash: [u8; 32], +} + +/// Packed feed information containing ID, value, and validation requirements +/// +/// This structure stores individual feed data within a quote. The layout is optimized +/// for compatibility with JavaScript serialization, with the feed ID first, followed +/// by the value and minimum sample requirement. +/// +/// Size: 49 bytes (32 + 16 + 1) +#[derive(Copy, Clone, Debug)] +#[repr(packed)] +pub struct PackedFeedInfo { + /// 32-byte unique identifier for this feed + feed_id: [u8; 32], + /// Feed value as a fixed-point integer (scaled by PRECISION) + feed_value: i128, + /// Minimum number of oracle samples required for this feed to be considered valid + min_oracle_samples: u8, +} + +impl PackedFeedInfo { + /// The size in bytes of this packed structure + pub const PACKED_SIZE: usize = 49; + + /// Returns a reference to the 32-byte feed ID + #[inline(always)] + pub fn feed_id(&self) -> &[u8; 32] { + &self.feed_id + } + + /// Returns the feed ID as a hexadecimal string with "0x" prefix + /// + /// This is useful for displaying feed IDs in a human-readable format + /// or for use in APIs that expect hex-encoded identifiers. + #[inline(always)] + pub fn hex_id(&self) -> String { + String::from("0x") + &hex_string(self.feed_id()) + } + + /// Returns the raw feed value as a fixed-point integer + /// + /// This value is scaled by the program-wide `PRECISION` constant. + /// Use [`value()`](Self::value) to get the human-readable decimal form. + #[inline(always)] + pub fn feed_value(&self) -> i128 { + self.feed_value + } + + /// Returns the feed value as a `Decimal`, scaled using the program-wide `PRECISION`. + /// + /// This converts the raw fixed-point integer into a human-readable decimal form. + /// For example, if the raw value is 115525650000000000000000 and PRECISION is 18, + /// this will return approximately 115525.65. + #[inline(always)] + pub fn value(&self) -> Decimal { + Decimal::from_i128_with_scale(self.feed_value(), PRECISION).normalize() + } + + /// Returns the minimum number of oracle samples required for this feed + #[inline(always)] + pub fn min_oracle_samples(&self) -> u8 { + self.min_oracle_samples + } +} + +#[cfg(test)] +mod tests { + + use super::*; + + #[test] + fn test_packed_feed_info_layout() { + // Simulate JavaScript serialized data: feed_id (32) + feed_value (16) + min_oracle_samples (1) + let mut data = [0u8; 49]; + + // Feed ID (32 bytes) - some test hash + data[0..32].fill(0x42); + + // Feed value at offset 32: 115525650000000000000000 (i128, scaled by 18 decimals) + // This should decode to approximately 115525.65 + let feed_value_scaled: i128 = 115525650000000000000000i128; + let value_bytes = feed_value_scaled.to_le_bytes(); + data[32..48].copy_from_slice(&value_bytes); + + // Min oracle samples (1 byte) at offset 48 + data[48] = 5; + + // Cast to PackedFeedInfo + let feed_info = unsafe { &*(data.as_ptr() as *const PackedFeedInfo) }; + + // Test reading the feed value + let raw_value = feed_info.feed_value(); + println!("Raw feed value: {}", raw_value); + println!("Expected: {}", feed_value_scaled); + assert_eq!(raw_value, feed_value_scaled); + + // Test the decimal conversion + let decimal_value = feed_info.value(); + println!("Decimal value: {}", decimal_value); + + // Test other fields + assert_eq!(feed_info.min_oracle_samples(), 5); + assert_eq!(feed_info.feed_id()[0], 0x42); + + println!( + "✅ Test passed! Feed value reads correctly: {}", + decimal_value + ); + } +} diff --git a/programs/switchboard-on-demand/src/on_demand/oracle_quote/mod.rs b/programs/switchboard-on-demand/src/on_demand/oracle_quote/mod.rs new file mode 100644 index 0000000000..087af26c00 --- /dev/null +++ b/programs/switchboard-on-demand/src/on_demand/oracle_quote/mod.rs @@ -0,0 +1,55 @@ +//! Oracle quote verification and data extraction +//! +//! This module provides functionality for verifying and extracting data from oracle quotes +//! that have been cryptographically signed by multiple oracles. The main components are: +//! +//! - [`OracleQuote`] - A verified quote containing oracle feed data +//! - [`QuoteVerifier`] - Builder pattern for configuring and performing verification +//! - [`PackedFeedInfo`] and [`PackedQuoteHeader`] - Zero-copy data structures for efficient access +//! +//! # Usage with Anchor +//! +//! The QuoteVerifier is designed to work seamlessly with Anchor's account wrapper types: +//! +//! ```rust,ignore +//! use anchor_lang::prelude::*; +//! use switchboard_on_demand::QuoteVerifier; +//! +//! pub fn verify_oracle_data(ctx: Context) -> Result<()> { +//! // Destructure accounts - works without lifetime issues +//! let VerifyCtx { queue, oracle, sysvars, .. } = ctx.accounts; +//! let clock_slot = switchboard_on_demand::clock::get_slot(&sysvars.clock); +//! +//! // Build and verify - accepts Anchor wrapper types directly +//! let quote = QuoteVerifier::new() +//! .queue(&queue) // Works with AccountLoader +//! .slothash_sysvar(&sysvars.slothashes) // Works with Sysvar +//! .ix_sysvar(&sysvars.instructions) // Works with Sysvar +//! .clock_slot(clock_slot) // Uses clock slot +//! .max_age(150) +//! .verify_account(&oracle)?; // Works with AccountLoader +//! +//! // Access verified feed data +//! for feed in quote.feeds() { +//! msg!("Feed {}: ${}", feed.hex_id(), feed.value()); +//! } +//! Ok(()) +//! } +//! ``` +//! +//! # Key Features +//! +//! - **Anchor Integration**: All methods accept types implementing `AsAccountInfo` +//! - **Flexible API**: Works with both raw `AccountInfo` and Anchor wrapper types +//! - **Lifetime Safety**: No unsafe code, proper lifetime management through ownership +//! - **Context Destructuring**: Supports destructuring Anchor contexts without lifetime issues + +pub mod feed_info; +pub use feed_info::*; +pub mod quote; +pub use quote::*; +pub mod quote_verifier; +pub use quote_verifier::*; +/// Oracle quote account utilities for Anchor integration +#[cfg(feature = "anchor")] +pub mod quote_account; diff --git a/programs/switchboard-on-demand/src/on_demand/oracle_quote/quote.rs b/programs/switchboard-on-demand/src/on_demand/oracle_quote/quote.rs new file mode 100644 index 0000000000..32c80193fd --- /dev/null +++ b/programs/switchboard-on-demand/src/on_demand/oracle_quote/quote.rs @@ -0,0 +1,781 @@ +//! Oracle quote verification and data extraction functionality +//! +//! This module provides the core `OracleQuote` struct for working with verified oracle data quotes. +//! A quote contains aggregated feed data from multiple oracles, cryptographically verified +//! through ED25519 signatures and Solana's instruction sysvar. + +use core::ptr::read_unaligned; + +use anyhow::{Context, Error as AnyError}; + +use crate::solana_compat::sol_memcpy_; +// Use our AccountInfo type alias that conditionally uses pinocchio or anchor/solana-program +use crate::AccountInfo; +use crate::{borrow_mut_account_data, check_pubkey_eq, AsAccountInfo, Instructions, Pubkey}; + +#[allow(unused)] +const SLOTS_PER_EPOCH: u64 = 432_000; + +/// Default discriminator for Switchboard Oracle data +pub const QUOTE_DISCRIMINATOR: [u8; 8] = *b"SBOracle"; +/// QUOTE_DISCRIMINATOR as little-endian u64 for efficient comparison +pub const QUOTE_DISCRIMINATOR_U64_LE: u64 = u64::from_le_bytes(QUOTE_DISCRIMINATOR); + +/// A verified oracle quote containing feed data from multiple oracles. +/// +/// This struct provides zero-copy access to aggregated oracle feed data that has been +/// cryptographically verified through ED25519 signatures. The quote contains: +/// - Feed data with values and metadata +/// - Oracle signature information and indices +/// - Slot and version information for freshness validation +/// - Raw instruction data for serialization (when available) +/// +/// All data is stored as references to avoid unnecessary copying, making this struct +/// highly efficient for on-chain programs where compute units are precious. +#[derive(Clone, Copy)] +pub struct OracleQuote<'a> { + /// Reference to the quote header containing signed slot hash + quote_header_refs: &'a crate::on_demand::oracle_quote::feed_info::PackedQuoteHeader, + /// Number of oracle signatures that verified this quote + pub oracle_count: u8, + /// Zero-copy reference to the packed feed data from the first signature + pub packed_feed_infos: &'a [crate::on_demand::oracle_quote::feed_info::PackedFeedInfo], + /// Number of valid feeds in the quote (private, calculated during verification) + feed_count: u8, + /// Oracle indices that correspond to the queue's oracle array + pub oracle_idxs: &'a [u8], + /// Recent slot from the ED25519 instruction data used for freshness validation + pub recent_slot: u64, + /// Version from the ED25519 instruction data + pub version: u8, + /// Reference to the raw ED25519 instruction data for serialization + pub raw_buffer: &'a [u8], +} + +impl<'a> OracleQuote<'a> { + /// Creates a new OracleQuote with header references and zero-copy feed data. + /// + /// This constructor is used internally after verification to create an OracleQuote + /// instance with validated data. All parameters should be pre-verified. + /// + /// # Arguments + /// * `quote_header_ref` - Reference to the verified quote header + /// * `oracle_count` - Number of oracle signatures + /// * `packed_feed_infos` - Slice of packed feed information + /// * `feed_count` - Number of valid feeds + /// * `oracle_idxs` - Oracle indices array + /// * `recent_slot` - Recent slot from ED25519 instruction + /// * `version` - Version from ED25519 instruction + /// * `raw_buffer` - Reference to the raw ED25519 instruction data + #[inline(always)] + #[allow(clippy::too_many_arguments)] + pub(crate) fn new( + quote_header_ref: &'a crate::on_demand::oracle_quote::feed_info::PackedQuoteHeader, + oracle_count: u8, + packed_feed_infos: &'a [crate::on_demand::oracle_quote::feed_info::PackedFeedInfo], + feed_count: u8, + oracle_idxs: &'a [u8], + recent_slot: u64, + version: u8, + raw_buffer: &'a [u8], + ) -> Self { + Self { + quote_header_refs: quote_header_ref, + oracle_count, + packed_feed_infos, + feed_count, + oracle_idxs, + recent_slot, + version, + raw_buffer, + } + } + + /// Returns the recent slot from the ED25519 instruction data. + /// + /// This slot value represents when the quote was created and is used + /// for freshness validation against the slot hash sysvar. + #[inline(always)] + pub fn slot(&self) -> u64 { + self.recent_slot + } + + /// Returns the version from the ED25519 instruction data. + /// + /// The version indicates the quote format version used by the oracles. + #[inline(always)] + pub fn version(&self) -> u8 { + self.version + } + + /// Returns a reference to the raw ED25519 instruction data used to create this quote. + /// + /// This method provides access to the original verified instruction data that can be + /// used for serialization, storage, or further processing. The data includes all + /// signatures and quote information in its original binary format. + /// + /// # Returns + /// * `Some(&[u8])` - Reference to the raw instruction data if available + /// * `None` - Raw data not available (e.g., quote created from account data) + /// + /// # Example + /// ```rust,ignore + /// let quote = verifier.verify_instruction_at(0)?; + /// + /// if let Some(raw_data) = quote.raw_data() { + /// // Store or transmit the raw oracle data + /// store_oracle_quote(raw_data)?; + /// } + /// ``` + #[inline(always)] + pub fn raw_data(&self) -> &[u8] { + self.raw_buffer + } + + /// Returns a slice of the valid packed feeds. + /// + /// This provides access to all verified feed data in the quote. + /// Each feed contains a feed ID, value, and minimum oracle samples requirement. + #[inline(always)] + pub fn feeds(&self) -> &[crate::on_demand::oracle_quote::feed_info::PackedFeedInfo] { + &self.packed_feed_infos[..self.feed_count as usize] + } + + #[inline(always)] + pub fn feed_ids(&self) -> Vec<&[u8]> { + self.feeds() + .iter() + .map(|info| info.feed_id().as_slice()) + .collect() + } + + /// Returns the number of valid feeds in this quote + #[inline(always)] + pub fn len(&self) -> usize { + self.feed_count as usize + } + + /// Returns true if this quote contains no feeds + #[inline(always)] + pub fn is_empty(&self) -> bool { + self.feed_count == 0 + } + + /// Returns the oracle index for a specific signature position. + /// + /// # Arguments + /// * `signature_index` - The position of the signature (0 to oracle_count-1) + /// + /// # Returns + /// * `Ok(u8)` - The oracle index that corresponds to the queue's oracle array + /// * `Err(AnyError)` - If signature_index is out of bounds + /// + /// # Example + /// ```rust,ignore + /// let oracle_idx = quote.oracle_index(0)?; // Get first oracle's index + /// ``` + #[inline(always)] + pub fn oracle_index(&self, signature_index: usize) -> Result { + if signature_index < self.oracle_count as usize { + Ok(self.oracle_idxs[signature_index]) + } else { + anyhow::bail!( + "Invalid signature index {} for quote with {} oracles", + signature_index, + self.oracle_count + ) + } + } + + /// Returns a reference to the quote header. + /// + /// The header contains the signed slot hash that was verified against + /// the slot hash sysvar during quote verification. + #[inline(always)] + pub fn header(&self) -> &'a crate::on_demand::oracle_quote::feed_info::PackedQuoteHeader { + self.quote_header_refs + } + + /// Finds a packed feed with a specific feed ID. + /// + /// # Arguments + /// * `feed_id` - A 32-byte array representing the feed ID to look for + /// + /// # Returns + /// * `Ok(&PackedFeedInfo)` - Reference to the feed info if found + /// * `Err(AnyError)` - Error if the feed ID is not found in the quote + /// + /// # Example + /// ```rust,ignore + /// let feed_id = [0u8; 32]; // Your feed ID + /// match quote.feed(&feed_id) { + /// Ok(feed_info) => println!("Feed value: {}", feed_info.value()), + /// Err(_) => println!("Feed not found in quote"), + /// } + /// ``` + #[inline(always)] + pub fn feed( + &self, + feed_id: &[u8; 32], + ) -> std::result::Result<&crate::on_demand::oracle_quote::feed_info::PackedFeedInfo, AnyError> + { + let info = self.packed_feed_infos[..self.feed_count as usize] + .iter() + .find(|info| info.feed_id() == feed_id) + .context("Switchboard On-Demand FeedNotFound")?; + Ok(info) + } + + /// High-performance ED25519 instruction data copy with slot validation. + /// + /// This function performs an optimized copy of oracle quote data from ED25519 instruction data + /// to a destination buffer with a length prefix. It implements slot-based ordering validation + /// to prevent oracle quote replay attacks and ensures data freshness. + /// + /// # Data Format + /// + /// **Source format** (ED25519 instruction data): + /// ``` + /// [message_data][oracle_signatures][recent_slot(8)][version(1)][SBOD(4)] + /// ``` + /// - Slot is located at offset `data_len - 13` (13 = 8 + 1 + 4) + /// + /// **Destination format** (after this function): + /// ``` + /// [length(2)][message_data][oracle_signatures][recent_slot(8)][version(1)][SBOD(4)] + /// ``` + /// - Adds 2-byte length prefix to the instruction data + /// + /// # Arguments + /// + /// * `clock_slot` - Current slot for validation + /// * `source` - ED25519 instruction data slice containing oracle quote + /// * `dst` - Mutable destination buffer (will be prefixed with 2-byte length) + /// + /// # Safety + /// + /// This function performs unsafe memory operations for performance: + /// - **ASSUMES** `source` contains valid ED25519 instruction data with slot at correct offset + /// - **ASSUMES** `dst` buffer has sufficient capacity (source.len() + 2 bytes) + /// - **REQUIRES** instruction data format: [...data][slot(8)][version(1)][SBOD(4)] + /// + /// # Validation + /// + /// Performs critical slot-based validations: + /// - **Freshness**: new slot < clock.slot (prevents stale data) + /// - **Progression**: new slot ≥ existing slot in destination (anti-replay protection) + /// - **Capacity**: destination buffer can hold length prefix + data + /// + /// # Performance + /// + /// Optimized for maximum performance at approximately 79 compute units with validations. + /// + /// # Panics + /// + /// Panics if critical validations fail: + /// - New slot >= clock slot (stale oracle data) + /// - Slot regression detected (replay attack prevention) + /// - Destination buffer too small for prefixed data + #[inline(always)] + pub fn store_delimited(clock_slot: u64, source: &[u8], dst: &mut [u8]) { + // Validate slot progression before writing + Self::validate_slot_progression(clock_slot, source, dst); + + // 79 Compute units with safety checks and sequencing + unsafe { + let dst_ptr = dst.as_mut_ptr(); + let data_len = source.len(); + + // Write the new data + assert!(data_len + 2 <= dst.len()); // ensure dst buffer is large enough + *(dst_ptr as *mut u16) = data_len as u16; + sol_memcpy_(dst_ptr.add(2), source.as_ptr(), data_len as u64); + } + } + + /// Stores oracle quote data with length delimiter but without slot validation. + /// + /// This method writes oracle data directly to a buffer without performing any + /// slot progression or freshness validation. It simply trusts the slot number + /// embedded in the source data. + /// + /// **USE WITH CAUTION**: This method bypasses all safety checks including: + /// - Slot progression validation + /// - Slot freshness checks + /// - Slot hash verification + /// + /// # Arguments + /// * `source` - Raw ED25519 instruction data to store + /// * `dst` - Target buffer to write to (must have space for length + data) + /// + /// # Safety + /// This method performs minimal validation and writes directly to memory. + /// Only basic buffer size checks are performed. + /// + /// # Panics + /// Panics if the destination buffer is too small for the data. + #[inline(always)] + pub fn store_delimited_unchecked(source: &[u8], dst: &mut [u8]) { + // Skip slot validation - trust the data + unsafe { + let dst_ptr = dst.as_mut_ptr(); + let data_len = source.len(); + + // Write the new data (minimal validation) + assert!(data_len + 2 <= dst.len()); // ensure dst buffer is large enough + *(dst_ptr as *mut u16) = data_len as u16; + sol_memcpy_(dst_ptr.add(2), source.as_ptr(), data_len as u64); + } + } + + /// Validates slot progression before writing oracle data. + /// + /// Ensures that: + /// - New slot >= existing slot in account (no regression) + /// - New slot < current clock slot (no stale data) + /// + /// # Arguments + /// * `clock_slot` - Current slot + /// * `source` - New oracle data to write + /// * `existing_data` - Current account data (may be empty) + /// + /// # Panics + /// Panics if slot validation fails + #[inline(always)] + fn validate_slot_progression(clock_slot: u64, source: &[u8], existing_data: &[u8]) { + let source_len = source.len(); + if source_len < 13 { + panic!("Invalid source data length: {}", source_len); + } + + unsafe { + // Extract slot from new data (13 bytes from end: 8 slot + 1 version + 4 SBOD) + let slot_offset = source_len - 13; + let new_slot = read_unaligned(source.as_ptr().add(slot_offset) as *const u64); + + // Validate new slot is not stale + assert!( + new_slot < clock_slot, + "SB oracle slot is stale new_slot: {}, clock.slot: {}", + new_slot, + clock_slot + ); + + // Check existing data for slot regression - always calculate from the back + if existing_data.len() >= 13 { + // Minimum data with slot + let existing_slot_offset = existing_data.len() - 13; + let existing_slot = + read_unaligned(existing_data.as_ptr().add(existing_slot_offset) as *const u64); + assert!( + new_slot >= existing_slot, + "SB oracle slot regression new_slot: {}, existing_slot: {}", + new_slot, + existing_slot + ); + } + } + } + + /// Writes ED25519 instruction data directly to an oracle account with discriminator. + /// + /// This convenience method writes oracle quote data to a target account with the + /// Switchboard Oracle discriminator prefix. The account data format becomes: + /// + /// ``` + /// [discriminator(8)][queue(32)][length(2)][message_data][oracle_signatures][recent_slot(8)][version(1)][SBOD(4)] + /// ``` + /// + /// # Arguments + /// + /// * `clock_slot` - Current slot for validation and freshness checks + /// * `source` - ED25519 instruction data containing oracle quote + /// * `oracle_account` - Target oracle account to write the data to + /// + /// # Safety + /// + /// This function assumes: + /// - Oracle account has sufficient space (at least discriminator + length + source data) + /// - Minimum 23 bytes (8 discriminator + 2 length + 13 minimum data with slot) + /// - Performs unsafe memory operations for maximum efficiency + /// + /// # Validation + /// + /// Performs comprehensive slot validation before writing: + /// - **Freshness**: new slot < clock.slot (prevents stale data) + /// - **Progression**: new slot ≥ existing slot in account (prevents replay attacks) + /// + /// # Panics + /// + /// Panics if the oracle account buffer is too small or slot validation fails. + #[inline(always)] + pub fn write(clock_slot: u64, source: &[u8], queue: &[u8; 32], oracle_account: &AccountInfo) { + let mut dst_ref = borrow_mut_account_data!(oracle_account); + let dst: &mut [u8] = &mut dst_ref; + assert!(dst.len() >= 55); // discriminator(8) + queue(32) + u16 + minimum data (13 bytes) + unsafe { + let dst_ptr = dst.as_mut_ptr(); + *(dst_ptr as *mut u64) = QUOTE_DISCRIMINATOR_U64_LE; + // Copy queue at offset 8 using 4 u64 writes + let queue_ptr = queue.as_ptr() as *const u64; + let dst_queue_ptr = dst_ptr.add(8) as *mut u64; + *dst_queue_ptr = *queue_ptr; + *dst_queue_ptr.add(1) = *queue_ptr.add(1); + *dst_queue_ptr.add(2) = *queue_ptr.add(2); + *dst_queue_ptr.add(3) = *queue_ptr.add(3); + } + Self::store_delimited(clock_slot, source, &mut dst[40..]); + } + + /// Writes ED25519 instruction data directly to an oracle account without slot validation. + /// + /// This method writes oracle quote data to a target account with the Switchboard Oracle + /// discriminator prefix but **bypasses all slot validation checks**. The account data + /// format becomes: + /// + /// ```text + /// [8 bytes discriminator][32 bytes queue][2 bytes length][N bytes ED25519 data] + /// ``` + /// + /// **USE WITH CAUTION**: This method does not validate: + /// - Slot progression against existing data + /// - Slot freshness against current clock + /// - Slot hash existence in recent slot hashes + /// + /// # Arguments + /// * `source` - Raw ED25519 instruction data to write + /// * `oracle_account` - Target oracle account to write to + /// + /// # Safety + /// This method performs minimal validation and writes directly to account memory. + /// Ensure the source data is well-formed and from a trusted source. + /// + /// # Panics + /// Panics if the oracle account buffer is too small for the data. + #[inline(always)] + pub fn write_unchecked(source: &[u8], queue: &[u8; 32], oracle_account: &AccountInfo) { + let mut dst_ref = borrow_mut_account_data!(oracle_account); + let dst: &mut [u8] = &mut dst_ref; + assert!(dst.len() >= 55); // discriminator(8) + queue(32) + u16 + minimum data (13 bytes) + unsafe { + let dst_ptr = dst.as_mut_ptr(); + *(dst_ptr as *mut u64) = QUOTE_DISCRIMINATOR_U64_LE; + // Copy queue at offset 8 using 4 u64 writes + let queue_ptr = queue.as_ptr() as *const u64; + let dst_queue_ptr = dst_ptr.add(8) as *mut u64; + *dst_queue_ptr = *queue_ptr; + *dst_queue_ptr.add(1) = *queue_ptr.add(1); + *dst_queue_ptr.add(2) = *queue_ptr.add(2); + *dst_queue_ptr.add(3) = *queue_ptr.add(3); + } + Self::store_delimited_unchecked(source, &mut dst[40..]); + } + + /// Writes oracle quote data from an ED25519 instruction to an oracle account. + /// + /// This convenience method extracts ED25519 instruction data from the instructions sysvar + /// and writes it to the target oracle account with proper validation and discriminator. + /// + /// # Arguments + /// * `ix_sysvar` - Any type that implements `AsAccountInfo` (e.g., `Sysvar`, direct `AccountInfo` reference, pinocchio AccountInfo) + /// * `oracle_account` - Any type that implements `AsAccountInfo` (e.g., `AccountLoader`, direct `AccountInfo` reference, pinocchio AccountInfo) + /// * `clock_slot` - Current slot value + /// * `instruction_index` - Index of the ED25519 instruction to extract (typically 0) + /// + /// # Example with Anchor + /// ```rust,ignore + /// use anchor_lang::prelude::*; + /// use switchboard_on_demand::OracleQuote; + /// + /// pub fn update_oracle(ctx: Context) -> Result<()> { + /// let UpdateCtx { oracle, sysvars, .. } = ctx.accounts; + /// let clock_slot = switchboard_on_demand::clock::get_slot(&sysvars.clock); + /// + /// // Works directly with Anchor wrapper types and clock slot + /// OracleQuote::write_from_ix(&sysvars.instructions, &oracle, clock_slot, 0); + /// Ok(()) + /// } + /// ``` + /// + /// # Validation + /// Performs comprehensive validation: + /// - **Program ID**: Ensures instruction is from ED25519 program + /// - **Sysvar ID**: Validates instructions sysvar account + /// - **Slot progression**: Prevents stale data and replay attacks + /// + /// # Panics + /// Panics if instruction extraction fails, program ID validation fails, or slot validation fails. + #[inline(always)] + pub fn write_from_ix<'b, I, O>( + ix_sysvar: I, + oracle_account: O, + queue: &[u8; 32], + curr_slot: u64, + instruction_index: usize, + ) where + I: AsAccountInfo<'b>, + O: AsAccountInfo<'b>, + { + let ix_sysvar = ix_sysvar.as_account_info(); + let oracle_account = oracle_account.as_account_info(); + + let data = Instructions::extract_ix_data(ix_sysvar, instruction_index); + Self::write(curr_slot, data, queue, oracle_account); + } + + /// Writes oracle quote data from an ED25519 instruction to an oracle account without slot validation. + /// + /// # ⚠️ WARNING ⚠️ + /// + /// **This method bypasses critical security validations and should only be used in very specific scenarios.** + /// + /// ## Security Risks + /// This method **DOES NOT VALIDATE**: + /// - **Slot progression**: Allows slot regression attacks + /// - **Slot freshness**: Accepts stale/outdated data + /// - **Slot hash existence**: No verification against recent slot hashes + /// - **Data integrity**: Minimal validation of instruction data + /// + /// ## Potential Attack Vectors + /// - **Replay attacks**: Old data can be replayed without detection + /// - **Time manipulation**: Attackers can use data from arbitrary past slots + /// - **Stale data injection**: Outdated oracle data may be accepted as current + /// + /// ## Safe Usage Scenarios + /// Only use this method when: + /// - You're in a trusted environment and want to skip validation for performance + /// - You're replaying historical data where slot hashes may not be available + /// - You're testing with simulated data + /// + /// # Arguments + /// * `ix_sysvar` - Any type that implements `AsAccountInfo` (e.g., `Sysvar`, direct `AccountInfo` reference, pinocchio AccountInfo) + /// * `oracle_account` - Any type that implements `AsAccountInfo` (e.g., `AccountLoader`, direct `AccountInfo` reference, pinocchio AccountInfo) + /// * `instruction_index` - Index of the ED25519 instruction to extract (typically 0) + /// + /// # Example with Anchor + /// ```rust,ignore + /// use anchor_lang::prelude::*; + /// use switchboard_on_demand::OracleQuote; + /// + /// pub fn update_oracle_unchecked(ctx: Context) -> Result<()> { + /// let UpdateCtx { oracle, sysvars, .. } = ctx.accounts; + /// + /// // Skip slot validation - trusts the slot in the instruction data + /// OracleQuote::write_from_ix_unchecked(&sysvars.instructions, &oracle, 0); + /// Ok(()) + /// } + /// ``` + /// + /// # Safety + /// + /// **EXTREME CAUTION REQUIRED**: This method: + /// - Writes directly to account memory with minimal validation + /// - Bypasses all temporal security checks + /// - Can lead to critical security vulnerabilities if misused + /// - Should never be used in production code without thorough security review + /// + /// **Requirements for safe usage**: + /// - Instruction data must be from a completely trusted source + /// - Data must be cryptographically verified externally + /// - Must implement your own replay protection mechanisms + /// - Thorough testing in isolated environments required + /// + /// # Panics + /// Panics if instruction extraction fails or if the oracle account buffer is too small. + /// + /// # Security Recommendation + /// **Strongly consider using [`write_from_ix`] instead**, which includes proper slot validation. + /// + /// [`write_from_ix`]: Self::write_from_ix + #[inline(always)] + #[allow(clippy::missing_safety_doc)] // Safety documentation is comprehensive above + pub fn write_from_ix_unchecked<'b, I, O>( + ix_sysvar: I, + oracle_account: O, + queue: &[u8; 32], + instruction_index: usize, + ) where + I: AsAccountInfo<'b>, + O: AsAccountInfo<'b>, + { + let ix_sysvar = ix_sysvar.as_account_info(); + let oracle_account = oracle_account.as_account_info(); + + let data = Instructions::extract_ix_data_unchecked(ix_sysvar, instruction_index); + Self::write_unchecked(data, queue, oracle_account); + } + + /// Derives the canonical program-derived address (PDA) for this oracle quote. + /// + /// This function computes a deterministic address based on the feed IDs contained + /// in this oracle quote. The canonical address can be used to store or reference + /// data associated with this specific combination of feeds. + /// + /// # Arguments + /// * `program_id` - The program ID to use for PDA derivation + /// + /// # Returns + /// A tuple containing: + /// * `Pubkey` - The derived program address + /// * `Vec<&[u8; 32]>` - Vector of feed ID references used as seeds + /// * `u8` - The bump seed found during PDA derivation + /// + /// # Example + /// ```rust,ignore + /// use crate::Pubkey; + /// + /// let quote = verifier.verify_instruction_at(0)?; + /// let program_id = Pubkey::new_unique(); + /// let (address, seeds, bump) = quote.canonical_address(&program_id); + /// + /// // Use the derived address for account operations + /// println!("Canonical address: {}", address); + /// println!("Used {} feed IDs as seeds", seeds.len()); + /// ``` + /// + /// # Implementation Details + /// - Uses all feed IDs from `self.feeds()` as seeds for PDA derivation + /// - Feed IDs are processed in the order they appear in the quote + /// - The resulting address is deterministic for the same set of feeds and program ID + #[inline(always)] + pub fn find_canonical_address( + &self, + queue_key: &Pubkey, + program_id: &Pubkey, + ) -> (Pubkey, Vec>, u8) { + // Stack-allocated array for up to 9 feeds + queue (common case) + let mut seed_refs: [&[u8]; 10] = [&[]; 10]; + let mut len = 0; + + // Add queue key directly as reference (no allocation) + seed_refs[len] = queue_key.as_ref(); + len += 1; + + // Add feed IDs directly as references (no allocation) + for info in self.feeds() { + if len >= 10 { + break; // Safety: prevent array overflow + } + seed_refs[len] = info.feed_id(); + len += 1; + } + + let address = Pubkey::find_program_address(&seed_refs[..len], program_id); + + // Only allocate Vec for return value compatibility (but we could optimize this API too) + let mut seeds: Vec> = Vec::with_capacity(len); + seeds.push(queue_key.to_bytes().to_vec()); + for feed_info in self.feeds() { + seeds.push(feed_info.feed_id().to_vec()); + } + + (address.0, seeds, address.1) + } + + /// Get the canonical oracle account public key for this quote's feeds. + /// + /// This is a convenience method that extracts feed IDs from the current quote + /// and derives the canonical oracle account using the provided program ID. + /// + /// # Arguments + /// * `queue_key` - The queue public key to use as the first seed + /// * `program_id` - The program ID that owns the oracle account (usually the quote program) + /// + /// # Returns + /// The canonical oracle account public key for this quote's feeds + /// + /// # Example + /// ```rust,ignore + /// let canonical_key = quote.canonical_key(&queue_key, "e_program_id); + /// ``` + #[inline(always)] + pub fn canonical_key(&self, queue_key: &Pubkey, program_id: &Pubkey) -> Pubkey { + let (canonical_key, _, _) = self.find_canonical_address(queue_key, program_id); + canonical_key + } + + #[inline(always)] + #[cfg(target_os = "solana")] + pub fn create_canonical_address( + &self, + queue_key: &Pubkey, + program_id: &Pubkey, + bump: &[u8], + ) -> Pubkey { + use crate::solana_program::syscalls; + let mut seeds: [&[u8]; 10] = [&[]; 10]; + let mut len: usize = 0; + + seeds[len] = queue_key.as_ref(); + len += 1; + + for info in self.feeds() { + seeds[len] = info.feed_id().as_ref(); + len += 1; + } + + seeds[len] = bump; + len += 1; + + let mut bytes = [0; 32]; + unsafe { + let res = syscalls::sol_create_program_address( + &seeds as *const _ as *const u8, + len as u64, + program_id as *const _ as *const u8, + &mut bytes as *mut _ as *mut u8, + ); + assert!(res == 0, "Failed to create program address"); + }; + + Pubkey::new_from_array(bytes) + } + + /// Compares the keys of this oracle quote with another oracle quote to ensure they match. + /// + /// This method validates that both oracle quotes have: + /// - The same number of feeds and feed IDs in the exact same order + /// - The same number of oracles and oracle indices in the exact same order + /// + /// This is useful for ensuring that two oracle quotes are comparable and represent + /// data from the same feeds and oracle set in the same order. + /// + /// # Arguments + /// * `other` - Another oracle quote to compare against + /// + /// # Returns + /// * `true` - If both quotes have matching feed IDs and oracle indices in the same order + /// * `false` - If there are differences in counts, feed IDs, or oracle indices + /// + /// # Example + /// ```rust,ignore + /// let quote1 = verifier.verify_instruction_at(0)?; + /// let quote2 = verifier.verify_instruction_at(1)?; + /// + /// if quote1.keys_match("e2) { + /// println!("Quotes have matching keys - safe to compare"); + /// } else { + /// println!("Quotes have different keys - comparison may not be meaningful"); + /// } + /// ``` + #[inline(always)] + pub fn keys_match(&self, other: &OracleQuote) -> bool { + // Compare counts first for early exit + if self.feed_count != other.feed_count { + return false; + } + + // Compare feed IDs in order (avoiding method calls) + let feed_count = self.feed_count as usize; + for i in 0..feed_count { + if !check_pubkey_eq( + self.packed_feed_infos[i].feed_id(), + other.packed_feed_infos[i].feed_id(), + ) { + return false; + } + } + + true + } +} diff --git a/programs/switchboard-on-demand/src/on_demand/oracle_quote/quote_account.rs b/programs/switchboard-on-demand/src/on_demand/oracle_quote/quote_account.rs new file mode 100644 index 0000000000..caafd9c601 --- /dev/null +++ b/programs/switchboard-on-demand/src/on_demand/oracle_quote/quote_account.rs @@ -0,0 +1,277 @@ +pub const QUOTE_DISCRIMINATOR: &[u8; 8] = b"SBOracle"; + +#[macro_export] +macro_rules! switchboard_anchor_bindings { + () => { + pub const __QUOTE_OWNER_PIDS: &[Pubkey] = &[ + switchboard_on_demand::QUOTE_PROGRAM_ID, + crate::ID, + ]; + + /// Macro to generate Anchor bindings for Switchboard quote accounts + #[derive(Debug, PartialEq, Eq, Clone, Copy, AnchorDeserialize, AnchorSerialize)] + #[repr(C)] + pub struct SwitchboardQuote { + pub queue: [u8; 32], + pub data: [u8; 1024], + } + + unsafe impl bytemuck::Pod for SwitchboardQuote {} + unsafe impl bytemuck::Zeroable for SwitchboardQuote {} + + impl Discriminator for SwitchboardQuote { + const DISCRIMINATOR: &[u8] = switchboard_on_demand::quote_account::QUOTE_DISCRIMINATOR; + } + + impl AccountSerialize for SwitchboardQuote { + fn try_serialize(&self, writer: &mut W) -> anchor_lang::Result<()> { + writer.write_all(Self::DISCRIMINATOR)?; + writer.write_all(bytemuck::bytes_of(self))?; + Ok(()) + } + } + + impl AccountDeserialize for SwitchboardQuote { + fn try_deserialize(buf: &mut &[u8]) -> anchor_lang::Result { + if buf.len() < Self::DISCRIMINATOR.len() { + return Err(anchor_lang::error::ErrorCode::AccountDiscriminatorNotFound.into()); + } + let given_disc = &buf[..Self::DISCRIMINATOR.len()]; + if given_disc != Self::DISCRIMINATOR { + return Err(anchor_lang::error::ErrorCode::AccountDiscriminatorMismatch.into()); + } + *buf = &buf[Self::DISCRIMINATOR.len()..]; + Self::try_deserialize_unchecked(buf) + } + + fn try_deserialize_unchecked(buf: &mut &[u8]) -> anchor_lang::Result { + if buf.len() < std::mem::size_of::() { + return Err(anchor_lang::error::ErrorCode::AccountDidNotSerialize.into()); + } + let data = bytemuck::try_from_bytes(&buf[..std::mem::size_of::()]) + .map_err(|_| anchor_lang::error::ErrorCode::AccountDidNotDeserialize)?; + *buf = &buf[std::mem::size_of::()..]; + Ok(*data) + } + } + + impl SwitchboardQuote { + pub const LEN: usize = 32 + 1024 + 8; + + /// Extracts feed information from the oracle quote data + /// + /// Parses the stored oracle quote data and returns a slice of PackedFeedInfo + /// structures containing feed IDs, values, and minimum oracle samples. + /// + /// # Returns + /// A slice of PackedFeedInfo structures, or an empty slice if no valid feeds are found + /// + /// # Example + /// ```rust + /// let feeds = quote.feeds(); + /// for feed in feeds { + /// println!("Feed {}: {}", feed.hex_id(), feed.value()); + /// } + /// ``` + pub fn feeds(&self) -> &[switchboard_on_demand::on_demand::oracle_quote::feed_info::PackedFeedInfo] { + use core::ptr::read_unaligned; + + // Check if we have enough data for length prefix + if self.data.len() < 2 { + return &[]; + } + + unsafe { + // Read the length prefix (first 2 bytes) + let data_len = read_unaligned(self.data.as_ptr() as *const u16) as usize; + + // Ensure we have enough data + if self.data.len() < data_len + 2 || data_len < 13 { + return &[]; + } + + // Skip the length prefix and parse the ED25519 instruction data + let instruction_data = &self.data[2..data_len + 2]; + + // Parse the instruction to extract feed information + match switchboard_on_demand::sysvar::ed25519_sysvar::Ed25519Sysvar::parse_instruction(instruction_data) + { + Ok((parsed_sigs, sig_count, _, _, _)) => { + if sig_count > 0 { + // Get feed info from the first signature + parsed_sigs[0].feed_infos() + } else { + &[] + } + } + Err(_) => &[], + } + } + } + + /// Get the canonical oracle account public key for the given feed IDs + /// + /// This method derives the canonical oracle account that the quote program + /// creates and manages for storing verified oracle data. + /// + /// ## Parameters + /// - `feed_ids`: Array of feed ID byte arrays (32 bytes each) + /// - `program_id`: The quote program ID to use for derivation + /// + /// ## Returns + /// The canonical oracle account public key + /// + /// ## Example + /// ```rust + /// let oracle_key = SwitchboardQuote::get_canonical_key(&queue_key, &[feed_id_bytes], "e_program_id); + /// ``` + pub fn get_canonical_key(queue_key: &Pubkey, feed_ids: &[&[u8; 32]], program_id: &Pubkey) -> Pubkey { + let mut seeds: Vec<&[u8]> = Vec::with_capacity(feed_ids.len() + 1); + seeds.push(queue_key.as_ref()); + for id in feed_ids { + seeds.push(id.as_slice()); + } + let (oracle_account, _) = Pubkey::find_program_address(&seeds, program_id); + oracle_account + } + + /// Get the canonical oracle account for this quote's feeds + /// + /// Convenience method that extracts feed IDs from the current quote + /// and derives the canonical oracle account using the provided owner. + /// + /// ## Parameters + /// - `queue_key`: The queue public key to use as the first seed + /// - `owner`: The program ID that owns this oracle account (usually the quote program) + /// + /// ## Returns + /// The canonical oracle account public key for this quote's feeds + /// + /// ## Example + /// ```rust + /// let canonical_key = quote.canonical_key(&queue_key, &oracle_account.owner); + /// ``` + pub fn canonical_key(&self, queue_key: &Pubkey, owner: &Pubkey) -> Pubkey { + let feed_ids: Vec<&[u8; 32]> = self.feeds().iter().map(|feed| feed.feed_id()).collect(); + Self::get_canonical_key(queue_key, &feed_ids, owner) + } + } + + impl anchor_lang::Owner for SwitchboardQuote { + fn owner() -> anchor_lang::solana_program::pubkey::Pubkey { + crate::ID + } + } + + impl anchor_lang::ZeroCopy for SwitchboardQuote {} + + impl anchor_lang::Owners for SwitchboardQuote { + fn owners() -> &'static [anchor_lang::solana_program::pubkey::Pubkey] { + __QUOTE_OWNER_PIDS + } + } + + /// Extension trait to provide convenient methods for Anchor InterfaceAccount + pub trait SwitchboardQuoteExt<'a> { + /// Get the canonical oracle account key for this quote's feeds + fn canonical_key(&self, queue: &Pubkey) -> Pubkey; + // + // /// Get the canonical oracle account key for this quote's feeds with a specific owner + // fn canonical_key_with_owner(&self, owner: &Pubkey) -> Pubkey; + + /// Get the owner of the account + fn owner(&self) -> &Pubkey; + + /// Get feeds from the oracle quote + fn feeds(&self) -> &[switchboard_on_demand::on_demand::oracle_quote::feed_info::PackedFeedInfo]; + + /// Write oracle quote data from an ED25519 instruction with slot validation + fn write_from_ix<'b, I>(&mut self, ix_sysvar: I, curr_slot: u64, instruction_index: usize) + where + I: AsRef>; + + /// Write oracle quote data from an ED25519 instruction without slot validation. + /// + /// # ⚠️ WARNING ⚠️ + /// **This method bypasses critical security validations. See [`OracleQuote::write_from_ix_unchecked`] for detailed security warnings.** + /// + /// [`OracleQuote::write_from_ix_unchecked`]: crate::on_demand::oracle_quote::OracleQuote::write_from_ix_unchecked + fn write_from_ix_unchecked<'b, I>(&mut self, ix_sysvar: I, instruction_index: usize) + where + I: AsRef>; + + /// Check if the account is initialized by checking the last 4 bytes are SBOD + fn is_initialized(&self) -> bool; + + /// if !is_initialized, return if the new quotes canonical key matches the account key + /// else just check if the account key match the new quotes + fn keys_match(&self, quote: &switchboard_on_demand::on_demand::oracle_quote::OracleQuote) -> bool; + } + + impl<'info> SwitchboardQuoteExt<'info> + for anchor_lang::prelude::InterfaceAccount<'info, SwitchboardQuote> + { + fn canonical_key(&self, queue: &Pubkey) -> Pubkey { + (**self).canonical_key(queue, self.to_account_info().owner) + } + + fn owner(&self) -> &Pubkey { + self.to_account_info().owner + } + + fn feeds(&self) -> &[switchboard_on_demand::on_demand::oracle_quote::feed_info::PackedFeedInfo] { + (**self).feeds() + } + + fn write_from_ix<'b, I>(&mut self, ix_sysvar: I, curr_slot: u64, instruction_index: usize) + where + I: AsRef>, + { + let ix_sysvar = ix_sysvar.as_ref(); + let data = switchboard_on_demand::Instructions::extract_ix_data(ix_sysvar, instruction_index); + switchboard_on_demand::on_demand::oracle_quote::OracleQuote::write(curr_slot, data, &self.queue, &self.to_account_info()); + } + + fn write_from_ix_unchecked<'b, I>(&mut self, ix_sysvar: I, instruction_index: usize) + where + I: AsRef>, + { + let ix_sysvar = ix_sysvar.as_ref(); + let data = switchboard_on_demand::Instructions::extract_ix_data(ix_sysvar, instruction_index); + switchboard_on_demand::on_demand::oracle_quote::OracleQuote::write_unchecked(data, &self.queue, &self.to_account_info()); + } + + fn is_initialized(&self) -> bool { + static tail_discriminator: u32 = u32::from_le_bytes(*b"SBOD"); + let account_info = self.to_account_info(); + let data = account_info.data.borrow(); + if data.len() < 4 { + return false; + } + if let Ok(last_four) = data[data.len() - 4..].try_into() { + let marker = u32::from_le_bytes(last_four); + marker == tail_discriminator + } else { + false + } + } + + fn keys_match(&self, quote: &switchboard_on_demand::on_demand::oracle_quote::OracleQuote) -> bool { + if !self.is_initialized() { + return false; + } + let own_feeds = self.feeds(); + let other_feeds = quote.feeds(); + if own_feeds.len() != other_feeds.len() { + return false; + } + for i in 0..own_feeds.len() { + if !switchboard_on_demand::check_pubkey_eq(own_feeds[i].feed_id(), other_feeds[i].feed_id()) { + return false; + } + } + true + } + } + }; +} diff --git a/programs/switchboard-on-demand/src/on_demand/oracle_quote/quote_verifier.rs b/programs/switchboard-on-demand/src/on_demand/oracle_quote/quote_verifier.rs new file mode 100644 index 0000000000..5ef0e92f48 --- /dev/null +++ b/programs/switchboard-on-demand/src/on_demand/oracle_quote/quote_verifier.rs @@ -0,0 +1,1302 @@ +//! Oracle quote verification for creating and verifying oracle data quotes +//! +//! This module provides the `QuoteVerifier` which allows you to construct +//! a verifier with specific accounts and parameters, then use it to verify ED25519 +//! instruction data and create validated `OracleQuote` instances. +//! +//! The verification process checks: +//! - ED25519 signature validity +//! - Oracle signing key authorization +//! - Slot hash verification against the sysvar +//! - Quote age validation against max_age parameter (requires clock sysvar) +//! - Oracle quote data integrity +//! +//! For debugging or analysis purposes, the verifier also provides `parse_unverified` methods +//! that extract quote structure without performing security validations. + +use core::ptr::read_unaligned; + +use anyhow::{bail, Error as AnyError}; +// Conditional import for non-pinocchio builds +#[cfg(not(feature = "pinocchio"))] +use solana_program::sysvar::instructions::get_instruction_relative; + +use crate::prelude::*; +// Use our AccountInfo type alias that conditionally uses pinocchio or anchor/solana-program +use crate::AccountInfo; +use crate::{ + borrow_account_data, check_p64_eq, check_pubkey_eq, get_account_key, solana_program, + AsAccountInfo, +}; +#[allow(unused_imports)] +use crate::{ON_DEMAND_DEVNET_PID, ON_DEMAND_MAINNET_PID}; + +/// Maximum number of slots stored in the slot hash sysvar +const SYSVAR_SLOT_LEN: u64 = 512; + +/// Oracle quote verifier with builder pattern for configuring and performing verification. +/// +/// This verifier allows you to configure the required accounts step by step before +/// using it to verify oracle quotes. All required accounts must be set before +/// verification can be performed. +/// +/// The verifier accepts any type that implements `AsAccountInfo`, making it compatible +/// with Anchor wrapper types like `AccountLoader`, `Sysvar`, etc., as well as pinocchio AccountInfo. +/// +/// # Example with Anchor Context +/// ```rust,ignore +/// use anchor_lang::prelude::*; +/// use switchboard_on_demand::QuoteVerifier; +/// +/// pub fn verify(ctx: Context) -> Result<()> { +/// let VerifyCtx { queue, oracle, sysvars, .. } = ctx.accounts; +/// let clock_slot = switchboard_on_demand::clock::get_slot(&sysvars.clock); +/// +/// let quote = QuoteVerifier::new() +/// .queue(&queue) +/// .slothash_sysvar(&sysvars.slothashes) +/// .ix_sysvar(&sysvars.instructions) +/// .clock_slot(clock_slot) +/// .verify_account(&oracle) +/// .unwrap(); +/// +/// // Use the verified quote data +/// for feed in quote.feeds() { +/// msg!("Feed {}: {}", feed.hex_id(), feed.value()); +/// } +/// Ok(()) +/// } +/// ``` +#[derive(Clone)] +#[cfg(feature = "pinocchio")] +pub struct QuoteVerifier<'a> { + queue: Option<&'a AccountInfo>, + slothash_sysvar: Option<&'a AccountInfo>, + ix_sysvar: Option<&'a AccountInfo>, + clock_slot: Option, + max_age: u64, +} + +#[derive(Clone)] +#[cfg(not(feature = "pinocchio"))] +pub struct QuoteVerifier<'a> { + queue: Option>, + slothash_sysvar: Option>, + ix_sysvar: Option>, + clock_slot: Option, + max_age: u64, +} + +#[cfg(feature = "pinocchio")] +impl<'a> Default for QuoteVerifier<'a> { + fn default() -> Self { + Self::new() + } +} + +#[cfg(not(feature = "pinocchio"))] +impl<'a> Default for QuoteVerifier<'a> { + fn default() -> Self { + Self::new() + } +} + +#[cfg(feature = "pinocchio")] +impl<'a> QuoteVerifier<'a> { + /// Creates a new `QuoteVerifier` with default values. + #[inline(always)] + pub fn new() -> Self { + Self { + queue: None, + slothash_sysvar: None, + ix_sysvar: None, + clock_slot: None, + max_age: 30, + } + } + + /// Sets the oracle queue account for verification. + /// + /// The queue account contains the authorized oracle signing keys that will + /// be used to validate the signatures in the oracle quote. + /// + /// # Arguments + /// * `account` - Any type that implements `AsAccountInfo` (e.g., `AccountLoader`, direct `AccountInfo` reference, pinocchio AccountInfo) + /// + /// # Example + /// ```rust,ignore + /// verifier.queue(&ctx.accounts.queue); // Works with Anchor AccountLoader + /// verifier.queue(&account_info); // Works with AccountInfo reference + /// verifier.queue(&pinocchio_account); // Works with pinocchio AccountInfo + /// ``` + #[inline(always)] + pub fn queue(&mut self, account: &'a AccountInfo) -> &mut Self { + self.queue = Some(account); + self + } + + /// Sets the slot hash sysvar account for verification. + /// + /// The slot hash sysvar is used to validate that the signed slot hash + /// in the oracle quote corresponds to a valid historical slot. + /// + /// # Arguments + /// * `sysvar` - Any type that implements `AsAccountInfo` (e.g., `Sysvar`, direct `AccountInfo` reference, pinocchio AccountInfo) + /// + /// # Example + /// ```rust,ignore + /// verifier.slothash_sysvar(&ctx.accounts.slothashes); // Works with Anchor Sysvar + /// verifier.slothash_sysvar(&slothash_account); // Works with AccountInfo reference + /// verifier.slothash_sysvar(&pinocchio_account); // Works with pinocchio AccountInfo + /// ``` + #[inline(always)] + pub fn slothash_sysvar(&mut self, sysvar: &'a AccountInfo) -> &mut Self { + self.slothash_sysvar = Some(sysvar); + self + } + + /// Sets the instructions sysvar account for verification. + /// + /// The instructions sysvar contains the ED25519 instruction data that + /// will be parsed to extract the oracle signatures and quote data. + /// + /// # Arguments + /// * `sysvar` - Any type that implements `AsAccountInfo` (e.g., `Sysvar`, direct `AccountInfo` reference, pinocchio AccountInfo) + /// + /// # Example + /// ```rust,ignore + /// verifier.ix_sysvar(&ctx.accounts.instructions); // Works with Anchor Sysvar + /// verifier.ix_sysvar(&ix_account); // Works with AccountInfo reference + /// verifier.ix_sysvar(&pinocchio_account); // Works with pinocchio AccountInfo + /// ``` + #[inline(always)] + pub fn ix_sysvar(&mut self, sysvar: &'a AccountInfo) -> &mut Self { + self.ix_sysvar = Some(sysvar); + self + } + + /// Sets the clock slot for freshness validation. + #[inline(always)] + pub fn clock_slot(&mut self, clock_slot: u64) -> &mut Self { + self.clock_slot = Some(clock_slot); + self + } + + /// Sets the maximum age in slots for oracle quote freshness validation. + /// + /// Oracle quotes older than this many slots will be rejected during verification. + /// This helps prevent replay attacks and ensures data freshness. + /// + /// # Arguments + /// * `max_age` - Maximum age in slots (typically 100-500 slots) + #[inline(always)] + pub fn max_age(&mut self, max_age: u64) -> &mut Self { + self.max_age = max_age; + self + } + + /// Verifies an oracle account containing oracle quote data. + /// + /// This method extracts the oracle quote data from an oracle account (skipping the + /// 8-byte discriminator) and verifies it using the configured accounts. + /// + /// # Arguments + /// * `oracle_account` - Any type that implements `AsAccountInfo` containing the oracle quote data + /// (e.g., `AccountLoader`, direct `AccountInfo` reference, pinocchio AccountInfo) + /// + /// # Returns + /// * `Ok(OracleQuote)` - Successfully verified oracle quote with feed data + /// * `Err(AnyError)` - Verification failed (invalid signatures, expired data, etc.) + /// + /// # Example + /// ```rust,ignore + /// let quote = verifier.verify_account(&ctx.accounts.oracle)?; + /// for feed in quote.feeds() { + /// println!("Feed {}: ${}", feed.hex_id(), feed.value()); + /// } + /// ``` + #[cfg(feature = "pinocchio")] + #[inline(always)] + pub fn verify_account<'data, T>( + &self, + oracle_account: &'data T, + ) -> Result, AnyError> + where + T: AsAccountInfo<'data>, + { + let account_info = oracle_account.as_account_info(); + + let oracle_data = unsafe { account_info.borrow_data_unchecked() }; + + if oracle_data.len() < 40 { + bail!( + "Oracle account too small: {} bytes, expected at least 40", + oracle_data.len() + ); + } + + unsafe { + if read_unaligned(oracle_data.as_ptr() as *const u64) != QUOTE_DISCRIMINATOR_U64_LE { + bail!("Invalid oracle account discriminator"); + } + } + + self.verify_delimited(&oracle_data[40..]) + } + + #[cfg(not(feature = "pinocchio"))] + #[inline(always)] + pub fn verify_account<'data, T>( + &self, + oracle_account: &'data T, + ) -> Result, AnyError> + where + T: AsAccountInfo<'data>, + { + let account_info = oracle_account.as_account_info(); + + let oracle_data = unsafe { &*account_info.data.as_ptr() }; + + if oracle_data.len() < 40 { + bail!( + "Oracle account too small: {} bytes, expected at least 40", + oracle_data.len() + ); + } + + unsafe { + if read_unaligned(oracle_data.as_ptr() as *const u64) != QUOTE_DISCRIMINATOR_U64_LE { + bail!("Invalid oracle account discriminator"); + } + } + + self.verify_delimited(&oracle_data[40..]) + } + + /// Verifies raw ED25519 instruction data and creates a validated OracleQuote. + /// + /// This is the core verification method that performs all security checks: + /// - Parses ED25519 signatures and extracts oracle indices + /// - Validates oracle signing keys against the queue + /// - Verifies slot hash against the sysvar + /// - Validates quote age against max_age (requires clock sysvar) + /// - Ensures oracle quote data integrity + /// + /// # Arguments + /// * `data` - Raw ED25519 instruction data containing signatures and quote + /// + /// # Returns + /// * `Ok(OracleQuote)` - Successfully verified and parsed oracle quote + /// * `Err(AnyError)` - Verification failed with detailed error message + /// + /// # Errors + /// - Clock slot not set + /// - No signatures provided + /// - Invalid oracle signing keys + /// - Slot hash mismatch + /// - Quote is too old (exceeds max_age slots) + /// - Malformed instruction data + #[inline(always)] + pub fn verify_delimited<'data>( + &self, + data: &'data [u8], + ) -> Result, AnyError> { + // # Safety + // + // This unsafe block is safe because: + // - We verify `data` has at least 2 bytes before reading the length + // - `read_unaligned` safely reads u16 from potentially unaligned memory + // - The bounds check ensures we don't read beyond the data buffer + // - Data slice is guaranteed valid for the function duration + if data.len() < 2 { + bail!("Data too small for length prefix: {} bytes", data.len()); + } + unsafe { + let len = read_unaligned(data.as_ptr() as *const u16) as usize; + if data.len() < len + 2 { + bail!( + "Data length mismatch: expected {}, got {}", + len + 2, + data.len() + ); + } + self.verify(&data[2..len + 2]) + } + } + + /// Parses oracle quote data without performing any verification checks. + /// + /// This method extracts the quote structure from ED25519 instruction data + /// but skips all security validations including: + /// - Clock/age validation + /// - Signature verification + /// - Oracle key authorization + /// - Slot hash verification + /// + /// **WARNING**: This method should only be used for debugging, analysis, or + /// scenarios where verification is handled separately. Never use unverified + /// quotes for production decisions. + /// + /// # Arguments + /// * `data` - Raw ED25519 instruction data containing signatures and quote + /// + /// # Returns + /// * `Ok(OracleQuote)` - Successfully parsed oracle quote (unverified) + /// * `Err(AnyError)` - Failed to parse the quote data structure + /// + /// # Example + /// ```rust,ignore + /// // Parse quote without verification (use cautiously) + /// let unverified_quote = verifier.parse_unverified(&instruction_data)?; + /// println!("Quote contains {} feeds", unverified_quote.feeds().len()); + /// ``` + #[inline(always)] + pub fn parse_unverified<'data>( + &self, + data: &'data [u8], + ) -> Result, AnyError> { + let (parsed_sigs, sig_count, oracle_idxs, recent_slot, version) = + Ed25519Sysvar::parse_instruction(data)?; + + if sig_count == 0 { + bail!("No signatures provided"); + } + + let reference_sig = &parsed_sigs[0]; + let reference_feed_infos = unsafe { reference_sig.feed_infos() }; + let feed_count = reference_feed_infos.len(); + + Ok(OracleQuote::new( + unsafe { reference_sig.quote_header() }, + sig_count, + reference_feed_infos, + feed_count as u8, + oracle_idxs, + recent_slot, + version, + data, + )) + } + + /// Parses oracle quote data from an account without performing verification checks. + /// + /// This is a convenience method that extracts quote data from a Switchboard + /// oracle account and parses it without any security validations. + /// + /// **WARNING**: This method should only be used for debugging, analysis, or + /// scenarios where verification is handled separately. Never use unverified + /// quotes for production decisions. + /// + /// # Arguments + /// * `oracle_account` - Oracle account containing quote data + /// + /// # Returns + /// * `Ok(OracleQuote)` - Successfully parsed oracle quote (unverified) + /// * `Err(AnyError)` - Failed to parse the account or quote data + /// + /// # Example + /// ```rust,ignore + /// // Parse account quote without verification (use cautiously) + /// let unverified_quote = verifier.parse_account_unverified(&oracle_account)?; + /// ``` + #[cfg(feature = "pinocchio")] + #[inline(always)] + pub fn parse_account_unverified<'data, T>( + &self, + oracle_account: &'data T, + ) -> Result, AnyError> + where + T: AsAccountInfo<'data>, + { + let account_info = oracle_account.as_account_info(); + + let oracle_data = unsafe { account_info.borrow_data_unchecked() }; + + if oracle_data.len() < 40 { + bail!( + "Oracle account too small: {} bytes, expected at least 40", + oracle_data.len() + ); + } + + self.parse_unverified_delimited(&oracle_data[40..]) + } + + #[cfg(not(feature = "pinocchio"))] + #[inline(always)] + pub fn parse_account_unverified<'data, T>( + &self, + oracle_account: &'data T, + ) -> Result, AnyError> + where + T: AsAccountInfo<'data>, + { + let account_info = oracle_account.as_account_info(); + + let oracle_data = unsafe { &*account_info.data.as_ptr() }; + + if oracle_data.len() < 40 { + bail!( + "Oracle account too small: {} bytes, expected at least 40", + oracle_data.len() + ); + } + + self.parse_unverified_delimited(&oracle_data[40..]) + } + + /// Parses length-delimited oracle quote data without verification checks. + /// + /// This method handles the length prefix parsing and delegates to `parse_unverified`. + /// + /// # Arguments + /// * `data` - Length-delimited ED25519 instruction data + /// + /// # Returns + /// * `Ok(OracleQuote)` - Successfully parsed oracle quote (unverified) + /// * `Err(AnyError)` - Failed to parse the data + #[inline(always)] + pub fn parse_unverified_delimited<'data>( + &self, + data: &'data [u8], + ) -> Result, AnyError> { + if data.len() < 2 { + bail!("Data too small for length prefix: {} bytes", data.len()); + } + unsafe { + let len = read_unaligned(data.as_ptr() as *const u16) as usize; + if data.len() < len + 2 { + bail!( + "Data length mismatch: expected {}, got {}", + len + 2, + data.len() + ); + } + self.parse_unverified(&data[2..len + 2]) + } + } + + /// Verifies oracle quote data and returns a validated OracleQuote + pub fn verify<'data>(&self, data: &'data [u8]) -> Result, AnyError> { + let (parsed_sigs, sig_count, oracle_idxs, recent_slot, version) = + Ed25519Sysvar::parse_instruction(data)?; + let queue = self + .queue + .as_ref() + .ok_or_else(|| anyhow::anyhow!("Queue account not set"))?; + let slothash_sysvar = self + .slothash_sysvar + .as_ref() + .ok_or_else(|| anyhow::anyhow!("Slothash sysvar not set"))?; + + // Validate quote freshness - clock slot is required for all verifications + let clock_slot = self + .clock_slot + .ok_or_else(|| anyhow::anyhow!("Clock slot not set"))?; + if clock_slot < recent_slot || clock_slot - recent_slot > self.max_age { + bail!( + "Quote is too old: recent_slot={}, current_slot={}, max_age={}", + recent_slot, + clock_slot, + self.max_age + ); + } + + if sig_count == 0 { + bail!("No signatures provided"); + } + + // Get queue data for oracle signing keys + // Safely access queue data using RefCell borrow and try_from_bytes + let queue_buf = unsafe { borrow_account_data!(queue) }; + if queue_buf.len() != 6280 { + bail!("Queue account too small: {} bytes", queue_buf.len()); + } + let queue_data: &QueueAccountData = + unsafe { &*(queue_buf.as_ptr().add(8) as *const QueueAccountData) }; + + // Find the target slothash from the oracle quote + let reference_sig = &parsed_sigs[0]; + let header = unsafe { reference_sig.quote_header() }; + + // Find the target slothash from oracle quote and get corresponding hash from sysvar + let target_slothash = &header.signed_slothash as *const _ as *const u64; + let found_slothash = + &Self::find_slothash_in_sysvar(recent_slot, slothash_sysvar)? as *const _ as *const u64; + + assert!(unsafe { check_p64_eq(found_slothash, target_slothash) }); + + // Oracle signing key validation (32 bytes per oracle: actual should match expected) + for i in 0..sig_count { + // Branchless bounds check, 30 is max oracles in queue + let oracle_idx = (oracle_idxs[i as usize] as usize) % 30; + let expected_oracle_key = queue_data.ed25519_oracle_signing_keys[oracle_idx]; + let actual_oracle_key = unsafe { parsed_sigs[i as usize].pubkey() }; + assert!(unsafe { + check_p64_eq( + actual_oracle_key as *const _ as *const u64, + &expected_oracle_key as *const _ as *const u64, + ) + }); + } + + // Continue with remaining processing... + let reference_feed_infos = unsafe { reference_sig.feed_infos() }; + let feed_count = reference_feed_infos.len(); + + Ok(OracleQuote::new( + unsafe { reference_sig.quote_header() }, + sig_count, + reference_feed_infos, + feed_count as u8, + oracle_idxs, + recent_slot, + version, + data, + )) + } + + /// Loads and verifies an ED25519 instruction from the instructions sysvar with age validation. + /// + /// This method extracts instruction data from the instructions sysvar at the specified + /// index, validates that it comes from the ED25519 program, checks the quote age against + /// the current slot using the configured max_age, and then verifies the oracle quote data. + /// + /// # Arguments + /// * `instruction_idx` - Index of the instruction to load from the sysvar (typically 0 for first instruction) + /// + /// # Returns + /// * `Ok(OracleQuote)` - Successfully loaded and verified oracle quote + /// * `Err(AnyError)` - Failed to load or verify the instruction + /// + /// # Errors + /// - Instruction not found at the specified index + /// - Instruction is not from the ED25519 program + /// - Quote is too old (exceeds max_age slots) + /// - Verification of the quote data fails + #[inline(always)] + pub fn verify_instruction_at(&self, instruction_idx: i64) -> Result, AnyError> { + use crate::Instructions; + + let ix_sysvar = self + .ix_sysvar + .as_ref() + .ok_or_else(|| anyhow::anyhow!("Instructions sysvar not set"))?; + + // Extract instruction data and validate program ID using the existing helper + let data = { + #[cfg(feature = "pinocchio")] + { + Instructions::extract_ix_data(*ix_sysvar, instruction_idx as usize) + } + #[cfg(not(feature = "pinocchio"))] + { + Instructions::extract_ix_data(ix_sysvar, instruction_idx as usize) + } + }; + + // Verify the instruction data + self.verify(data) + } + + /// Finds and returns a specific slot hash from the slot hash sysvar. + /// + /// This function searches through the slot hash sysvar to find the hash + /// corresponding to the target slot. It uses an optimized search starting + /// from an estimated position and working backwards. + /// + /// # Arguments + /// * `target_slot` - The slot number to find the hash for + /// * `slothash_sysvar` - Reference to the slot hash sysvar account + /// + /// # Returns + /// * `Ok([u8; 32])` - The 32-byte hash for the target slot + /// * `Err(AnyError)` - Slot not found in the sysvar + /// + /// # Performance + /// Uses an estimated starting position based on slot ordering to minimize + /// the number of entries that need to be checked. + fn find_slothash_in_sysvar( + target_slot: u64, + slothash_sysvar: &AccountInfo, + ) -> Result<[u8; 32], AnyError> { + assert!(check_pubkey_eq( + *get_account_key!(slothash_sysvar), + solana_program::sysvar::slot_hashes::ID + )); + let slothash_data = unsafe { borrow_account_data!(slothash_sysvar) }; + + // # Safety + // + // This transmute is safe because: + // - SlotHash is a POD type with known layout (u64 + [u8; 32]) + // - We skip the 8-byte sysvar header before transmuting + // - The Solana runtime guarantees proper alignment and initialization of sysvar data + // - The slice length is determined by the actual data size + let slot_data: &[SlotHash] = unsafe { std::mem::transmute(&slothash_data[8..]) }; + + let mut estimated_idx = ((slot_data[0].slot - target_slot) % SYSVAR_SLOT_LEN) as usize; + + // Optimized search with early termination + loop { + let slot_entry = &slot_data[estimated_idx]; + if slot_entry.slot == target_slot { + return Ok(slot_entry.hash); + } + if estimated_idx == 0 { + break; + } + estimated_idx -= 1; + } + bail!("Slot not found in slothash sysvar"); + } +} + +#[cfg(not(feature = "pinocchio"))] +impl<'a> QuoteVerifier<'a> { + /// Creates a new `QuoteVerifier` with default values. + #[inline(always)] + pub fn new() -> Self { + Self { + queue: None, + slothash_sysvar: None, + ix_sysvar: None, + clock_slot: None, + max_age: 30, + } + } + + /// Sets the oracle queue account for verification. + /// + /// The queue account contains the authorized oracle signing keys that will + /// be used to validate the signatures in the oracle quote. + /// + /// # Arguments + /// * `account` - Any type that implements `AsAccountInfo` (e.g., `AccountLoader`, direct `AccountInfo` reference, pinocchio AccountInfo) + /// + /// # Example + /// ```rust,ignore + /// verifier.queue(&ctx.accounts.queue); // Works with Anchor AccountLoader + /// verifier.queue(&account_info); // Works with AccountInfo reference + /// verifier.queue(&pinocchio_account); // Works with pinocchio AccountInfo + /// ``` + #[inline(always)] + pub fn queue(&mut self, account: T) -> &mut Self + where + T: AsAccountInfo<'a>, + { + self.queue = Some(account.as_account_info().clone()); + self + } + + /// Sets the slot hash sysvar account for verification. + /// + /// The slot hash sysvar is used to validate that the signed slot hash + /// in the oracle quote corresponds to a valid historical slot. + /// + /// # Arguments + /// * `sysvar` - Any type that implements `AsAccountInfo` (e.g., `Sysvar`, direct `AccountInfo` reference, pinocchio AccountInfo) + /// + /// # Example + /// ```rust,ignore + /// verifier.slothash_sysvar(&ctx.accounts.slothashes); // Works with Anchor Sysvar + /// verifier.slothash_sysvar(&slothash_account); // Works with AccountInfo reference + /// verifier.slothash_sysvar(&pinocchio_account); // Works with pinocchio AccountInfo + /// ``` + #[inline(always)] + pub fn slothash_sysvar(&mut self, sysvar: T) -> &mut Self + where + T: AsAccountInfo<'a>, + { + self.slothash_sysvar = Some(sysvar.as_account_info().clone()); + self + } + + /// Sets the instructions sysvar account for verification. + /// + /// The instructions sysvar contains the ED25519 instruction data that + /// will be parsed to extract the oracle signatures and quote data. + /// + /// # Arguments + /// * `sysvar` - Any type that implements `AsAccountInfo` (e.g., `Sysvar`, direct `AccountInfo` reference, pinocchio AccountInfo) + /// + /// # Example + /// ```rust,ignore + /// verifier.ix_sysvar(&ctx.accounts.instructions); // Works with Anchor Sysvar + /// verifier.ix_sysvar(&ix_account); // Works with AccountInfo reference + /// verifier.ix_sysvar(&pinocchio_account); // Works with pinocchio AccountInfo + /// ``` + #[inline(always)] + pub fn ix_sysvar(&mut self, sysvar: T) -> &mut Self + where + T: AsAccountInfo<'a>, + { + self.ix_sysvar = Some(sysvar.as_account_info().clone()); + self + } + + /// Sets the clock slot for freshness validation. + #[inline(always)] + pub fn clock_slot(&mut self, clock_slot: u64) -> &mut Self { + self.clock_slot = Some(clock_slot); + self + } + + /// Sets the maximum age in slots for oracle quote freshness validation. + /// + /// Oracle quotes older than this many slots will be rejected during verification. + /// This helps prevent replay attacks and ensures data freshness. + /// + /// # Arguments + /// * `max_age` - Maximum age in slots (typically 100-500 slots) + #[inline(always)] + pub fn max_age(&mut self, max_age: u64) -> &mut Self { + self.max_age = max_age; + self + } + + /// Verifies an oracle account containing oracle quote data. + /// + /// This method extracts the oracle quote data from an oracle account (skipping the + /// 8-byte discriminator) and verifies it using the configured accounts. + /// + /// # Arguments + /// * `oracle_account` - Any type that implements `AsAccountInfo` containing the oracle quote data + /// (e.g., `AccountLoader`, direct `AccountInfo` reference, pinocchio AccountInfo) + /// + /// # Returns + /// * `Ok(OracleQuote)` - Successfully verified oracle quote with feed data + /// * `Err(AnyError)` - Verification failed (invalid signatures, expired data, etc.) + /// + /// # Example + /// ```rust,ignore + /// let quote = verifier.verify_account(&ctx.accounts.oracle)?; + /// for feed in quote.feeds() { + /// println!("Feed {}: ${}", feed.hex_id(), feed.value()); + /// } + /// ``` + #[cfg(feature = "pinocchio")] + #[inline(always)] + pub fn verify_account<'data, T>( + &self, + queue: &[u8; 32], + oracle_account: &'data T, + ) -> Result, AnyError> + where + T: AsAccountInfo<'data>, + { + let account_info = oracle_account.as_account_info(); + + // For pinocchio, use raw data access to avoid temporary borrow lifetime issues + // # Safety: Account data is memory-mapped by Solana runtime and lives for the transaction duration + // We're using unsafe to extend the lifetime from the temporary borrow to match the account parameter + let oracle_data: &'data [u8] = unsafe { + let temp_borrow = account_info.borrow_data_unchecked(); + std::slice::from_raw_parts(temp_borrow.as_ptr(), temp_borrow.len()) + }; + + if oracle_data.len() < 40 { + bail!( + "Oracle account too small: {} bytes, expected at least 40", + oracle_data.len() + ); + } + + unsafe { + if read_unaligned(oracle_data.as_ptr() as *const u64) != QUOTE_DISCRIMINATOR_U64_LE { + bail!("Invalid oracle account discriminator"); + } + let data_ptr = oracle_data.as_ptr().add(8) as *const u64; + let queue_ptr = queue.as_ptr() as *const u64; + if !check_p64_eq(data_ptr, queue_ptr) { + bail!("Oracle account does not belong to the specified queue"); + } + } + + self.verify_delimited(&oracle_data[40..]) + } + + #[cfg(not(feature = "pinocchio"))] + #[inline(always)] + pub fn verify_account<'data, T>( + &self, + queue: &[u8; 32], + oracle_account: &'data T, + ) -> Result, AnyError> + where + T: AsAccountInfo<'data>, + { + let account_info = oracle_account.as_account_info(); + + let oracle_data = unsafe { &*account_info.data.as_ptr() }; + + if oracle_data.len() < 40 { + bail!( + "Oracle account too small: {} bytes, expected at least 40", + oracle_data.len() + ); + } + + unsafe { + if read_unaligned(oracle_data.as_ptr() as *const u64) != QUOTE_DISCRIMINATOR_U64_LE { + bail!("Invalid oracle account discriminator"); + } + let data_ptr = oracle_data.as_ptr().add(8) as *const u64; + let queue_ptr = queue.as_ptr() as *const u64; + if !check_p64_eq(data_ptr, queue_ptr) { + bail!("Oracle account does not belong to the specified queue"); + } + } + + self.verify_delimited(&oracle_data[40..]) + } + + /// Verifies raw ED25519 instruction data and creates a validated OracleQuote. + /// + /// This is the core verification method that performs all security checks: + /// - Parses ED25519 signatures and extracts oracle indices + /// - Validates oracle signing keys against the queue + /// - Verifies slot hash against the sysvar + /// - Validates quote age against max_age (requires clock sysvar) + /// - Ensures oracle quote data integrity + /// + /// # Arguments + /// * `data` - Raw ED25519 instruction data containing signatures and quote + /// + /// # Returns + /// * `Ok(OracleQuote)` - Successfully verified and parsed oracle quote + /// * `Err(AnyError)` - Verification failed with detailed error message + /// + /// # Errors + /// - Clock slot not set + /// - No signatures provided + /// - Invalid oracle signing keys + /// - Slot hash mismatch + /// - Quote is too old (exceeds max_age slots) + /// - Malformed instruction data + #[inline(always)] + pub fn verify_delimited<'data>( + &self, + data: &'data [u8], + ) -> Result, AnyError> { + // # Safety + // + // This unsafe block is safe because: + // - We verify `data` has at least 2 bytes before reading the length + // - `read_unaligned` safely reads u16 from potentially unaligned memory + // - The bounds check ensures we don't read beyond the data buffer + // - Data slice is guaranteed valid for the function duration + if data.len() < 2 { + bail!("Data too small for length prefix: {} bytes", data.len()); + } + unsafe { + let len = read_unaligned(data.as_ptr() as *const u16) as usize; + if data.len() < len + 2 { + bail!( + "Data length mismatch: expected {}, got {}", + len + 2, + data.len() + ); + } + self.verify(&data[2..len + 2]) + } + } + + /// Parses oracle quote data without performing any verification checks. + /// + /// This method extracts the quote structure from ED25519 instruction data + /// but skips all security validations including: + /// - Clock/age validation + /// - Signature verification + /// - Oracle key authorization + /// - Slot hash verification + /// + /// **WARNING**: This method should only be used for debugging, analysis, or + /// scenarios where verification is handled separately. Never use unverified + /// quotes for production decisions. + /// + /// # Arguments + /// * `data` - Raw ED25519 instruction data containing signatures and quote + /// + /// # Returns + /// * `Ok(OracleQuote)` - Successfully parsed oracle quote (unverified) + /// * `Err(AnyError)` - Failed to parse the quote data structure + /// + /// # Example + /// ```rust,ignore + /// // Parse quote without verification (use cautiously) + /// let unverified_quote = verifier.parse_unverified(&instruction_data)?; + /// println!("Quote contains {} feeds", unverified_quote.feeds().len()); + /// ``` + #[inline(always)] + pub fn parse_unverified<'data>( + &self, + data: &'data [u8], + ) -> Result, AnyError> { + let (parsed_sigs, sig_count, oracle_idxs, recent_slot, version) = + Ed25519Sysvar::parse_instruction(data)?; + + if sig_count == 0 { + bail!("No signatures provided"); + } + + let reference_sig = &parsed_sigs[0]; + let reference_feed_infos = unsafe { reference_sig.feed_infos() }; + let feed_count = reference_feed_infos.len(); + + Ok(OracleQuote::new( + unsafe { reference_sig.quote_header() }, + sig_count, + reference_feed_infos, + feed_count as u8, + oracle_idxs, + recent_slot, + version, + data, + )) + } + + /// Parses oracle quote data from an account without performing verification checks. + /// + /// This is a convenience method that extracts quote data from a Switchboard + /// oracle account and parses it without any security validations. + /// + /// **WARNING**: This method should only be used for debugging, analysis, or + /// scenarios where verification is handled separately. Never use unverified + /// quotes for production decisions. + /// + /// # Arguments + /// * `oracle_account` - Oracle account containing quote data + /// + /// # Returns + /// * `Ok(OracleQuote)` - Successfully parsed oracle quote (unverified) + /// * `Err(AnyError)` - Failed to parse the account or quote data + /// + /// # Example + /// ```rust,ignore + /// // Parse account quote without verification (use cautiously) + /// let unverified_quote = verifier.parse_account_unverified(&oracle_account)?; + /// ``` + #[cfg(feature = "pinocchio")] + #[inline(always)] + pub fn parse_account_unverified<'data, T>( + &self, + oracle_account: &'data T, + ) -> Result, AnyError> + where + T: AsAccountInfo<'data>, + { + let account_info = oracle_account.as_account_info(); + + let oracle_data = account_info.borrow_data_unchecked(); + + if oracle_data.len() < 40 { + bail!( + "Oracle account too small: {} bytes, expected at least 40", + oracle_data.len() + ); + } + + self.parse_unverified_delimited(&oracle_data[40..]) + } + + #[cfg(not(feature = "pinocchio"))] + #[inline(always)] + pub fn parse_account_unverified<'data, T>( + &self, + oracle_account: &'data T, + ) -> Result, AnyError> + where + T: AsAccountInfo<'data>, + { + let account_info = oracle_account.as_account_info(); + + let oracle_data = unsafe { &*account_info.data.as_ptr() }; + + if oracle_data.len() < 40 { + bail!( + "Oracle account too small: {} bytes, expected at least 40", + oracle_data.len() + ); + } + + self.parse_unverified_delimited(&oracle_data[40..]) + } + + /// Parses length-delimited oracle quote data without verification checks. + /// + /// This method handles the length prefix parsing and delegates to `parse_unverified`. + /// + /// # Arguments + /// * `data` - Length-delimited ED25519 instruction data + /// + /// # Returns + /// * `Ok(OracleQuote)` - Successfully parsed oracle quote (unverified) + /// * `Err(AnyError)` - Failed to parse the data + #[inline(always)] + pub fn parse_unverified_delimited<'data>( + &self, + data: &'data [u8], + ) -> Result, AnyError> { + if data.len() < 2 { + bail!("Data too small for length prefix: {} bytes", data.len()); + } + unsafe { + let len = read_unaligned(data.as_ptr() as *const u16) as usize; + if data.len() < len + 2 { + bail!( + "Data length mismatch: expected {}, got {}", + len + 2, + data.len() + ); + } + self.parse_unverified(&data[2..len + 2]) + } + } + + /// Verifies oracle quote data and returns a validated OracleQuote + pub fn verify<'data>(&self, data: &'data [u8]) -> Result, AnyError> { + let (parsed_sigs, sig_count, oracle_idxs, recent_slot, version) = + Ed25519Sysvar::parse_instruction(data)?; + let queue = self + .queue + .as_ref() + .ok_or_else(|| anyhow::anyhow!("Queue account not set"))?; + let slothash_sysvar = self + .slothash_sysvar + .as_ref() + .ok_or_else(|| anyhow::anyhow!("Slothash sysvar not set"))?; + + // Validate quote freshness - clock slot is required for all verifications + let clock_slot = self + .clock_slot + .ok_or_else(|| anyhow::anyhow!("Clock slot not set"))?; + if clock_slot < recent_slot || clock_slot - recent_slot > self.max_age { + bail!( + "Quote is too old: recent_slot={}, current_slot={}, max_age={}", + recent_slot, + clock_slot, + self.max_age + ); + } + + if sig_count == 0 { + bail!("No signatures provided"); + } + + // Get queue data for oracle signing keys + // Safely access queue data using RefCell borrow and try_from_bytes + let queue_buf = borrow_account_data!(queue); + if queue_buf.len() != 6280 { + bail!("Queue account too small: {} bytes", queue_buf.len()); + } + let queue_data: &QueueAccountData = + unsafe { &*(queue_buf.as_ptr().add(8) as *const QueueAccountData) }; + + // Find the target slothash from the oracle quote + let reference_sig = &parsed_sigs[0]; + let header = unsafe { reference_sig.quote_header() }; + + // Find the target slothash from oracle quote and get corresponding hash from sysvar + let target_slothash = &header.signed_slothash as *const _ as *const u64; + let found_slothash = + &Self::find_slothash_in_sysvar(recent_slot, slothash_sysvar)? as *const _ as *const u64; + + assert!(unsafe { check_p64_eq(found_slothash, target_slothash) }); + + // Oracle signing key validation (32 bytes per oracle: actual should match expected) + for i in 0..sig_count { + // Branchless bounds check, 30 is max oracles in queue + let oracle_idx = (oracle_idxs[i as usize] as usize) % 30; + let expected_oracle_key = queue_data.ed25519_oracle_signing_keys[oracle_idx]; + let actual_oracle_key = unsafe { parsed_sigs[i as usize].pubkey() }; + assert!(unsafe { + check_p64_eq( + actual_oracle_key as *const _ as *const u64, + &expected_oracle_key as *const _ as *const u64, + ) + }); + } + + // Continue with remaining processing... + let reference_feed_infos = unsafe { reference_sig.feed_infos() }; + let feed_count = reference_feed_infos.len(); + + Ok(OracleQuote::new( + unsafe { reference_sig.quote_header() }, + sig_count, + reference_feed_infos, + feed_count as u8, + oracle_idxs, + recent_slot, + version, + data, + )) + } + + /// Loads and verifies an ED25519 instruction from the instructions sysvar with age validation. + /// + /// This method extracts instruction data from the instructions sysvar at the specified + /// index, validates that it comes from the ED25519 program, checks the quote age against + /// the current slot using the configured max_age, and then verifies the oracle quote data. + /// + /// # Arguments + /// * `instruction_idx` - Index of the instruction to load from the sysvar (typically 0 for first instruction) + /// + /// # Returns + /// * `Ok(OracleQuote)` - Successfully loaded and verified oracle quote + /// * `Err(AnyError)` - Failed to load or verify the instruction + /// + /// # Errors + /// - Instruction not found at the specified index + /// - Instruction is not from the ED25519 program + /// - Quote is too old (exceeds max_age slots) + /// - Verification of the quote data fails + #[inline(always)] + pub fn verify_instruction_at(&self, instruction_idx: i64) -> Result, AnyError> { + use crate::Instructions; + + let ix_sysvar = self + .ix_sysvar + .as_ref() + .ok_or_else(|| anyhow::anyhow!("Instructions sysvar not set"))?; + + // Extract instruction data and validate program ID using the existing helper + let data = { + #[cfg(feature = "pinocchio")] + { + Instructions::extract_ix_data(*ix_sysvar, instruction_idx as usize) + } + #[cfg(not(feature = "pinocchio"))] + { + Instructions::extract_ix_data(ix_sysvar, instruction_idx as usize) + } + }; + + // Verify the instruction data + self.verify(data) + } + + /// Finds and returns a specific slot hash from the slot hash sysvar. + /// + /// This function searches through the slot hash sysvar to find the hash + /// corresponding to the target slot. It uses an optimized search starting + /// from an estimated position and working backwards. + /// + /// # Arguments + /// * `target_slot` - The slot number to find the hash for + /// * `slothash_sysvar` - Reference to the slot hash sysvar account + /// + /// # Returns + /// * `Ok([u8; 32])` - The 32-byte hash for the target slot + /// * `Err(AnyError)` - Slot not found in the sysvar + /// + /// # Performance + /// Uses an estimated starting position based on slot ordering to minimize + /// the number of entries that need to be checked. + fn find_slothash_in_sysvar( + target_slot: u64, + slothash_sysvar: &AccountInfo, + ) -> Result<[u8; 32], AnyError> { + assert!(check_pubkey_eq( + *get_account_key!(slothash_sysvar), + solana_program::sysvar::slot_hashes::ID + )); + let slothash_data = borrow_account_data!(slothash_sysvar); + + // # Safety + // + // This transmute is safe because: + // - SlotHash is a POD type with known layout (u64 + [u8; 32]) + // - We skip the 8-byte sysvar header before transmuting + // - The Solana runtime guarantees proper alignment and initialization of sysvar data + // - The slice length is determined by the actual data size + let slot_data: &[SlotHash] = unsafe { std::mem::transmute(&slothash_data[8..]) }; + + let mut estimated_idx = ((slot_data[0].slot - target_slot) % SYSVAR_SLOT_LEN) as usize; + + // Optimized search with early termination + loop { + let slot_entry = &slot_data[estimated_idx]; + if slot_entry.slot == target_slot { + return Ok(slot_entry.hash); + } + if estimated_idx == 0 { + break; + } + estimated_idx -= 1; + } + bail!("Slot not found in slothash sysvar"); + } +} + +/// Convenience function for extracting the most recent ED25519 instruction from the instructions sysvar. +/// +/// This function retrieves the instruction immediately preceding the current one, +/// which should contain the ED25519 signature data. It handles the type coercion +/// from Anchor's Sysvar wrapper to AccountInfo for easier usage in programs. +/// +/// # Arguments +/// * `ix_sysvar` - Reference to the instructions sysvar (can be wrapped in various types) +/// +/// # Returns +/// * `Ok(Instruction)` - The ED25519 instruction with signature data +/// * `Err(ProgramError)` - Failed to retrieve the instruction +/// +/// # Example +/// ```rust,ignore +/// let ed25519_ix = get_ed25519_instruction(&ctx.accounts.instructions)?; +/// // Process the instruction data... +/// ``` +#[inline(always)] +pub fn get_ed25519_instruction<'a, T>( + ix_sysvar: &T, +) -> Result +where + T: AsAccountInfo<'a>, +{ + #[cfg(feature = "pinocchio")] + { + use core::ptr::read_unaligned; + + use solana_program::ed25519_program::ID as ED25519_PROGRAM_ID; + use solana_program::sysvar::instructions::ID as INSTRUCTIONS_SYSVAR_ID; + + use crate::{borrow_account_data, check_pubkey_eq, get_account_key, Instructions}; + + // Get the previous instruction (index -1 relative to current) + let ix_sysvar_account = ix_sysvar.as_account_info(); + + // First, we need to get the number of instructions to calculate the previous instruction index + assert!(check_pubkey_eq( + *get_account_key!(ix_sysvar_account), + INSTRUCTIONS_SYSVAR_ID + )); + + let num_instructions = unsafe { + let data = borrow_account_data!(ix_sysvar_account); + read_unaligned(data.as_ptr() as *const u16) as usize + }; + + // For get_instruction_relative(-1, ...), we want the previous instruction + // Since instructions are 0-indexed, the previous instruction is at index (num_instructions - 1) + if num_instructions == 0 { + return Err(solana_program::program_error::ProgramError::InvalidInstructionData); + } + + let prev_instruction_idx = num_instructions - 1; + let data = Instructions::extract_ix_data(ix_sysvar_account, prev_instruction_idx); + + // Create an Instruction struct from the extracted data + use solana_program::instruction::Instruction; + + Ok(Instruction { + program_id: ED25519_PROGRAM_ID, + accounts: vec![], // We don't parse account metas for this use case + data: data.to_vec(), + }) + } + + #[cfg(not(feature = "pinocchio"))] + get_instruction_relative(-1, ix_sysvar.as_account_info()) +} diff --git a/programs/switchboard-on-demand/src/on_demand/types.rs b/programs/switchboard-on-demand/src/on_demand/types.rs new file mode 100644 index 0000000000..0116888fd9 --- /dev/null +++ b/programs/switchboard-on-demand/src/on_demand/types.rs @@ -0,0 +1,57 @@ +use solana_program::sysvar::clock::Clock; + +use crate::{solana_program, Pubkey, VerificationStatus}; + +/// MR_ENCLAVE measurement type (32 bytes) +pub type MrEnclave = [u8; 32]; + +/// TEE quote verification data structure +#[repr(C)] +#[derive(Debug, Copy, Clone, bytemuck::Zeroable, bytemuck::Pod)] +pub struct Quote { + /// The address of the signer generated within an enclave. + pub enclave_signer: Pubkey, + /// The quotes MRENCLAVE measurement dictating the contents of the secure enclave. + pub mr_enclave: [u8; 32], + /// The VerificationStatus of the quote. + pub verification_status: u8, + padding1: [u8; 7], + /// The unix timestamp when the quote was last verified. + pub verification_timestamp: i64, + /// The unix timestamp when the quotes verification status expires. + pub valid_until: i64, + /// The off-chain registry where the verifiers quote can be located. + pub quote_registry: [u8; 32], + /// Key to lookup the buffer data in decentralized storage solutions. + pub registry_key: [u8; 64], + /// The secp256k1 public key of the enclave signer. Derived from the enclave_signer. + pub secp256k1_signer: [u8; 64], + /// Last ED25519 signer public key + pub last_ed25519_signer: Pubkey, + /// Last SECP256K1 signer public key (64 bytes) + pub last_secp256k1_signer: [u8; 64], + /// Slot number when keys were last rotated + pub last_rotate_slot: u64, + /// Array of guardian approver public keys + pub guardian_approvers: [Pubkey; 64], + /// Number of active guardian approvers + pub guardian_approvers_len: u8, + padding2: [u8; 7], + /// Reserved. + pub _ebuf: [u8; 1024], +} +impl Default for Quote { + fn default() -> Self { + unsafe { std::mem::zeroed() } + } +} +impl Quote { + /// Checks if the quote is currently verified based on clock + pub fn is_verified(&self, clock: &Clock) -> bool { + match self.verification_status.into() { + VerificationStatus::VerificationOverride => true, + VerificationStatus::VerificationSuccess => self.valid_until > clock.unix_timestamp, + _ => false, + } + } +} diff --git a/programs/switchboard-on-demand/src/prelude.rs b/programs/switchboard-on-demand/src/prelude.rs new file mode 100644 index 0000000000..0f095ea27c --- /dev/null +++ b/programs/switchboard-on-demand/src/prelude.rs @@ -0,0 +1,24 @@ +// Note: Most client items are NOT re-exported in prelude to avoid naming conflicts. +// Access client functionality via: use switchboard_on_demand::client::{Gateway, PullFeed}; +pub use std::result::Result; + +pub use rust_decimal; +pub use solana_program::entrypoint::ProgramResult; +pub use solana_program::instruction::{AccountMeta, Instruction}; +pub use solana_program::program::{invoke, invoke_signed}; + +pub use crate::accounts::*; +// Client utility functions +#[cfg(feature = "client")] +pub use crate::client::utils::{ix_to_tx, ix_to_tx_v0}; +pub use crate::decimal::*; +pub use crate::instructions::*; +// Use solana_program and Pubkey from the compat layer +pub use crate::solana_compat::{pubkey, solana_program, Pubkey}; +pub use crate::sysvar::*; +pub use crate::types::*; +pub use crate::utils::check_pubkey_eq; +pub use crate::AsAccountInfo; +// When both solana-v2 and client are enabled, export the conversion trait +#[cfg(all(feature = "solana-v2", feature = "client"))] +pub use crate::IntoV2Instruction; diff --git a/programs/switchboard-on-demand/src/program_id.rs b/programs/switchboard-on-demand/src/program_id.rs new file mode 100644 index 0000000000..7f6c1837dc --- /dev/null +++ b/programs/switchboard-on-demand/src/program_id.rs @@ -0,0 +1,34 @@ +#[allow(unused_imports)] +use std::str::FromStr; + +use crate::solana_compat::solana_program::pubkey::pubkey; +use crate::Pubkey; + +/// Program id for the Switchboard oracle program +/// SW1TCH7qEPTdLsDHRgPuMQjbQxKdH2aBStViMFnt64f +pub const SWITCHBOARD_PROGRAM_ID: Pubkey = pubkey!("SW1TCH7qEPTdLsDHRgPuMQjbQxKdH2aBStViMFnt64f"); + +/// Switchboard On-Demand program ID for mainnet +pub const ON_DEMAND_MAINNET_PID: Pubkey = pubkey!("SBondMDrcV3K4kxZR1HNVT7osZxAHVHgYXL5Ze1oMUv"); +/// Switchboard On-Demand program ID for devnet +pub const ON_DEMAND_DEVNET_PID: Pubkey = pubkey!("Aio4gaXjXzJNVLtzwtNVmSqGKpANtXhybbkhtAC94ji2"); + +pub const QUOTE_PROGRAM_ID: Pubkey = pubkey!("orac1eFjzWL5R3RbbdMV68K9H6TaCVVcL6LjvQQWAbz"); + +/// Gets the Switchboard on-demand program ID based on the current network +pub fn get_switchboard_on_demand_program_id() -> Pubkey { + if crate::utils::is_devnet() { + ON_DEMAND_DEVNET_PID + } else { + ON_DEMAND_MAINNET_PID + } +} + +/// Gets the Switchboard program ID for a specific cluster +pub fn get_sb_program_id(cluster: &str) -> Pubkey { + if !cluster.starts_with("mainnet") { + ON_DEMAND_DEVNET_PID + } else { + ON_DEMAND_MAINNET_PID + } +} diff --git a/programs/switchboard-on-demand/src/solana_compat.rs b/programs/switchboard-on-demand/src/solana_compat.rs new file mode 100644 index 0000000000..63a75d5fc6 --- /dev/null +++ b/programs/switchboard-on-demand/src/solana_compat.rs @@ -0,0 +1,92 @@ +//! Solana version compatibility layer +//! +//! This module provides compatibility between different Solana versions, +//! ensuring the correct types and modules are available regardless of which +//! version of the Solana SDK is being used. + +// ===== Compile-time feature compatibility checks ===== + +// Ensure only one Solana version is enabled +#[cfg(all(feature = "solana-v2", feature = "solana-v3"))] +compile_error!("Cannot enable both 'solana-v2' and 'solana-v3' features at the same time. Choose one."); + +// Ensure only one client version is enabled +#[cfg(all(feature = "client", feature = "client-v3"))] +compile_error!("Cannot enable both 'client' and 'client-v3' features at the same time. Use 'client' for Solana v2 or 'client-v3' for Solana v3."); + +#[cfg(all(feature = "client-v2", feature = "client-v3"))] +compile_error!("Cannot enable both 'client-v2' and 'client-v3' features at the same time. Use 'client-v2' for Solana v2 or 'client-v3' for Solana v3."); + +// When anchor is enabled, use anchor's solana_program (v2.x) +#[cfg(feature = "anchor")] +pub use anchor_lang::solana_program; + +// When anchor is NOT enabled, use version-specific solana_program +// v3 takes precedence when both v2 and v3 are enabled +#[cfg(all(not(feature = "anchor"), feature = "solana-v3"))] +pub extern crate solana_program_v3; +#[cfg(all(not(feature = "anchor"), feature = "solana-v3"))] +pub use solana_program_v3 as solana_program; + +#[cfg(all( + not(feature = "anchor"), + not(feature = "solana-v3"), + feature = "solana-v2" +))] +pub use solana_program_v2 as solana_program; + +// Default to v2 when neither anchor, v2, nor v3 is enabled +#[cfg(all( + not(feature = "anchor"), + not(feature = "solana-v2"), + not(feature = "solana-v3") +))] +pub use solana_program_v2 as solana_program; + +// ===== solana_sdk (only when client is enabled) ===== +// The client feature requires anchor-client, which provides solana_sdk + +// When client is enabled, use anchor_client's solana_sdk (which is v2) +#[cfg(feature = "client")] +pub use anchor_client::solana_sdk; + +// ===== solana_client (when client or client-v3 is enabled) ===== +// Version-specific solana-client selection based on features + +// When client-v3 is enabled, use solana-client v3 +#[cfg(feature = "client-v3")] +pub use solana_client_v3 as solana_client; + +// When client is enabled (default v2), use solana-client v2 +#[cfg(feature = "client")] +pub use solana_client_v2 as solana_client; + +// Re-export common types for easier access +pub use solana_program::{ + account_info::AccountInfo, + hash, + instruction::{AccountMeta, Instruction}, + msg, + pubkey::{pubkey, Pubkey}, + sysvar, +}; + +// System program ID constant (same across all versions) +pub const SYSTEM_PROGRAM_ID: Pubkey = pubkey!("11111111111111111111111111111111"); + +// Address lookup table program ID constant +pub const ADDRESS_LOOKUP_TABLE_PROGRAM_ID: Pubkey = + pubkey!("AddressLookupTab1e1111111111111111111111111"); + +// Re-export sol_memcpy_ based on version +// In v2, it's a direct import from the definitions module +#[cfg(any(feature = "anchor", feature = "solana-v2"))] +extern "C" { + pub fn sol_memcpy_(dst: *mut u8, src: *const u8, n: u64); +} + +// In v3+, declare it as extern (syscalls module doesn't re-export it) +#[cfg(all(not(feature = "anchor"), not(feature = "solana-v2")))] +extern "C" { + pub fn sol_memcpy_(dst: *mut u8, src: *const u8, n: u64); +} diff --git a/programs/switchboard-on-demand/src/sysvar/address_lookup_table.rs b/programs/switchboard-on-demand/src/sysvar/address_lookup_table.rs new file mode 100644 index 0000000000..82602ddf57 --- /dev/null +++ b/programs/switchboard-on-demand/src/sysvar/address_lookup_table.rs @@ -0,0 +1,37 @@ +use crate::Pubkey; + +use crate::{cfg_client, utils, ON_DEMAND_DEVNET_PID, ON_DEMAND_MAINNET_PID}; + +const LUT_SIGNER_SEED: &[u8] = b"LutSigner"; + +/// Finds the address lookup table signer PDA for a given key +pub fn find_lut_signer, P: From<[u8; 32]>>(k: &K) -> P { + let pid = if utils::is_devnet() { + ON_DEMAND_DEVNET_PID + } else { + ON_DEMAND_MAINNET_PID + }; + let (pk, _) = Pubkey::find_program_address(&[LUT_SIGNER_SEED, k.as_ref()], &pid); + P::from(pk.to_bytes()) +} + +cfg_client! { + use crate::OnDemandError; + use anchor_client::solana_client::nonblocking::rpc_client::RpcClient; + use spl_associated_token_account::solana_program::address_lookup_table::state::AddressLookupTable; + use spl_associated_token_account::solana_program::address_lookup_table::AddressLookupTableAccount; + + pub async fn fetch(client: &RpcClient, address: &Pubkey) -> Result { + let converted_address: anchor_client::solana_sdk::pubkey::Pubkey = address.to_bytes().into(); + let account = client.get_account_data(&converted_address) + .await + .map_err(|_| OnDemandError::AddressLookupTableFetchError)?; + let lut = AddressLookupTable::deserialize(&account) + .map_err(|_| OnDemandError::AddressLookupTableDeserializeError)?; + let out = AddressLookupTableAccount { + key: address.to_bytes().into(), + addresses: lut.addresses.iter().cloned().collect(), + }; + Ok(out) + } +} diff --git a/programs/switchboard-on-demand/src/sysvar/clock.rs b/programs/switchboard-on-demand/src/sysvar/clock.rs new file mode 100644 index 0000000000..15d85efebd --- /dev/null +++ b/programs/switchboard-on-demand/src/sysvar/clock.rs @@ -0,0 +1,63 @@ +use crate::{borrow_account_data, check_pubkey_eq, get_account_key, solana_program, AsAccountInfo}; + +/// Optimized function to extract the slot value from a Clock sysvar. +/// +/// This function extracts just the slot value from any type that implements +/// `AsAccountInfo`, making it compatible with Anchor's `Sysvar` wrapper and pinocchio AccountInfo. +/// This is more efficient than parsing the entire Clock struct when you only need the slot. +/// +/// # Arguments +/// * `clock_sysvar` - Any type that implements `AsAccountInfo` (e.g., `Sysvar`, direct `AccountInfo` reference, pinocchio AccountInfo) +/// +/// # Returns +/// The current slot value as a `u64`. +/// +/// # Example with Anchor +/// ```rust,ignore +/// use anchor_lang::prelude::*; +/// use switchboard_on_demand::clock::get_slot; +/// +/// pub fn my_function(ctx: Context) -> Result<()> { +/// let MyCtx { sysvars, .. } = ctx.accounts; +/// let clock_slot = get_slot(&sysvars.clock); // Works with Sysvar +/// +/// // Use the slot value +/// msg!("Current slot: {}", clock_slot); +/// Ok(()) +/// } +/// ``` +/// +/// # Safety +/// This function uses unsafe operations to directly read from the sysvar data. +/// It is safe because it validates the account key against the Clock sysvar ID first +/// and uses unaligned reads to safely extract the slot value. +#[inline(always)] +pub fn get_slot<'a, T>(clock_sysvar: T) -> u64 +where + T: AsAccountInfo<'a>, +{ + assert!(check_pubkey_eq( + *get_account_key!(clock_sysvar.as_account_info()), + solana_program::sysvar::clock::ID + )); + unsafe { + let clock_data = borrow_account_data!(clock_sysvar.as_account_info()); + core::ptr::read_unaligned(clock_data.as_ptr() as *const u64) + } +} + +crate::cfg_client! { + use crate::OnDemandError; + use futures::TryFutureExt; + pub async fn fetch_async( + client: &crate::RpcClient, + ) -> std::result::Result { + let pubkey = anchor_client::solana_sdk::sysvar::clock::id(); + let data = client + .get_account_data(&pubkey) + .map_err(|_| OnDemandError::AccountNotFound) + .await? + .to_vec(); + bincode::deserialize(&data).map_err(|_| OnDemandError::AccountNotFound) + } +} diff --git a/programs/switchboard-on-demand/src/sysvar/ed25519_sysvar.rs b/programs/switchboard-on-demand/src/sysvar/ed25519_sysvar.rs new file mode 100644 index 0000000000..fe8228a0a6 --- /dev/null +++ b/programs/switchboard-on-demand/src/sysvar/ed25519_sysvar.rs @@ -0,0 +1,320 @@ +use anyhow::{bail, Result}; + +use crate::on_demand::oracle_quote::feed_info::{PackedFeedInfo, PackedQuoteHeader}; + +/// Type alias for complex return type to improve readability +pub type ParsedInstructionResult<'a> = Result<( + [ParsedEd25519SignatureDataRef<'a>; 8], + u8, + &'a [u8], + u64, + u8, +)>; + +/// Size of a serialized ED25519 public key in bytes +pub const ED25519_PUBKEY_SERIALIZED_SIZE: usize = 32; +/// Size of a serialized ED25519 signature in bytes +pub const ED25519_SIGNATURE_SERIALIZED_SIZE: usize = 64; +/// Size of ED25519 signature offset structure in bytes +pub const ED25519_SIGNATURE_OFFSETS_SERIALIZED_SIZE: usize = 14; // 2+2+2+2+2+2+2 = 14 bytes + +// const SBOD_DISCRIMINATOR: u32 = u32::from_le_bytes(*b"SBOD"); + +/// Header structure for ED25519 signature instruction data +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct Ed25519SignatureHeader { + /// Number of signatures in the instruction + pub num_signatures: u8, + /// Padding byte for alignment + pub padding: u8, +} + +/// ED25519 signature data offsets within instruction data +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct Ed25519SignatureOffsets { + /// Offset to the signature data + pub signature_offset: u16, + /// Instruction index containing the signature + pub signature_instruction_index: u16, + /// Offset to the public key data + pub public_key_offset: u16, + /// Instruction index containing the public key + pub public_key_instruction_index: u16, + /// Offset to the message data + pub message_data_offset: u16, + /// Size of the message data in bytes + pub message_data_size: u16, + /// Instruction index containing the message + pub message_instruction_index: u16, +} + +/// Parsed ED25519 signature data with lifetime-bound references +#[derive(Debug, Copy, Clone)] +pub struct ParsedEd25519SignatureDataRef<'a> { + /// Signature data offsets + pub offsets: Ed25519SignatureOffsets, + /// Pointer to the public key data + pub pubkey: *const [u8; ED25519_PUBKEY_SERIALIZED_SIZE], + /// Pointer to the signature data + pub signature: *const [u8; ED25519_SIGNATURE_SERIALIZED_SIZE], + /// Pointer to the message data + pub message: *const u8, + /// Length of the message data + pub message_len: usize, + /// Pointer to the packed quote header + pub bundle_header: *const PackedQuoteHeader, + /// Pointer to the feed information array + pub feed_infos: *const PackedFeedInfo, + /// Number of feeds in the feed information array + pub feed_count: usize, + _phantom: core::marker::PhantomData<&'a ()>, +} + +impl<'a> ParsedEd25519SignatureDataRef<'a> { + /// Creates an empty ParsedEd25519SignatureDataRef with all null pointers + #[inline(always)] + pub fn default_empty() -> Self { + unsafe { core::mem::zeroed() } + } + + #[inline(always)] + /// Returns true if the signature data has valid pointers + pub fn is_valid(&self) -> bool { + !self.pubkey.is_null() + } + + #[inline(always)] + /// Returns the ED25519 public key from the signature + /// # Safety + /// This function assumes the signature data is properly formatted and aligned + pub unsafe fn pubkey(&self) -> &'a [u8; ED25519_PUBKEY_SERIALIZED_SIZE] { + &*self.pubkey + } + + #[inline(always)] + /// Returns the ED25519 signature bytes + /// # Safety + /// This function assumes the signature data is properly formatted and aligned + pub unsafe fn signature(&self) -> &'a [u8; ED25519_SIGNATURE_SERIALIZED_SIZE] { + &*self.signature + } + + #[inline(always)] + /// Returns the message that was signed + /// # Safety + /// This function assumes the message data is properly formatted + pub unsafe fn message(&self) -> &'a [u8] { + core::slice::from_raw_parts(self.message, self.message_len) + } + + #[inline(always)] + /// Returns the oracle quote header from the message + /// # Safety + /// This function assumes the message contains a valid PackedQuoteHeader + pub unsafe fn quote_header(&self) -> &'a PackedQuoteHeader { + &*self.bundle_header + } + + #[inline(always)] + /// Returns the array of feed information from the oracle quote + /// # Safety + /// This function assumes the message contains valid PackedFeedInfo data + pub unsafe fn feed_infos(&self) -> &'a [PackedFeedInfo] { + core::slice::from_raw_parts(self.feed_infos, self.feed_count) + } +} + +/// Utility for parsing ED25519 signature verification sysvar data +pub struct Ed25519Sysvar; +impl Ed25519Sysvar { + /// Ultra-efficient zero-copy ED25519 instruction parsing + /// Supports variable length messages unlike secp256k1 + /// Returns (signatures, sig_count, oracle_idxs, recent_slot, version) + #[inline(always)] + pub fn parse_instruction(data: &[u8]) -> ParsedInstructionResult<'_> { + let data_len = data.len(); // Update data_len to reflect actual ED25519 data length + // Validate minimum size for header before unsafe cast + if data_len < core::mem::size_of::() { + bail!("Data too short for Ed25519SignatureHeader"); + } + + // Parse the header (num_signatures + padding byte) + let header: &Ed25519SignatureHeader = unsafe { std::mem::transmute(&data[0]) }; + let num_signatures = header.num_signatures as usize; + if num_signatures > 8 { + bail!("Too many signatures - maximum 8 supported"); + } + if num_signatures == 0 { + bail!("No signatures found in instruction data"); + } + + // Extract recent_slot and version from the end of instruction data first + // Check for underflow before subtraction + if data_len < 13 + num_signatures { + bail!( + "Data too short for oracle indices and metadata: need {} bytes, got {}", + 13 + num_signatures, + data_len + ); + } + // Discriminator length is 4, slot is 8, version is 1 + let end_of_message = data_len - num_signatures - 13; + let suffix = &data[end_of_message..]; + let oracle_idxs: &[u8] = unsafe { suffix.get_unchecked(..num_signatures) }; + let suffix = unsafe { suffix.get_unchecked(num_signatures..) }; + let slot: u64 = unsafe { + // Direct u64 read for 64-bit machines - data already little-endian + core::ptr::read_unaligned(&suffix[0] as *const u8 as *const u64) + }; + let version: u8 = unsafe { *suffix.get_unchecked(8) }; + + let message_data = &data[..end_of_message]; + + let message_data_ptr = message_data.as_ptr(); + + // Use MaybeUninit to avoid unnecessary initialization + let mut parsed_sigs_array = + unsafe { core::mem::zeroed::<[ParsedEd25519SignatureDataRef; 8]>() }; + let parsed_sigs_ptr = parsed_sigs_array.as_mut_ptr(); + + unsafe { + let mut offset = 2usize; // Skip padding byte after count byte + + // Parse the first signature to get shared message structure + let offset_ptr = message_data_ptr.add(offset); + let first_offsets = *(offset_ptr as *const Ed25519SignatureOffsets); + let first_message_offset = first_offsets.message_data_offset as usize; + let first_message_size = first_offsets.message_data_size as usize; + + // Parse message structure once for all signatures + let message = core::slice::from_raw_parts( + message_data_ptr.add(first_message_offset), + first_message_size, + ); + + if first_message_size < core::mem::size_of::() { + bail!("Message too short for bundle header"); + } + let shared_header: &PackedQuoteHeader = std::mem::transmute(&message[0]); + + const HEADER_SIZE: usize = core::mem::size_of::(); + const FEED_INFO_SIZE: usize = core::mem::size_of::(); + let remaining_bytes = first_message_size - HEADER_SIZE; + + if remaining_bytes % FEED_INFO_SIZE != 0 { + bail!("Invalid message size: remaining bytes not divisible by feed info size, got {}, with feed info size {}", remaining_bytes, FEED_INFO_SIZE); + } + + let shared_feed_count = remaining_bytes / FEED_INFO_SIZE; + if shared_feed_count > 8 { + bail!( + "Too many feeds in message: {} feeds but maximum is 8", + shared_feed_count + ); + } + + let shared_feed_infos = core::slice::from_raw_parts( + message.as_ptr().add(HEADER_SIZE) as *const PackedFeedInfo, + shared_feed_count, + ); + + // Process first signature (i=0) outside the loop + let first_signature_offset = first_offsets.signature_offset as usize; + let first_pubkey_offset = first_offsets.public_key_offset as usize; + let first_message_instruction_index = first_offsets.message_instruction_index; + + let first_pubkey = &*(message_data_ptr.add(first_pubkey_offset) + as *const [u8; ED25519_PUBKEY_SERIALIZED_SIZE]); + let first_signature = &*(message_data_ptr.add(first_signature_offset) + as *const [u8; ED25519_SIGNATURE_SERIALIZED_SIZE]); + + // Write first signature to array + parsed_sigs_ptr.write(ParsedEd25519SignatureDataRef { + offsets: first_offsets, + pubkey: first_pubkey as *const _, + signature: first_signature as *const _, + message: message_data_ptr.add(first_message_offset), + message_len: first_message_size, + bundle_header: shared_header as *const _, + feed_infos: shared_feed_infos.as_ptr(), + feed_count: shared_feed_count, + _phantom: core::marker::PhantomData, + }); + + offset += ED25519_SIGNATURE_OFFSETS_SERIALIZED_SIZE; + + // Process remaining signatures (i=1 to num_signatures-1) + for i in 1..num_signatures { + // Ultra-fast direct access - no endianness conversion needed + let offset_ptr = message_data_ptr.add(offset); + let offsets = *(offset_ptr as *const Ed25519SignatureOffsets); + + // Direct access without endianness conversion (assumes little-endian or native format) + let signature_offset = offsets.signature_offset as usize; + let pubkey_offset = offsets.public_key_offset as usize; + let message_offset = offsets.message_data_offset as usize; + let message_size = offsets.message_data_size as usize; + + // Verify all messages are identical + if message_offset != first_message_offset || message_size != first_message_size { + bail!("Inconsistent message offsets or sizes"); + } + + // Validate that all instruction indexes match the first signature's message_instruction_index + if offsets.signature_instruction_index != first_message_instruction_index { + bail!( + "Signature instruction index mismatch: expected {}, got {}", + first_message_instruction_index, + offsets.signature_instruction_index + ); + } + if offsets.public_key_instruction_index != first_message_instruction_index { + bail!( + "Public key instruction index mismatch: expected {}, got {}", + first_message_instruction_index, + offsets.public_key_instruction_index + ); + } + if offsets.message_instruction_index != first_message_instruction_index { + bail!( + "Message instruction index mismatch: expected {}, got {}", + first_message_instruction_index, + offsets.message_instruction_index + ); + } + + // Zero-copy references - no copying or allocation + let pubkey = &*(message_data_ptr.add(pubkey_offset) + as *const [u8; ED25519_PUBKEY_SERIALIZED_SIZE]); + let signature = &*(message_data_ptr.add(signature_offset) + as *const [u8; ED25519_SIGNATURE_SERIALIZED_SIZE]); + + // Write directly to final array position - no intermediate copy + parsed_sigs_ptr.add(i).write(ParsedEd25519SignatureDataRef { + offsets, + pubkey: pubkey as *const _, + signature: signature as *const _, + message: message_data_ptr.add(message_offset), + message_len: message_size, + bundle_header: shared_header as *const _, + feed_infos: shared_feed_infos.as_ptr(), + feed_count: shared_feed_count, + _phantom: core::marker::PhantomData, + }); + + offset += ED25519_SIGNATURE_OFFSETS_SERIALIZED_SIZE; + } + + // Array is now fully initialized, safe to assume_init + Ok(( + parsed_sigs_array, + num_signatures as u8, + oracle_idxs, + slot, + version, + )) + } + } +} diff --git a/programs/switchboard-on-demand/src/sysvar/ix_sysvar.rs b/programs/switchboard-on-demand/src/sysvar/ix_sysvar.rs new file mode 100644 index 0000000000..ce13ec6cb5 --- /dev/null +++ b/programs/switchboard-on-demand/src/sysvar/ix_sysvar.rs @@ -0,0 +1,234 @@ +use core::ptr::read_unaligned; + +use solana_program::ed25519_program::ID as ED25519_PROGRAM_ID; +use solana_program::sysvar::instructions::ID as INSTRUCTIONS_SYSVAR_ID; + +use crate::{ + borrow_account_data, check_pubkey_eq, get_account_key, solana_program, AsAccountInfo, Pubkey, +}; + +/// Optimized wrapper for Solana's Instructions sysvar with fast instruction data extraction. +/// +/// This struct provides high-performance access to instruction data from the Instructions sysvar, +/// specifically optimized for ED25519 signature verification workflows. +#[derive(Clone, Default)] +#[cfg_attr(feature = "anchor", derive(serde::Serialize, serde::Deserialize))] +pub struct Instructions; + +/* +#[repr(C)] +pub struct Ed25519SignatureOffsets { + pub signature_offset: u16, + pub signature_instruction_index: u16, + pub public_key_offset: u16, + pub public_key_instruction_index: u16, + pub message_data_offset: u16, + pub message_data_size: u16, + pub message_instruction_index: u16, +} +*/ + +impl Instructions { + /// Extracts instruction data at the specified index. + /// + /// # Arguments + /// * `ix_sysvar` - Reference to the Instructions sysvar account + /// * `idx` - Index of the instruction to extract + /// + /// # Returns + /// * `&[u8]` - Reference to the instruction data + /// + /// # Performance + /// Returns a reference to avoid copying data, saving compute units. + #[inline(always)] + pub fn extract_ix_data<'a, T>(ix_sysvar: T, idx: usize) -> &'a [u8] + where + T: AsAccountInfo<'a>, + { + let ix_sysvar = ix_sysvar.as_account_info(); + assert!(check_pubkey_eq( + *get_account_key!(ix_sysvar), + INSTRUCTIONS_SYSVAR_ID + )); + unsafe { + let data = borrow_account_data!(ix_sysvar); + let base = data.as_ptr(); + + // Read num_instructions from offset + let num_instructions = read_unaligned(base as *const u16) as usize; + + // Ensure idx is within bounds - all instruction indexes MUST match idx + assert!( + idx < num_instructions, + "Instruction index {} out of bounds (max: {})", + idx, + num_instructions + ); + + // Read instruction offset from offset table at position (2 + idx * 2) + let start_offset = read_unaligned(base.add(2 + (idx << 1)) as *const u16) as usize; + + let mut p = base.add(start_offset); + + let num_accounts = read_unaligned(p as *const u16) as usize; + + // Bounds check for account metas (1 byte meta + 32 byte pubkey each) + p = p.add(2 + num_accounts * 33); + + // Read program_id (32 bytes) - return reference to avoid copying + let program_id = &*(p as *const Pubkey); + + // Read data length + let instruction_data_len = read_unaligned(p.add(32) as *const u16) as usize; + + let ix_data_ptr = p.add(34); + let instruction_data = core::slice::from_raw_parts(ix_data_ptr, instruction_data_len); + + // Validate Ed25519SignatureOffsets if this appears to be an Ed25519 instruction + assert!(check_pubkey_eq(program_id, ED25519_PROGRAM_ID)); + assert!(instruction_data_len >= 16); + // Read the first Ed25519SignatureOffsets from instruction data + // Skip 2-byte header (num_signatures + padding), then read offsets struct + // This only checks the first header, the verify call checks that the rest of the + // signatures match this index. + let signature_instruction_index = + read_unaligned(ix_data_ptr.add(4) as *const u16) as usize; + let public_key_instruction_index = + read_unaligned(ix_data_ptr.add(8) as *const u16) as usize; + let message_instruction_index = + read_unaligned(ix_data_ptr.add(14) as *const u16) as usize; + + // All instruction indexes MUST match the current instruction index + assert!( + signature_instruction_index == idx, + "Signature instruction index {} does not match current instruction index {}", + signature_instruction_index, + idx + ); + assert!( + public_key_instruction_index == idx, + "Public key instruction index {} does not match current instruction index {}", + public_key_instruction_index, + idx + ); + assert!( + message_instruction_index == idx, + "Message instruction index {} does not match current instruction index {}", + message_instruction_index, + idx + ); + + instruction_data + } + } + + #[inline(always)] + pub fn extract_ix_data_unchecked<'a, T>(ix_sysvar: T, idx: usize) -> &'a [u8] + where + T: AsAccountInfo<'a>, + { + let ix_sysvar = ix_sysvar.as_account_info(); + unsafe { + let data = borrow_account_data!(ix_sysvar); + let base = data.as_ptr(); + let start_offset = read_unaligned(base.add(2 + (idx << 1)) as *const u16) as usize; + let mut p = base.add(start_offset); + let num_accounts = read_unaligned(p as *const u16) as usize; + p = p.add(2 + num_accounts * 33); + let instruction_data_len = read_unaligned(p.add(32) as *const u16) as usize; + core::slice::from_raw_parts(p.add(34), instruction_data_len) + } + } + + /// Parses instruction data from the Instructions sysvar at the specified index into an OracleQuote without verification. + /// + /// **WARNING**: This function does NOT perform cryptographic verification: + /// - No ED25519 signature validation + /// - No oracle authorization checks + /// - No slot hash verification + /// + /// Use only for data extraction and analysis. For production use, use verified parsing methods. + /// + /// # Arguments + /// * `ix_sysvar` - Reference to the Instructions sysvar account + /// * `idx` - Index of the instruction to parse + /// + /// # Returns + /// * `OracleQuote` - Parsed but unverified oracle quote + /// + /// # Performance + /// Returns references to avoid copying data, saving compute units. + #[inline(always)] + pub fn parse_ix_data_unverified<'a, T>( + ix_sysvar: T, + idx: usize, + ) -> Result, anyhow::Error> + where + T: AsAccountInfo<'a>, + { + let instruction_data = Self::extract_ix_data(ix_sysvar, idx); + + // Create a temporary verifier to parse the instruction data + let verifier = crate::on_demand::oracle_quote::quote_verifier::QuoteVerifier::new(); + let oracle_quote = verifier.parse_unverified(instruction_data)?; + + Ok(oracle_quote) + } +} + +#[cfg(feature = "anchor")] +impl anchor_lang::Owner for Instructions { + fn owner() -> Pubkey { + anchor_lang::solana_program::sysvar::instructions::id() + .to_bytes() + .into() + } +} + +#[cfg(feature = "anchor")] +impl anchor_lang::AccountDeserialize for Instructions { + fn try_deserialize_unchecked(_buf: &mut &[u8]) -> anchor_lang::Result { + // This should not be called for sysvars, but we provide a stub + Err(anchor_lang::error::ErrorCode::AccountDidNotDeserialize.into()) + } +} + +#[cfg(feature = "anchor")] +impl anchor_lang::AccountSerialize for Instructions { + fn try_serialize(&self, _writer: &mut W) -> anchor_lang::Result<()> { + // This should not be called for sysvars, but we provide a stub + Err(anchor_lang::error::ErrorCode::AccountDidNotSerialize.into()) + } +} + +#[cfg(feature = "anchor")] +impl anchor_lang::solana_program::sysvar::SysvarId for Instructions { + fn id() -> anchor_lang::solana_program::pubkey::Pubkey { + anchor_lang::solana_program::sysvar::instructions::id() + } + + fn check_id(pubkey: &anchor_lang::solana_program::pubkey::Pubkey) -> bool { + pubkey == &Self::id() + } +} + +#[cfg(feature = "anchor")] +impl anchor_lang::solana_program::sysvar::Sysvar for Instructions { + fn size_of() -> usize { + // Instructions sysvar has variable size, return 0 as it's not used for deserialization + 0 + } + + fn from_account_info( + account_info: &anchor_lang::solana_program::account_info::AccountInfo, + ) -> core::result::Result { + use anchor_lang::solana_program::sysvar::SysvarId; + // We don't actually deserialize the Instructions sysvar data since we access it directly + // Just validate that it's the correct account + if Self::check_id(account_info.key) { + Ok(Self) + } else { + Err(anchor_lang::solana_program::program_error::ProgramError::InvalidAccountData) + } + } +} diff --git a/programs/switchboard-on-demand/src/sysvar/mod.rs b/programs/switchboard-on-demand/src/sysvar/mod.rs new file mode 100644 index 0000000000..2550c771dc --- /dev/null +++ b/programs/switchboard-on-demand/src/sysvar/mod.rs @@ -0,0 +1,20 @@ +/// Address lookup table utilities +pub mod address_lookup_table; +#[allow(unused_imports)] +pub use address_lookup_table::*; + +/// Slot hash sysvar utilities +pub mod slothash_sysvar; +pub use slothash_sysvar::*; + +/// Instruction sysvar utilities +pub mod ix_sysvar; +pub use ix_sysvar::*; + +/// ED25519 signature verification sysvar utilities +pub mod ed25519_sysvar; +pub use ed25519_sysvar::*; + +/// Clock sysvar utilities +pub mod clock; +pub use clock::*; diff --git a/programs/switchboard-on-demand/src/sysvar/slothash_sysvar.rs b/programs/switchboard-on-demand/src/sysvar/slothash_sysvar.rs new file mode 100644 index 0000000000..4379a825ff --- /dev/null +++ b/programs/switchboard-on-demand/src/sysvar/slothash_sysvar.rs @@ -0,0 +1,110 @@ +use anyhow::{anyhow, bail, Result}; +use arrayref::array_ref; +use bytemuck; + +use crate::solana_compat::{msg, sysvar}; +use crate::{borrow_account_data, check_pubkey_eq, get_account_key}; + +/// Solana slot hash data structure containing slot number and corresponding hash +#[repr(C)] +#[derive(bytemuck::Pod, bytemuck::Zeroable, Debug, Clone, Copy)] +pub struct SlotHash { + /// Slot number + pub slot: u64, + /// 32-byte hash for this slot + pub hash: [u8; 32], +} + +/// Finds the index of a specific slot in the slot hashes array using binary search +/// since slots are often skipped +pub fn find_idx(slot_hashes: &[SlotHash], slot: u64) -> Option { + slot_hashes.binary_search_by(|x| slot.cmp(&x.slot)).ok() +} + +/// Slot hashes sysvar for Solana slot hash verification +#[derive(Copy, Clone, Default, serde::Serialize, serde::Deserialize)] +pub struct SlotHashes; + +#[cfg(feature = "anchor")] +impl anchor_lang::solana_program::sysvar::SysvarId for SlotHashes { + fn id() -> anchor_lang::solana_program::pubkey::Pubkey { + sysvar::slot_hashes::id().to_bytes().into() + } + + fn check_id(id: &anchor_lang::solana_program::pubkey::Pubkey) -> bool { + sysvar::slot_hashes::id() == id.to_bytes().into() + } +} +#[cfg(feature = "anchor")] +impl anchor_lang::solana_program::sysvar::Sysvar for SlotHashes { + // override + fn size_of() -> usize { + // hard-coded so that we don't have to construct an empty + 20_488 // golden, update if MAX_ENTRIES changes + } + + fn from_account_info( + _account_info: &anchor_lang::prelude::AccountInfo, + ) -> Result { + Ok(Self {}) + } +} + +impl<'a> SlotHashes { + /// Gets slot hash using lower byte optimization for performance + #[inline(always)] + pub fn get_slothash_from_lower_byte( + slot_hashes: &crate::AccountInfo, + slot: u16, + ) -> Result { + let (upper_slot, lower_slot) = { + #[allow(unused_unsafe)] + let slots_data = unsafe { borrow_account_data!(slot_hashes) }; + let slots: &[u8] = array_ref![slots_data, 8, 20_480]; + // 20_480 / 40 = 512 + let slots: &[SlotHash] = + unsafe { std::slice::from_raw_parts(slots.as_ptr() as *const SlotHash, 512) }; + let upper_slot = (slots[0].slot & 0xFFFFFFFFFFFF0000) | slot as u64; + let lower_slot = (slots[slots.len() - 1].slot & 0xFFFFFFFFFFFF0000) | slot as u64; + (upper_slot, lower_slot) + }; + if let Ok(slothash) = Self::get_slothash(slot_hashes, upper_slot) { + return Ok(SlotHash { + slot: upper_slot, + hash: slothash, + }); + } + Self::get_slothash(slot_hashes, lower_slot).map(|hash| SlotHash { + slot: lower_slot, + hash, + }) + } + + /// Gets the slot hash for a specific slot from the slot hashes sysvar + pub fn get_slothash(slot_sysvar: &crate::AccountInfo, slot: u64) -> Result<[u8; 32]> { + assert!(check_pubkey_eq( + sysvar::slot_hashes::ID, + *get_account_key!(slot_sysvar) + )); + let slot_hashes = slot_sysvar; + #[allow(unused_unsafe)] + let slots_data = unsafe { borrow_account_data!(slot_hashes) }; + let slots: &[u8] = array_ref![slots_data, 8, 20_480]; + // 20_480 / 40 = 512 + let slots: &[SlotHash] = + unsafe { std::slice::from_raw_parts(slots.as_ptr() as *const SlotHash, 512) }; + if slot > slots[0].slot { + msg!("Error: Your provided slot is too new. Please use confirmed commitment for your connection and processed for simulation."); + bail!("SwitchboardError::InvalidSlotNumber"); + } + let idx = find_idx(slots, slot).ok_or_else(|| anyhow!("InvalidSlotNumber"))?; + let signed_slot = slots[idx]; + assert_eq!(signed_slot.slot, slot); + Ok(signed_slot.hash) + } + + /// Parses slot hash data from raw bytes into SlotHash array + pub fn parse(data: &'a [u8]) -> &'a [SlotHash] { + unsafe { std::slice::from_raw_parts(data[8..].as_ptr() as *const SlotHash, 512) } + } +} diff --git a/programs/switchboard-on-demand/src/test_ids.rs b/programs/switchboard-on-demand/src/test_ids.rs new file mode 100644 index 0000000000..cd4d46770d --- /dev/null +++ b/programs/switchboard-on-demand/src/test_ids.rs @@ -0,0 +1,25 @@ +#[cfg(test)] +mod tests { + use crate::solana_program::sysvar::instructions::ID as INSTRUCTIONS_SYSVAR_ID; + + #[test] + fn print_instructions_sysvar_id() { + let bytes = INSTRUCTIONS_SYSVAR_ID.to_bytes(); + println!("Instructions sysvar ID bytes: {:02x?}", bytes); + + // Convert to u64 array for assembly + let ptr = bytes.as_ptr() as *const u64; + unsafe { + let u64_0 = ptr.read_unaligned(); + let u64_1 = ptr.add(1).read_unaligned(); + let u64_2 = ptr.add(2).read_unaligned(); + let u64_3 = ptr.add(3).read_unaligned(); + + println!("As u64 array for assembly:"); + println!(" [0]: 0x{:016x}", u64_0); + println!(" [1]: 0x{:016x}", u64_1); + println!(" [2]: 0x{:016x}", u64_2); + println!(" [3]: 0x{:016x}", u64_3); + } + } +} \ No newline at end of file diff --git a/programs/switchboard-on-demand/src/types.rs b/programs/switchboard-on-demand/src/types.rs new file mode 100644 index 0000000000..05dc8c2984 --- /dev/null +++ b/programs/switchboard-on-demand/src/types.rs @@ -0,0 +1,2 @@ +pub use crate::decimal::SwitchboardDecimal; +pub use crate::on_demand::*; diff --git a/programs/switchboard-on-demand/src/utils.rs b/programs/switchboard-on-demand/src/utils.rs new file mode 100644 index 0000000000..102e18fa41 --- /dev/null +++ b/programs/switchboard-on-demand/src/utils.rs @@ -0,0 +1,129 @@ +use solana_program::instruction::Instruction; + +use crate::anchor_traits::*; +use crate::solana_compat::{hash, pubkey}; +use crate::{solana_program, Pubkey}; + +/// Check if devnet environment is enabled via feature flag OR SB_ENV environment variable +#[inline(always)] +pub fn is_devnet() -> bool { + cfg!(feature = "devnet") || std::env::var("SB_ENV").unwrap_or_default() == "devnet" +} + +/// Default devnet queue address +pub const DEFAULT_DEVNET_QUEUE: Pubkey = pubkey!("EYiAmGSdsQTuCw413V5BzaruWuCCSDgTPtBGvLkXHbe7"); +/// Default mainnet queue address +pub const DEFAULT_MAINNET_QUEUE: Pubkey = pubkey!("A43DyUGA7s8eXPxqEjJY6EBu1KKbNgfxF8h17VAHn13w"); + +/// Returns the default queue address based on the environment (devnet or mainnet) +#[inline(always)] +pub fn default_queue() -> Pubkey { + if is_devnet() { + DEFAULT_DEVNET_QUEUE + } else { + DEFAULT_MAINNET_QUEUE + } +} + +/// SPL Associated Token Account program ID +pub const SPL_ASSOCIATED_TOKEN_ACCOUNT_PROGRAM_ID: Pubkey = + pubkey!("ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL"); + +/// SPL Token program ID +pub const SPL_TOKEN_PROGRAM_ID: Pubkey = pubkey!("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"); + +/// Finds the associated token account address for a given owner and mint +pub fn find_associated_token_address(owner: &Pubkey, mint: &Pubkey) -> Pubkey { + let (akey, _bump) = Pubkey::find_program_address( + &[owner.as_ref(), SPL_TOKEN_PROGRAM_ID.as_ref(), mint.as_ref()], + &SPL_ASSOCIATED_TOKEN_ACCOUNT_PROGRAM_ID, + ); + akey +} + +/// Gets the instruction discriminator for a given instruction name +pub fn get_ixn_discriminator(ixn_name: &str) -> [u8; 8] { + let preimage = format!("global:{}", ixn_name); + let mut sighash = [0u8; 8]; + sighash.copy_from_slice(&solana_program::hash::hash(preimage.as_bytes()).to_bytes()[..8]); + sighash +} + +/// Gets the account discriminator for a given account name +pub fn get_account_discriminator(account_name: &str) -> [u8; 8] { + let id = format!("account:{}", account_name); + hash::hash(id.as_bytes()).to_bytes()[..8] + .try_into() + .unwrap() +} + +/// Reads a u64 value from a pointer at a given offset (unsafe) +/// +/// # Safety +/// The caller must ensure that: +/// - `ptr` is a valid pointer +/// - `ptr.add(offset)` is within bounds and valid +/// - The memory at `ptr.add(offset)` contains a valid u64 value +#[inline(always)] +pub unsafe fn read_u64_at(ptr: *const u64, offset: usize) -> u64 { + core::ptr::read_unaligned(ptr.add(offset)) +} + +/// Reads a u64 value from a pointer (unsafe) +/// +/// # Safety +/// The caller must ensure that: +/// - `ptr` is valid and properly aligned for u64 access +/// - `ptr.add(offset)` is within bounds and valid +/// - The memory at `ptr.add(offset)` contains a valid u64 value +#[inline(always)] +pub unsafe fn read(ptr: *const u64, offset: usize) -> u64 { + *ptr.add(offset) +} + +/// Efficiently compares two Pubkeys for equality +#[inline(always)] +pub fn check_pubkey_eq, R: AsRef<[u8]>>(lhs: L, rhs: R) -> bool { + let lhs_bytes = lhs.as_ref(); + let rhs_bytes = rhs.as_ref(); + + unsafe { + let lhs_ptr = lhs_bytes.as_ptr() as *const u64; + let rhs_ptr = rhs_bytes.as_ptr() as *const u64; + core::ptr::read_unaligned(lhs_ptr) == core::ptr::read_unaligned(rhs_ptr) + && core::ptr::read_unaligned(lhs_ptr.add(1)) + == core::ptr::read_unaligned(rhs_ptr.add(1)) + && core::ptr::read_unaligned(lhs_ptr.add(2)) + == core::ptr::read_unaligned(rhs_ptr.add(2)) + && core::ptr::read_unaligned(lhs_ptr.add(3)) + == core::ptr::read_unaligned(rhs_ptr.add(3)) + } +} + +/// Efficiently compares two 32-byte arrays via u64 pointers (unsafe) +/// +/// # Safety +/// The caller must ensure that: +/// - Both `lhs_ptr` and `rhs_ptr` are valid pointers +/// - Both pointers point to memory regions of at least 32 bytes (4 u64 values) +/// - The memory regions are accessible for the duration of the function call +#[inline(always)] +pub unsafe fn check_p64_eq(lhs_ptr: *const u64, rhs_ptr: *const u64) -> bool { + core::ptr::read_unaligned(lhs_ptr) == core::ptr::read_unaligned(rhs_ptr) + && core::ptr::read_unaligned(lhs_ptr.add(1)) == core::ptr::read_unaligned(rhs_ptr.add(1)) + && core::ptr::read_unaligned(lhs_ptr.add(2)) == core::ptr::read_unaligned(rhs_ptr.add(2)) + && core::ptr::read_unaligned(lhs_ptr.add(3)) == core::ptr::read_unaligned(rhs_ptr.add(3)) +} + +/// Builds a Solana instruction from account metas and instruction data +pub fn build_ix( + program_id: &Pubkey, + accounts: &A, + params: &I, +) -> Instruction { + Instruction { + program_id: *program_id, + accounts: accounts.to_account_metas(None), + data: params.data(), + } +} diff --git a/programs/switchboard-on-demand/src/v2_client_compat.rs b/programs/switchboard-on-demand/src/v2_client_compat.rs new file mode 100644 index 0000000000..abf4a49164 --- /dev/null +++ b/programs/switchboard-on-demand/src/v2_client_compat.rs @@ -0,0 +1,105 @@ +//! Type compatibility layer for using solana-v2 with client features +//! +//! When both features are enabled, this module provides conversion utilities +//! between Solana SDK v2 types (used by on-chain code) and Solana SDK v3 types +//! (used by anchor-client). + +use anchor_client::solana_sdk; + +/// Convert v3 Instruction to v2 Instruction +/// +/// This accepts the specific anchor_lang::solana_program::instruction::Instruction type +/// and converts it to v2 by extracting bytes and reconstructing. +pub fn instruction_v3_to_v2( + ix: anchor_lang::solana_program::instruction::Instruction, +) -> crate::solana_compat::Instruction { + crate::solana_compat::Instruction { + program_id: crate::solana_compat::Pubkey::from(ix.program_id.to_bytes()), + accounts: ix + .accounts + .into_iter() + .map(|meta| crate::solana_compat::AccountMeta { + pubkey: crate::solana_compat::Pubkey::from(meta.pubkey.to_bytes()), + is_signer: meta.is_signer, + is_writable: meta.is_writable, + }) + .collect(), + data: ix.data, + } +} + +/// Trait for converting any instruction type to v2 +pub trait IntoV2Instruction { + fn into_v2_instruction(self) -> crate::solana_compat::Instruction; +} + +/// Implement for anchor_lang's solana_program Instruction type +/// +/// When anchor feature is enabled, `use anchor_lang::solana_program` brings this type into scope, +/// and this is what cfg_client! blocks use +impl IntoV2Instruction for anchor_lang::solana_program::instruction::Instruction { + fn into_v2_instruction(self) -> crate::solana_compat::Instruction { + crate::solana_compat::Instruction { + program_id: crate::solana_compat::Pubkey::from(self.program_id.to_bytes()), + accounts: self + .accounts + .into_iter() + .map(|meta| crate::solana_compat::AccountMeta { + pubkey: crate::solana_compat::Pubkey::from(meta.pubkey.to_bytes()), + is_signer: meta.is_signer, + is_writable: meta.is_writable, + }) + .collect(), + data: self.data, + } + } +} + +/// Convert a Solana v2 Instruction to v3 Instruction +pub fn instruction_v2_to_v3( + ix: crate::solana_compat::Instruction, +) -> solana_sdk::instruction::Instruction { + solana_sdk::instruction::Instruction { + program_id: pubkey_v2_to_v3(ix.program_id), + accounts: ix.accounts.into_iter().map(account_meta_v2_to_v3).collect(), + data: ix.data, + } +} + +/// Convert a Solana v3 Pubkey to v2 Pubkey +pub fn pubkey_v3_to_v2(pubkey: solana_sdk::pubkey::Pubkey) -> crate::solana_compat::Pubkey { + crate::solana_compat::Pubkey::from(pubkey.to_bytes()) +} + +/// Convert a Solana v2 Pubkey to v3 Pubkey +pub fn pubkey_v2_to_v3(pubkey: crate::solana_compat::Pubkey) -> solana_sdk::pubkey::Pubkey { + solana_sdk::pubkey::Pubkey::from(pubkey.to_bytes()) +} + +/// Convert a Solana v3 AccountMeta to v2 AccountMeta +pub fn account_meta_v3_to_v2( + meta: solana_sdk::instruction::AccountMeta, +) -> crate::solana_compat::AccountMeta { + crate::solana_compat::AccountMeta { + pubkey: pubkey_v3_to_v2(meta.pubkey), + is_signer: meta.is_signer, + is_writable: meta.is_writable, + } +} + +/// Convert a Solana v2 AccountMeta to v3 AccountMeta +pub fn account_meta_v2_to_v3( + meta: crate::solana_compat::AccountMeta, +) -> solana_sdk::instruction::AccountMeta { + if meta.is_writable { + if meta.is_signer { + solana_sdk::instruction::AccountMeta::new(pubkey_v2_to_v3(meta.pubkey), true) + } else { + solana_sdk::instruction::AccountMeta::new(pubkey_v2_to_v3(meta.pubkey), false) + } + } else if meta.is_signer { + solana_sdk::instruction::AccountMeta::new_readonly(pubkey_v2_to_v3(meta.pubkey), true) + } else { + solana_sdk::instruction::AccountMeta::new_readonly(pubkey_v2_to_v3(meta.pubkey), false) + } +} diff --git a/rust-toolchain.toml b/rust-toolchain.toml new file mode 100644 index 0000000000..b78a8dbfe7 --- /dev/null +++ b/rust-toolchain.toml @@ -0,0 +1,3 @@ +[toolchain] +components = ["rustfmt", "clippy"] +channel = "nightly-2024-11-19" From 0340b6535cb06fc31c291b942320614ceda2fa55 Mon Sep 17 00:00:00 2001 From: Mitch Gildenberg Date: Sat, 11 Oct 2025 19:11:44 -0400 Subject: [PATCH 2/2] sync lib --- programs/drift/src/lib.rs | 3 + programs/drift/src/state/oracle.rs | 43 ++ programs/switchboard-on-demand/src/lib.rs | 425 ++++++------ programs/switchboard-on-demand/src/macros.rs | 8 +- .../src/on_demand/accounts/queue.rs | 3 - .../instructions/randomness_commit.rs | 6 +- .../src/on_demand/oracle_quote/feed_info.rs | 98 ++- .../src/on_demand/oracle_quote/mod.rs | 9 +- .../src/on_demand/oracle_quote/quote.rs | 20 +- .../on_demand/oracle_quote/quote_account.rs | 654 +++++++++++------- .../src/solana_compat.rs | 17 +- .../src/sysvar/ed25519_sysvar.rs | 19 +- .../src/sysvar/ix_sysvar.rs | 6 +- programs/switchboard-on-demand/src/utils.rs | 2 +- 14 files changed, 806 insertions(+), 507 deletions(-) diff --git a/programs/drift/src/lib.rs b/programs/drift/src/lib.rs index e71b6de2a1..6dcceeee6f 100644 --- a/programs/drift/src/lib.rs +++ b/programs/drift/src/lib.rs @@ -34,6 +34,9 @@ pub mod state; mod test_utils; mod validation; +// Generate Switchboard quote account bindings +switchboard_on_demand::switchboard_anchor_bindings!(); + // main program entrypoint // anchor `#[program]` entrypoint is compiled out by `no-entrypoint` #[cfg(not(feature = "cpi"))] diff --git a/programs/drift/src/state/oracle.rs b/programs/drift/src/state/oracle.rs index 3becf945f6..32c969776c 100644 --- a/programs/drift/src/state/oracle.rs +++ b/programs/drift/src/state/oracle.rs @@ -132,6 +132,7 @@ pub enum OracleSource { PythLazer1K, PythLazer1M, PythLazerStableCoin, + SwitchboardSurge, } impl OracleSource { @@ -345,6 +346,7 @@ pub fn get_oracle_price( OracleSource::PythLazerStableCoin => { get_pyth_stable_coin_price(price_oracle, clock_slot, oracle_source) } + OracleSource::SwitchboardSurge => get_switchboard_surge_price(price_oracle, clock_slot), } } @@ -545,6 +547,47 @@ pub fn get_sb_on_demand_price( }) } +pub fn get_switchboard_surge_price( + price_oracle: &AccountInfo, + _clock_slot: u64, +) -> DriftResult { + use crate::SwitchboardQuote; + + let quote_account: Ref = + load_ref(price_oracle).or(Err(ErrorCode::UnableToLoadOracle))?; + + let feeds = quote_account.feeds(); + + validate!( + !feeds.is_empty(), + ErrorCode::UnableToLoadOracle, + "No feeds found in SwitchboardQuote" + )?; + + // Get the first feed value (i128 with precision 18) + let feed_value_i128 = feeds[0].feed_value(); + + // Convert from switchboard precision (18) to PRICE_PRECISION (6) + let price = convert_sb_i128(&feed_value_i128)?.cast::()?; + + // For Switchboard Surge, we don't have a direct confidence value in the quote + // We'll use a minimal confidence based on the price + let confidence = price.unsigned_abs().safe_div(1000)?; // 0.1% of price as confidence + + // Delay is 0 since Switchboard Surge quotes don't have slot information embedded + let delay = 0; + + let has_sufficient_number_of_data_points = true; + + Ok(OraclePriceData { + price, + confidence, + delay, + has_sufficient_number_of_data_points, + sequence_id: None, + }) +} + /// Given a decimal number represented as a mantissa (the digits) plus an /// original_precision (10.pow(some number of decimals)), scale the /// mantissa/digits to make sense with a new_precision. diff --git a/programs/switchboard-on-demand/src/lib.rs b/programs/switchboard-on-demand/src/lib.rs index 80779e43a5..dcea31d748 100644 --- a/programs/switchboard-on-demand/src/lib.rs +++ b/programs/switchboard-on-demand/src/lib.rs @@ -1,234 +1,221 @@ -use anchor_lang::declare_id; -use anchor_lang::prelude::*; -use anchor_lang::program; -use anchor_lang::AnchorDeserialize; -use solana_program::pubkey::Pubkey; - -#[cfg(feature = "mainnet-beta")] -declare_id!("SBondMDrcV3K4kxZR1HNVT7osZxAHVHgYXL5Ze1oMUv"); -#[cfg(not(feature = "mainnet-beta"))] -declare_id!("Aio4gaXjXzJNVLtzwtNVmSqGKpANtXhybbkhtAC94ji2"); - -#[program] -pub mod switchboard_on_demand {} -pub const SB_ON_DEMAND_PRECISION: u32 = 18; - -#[repr(C)] -#[derive(Clone, Copy, Debug, bytemuck::Pod, bytemuck::Zeroable)] -pub struct CompactResult { - pub std_dev: f32, - pub mean: f32, - pub slot: u64, -} - -#[repr(C)] -#[derive(Clone, Copy, Debug, bytemuck::Pod, bytemuck::Zeroable)] -pub struct CurrentResult { - /// The median value of the submissions needed for quorom size - pub value: i128, - /// The standard deviation of the submissions needed for quorom size - pub std_dev: i128, - /// The mean of the submissions needed for quorom size - pub mean: i128, - /// The range of the submissions needed for quorom size - pub range: i128, - /// The minimum value of the submissions needed for quorom size - pub min_value: i128, - /// The maximum value of the submissions needed for quorom size - pub max_value: i128, - /// The number of samples used to calculate this result - pub num_samples: u8, - /// The index of the submission that was used to calculate this result - pub submission_idx: u8, - pub padding1: [u8; 6], - /// The slot at which this value was signed. - pub slot: u64, - /// The slot at which the first considered submission was made - pub min_slot: u64, - /// The slot at which the last considered submission was made - pub max_slot: u64, -} -impl CurrentResult { - /// The median value of the submissions needed for quorom size - pub fn value(&self) -> Option { - if self.slot == 0 { - return None; - } - Some(self.value) - } - - /// The standard deviation of the submissions needed for quorom size - pub fn std_dev(&self) -> Option { - if self.slot == 0 { - return None; - } - Some(self.std_dev) - } - - /// The mean of the submissions needed for quorom size - pub fn mean(&self) -> Option { - if self.slot == 0 { - return None; - } - Some(self.mean) - } - - /// The range of the submissions needed for quorom size - pub fn range(&self) -> Option { - if self.slot == 0 { - return None; - } - Some(self.range) - } - - /// The minimum value of the submissions needed for quorom size - pub fn min_value(&self) -> Option { - if self.slot == 0 { - return None; - } - Some(self.min_value) - } - - /// The maximum value of the submissions needed for quorom size - pub fn max_value(&self) -> Option { - if self.slot == 0 { - return None; - } - Some(self.max_value) - } - - pub fn result_slot(&self) -> Option { - if self.slot == 0 { - return None; - } - Some(self.slot) - } - - pub fn min_slot(&self) -> Option { - if self.slot == 0 { - return None; - } - Some(self.min_slot) - } - - pub fn max_slot(&self) -> Option { - if self.slot == 0 { - return None; - } - Some(self.max_slot) +#![allow(clippy::crate_in_macro_def)] +#![allow(clippy::repr_packed_without_abi)] +#![allow(clippy::manual_is_multiple_of)] +#![doc(html_logo_url = "https://i.imgur.com/2cZloJp.png")] +#![allow(unexpected_cfgs)] +#![allow(unused_attributes)] +#![allow(clippy::result_large_err)] +//! # Switchboard On-Demand Oracle SDK +//! +//! Official Rust SDK for Switchboard On-Demand Oracles on Solana. +//! +//! This SDK provides secure, efficient access to real-time oracle data with +//! comprehensive validation and zero-copy performance optimizations. +//! +//! ## Quick Start +//! +//! ```rust,no_run +//! use switchboard_on_demand::prelude::*; +//! # use solana_program::account_info::AccountInfo; +//! # let queue_account: AccountInfo = todo!(); +//! # let slothash_sysvar: AccountInfo = todo!(); +//! # let instructions_sysvar: AccountInfo = todo!(); +//! # let clock_slot: u64 = 0; +//! +//! // Configure the verifier with required accounts +//! let quote = QuoteVerifier::new() +//! .queue(&queue_account) +//! .slothash_sysvar(&slothash_sysvar) +//! .ix_sysvar(&instructions_sysvar) +//! .clock_slot(clock_slot) +//! .max_age(150) +//! .verify_instruction_at(0)?; +//! +//! // Access feed data +//! for feed in quote.feeds() { +//! println!("Feed {}: {}", feed.hex_id(), feed.value()); +//! } +//! # Ok::<(), Box>(()) +//! ``` +//! +//! ## Security Considerations +//! +//! - Always validate oracle data freshness with appropriate `max_age` values +//! - Use minimum sample counts for critical operations +//! - Verify feed signatures in production environments +//! - Monitor for stale data and implement appropriate fallback mechanisms +//! +//! ## Feature Flags +//! +//! - `client` - Enable RPC client functionality +//! - `anchor` - Enable Anchor framework integration + +// ===== Feature compatibility checks ===== +// These compile errors catch mutually exclusive features at build time + +#[cfg(all(feature = "solana-v2", feature = "solana-v3"))] +compile_error!("Cannot enable both 'solana-v2' and 'solana-v3' features. Choose one: use 'solana-v2' for production or 'solana-v3' for experimental builds."); + +#[cfg(all(feature = "client", feature = "client-v3"))] +compile_error!("Cannot enable both 'client' (v2) and 'client-v3' features. Use 'client' for Solana v2 or 'client-v3' for Solana v3."); + +#[cfg(all(feature = "client-v2", feature = "client-v3"))] +compile_error!("Cannot enable both 'client-v2' and 'client-v3' features. Choose one client version."); + +// When both solana-v2 and client features are enabled, provide type compatibility layers +#[cfg(all(feature = "solana-v2", feature = "client"))] +pub mod v2_client_compat; + +#[cfg(all(feature = "solana-v2", feature = "client"))] +pub mod instruction_compat; + +#[cfg(all(feature = "solana-v2", feature = "client"))] +pub use instruction_compat::CompatInstruction; +#[cfg(all(feature = "solana-v2", feature = "client"))] +pub use v2_client_compat::IntoV2Instruction; + +// Implement the conversion trait at crate root so it's always available +#[cfg(all(feature = "solana-v2", feature = "client"))] +impl instruction_compat::mixed_version::IntoInstructionBytes + for anchor_lang::solana_program::instruction::Instruction +{ + fn into_bytes(self) -> ([u8; 32], Vec<([u8; 32], bool, bool)>, Vec) { + let program_id_bytes = self.program_id.to_bytes(); + let accounts_data: Vec<([u8; 32], bool, bool)> = self + .accounts + .into_iter() + .map(|meta| (meta.pubkey.to_bytes(), meta.is_signer, meta.is_writable)) + .collect(); + (program_id_bytes, accounts_data, self.data) } } -#[repr(C)] -#[derive(Clone, Copy, Debug, bytemuck::Pod, bytemuck::Zeroable)] -pub struct OracleSubmission { - /// The public key of the oracle that submitted this value. - pub oracle: Pubkey, - /// The slot at which this value was signed. - pub slot: u64, - /// The slot at which this value was landed on chain. - pub landed_at: u64, - /// The value that was submitted. - pub value: i128, -} - -impl OracleSubmission { - pub fn is_empty(&self) -> bool { - self.slot == 0 - } - - pub fn value(&self) -> i128 { - self.value +mod macros; +#[allow(unused_imports)] +use std::sync::Arc; + +/// Current SDK version +pub const VERSION: &str = env!("CARGO_PKG_VERSION"); + +/// SDK name for identification +pub const SDK_NAME: &str = "switchboard-on-demand"; + +/// Supported Switchboard On-Demand program versions on Solana +pub const SUPPORTED_PROGRAM_VERSIONS: &[&str] = &["0.7.0"]; + +/// Minimum supported Solana version for compatibility +pub const MIN_SOLANA_VERSION: &str = "1.18.0"; + +/// Decimal number utilities for handling Switchboard oracle data +pub mod decimal; +pub use decimal::*; + +/// Small vector types with compact length prefixes for Borsh serialization +pub mod smallvec; + +/// Core oracle functionality for on-demand data feeds +pub mod on_demand; +pub use on_demand::*; + +/// Utility functions and helpers +pub mod utils; +pub use utils::*; + +/// Traits extracted from anchor-lang to avoid dependency conflicts +pub mod anchor_traits; +pub use anchor_traits::*; + +/// Solana program ID constants +pub mod program_id; +pub use program_id::*; + +/// Solana account definitions and parsers +pub mod accounts; +/// Solana instruction builders and processors +pub mod instructions; +/// Common type definitions +pub mod types; + +/// Re-exports of commonly used types and traits for convenience +pub mod prelude; + +/// Solana version compatibility layer +pub mod solana_compat; + +// Re-export everything from solana_compat for internal use +pub use solana_compat::{solana_program, AccountMeta, Instruction, Pubkey, SYSTEM_PROGRAM_ID}; + +// Re-export solana_sdk for client code (when client feature is enabled) +#[cfg(feature = "client")] +pub use solana_compat::solana_sdk; + +/// Solana sysvar utilities +pub mod sysvar; +pub use sysvar::*; + +/// AccountInfo compatibility layer +mod account_info_compat; +pub use account_info_compat::{AccountInfo, AsAccountInfo}; + +cfg_client! { + use anchor_client::solana_sdk::signer::keypair::Keypair; + pub type AnchorClient = anchor_client::Client>; + pub type RpcClient = anchor_client::solana_client::nonblocking::rpc_client::RpcClient; + + /// Client functionality for off-chain interactions with Switchboard On-Demand + /// + /// This module provides comprehensive tools for interacting with the Switchboard + /// Oracle Network and Crossbar API, including: + /// - Gateway and Crossbar API clients + /// - Pull feed management + /// - Oracle job definitions + /// - Transaction builders + /// - Cryptographic utilities + /// + /// Enable this module with the `client` feature flag. + /// + /// Access client functionality via the `client` module to avoid naming conflicts. + /// For example: `use switchboard_on_demand::client::{Gateway, PullFeed};` + pub mod client; + + /// Returns the appropriate Switchboard On-Demand program ID for the current network. + /// + /// This client-compatible version returns anchor_lang::prelude::Pubkey type. + pub fn get_switchboard_on_demand_program_id() -> anchor_lang::prelude::Pubkey { + use anchor_lang::prelude::Pubkey; + if is_devnet() { + Pubkey::from(crate::ON_DEMAND_DEVNET_PID.to_bytes()) + } else { + Pubkey::from(crate::ON_DEMAND_MAINNET_PID.to_bytes()) + } } -} - -/// A representation of the data in a pull feed account. -#[repr(C)] -#[account(zero_copy)] -pub struct PullFeedAccountData { - /// The oracle submissions for this feed. - pub submissions: [OracleSubmission; 32], - /// The public key of the authority that can update the feed hash that - /// this account will use for registering updates. - pub authority: Pubkey, - /// The public key of the queue which oracles must be bound to in order to - /// submit data to this feed. - pub queue: Pubkey, - /// SHA-256 hash of the job schema oracles will execute to produce data - /// for this feed. - pub feed_hash: [u8; 32], - /// The slot at which this account was initialized. - pub initialized_at: i64, - pub permissions: u64, - pub max_variance: u64, - pub min_responses: u32, - pub name: [u8; 32], - _padding1: [u8; 2], - pub historical_result_idx: u8, - pub min_sample_size: u8, - pub last_update_timestamp: i64, - pub lut_slot: u64, - _reserved1: [u8; 32], // deprecated - pub result: CurrentResult, - pub max_staleness: u32, - _padding2: [u8; 12], - pub historical_results: [CompactResult; 32], - _ebuf4: [u8; 8], - _ebuf3: [u8; 24], - _ebuf2: [u8; 256], -} -impl PullFeedAccountData { - pub fn discriminator() -> [u8; 8] { - [196, 27, 108, 196, 10, 215, 219, 40] + /// Determines if the devnet environment is enabled for client usage. + pub fn is_devnet() -> bool { + cfg!(feature = "devnet") || std::env::var("SB_ENV").unwrap_or_default() == "devnet" } - /// The median value of the submissions needed for quorom size - pub fn median_value(&self) -> Option { - self.result.value() - } + /// Seed bytes for deriving the Switchboard state account PDA. + pub const STATE_SEED: &[u8] = b"STATE"; - /// The standard deviation of the submissions needed for quorom size - pub fn std_dev(&self) -> Option { - self.result.std_dev() - } + /// Seed bytes for deriving oracle feed statistics account PDAs. + pub const ORACLE_FEED_STATS_SEED: &[u8] = b"OracleFeedStats"; - /// The mean of the submissions needed for quorom size - pub fn mean(&self) -> Option { - self.result.mean() - } + /// Seed bytes for deriving oracle randomness statistics account PDAs. + pub const ORACLE_RANDOMNESS_STATS_SEED: &[u8] = b"OracleRandomnessStats"; - /// The range of the submissions needed for quorom size - pub fn range(&self) -> Option { - self.result.range() - } + /// Seed bytes for deriving oracle statistics account PDAs. + pub const ORACLE_STATS_SEED: &[u8] = b"OracleStats"; - /// The minimum value of the submissions needed for quorom size - pub fn min_value(&self) -> Option { - self.result.min_value() - } + /// Seed bytes for deriving lookup table signer account PDAs. + pub const LUT_SIGNER_SEED: &[u8] = b"LutSigner"; - /// The maximum value of the submissions needed for quorom size - pub fn max_value(&self) -> Option { - self.result.max_value() - } + /// Seed bytes for deriving delegation account PDAs. + pub const DELEGATION_SEED: &[u8] = b"Delegation"; - pub fn median_result_land_slot(&self) -> u64 { - let submission: OracleSubmission = self.submissions[self.result.submission_idx as usize]; - submission.landed_at - } + /// Seed bytes for deriving delegation group account PDAs. + pub const DELEGATION_GROUP_SEED: &[u8] = b"Group"; - pub fn latest_submissions(&self) -> Vec { - let max_landed_at = self - .submissions - .iter() - .map(|s| s.landed_at) - .max() - .unwrap_or(0); - self.submissions - .iter() - .filter(|submission| submission.landed_at == max_landed_at) - .cloned() - .collect() - } + /// Seed bytes for deriving reward pool vault account PDAs. + pub const REWARD_POOL_VAULT_SEED: &[u8] = b"RewardPool"; } diff --git a/programs/switchboard-on-demand/src/macros.rs b/programs/switchboard-on-demand/src/macros.rs index 5e5f9b1fd3..1b38128716 100644 --- a/programs/switchboard-on-demand/src/macros.rs +++ b/programs/switchboard-on-demand/src/macros.rs @@ -152,8 +152,7 @@ macro_rules! blocking_retry { #[macro_export] macro_rules! impl_account_deserialize { ($struct_name:ident) => { - use anchor_client; - use anchor_lang::prelude::{Error, ErrorCode}; + use anchor_client::anchor_lang::prelude::{Error, ErrorCode}; impl anchor_client::anchor_lang::AccountDeserialize for $struct_name { fn try_deserialize(buf: &mut &[u8]) -> Result { @@ -165,7 +164,10 @@ macro_rules! impl_account_deserialize { if $struct_name::discriminator() != given_disc { return Err(ErrorCode::AccountDiscriminatorMismatch.into()); } - Self::try_deserialize_unchecked(buf) + if let Ok(ret) = Self::try_deserialize_unchecked(buf) { + return Ok(ret); + } + Err(ErrorCode::AccountDidNotDeserialize.into()) } fn try_deserialize_unchecked(buf: &mut &[u8]) -> Result { diff --git a/programs/switchboard-on-demand/src/on_demand/accounts/queue.rs b/programs/switchboard-on-demand/src/on_demand/accounts/queue.rs index c9c3ebf6bc..59ee1f3a81 100644 --- a/programs/switchboard-on-demand/src/on_demand/accounts/queue.rs +++ b/programs/switchboard-on-demand/src/on_demand/accounts/queue.rs @@ -147,9 +147,6 @@ impl anchor_lang::Owner for QueueAccountData { #[cfg(feature = "anchor")] impl anchor_lang::ZeroCopy for QueueAccountData {} -#[cfg(feature = "anchor")] -impl anchor_lang::IdlBuild for QueueAccountData {} - impl QueueAccountData { /// Returns the total size of a queue account in bytes pub fn size() -> usize { diff --git a/programs/switchboard-on-demand/src/on_demand/instructions/randomness_commit.rs b/programs/switchboard-on-demand/src/on_demand/instructions/randomness_commit.rs index 3cce865b2e..e495ceacd8 100644 --- a/programs/switchboard-on-demand/src/on_demand/instructions/randomness_commit.rs +++ b/programs/switchboard-on-demand/src/on_demand/instructions/randomness_commit.rs @@ -152,12 +152,10 @@ impl RandomnessCommit { #[cfg(not(feature = "pinocchio"))] fn ix_discriminator(name: &str) -> [u8; 8] { + use crate::solana_compat::hash; let preimage = format!("global:{}", name); let mut sighash = [0u8; 8]; - #[cfg(not(feature = "anchor"))] - let hash_result = solana_program::hash::hash(preimage.as_bytes()); - #[cfg(feature = "anchor")] - let hash_result = anchor_lang::solana_program::hash::hash(preimage.as_bytes()); + let hash_result = hash::hash(preimage.as_bytes()); sighash.copy_from_slice(&hash_result.to_bytes()[..8]); sighash } diff --git a/programs/switchboard-on-demand/src/on_demand/oracle_quote/feed_info.rs b/programs/switchboard-on-demand/src/on_demand/oracle_quote/feed_info.rs index 0587d0ec37..8455e9161d 100644 --- a/programs/switchboard-on-demand/src/on_demand/oracle_quote/feed_info.rs +++ b/programs/switchboard-on-demand/src/on_demand/oracle_quote/feed_info.rs @@ -15,13 +15,48 @@ use crate::prelude::*; /// that is used to validate the quote's freshness against the slot hash sysvar. /// /// Size: 32 bytes -#[derive(Copy, Clone, Debug)] +#[derive(Copy, Clone, Debug, PartialEq, Eq)] #[repr(packed)] pub struct PackedQuoteHeader { /// The 32-byte slot hash that was signed by all oracles in the quote pub signed_slothash: [u8; 32], } +// Custom Borsh implementation for packed struct +impl borsh::BorshSerialize for PackedQuoteHeader { + fn serialize(&self, writer: &mut W) -> std::io::Result<()> { + // Read values without taking references (safe for packed structs) + let slothash = self.signed_slothash; + writer.write_all(&slothash)?; + Ok(()) + } +} + +impl borsh::BorshDeserialize for PackedQuoteHeader { + fn deserialize_reader(reader: &mut R) -> std::io::Result { + let mut signed_slothash = [0u8; 32]; + reader.read_exact(&mut signed_slothash)?; + Ok(Self { signed_slothash }) + } +} + +#[cfg(feature = "anchor")] +impl anchor_lang::AnchorDeserialize for PackedQuoteHeader { + fn deserialize_reader(reader: &mut R) -> std::io::Result { + ::deserialize_reader(reader) + } +} + +#[cfg(feature = "anchor")] +impl anchor_lang::AnchorSerialize for PackedQuoteHeader { + fn serialize(&self, writer: &mut W) -> std::io::Result<()> { + ::serialize(self, writer) + } +} + +#[cfg(feature = "idl-build")] +impl anchor_lang::IdlBuild for PackedQuoteHeader {} + /// Packed feed information containing ID, value, and validation requirements /// /// This structure stores individual feed data within a quote. The layout is optimized @@ -29,17 +64,70 @@ pub struct PackedQuoteHeader { /// by the value and minimum sample requirement. /// /// Size: 49 bytes (32 + 16 + 1) -#[derive(Copy, Clone, Debug)] +#[derive(Copy, Clone, Debug, PartialEq, Eq)] #[repr(packed)] pub struct PackedFeedInfo { /// 32-byte unique identifier for this feed - feed_id: [u8; 32], + pub feed_id: [u8; 32], /// Feed value as a fixed-point integer (scaled by PRECISION) - feed_value: i128, + pub feed_value: i128, /// Minimum number of oracle samples required for this feed to be considered valid - min_oracle_samples: u8, + pub min_oracle_samples: u8, } +// Custom Borsh implementation for packed struct +impl borsh::BorshSerialize for PackedFeedInfo { + fn serialize(&self, writer: &mut W) -> std::io::Result<()> { + // Read values without taking references (safe for packed structs) + let feed_id = self.feed_id; + let feed_value = self.feed_value; + let min_oracle_samples = self.min_oracle_samples; + + writer.write_all(&feed_id)?; + writer.write_all(&feed_value.to_le_bytes())?; + writer.write_all(&[min_oracle_samples])?; + Ok(()) + } +} + +impl borsh::BorshDeserialize for PackedFeedInfo { + fn deserialize_reader(reader: &mut R) -> std::io::Result { + let mut feed_id = [0u8; 32]; + reader.read_exact(&mut feed_id)?; + + let mut value_bytes = [0u8; 16]; + reader.read_exact(&mut value_bytes)?; + let feed_value = i128::from_le_bytes(value_bytes); + + let mut min_samples = [0u8; 1]; + reader.read_exact(&mut min_samples)?; + let min_oracle_samples = min_samples[0]; + + Ok(Self { + feed_id, + feed_value, + min_oracle_samples, + }) + } +} + +#[cfg(feature = "anchor")] +impl anchor_lang::AnchorDeserialize for PackedFeedInfo { + fn deserialize_reader(reader: &mut R) -> std::io::Result { + ::deserialize_reader(reader) + } +} + +#[cfg(feature = "anchor")] +impl anchor_lang::AnchorSerialize for PackedFeedInfo { + fn serialize(&self, writer: &mut W) -> std::io::Result<()> { + ::serialize(self, writer) + } +} + +#[cfg(feature = "idl-build")] +impl anchor_lang::IdlBuild for PackedFeedInfo {} + impl PackedFeedInfo { /// The size in bytes of this packed structure pub const PACKED_SIZE: usize = 49; diff --git a/programs/switchboard-on-demand/src/on_demand/oracle_quote/mod.rs b/programs/switchboard-on-demand/src/on_demand/oracle_quote/mod.rs index 087af26c00..2b1646ed31 100644 --- a/programs/switchboard-on-demand/src/on_demand/oracle_quote/mod.rs +++ b/programs/switchboard-on-demand/src/on_demand/oracle_quote/mod.rs @@ -50,6 +50,13 @@ pub mod quote; pub use quote::*; pub mod quote_verifier; pub use quote_verifier::*; +pub mod instruction_parser; +pub use instruction_parser::*; /// Oracle quote account utilities for Anchor integration -#[cfg(feature = "anchor")] pub mod quote_account; +pub use quote_account::{OracleSignature, SwitchboardQuote}; +/// Extension trait for Anchor account wrappers +#[cfg(feature = "anchor")] +pub mod quote_ext; +#[cfg(feature = "anchor")] +pub use quote_ext::SwitchboardQuoteExt; diff --git a/programs/switchboard-on-demand/src/on_demand/oracle_quote/quote.rs b/programs/switchboard-on-demand/src/on_demand/oracle_quote/quote.rs index 32c80193fd..7f42edc48d 100644 --- a/programs/switchboard-on-demand/src/on_demand/oracle_quote/quote.rs +++ b/programs/switchboard-on-demand/src/on_demand/oracle_quote/quote.rs @@ -409,7 +409,7 @@ impl<'a> OracleQuote<'a> { /// /// Panics if the oracle account buffer is too small or slot validation fails. #[inline(always)] - pub fn write(clock_slot: u64, source: &[u8], queue: &[u8; 32], oracle_account: &AccountInfo) { + pub fn write(clock_slot: u64, source: &[u8], queue: impl AsRef<[u8]>, oracle_account: &AccountInfo) { let mut dst_ref = borrow_mut_account_data!(oracle_account); let dst: &mut [u8] = &mut dst_ref; assert!(dst.len() >= 55); // discriminator(8) + queue(32) + u16 + minimum data (13 bytes) @@ -417,7 +417,7 @@ impl<'a> OracleQuote<'a> { let dst_ptr = dst.as_mut_ptr(); *(dst_ptr as *mut u64) = QUOTE_DISCRIMINATOR_U64_LE; // Copy queue at offset 8 using 4 u64 writes - let queue_ptr = queue.as_ptr() as *const u64; + let queue_ptr = queue.as_ref().as_ptr() as *const u64; let dst_queue_ptr = dst_ptr.add(8) as *mut u64; *dst_queue_ptr = *queue_ptr; *dst_queue_ptr.add(1) = *queue_ptr.add(1); @@ -453,7 +453,7 @@ impl<'a> OracleQuote<'a> { /// # Panics /// Panics if the oracle account buffer is too small for the data. #[inline(always)] - pub fn write_unchecked(source: &[u8], queue: &[u8; 32], oracle_account: &AccountInfo) { + pub fn write_unchecked(source: &[u8], queue: impl AsRef<[u8]>, oracle_account: &AccountInfo) { let mut dst_ref = borrow_mut_account_data!(oracle_account); let dst: &mut [u8] = &mut dst_ref; assert!(dst.len() >= 55); // discriminator(8) + queue(32) + u16 + minimum data (13 bytes) @@ -461,7 +461,7 @@ impl<'a> OracleQuote<'a> { let dst_ptr = dst.as_mut_ptr(); *(dst_ptr as *mut u64) = QUOTE_DISCRIMINATOR_U64_LE; // Copy queue at offset 8 using 4 u64 writes - let queue_ptr = queue.as_ptr() as *const u64; + let queue_ptr = queue.as_ref().as_ptr() as *const u64; let dst_queue_ptr = dst_ptr.add(8) as *mut u64; *dst_queue_ptr = *queue_ptr; *dst_queue_ptr.add(1) = *queue_ptr.add(1); @@ -506,15 +506,16 @@ impl<'a> OracleQuote<'a> { /// # Panics /// Panics if instruction extraction fails, program ID validation fails, or slot validation fails. #[inline(always)] - pub fn write_from_ix<'b, I, O>( + pub fn write_from_ix<'b, I, O, Q>( ix_sysvar: I, oracle_account: O, - queue: &[u8; 32], + queue: Q, curr_slot: u64, instruction_index: usize, ) where I: AsAccountInfo<'b>, O: AsAccountInfo<'b>, + Q: AsRef<[u8]>, { let ix_sysvar = ix_sysvar.as_account_info(); let oracle_account = oracle_account.as_account_info(); @@ -589,14 +590,15 @@ impl<'a> OracleQuote<'a> { /// [`write_from_ix`]: Self::write_from_ix #[inline(always)] #[allow(clippy::missing_safety_doc)] // Safety documentation is comprehensive above - pub fn write_from_ix_unchecked<'b, I, O>( + pub fn write_from_ix_unchecked<'b, I, O, Q>( ix_sysvar: I, oracle_account: O, - queue: &[u8; 32], + queue: Q, instruction_index: usize, ) where I: AsAccountInfo<'b>, O: AsAccountInfo<'b>, + Q: AsRef<[u8]>, { let ix_sysvar = ix_sysvar.as_account_info(); let oracle_account = oracle_account.as_account_info(); @@ -702,7 +704,7 @@ impl<'a> OracleQuote<'a> { program_id: &Pubkey, bump: &[u8], ) -> Pubkey { - use crate::solana_program::syscalls; + use crate::solana_compat::syscalls; let mut seeds: [&[u8]; 10] = [&[]; 10]; let mut len: usize = 0; diff --git a/programs/switchboard-on-demand/src/on_demand/oracle_quote/quote_account.rs b/programs/switchboard-on-demand/src/on_demand/oracle_quote/quote_account.rs index caafd9c601..48f4c9e9a2 100644 --- a/programs/switchboard-on-demand/src/on_demand/oracle_quote/quote_account.rs +++ b/programs/switchboard-on-demand/src/on_demand/oracle_quote/quote_account.rs @@ -1,277 +1,417 @@ +use crate::sysvar::ed25519_sysvar::Ed25519SignatureOffsets; +use crate::smallvec::{SmallVec, U8Prefix, U16Prefix}; +use crate::on_demand::oracle_quote::feed_info::{PackedFeedInfo, PackedQuoteHeader}; +use crate::Pubkey; + pub const QUOTE_DISCRIMINATOR: &[u8; 8] = b"SBOracle"; -#[macro_export] -macro_rules! switchboard_anchor_bindings { - () => { - pub const __QUOTE_OWNER_PIDS: &[Pubkey] = &[ - switchboard_on_demand::QUOTE_PROGRAM_ID, - crate::ID, - ]; - - /// Macro to generate Anchor bindings for Switchboard quote accounts - #[derive(Debug, PartialEq, Eq, Clone, Copy, AnchorDeserialize, AnchorSerialize)] - #[repr(C)] - pub struct SwitchboardQuote { - pub queue: [u8; 32], - pub data: [u8; 1024], - } +/// Oracle signature data with offsets +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[repr(C)] +pub struct OracleSignature { + /// Offsets to locate signature data within instruction + pub offsets: Ed25519SignatureOffsets, + /// ED25519 public key + pub pubkey: Pubkey, + /// ED25519 signature (64 bytes) + pub signature: [u8; 64], +} + +impl borsh::BorshSerialize for OracleSignature { + fn serialize(&self, writer: &mut W) -> std::io::Result<()> { + self.offsets.serialize(writer)?; + writer.write_all(self.pubkey.as_ref())?; + writer.write_all(&self.signature)?; + Ok(()) + } +} + +impl borsh::BorshDeserialize for OracleSignature { + fn deserialize_reader(reader: &mut R) -> std::io::Result { + let offsets = Ed25519SignatureOffsets::deserialize_reader(reader)?; + let mut pubkey_bytes = [0u8; 32]; + reader.read_exact(&mut pubkey_bytes)?; + let pubkey = Pubkey::new_from_array(pubkey_bytes); + let mut signature = [0u8; 64]; + reader.read_exact(&mut signature)?; + Ok(Self { + offsets, + pubkey, + signature, + }) + } +} + +#[cfg(feature = "anchor")] +impl anchor_lang::AnchorDeserialize for OracleSignature { + fn deserialize_reader(reader: &mut R) -> std::io::Result { + ::deserialize_reader(reader) + } +} + +#[cfg(feature = "anchor")] +impl anchor_lang::AnchorSerialize for OracleSignature { + fn serialize(&self, writer: &mut W) -> std::io::Result<()> { + ::serialize(self, writer) + } +} + +#[cfg(feature = "idl-build")] +impl anchor_lang::IdlBuild for OracleSignature {} + +/// Switchboard oracle quote account structure +/// +/// # On-chain Layout (excluding 8-byte discriminator): +/// ```text +/// [0..32] queue: Queue pubkey (32 bytes) +/// [34..] signatures: SmallVec of OracleSignature (2-byte u16 length + 110 bytes each) +/// - Ed25519SignatureOffsets (14 bytes) +/// - pubkey (32 bytes) +/// - signature (64 bytes) +/// [..] quote_header: PackedQuoteHeader (32 bytes) +/// [..] feeds: SmallVec of PackedFeedInfo (1-byte u8 length + 49 bytes each) +/// [..] oracle_idxs: SmallVec of oracle indices (1-byte u8 length + u8 each) +/// [..] slot: Slot number (u64, 8 bytes) +/// [..] version: Version (u8, 1 byte) +/// [..] tail_discriminator: "SBOD" (4 bytes) +/// ``` +/// +/// # Length Prefix Sizes +/// - `signatures`: 2-byte (u16) length prefix - allows up to 65535 signatures +/// - `feeds`: 1-byte (u8) length prefix - max 255 feeds +/// - `oracle_idxs`: 1-byte (u8) length prefix - max 255 indices +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct SwitchboardQuote { + /// Queue pubkey that this oracle quote belongs to + pub queue: Pubkey, + /// Uses 2-byte (u16) length prefix + pub signatures: SmallVec, + /// Quote header containing the signed slot hash + pub quote_header: PackedQuoteHeader, + /// Array of feed information (max 255) + /// Uses 1-byte (u8) length prefix + pub feeds: SmallVec, + /// Oracle indices that correspond to the queue's oracle array (max 255) + /// Uses 1-byte (u8) length prefix + pub oracle_idxs: SmallVec, + /// Recent slot from the ED25519 instruction data used for freshness validation + pub slot: u64, + /// Version from the ED25519 instruction data + pub version: u8, + /// Tail discriminator "SBOD" for validation + pub tail_discriminator: [u8; 4], +} + +impl borsh::BorshSerialize for SwitchboardQuote { + fn serialize(&self, writer: &mut W) -> std::io::Result<()> { + writer.write_all(self.queue.as_ref())?; + self.signatures.serialize(writer)?; + self.quote_header.serialize(writer)?; + self.feeds.serialize(writer)?; + self.oracle_idxs.serialize(writer)?; + self.slot.serialize(writer)?; + self.version.serialize(writer)?; + self.tail_discriminator.serialize(writer)?; + Ok(()) + } +} + +impl borsh::BorshDeserialize for SwitchboardQuote { + fn deserialize_reader(reader: &mut R) -> std::io::Result { + let mut queue_bytes = [0u8; 32]; + reader.read_exact(&mut queue_bytes)?; + Ok(Self { + queue: Pubkey::new_from_array(queue_bytes), + signatures: borsh::BorshDeserialize::deserialize_reader(reader)?, + quote_header: borsh::BorshDeserialize::deserialize_reader(reader)?, + feeds: borsh::BorshDeserialize::deserialize_reader(reader)?, + oracle_idxs: borsh::BorshDeserialize::deserialize_reader(reader)?, + slot: borsh::BorshDeserialize::deserialize_reader(reader)?, + version: borsh::BorshDeserialize::deserialize_reader(reader)?, + tail_discriminator: borsh::BorshDeserialize::deserialize_reader(reader)?, + }) + } +} + +#[cfg(feature = "anchor")] +impl anchor_lang::AnchorDeserialize for SwitchboardQuote { + fn deserialize_reader(reader: &mut R) -> std::io::Result { + ::deserialize_reader(reader) + } +} + +#[cfg(feature = "anchor")] +impl anchor_lang::AnchorSerialize for SwitchboardQuote { + fn serialize(&self, writer: &mut W) -> std::io::Result<()> { + ::serialize(self, writer) + } +} + +#[cfg(feature = "anchor")] +impl anchor_lang::Discriminator for SwitchboardQuote { + const DISCRIMINATOR: &[u8] = QUOTE_DISCRIMINATOR; +} + +#[cfg(feature = "anchor")] +impl anchor_lang::AccountSerialize for SwitchboardQuote { + fn try_serialize(&self, writer: &mut W) -> anchor_lang::Result<()> { + use anchor_lang::Discriminator; + + // Write discriminator (8 bytes) + writer.write_all(Self::DISCRIMINATOR)?; + + // Write queue pubkey (32 bytes) + writer.write_all(self.queue.as_ref())?; + + // Serialize the delimited data to a buffer first to get length + let mut delimited_buf = Vec::new(); + borsh::BorshSerialize::serialize(&self.signatures, &mut delimited_buf) + .map_err(|_| anchor_lang::error::ErrorCode::AccountDidNotSerialize)?; + borsh::BorshSerialize::serialize(&self.quote_header, &mut delimited_buf) + .map_err(|_| anchor_lang::error::ErrorCode::AccountDidNotSerialize)?; + borsh::BorshSerialize::serialize(&self.feeds, &mut delimited_buf) + .map_err(|_| anchor_lang::error::ErrorCode::AccountDidNotSerialize)?; + borsh::BorshSerialize::serialize(&self.oracle_idxs, &mut delimited_buf) + .map_err(|_| anchor_lang::error::ErrorCode::AccountDidNotSerialize)?; + borsh::BorshSerialize::serialize(&self.slot, &mut delimited_buf) + .map_err(|_| anchor_lang::error::ErrorCode::AccountDidNotSerialize)?; + borsh::BorshSerialize::serialize(&self.version, &mut delimited_buf) + .map_err(|_| anchor_lang::error::ErrorCode::AccountDidNotSerialize)?; + borsh::BorshSerialize::serialize(&self.tail_discriminator, &mut delimited_buf) + .map_err(|_| anchor_lang::error::ErrorCode::AccountDidNotSerialize)?; + + // Write u16 length prefix + let len = delimited_buf.len() as u16; + writer.write_all(&len.to_le_bytes())?; + + // Write delimited data + writer.write_all(&delimited_buf)?; + + Ok(()) + } +} - unsafe impl bytemuck::Pod for SwitchboardQuote {} - unsafe impl bytemuck::Zeroable for SwitchboardQuote {} +#[cfg(feature = "anchor")] +impl anchor_lang::AccountDeserialize for SwitchboardQuote { + fn try_deserialize(buf: &mut &[u8]) -> anchor_lang::Result { + use anchor_lang::Discriminator; + use crate::on_demand::oracle_quote::instruction_parser::ParsedEd25519Instruction; - impl Discriminator for SwitchboardQuote { - const DISCRIMINATOR: &[u8] = switchboard_on_demand::quote_account::QUOTE_DISCRIMINATOR; + // Check minimum size: discriminator (8) + queue (32) = 40 bytes minimum + if buf.len() < 40 { + return Err(anchor_lang::error::ErrorCode::AccountDiscriminatorNotFound.into()); } - impl AccountSerialize for SwitchboardQuote { - fn try_serialize(&self, writer: &mut W) -> anchor_lang::Result<()> { - writer.write_all(Self::DISCRIMINATOR)?; - writer.write_all(bytemuck::bytes_of(self))?; - Ok(()) - } + // Check discriminator + let given_disc = &buf[..Self::DISCRIMINATOR.len()]; + if given_disc != Self::DISCRIMINATOR { + return Err(anchor_lang::error::ErrorCode::AccountDiscriminatorMismatch.into()); } - impl AccountDeserialize for SwitchboardQuote { - fn try_deserialize(buf: &mut &[u8]) -> anchor_lang::Result { - if buf.len() < Self::DISCRIMINATOR.len() { - return Err(anchor_lang::error::ErrorCode::AccountDiscriminatorNotFound.into()); - } - let given_disc = &buf[..Self::DISCRIMINATOR.len()]; - if given_disc != Self::DISCRIMINATOR { - return Err(anchor_lang::error::ErrorCode::AccountDiscriminatorMismatch.into()); - } - *buf = &buf[Self::DISCRIMINATOR.len()..]; - Self::try_deserialize_unchecked(buf) - } - - fn try_deserialize_unchecked(buf: &mut &[u8]) -> anchor_lang::Result { - if buf.len() < std::mem::size_of::() { - return Err(anchor_lang::error::ErrorCode::AccountDidNotSerialize.into()); - } - let data = bytemuck::try_from_bytes(&buf[..std::mem::size_of::()]) - .map_err(|_| anchor_lang::error::ErrorCode::AccountDidNotDeserialize)?; - *buf = &buf[std::mem::size_of::()..]; - Ok(*data) - } + // Extract queue pubkey (bytes 8-40) + let queue = Pubkey::new_from_array(buf[8..40].try_into().unwrap()); + + // Parse length-delimited ED25519 instruction data starting at byte 40 + let data = &buf[40..]; + if data.len() < 2 { + return Err(anchor_lang::error::ErrorCode::AccountDidNotDeserialize.into()); } - impl SwitchboardQuote { - pub const LEN: usize = 32 + 1024 + 8; - - /// Extracts feed information from the oracle quote data - /// - /// Parses the stored oracle quote data and returns a slice of PackedFeedInfo - /// structures containing feed IDs, values, and minimum oracle samples. - /// - /// # Returns - /// A slice of PackedFeedInfo structures, or an empty slice if no valid feeds are found - /// - /// # Example - /// ```rust - /// let feeds = quote.feeds(); - /// for feed in feeds { - /// println!("Feed {}: {}", feed.hex_id(), feed.value()); - /// } - /// ``` - pub fn feeds(&self) -> &[switchboard_on_demand::on_demand::oracle_quote::feed_info::PackedFeedInfo] { - use core::ptr::read_unaligned; - - // Check if we have enough data for length prefix - if self.data.len() < 2 { - return &[]; - } - - unsafe { - // Read the length prefix (first 2 bytes) - let data_len = read_unaligned(self.data.as_ptr() as *const u16) as usize; - - // Ensure we have enough data - if self.data.len() < data_len + 2 || data_len < 13 { - return &[]; - } - - // Skip the length prefix and parse the ED25519 instruction data - let instruction_data = &self.data[2..data_len + 2]; - - // Parse the instruction to extract feed information - match switchboard_on_demand::sysvar::ed25519_sysvar::Ed25519Sysvar::parse_instruction(instruction_data) - { - Ok((parsed_sigs, sig_count, _, _, _)) => { - if sig_count > 0 { - // Get feed info from the first signature - parsed_sigs[0].feed_infos() - } else { - &[] - } - } - Err(_) => &[], - } - } - } - - /// Get the canonical oracle account public key for the given feed IDs - /// - /// This method derives the canonical oracle account that the quote program - /// creates and manages for storing verified oracle data. - /// - /// ## Parameters - /// - `feed_ids`: Array of feed ID byte arrays (32 bytes each) - /// - `program_id`: The quote program ID to use for derivation - /// - /// ## Returns - /// The canonical oracle account public key - /// - /// ## Example - /// ```rust - /// let oracle_key = SwitchboardQuote::get_canonical_key(&queue_key, &[feed_id_bytes], "e_program_id); - /// ``` - pub fn get_canonical_key(queue_key: &Pubkey, feed_ids: &[&[u8; 32]], program_id: &Pubkey) -> Pubkey { - let mut seeds: Vec<&[u8]> = Vec::with_capacity(feed_ids.len() + 1); - seeds.push(queue_key.as_ref()); - for id in feed_ids { - seeds.push(id.as_slice()); - } - let (oracle_account, _) = Pubkey::find_program_address(&seeds, program_id); - oracle_account - } - - /// Get the canonical oracle account for this quote's feeds - /// - /// Convenience method that extracts feed IDs from the current quote - /// and derives the canonical oracle account using the provided owner. - /// - /// ## Parameters - /// - `queue_key`: The queue public key to use as the first seed - /// - `owner`: The program ID that owns this oracle account (usually the quote program) - /// - /// ## Returns - /// The canonical oracle account public key for this quote's feeds - /// - /// ## Example - /// ```rust - /// let canonical_key = quote.canonical_key(&queue_key, &oracle_account.owner); - /// ``` - pub fn canonical_key(&self, queue_key: &Pubkey, owner: &Pubkey) -> Pubkey { - let feed_ids: Vec<&[u8; 32]> = self.feeds().iter().map(|feed| feed.feed_id()).collect(); - Self::get_canonical_key(queue_key, &feed_ids, owner) - } + // Read u16 length prefix + let len = u16::from_le_bytes([data[0], data[1]]) as usize; + if data.len() < len + 2 { + return Err(anchor_lang::error::ErrorCode::AccountDidNotDeserialize.into()); } - impl anchor_lang::Owner for SwitchboardQuote { - fn owner() -> anchor_lang::solana_program::pubkey::Pubkey { - crate::ID - } + // Parse the ED25519 instruction data + let ed25519_data = &data[2..len + 2]; + let parsed = ParsedEd25519Instruction::parse(ed25519_data) + .map_err(|_| anchor_lang::error::ErrorCode::AccountDidNotDeserialize)?; + + // Convert Vec to SmallVec (will fail if exceeds capacity) + let signatures = parsed.signatures.into_iter() + .map(|sig| OracleSignature { + offsets: sig.offsets, + pubkey: Pubkey::new_from_array(sig.pubkey), + signature: sig.signature, + }) + .collect::>() + .try_into() + .map_err(|_| anchor_lang::error::ErrorCode::AccountDidNotDeserialize)?; + + let feeds = parsed.feeds.into_iter() + .collect::>() + .try_into() + .map_err(|_| anchor_lang::error::ErrorCode::AccountDidNotDeserialize)?; + + let oracle_idxs = parsed.oracle_idxs.into_iter() + .collect::>() + .try_into() + .map_err(|_| anchor_lang::error::ErrorCode::AccountDidNotDeserialize)?; + + Ok(Self { + queue, + signatures, + quote_header: parsed.quote_header, + feeds, + oracle_idxs, + slot: parsed.slot, + version: parsed.version, + tail_discriminator: parsed.discriminator, + }) + } + + fn try_deserialize_unchecked(buf: &mut &[u8]) -> anchor_lang::Result { + use crate::on_demand::oracle_quote::instruction_parser::ParsedEd25519Instruction; + + if buf.len() < 40 { + return Err(anchor_lang::error::ErrorCode::AccountDidNotDeserialize.into()); } - impl anchor_lang::ZeroCopy for SwitchboardQuote {} + let full_buf = *buf; + *buf = &[]; // Consume the buffer + + // Extract queue pubkey (bytes 8-40) - skip discriminator check for unchecked + let queue = Pubkey::new_from_array(full_buf[8..40].try_into().unwrap()); + + // Parse length-delimited ED25519 instruction data starting at byte 40 + let data = &full_buf[40..]; + if data.len() < 2 { + return Err(anchor_lang::error::ErrorCode::AccountDidNotDeserialize.into()); + } - impl anchor_lang::Owners for SwitchboardQuote { - fn owners() -> &'static [anchor_lang::solana_program::pubkey::Pubkey] { - __QUOTE_OWNER_PIDS - } + // Read u16 length prefix + let len = u16::from_le_bytes([data[0], data[1]]) as usize; + if data.len() < len + 2 { + return Err(anchor_lang::error::ErrorCode::AccountDidNotDeserialize.into()); } - /// Extension trait to provide convenient methods for Anchor InterfaceAccount - pub trait SwitchboardQuoteExt<'a> { - /// Get the canonical oracle account key for this quote's feeds - fn canonical_key(&self, queue: &Pubkey) -> Pubkey; - // - // /// Get the canonical oracle account key for this quote's feeds with a specific owner - // fn canonical_key_with_owner(&self, owner: &Pubkey) -> Pubkey; - - /// Get the owner of the account - fn owner(&self) -> &Pubkey; - - /// Get feeds from the oracle quote - fn feeds(&self) -> &[switchboard_on_demand::on_demand::oracle_quote::feed_info::PackedFeedInfo]; - - /// Write oracle quote data from an ED25519 instruction with slot validation - fn write_from_ix<'b, I>(&mut self, ix_sysvar: I, curr_slot: u64, instruction_index: usize) - where - I: AsRef>; - - /// Write oracle quote data from an ED25519 instruction without slot validation. - /// - /// # ⚠️ WARNING ⚠️ - /// **This method bypasses critical security validations. See [`OracleQuote::write_from_ix_unchecked`] for detailed security warnings.** - /// - /// [`OracleQuote::write_from_ix_unchecked`]: crate::on_demand::oracle_quote::OracleQuote::write_from_ix_unchecked - fn write_from_ix_unchecked<'b, I>(&mut self, ix_sysvar: I, instruction_index: usize) - where - I: AsRef>; - - /// Check if the account is initialized by checking the last 4 bytes are SBOD - fn is_initialized(&self) -> bool; - - /// if !is_initialized, return if the new quotes canonical key matches the account key - /// else just check if the account key match the new quotes - fn keys_match(&self, quote: &switchboard_on_demand::on_demand::oracle_quote::OracleQuote) -> bool; + // Parse the ED25519 instruction data + let ed25519_data = &data[2..len + 2]; + let parsed = ParsedEd25519Instruction::parse(ed25519_data) + .map_err(|_| anchor_lang::error::ErrorCode::AccountDidNotDeserialize)?; + + // Convert Vec to SmallVec (will fail if exceeds capacity) + let signatures = parsed.signatures.into_iter() + .map(|sig| OracleSignature { + offsets: sig.offsets, + pubkey: Pubkey::new_from_array(sig.pubkey), + signature: sig.signature, + }) + .collect::>() + .try_into() + .map_err(|_| anchor_lang::error::ErrorCode::AccountDidNotDeserialize)?; + + let feeds = parsed.feeds.into_iter() + .collect::>() + .try_into() + .map_err(|_| anchor_lang::error::ErrorCode::AccountDidNotDeserialize)?; + + let oracle_idxs = parsed.oracle_idxs.into_iter() + .collect::>() + .try_into() + .map_err(|_| anchor_lang::error::ErrorCode::AccountDidNotDeserialize)?; + + Ok(Self { + queue, + signatures, + quote_header: parsed.quote_header, + feeds, + oracle_idxs, + slot: parsed.slot, + version: parsed.version, + tail_discriminator: parsed.discriminator, + }) + } +} + +#[cfg(feature = "idl-build")] +impl anchor_lang::IdlBuild for SwitchboardQuote {} + +impl SwitchboardQuote { + /// Maximum serialized size estimate for account initialization + /// This is conservative: queue(32) + max_sigs(2 + 8*110) + quote_header(32) + max_feeds(1 + 8*49) + oracle_idxs(1 + 8) + slot(8) + version(1) + tail(4) + pub const MAX_LEN: usize = 32 + (2 + 8 * 110) + 32 + (1 + 8 * 49) + (1 + 8) + 8 + 1 + 4; + + /// Minimum size for empty quote + pub const MIN_LEN: usize = 32 + 2 + 32 + 1 + 1 + 8 + 1 + 4; + + /// Returns a reference to the feed information array + /// + /// # Example + /// ```rust + /// let feeds = quote.feeds_slice(); + /// for feed in feeds { + /// println!("Feed {}: {}", feed.hex_id(), feed.value()); + /// } + /// ``` + pub fn feeds_slice(&self) -> &[PackedFeedInfo] { + self.feeds.as_slice() + } + + /// Get the canonical oracle account public key for the given feed IDs + /// + /// This method derives the canonical oracle account that the quote program + /// creates and manages for storing verified oracle data. + /// + /// ## Parameters + /// - `queue_key`: The queue public key to use as the first seed + /// - `feed_ids`: Array of feed ID byte arrays (32 bytes each) + /// - `program_id`: The quote program ID to use for derivation + /// + /// ## Returns + /// The canonical oracle account public key + /// + /// ## Example + /// ```rust,ignore + /// let oracle_key = SwitchboardQuote::get_canonical_key(&queue_key, &[feed_id_bytes], "e_program_id); + /// ``` + #[cfg(feature = "anchor")] + pub fn get_canonical_key( + queue_key: &anchor_lang::solana_program::pubkey::Pubkey, + feed_ids: &[&[u8; 32]], + program_id: &anchor_lang::solana_program::pubkey::Pubkey, + ) -> anchor_lang::solana_program::pubkey::Pubkey { + let mut seeds: Vec<&[u8]> = Vec::with_capacity(feed_ids.len() + 1); + seeds.push(queue_key.as_ref()); + for id in feed_ids { + seeds.push(id.as_slice()); } + let (oracle_account, _) = + anchor_lang::solana_program::pubkey::Pubkey::find_program_address(&seeds, program_id); + oracle_account + } + + /// Get the canonical oracle account for this quote's feeds + /// + /// Convenience method that extracts feed IDs from the current quote + /// and derives the canonical oracle account using the provided owner. + /// + /// ## Parameters + /// - `queue_key`: The queue public key to use as the first seed + /// - `owner`: The program ID that owns this oracle account (usually the quote program) + /// + /// ## Returns + /// The canonical oracle account public key for this quote's feeds + /// + /// ## Example + /// ```rust,ignore + /// let canonical_key = quote.canonical_key(&queue_key, &oracle_account.owner); + /// ``` + #[cfg(feature = "anchor")] + pub fn canonical_key( + &self, + queue_key: &anchor_lang::solana_program::pubkey::Pubkey, + owner: &anchor_lang::solana_program::pubkey::Pubkey, + ) -> anchor_lang::solana_program::pubkey::Pubkey { + let feed_ids: Vec<&[u8; 32]> = self.feeds.iter().map(|feed| &feed.feed_id).collect(); + Self::get_canonical_key(queue_key, &feed_ids, owner) + } +} - impl<'info> SwitchboardQuoteExt<'info> - for anchor_lang::prelude::InterfaceAccount<'info, SwitchboardQuote> - { - fn canonical_key(&self, queue: &Pubkey) -> Pubkey { - (**self).canonical_key(queue, self.to_account_info().owner) - } - - fn owner(&self) -> &Pubkey { - self.to_account_info().owner - } - - fn feeds(&self) -> &[switchboard_on_demand::on_demand::oracle_quote::feed_info::PackedFeedInfo] { - (**self).feeds() - } - - fn write_from_ix<'b, I>(&mut self, ix_sysvar: I, curr_slot: u64, instruction_index: usize) - where - I: AsRef>, - { - let ix_sysvar = ix_sysvar.as_ref(); - let data = switchboard_on_demand::Instructions::extract_ix_data(ix_sysvar, instruction_index); - switchboard_on_demand::on_demand::oracle_quote::OracleQuote::write(curr_slot, data, &self.queue, &self.to_account_info()); - } - - fn write_from_ix_unchecked<'b, I>(&mut self, ix_sysvar: I, instruction_index: usize) - where - I: AsRef>, - { - let ix_sysvar = ix_sysvar.as_ref(); - let data = switchboard_on_demand::Instructions::extract_ix_data(ix_sysvar, instruction_index); - switchboard_on_demand::on_demand::oracle_quote::OracleQuote::write_unchecked(data, &self.queue, &self.to_account_info()); - } - - fn is_initialized(&self) -> bool { - static tail_discriminator: u32 = u32::from_le_bytes(*b"SBOD"); - let account_info = self.to_account_info(); - let data = account_info.data.borrow(); - if data.len() < 4 { - return false; - } - if let Ok(last_four) = data[data.len() - 4..].try_into() { - let marker = u32::from_le_bytes(last_four); - marker == tail_discriminator - } else { - false - } - } - - fn keys_match(&self, quote: &switchboard_on_demand::on_demand::oracle_quote::OracleQuote) -> bool { - if !self.is_initialized() { - return false; - } - let own_feeds = self.feeds(); - let other_feeds = quote.feeds(); - if own_feeds.len() != other_feeds.len() { - return false; - } - for i in 0..own_feeds.len() { - if !switchboard_on_demand::check_pubkey_eq(own_feeds[i].feed_id(), other_feeds[i].feed_id()) { - return false; - } - } - true - } - } - }; +#[cfg(feature = "anchor")] +impl anchor_lang::Owner for SwitchboardQuote { + fn owner() -> anchor_lang::solana_program::pubkey::Pubkey { + crate::QUOTE_PROGRAM_ID + } } diff --git a/programs/switchboard-on-demand/src/solana_compat.rs b/programs/switchboard-on-demand/src/solana_compat.rs index 63a75d5fc6..2f9bca72da 100644 --- a/programs/switchboard-on-demand/src/solana_compat.rs +++ b/programs/switchboard-on-demand/src/solana_compat.rs @@ -64,13 +64,28 @@ pub use solana_client_v2 as solana_client; // Re-export common types for easier access pub use solana_program::{ account_info::AccountInfo, - hash, instruction::{AccountMeta, Instruction}, msg, pubkey::{pubkey, Pubkey}, sysvar, }; +// When anchor is enabled, anchor_lang::solana_program doesn't re-export hash and ed25519_program +// So we need to import them directly from solana_program_v2 +#[cfg(feature = "anchor")] +pub use solana_program_v2::{ed25519_program, hash}; + +// When anchor is NOT enabled, solana_program already has these modules +#[cfg(not(feature = "anchor"))] +pub use solana_program::{ed25519_program, hash}; + +// Export syscalls module for on-chain use +#[cfg(all(target_os = "solana", not(feature = "anchor")))] +pub use solana_program::syscalls; + +#[cfg(all(target_os = "solana", feature = "anchor"))] +pub use solana_program_v2::syscalls; + // System program ID constant (same across all versions) pub const SYSTEM_PROGRAM_ID: Pubkey = pubkey!("11111111111111111111111111111111"); diff --git a/programs/switchboard-on-demand/src/sysvar/ed25519_sysvar.rs b/programs/switchboard-on-demand/src/sysvar/ed25519_sysvar.rs index fe8228a0a6..7176d3ca2d 100644 --- a/programs/switchboard-on-demand/src/sysvar/ed25519_sysvar.rs +++ b/programs/switchboard-on-demand/src/sysvar/ed25519_sysvar.rs @@ -32,7 +32,7 @@ pub struct Ed25519SignatureHeader { /// ED25519 signature data offsets within instruction data #[repr(C)] -#[derive(Debug, Copy, Clone)] +#[derive(Debug, Copy, Clone, PartialEq, Eq, borsh::BorshSerialize, borsh::BorshDeserialize)] pub struct Ed25519SignatureOffsets { /// Offset to the signature data pub signature_offset: u16, @@ -50,6 +50,23 @@ pub struct Ed25519SignatureOffsets { pub message_instruction_index: u16, } +#[cfg(feature = "anchor")] +impl anchor_lang::AnchorDeserialize for Ed25519SignatureOffsets { + fn deserialize_reader(reader: &mut R) -> std::io::Result { + ::deserialize_reader(reader) + } +} + +#[cfg(feature = "anchor")] +impl anchor_lang::AnchorSerialize for Ed25519SignatureOffsets { + fn serialize(&self, writer: &mut W) -> std::io::Result<()> { + ::serialize(self, writer) + } +} + +#[cfg(feature = "idl-build")] +impl anchor_lang::IdlBuild for Ed25519SignatureOffsets {} + /// Parsed ED25519 signature data with lifetime-bound references #[derive(Debug, Copy, Clone)] pub struct ParsedEd25519SignatureDataRef<'a> { diff --git a/programs/switchboard-on-demand/src/sysvar/ix_sysvar.rs b/programs/switchboard-on-demand/src/sysvar/ix_sysvar.rs index ce13ec6cb5..77c9aa7baa 100644 --- a/programs/switchboard-on-demand/src/sysvar/ix_sysvar.rs +++ b/programs/switchboard-on-demand/src/sysvar/ix_sysvar.rs @@ -1,10 +1,10 @@ use core::ptr::read_unaligned; -use solana_program::ed25519_program::ID as ED25519_PROGRAM_ID; -use solana_program::sysvar::instructions::ID as INSTRUCTIONS_SYSVAR_ID; +use crate::solana_compat::ed25519_program::ID as ED25519_PROGRAM_ID; +use crate::solana_compat::sysvar::instructions::ID as INSTRUCTIONS_SYSVAR_ID; use crate::{ - borrow_account_data, check_pubkey_eq, get_account_key, solana_program, AsAccountInfo, Pubkey, + borrow_account_data, check_pubkey_eq, get_account_key, AsAccountInfo, Pubkey, }; /// Optimized wrapper for Solana's Instructions sysvar with fast instruction data extraction. diff --git a/programs/switchboard-on-demand/src/utils.rs b/programs/switchboard-on-demand/src/utils.rs index 102e18fa41..49b5876aa3 100644 --- a/programs/switchboard-on-demand/src/utils.rs +++ b/programs/switchboard-on-demand/src/utils.rs @@ -45,7 +45,7 @@ pub fn find_associated_token_address(owner: &Pubkey, mint: &Pubkey) -> Pubkey { pub fn get_ixn_discriminator(ixn_name: &str) -> [u8; 8] { let preimage = format!("global:{}", ixn_name); let mut sighash = [0u8; 8]; - sighash.copy_from_slice(&solana_program::hash::hash(preimage.as_bytes()).to_bytes()[..8]); + sighash.copy_from_slice(&hash::hash(preimage.as_bytes()).to_bytes()[..8]); sighash }