diff --git a/contracts/admin/src/lib.rs b/contracts/admin/src/lib.rs index e6cd500d..e2a7f96f 100644 --- a/contracts/admin/src/lib.rs +++ b/contracts/admin/src/lib.rs @@ -631,10 +631,7 @@ mod tests { super::execute_role_proposal(&env, executor, proposal_id) } - pub fn get_role_proposal( - env: Env, - proposal_id: u64, - ) -> Option { + pub fn get_role_proposal(env: Env, proposal_id: u64) -> Option { super::get_role_proposal(&env, proposal_id) } diff --git a/contracts/admin/src/multisig.rs b/contracts/admin/src/multisig.rs index 54a7d26f..f24b7b73 100644 --- a/contracts/admin/src/multisig.rs +++ b/contracts/admin/src/multisig.rs @@ -456,9 +456,10 @@ pub fn create_role_proposal( soroban_sdk::panic_with_error!(env, AdminError::RoleAlreadyGranted); } let id = create_proposal(env, creator, description); - env.storage() - .instance() - .set(&AdminKey::RoleGrantProposal(id), &RoleGrantAction { role, target }); + env.storage().instance().set( + &AdminKey::RoleGrantProposal(id), + &RoleGrantAction { role, target }, + ); extend_instance_ttl(env); id } @@ -603,7 +604,6 @@ pub fn execute_role_proposal( proposal_id: u64, ) -> Result<(), AdminError> { let _reentrancy_guard = reentrancy_guard::enter(env); - executor.require_auth(); if !get_admin_pool(env).contains(&executor) { return Err(AdminError::UnauthorizedRole); } diff --git a/contracts/admin/src/tests/issue_914_918.rs b/contracts/admin/src/tests/issue_914_918.rs index f6d9b6cd..63d37049 100644 --- a/contracts/admin/src/tests/issue_914_918.rs +++ b/contracts/admin/src/tests/issue_914_918.rs @@ -61,7 +61,9 @@ fn test_role_proposal_requires_quorum_and_executes_the_bound_grant() { ); assert_eq!( client.try_mark_executed(&proposal_id), - Err(Ok(AdminError::RoleProposalRequiresExecution)), + Err(Ok(soroban_sdk::Error::from_contract_error( + AdminError::RoleProposalRequiresExecution as u32, + ))), ); client.approve_proposal(&second_admin, &proposal_id); diff --git a/docs/ACCESS_CONTROL.md b/docs/ACCESS_CONTROL.md index 3f4c2930..63617c41 100644 --- a/docs/ACCESS_CONTROL.md +++ b/docs/ACCESS_CONTROL.md @@ -113,6 +113,8 @@ storage slot, domain-separated by Soroban's storage API. | `Threshold` | `instance()` | `u32` | Approvals required for proposal | | `Proposal(u64)` | `instance()` | `Proposal` | Governance proposal data | | `ProposalIdCounter` | `instance()` | `u64` | Auto-incrementing proposal ID | +| `UpgradeProposal(u64)` | `instance()` | `UpgradeProposal` | Multi-sig WASM upgrade proposal | +| `UpgradeProposalIdCounter` | `instance()` | `u64` | Auto-incrementing upgrade proposal ID | | `SuperAdmin(Address)` | `persistent()` | `bool` | Populated by `migrate_admin` | `instance()` state lives on the contract instance ledger entry (shared TTL). @@ -152,6 +154,8 @@ The table below lists every RBAC-guarded entrypoint across the workspace. | `create_proposal` | Admin-pool member | pool membership + `require_auth` | | `approve_proposal` | Admin-pool member | pool membership + `require_auth` | | `mark_executed` | Admin | `admin.require_auth` (threshold check) | +| `submit_upgrade_proposal` | Admin-pool member | membership check (`Address::require_auth`) | +| `get_upgrade_proposal` | Public read | none | ### Lifecycle module (`contracts/lifecycle`) @@ -309,6 +313,16 @@ if (isZeroAddress(someAddress)) { } ``` +## WASM upgrade proposals + +`submit_upgrade_proposal` starts the multi-sig gated WASM upgrade flow. A +proposal records the submitting pool member, the target 32-byte WASM hash, and a +non-empty description; the creator is recorded as the first approval and the +proposal receives a unique auto-incrementing ID from its own counter (so generic +and upgrade proposal IDs never collide). Submissions by non-pool members, the +zero address, the all-zero WASM hash, or with an empty description are rejected +with typed errors. + ## Source of truth - Role definitions and guards: diff --git a/package-lock.json b/package-lock.json index cd479a5c..f74dfd13 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,7 +12,6 @@ "indexer" ], "devDependencies": { - "@axe-core/playwright": "^4.14.0", "@changesets/cli": "^3.0.3", "husky": "^9.1.7", "lint-staged": "^16.4.0", @@ -20,7 +19,8 @@ "typedoc": "^0.28.20", "typedoc-plugin-markdown": "^4.13.1", "typescript": "^6.0.3", - "vitepress": "^1.6.4" + "vitepress": "^1.6.4", + "@axe-core/playwright": "^4.14.0" } }, "cli": { @@ -49,6 +49,53 @@ "node": ">=18.0.0" } }, + "cli/node_modules/@stellar/js-xdr": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@stellar/js-xdr/-/js-xdr-5.0.0.tgz", + "integrity": "sha512-HBDNKnxr+ecdaEmbZ0mcKkirOF8tXXEbWSw34P3wT40Tn3g+u+cCH17xAWZymzscq8cojHB8340pR8QNVaD32w==", + "license": "Apache-2.0", + "engines": { + "node": ">=22.0.0", + "pnpm": ">=10.0.0" + } + }, + "cli/node_modules/@stellar/stellar-sdk": { + "version": "17.2.0", + "resolved": "https://registry.npmjs.org/@stellar/stellar-sdk/-/stellar-sdk-17.2.0.tgz", + "integrity": "sha512-hGdbvhnOMFwAe+QOAUVPrtLf8U+arO2XG+0osEeY87Ti5scj1R52YSw8HW828gf6UG4PW/jtAlfnyaGCj8t6UA==", + "license": "Apache-2.0", + "dependencies": { + "@exodus/bytes": "^1.15.1", + "@noble/ed25519": "^3.1.0", + "@noble/hashes": "^2.2.0", + "@stellar/js-xdr": "^5.0.0", + "@types/json-schema": "^7.0.15", + "axios": "1.20.0", + "bignumber.js": "^11.1.4", + "commander": "^14.0.3", + "eventsource": "^4.1.0", + "feaxios": "^0.0.23", + "smol-toml": "^1.6.1", + "uint8array-extras": "^1.5.0" + }, + "bin": { + "stellar-contract-bindings-typescript": "bin/stellar-contract-bindings-typescript", + "stellar-js": "bin/stellar-js", + "stellar-sdk": "bin/stellar-js" + }, + "engines": { + "node": ">=22.12.0" + } + }, + "cli/node_modules/@stellar/stellar-sdk/node_modules/commander": { + "version": "14.0.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.3.tgz", + "integrity": "sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw==", + "license": "MIT", + "engines": { + "node": ">=20" + } + }, "cli/node_modules/@types/node": { "version": "26.6.2", "resolved": "https://registry.npmjs.org/@types/node/-/node-26.6.2.tgz", @@ -353,7 +400,6 @@ "integrity": "sha512-fHnALZfbEnODczGk14Y/1YBRApp6UEpZUTexGcMUPzY7RDc7q4HN2Y6jh0KUG8Jo9B+q+wOoQEc3ziR0ErbuFg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@algolia/client-common": "5.59.0", "@algolia/requester-browser-xhr": "5.59.0", @@ -472,22 +518,6 @@ "dev": true, "license": "ISC" }, - "node_modules/@axe-core/playwright": { - "version": "4.14.0", - "resolved": "https://registry.npmjs.org/@axe-core/playwright/-/playwright-4.14.0.tgz", - "integrity": "sha512-SGUhG5PIHd2eMdpgBF2PyQLOhX+qyDR2PT4cmoS4Qk2ak+jX/rrSvst9l0PGv5WTHolKpUMvVmoHpr4cZgf1RQ==", - "dev": true, - "license": "MPL-2.0", - "dependencies": { - "axe-core": "~4.14.0" - }, - "engines": { - "node": ">=22.12.0" - }, - "peerDependencies": { - "playwright-core": ">= 1.0.0" - } - }, "node_modules/@babel/code-frame": { "version": "7.29.7", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz", @@ -519,7 +549,6 @@ "integrity": "sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/code-frame": "^7.29.7", "@babel/generator": "^7.29.7", @@ -1497,7 +1526,6 @@ } ], "license": "MIT", - "peer": true, "engines": { "node": ">=18" }, @@ -1521,7 +1549,6 @@ } ], "license": "MIT", - "peer": true, "engines": { "node": ">=18" } @@ -1588,6 +1615,50 @@ } } }, + "node_modules/@docsearch/js/node_modules/@types/react": { + "version": "18.3.31", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.31.tgz", + "integrity": "sha512-vfEqpXTvwT91yhmwdfouStN2hSKwTvyRs8qpLfADyrq/kxDw0hZM7Wk9Ug1FELj8hIby+S/+kQCSRFF32nv2Qw==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "@types/prop-types": "*", + "csstype": "^3.2.2" + } + }, + "node_modules/@docsearch/js/node_modules/react": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", + "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "loose-envify": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@docsearch/js/node_modules/react-dom": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", + "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.2" + }, + "peerDependencies": { + "react": "^18.3.1" + } + }, "node_modules/@docsearch/js/node_modules/scheduler": { "version": "0.23.2", "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", @@ -1595,10 +1666,34 @@ "dev": true, "license": "MIT", "optional": true, + "peer": true, "dependencies": { "loose-envify": "^1.1.0" } }, + "node_modules/@emnapi/core": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz", + "integrity": "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/wasi-threads": "1.2.1", + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/runtime": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.10.0.tgz", + "integrity": "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, "node_modules/@emnapi/wasi-threads": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz", @@ -2206,6 +2301,23 @@ "node": "^20.19.0 || ^22.13.0 || >=24" } }, + "node_modules/@exodus/bytes": { + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/@exodus/bytes/-/bytes-1.16.0.tgz", + "integrity": "sha512-IcpW84uEn3N7ETtNZMlxKhfl6Pec8rUNGOTBtWbK1FKhJxIFAptZyVrvVRVBimAJxJCgc3PxepxkdWWG4DVzfA==", + "license": "MIT", + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + }, + "peerDependencies": { + "@noble/hashes": "^1.8.0 || ^2.0.0" + }, + "peerDependenciesMeta": { + "@noble/hashes": { + "optional": true + } + } + }, "node_modules/@gerrit0/mini-shiki": { "version": "3.23.0", "resolved": "https://registry.npmjs.org/@gerrit0/mini-shiki/-/mini-shiki-3.23.0.tgz", @@ -5601,7 +5713,6 @@ "integrity": "sha512-yzr2S9HyAIdhz2/6qHgbs665Q7PKVcDF05vsOlHPxG1mo36gKVesdYVeDLnXgfjJ03CrKRk08knc6+E/9m8v2Q==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/code-frame": "^7.10.4", "@babel/runtime": "^7.12.5", @@ -5949,7 +6060,6 @@ "integrity": "sha512-yOriVnggzrnQ3a9OKOCxaVuSug3w3/SbOj5i7VwXWZEyUNl3bLF9V3MfxGbZKuwqJOQyRfqXyROBB1CoZLFWzA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@types/node": "*", "@types/tough-cookie": "*", @@ -5960,7 +6070,6 @@ "version": "7.0.15", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", - "dev": true, "license": "MIT" }, "node_modules/@types/linkify-it": { @@ -6035,7 +6144,8 @@ "integrity": "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==", "dev": true, "license": "MIT", - "optional": true + "optional": true, + "peer": true }, "node_modules/@types/qs": { "version": "6.15.1", @@ -6057,7 +6167,6 @@ "integrity": "sha512-N0rFCuH9YoxG9/m61l9MfpJKfmLOVU0em7ipIz6TRgSSkvReLB9vL85GB+yr8Bs5leqpvg96JSwF4ZS1s4viQg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "csstype": "^3.2.2" } @@ -6068,7 +6177,6 @@ "integrity": "sha512-ZI7bU42mZXXKHn/qNLEw2IrbiINU7X5+vfgdixBHkCNpYWXjKgfQ/P+uyGb5CjOLB9UcnTeg3rylQtV2hym44Q==", "dev": true, "license": "MIT", - "peer": true, "peerDependencies": { "@types/react": "^19.3.0" } @@ -6199,7 +6307,6 @@ "integrity": "sha512-nO974WLllwhSFWQXnMLj6nDGa8f0khKEz1JzpPJ1u7Vm/4X1X6ZHajpoknU4bb41vJyMB0HHVyS2GqdhWfIXZw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "8.70.1", "@typescript-eslint/types": "8.70.1", @@ -7535,7 +7642,6 @@ "integrity": "sha512-xRQbDb9BnwDafYNn6Vwl839DYVjqXYb1XVGtWAZ1kcDc6iwAL4hg3B1dZlRiuENFeO2H53gFG3in621AdERVAg==", "dev": true, "license": "MIT", - "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -7557,9 +7663,7 @@ "version": "6.0.2", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "dev": true, "license": "MIT", - "optional": true, "dependencies": { "debug": "4" }, @@ -7629,7 +7733,6 @@ "integrity": "sha512-wUXzaeI7B526W4y1gFg3lcxgDZ67XSgRJIiellYWOas/pLpO7rOtxm9Gr2E/C8aiSDXIgx1q5TdSsvK67Uakqw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@algolia/abtesting": "1.25.0", "@algolia/client-abtesting": "5.59.0", @@ -7936,9 +8039,7 @@ "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", - "dev": true, - "license": "MIT", - "optional": true + "license": "MIT" }, "node_modules/atomically": { "version": "2.1.1", @@ -7976,6 +8077,18 @@ "node": ">=4" } }, + "node_modules/axios": { + "version": "1.20.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.20.0.tgz", + "integrity": "sha512-r8aOh8j9cGKpgQAqpzrUHnSIc6a59Y3Xf/cv8sy1DrHCkZHzQGEuoq1tARk6qSyDdtQGSDgpb9kFlruzPvrgwg==", + "license": "MIT", + "dependencies": { + "follow-redirects": "^1.16.0", + "form-data": "^4.0.6", + "https-proxy-agent": "^5.0.1", + "proxy-from-env": "^2.1.0" + } + }, "node_modules/babel-jest": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.7.0.tgz", @@ -8240,7 +8353,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "baseline-browser-mapping": "^2.10.42", "caniuse-lite": "^1.0.30001803", @@ -8748,9 +8860,7 @@ "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "dev": true, "license": "MIT", - "optional": true, "dependencies": { "delayed-stream": "~1.0.0" }, @@ -9195,9 +9305,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", - "dev": true, "license": "MIT", - "optional": true, "engines": { "node": ">=0.4.0" } @@ -9613,7 +9721,6 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", - "dev": true, "license": "MIT", "dependencies": { "es-errors": "^1.3.0", @@ -9736,7 +9843,6 @@ "integrity": "sha512-P7a6UEEqb9G95MYAtqkmsTbVXIYyzIfl6NGOIJk162PaahFxFyeGcrlXYFSiagECg4sEm8IseJdZBKR3rx6MsQ==", "dev": true, "license": "MIT", - "peer": true, "workspaces": [ "packages/*" ], @@ -10435,7 +10541,6 @@ "integrity": "sha512-/yNdlIkpWbM0ptxno3ONTuf+2g318kh2ez3KSeZN5dZ8YC6AAmgeWz+GasYYiBJPFaYcSAPeu4GfhUaChzIJXA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "tabbable": "^6.4.0" } @@ -10444,7 +10549,6 @@ "version": "1.16.1", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.16.1.tgz", "integrity": "sha512-FNvFGzoMLWmE6Yj9spb/zjd7yiNCHiAW9/Tg9CXrQ8wuu32HtlJOwWO11OJafl5FfY3DxTdQ0vj42zU1kvv5jg==", - "dev": true, "funding": [ { "type": "individual", @@ -10452,7 +10556,6 @@ } ], "license": "MIT", - "optional": true, "engines": { "node": ">=4.0" }, @@ -10512,9 +10615,7 @@ "version": "4.0.6", "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.6.tgz", "integrity": "sha512-vKatAh4SlVfgbv+YtmhiRjhEMJsYpsG1Y2rMQtR+SVSbytsSD1YGzDIcrAJmdFec88u/+VoGmxnl+80gL1tRCQ==", - "dev": true, "license": "MIT", - "optional": true, "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", @@ -10904,7 +11005,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", - "dev": true, "license": "MIT", "dependencies": { "has-symbols": "^1.0.3" @@ -11089,9 +11189,7 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", - "dev": true, "license": "MIT", - "optional": true, "dependencies": { "agent-base": "6", "debug": "4" @@ -11935,7 +12033,6 @@ "integrity": "sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@jest/core": "^29.7.0", "@jest/types": "^29.6.3", @@ -12802,7 +12899,6 @@ "integrity": "sha512-Cvc9WUhxSMEo4McES3P7oK3QaXldCfNWp7pl2NNeiIFlCoLr3kfq9kb1fxftiwk1FLV7CvpvDfonxtzUDeSOPg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "cssstyle": "^4.2.1", "data-urls": "^5.0.0", @@ -12943,7 +13039,6 @@ "integrity": "sha512-CYDD3SOtsHtyXeEORYRx2qBtpDJFjRTGXUtmNEMGyzYOKj1TE3tycdlho7kA1Ufx9OYWZzg52QFBGALTirzDSw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@keyv/serialize": "^1.1.1" } @@ -13042,6 +13137,7 @@ "os": [ "android" ], + "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -13063,6 +13159,7 @@ "os": [ "darwin" ], + "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -13084,6 +13181,7 @@ "os": [ "darwin" ], + "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -13105,6 +13203,7 @@ "os": [ "freebsd" ], + "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -13126,6 +13225,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -13147,6 +13247,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -13168,6 +13269,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -13189,6 +13291,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -13210,6 +13313,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -13231,6 +13335,7 @@ "os": [ "win32" ], + "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -13252,6 +13357,7 @@ "os": [ "win32" ], + "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -14859,7 +14965,6 @@ "integrity": "sha512-rYCsBF/M5HjUch52bbtVONEFjv6Xu8sm8h72dNlR5bzIE1fvC/bxgspzkjSfU+MweEMmPM8KJebG6nnyxo5mCg==", "dev": true, "license": "Apache-2.0", - "peer": true, "bin": { "playwright-core": "cli.js" }, @@ -14897,7 +15002,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "nanoid": "^3.3.18", "picocolors": "^1.1.1", @@ -14942,7 +15046,6 @@ "integrity": "sha512-Z/CJHIkdujO/OtN7nXUii0Rf3VT5SRuhjBA82Xvu2XhBUgX3nhP67T0LHceBdQLex7OOFGTox+Q5Yg8Jk2Qivg==", "dev": true, "license": "MIT", - "peer": true, "bin": { "prettier": "bin/prettier.cjs" }, @@ -14995,7 +15098,6 @@ "devOptional": true, "hasInstallScript": true, "license": "Apache-2.0", - "peer": true, "dependencies": { "@prisma/engines": "5.22.0" }, @@ -15063,9 +15165,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-2.1.0.tgz", "integrity": "sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==", - "dev": true, "license": "MIT", - "optional": true, "engines": { "node": ">=10" } @@ -15173,7 +15273,6 @@ "integrity": "sha512-E8LUcbtBWt20bbl2YoHfx4ZDBdxVTfOKtCZn9cDSJ4l6/nuoApcpIBcj47t2wZoVX8g2ZHuMHbiShgCR1T5Sog==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=0.10.0" } @@ -15264,7 +15363,6 @@ "integrity": "sha512-JDk8dgif51OjFoDE70+OT9ICyYr+69HlmihNwp1+Nsfbna3t5sIiCa9ZJktDmQ4/1b/rn26hIAR2uYXDMr5r0Q==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "scheduler": "^0.28.0" }, @@ -15564,7 +15662,6 @@ "integrity": "sha512-T5vnZ2y4QqC3/4P+w2+JO+Q/OVdnPsv4XcSYJYMEn0R9/jjl5AgLwO9LAZMzP2lN71O6pypn91rB7lDstUkfrQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@types/estree": "1.0.9" }, @@ -16252,7 +16349,6 @@ "integrity": "sha512-NeEmukMWPA5OqHizUkQtxCIhGt7MUZLPY4FFgpC0LNiipjrac/oKpH0TxI+9Zc+vI5+IoN+NiskOmBP7gtYfmA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@storybook/global": "^5.0.0", "@storybook/icons": "^2.0.2", @@ -17013,7 +17109,6 @@ "integrity": "sha512-GQHnkIfxyx1wYCOS/wonik5MVRZU9hi1TEZmzGZSCJB1y9YgoZ8H6itNE/u4suE+yLmOzuE4E5S4TZ/ZX2wcWQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "esbuild": "~0.28.0" }, @@ -17238,7 +17333,6 @@ "integrity": "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==", "dev": true, "license": "Apache-2.0", - "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -17602,7 +17696,6 @@ "integrity": "sha512-lhZBVvEHefgE+HQZC9O7EBJgCU/nVzFNl7vkS4RE0APtWLP02/8QVIkQtzBxPquh7lq5/78NHipTj7ODQ6XuyQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "lightningcss": "^1.33.0", "picomatch": "^4.0.7", @@ -18178,7 +18271,6 @@ "integrity": "sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "esbuild": "^0.21.3", "postcss": "^8.4.43", @@ -18239,7 +18331,6 @@ "integrity": "sha512-iA95lQbKEkvrtTkdAgnWbXfbipWiiWe/hDl2P5tMi6WFwD76G0NxXAGp/M9EOcYupeGJRr6wppMc7CoA41TQjg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@types/chai": "^5.2.2", "@vitest/mocker": "5.0.1", @@ -18343,7 +18434,6 @@ "integrity": "sha512-o5qZoksdnjIKvW1srZ3ab7pcDNYAerBjRe54D0LBLfRdCYFrSgBHVXokMas35czQc0//lmx4/tuY4ZNQ+Rf2Ng==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@vue/compiler-dom": "3.5.43", "@vue/compiler-sfc": "3.5.43", @@ -18768,7 +18858,6 @@ "integrity": "sha512-3NxN8+78OdzbT7C/WjGsyfPAtJaN3FNDsWxv7Y7mcDsT/oOmgW8BpyQQFFBnvZE3j9Y2Sdz1ULFLezL7Eb2yFw==", "dev": true, "license": "ISC", - "peer": true, "bin": { "yaml": "bin.mjs" }, @@ -18827,7 +18916,6 @@ "integrity": "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==", "dev": true, "license": "MIT", - "peer": true, "funding": { "url": "https://github.com/sponsors/colinhacks" } @@ -19869,7 +19957,6 @@ "dev": true, "hasInstallScript": true, "license": "MIT", - "peer": true, "bin": { "esbuild": "bin/esbuild" }, @@ -20972,7 +21059,6 @@ "version": "10.1.8", "dev": true, "license": "MIT", - "peer": true, "bin": { "eslint-config-prettier": "bin/cli.js" }, @@ -21032,6 +21118,22 @@ "version": "7.24.6", "dev": true, "license": "MIT" + }, + "node_modules/@axe-core/playwright": { + "version": "4.14.0", + "resolved": "https://registry.npmjs.org/@axe-core/playwright/-/playwright-4.14.0.tgz", + "integrity": "sha512-SGUhG5PIHd2eMdpgBF2PyQLOhX+qyDR2PT4cmoS4Qk2ak+jX/rrSvst9l0PGv5WTHolKpUMvVmoHpr4cZgf1RQ==", + "dev": true, + "license": "MPL-2.0", + "dependencies": { + "axe-core": "~4.14.0" + }, + "engines": { + "node": ">=22.12.0" + }, + "peerDependencies": { + "playwright-core": ">= 1.0.0" + } } } } diff --git a/react/e2e/roles.spec.ts b/react/e2e/roles.spec.ts index 699d4f40..1cb9ed7f 100644 --- a/react/e2e/roles.spec.ts +++ b/react/e2e/roles.spec.ts @@ -1,9 +1,16 @@ // SPDX-License-Identifier: MIT -import { test, expect } from '@playwright/test'; -import { installFreighterStub, installNetworkStubs, MOCK_PUBLIC_KEY, MOCK_TX_HASH } from './stubs'; - -test.describe('Role Management flow', () => { - test('looks up address, asserts badges, and grants minter role', async ({ page }) => { +import { test, expect } from "@playwright/test"; +import { + installFreighterStub, + installNetworkStubs, + MOCK_PUBLIC_KEY, + MOCK_TX_HASH, +} from "./stubs"; + +test.describe("Role Management flow", () => { + test("looks up address, asserts badges, and grants minter role", async ({ + page, + }) => { let minterGranted = true; await installFreighterStub(page, MOCK_PUBLIC_KEY); @@ -16,91 +23,122 @@ test.describe('Role Management flow', () => { }, }); - await page.goto('/#/'); - await page.getByTestId('connect-freighter').click(); - await expect(page.getByTestId('connected-wallet')).toBeVisible(); + await page.goto("/#/"); + await page.getByTestId("connect-freighter").click(); + await expect(page.getByTestId("connected-wallet")).toBeVisible(); - await page.getByTestId('nav-roles').click(); + await page.getByTestId("nav-roles").click(); // Heading assertion - must fail if missing - await expect(page.getByRole('heading', { name: 'Role Management' })).toBeVisible(); + await expect( + page.getByRole("heading", { name: "Role Management" }), + ).toBeVisible(); // Type target address const targetInput = page.locator('input[name="target"]'); - await targetInput.fill('GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWHF'); + await targetInput.fill( + "GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWHF", + ); // Assert minter and super-admin badges are shown - const minterBadge = page.getByTestId('role-badge-Minter'); - const superAdminBadge = page.getByTestId('role-badge-SuperAdmin'); + const minterBadge = page.getByTestId("role-badge-Minter"); + const superAdminBadge = page.getByTestId("role-badge-SuperAdmin"); await expect(minterBadge).toBeVisible(); - await expect(minterBadge).toContainText('Minter: Granted'); + await expect(minterBadge).toContainText("Minter: Granted"); await expect(superAdminBadge).toBeVisible(); - await expect(superAdminBadge).toContainText('SuperAdmin: Granted'); + await expect(superAdminBadge).toContainText("SuperAdmin: Granted"); // Click grant minter button - const grantMinterBtn = page.getByTestId('grant-minter'); + const grantMinterBtn = page.getByTestId("grant-minter"); await expect(grantMinterBtn).toBeEnabled(); await grantMinterBtn.click(); // Assert success alert or badge update - await expect(page.locator('text=Grant Minter succeeded')).toBeVisible(); - await expect(minterBadge).toContainText('Minter: Granted'); + await expect(page.locator("text=Grant Minter succeeded")).toBeVisible(); + await expect(minterBadge).toContainText("Minter: Granted"); }); }); -*/ -test.describe('RolesScreen Role Actions (#1256)', () => { +test.describe("RolesScreen Role Actions (#1256)", () => { test.beforeEach(async ({ page }) => { // Navigate to the roles management screen - await page.goto('/roles'); + await page.goto("/roles"); }); - test('should successfully grant minter role, open confirmation, submit, and toggle badge to Granted', async ({ page }) => { + test("should successfully grant minter role, open confirmation, submit, and toggle badge to Granted", async ({ + page, + }) => { // Input target address for grant action - const addressInput = page.locator('input[name="minterAddress"], [data-testid="minter-address-input"]'); - await addressInput.fill('GB7X6Y8Z...MOCKVALIDADDRESS'); + const addressInput = page.locator( + 'input[name="minterAddress"], [data-testid="minter-address-input"]', + ); + await addressInput.fill("GB7X6Y8Z...MOCKVALIDADDRESS"); // Click Grant Minter action trigger - const grantTriggerBtn = page.locator('button:has-text("Grant Minter"), [data-testid="grant-minter-btn"]'); + const grantTriggerBtn = page.locator( + 'button:has-text("Grant Minter"), [data-testid="grant-minter-btn"]', + ); await grantTriggerBtn.click(); // Verify confirmation modal opens - const confirmationModal = page.locator('[role="dialog"], .confirmation-modal'); + const confirmationModal = page.locator( + '[role="dialog"], .confirmation-modal', + ); await expect(confirmationModal).toBeVisible(); - await expect(confirmationModal).toContainText(/Confirm Transaction|Grant Minter/i); + await expect(confirmationModal).toContainText( + /Confirm Transaction|Grant Minter/i, + ); // Confirm transaction inside modal - const confirmBtn = confirmationModal.locator('button:has-text("Confirm"), button:has-text("Approve")'); + const confirmBtn = confirmationModal.locator( + 'button:has-text("Confirm"), button:has-text("Approve")', + ); await confirmBtn.click(); // Verify success alert and badge state transition to 'Granted' - const statusBadge = page.locator('[data-testid="minter-status"], .badge-granted'); + const statusBadge = page.locator( + '[data-testid="minter-status"], .badge-granted', + ); await expect(statusBadge).toBeVisible(); await expect(statusBadge).toHaveText(/Granted/i); }); - test('should successfully revoke minter role with confirmation dialog and badge update', async ({ page }) => { + test("should successfully revoke minter role with confirmation dialog and badge update", async ({ + page, + }) => { // Locate existing minter and click Revoke - const revokeTriggerBtn = page.locator('button:has-text("Revoke Minter"), [data-testid="revoke-minter-btn"]').first(); + const revokeTriggerBtn = page + .locator( + 'button:has-text("Revoke Minter"), [data-testid="revoke-minter-btn"]', + ) + .first(); await revokeTriggerBtn.click(); // Verify confirmation modal opens - const confirmationModal = page.locator('[role="dialog"], .confirmation-modal'); + const confirmationModal = page.locator( + '[role="dialog"], .confirmation-modal', + ); await expect(confirmationModal).toBeVisible(); await expect(confirmationModal).toContainText(/Revoke|Confirm/i); // Confirm revocation - const confirmRevokeBtn = confirmationModal.locator('button:has-text("Confirm"), button:has-text("Revoke")'); + const confirmRevokeBtn = confirmationModal.locator( + 'button:has-text("Confirm"), button:has-text("Revoke")', + ); await confirmRevokeBtn.click(); // Verify badge updates to Revoked / Inactive - const statusBadge = page.locator('[data-testid="minter-status"], .badge-revoked').first(); + const statusBadge = page + .locator('[data-testid="minter-status"], .badge-revoked') + .first(); await expect(statusBadge).toHaveText(/Revoked|Inactive|Not Granted/i); }); - test('should display helpful UI alerts when wallet is disconnected or unauthenticated', async ({ page }) => { + test("should display helpful UI alerts when wallet is disconnected or unauthenticated", async ({ + page, + }) => { // Simulate disconnected state by clearing session/local storage await page.evaluate(() => { window.localStorage.clear(); @@ -109,8 +147,12 @@ test.describe('RolesScreen Role Actions (#1256)', () => { await page.reload(); // Verify unauthenticated alert or connect wallet prompt is surfaced - const alertBanner = page.locator('[role="alert"], .wallet-disconnected-alert'); + const alertBanner = page.locator( + '[role="alert"], .wallet-disconnected-alert', + ); await expect(alertBanner).toBeVisible(); - await expect(alertBanner).toContainText(/connect wallet|unauthenticated|please connect/i); + await expect(alertBanner).toContainText( + /connect wallet|unauthenticated|please connect/i, + ); }); -}); \ No newline at end of file +}); diff --git a/react/e2e/transfer.spec.ts b/react/e2e/transfer.spec.ts index 6c96b1ce..83acc0c4 100644 --- a/react/e2e/transfer.spec.ts +++ b/react/e2e/transfer.spec.ts @@ -1,143 +1,198 @@ // SPDX-License-Identifier: MIT -import { test, expect } from '@playwright/test'; -import { installFreighterStub, installNetworkStubs, MOCK_PUBLIC_KEY, MOCK_TX_HASH } from './stubs'; - -test.describe('Transfer Tokens flow', () => { - test('submits valid transfer and shows success hash', async ({ page }) => { +import { test, expect } from "@playwright/test"; +import { + installFreighterStub, + installNetworkStubs, + MOCK_PUBLIC_KEY, + MOCK_TX_HASH, +} from "./stubs"; + +test.describe("Transfer Tokens flow", () => { + test("submits valid transfer and shows success hash", async ({ page }) => { await installFreighterStub(page, MOCK_PUBLIC_KEY); await installNetworkStubs(page, { balance: 1000n }); - await page.goto('/#/'); - await page.getByTestId('connect-freighter').click(); - await expect(page.getByTestId('connected-wallet')).toBeVisible(); + await page.goto("/#/"); + await page.getByTestId("connect-freighter").click(); + await expect(page.getByTestId("connected-wallet")).toBeVisible(); - await page.getByTestId('nav-transfer').click(); + await page.getByTestId("nav-transfer").click(); // Heading assertion - must fail if missing - await expect(page.getByRole('heading', { name: 'Transfer Tokens' })).toBeVisible(); + await expect( + page.getByRole("heading", { name: "Transfer Tokens" }), + ).toBeVisible(); // Fill destination and amount - await page.locator('#transfer-destination').fill('GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWHF'); - await page.locator('#transfer-amount').fill('100'); + await page + .locator("#transfer-destination") + .fill("GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWHF"); + await page.locator("#transfer-amount").fill("100"); // Submit and assert success state - const submitBtn = page.getByTestId('transfer-submit'); + const submitBtn = page.getByTestId("transfer-submit"); await expect(submitBtn).toBeEnabled(); await submitBtn.click(); - const successAlert = page.getByTestId('transfer-success'); + const successAlert = page.getByTestId("transfer-success"); await expect(successAlert).toBeVisible(); await expect(successAlert).toContainText(MOCK_TX_HASH); }); - test('disables submit button when amount exceeds mocked balance', async ({ page }) => { + test("disables submit button when amount exceeds mocked balance", async ({ + page, + }) => { await installFreighterStub(page, MOCK_PUBLIC_KEY); await installNetworkStubs(page, { balance: 500n }); - await page.goto('/#/'); - await page.getByTestId('connect-freighter').click(); - await expect(page.getByTestId('connected-wallet')).toBeVisible(); + await page.goto("/#/"); + await page.getByTestId("connect-freighter").click(); + await expect(page.getByTestId("connected-wallet")).toBeVisible(); - await page.getByTestId('nav-transfer').click(); + await page.getByTestId("nav-transfer").click(); - await expect(page.getByRole('heading', { name: 'Transfer Tokens' })).toBeVisible(); + await expect( + page.getByRole("heading", { name: "Transfer Tokens" }), + ).toBeVisible(); - await page.locator('#transfer-destination').fill('GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWHF'); - await page.locator('#transfer-amount').fill('9999'); + await page + .locator("#transfer-destination") + .fill("GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWHF"); + await page.locator("#transfer-amount").fill("9999"); // Over-balance warning and disabled submit button assertion - await expect(page.getByTestId('transfer-over-balance')).toBeVisible(); - const submitBtn = page.getByTestId('transfer-submit'); + await expect(page.getByTestId("transfer-over-balance")).toBeVisible(); + const submitBtn = page.getByTestId("transfer-submit"); await expect(submitBtn).toBeDisabled(); }); }); -*/ -test.describe('TransferScreen Balance & Transfers Flow (#1253)', () => { +test.describe("TransferScreen Balance & Transfers Flow (#1253)", () => { test.beforeEach(async ({ page }) => { - await page.goto('/transfer'); - await page.waitForLoadState('domcontentloaded'); + await page.goto("/transfer"); + await page.waitForLoadState("domcontentloaded"); }); - test('should display insufficient balance warning when entering an amount exceeding wallet balance', async ({ page }) => { - const amountInput = page.locator('input[name="transferAmount"], [data-testid="transfer-amount-input"]'); + test("should display insufficient balance warning when entering an amount exceeding wallet balance", async ({ + page, + }) => { + const amountInput = page.locator( + 'input[name="transferAmount"], [data-testid="transfer-amount-input"]', + ); await expect(amountInput).toBeVisible(); // Enter an excessively high amount - await amountInput.fill('99999999.00'); + await amountInput.fill("99999999.00"); // Assert insufficient balance warning message appears - const warningAlert = page.locator('text=Insufficient Balance, [data-testid="insufficient-balance-warning"]'); + const warningAlert = page.locator( + 'text=Insufficient Balance, [data-testid="insufficient-balance-warning"]', + ); await expect(warningAlert).toBeVisible(); // Assert transfer submit button is disabled - const submitBtn = page.locator('button:has-text("Transfer"), [data-testid="submit-transfer-btn"]'); + const submitBtn = page.locator( + 'button:has-text("Transfer"), [data-testid="submit-transfer-btn"]', + ); await expect(submitBtn).toBeDisabled(); }); - test('should populate amount correctly when clicking MAX button', async ({ page }) => { - const maxBtn = page.locator('button:has-text("MAX"), [data-testid="max-balance-btn"]'); + test("should populate amount correctly when clicking MAX button", async ({ + page, + }) => { + const maxBtn = page.locator( + 'button:has-text("MAX"), [data-testid="max-balance-btn"]', + ); await expect(maxBtn).toBeVisible(); await maxBtn.click(); - const amountInput = page.locator('input[name="transferAmount"], [data-testid="transfer-amount-input"]'); + const amountInput = page.locator( + 'input[name="transferAmount"], [data-testid="transfer-amount-input"]', + ); const value = await amountInput.inputValue(); expect(Number(value)).toBeGreaterThan(0); }); - test('should complete full transfer flow from recipient input to confirmation receipt and balance decrement', async ({ page }) => { + test("should complete full transfer flow from recipient input to confirmation receipt and balance decrement", async ({ + page, + }) => { // 1. Enter recipient address - const recipientInput = page.locator('input[name="recipientAddress"], [data-testid="recipient-address-input"]'); - await recipientInput.fill('GBZXN7GNHQGNZROXYFA6W24Y4P73X26Y3J3XY6S3JZ6DYZN3X7Y2X3Y'); + const recipientInput = page.locator( + 'input[name="recipientAddress"], [data-testid="recipient-address-input"]', + ); + await recipientInput.fill( + "GBZXN7GNHQGNZROXYFA6W24Y4P73X26Y3J3XY6S3JZ6DYZN3X7Y2X3Y", + ); // 2. Enter valid transfer amount - const amountInput = page.locator('input[name="transferAmount"], [data-testid="transfer-amount-input"]'); - await amountInput.fill('10.00'); + const amountInput = page.locator( + 'input[name="transferAmount"], [data-testid="transfer-amount-input"]', + ); + await amountInput.fill("10.00"); // 3. Submit transfer - const submitBtn = page.locator('button:has-text("Transfer"), [data-testid="submit-transfer-btn"]'); + const submitBtn = page.locator( + 'button:has-text("Transfer"), [data-testid="submit-transfer-btn"]', + ); await expect(submitBtn).toBeEnabled(); await submitBtn.click(); // 4. Verify transaction success confirmation modal / receipt - const successReceipt = page.locator('text=Transfer Successful, text=Transaction Confirmed, [data-testid="transfer-success-receipt"]'); + const successReceipt = page.locator( + 'text=Transfer Successful, text=Transaction Confirmed, [data-testid="transfer-success-receipt"]', + ); await expect(successReceipt).toBeVisible({ timeout: 15000 }); }); - test('should pass automated WCAG 2.1 AA accessibility audit on TransferScreen', async ({ page }) => { + test("should pass automated WCAG 2.1 AA accessibility audit on TransferScreen", async ({ + page, + }) => { const accessibilityScanResults = await new AxeBuilder({ page }) - .withTags(['wcag2a', 'wcag2aa', 'wcag21a', 'wcag21aa']) + .withTags(["wcag2a", "wcag2aa", "wcag21a", "wcag21aa"]) .analyze(); if (accessibilityScanResults.violations.length > 0) { - console.error('Accessibility violations found on TransferScreen:', JSON.stringify(accessibilityScanResults.violations, null, 2)); + console.error( + "Accessibility violations found on TransferScreen:", + JSON.stringify(accessibilityScanResults.violations, null, 2), + ); } expect(accessibilityScanResults.violations).toEqual([]); }); }); -*/ -test.describe('RolesScreen Inspection & Badge Matrix Flow (#1255)', () => { +test.describe("RolesScreen Inspection & Badge Matrix Flow (#1255)", () => { test.beforeEach(async ({ page }) => { - await page.goto('/admin/roles'); - await page.waitForLoadState('domcontentloaded'); + await page.goto("/admin/roles"); + await page.waitForLoadState("domcontentloaded"); }); - test('should accept target address input and verify debounced role badge matrix statuses', async ({ page }) => { + test("should accept target address input and verify debounced role badge matrix statuses", async ({ + page, + }) => { // 1. Locate address input field - const addressInput = page.locator('input[name="targetAddress"], [data-testid="target-address-input"]'); + const addressInput = page.locator( + 'input[name="targetAddress"], [data-testid="target-address-input"]', + ); await expect(addressInput).toBeVisible(); // 2. Enter valid test Stellar public address - const testAddress = 'GBZXN7GNHQGNZROXYFA6W24Y4P73X26Y3J3XY6S3JZ6DYZN3X7Y2X3Y'; + const testAddress = + "GBZXN7GNHQGNZROXYFA6W24Y4P73X26Y3J3XY6S3JZ6DYZN3X7Y2X3Y"; await addressInput.fill(testAddress); // 3. Assert debounced fetch populates role matrix badges const adminBadge = page.locator('[data-testid="badge-admin"], text=Admin'); - const superAdminBadge = page.locator('[data-testid="badge-superadmin"], text=SuperAdmin'); - const minterBadge = page.locator('[data-testid="badge-minter"], text=Minter'); - const pauserBadge = page.locator('[data-testid="badge-pauser"], text=Pauser'); + const superAdminBadge = page.locator( + '[data-testid="badge-superadmin"], text=SuperAdmin', + ); + const minterBadge = page.locator( + '[data-testid="badge-minter"], text=Minter', + ); + const pauserBadge = page.locator( + '[data-testid="badge-pauser"], text=Pauser', + ); await expect(adminBadge).toBeVisible({ timeout: 10000 }); await expect(superAdminBadge).toBeVisible(); @@ -145,15 +200,20 @@ test.describe('RolesScreen Inspection & Badge Matrix Flow (#1255)', () => { await expect(pauserBadge).toBeVisible(); }); - test('should pass automated WCAG 2.1 AA accessibility audit on RolesScreen', async ({ page }) => { + test("should pass automated WCAG 2.1 AA accessibility audit on RolesScreen", async ({ + page, + }) => { const accessibilityScanResults = await new AxeBuilder({ page }) - .withTags(['wcag2a', 'wcag2aa', 'wcag21a', 'wcag21aa']) + .withTags(["wcag2a", "wcag2aa", "wcag21a", "wcag21aa"]) .analyze(); if (accessibilityScanResults.violations.length > 0) { - console.error('Accessibility violations found on RolesScreen:', JSON.stringify(accessibilityScanResults.violations, null, 2)); + console.error( + "Accessibility violations found on RolesScreen:", + JSON.stringify(accessibilityScanResults.violations, null, 2), + ); } expect(accessibilityScanResults.violations).toEqual([]); }); -}); \ No newline at end of file +}); diff --git a/react/src/components/ProductComponents.test.tsx b/react/src/components/ProductComponents.test.tsx index b7dc2c56..fca0ba57 100644 --- a/react/src/components/ProductComponents.test.tsx +++ b/react/src/components/ProductComponents.test.tsx @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: MIT import "@testing-library/jest-dom"; import React from "react"; import { diff --git a/react/src/hooks.test.tsx b/react/src/hooks.test.tsx index 47baa748..48a7e22d 100644 --- a/react/src/hooks.test.tsx +++ b/react/src/hooks.test.tsx @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: MIT import "@testing-library/jest-dom"; // SPDX-License-Identifier: MIT import { act, renderHook, waitFor } from "@testing-library/react"; @@ -47,10 +48,8 @@ const mockVaultClient = { const mockUseWallet = jest.fn(() => ({ status: "connected" as string, connected: true, - publicKey: - "GBRPYHIL2CI3FNQ4BXLFMNDLFJUNPU2HY3ZMFTGWEBUSAVCBCY42YOXT" as - | string - | null, + publicKey: "GBRPYHIL2CI3FNQ4BXLFMNDLFJUNPU2HY3ZMFTGWEBUSAVCBCY42YOXT" as + string | null, error: null as Error | null, })); @@ -285,15 +284,15 @@ describe("React client hooks", () => { status: "wrong-network", connected: false, publicKey: null, - error: new Error( - "Wallet is connected to a different Stellar network.", - ), + error: new Error("Wallet is connected to a different Stellar network."), }); const { result } = renderHook(() => useBalance()); expect(result.current.data).toBeNull(); - expect(result.current.error?.message).toMatch(/different Stellar network/); + expect(result.current.error?.message).toMatch( + /different Stellar network/, + ); expect(result.current.alertMessage).toBe( "Wallet is connected to a different Stellar network than expected.", ); @@ -1514,9 +1513,7 @@ describe("React client hooks", () => { }); it("captures errors gracefully and provides refetch capability", async () => { - mockClient.getAdmin.mockRejectedValue( - new Error("RPC Network Failure"), - ); + mockClient.getAdmin.mockRejectedValue(new Error("RPC Network Failure")); mockClient.getRoleAdmin.mockRejectedValue( new Error("RPC Network Failure"), ); @@ -1738,7 +1735,7 @@ describe("React client hooks", () => { expect(result.current.data).toBeNull(); }); }); -describe("useFlashLoanGuardStatus (#1201)", () => { + describe("useFlashLoanGuardStatus (#1201)", () => { it("returns unlocked state when flash loan guard is not engaged", async () => { mockClient.getFlashLoanLockStatus.mockResolvedValue({ isLocked: false, @@ -1853,7 +1850,7 @@ describe("useFlashLoanGuardStatus (#1201)", () => { expect(result.current.recipients).toEqual([]); }); }); -describe("useContractEvents (#1195)", () => { + describe("useContractEvents (#1195)", () => { const sampleEvents = [ { id: "1", diff --git a/react/stories/sdk.ts b/react/stories/sdk.ts index 90378b2f..825d03d7 100644 --- a/react/stories/sdk.ts +++ b/react/stories/sdk.ts @@ -69,9 +69,20 @@ export class FreighterAdapter implements WalletAdapter { } } export class AlbedoAdapter extends FreighterAdapter { - override name = 'albedo'; + override name = "albedo"; } export async function calculateApy(): Promise { throw new Error("Pass deterministic points to APYChart stories"); } + +export enum Role { + Admin = "Admin", + SuperAdmin = "SuperAdmin", + Minter = "Minter", + Pauser = "Pauser", +} + +export function parseContractError(_errorMsg: string, _method?: string) { + return null; +} diff --git a/react/visual/__screenshots__/linux-chromium-arm64/admin.png b/react/visual/__screenshots__/linux-chromium-arm64/admin.png new file mode 100644 index 00000000..59e9ca82 Binary files /dev/null and b/react/visual/__screenshots__/linux-chromium-arm64/admin.png differ diff --git a/react/visual/__screenshots__/linux-chromium-arm64/landing.png b/react/visual/__screenshots__/linux-chromium-arm64/landing.png new file mode 100644 index 00000000..c379a5fa Binary files /dev/null and b/react/visual/__screenshots__/linux-chromium-arm64/landing.png differ diff --git a/react/visual/__screenshots__/linux-chromium-arm64/products-transactiontoast--success.png b/react/visual/__screenshots__/linux-chromium-arm64/products-transactiontoast--success.png index 7140f653..56a79eb6 100644 Binary files a/react/visual/__screenshots__/linux-chromium-arm64/products-transactiontoast--success.png and b/react/visual/__screenshots__/linux-chromium-arm64/products-transactiontoast--success.png differ diff --git a/react/visual/__screenshots__/linux-chromium-arm64/vaults.png b/react/visual/__screenshots__/linux-chromium-arm64/vaults.png new file mode 100644 index 00000000..32d8f759 Binary files /dev/null and b/react/visual/__screenshots__/linux-chromium-arm64/vaults.png differ diff --git a/sdk/src/generated/src/index.ts b/sdk/src/generated/src/index.ts index 4abf83bd..d466647c 100644 --- a/sdk/src/generated/src/index.ts +++ b/sdk/src/generated/src/index.ts @@ -261,7 +261,7 @@ export interface RateLimitConfig { * @notice Enumerates the storage keys used by the access-control layer. * @dev Each variant maps to a distinct ledger slot; append new variants rather than reordering. */ -export type AdminKey = {tag: "Admin", values: void} | {tag: "Role", values: readonly [Role, string]} | {tag: "AddressRole", values: readonly [string, Role]} | {tag: "AdminPool", values: void} | {tag: "Threshold", values: void} | {tag: "Proposal", values: readonly [u64]} | {tag: "ProposalIdCounter", values: void} | {tag: "ProposalTimelock", values: readonly [u64]} | {tag: "SuperAdmin", values: readonly [string]} | {tag: "UpgradeProposal", values: readonly [u64]} | {tag: "UpgradeProposalIdCounter", values: void} | {tag: "PrivilegeProposal", values: readonly [PrivilegeAction]} | {tag: "RoleMask", values: readonly [string]} | {tag: "InstalledWasmHash", values: readonly [Buffer]} | {tag: "InstanceLiveUntil", values: void}; +export type AdminKey = {tag: "Admin", values: void} | {tag: "Role", values: readonly [Role, string]} | {tag: "AddressRole", values: readonly [string, Role]} | {tag: "AdminPool", values: void} | {tag: "Threshold", values: void} | {tag: "Proposal", values: readonly [u64]} | {tag: "ProposalIdCounter", values: void} | {tag: "ProposalTimelock", values: readonly [u64]} | {tag: "SuperAdmin", values: readonly [string]} | {tag: "UpgradeProposal", values: readonly [u64]} | {tag: "UpgradeProposalIdCounter", values: void} | {tag: "PrivilegeProposal", values: readonly [PrivilegeAction]} | {tag: "RoleMask", values: readonly [string]} | {tag: "InstalledWasmHash", values: readonly [Buffer]} | {tag: "InstanceLiveUntil", values: void} | {tag: "RoleGrantProposal", values: readonly [u64]}; /** * Errors returned by the admin access-control module. @@ -401,7 +401,15 @@ export const AdminError = { /** * The last SuperAdmin tried to renounce; at least one must remain (#915). */ - 29: {message:"LastSuperAdmin"} + 29: {message:"LastSuperAdmin"}, + /** + * A role proposal could not be found for the requested proposal ID. + */ + 30: {message:"RoleProposalNotFound"}, + /** + * A role proposal must be executed through `execute_role_proposal`. + */ + 31: {message:"RoleProposalRequiresExecution"} } @@ -521,6 +529,16 @@ expiry_ledger: Option; export type ProposalStatus = {tag: "Pending", values: void} | {tag: "Approved", values: void} | {tag: "Executed", values: void} | {tag: "Cancelled", values: void} | {tag: "Expired", values: void}; +/** + * Role grant bound to a legacy multisig proposal without changing the + * persisted `Proposal` layout. + */ +export interface RoleGrantAction { + role: Role; + target: string; +} + + /** * A multi-sig proposal to upgrade the WASM of one or more contracts. * @@ -641,6 +659,19 @@ pending_ids: Array; } +/** + * Role proposal information needed by the voting interface. + */ +export interface RoleGrantProposalDetails { + approvals: u32; + description: string; + executed: boolean; + quorum: u32; + role: Role; + target: string; +} + + /** * One address's role membership across the whole hierarchy, in one call. * @@ -832,6 +863,12 @@ export interface Client { */ decimals: (options?: MethodOptions) => Promise> + /** + * Construct and simulate a has_role transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object. + * Checks whether an address holds a role. + */ + has_role: ({role, address}: {role: Role, address: string}, options?: MethodOptions) => Promise> + /** * Construct and simulate a pause_as transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object. * Pauses the contract as a specific caller. @@ -889,6 +926,12 @@ export interface Client { */ get_nonce: ({address}: {address: string}, options?: MethodOptions) => Promise> + /** + * Construct and simulate a is_paused transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object. + * Returns whether token operations are currently paused. + */ + is_paused: (options?: MethodOptions) => Promise> + /** * Construct and simulate a batch_mint transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object. * Mints new tokens to multiple recipients in a single call. @@ -902,6 +945,12 @@ export interface Client { */ batch_mint: ({minter, recipients}: {minter: string, recipients: Array}, options?: MethodOptions) => Promise>> + /** + * Construct and simulate a grant_role transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object. + * Grants a role to an address through the shared admin module. + */ + grant_role: ({caller, role, address}: {caller: string, role: Role, address: string}, options?: MethodOptions) => Promise> + /** * Construct and simulate a initialize transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object. * Initializes the token contract. @@ -940,6 +989,12 @@ export interface Client { */ lock_tokens: ({caller, user, amount, unlock_timestamp}: {caller: string, user: string, amount: i128, unlock_timestamp: u64}, options?: MethodOptions) => Promise>> + /** + * Construct and simulate a revoke_role transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object. + * Revokes a role from an address through the shared admin module. + */ + revoke_role: ({caller, role, address}: {caller: string, role: Role, address: string}, options?: MethodOptions) => Promise>> + /** * Construct and simulate a update_name transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object. * Updates the token name after initialization. @@ -957,6 +1012,12 @@ export interface Client { */ update_name: ({new_name}: {new_name: string}, options?: MethodOptions) => Promise>> + /** + * Construct and simulate a get_proposal transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object. + * Returns the details for a legacy multisig proposal. + */ + get_proposal: ({proposal_id}: {proposal_id: u64}, options?: MethodOptions) => Promise>> + /** * Construct and simulate a get_treasury transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object. * Returns the current treasury address. @@ -1000,6 +1061,12 @@ export interface Client { */ set_treasury: ({caller, treasury}: {caller: string, treasury: string}, options?: MethodOptions) => Promise>> + /** + * Construct and simulate a get_threshold transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object. + * Returns the configured multisig approval threshold. + */ + get_threshold: (options?: MethodOptions) => Promise> + /** * Construct and simulate a rescue_tokens transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object. * Rescues a foreign SEP-41 token balance out of the contract. @@ -1072,6 +1139,12 @@ export interface Client { */ batch_transfer: ({from, recipients}: {from: string, recipients: Array}, options?: MethodOptions) => Promise>> + /** + * Construct and simulate a get_admin_pool transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object. + * Returns the configured multisig admin pool. + */ + get_admin_pool: (options?: MethodOptions) => Promise>> + /** * Construct and simulate a get_fee_config transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object. * Returns the current fee configuration. @@ -1176,6 +1249,12 @@ export interface Client { */ approve_proposal: ({admin, proposal_id}: {admin: string, proposal_id: u64}, options?: MethodOptions) => Promise> + /** + * Construct and simulate a get_role_proposal transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object. + * Returns role action details and approval tally for a proposal. + */ + get_role_proposal: ({proposal_id}: {proposal_id: u64}, options?: MethodOptions) => Promise>> + /** * Construct and simulate a is_proposal_ready transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object. * Returns whether a governance proposal has met its approval quorum. @@ -1206,6 +1285,12 @@ export interface Client { */ transfer_ownership: ({new_admin}: {new_admin: string}, options?: MethodOptions) => Promise>> + /** + * Construct and simulate a create_role_proposal transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object. + * Creates a multisig proposal that grants a role after approval. + */ + create_role_proposal: ({creator, role, target, description}: {creator: string, role: Role, target: string, description: string}, options?: MethodOptions) => Promise> + /** * Construct and simulate a remove_fee_exemption transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object. * Removes a fee exemption for a specific address. @@ -1242,6 +1327,18 @@ export interface Client { */ execute_from_contract: ({from, operations, nonce, max_ledger}: {from: string, operations: Array, nonce: u64, max_ledger: u32}, options?: MethodOptions) => Promise>> + /** + * Construct and simulate a execute_role_proposal transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object. + * Executes a role grant after its multisig proposal reaches quorum. + */ + execute_role_proposal: ({executor, proposal_id}: {executor: string, proposal_id: u64}, options?: MethodOptions) => Promise>> + + /** + * Construct and simulate a list_legacy_proposals transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object. + * Lists pending and approved legacy multisig proposals by page. + */ + list_legacy_proposals: ({start_after}: {start_after: u64}, options?: MethodOptions) => Promise> + /** * Construct and simulate a get_privilege_proposal transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object. * Read-only view of the privileged-action proposal for `action` (#914). @@ -1340,29 +1437,36 @@ export class Client extends ContractClient { "AAAAAAAAAVpVbnBhdXNlcyB0aGUgY29udHJhY3QuCgpAbm90aWNlIFJlc3VtZXMgYWxsIHRva2VuIG9wZXJhdGlvbnMuIE9ubHkgdGhlIGFkbWluIChvciBTdXBlckFkbWluL1BhdXNlciByb2xlIGhvbGRlcikgY2FuIGNhbGwgdGhpcyBmdW5jdGlvbi4KQHBhcmFtIGVudiBUaGUgU29yb2JhbiBlbnZpcm9ubWVudC4KQHBhcmFtIGNhbGxlciBUaGUgYWRkcmVzcyByZXF1ZXN0aW5nIHRoZSB1bnBhdXNlOyBtdXN0IGJlIGFkbWluIG9yIGhvbGQgdGhlIFBhdXNlciByb2xlLgpAcmV0dXJuIGBPaygoKSlgIG9uIHN1Y2Nlc3MsIG9yIGFuIGVycm9yIGlmIHRoZSBjYWxsZXIgaXMgdW5hdXRob3JpemVkIG9yIG5vdCBwYXVzZWQuAAAAAAAHdW5wYXVzZQAAAAABAAAAAAAAAAZjYWxsZXIAAAAAABMAAAABAAAD6QAAA+0AAAAAAAAH0AAAAApUb2tlbkVycm9yAAA=", "AAAAAAAAAi5VcGdyYWRlcyB0aGUgY29udHJhY3QncyBleGVjdXRhYmxlIHRvIGEgbmV3IFdBU00gaGFzaC4KCkBub3RpY2UgVXBncmFkZXMgdGhlIGNvbnRyYWN0J3MgZXhlY3V0YWJsZSBjb2RlIHRvIGBuZXdfd2FzbV9oYXNoYC4gT25seSB0aGUgU3VwZXJBZG1pbiByb2xlIGhvbGRlciBjYW4gY2FsbCB0aGlzIGZ1bmN0aW9uLgpAZGV2IEdhdGVkIHRvIGBSb2xlOjpTdXBlckFkbWluYCAob3IgYFJvbGU6OkFkbWluYCwgd2hpY2ggaXMgYSBzdXBlcnNldCBvZiBldmVyeSByb2xlKSBzaW5jZSBhIHByb3RvY29sIHVwZ3JhZGUgY2FuIHJlcGxhY2UgYWxsIGNvbnRyYWN0IGxvZ2ljLgpAcGFyYW0gZW52IFRoZSBTb3JvYmFuIGVudmlyb25tZW50LgpAcGFyYW0gdXBncmFkZXIgVGhlIGFkZHJlc3MgY2FsbGluZyB0aGUgdXBncmFkZSAobXVzdCBoYXZlIFN1cGVyQWRtaW4gcm9sZSkuCkBwYXJhbSBuZXdfd2FzbV9oYXNoIFRoZSBuZXcgV0FTTSBoYXNoIHRvIGRlcGxveS4KQHJldHVybiBgT2soKCkpYCBvbiBzdWNjZXNzLCBvciBhbiBlcnJvciBpZiB0aGUgY2FsbGVyIGlzIHVuYXV0aG9yaXplZC4AAAAAAAd1cGdyYWRlAAAAAAIAAAAAAAAACHVwZ3JhZGVyAAAAEwAAAAAAAAANbmV3X3dhc21faGFzaAAAAAAAA+4AAAAgAAAAAQAAA+kAAAPtAAAAAAAAB9AAAAAKVG9rZW5FcnJvcgAA", "AAAAAAAAANpSZXR1cm5zIHRoZSBudW1iZXIgb2YgZGVjaW1hbCBwbGFjZXMgZm9yIHRoZSB0b2tlbi4KCkBub3RpY2UgUmV0dXJucyB0aGUgdG9rZW4ncyBwcmVjaXNpb24gKG51bWJlciBvZiBkZWNpbWFsIHBsYWNlcykuIERlZmF1bHRzIHRvIDcgaWYgbm90IHNldC4KQHBhcmFtIGVudiBUaGUgU29yb2JhbiBlbnZpcm9ubWVudC4KQHJldHVybiBUaGUgbnVtYmVyIG9mIGRlY2ltYWwgcGxhY2VzLgAAAAAACGRlY2ltYWxzAAAAAAAAAAEAAAAE", + "AAAAAAAAACdDaGVja3Mgd2hldGhlciBhbiBhZGRyZXNzIGhvbGRzIGEgcm9sZS4AAAAACGhhc19yb2xlAAAAAgAAAAAAAAAEcm9sZQAAB9AAAAAEUm9sZQAAAAAAAAAHYWRkcmVzcwAAAAATAAAAAQAAAAE=", "AAAAAAAAAShQYXVzZXMgdGhlIGNvbnRyYWN0IGFzIGEgc3BlY2lmaWMgY2FsbGVyLgoKQG5vdGljZSBQYXVzZXMgYWxsIHRva2VuIG9wZXJhdGlvbnMgYXMgdGhlIGdpdmVuIGNhbGxlci4gVXNlZCBmb3IgZ292ZXJuYW5jZSBvciBlbWVyZ2VuY3kgc2NlbmFyaW9zIHdoZXJlIHRoZSBjYWxsZXIgZGlmZmVycyBmcm9tIHRoZSBhZG1pbi4KQHBhcmFtIGVudiBUaGUgU29yb2JhbiBlbnZpcm9ubWVudC4KQHBhcmFtIGNhbGxlciBUaGUgYWRkcmVzcyByZXF1ZXN0aW5nIHRoZSBwYXVzZS4KQHJldHVybiBgT2soKCkpYCBvbiBzdWNjZXNzLgAAAAhwYXVzZV9hcwAAAAEAAAAAAAAABmNhbGxlcgAAAAAAEwAAAAEAAAPpAAAD7QAAAAAAAAfQAAAAClRva2VuRXJyb3IAAA==", "AAAAAAAAAchUcmFuc2ZlcnMgdG9rZW5zIGZyb20gYGZyb21gIHRvIGB0b2AuCgpAbm90aWNlIFRyYW5zZmVycyBgYW1vdW50YCB0b2tlbnMgZnJvbSBgZnJvbWAgdG8gYHRvYC4gUmVxdWlyZXMgYGZyb21gIHRvIGF1dGhlbnRpY2F0ZSB0aGUgY2FsbC4KQGRldiBSZWplY3RzIHdpdGggW2BUb2tlbkVycm9yOjpDb250cmFjdFBhdXNlZGBdIHdoaWxlIHRoZSBsaWZlY3ljbGUgbW9kdWxlIHJlcG9ydHMgdGhlCmNvbnRyYWN0IHBhdXNlZC4gQ2hlY2tzIHJhdGUgbGltaXRzIGJlZm9yZSB0cmFuc2ZlcnJpbmcuIEVtaXRzIGEgYHRyYW5zZmVyYCBldmVudCBvbiBzdWNjZXNzLgpAcGFyYW0gZW52IFRoZSBTb3JvYmFuIGVudmlyb25tZW50LgpAcGFyYW0gZnJvbSBUaGUgc2VuZGVyIGFkZHJlc3MuCkBwYXJhbSB0byBUaGUgcmVjaXBpZW50IGFkZHJlc3MuCkBwYXJhbSBhbW91bnQgVGhlIGFtb3VudCB0byB0cmFuc2Zlci4AAAAIdHJhbnNmZXIAAAADAAAAAAAAAARmcm9tAAAAEwAAAAAAAAACdG8AAAAAABMAAAAAAAAABmFtb3VudAAAAAAACwAAAAA=", "AAAAAAAAAHNSZXR1cm5zIHRoZSByZW1haW5pbmcgYWxsb3dhbmNlIHRoYXQgYHNwZW5kZXJgIGlzIGFsbG93ZWQgdG8gc3BlbmQgb24gYmVoYWxmIG9mIGBmcm9tYC4KCkBpbmhlcml0ZG9jIFRva2VuSW50ZXJmYWNlAAAAAAlhbGxvd2FuY2UAAAAAAAACAAAAAAAAAARmcm9tAAAAEwAAAAAAAAAHc3BlbmRlcgAAAAATAAAAAQAAAAs=", "AAAAAAAAAdtCdXJucyB0b2tlbnMgZnJvbSBhbm90aGVyIGFkZHJlc3MncyBiYWxhbmNlIHVzaW5nIHRoZSBhbGxvd2FuY2UgbWVjaGFuaXNtLgoKQG5vdGljZSBQZXJtYW5lbnRseSByZW1vdmVzIGBhbW91bnRgIHRva2VucyBmcm9tIGBmcm9tYCdzIGJhbGFuY2UsIHJlZHVjaW5nIHRvdGFsIHN1cHBseS4gUmVxdWlyZXMgYHNwZW5kZXJgIHRvIGhhdmUgc3VmZmljaWVudCBhbGxvd2FuY2UuCkBkZXYgRGVkdWN0cyB0aGUgYWxsb3dhbmNlIGFmdGVyIGJ1cm5pbmcuIEVtaXRzIGEgYGJ1cm5gIGV2ZW50LgpAcGFyYW0gZW52IFRoZSBTb3JvYmFuIGVudmlyb25tZW50LgpAcGFyYW0gc3BlbmRlciBUaGUgYWRkcmVzcyBjYWxsaW5nIHRoZSBidXJuIChtdXN0IGhhdmUgc3VmZmljaWVudCBhbGxvd2FuY2UpLgpAcGFyYW0gZnJvbSBUaGUgYWRkcmVzcyB3aG9zZSB0b2tlbnMgYXJlIGJ1cm5lZC4KQHBhcmFtIGFtb3VudCBUaGUgYW1vdW50IHRvIGJ1cm4uAAAAAAlidXJuX2Zyb20AAAAAAAADAAAAAAAAAAdzcGVuZGVyAAAAABMAAAAAAAAABGZyb20AAAATAAAAAAAAAAZhbW91bnQAAAAAAAsAAAAA", "AAAAAAAAAP1SZXR1cm5zIHRoZSBjdXJyZW50IHJlcGxheS1wcm90ZWN0aW9uIG5vbmNlIGZvciBhbiBhZGRyZXNzLgoKQG5vdGljZSBSZXR1cm5zIHRoZSBub25jZSBmb3IgYGFkZHJlc3NgIHVzZWQgaW4gYGV4ZWN1dGVfZnJvbV9jb250cmFjdGAuCkBwYXJhbSBlbnYgVGhlIFNvcm9iYW4gZW52aXJvbm1lbnQuCkBwYXJhbSBhZGRyZXNzIFRoZSBhZGRyZXNzIHRvIHF1ZXJ5IHRoZSBub25jZSBmb3IuCkByZXR1cm4gVGhlIGN1cnJlbnQgbm9uY2UgdmFsdWUuAAAAAAAACWdldF9ub25jZQAAAAAAAAEAAAAAAAAAB2FkZHJlc3MAAAAAEwAAAAEAAAAG", + "AAAAAAAAADZSZXR1cm5zIHdoZXRoZXIgdG9rZW4gb3BlcmF0aW9ucyBhcmUgY3VycmVudGx5IHBhdXNlZC4AAAAAAAlpc19wYXVzZWQAAAAAAAAAAAAAAQAAAAE=", "AAAAAgAAAG9BbiBpbm5lciBvcGVyYXRpb24gdGhhdCBjYW4gYmUgZXhlY3V0ZWQgaW4gYSBiYXRjaCB2aWEgW2BCY0ZvcmdlVG9rZW46OmV4ZWN1dGVfZnJvbV9jb250cmFjdGBdLgoKQHRpdGxlIEJhdGNoT3AAAAAAAAAAAAdCYXRjaE9wAAAAAAIAAAABAAAAYkFwcHJvdmUgYSBzcGVuZGVyIHRvIHNwZW5kIHRva2VucyBvbiBiZWhhbGYgb2YgdGhlIHdhbGxldDogYChzcGVuZGVyLCBhbW91bnQsIGV4cGlyYXRpb25fbGVkZ2VyKWAuAAAAAAAHQXBwcm92ZQAAAAADAAAAEwAAAAsAAAAEAAAAAQAAAC9UcmFuc2ZlciB0b2tlbnMgdG8gYSByZWNpcGllbnQ6IGAodG8sIGFtb3VudClgLgAAAAAIVHJhbnNmZXIAAAACAAAAEwAAAAs=", "AAAAAgAAAAAAAAAAAAAAB0RhdGFLZXkAAAAADwAAAAAAAABVQWRtaW4gYWRkcmVzcyDigJQgc3RvcmVkIGhlcmUgZm9yIGNhbGxlciBjb252ZW5pZW5jZTsgZGVsZWdhdGVzIHRvIGBBZG1pbktleTo6QWRtaW5gLgAAAAAAAAVBZG1pbgAAAAAAAAAAAACPTGVnYWN5IHBlbmRpbmcgYWRtaW4g4oCUIHVudXNlZDsgcmV0YWluZWQgdG8gcHJlc2VydmUgc3RvcmFnZSBkaXNjcmltaW5hbnQgb3JkZXIuClRoZSB0cmFuc2Zlci1vd25lcnNoaXAgZmxvdyB1c2VzIGBhZG1pbjo6c2V0X2FkbWluYCBkaXJlY3RseS4AAAAADFBlbmRpbmdBZG1pbgAAAAEAAABFU3BlbmRpbmcgYWxsb3dhbmNlOiAob3duZXIsIHNwZW5kZXIpIC0+IGFtb3VudCBhbmQgZXhwaXJhdGlvbiBsZWRnZXIuAAAAAAAACUFsbG93YW5jZQAAAAAAAAIAAAATAAAAEwAAAAEAAABOTGVnYWN5IGFsbG93YW5jZSBleHBpcmF0aW9uIOKAlCBzdG9yZWQgcGVyLWtleTsgcHJlZmVyIGBBbGxvd2FuY2VEYXRhYCBzdHJ1Y3QuAAAAAAAMQWxsb3dhbmNlRXhwAAAAAgAAABMAAAATAAAAAQAAAB1Ub2tlbiBiYWxhbmNlIGZvciBhbiBhZGRyZXNzLgAAAAAAAAdCYWxhbmNlAAAAAAEAAAATAAAAAQAAAHZMb2NrdXAgc3RhdGUgZm9yIGFuIGFkZHJlc3M6IGFtb3VudCBjdXJyZW50bHkgbG9ja2VkIGFuZCB0aGUgdGltZXN0YW1wCmF0IHdoaWNoIHRoZSBsb2NrZWQgdG9rZW5zIGJlY29tZSB3aXRoZHJhd2FibGUuAAAAAAAGTG9ja3VwAAAAAAABAAAAEwAAAAAAAAAnTnVtYmVyIG9mIGRlY2ltYWwgcGxhY2VzIGZvciB0aGUgdG9rZW4uAAAAAAhEZWNpbWFscwAAAAAAAAAkVG9rZW4gbmFtZSAoZS5nLiwgImJjLWZvcmdlIFRva2VuIikuAAAABE5hbWUAAAAAAAAAG1Rva2VuIHN5bWJvbCAoZS5nLiwgIlNGRyIpLgAAAAAGU3ltYm9sAAAAAAAAAAAAG0N1cnJlbnQgdG90YWwgdG9rZW4gc3VwcGx5LgAAAAAGU3VwcGx5AAAAAAAAAAAAGU1heGltdW0gdG90YWwgc3VwcGx5IGNhcC4AAAAAAAAJTWF4U3VwcGx5AAAAAAAAAAAAACRUcmVhc3VyeSBhZGRyZXNzIGZvciBjb2xsZWN0ZWQgZmVlcy4AAAAIVHJlYXN1cnkAAAAAAAAAEkZlZSBjb25maWd1cmF0aW9uLgAAAAAACUZlZUNvbmZpZwAAAAAAAAEAAAAgRmVlIGV4ZW1wdGlvbnMga2V5ZWQgYnkgYWRkcmVzcy4AAAAMRmVlRXhlbXB0aW9uAAAAAQAAABMAAAABAAAAPE5vbmNlIGZvciBjb250cmFjdCB3YWxsZXQgYmF0Y2ggZXhlY3V0aW9uIHJlcGxheSBwcm90ZWN0aW9uLgAAAAVOb25jZQAAAAAAAAEAAAAT", "AAAAAAAAAk1NaW50cyBuZXcgdG9rZW5zIHRvIG11bHRpcGxlIHJlY2lwaWVudHMgaW4gYSBzaW5nbGUgY2FsbC4KCkBub3RpY2UgTWludHMgdG9rZW5zIHRvIGVhY2ggcmVjaXBpZW50IGluIHRoZSBgcmVjaXBpZW50c2AgbGlzdC4gT25seSBhdXRob3JpemVkIG1pbmVycyBjYW4gY2FsbCB0aGlzIGZ1bmN0aW9uLgpAZGV2IFJlcXVpcmVzIHRoZSBjYWxsZXIgdG8gaGF2ZSB0aGUgTWludGVyIHJvbGUuIFJhdGUgbGltaXRzIGFyZSBjaGVja2VkIHBlciByZWNpcGllbnQuIFRoZSB0b3RhbCBzdXBwbHkgaXMgdXBkYXRlZCBhdG9taWNhbGx5LgpAcGFyYW0gZW52IFRoZSBTb3JvYmFuIGVudmlyb25tZW50LgpAcGFyYW0gbWludGVyIFRoZSBhZGRyZXNzIG9mIHRoZSBtaW50ZXIgY2FsbGluZyB0aGlzIGZ1bmN0aW9uLgpAcGFyYW0gcmVjaXBpZW50cyBBIGxpc3Qgb2YgcmVjaXBpZW50cyB3aXRoIGFtb3VudHMgdG8gbWludCB0byBlYWNoLgpAcmV0dXJuIGBPaygoKSlgIG9uIHN1Y2Nlc3MsIG9yIGFuIGVycm9yIGlmIHRoZSBtaW50ZXIgaXMgdW5hdXRob3JpemVkLCB0aGUgY29udHJhY3QgaXMgcGF1c2VkLCBvciBhbnkgYW1vdW50IGlzIGludmFsaWQuAAAAAAAACmJhdGNoX21pbnQAAAAAAAIAAAAAAAAABm1pbnRlcgAAAAAAEwAAAAAAAAAKcmVjaXBpZW50cwAAAAAD6gAAB9AAAAAJUmVjaXBpZW50AAAAAAAAAQAAA+kAAAPtAAAAAAAAB9AAAAAKVG9rZW5FcnJvcgAA", + "AAAAAAAAADxHcmFudHMgYSByb2xlIHRvIGFuIGFkZHJlc3MgdGhyb3VnaCB0aGUgc2hhcmVkIGFkbWluIG1vZHVsZS4AAAAKZ3JhbnRfcm9sZQAAAAAAAwAAAAAAAAAGY2FsbGVyAAAAAAATAAAAAAAAAARyb2xlAAAH0AAAAARSb2xlAAAAAAAAAAdhZGRyZXNzAAAAABMAAAAA", "AAAAAAAAA2xJbml0aWFsaXplcyB0aGUgdG9rZW4gY29udHJhY3QuCgpTZXRzIHRoZSBhZG1pbiBhZGRyZXNzLCBkZWNpbWFscywgbmFtZSwgYW5kIHN5bWJvbC4KQ29uZmlndXJlcyBkZWZhdWx0IHJhdGUgbGltaXRzIGZvciBtaW50LCB0cmFuc2ZlciwgdHJhbnNmZXJfZnJvbSwgYnVybiwgYW5kIGJ1cm5fZnJvbSBvcGVyYXRpb25zLgpFbWl0cyB0aGUgYGluaXRgIGV2ZW50LiBDYW4gb25seSBiZSBjYWxsZWQgb25jZS4KCkBub3RpY2UgSW5pdGlhbGl6ZXMgdGhlIHRva2VuIGNvbnRyYWN0IHdpdGggdGhlIGdpdmVuIGFkbWluLCBkZWNpbWFscywgbmFtZSwgYW5kIHN5bWJvbC4KQGRldiBUaGlzIGZ1bmN0aW9uIGNhbiBvbmx5IGJlIGNhbGxlZCBvbmNlLiBTdWJzZXF1ZW50IGNhbGxzIHdpbGwgcmV2ZXJ0IHdpdGggYEFscmVhZHlJbml0aWFsaXplZGAuCkRlZmF1bHQgcmF0ZSBsaW1pdHMgYXJlIHNldCB0byAxMDAwIG9wZXJhdGlvbnMgcGVyIDYwLXNlY29uZCB3aW5kb3cgZm9yIGVhY2ggb3BlcmF0aW9uIHR5cGUuCkBwYXJhbSBlbnYgVGhlIFNvcm9iYW4gZW52aXJvbm1lbnQuCkBwYXJhbSBhZG1pbl9hZGRyZXNzIFRoZSBhZGRyZXNzIHRvIHNldCBhcyB0aGUgY29udHJhY3QgYWRtaW4uCkBwYXJhbSBkZWNpbWFsIFRoZSBudW1iZXIgb2YgZGVjaW1hbCBwbGFjZXMgZm9yIHRoZSB0b2tlbi4KQHBhcmFtIG5hbWUgVGhlIHRva2VuIG5hbWUgKGUuZy4sICJiYy1mb3JnZSBUb2tlbiIpLgpAcGFyYW0gc3ltYm9sIFRoZSB0b2tlbiBzeW1ib2wgKGUuZy4sICJTRkciKS4KQHJldHVybiBgT2soKCkpYCBvbiBzdWNjZXNzLCBvciBgVG9rZW5FcnJvcjo6QWxyZWFkeUluaXRpYWxpemVkYCBpZiB0aGUgY29udHJhY3QgaXMgYWxyZWFkeSBpbml0aWFsaXplZC4AAAAKaW5pdGlhbGl6ZQAAAAAABAAAAAAAAAANYWRtaW5fYWRkcmVzcwAAAAAAABMAAAAAAAAAB2RlY2ltYWwAAAAABAAAAAAAAAAEbmFtZQAAABAAAAAAAAAABnN5bWJvbAAAAAAAEAAAAAEAAAPpAAAD7QAAAAAAAAfQAAAAClRva2VuRXJyb3IAAA==", "AAAAAAAAAS1VbnBhdXNlcyB0aGUgY29udHJhY3QgYXMgYSBzcGVjaWZpYyBjYWxsZXIuCgpAbm90aWNlIFJlc3VtZXMgYWxsIHRva2VuIG9wZXJhdGlvbnMgYXMgdGhlIGdpdmVuIGNhbGxlci4gVXNlZCBmb3IgZ292ZXJuYW5jZSBvciBlbWVyZ2VuY3kgc2NlbmFyaW9zIHdoZXJlIHRoZSBjYWxsZXIgZGlmZmVycyBmcm9tIHRoZSBhZG1pbi4KQHBhcmFtIGVudiBUaGUgU29yb2JhbiBlbnZpcm9ubWVudC4KQHBhcmFtIGNhbGxlciBUaGUgYWRkcmVzcyByZXF1ZXN0aW5nIHRoZSB1bnBhdXNlLgpAcmV0dXJuIGBPaygoKSlgIG9uIHN1Y2Nlc3MuAAAAAAAACnVucGF1c2VfYXMAAAAAAAEAAAAAAAAABmNhbGxlcgAAAAAAEwAAAAEAAAPpAAAD7QAAAAAAAAfQAAAAClRva2VuRXJyb3IAAA==", "AAAAAAAAAI5SZXN0cmljdHMgcGFydCBvZiBhbiBleGlzdGluZyBob2xkZXIgYmFsYW5jZSB1bnRpbCBgdW5sb2NrX3RpbWVzdGFtcGAuCkV4aXN0aW5nIGxvY2tzIGFjY3VtdWxhdGUgYW5kIGNhbiBvbmx5IGhhdmUgdGhlaXIgdW5sb2NrIHRpbWUgZXh0ZW5kZWQuAAAAAAALbG9ja190b2tlbnMAAAAABAAAAAAAAAAGY2FsbGVyAAAAAAATAAAAAAAAAAR1c2VyAAAAEwAAAAAAAAAGYW1vdW50AAAAAAALAAAAAAAAABB1bmxvY2tfdGltZXN0YW1wAAAABgAAAAEAAAPpAAAD7QAAAAAAAAfQAAAAClRva2VuRXJyb3IAAA==", + "AAAAAAAAAD9SZXZva2VzIGEgcm9sZSBmcm9tIGFuIGFkZHJlc3MgdGhyb3VnaCB0aGUgc2hhcmVkIGFkbWluIG1vZHVsZS4AAAAAC3Jldm9rZV9yb2xlAAAAAAMAAAAAAAAABmNhbGxlcgAAAAAAEwAAAAAAAAAEcm9sZQAAB9AAAAAEUm9sZQAAAAAAAAAHYWRkcmVzcwAAAAATAAAAAQAAA+kAAAPtAAAAAAAAB9AAAAAKQWRtaW5FcnJvcgAA", "AAAAAAAAAm5VcGRhdGVzIHRoZSB0b2tlbiBuYW1lIGFmdGVyIGluaXRpYWxpemF0aW9uLgoKQG5vdGljZSBTdG9yZXMgYG5ld19uYW1lYCBpbiBpbnN0YW5jZSBzdG9yYWdlIGFuZCBlbWl0cyBgdXBkX25hbWVgIHdpdGgKdGhlIGFkbWluLCBvbGQgbmFtZSwgYW5kIG5ldyBuYW1lIChzcGVjOiBtZXRhZGF0YS11cGRhdGUtZnVuY3Rpb25zCnJlcXVpcmVtZW50cyAxLjEtMS43KS4gRW1wdHkgc3RyaW5ncyBhcmUgYWNjZXB0ZWQ7IHRoZSBjb250cmFjdAptdXN0IGJlIGluaXRpYWxpemVkIG9yIGBUb2tlbkVycm9yOjpOb3RJbml0aWFsaXplZGAgaXMgcmV0dXJuZWQ7CnBhdXNlIHN0YXRlIGRvZXMgbm90IGFmZmVjdCB0aGUgdXBkYXRlLgpAcGFyYW0gZW52IFRoZSBTb3JvYmFuIGVudmlyb25tZW50LgpAcGFyYW0gbmV3X25hbWUgVGhlIG5ldyB0b2tlbiBuYW1lIChtYXkgYmUgZW1wdHk7IHN0b3JlZCB2ZXJiYXRpbSkuCkByZXR1cm4gYE9rKCgpKWAgb24gc3VjY2Vzcywgb3IgYFRva2VuRXJyb3I6Ok5vdEluaXRpYWxpemVkYCBpZiB0aGUKY29udHJhY3QgaGFzIG5vdCBiZWVuIGluaXRpYWxpemVkLiBQYW5pY3MgaWYgdGhlIHN0b3JlZCBhZG1pbgpkb2VzIG5vdCBhdXRob3JpemUgdGhlIGludm9jYXRpb24uAAAAAAALdXBkYXRlX25hbWUAAAAAAQAAAAAAAAAIbmV3X25hbWUAAAAQAAAAAQAAA+kAAAPtAAAAAAAAB9AAAAAKVG9rZW5FcnJvcgAA", "AAAAAQAAAEZGZWUgY29uZmlndXJhdGlvbiBmb3IgZHluYW1pYyBjb250cmFjdCBmZWUgY2hhcmdpbmcuCgpAdGl0bGUgRmVlQ29uZmlnAAAAAAAAAAAACUZlZUNvbmZpZwAAAAAAAAQAAAAmQmFzZSBmZWUgYW1vdW50IGNoYXJnZWQgcGVyIG9wZXJhdGlvbi4AAAAAAAhiYXNlX2ZlZQAAAAsAAAA8TXVsdGlwbGllciBhcHBsaWVkIHRvIHRoZSBmZWUgYmFzZWQgb24gb3BlcmF0aW9uIGNvbXBsZXhpdHkuAAAAFWNvbXBsZXhpdHlfbXVsdGlwbGllcgAAAAAAAAQAAAAgV2hldGhlciBmZWUgY2hhcmdpbmcgaXMgZW5hYmxlZC4AAAAHZW5hYmxlZAAAAAABAAAAEE1heGltdW0gZmVlIGNhcC4AAAAHbWF4X2ZlZQAAAAAL", "AAAAAQAAADJBIG1pbnQgcmVjaXBpZW50IHdpdGggYW4gYW1vdW50LgoKQHRpdGxlIFJlY2lwaWVudAAAAAAAAAAAAAlSZWNpcGllbnQAAAAAAAACAAAAH1RoZSBhbW91bnQgdG8gbWludCBvciB0cmFuc2Zlci4AAAAABmFtb3VudAAAAAAACwAAABZUaGUgcmVjaXBpZW50IGFkZHJlc3MuAAAAAAACdG8AAAAAABM=", + "AAAAAAAAADNSZXR1cm5zIHRoZSBkZXRhaWxzIGZvciBhIGxlZ2FjeSBtdWx0aXNpZyBwcm9wb3NhbC4AAAAADGdldF9wcm9wb3NhbAAAAAEAAAAAAAAAC3Byb3Bvc2FsX2lkAAAAAAYAAAABAAAD6AAAB9AAAAAIUHJvcG9zYWw=", "AAAAAAAAAM9SZXR1cm5zIHRoZSBjdXJyZW50IHRyZWFzdXJ5IGFkZHJlc3MuCgpAbm90aWNlIFJldHVybnMgdGhlIHRyZWFzdXJ5IGFkZHJlc3MgZm9yIGNvbGxlY3RlZCBmZWVzLgpAcGFyYW0gZW52IFRoZSBTb3JvYmFuIGVudmlyb25tZW50LgpAcmV0dXJuIFRoZSB0cmVhc3VyeSBhZGRyZXNzLCBvciBgVG9rZW5FcnJvcjo6RmVlTm90Q29uZmlndXJlZGAgaWYgbm90IHNldC4AAAAADGdldF90cmVhc3VyeQAAAAAAAAABAAAD6QAAABMAAAfQAAAAClRva2VuRXJyb3IAAA==", "AAAAAAAAA1hTZXRzIG5hbWUsIHN5bWJvbCwgYW5kIGRlY2ltYWxzIHdpdGggYW4gaW1tdXRhYmlsaXR5IGd1YXJkICgjOTExKS4KCkBub3RpY2UgQWRtaW4tb25seSBmdWxsLW1ldGFkYXRhIHNldHRlci4gQWZ0ZXIgaW5pdGlhbGl6YXRpb24gdGhlCmBkZWNpbWFsc2Agc2NhbGUgaXMgZml4ZWQgYmVjYXVzZSBob2xkZXJzIGFuZCB0aGUgU0RLIGFzc3VtZSBhCmZpeGVkIHNjYWxlLCBzbyBhbnkgYXR0ZW1wdCB0byBzdXBwbHkgYSBgZGVjaW1hbHNgIHZhbHVlIHRoYXQKZGlmZmVycyBmcm9tIHRoZSBzdG9yZWQgb25lIGlzIHJlamVjdGVkIHdpdGgKYFRva2VuRXJyb3I6OkRlY2ltYWxzSW1tdXRhYmxlYC4gTmFtZSBhbmQgc3ltYm9sIGFyZSBzdG9yZWQKdmVyYmF0aW0gYW5kIGFuIGB1cGRfbWV0YWAgZXZlbnQgaXMgZW1pdHRlZCB3aXRoIHRoZSBuZXcgdmFsdWVzLgpAcGFyYW0gZW52IFRoZSBTb3JvYmFuIGVudmlyb25tZW50LgpAcGFyYW0gY2FsbGVyIFRoZSBhZGRyZXNzIGNhbGxpbmcgdGhpcyBmdW5jdGlvbiAobXVzdCBoYXZlIEFkbWluIHJvbGUpLgpAcGFyYW0gbmFtZSBUaGUgbmV3IHRva2VuIG5hbWUuCkBwYXJhbSBzeW1ib2wgVGhlIG5ldyB0b2tlbiBzeW1ib2wuCkBwYXJhbSBkZWNpbWFscyBUaGUgcmVxdWVzdGVkIGRlY2ltYWwgcGxhY2VzOyBtdXN0IGVxdWFsIHRoZSBzdG9yZWQgdmFsdWUuCkByZXR1cm4gYE9rKCgpKWAgb24gc3VjY2VzcywgYFRva2VuRXJyb3I6Ok5vdEluaXRpYWxpemVkYCBpZiB0aGUgY29udHJhY3QKaXMgdW5pbml0aWFsaXplZCwgb3IgYFRva2VuRXJyb3I6OkRlY2ltYWxzSW1tdXRhYmxlYCBpZiBgZGVjaW1hbHNgCndvdWxkIGNoYW5nZSB0aGUgaW5pdGlhbGl6ZWQgc2NhbGUuAAAADHNldF9tZXRhZGF0YQAAAAQAAAAAAAAABmNhbGxlcgAAAAAAEwAAAAAAAAAEbmFtZQAAABAAAAAAAAAABnN5bWJvbAAAAAAAEAAAAAAAAAAIZGVjaW1hbHMAAAAEAAAAAQAAA+kAAAPtAAAAAAAAB9AAAAAKVG9rZW5FcnJvcgAA", "AAAAAAAAAYNTZXRzIHRoZSB0cmVhc3VyeSBhZGRyZXNzIGZvciBjb2xsZWN0ZWQgZmVlcy4KCkBub3RpY2UgQ29uZmlndXJlcyB0aGUgdHJlYXN1cnkgYWRkcmVzcyB0aGF0IHJlY2VpdmVzIGNvbGxlY3RlZCBmZWVzLiBPbmx5IHRoZSBhZG1pbiBjYW4gY2FsbCB0aGlzIGZ1bmN0aW9uLgpAcGFyYW0gZW52IFRoZSBTb3JvYmFuIGVudmlyb25tZW50LgpAcGFyYW0gY2FsbGVyIFRoZSBhZGRyZXNzIGNhbGxpbmcgdGhpcyBmdW5jdGlvbiAobXVzdCBoYXZlIEFkbWluIHJvbGUpLgpAcGFyYW0gdHJlYXN1cnkgVGhlIGFkZHJlc3MgdG8gc2V0IGFzIHRoZSB0cmVhc3VyeS4KQHJldHVybiBgT2soKCkpYCBvbiBzdWNjZXNzLCBvciBhbiBlcnJvciBpZiB0aGUgY2FsbGVyIGlzIHVuYXV0aG9yaXplZC4AAAAADHNldF90cmVhc3VyeQAAAAIAAAAAAAAABmNhbGxlcgAAAAAAEwAAAAAAAAAIdHJlYXN1cnkAAAATAAAAAQAAA+kAAAPtAAAAAAAAB9AAAAAKVG9rZW5FcnJvcgAA", "AAAABAAAAAAAAAAAAAAAClRva2VuRXJyb3IAAAAAABYAAAA8Q29udHJhY3QgaGFzIGFscmVhZHkgYmVlbiBpbml0aWFsaXplZDsgY2Fubm90IHJlLWluaXRpYWxpemUuAAAAEkFscmVhZHlJbml0aWFsaXplZAAAAAAAAQAAACZDb250cmFjdCBoYXMgbm90IGJlZW4gaW5pdGlhbGl6ZWQgeWV0LgAAAAAADk5vdEluaXRpYWxpemVkAAAAAAACAAAAOFRoZSBhbW91bnQgcHJvdmlkZWQgaXMgaW52YWxpZCAoZS5nLiwgbmVnYXRpdmUgb3IgemVybykuAAAADUludmFsaWRBbW91bnQAAAAAAAADAAAAQVRoZSBjYWxsZXIncyBiYWxhbmNlIGlzIGluc3VmZmljaWVudCBmb3IgdGhlIHJlcXVlc3RlZCBvcGVyYXRpb24uAAAAAAAAE0luc3VmZmljaWVudEJhbGFuY2UAAAAABAAAAERUaGUgc3BlbmRlcidzIGFsbG93YW5jZSBpcyBpbnN1ZmZpY2llbnQgZm9yIHRoZSByZXF1ZXN0ZWQgb3BlcmF0aW9uLgAAABVJbnN1ZmZpY2llbnRBbGxvd2FuY2UAAAAAAAAFAAAAPVRoZSBjb250cmFjdCBpcyBjdXJyZW50bHkgcGF1c2VkIGFuZCBvcGVyYXRpb25zIGFyZSByZWplY3RlZC4AAAAAAAAOQ29udHJhY3RQYXVzZWQAAAAAAAYAAAAjRmVlIGNvbmZpZ3VyYXRpb24gaGFzIG5vdCBiZWVuIHNldC4AAAAAEEZlZU5vdENvbmZpZ3VyZWQAAAAHAAAAMlRyZWFzdXJ5IGJhbGFuY2UgaXMgaW5zdWZmaWNpZW50IHRvIGNvdmVyIHRoZSBmZWUuAAAAAAAWSW5zdWZmaWNpZW50RmVlQmFsYW5jZQAAAAAACAAAADFObyBmZWUgZXhlbXB0aW9uIGZvdW5kIGZvciB0aGUgc3BlY2lmaWVkIGFkZHJlc3MuAAAAAAAAFEZlZUV4ZW1wdGlvbk5vdEZvdW5kAAAACQAAADNNaW50aW5nIHdvdWxkIGV4Y2VlZCB0aGUgY29uZmlndXJlZCBtYXhpbXVtIHN1cHBseS4AAAAAEU1heFN1cHBseUV4Y2VlZGVkAAAAAAAACgAAAAAAAAANQWxyZWFkeVBhdXNlZAAAAAAAAAsAAAAAAAAACU5vdFBhdXNlZAAAAAAAAAwAAAA2QmF0Y2ggb3BlcmF0aW9ucyBsaXN0IGV4Y2VlZHMgbWF4aW11bSBhbGxvd2VkIGNhcCAoOCkuAAAAAAANQmF0Y2hUb29MYXJnZQAAAAAAAA0AAAAfQmF0Y2ggb3BlcmF0aW9ucyBsaXN0IGlzIGVtcHR5LgAAAAAKQmF0Y2hFbXB0eQAAAAAADgAAADhCYXRjaCBwYXlsb2FkIGV4ZWN1dGlvbiBtYXggbGVkZ2VyIHNlcXVlbmNlIGhhcyBleHBpcmVkLgAAAA5QYXlsb2FkRXhwaXJlZAAAAAAADwAAADhCYXRjaCBwYXlsb2FkIG5vbmNlIGhhcyBhbHJlYWR5IGJlZW4gdXNlZCBvciBpcyBpbnZhbGlkLgAAAA9QYXlsb2FkUmVwbGF5ZWQAAAAAEAAAAKtgcmVzY3VlX3Rva2Vuc2Agd2FzIGNhbGxlZCBvbiB0aGlzIGNvbnRyYWN0J3Mgb3duIHRva2VuIGlkLiBUaGUgdG9rZW4KY29udHJhY3QgY2FuIG5ldmVyIHJlc2N1ZSBpdHNlbGY6IGl0cyBiYWxhbmNlcyBhcmUgYWNjb3VudGVkIHVzZXIKZnVuZHMsIG5vdCBzdHJhbmRlZCBmb3JlaWduIGFzc2V0cy4AAAAADFVua25vd25Ub2tlbgAAABEAAABDTWV0YWRhdGEgd291bGQgY2hhbmdlIGBkZWNpbWFsc2AgYWZ0ZXIgaW5pdGlhbGl6YXRpb24gKGlzc3VlICM5MTEpLgAAAAARRGVjaW1hbHNJbW11dGFibGUAAAAAAAASAAAAvkEgcHJpdmlsZWdlZCBhY3Rpb24gKGZlZS1jb25maWcgY2hhbmdlIG9yIG93bmVyc2hpcCB0cmFuc2Zlcikgd2FzCmF0dGVtcHRlZCB3aGlsZSBpdHMgcHJvcG9zYWwncyB0aW1lbG9jayBkZWxheSBoYWQgbm90IHlldCBlbGFwc2VkCigjOTE0KS4gQ29kZXMgYXJlIGFwcGVuZC1vbmx5IHBlciB0aGlzIGNyYXRlJ3MgQUJJIHBvbGljeS4AAAAAABJUaW1lbG9ja05vdEVsYXBzZWQAAAAAABMAAAC+Tm8gbGl2ZSBwcml2aWxlZ2VkLWFjdGlvbiBwcm9wb3NhbCBleGlzdHMgZm9yIHRoZSByZXF1ZXN0ZWQgYWN0aW9uOgpub25lIHdhcyBwcm9wb3NlZCwgaXQgd2FzIGFscmVhZHkgY29uc3VtZWQsIG9yIGl0IHdhcyBjYW5jZWxsZWQKKCM5MTQpLiBDb2RlcyBhcmUgYXBwZW5kLW9ubHkgcGVyIHRoaXMgY3JhdGUncyBBQkkgcG9saWN5LgAAAAAAGVByaXZpbGVnZVByb3Bvc2FsTm90Rm91bmQAAAAAAAAUAAAAL05vIGxvY2sgcmVjb3JkIGV4aXN0cyBmb3IgdGhlIHJlcXVlc3RlZCBob2xkZXIuAAAAAA5Mb2NrdXBOb3RGb3VuZAAAAAAAFQAAADdUaGUgaG9sZGVyJ3MgbG9jayBoYXMgbm90IHJlYWNoZWQgaXRzIHVubG9jayB0aW1lc3RhbXAuAAAAABFUb2tlbnNTdGlsbExvY2tlZAAAAAAAABY=", + "AAAAAAAAADNSZXR1cm5zIHRoZSBjb25maWd1cmVkIG11bHRpc2lnIGFwcHJvdmFsIHRocmVzaG9sZC4AAAAADWdldF90aHJlc2hvbGQAAAAAAAAAAAAAAQAAAAQ=", "AAAAAAAABABSZXNjdWVzIGEgZm9yZWlnbiBTRVAtNDEgdG9rZW4gYmFsYW5jZSBvdXQgb2YgdGhlIGNvbnRyYWN0LgoKU0VQLTQxIHRva2VucyBzZW50IHRvIHRoZSBjb250cmFjdCBieSBtaXN0YWtlIHdvdWxkIG90aGVyd2lzZSBiZSBzdHVjazoKbm90aGluZyBpbiB0aGUgdG9rZW4ncyBvd24gaW50ZXJmYWNlIG1vdmVzIGEgYmFsYW5jZSB0aGF0IGRvZXMgbm90CmJlbG9uZyB0byBhIGhvbGRlciB3aG8gY2FuIHNpZ24uIFRoaXMgZXNjYXBlIGhhdGNoIGxldHMgdGhlIGFkbWluIHNlbmQKc3VjaCBhIHN0cmFuZGVkIGJhbGFuY2UgdG8gYSByZWNvdmVyeSBhZGRyZXNzLgoKVGhlIGJhbiBsaXN0IGlzIGRlbGliZXJhdGVseSBtaW5pbWFsIGFuZCBleGFjdC4gUmVzY3VpbmcgdGhpcwpjb250cmFjdCdzICpvd24qIHRva2VuIGlkIGlzIHJlamVjdGVkIHdpdGggW2BUb2tlbkVycm9yOjpVbmtub3duVG9rZW5gXQooYHJlc2N1ZV90b2tlbnMoJmVudi5jdXJyZW50X2NvbnRyYWN0X2FkZHJlc3MoKSwgLi4pYCksIGJlY2F1c2UgZXZlcnkKYmFsYW5jZSBpbiB0aGlzIGNvbnRyYWN0J3Mgb3duIGxlZGdlciBlbnRyeSBpcyBhY2NvdW50ZWQgdXNlciBtb25leToKZHJhaW5pbmcgaXQgdGhyb3VnaCB0aGUgcmVzY3VlIGhhdGNoIHdvdWxkIGJlIGluZGlzdGluZ3Vpc2hhYmxlIGZyb20KdGhlZnQuIEFueSAqb3RoZXIqIHRva2VuIGlkIGlzIHJlc2N1YWJsZSwgd2hpY2ggaXMgdGhlIHBvaW50IG9mIHRoZQpoYXRjaDogYnkgY29uc3RydWN0aW9uIHRoZSBjb250cmFjdCBuZXZlciBhY2NvdW50cyBiYWxhbmNlcyBvZiBhIHRva2VuCml0IGRvZXMgbm90IGlzc3VlLCBzbyBubyBhY2NvdW50ZWQgZnVuZHMgY2FuIHNpdCB1bmRlciBhIGZvcmVpZ24gaWQuCgojIFNlY3VyaXR5CgotIEFkbWluLWdhdGVkOiByZXZlcnRzIHVubGVzcyBgY2FsbGVyYCBob2xkcyB0aGUgYEFkbWluYCByb2xlIChvciB0aGUKaW1wbGljaXQgYWxsLXJvbGVzIGdyYW50IHRoZSBhZG1pbiBjYXJyaWVzKSB2aWEKW2BhZG1pbjo6cmVxdWlyZV9hZG1pbmBdAAAADXJlc2N1ZV90b2tlbnMAAAAAAAAEAAAAAAAAAAZjYWxsZXIAAAAAABMAAAAAAAAABXRva2VuAAAAAAAAEwAAAAAAAAACdG8AAAAAABMAAAAAAAAABmFtb3VudAAAAAAACwAAAAEAAAPpAAAD7QAAAAAAAAfQAAAAClRva2VuRXJyb3IAAA==", "AAAAAAAAAn9UcmFuc2ZlcnMgdG9rZW5zIGZyb20gYGZyb21gIHRvIGB0b2Agb24gYmVoYWxmIG9mIGBzcGVuZGVyYC4KCkBub3RpY2UgVHJhbnNmZXJzIGBhbW91bnRgIHRva2VucyBmcm9tIGBmcm9tYCB0byBgdG9gIHVzaW5nIHRoZSBhbGxvd2FuY2UgbWVjaGFuaXNtLiBSZXF1aXJlcyBgc3BlbmRlcmAgdG8gYXV0aGVudGljYXRlIHRoZSBjYWxsLgpAZGV2IFJlamVjdHMgd2l0aCBbYFRva2VuRXJyb3I6OkNvbnRyYWN0UGF1c2VkYF0gd2hpbGUgcGF1c2VkLiBDaGVja3MgcmF0ZSBsaW1pdHMgYW5kCnN1ZmZpY2llbnQgYWxsb3dhbmNlIGJlZm9yZSB0cmFuc2ZlcnJpbmcuIERlZHVjdHMgdGhlIGFsbG93YW5jZSBhZnRlciBhIHN1Y2Nlc3NmdWwKdHJhbnNmZXIuIEVtaXRzIGEgYHRyYW5zZmVyX2Zyb21gIGV2ZW50LgpAcGFyYW0gZW52IFRoZSBTb3JvYmFuIGVudmlyb25tZW50LgpAcGFyYW0gc3BlbmRlciBUaGUgYWRkcmVzcyBjYWxsaW5nIHRoZSBmdW5jdGlvbiAobXVzdCBoYXZlIHN1ZmZpY2llbnQgYWxsb3dhbmNlKS4KQHBhcmFtIGZyb20gVGhlIGFkZHJlc3MgdG8gdHJhbnNmZXIgdG9rZW5zIGZyb20uCkBwYXJhbSB0byBUaGUgcmVjaXBpZW50IGFkZHJlc3MuCkBwYXJhbSBhbW91bnQgVGhlIGFtb3VudCB0byB0cmFuc2Zlci4AAAAADXRyYW5zZmVyX2Zyb20AAAAAAAAEAAAAAAAAAAdzcGVuZGVyAAAAABMAAAAAAAAABGZyb20AAAATAAAAAAAAAAJ0bwAAAAAAEwAAAAAAAAAGYW1vdW50AAAAAAALAAAAAA==", "AAAAAAAAAnlVcGRhdGVzIHRoZSB0b2tlbiBzeW1ib2wgYWZ0ZXIgaW5pdGlhbGl6YXRpb24uCgpAbm90aWNlIFN0b3JlcyBgbmV3X3N5bWJvbGAgaW4gaW5zdGFuY2Ugc3RvcmFnZSBhbmQgZW1pdHMgYHVwZF9zeW1gIHdpdGgKdGhlIGFkbWluLCBvbGQgc3ltYm9sLCBhbmQgbmV3IHN5bWJvbCAoc3BlYzogbWV0YWRhdGEtdXBkYXRlLWZ1bmN0aW9ucwpyZXF1aXJlbWVudHMgMi4xLTIuNykuIEVtcHR5IHN0cmluZ3MgYXJlIGFjY2VwdGVkOyB0aGUgY29udHJhY3QKbXVzdCBiZSBpbml0aWFsaXplZCBvciBgVG9rZW5FcnJvcjo6Tm90SW5pdGlhbGl6ZWRgIGlzIHJldHVybmVkOwpwYXVzZSBzdGF0ZSBkb2VzIG5vdCBhZmZlY3QgdGhlIHVwZGF0ZS4KQHBhcmFtIGVudiBUaGUgU29yb2JhbiBlbnZpcm9ubWVudC4KQHBhcmFtIG5ld19zeW1ib2wgVGhlIG5ldyB0b2tlbiBzeW1ib2wgKG1heSBiZSBlbXB0eTsgc3RvcmVkIHZlcmJhdGltKS4KQHJldHVybiBgT2soKCkpYCBvbiBzdWNjZXNzLCBvciBgVG9rZW5FcnJvcjo6Tm90SW5pdGlhbGl6ZWRgIGlmIHRoZQpjb250cmFjdCBoYXMgbm90IGJlZW4gaW5pdGlhbGl6ZWQuIFBhbmljcyBpZiB0aGUgc3RvcmVkIGFkbWluCmRvZXMgbm90IGF1dGhvcml6ZSB0aGUgaW52b2NhdGlvbi4AAAAAAAANdXBkYXRlX3N5bWJvbAAAAAAAAAEAAAAAAAAACm5ld19zeW1ib2wAAAAAABAAAAABAAAD6QAAA+0AAAAAAAAH0AAAAApUb2tlbkVycm9yAAA=", "AAAAAQAAAGhMb2NrdXAgcGVyaW9kIHN0YXRlIGZvciBhIHNpbmdsZSB1c2VyLCBzdG9yZWQgcGVyIGFkZHJlc3MgdW5kZXIKW2BEYXRhS2V5OjpMb2NrdXBgXS4KCkB0aXRsZSBMb2NrdXBTdGF0ZQAAAAAAAAALTG9ja3VwU3RhdGUAAAAAAgAAADVUb3RhbCBhbW91bnQgb2YgdG9rZW5zIGN1cnJlbnRseSBsb2NrZWQgZm9yIHRoZSB1c2VyLgAAAAAAAAZhbW91bnQAAAAAAAsAAABUVW5peCB0aW1lc3RhbXAgKHNlY29uZHMgc2luY2UgZXBvY2gpIGF0IHdoaWNoIHRoZSBsb2NrZWQgdG9rZW5zCmJlY29tZSB3aXRoZHJhd2FibGUuAAAAEHVubG9ja190aW1lc3RhbXAAAAAG", "AAAAAAAAAj9UcmFuc2ZlcnMgdG9rZW5zIGZyb20gYSBzaW5nbGUgc2VuZGVyIHRvIG11bHRpcGxlIHJlY2lwaWVudHMuCgpAbm90aWNlIFRyYW5zZmVycyBgYW1vdW50YCB0b2tlbnMgZnJvbSBgZnJvbWAgdG8gZWFjaCByZWNpcGllbnQgaW4gc2VxdWVuY2UuIFRoZSBjYWxsZXIgbXVzdCBiZSB0aGUgYGZyb21gIGFkZHJlc3MuCkBkZXYgUmVxdWlyZXMgdGhlIGNhbGxlciB0byBiZSB0aGUgYGZyb21gIGFkZHJlc3MuIFJhdGUgbGltaXRzIGFyZSBjaGVja2VkIHBlciB0cmFuc2Zlci4gVG90YWwgYmFsYW5jZSBpcyB2ZXJpZmllZCBiZWZvcmUgYW55IHRyYW5zZmVycy4KQHBhcmFtIGVudiBUaGUgU29yb2JhbiBlbnZpcm9ubWVudC4KQHBhcmFtIGZyb20gVGhlIGFkZHJlc3Mgc2VuZGluZyB0aGUgdG9rZW5zLgpAcGFyYW0gcmVjaXBpZW50cyBBIGxpc3Qgb2YgKHJlY2lwaWVudCwgYW1vdW50KSBwYWlycy4KQHJldHVybiBgT2soKCkpYCBvbiBzdWNjZXNzLCBvciBhbiBlcnJvciBpZiB0aGUgYmFsYW5jZSBpcyBpbnN1ZmZpY2llbnQsIGFueSBhbW91bnQgaXMgaW52YWxpZCwgb3IgYSByYXRlIGxpbWl0IGlzIGV4Y2VlZGVkLgAAAAAOYmF0Y2hfdHJhbnNmZXIAAAAAAAIAAAAAAAAABGZyb20AAAATAAAAAAAAAApyZWNpcGllbnRzAAAAAAPqAAAD7QAAAAIAAAATAAAACwAAAAEAAAPpAAAD7QAAAAAAAAfQAAAAClRva2VuRXJyb3IAAA==", + "AAAAAAAAACtSZXR1cm5zIHRoZSBjb25maWd1cmVkIG11bHRpc2lnIGFkbWluIHBvb2wuAAAAAA5nZXRfYWRtaW5fcG9vbAAAAAAAAAAAAAEAAAPqAAAAEw==", "AAAAAAAAAN5SZXR1cm5zIHRoZSBjdXJyZW50IGZlZSBjb25maWd1cmF0aW9uLgoKQG5vdGljZSBSZXR1cm5zIHRoZSBjdXJyZW50IGZlZSBjb25maWd1cmF0aW9uIGZvciB0aGUgdG9rZW4gY29udHJhY3QuCkBwYXJhbSBlbnYgVGhlIFNvcm9iYW4gZW52aXJvbm1lbnQuCkByZXR1cm4gVGhlIGZlZSBjb25maWd1cmF0aW9uLCBvciBgVG9rZW5FcnJvcjo6RmVlTm90Q29uZmlndXJlZGAgaWYgbm90IHNldC4AAAAAAA5nZXRfZmVlX2NvbmZpZwAAAAAAAAAAAAEAAAPpAAAH0AAAAAlGZWVDb25maWcAAAAAAAfQAAAAClRva2VuRXJyb3IAAA==", "AAAAAAAAAKtSZXR1cm5zIHRoZSBtYXhpbXVtIHRvdGFsIHN1cHBseSBjYXAuCgpAbm90aWNlIFJldHVybnMgdGhlIG1heGltdW0gc3VwcGx5IHRoYXQgdGhlIHRva2VuIGNhbiBldmVyIGhhdmUuCkBwYXJhbSBlbnYgVGhlIFNvcm9iYW4gZW52aXJvbm1lbnQuCkByZXR1cm4gVGhlIG1heGltdW0gc3VwcGx5IGNhcC4AAAAADmdldF9tYXhfc3VwcGx5AAAAAAAAAAAAAQAAAAs=", "AAAAAAAAAEhDb25maWd1cmVzIHRoZSBtdWx0aS1zaWcgYWRtaW4gcG9vbCBhbmQgYXBwcm92YWwgdGhyZXNob2xkIGZvciB1cGdyYWRlcy4AAAAOc2V0X2FkbWluX3Bvb2wAAAAAAAIAAAAAAAAABHBvb2wAAAPqAAAAEwAAAAAAAAAJdGhyZXNob2xkAAAAAAAABAAAAAA=", @@ -1374,11 +1478,15 @@ export class Client extends ContractClient { "AAAAAAAAAipVcGRhdGVzIG5hbWUgYW5kIHN5bWJvbCB0b2dldGhlciAoIzkxMSkuCgpAbm90aWNlIEFkbWluLW9ubHkgbWV0YWRhdGEgdXBkYXRlciB0aGF0IGNoYW5nZXMgbmFtZSBhbmQgc3ltYm9sIGluIG9uZQpjYWxsLiBgZGVjaW1hbHNgIGlzIG5vdCBhIHBhcmFtZXRlciwgc28gdGhlIGluaXRpYWxpemVkIHNjYWxlCmNhbm5vdCBjaGFuZ2UgdGhyb3VnaCB0aGlzIGVudHJ5IHBvaW50LiBFbWl0cyBgdXBkX21ldGFgIHdpdGgKdGhlIGNhbGxlciwgbmV3IG5hbWUsIGFuZCBuZXcgc3ltYm9sLgpAcGFyYW0gZW52IFRoZSBTb3JvYmFuIGVudmlyb25tZW50LgpAcGFyYW0gY2FsbGVyIFRoZSBhZGRyZXNzIGNhbGxpbmcgdGhpcyBmdW5jdGlvbiAobXVzdCBoYXZlIEFkbWluIHJvbGUpLgpAcGFyYW0gbmFtZSBUaGUgbmV3IHRva2VuIG5hbWUuCkBwYXJhbSBzeW1ib2wgVGhlIG5ldyB0b2tlbiBzeW1ib2wuCkByZXR1cm4gYE9rKCgpKWAgb24gc3VjY2Vzcywgb3IgYFRva2VuRXJyb3I6Ok5vdEluaXRpYWxpemVkYCBpZiB0aGUKY29udHJhY3QgaGFzIG5vdCBiZWVuIGluaXRpYWxpemVkLgAAAAAAD3VwZGF0ZV9tZXRhZGF0YQAAAAADAAAAAAAAAAZjYWxsZXIAAAAAABMAAAAAAAAABG5hbWUAAAAQAAAAAAAAAAZzeW1ib2wAAAAAABAAAAABAAAD6QAAA+0AAAAAAAAH0AAAAApUb2tlbkVycm9yAAA=", "AAAAAAAAAMZSZW1vdmVzIGEgaG9sZGVyJ3MgY29tcGxldGUgbG9jayBhZnRlciBpdHMgdW5sb2NrIHRpbWVzdGFtcCBpcyByZWFjaGVkLgoKRG9lcyBub3QgY2hhbmdlIHRoZSBob2xkZXIncyBiYWxhbmNlIG9yIHRvdGFsIHN1cHBseS4gVGhlIGhvbGRlciBtdXN0CmF1dGhvcml6ZSB0aGUgY2FsbDsgYW4gYWRtaW4gc2lnbmF0dXJlIGlzIG5vdCByZXF1aXJlZC4AAAAAAA93aXRoZHJhd19sb2NrZWQAAAAAAQAAAAAAAAAEdXNlcgAAABMAAAABAAAD6QAAA+0AAAAAAAAH0AAAAApUb2tlbkVycm9yAAA=", "AAAAAAAAAJRBcHByb3ZlcyBhIG11bHRpLXNpZyBnb3Zlcm5hbmNlIHByb3Bvc2FsLgoKQG5vdGljZSBSZWNvcmRzIGBhZG1pbmAncyBhcHByb3ZhbCBmb3IgYHByb3Bvc2FsX2lkYC4KQGRldiBUaGluIHdyYXBwZXIgb3ZlciBbYGFkbWluOjphcHByb3ZlX3Byb3Bvc2FsYF0uAAAAEGFwcHJvdmVfcHJvcG9zYWwAAAACAAAAAAAAAAVhZG1pbgAAAAAAABMAAAAAAAAAC3Byb3Bvc2FsX2lkAAAAAAYAAAAA", + "AAAAAAAAAD5SZXR1cm5zIHJvbGUgYWN0aW9uIGRldGFpbHMgYW5kIGFwcHJvdmFsIHRhbGx5IGZvciBhIHByb3Bvc2FsLgAAAAAAEWdldF9yb2xlX3Byb3Bvc2FsAAAAAAAAAQAAAAAAAAALcHJvcG9zYWxfaWQAAAAABgAAAAEAAAPoAAAH0AAAABhSb2xlR3JhbnRQcm9wb3NhbERldGFpbHM=", "AAAAAAAAAEJSZXR1cm5zIHdoZXRoZXIgYSBnb3Zlcm5hbmNlIHByb3Bvc2FsIGhhcyBtZXQgaXRzIGFwcHJvdmFsIHF1b3J1bS4AAAAAABFpc19wcm9wb3NhbF9yZWFkeQAAAAAAAAEAAAAAAAAAC3Byb3Bvc2FsX2lkAAAAAAYAAAABAAAAAQ==", "AAAAAAAAAaRTZXRzIGEgZmVlIGV4ZW1wdGlvbiBmb3IgYSBzcGVjaWZpYyBhZGRyZXNzLgoKQG5vdGljZSBDb25maWd1cmVzIGEgZmVlIGV4ZW1wdGlvbiBmb3IgdGhlIGdpdmVuIGFkZHJlc3MuIE9ubHkgdGhlIGFkbWluIGNhbiBjYWxsIHRoaXMgZnVuY3Rpb24uCkBwYXJhbSBlbnYgVGhlIFNvcm9iYW4gZW52aXJvbm1lbnQuCkBwYXJhbSBjYWxsZXIgVGhlIGFkZHJlc3MgY2FsbGluZyB0aGlzIGZ1bmN0aW9uIChtdXN0IGhhdmUgQWRtaW4gcm9sZSkuCkBwYXJhbSBhZGRyZXNzIFRoZSBhZGRyZXNzIHRvIGV4ZW1wdCBmcm9tIGZlZXMuCkBwYXJhbSBleGVtcHRpb24gVGhlIGZlZSBleGVtcHRpb24gY29uZmlndXJhdGlvbi4KQHJldHVybiBgT2soKCkpYCBvbiBzdWNjZXNzLCBvciBhbiBlcnJvciBpZiB0aGUgY2FsbGVyIGlzIHVuYXV0aG9yaXplZC4AAAARc2V0X2ZlZV9leGVtcHRpb24AAAAAAAADAAAAAAAAAAZjYWxsZXIAAAAAABMAAAAAAAAAB2FkZHJlc3MAAAAAEwAAAAAAAAAJZXhlbXB0aW9uAAAAAAAH0AAAAAxGZWVFeGVtcHRpb24AAAABAAAD6QAAA+0AAAAAAAAH0AAAAApUb2tlbkVycm9yAAA=", "AAAAAAAAAThUcmFuc2ZlcnMgY29udHJhY3Qgb3duZXJzaGlwIHRvIGEgbmV3IGFkbWluLgoKQG5vdGljZSBUcmFuc2ZlcnMgdGhlIGFkbWluIHJvbGUgdG8gYG5ld19hZG1pbmAuIE9ubHkgdGhlIGN1cnJlbnQgYWRtaW4gY2FuIGNhbGwgdGhpcyBmdW5jdGlvbi4KQHBhcmFtIGVudiBUaGUgU29yb2JhbiBlbnZpcm9ubWVudC4KQHBhcmFtIG5ld19hZG1pbiBUaGUgYWRkcmVzcyB0byBiZWNvbWUgdGhlIG5ldyBhZG1pbi4KQHJldHVybiBgT2soKCkpYCBvbiBzdWNjZXNzLCBvciBhbiBlcnJvciBpZiB0aGUgY2FsbGVyIGlzIG5vdCB0aGUgY3VycmVudCBhZG1pbi4AAAASdHJhbnNmZXJfb3duZXJzaGlwAAAAAAABAAAAAAAAAAluZXdfYWRtaW4AAAAAAAATAAAAAQAAA+kAAAPtAAAAAAAAB9AAAAAKVG9rZW5FcnJvcgAA", + "AAAAAAAAAD5DcmVhdGVzIGEgbXVsdGlzaWcgcHJvcG9zYWwgdGhhdCBncmFudHMgYSByb2xlIGFmdGVyIGFwcHJvdmFsLgAAAAAAFGNyZWF0ZV9yb2xlX3Byb3Bvc2FsAAAABAAAAAAAAAAHY3JlYXRvcgAAAAATAAAAAAAAAARyb2xlAAAH0AAAAARSb2xlAAAAAAAAAAZ0YXJnZXQAAAAAABMAAAAAAAAAC2Rlc2NyaXB0aW9uAAAAABAAAAABAAAABg==", "AAAAAAAAAX1SZW1vdmVzIGEgZmVlIGV4ZW1wdGlvbiBmb3IgYSBzcGVjaWZpYyBhZGRyZXNzLgoKQG5vdGljZSBSZW1vdmVzIHRoZSBmZWUgZXhlbXB0aW9uIGZvciB0aGUgZ2l2ZW4gYWRkcmVzcy4gT25seSB0aGUgYWRtaW4gY2FuIGNhbGwgdGhpcyBmdW5jdGlvbi4KQHBhcmFtIGVudiBUaGUgU29yb2JhbiBlbnZpcm9ubWVudC4KQHBhcmFtIGNhbGxlciBUaGUgYWRkcmVzcyBjYWxsaW5nIHRoaXMgZnVuY3Rpb24gKG11c3QgaGF2ZSBBZG1pbiByb2xlKS4KQHBhcmFtIGFkZHJlc3MgVGhlIGFkZHJlc3MgdG8gcmVtb3ZlIHRoZSBleGVtcHRpb24gZnJvbS4KQHJldHVybiBgT2soKCkpYCBvbiBzdWNjZXNzLCBvciBhbiBlcnJvciBpZiB0aGUgY2FsbGVyIGlzIHVuYXV0aG9yaXplZC4AAAAAAAAUcmVtb3ZlX2ZlZV9leGVtcHRpb24AAAACAAAAAAAAAAZjYWxsZXIAAAAAABMAAAAAAAAAB2FkZHJlc3MAAAAAEwAAAAEAAAPpAAAD7QAAAAAAAAfQAAAAClRva2VuRXJyb3IAAA==", "AAAAAAAABABFeGVjdXRlcyBhIGJhdGNoIG9mIGF1dGhvcml6ZWQgb3BlcmF0aW9ucyAoYXBwcm92ZSBhbmQgdHJhbnNmZXIpIG9uIGJlaGFsZiBvZiBgZnJvbWAuCgpAbm90aWNlIEV4ZWN1dGVzIGEgYm91bmRlZCBsaXN0IG9mIGlubmVyIG9wZXJhdGlvbnMgKGFwcHJvdmUgYW5kIHRyYW5zZmVyIG9ubHkpIGluIGEgc2luZ2xlIGF1dGhvcml6ZWQgaW52b2NhdGlvbi4KQGRldiBIYXJkIGNhcCBvZiA4IG9wZXJhdGlvbnMgcGVyIGJhdGNoLiBSZXF1aXJlcyBgZnJvbWAgdG8gYXV0aGVudGljYXRlLgpSZXBsYXktcHJvdGVjdGVkIHZpYSBgbm9uY2VgIChzdG9yZWQgaW4gcGVyc2lzdGVudCBzdG9yYWdlKSBhbmQgYG1heF9sZWRnZXJgIChsZWRnZXIgZXhwaXJ5KS4KQWRtaW4tb25seSBmdW5jdGlvbnMgYXJlIHN0cmljdGx5IHVucmVhY2hhYmxlIGFzIGBCYXRjaE9wYCBpcyBib3VuZGVkIHRvIGBBcHByb3ZlYCBhbmQgYFRyYW5zZmVyYC4KCiMgQXJndW1lbnRzCiogYGVudmAgLSBUaGUgU29yb2JhbiBlbnZpcm9ubWVudC4KKiBgZnJvbWAgLSBUaGUgd2FsbGV0IGF1dGhvcml6aW5nIHRoZSBiYXRjaCBvcGVyYXRpb25zLgoqIGBvcGVyYXRpb25zYCAtIFZlY3RvciBvZiBpbm5lciBvcGVyYXRpb25zIChgQmF0Y2hPcDo6QXBwcm92ZWAgb3IgYEJhdGNoT3A6OlRyYW5zZmVyYCksIHVwIHRvIDggb3BlcmF0aW9ucy4KKiBgbm9uY2VgIC0gRXhwZWN0ZWQgc2VxdWVudGlhbCB0cmFuc2FjdGlvbiBub25jZSBmb3IgYGZyb21gLgoqIGBtYXhfbGVkZ2VyYCAtIE1heGltdW0gbGVkZ2VyIHNlcXVlbmNlIG51bWJlciB1bnRpbCB3aGljaCB0aGlzIHBheWxvYWQgaXMgdmFsaWQgKDAgPSBubyBleHBpcnkpLgoKIyBQYW5pY3MKUGFuaWNzIHdpdGggY29udHJhY3QgZXJyb3IgaWYgaW5pdGlhbGl6ZWQvcGF1c2VkIGNoZWNrcyBvciBhdXRoZW50aWNhdGlvbiBmYWlsLgoKIyBFdmVudHMKRW1pdHMgYGFwcHJvdmVgIGFuZCBgdHJhbnNmZXJgIGV2ZW50cyBmb3IgZWFjaCBleGVjdXRlZCBvcGVyYXRpb24sIGFuZCBgZXhlY19idGNoAAAAFWV4ZWN1dGVfZnJvbV9jb250cmFjdAAAAAAAAAQAAAAAAAAABGZyb20AAAATAAAAAAAAAApvcGVyYXRpb25zAAAAAAPqAAAH0AAAAAdCYXRjaE9wAAAAAAAAAAAFbm9uY2UAAAAAAAAGAAAAAAAAAAptYXhfbGVkZ2VyAAAAAAAEAAAAAQAAA+kAAAPtAAAAAAAAB9AAAAAKVG9rZW5FcnJvcgAA", + "AAAAAAAAAEFFeGVjdXRlcyBhIHJvbGUgZ3JhbnQgYWZ0ZXIgaXRzIG11bHRpc2lnIHByb3Bvc2FsIHJlYWNoZXMgcXVvcnVtLgAAAAAAABVleGVjdXRlX3JvbGVfcHJvcG9zYWwAAAAAAAACAAAAAAAAAAhleGVjdXRvcgAAABMAAAAAAAAAC3Byb3Bvc2FsX2lkAAAAAAYAAAABAAAD6QAAA+0AAAAAAAAH0AAAAApBZG1pbkVycm9yAAA=", + "AAAAAAAAAD1MaXN0cyBwZW5kaW5nIGFuZCBhcHByb3ZlZCBsZWdhY3kgbXVsdGlzaWcgcHJvcG9zYWxzIGJ5IHBhZ2UuAAAAAAAAFWxpc3RfbGVnYWN5X3Byb3Bvc2FscwAAAAAAAAEAAAAAAAAAC3N0YXJ0X2FmdGVyAAAAAAYAAAABAAAH0AAAABNMZWdhY3lQcm9wb3NhbExpc3RzAA==", "AAAAAAAAAS5SZWFkLW9ubHkgdmlldyBvZiB0aGUgcHJpdmlsZWdlZC1hY3Rpb24gcHJvcG9zYWwgZm9yIGBhY3Rpb25gICgjOTE0KS4KCkBub3RpY2UgUmV0dXJucyB0aGUgcGVuZGluZy9leGVjdXRlZC9jYW5jZWxsZWQgcHJvcG9zYWwgZm9yIHRoZSBhY3Rpb24sIGlmIGFueS4KQHBhcmFtIGVudiBUaGUgU29yb2JhbiBlbnZpcm9ubWVudC4KQHBhcmFtIGFjdGlvbiBUaGUgcHJpdmlsZWdlZCBhY3Rpb24gdG8gcXVlcnkuCkByZXR1cm4gVGhlIHByb3Bvc2FsIHN0YXRlLCBvciBgTm9uZWAgd2hlbiBub3RoaW5nIHdhcyBldmVyIHByb3Bvc2VkLgAAAAAAFmdldF9wcml2aWxlZ2VfcHJvcG9zYWwAAAAAAAEAAAAAAAAABmFjdGlvbgAAAAAH0AAAAA9Qcml2aWxlZ2VBY3Rpb24AAAAAAQAAA+gAAAfQAAAAEVByaXZpbGVnZVByb3Bvc2FsAAAA", "AAAAAAAAAlFDYW5jZWxzIGEgcGVuZGluZyBwcml2aWxlZ2VkIGFjdGlvbiAoIzkxNCkuIEFkbWluLW9ubHk6IGNhbmNlbGxhdGlvbgppcyB0aGUgZW1lcmdlbmN5IGJyYWtlLCBhdmFpbGFibGUgdG8gYW55IGFkbWluIGR1cmluZyB0aGUgZGVsYXkKd2luZG93IOKAlCBpdCBtdXN0IG5vdCBiZSBnYXRlZCBvbiB0aGUgY29tcHJvbWlzZWQga2V5IGFsb25lLgoKQG5vdGljZSBDYW5jZWxzIGEgcGVuZGluZyBwcml2aWxlZ2VkLWFjdGlvbiBwcm9wb3NhbC4KQGRldiBBZG1pbi1vbmx5LiBBIGNhbmNlbGxlZCBwcm9wb3NhbCBjYW4gbmV2ZXIgZXhlY3V0ZTsgYSBmcmVzaCBvbmUKbWF5IGJlIHByb3Bvc2VkIGFmdGVyd2FyZHMuCkBwYXJhbSBlbnYgVGhlIFNvcm9iYW4gZW52aXJvbm1lbnQuCkBwYXJhbSBjYWxsZXIgVGhlIGFkbWluIGNhbmNlbGxpbmcgdGhlIGFjdGlvbi4KQHBhcmFtIGFjdGlvbiBUaGUgcHJpdmlsZWdlZCBhY3Rpb24gdG8gY2FuY2VsLgpAcmV0dXJuIGBPaygoKSlgIG9uIHN1Y2Nlc3MsIG9yIFtgVG9rZW5FcnJvcjo6UHJpdmlsZWdlUHJvcG9zYWxOb3RGb3VuZGBdCmlmIG5vIGxpdmUgcHJvcG9zYWwgZXhpc3RzIGZvciB0aGUgYWN0aW9uLgAAAAAAABdjYW5jZWxfcHJpdmlsZWdlX2FjdGlvbgAAAAACAAAAAAAAAAZjYWxsZXIAAAAAABMAAAAAAAAABmFjdGlvbgAAAAAH0AAAAA9Qcml2aWxlZ2VBY3Rpb24AAAAAAQAAA+kAAAPtAAAAAAAAB9AAAAAKVG9rZW5FcnJvcgAA", "AAAAAAAAArtQcm9wb3NlcyBhIHByaXZpbGVnZWQgYWN0aW9uICgjOTE0KTogYSBmZWUtY29uZmlnIGNoYW5nZSBvciBhbgpvd25lcnNoaXAgdHJhbnNmZXIuIEFkbWluLW9ubHkuIFRoZSBhY3Rpb24gYmVjb21lcyBleGVjdXRhYmxlIGFmdGVyCnRoZSAyNGggdGltZWxvY2sgYW5kIGlzIGFwcGxpZWQgYnkgdGhlIG1hdGNoaW5nIGVmZmVjdCBmdW5jdGlvbgooYHNldF9mZWVfY29uZmlnYCAvIGB0cmFuc2Zlcl9vd25lcnNoaXBgKSwgd2hpY2ggY29uc3VtZXMgdGhlCnByb3Bvc2FsIGF0IHRoZSBwb2ludCBvZiBlZmZlY3QuCgpAbm90aWNlIFByb3Bvc2VzIGEgcHJpdmlsZWdlZCBhY3Rpb24gdW5kZXIgdGhlICM5MTQgdGltZWxvY2suCkBkZXYgQWRtaW4tb25seS4gUmVqZWN0cyB3aGlsZSBhIGxpdmUgcHJvcG9zYWwgZm9yIHRoZSBzYW1lIGFjdGlvbgpraW5kIGlzIHBlbmRpbmc7IHJlc3VibWl0dGluZyBhZnRlciBleGVjdXRpb24vY2FuY2VsbGF0aW9uCnJlc3RhcnRzIHRoZSBjbG9jay4KQHBhcmFtIGVudiBUaGUgU29yb2JhbiBlbnZpcm9ubWVudC4KQHBhcmFtIHN1Ym1pdHRlciBUaGUgYWRtaW4gcHJvcG9zaW5nIHRoZSBhY3Rpb24uCkBwYXJhbSBhY3Rpb24gVGhlIHByaXZpbGVnZWQgYWN0aW9uIHRvIHNjaGVkdWxlLgpAcmV0dXJuIFRoZSB1bml4IHRpbWVzdGFtcCBhdCB3aGljaCB0aGUgYWN0aW9uIGJlY29tZXMgZXhlY3V0YWJsZS4AAAAAGHByb3Bvc2VfcHJpdmlsZWdlX2FjdGlvbgAAAAIAAAAAAAAACXN1Ym1pdHRlcgAAAAAAABMAAAAAAAAABmFjdGlvbgAAAAAH0AAAAA9Qcml2aWxlZ2VBY3Rpb24AAAAAAQAAA+kAAAAGAAAH0AAAAApUb2tlbkVycm9yAAA=", @@ -1389,16 +1497,18 @@ export class Client extends ContractClient { "AAAAAQAAAAAAAAAAAAAAD1JhdGVMaW1pdENvbmZpZwAAAAACAAAAAAAAAAVsaW1pdAAAAAAAAAYAAAAAAAAADndpbmRvd19zZWNvbmRzAAAAAAAG", "AAAAAAAAACtTZXQgZ2xvYmFsIHJhdGUgbGltaXQgZm9yIGFuIG9wZXJhdGlvbiB0eXBlAAAAABVzZXRfZ2xvYmFsX3JhdGVfbGltaXQAAAAAAAAEAAAAAAAAAAZjYWxsZXIAAAAAABMAAAAAAAAADm9wZXJhdGlvbl90eXBlAAAAAAAQAAAAAAAAAAVsaW1pdAAAAAAAAAYAAAAAAAAADndpbmRvd19zZWNvbmRzAAAAAAAGAAAAAA==", "AAAAAAAAADBTZXQgcGVyLWFkZHJlc3MgcmF0ZSBsaW1pdCBmb3IgYW4gb3BlcmF0aW9uIHR5cGUAAAAWc2V0X2FkZHJlc3NfcmF0ZV9saW1pdAAAAAAABQAAAAAAAAAGY2FsbGVyAAAAAAATAAAAAAAAAAdhZGRyZXNzAAAAABMAAAAAAAAADm9wZXJhdGlvbl90eXBlAAAAAAAQAAAAAAAAAAVsaW1pdAAAAAAAAAYAAAAAAAAADndpbmRvd19zZWNvbmRzAAAAAAAGAAAAAA==", - "AAAAAgAAAbFTdG9yYWdlIGtleXMgZm9yIHRoZSBhY2Nlc3MtY29udHJvbCBsYXllci4KCmAjW2NvbnRyYWN0dHlwZV1gIGRlcml2ZXMgYSBkaXN0aW5jdCBsZWRnZXIga2V5IGZvciBldmVyeSB2YXJpYW50IChhbmQsCmZvciBgUm9sZShSb2xlLCBBZGRyZXNzKWAsIGZvciBldmVyeSBgKFJvbGUsIEFkZHJlc3MpYCBwYWlyKSwgc28gZW50cmllcwpuZXZlciBjb2xsaWRlIHdpdGggZWFjaCBvdGhlciBvciB3aXRoIHRoZSBvdGhlciB2YXJpYW50cyBiZWxvdy4KCkB0aXRsZSBBZG1pbktleQpAbm90aWNlIEVudW1lcmF0ZXMgdGhlIHN0b3JhZ2Uga2V5cyB1c2VkIGJ5IHRoZSBhY2Nlc3MtY29udHJvbCBsYXllci4KQGRldiBFYWNoIHZhcmlhbnQgbWFwcyB0byBhIGRpc3RpbmN0IGxlZGdlciBzbG90OyBhcHBlbmQgbmV3IHZhcmlhbnRzIHJhdGhlciB0aGFuIHJlb3JkZXJpbmcuAAAAAAAAAAAAAAhBZG1pbktleQAAAA8AAAAAAAAAOVRoZSBzaW5ndWxhciBjb250cmFjdCBhZG1pbiBhZGRyZXNzLCBzZXQgdmlhIGBzZXRfYWRtaW5gLgAAAAAAAAVBZG1pbgAAAAAAAAEAAAEkTGVnYWN5IHBlci1yb2xlIG1lbWJlcnNoaXAgZmxhZzogbWFwcyBhIGAoUm9sZSwgQWRkcmVzcylgIHBhaXIgdG8gYHRydWVgCndoZW4gYGFkZHJlc3NgIGhlbGQgYHJvbGVgLiBTdXBlcnNlZGVkIGJ5IFtgQWRtaW5LZXk6OlJvbGVNYXNrYF07IGtlcHQgc28KcHJldmlvdXNseSBwZXJzaXN0ZWQga2V5cyBrZWVwIGRlY29kaW5nLiBOZXcgd3JpdGVzIGdvIHRvIHRoZSBtYXNrLCBhbmQKbGVnYWN5IGVudHJpZXMgZm9yIGFuIGFkZHJlc3MgYXJlIHJlbW92ZWQgb25jZSBpdHMgbWFzayBpcyBmaXJzdCB3cml0dGVuLgAAAARSb2xlAAAAAgAAB9AAAAAEUm9sZQAAABMAAAABAAAAfE1hcHMgYW4gYChBZGRyZXNzLCBSb2xlKWAgcGFpciB0byBgdHJ1ZWAgd2hlbiBgYWRkcmVzc2AgaG9sZHMgYHJvbGVgLgpUaGlzIGlzIHRoZSBBZGRyZXNzLXRvLVJvbGUgbWFwcGluZyBzdG9yYWdlIHN0cnVjdHVyZS4AAAALQWRkcmVzc1JvbGUAAAAAAgAAABMAAAfQAAAABFJvbGUAAAAAAAAAOU11bHRpLXNpZyBhZG1pbiBwb29sIGFkZHJlc3Nlcywgc2V0IHZpYSBgc2V0X2FkbWluX3Bvb2xgLgAAAAAAAAlBZG1pblBvb2wAAAAAAAAAAAAANU11bHRpLXNpZyBhcHByb3ZhbCB0aHJlc2hvbGQsIHNldCBhbG9uZ3NpZGUgdGhlIHBvb2wuAAAAAAAACVRocmVzaG9sZAAAAAAAAAEAAAAvR292ZXJuYW5jZSBwcm9wb3NhbCBkYXRhLCBrZXllZCBieSBwcm9wb3NhbCBJRC4AAAAACFByb3Bvc2FsAAAAAQAAAAYAAAAAAAAAK0F1dG8taW5jcmVtZW50aW5nIGNvdW50ZXIgZm9yIHByb3Bvc2FsIElEcy4AAAAAEVByb3Bvc2FsSWRDb3VudGVyAAAAAAAAAQAAAOpNYXBzIGEgcXVvcmF0ZSBwcm9wb3NhbCBJRCB0byB0aGUgdW5peCB0aW1lc3RhbXAgKHNlY29uZHMpIGF0IHdoaWNoIGl0cwptYW5kYXRvcnkgdGltZWxvY2sgZXhwaXJlcyBhbmQgZXhlY3V0aW9uIG1heSBwcm9jZWVkLiBSZWNvcmRlZCBvbmNlLAp3aGVuIHRoZSBhcHByb3ZhbCB0aHJlc2hvbGQgaXMgZmlyc3QgbWV0OyBhYnNlbnQgd2hpbGUgdGhlIHByb3Bvc2FsIGlzCnN0aWxsIHNob3J0IG9mIHF1b3J1bS4AAAAAABBQcm9wb3NhbFRpbWVsb2NrAAAAAQAAAAYAAAABAAAARlN1cGVyLWFkbWluIG1hcHBpbmcgcG9wdWxhdGVkIGJ5IGBtaWdyYXRlX2FkbWluYCBmb3IgbGVnYWN5IGNvbnRyYWN0cy4AAAAAAApTdXBlckFkbWluAAAAAAABAAAAEwAAAAEAAAE/TXVsdGktc2lnIFdBU00gdXBncmFkZSBwcm9wb3NhbCBzdGF0ZSwga2V5ZWQgYnkgdXBncmFkZSBwcm9wb3NhbCBJRC4KTGl2ZXMgaW4gYHBlcnNpc3RlbnQoKWAgKHVubGlrZSBbYEFkbWluS2V5OjpQcm9wb3NhbGBdKSBzbyBlYWNoIHByb3Bvc2FsCmNhcnJpZXMgaXRzIG93biBUVEwgaW5zdGVhZCBvZiByaWRpbmcgdGhlIHNoYXJlZCBpbnN0YW5jZSBUVEwsIGFuZCBzbyBhCmdyb3dpbmcgc2V0IG9mIHByb3Bvc2FscyBkb2VzIG5vdCBpbmZsYXRlIHRoZSBpbnN0YW5jZSBlbnRyeSB0aGF0IGV2ZXJ5Cmludm9jYXRpb24gbG9hZHMgYW5kIHdyaXRlcyBiYWNrLgAAAAAPVXBncmFkZVByb3Bvc2FsAAAAAAEAAAAGAAAAAAAAAIxBdXRvLWluY3JlbWVudGluZyBjb3VudGVyIGZvciB1cGdyYWRlIHByb3Bvc2FsIElEcy4gRGlzdGluY3QgZnJvbQpbYEFkbWluS2V5OjpQcm9wb3NhbElkQ291bnRlcmBdLCBzbyB0aGUgdHdvIGZsb3dzIG5ldmVyIHNoYXJlIGFuIElEIHNwYWNlLgAAABhVcGdyYWRlUHJvcG9zYWxJZENvdW50ZXIAAAABAAAAzlRoZSBsaXZlIHByaXZpbGVnZWQtYWN0aW9uIHByb3Bvc2FsIGZvciBhIGdpdmVuIGFjdGlvbiBraW5kICgjOTE0KS4KT25lIGVudHJ5IHBlciBhY3Rpb24gKGZlZSBjb25maWcsIG93bmVyc2hpcCB0cmFuc2ZlcikgaW4gYHBlcnNpc3RlbnQoKWAKc3RvcmFnZSBzbyBhIHBlbmRpbmcgcHJvcG9zYWwncyBjbG9jayBzdXJ2aXZlcyBpbnN0YW5jZSBhcmNoaXZpbmcuAAAAAAARUHJpdmlsZWdlUHJvcG9zYWwAAAAAAAABAAAH0AAAAA9Qcml2aWxlZ2VBY3Rpb24AAAAAAQAAAdVNYXBzIGFuIGFkZHJlc3MgdG8gaXRzIHJvbGUgYml0bWFzazogYml0IGBpYCBpcyBzZXQgd2hlbiB0aGUgYWRkcmVzcwpob2xkcyB0aGUgcm9sZSB3aG9zZSBiaXQgaXMgYDEgPDwgaWAgKHNlZSBbYFJPTEVfQklUX0FETUlOYF0gYW5kCmZyaWVuZHMpLiBPbmUgbGVkZ2VyIGVudHJ5IHBlciBhZGRyZXNzOyBncmFudHMgYW5kIHJldm9rZXMgYXJlIGEKbG9hZCAvIGJpdHdpc2UtT1IgLyBzdG9yZSBvbiB0aGlzIGVudHJ5LgoKU3VwZXJzZWRlcyBbYEFkbWluS2V5OjpSb2xlKFJvbGUsIEFkZHJlc3MpYF0sIHdoaWNoIGlzIHJldGFpbmVkIG9ubHkgc28KcHJldmlvdXNseSBwZXJzaXN0ZWQga2V5cyBrZWVwIGRlY29kaW5nOyBlbnRyaWVzIHVuZGVyIHRoZSBsZWdhY3kga2V5CmFyZSBtaWdyYXRlZCBpbnRvIHRoZSBtYXNrIG9uIGZpcnN0IHdyaXRlIGFuZCBhcmUgc3RpbGwgcmVhZCBhcyBhCmZhbGxiYWNrIHVudGlsIHRoZW4uAAAAAAAACFJvbGVNYXNrAAAAAQAAABMAAAABAAAA4U1hcmtzIGEgV0FTTSBoYXNoIGFzIGluc3RhbGxlZCBvbiB0aGUgbGVkZ2VyICh1cGxvYWRlZCB2aWEKYGVudi5kZXBsb3llcigpLnVwbG9hZF9jb250cmFjdF93YXNtYCBhbmQgcmVnaXN0ZXJlZCBieSBhbiBhZG1pbiksCm1ha2luZyBpdCBlbGlnaWJsZSB0byBiZSByZWZlcmVuY2VkIGJ5IGFuIHVwZ3JhZGUgcHJvcG9zYWwuIENoZWNrZWQgYnkKW2ByZXF1aXJlX3ZhbGlkX3dhc21faGFzaGBdLgAAAAAAABFJbnN0YWxsZWRXYXNtSGFzaAAAAAAAAAEAAAPuAAAAIAAAAAAAAAENTGVkZ2VyIHNlcXVlbmNlIHJlY29yZGVkIHdoZW4gdGhpcyBjb250cmFjdCBleHRlbmRzIGluc3RhbmNlIFRUTC4KR3Vlc3QgV0FTTSBvbiBzb3JvYmFuLXNkayAyMi4wLjExIGNhbm5vdCByZWFkIHRoZSBob3N0IGluc3RhbmNlIFRUTCwgc28KW2BnZXRfaW5zdGFuY2VfdHRsYF0gZGVyaXZlcyBhIG5vbi1uZWdhdGl2ZSByZW1haW5pbmcgbGlmZXRpbWUgZnJvbSB0aGlzCnZhbHVlLiBJdCBpcyBub3Qgb25lIG9mIHRoZSBmaXZlIG1vbml0b3JlZCBzaW5nbGV0b24ga2V5cy4AAAAAAAARSW5zdGFuY2VMaXZlVW50aWwAAAA=", - "AAAABAAAAOVFcnJvcnMgcmV0dXJuZWQgYnkgdGhlIGFkbWluIGFjY2Vzcy1jb250cm9sIG1vZHVsZS4KCkB0aXRsZSBBZG1pbkVycm9yCkBub3RpY2UgRW51bWVyYXRlcyB0aGUgZXJyb3IgY29kZXMgcmV0dXJuZWQgYnkgdGhlIGFkbWluIGFjY2Vzcy1jb250cm9sIG1vZHVsZS4KQGRldiBEaXNjcmltaW5hbnRzIGFyZSBBQkktc3RhYmxlOyBhcHBlbmQgbmV3IHZhcmlhbnRzIHJhdGhlciB0aGFuIHJlb3JkZXJpbmcuAAAAAAAAAAAAAApBZG1pbkVycm9yAAAAAAAdAAAAQ1VudXNlZDsga2VwdCBmb3IgQUJJIHN0YWJpbGl0eS4gUHJlZmVyIFtgQWRtaW5FcnJvcjo6Um9sZU5vdEhlbGRgXS4AAAAADlJvbGVOb3RHcmFudGVkAAAAAAABAAAAVUFuIGFkZHJlc3MgZG9lcyBub3QgaG9sZCB0aGUgcmVxdWlyZWQgcm9sZSAoZS5nLiBgcmV2b2tlX3JvbGVgIGNhbGxlZCBvbiBub24taG9sZGVyKS4AAAAAAAALUm9sZU5vdEhlbGQAAAAAAgAAAEhgcmVxdWlyZV9yb2xlX2d1YXJkYCBmYWlsZWQ6IHRoZSBjYWxsZXIgaXMgbm90IGF1dGhvcml6ZWQgZm9yIHRoaXMgcm9sZS4AAAAQVW5hdXRob3JpemVkUm9sZQAAAAMAAAA7QW4gb3BlcmF0aW9uIHdhcyBhdHRlbXB0ZWQgd2l0aCB0aGUgY2Fub25pY2FsIHplcm8gYWRkcmVzcy4AAAAADkludmFsaWRBZGRyZXNzAAAAAAAEAAAAQkEgcm9sZSB2YWx1ZSB0aGF0IGlzIG5vdCByZWNvZ25pemVkIGJ5IHRoaXMgY29udHJhY3Qgd2FzIHN1cHBsaWVkLgAAAAAAC0ludmFsaWRSb2xlAAAAAAUAAABXVGhlIGNvbnRyYWN0IGhhcyBhbHJlYWR5IGJlZW4gaW5pdGlhbGl6ZWQ7IGNhbGxpbmcgYGluaXRfc3RvcmFnZWAgYWdhaW4KaXMgbm90IGFsbG93ZWQuAAAAABJBbHJlYWR5SW5pdGlhbGl6ZWQAAAAAAAYAAAA+VGhlIGFwcHJvdmFsIHRocmVzaG9sZCBpcyB6ZXJvIG9yIGV4Y2VlZHMgdGhlIGFkbWluLXBvb2wgc2l6ZS4AAAAAABBJbnZhbGlkVGhyZXNob2xkAAAABwAAADFUaGUgcmVxdWVzdGVkIGdvdmVybmFuY2UgcHJvcG9zYWwgZG9lcyBub3QgZXhpc3QuAAAAAAAAEFByb3Bvc2FsTm90Rm91bmQAAAAIAAAAPFRoZSByZXF1ZXN0ZWQgZ292ZXJuYW5jZSBwcm9wb3NhbCBoYXMgYWxyZWFkeSBiZWVuIGV4ZWN1dGVkLgAAABdQcm9wb3NhbEFscmVhZHlFeGVjdXRlZAAAAAAJAAAAQVRoZSBhZG1pbiBoYXMgYWxyZWFkeSBhcHByb3ZlZCB0aGUgcmVxdWVzdGVkIGdvdmVybmFuY2UgcHJvcG9zYWwuAAAAAAAAF1Byb3Bvc2FsQWxyZWFkeUFwcHJvdmVkAAAAAAoAAAA/VGhlIGdvdmVybmFuY2UgcHJvcG9zYWwgaGFzIG5vdCByZWFjaGVkIGl0cyBhcHByb3ZhbCB0aHJlc2hvbGQuAAAAAA9UaHJlc2hvbGROb3RNZXQAAAAACwAAAEJUaGUgcHJvcG9zYWwgaGFzIG5vdCBnYXRoZXJlZCBlbm91Z2ggYXBwcm92YWxzIHRvIG1lZXQgdGhlIHF1b3J1bS4AAAAAAAxRdW9ydW1Ob3RNZXQAAAAMAAAAg1RoZSBtYW5kYXRvcnkgdGltZWxvY2sgZGVsYXkgaGFzIG5vdCBlbGFwc2VkIHlldDogdGhlIGN1cnJlbnQgbGVkZ2VyCnRpbWVzdGFtcCBpcyBzdGlsbCBiZWZvcmUgdGhlIHByb3Bvc2FsJ3MgcmVjb3JkZWQgdW5sb2NrIHRpbWUuAAAAAA5UaW1lbG9ja0FjdGl2ZQAAAAAADQAAAGlBIHN1cHBsaWVkIFdBU00gaGFzaCBmYWlsZWQgW2ByZXF1aXJlX3ZhbGlkX3dhc21faGFzaGBdOiBpdCBpcyBub3QKcmVnaXN0ZXJlZCBhcyBpbnN0YWxsZWQgb24gdGhlIGxlZGdlci4AAAAAAAAPSW52YWxpZFdhc21IYXNoAAAAAA4AAAB0YGNhbmNlbF9wcm9wb3NhbGAgd2FzIGNhbGxlZCBieSBhbiBhZGRyZXNzIG90aGVyIHRoYW4gdGhlCltgVXBncmFkZVByb3Bvc2FsOjpwcm9wb3NlcmBdIHRoYXQgc3VibWl0dGVkIHRoZSBwcm9wb3NhbC4AAAALTm90UHJvcG9zZXIAAAAADwAAAKpgY2FuY2VsX3Byb3Bvc2FsYCB3YXMgY2FsbGVkIG9uIGEgcHJvcG9zYWwgd2hvc2Ugc3RhdHVzIGlzIGFscmVhZHkKdGVybWluYWwgYW5kIG5vdCBgRXhlY3V0ZWRgIChpLmUuIGFscmVhZHkgYENhbmNlbGxlZGAgb3IgYEV4cGlyZWRgKTsKdGhlcmUgaXMgbm90aGluZyBsZWZ0IHRvIHdpdGhkcmF3LgAAAAAAFlByb3Bvc2FsTm90Q2FuY2VsbGFibGUAAAAAABAAAAA8QSBXQVNNIHVwZ3JhZGUgcHJvcG9zYWwgd2l0aCB0aGUgc3VwcGxpZWQgSUQgZG9lcyBub3QgZXhpc3QuAAAAF1VwZ3JhZGVQcm9wb3NhbE5vdEZvdW5kAAAAABEAAACKVGhlIHByb3Bvc2FsIGlzIG5vdCBpbiBhIHN0YXRlIHRoYXQgYWNjZXB0cyB2b3RlcyAoaXQgaXMgYEFwcHJvdmVkYCwKYEV4ZWN1dGVkYCwgYENhbmNlbGxlZGAsIGBFeHBpcmVkYCwgb3IgaXRzIHZvdGluZyB3aW5kb3cgaGFzIGNsb3NlZCkuAAAAAAASUHJvcG9zYWxOb3RQZW5kaW5nAAAAAAASAAAAOFRoZSBjYWxsZXIgYWxyZWFkeSBjYXN0IGEgdm90ZSBvbiB0aGlzIHVwZ3JhZGUgcHJvcG9zYWwuAAAADUR1cGxpY2F0ZVZvdGUAAAAAAAATAAAAuUdlbmVyYWwgYXV0aG9yaXphdGlvbiBmYWlsdXJlOiB0aGUgY2FsbGVyIGlzIG5vdCBwZXJtaXR0ZWQgdG8gcGVyZm9ybQp0aGUgcmVxdWVzdGVkIG9wZXJhdGlvbi4gRGlzdGluY3QgZnJvbSBbYEFkbWluRXJyb3I6OlVuYXV0aG9yaXplZFJvbGVgXSwKd2hpY2ggaXMgc3BlY2lmaWMgdG8gYSByb2xlLWd1YXJkIGZhaWx1cmUuAAAAAAAADFVuYXV0aG9yaXplZAAAABQAAABcYGV4ZWN1dGVfdXBncmFkZV9iYXRjaGAgd2FzIGNhbGxlZCB3aXRoIHByb3Bvc2FsIElEIGFuZCBXQVNNIGhhc2ggdmVjdG9ycwpvZiB1bmVxdWFsIGxlbmd0aC4AAAATQmF0Y2hMZW5ndGhNaXNtYXRjaAAAAAAVAAAAP1RoZSB0YXJnZXQgYWRkcmVzcyBhbHJlYWR5IGhvbGRzIHRoZSByb2xlIGJlaW5nIGdyYW50ZWQgKCM3NjgpLgAAAAASUm9sZUFscmVhZHlHcmFudGVkAAAAAAAWAAAAiFRoZSBwcm9wb3NhbCdzIGV4cGlyeSBsZWRnZXIgaGFzIHBhc3NlZDogaXQgY2FuIG5vIGxvbmdlciBleGVjdXRlLgpQcm9wb3NhbHMgbGl2ZSBmb3IgW2BQUk9QT1NBTF9FWFBJUllfTEVER0VSU2BdIGxlZGdlcnMgZnJvbSBjcmVhdGlvbi4AAAAPUHJvcG9zYWxFeHBpcmVkAAAAABcAAABxVGhlIHByb3Bvc2FsIHdhcyB3aXRoZHJhd24gYnkgaXRzIGNyZWF0b3IgdmlhIGBjYW5jZWxfbGVnYWN5X3Byb3Bvc2FsYAphbmQgY2FuIG5vIGxvbmdlciBiZSBhcHByb3ZlZCBvciBleGVjdXRlZC4AAAAAAAARUHJvcG9zYWxDYW5jZWxsZWQAAAAAAAAYAAAAe0EgcHJpdmlsZWdlZCBhY3Rpb24gKGZlZS1jb25maWcgY2hhbmdlLCBvd25lcnNoaXAgdHJhbnNmZXIpIHdhcwpwcm9wb3NlZCBidXQgaXRzIHRpbWVsb2NrIGRlbGF5IGhhcyBub3QgZWxhcHNlZCB5ZXQgKCM5MTQpLgAAAAAXUHJpdmlsZWdlVGltZWxvY2tBY3RpdmUAAAAAGQAAAGVUaGUgcHJpdmlsZWdlZC1hY3Rpb24gcHJvcG9zYWwgZG9lcyBub3QgZXhpc3Qgb3Igd2FzIGFscmVhZHkgY29uc3VtZWQKKGV4ZWN1dGVkIG9yIGNhbmNlbGxlZCkgKCM5MTQpLgAAAAAAABlQcml2aWxlZ2VQcm9wb3NhbE5vdEZvdW5kAAAAAAAAGgAAAHBUaGUgcHJpdmlsZWdlZC1hY3Rpb24gcHJvcG9zYWwgd2FzIHN1Ym1pdHRlZCBieSBhIGRpZmZlcmVudCBjYWxsZXIKdGhhbiB0aGUgb25lIG5vdyB0cnlpbmcgdG8gZXhlY3V0ZSBpdCAoIzkxNCkuAAAAGVByaXZpbGVnZVByb3Bvc2FsTm90T3duZXIAAAAAAAAbAAAARmByZW5vdW5jZV9yb2xlYCB3YXMgY2FsbGVkIGZvciBhIHJvbGUgdGhlIGNhbGxlciBkb2VzIG5vdCBob2xkICgjOTE1KS4AAAAAABZSb2xlTm90SGVsZEZvclJlbm91bmNlAAAAAAAcAAAAR1RoZSBsYXN0IFN1cGVyQWRtaW4gdHJpZWQgdG8gcmVub3VuY2U7IGF0IGxlYXN0IG9uZSBtdXN0IHJlbWFpbiAoIzkxNSkuAAAAAA5MYXN0U3VwZXJBZG1pbgAAAAAAHQ==", + "AAAAAgAAAbFTdG9yYWdlIGtleXMgZm9yIHRoZSBhY2Nlc3MtY29udHJvbCBsYXllci4KCmAjW2NvbnRyYWN0dHlwZV1gIGRlcml2ZXMgYSBkaXN0aW5jdCBsZWRnZXIga2V5IGZvciBldmVyeSB2YXJpYW50IChhbmQsCmZvciBgUm9sZShSb2xlLCBBZGRyZXNzKWAsIGZvciBldmVyeSBgKFJvbGUsIEFkZHJlc3MpYCBwYWlyKSwgc28gZW50cmllcwpuZXZlciBjb2xsaWRlIHdpdGggZWFjaCBvdGhlciBvciB3aXRoIHRoZSBvdGhlciB2YXJpYW50cyBiZWxvdy4KCkB0aXRsZSBBZG1pbktleQpAbm90aWNlIEVudW1lcmF0ZXMgdGhlIHN0b3JhZ2Uga2V5cyB1c2VkIGJ5IHRoZSBhY2Nlc3MtY29udHJvbCBsYXllci4KQGRldiBFYWNoIHZhcmlhbnQgbWFwcyB0byBhIGRpc3RpbmN0IGxlZGdlciBzbG90OyBhcHBlbmQgbmV3IHZhcmlhbnRzIHJhdGhlciB0aGFuIHJlb3JkZXJpbmcuAAAAAAAAAAAAAAhBZG1pbktleQAAABAAAAAAAAAAOVRoZSBzaW5ndWxhciBjb250cmFjdCBhZG1pbiBhZGRyZXNzLCBzZXQgdmlhIGBzZXRfYWRtaW5gLgAAAAAAAAVBZG1pbgAAAAAAAAEAAAEkTGVnYWN5IHBlci1yb2xlIG1lbWJlcnNoaXAgZmxhZzogbWFwcyBhIGAoUm9sZSwgQWRkcmVzcylgIHBhaXIgdG8gYHRydWVgCndoZW4gYGFkZHJlc3NgIGhlbGQgYHJvbGVgLiBTdXBlcnNlZGVkIGJ5IFtgQWRtaW5LZXk6OlJvbGVNYXNrYF07IGtlcHQgc28KcHJldmlvdXNseSBwZXJzaXN0ZWQga2V5cyBrZWVwIGRlY29kaW5nLiBOZXcgd3JpdGVzIGdvIHRvIHRoZSBtYXNrLCBhbmQKbGVnYWN5IGVudHJpZXMgZm9yIGFuIGFkZHJlc3MgYXJlIHJlbW92ZWQgb25jZSBpdHMgbWFzayBpcyBmaXJzdCB3cml0dGVuLgAAAARSb2xlAAAAAgAAB9AAAAAEUm9sZQAAABMAAAABAAAAfE1hcHMgYW4gYChBZGRyZXNzLCBSb2xlKWAgcGFpciB0byBgdHJ1ZWAgd2hlbiBgYWRkcmVzc2AgaG9sZHMgYHJvbGVgLgpUaGlzIGlzIHRoZSBBZGRyZXNzLXRvLVJvbGUgbWFwcGluZyBzdG9yYWdlIHN0cnVjdHVyZS4AAAALQWRkcmVzc1JvbGUAAAAAAgAAABMAAAfQAAAABFJvbGUAAAAAAAAAOU11bHRpLXNpZyBhZG1pbiBwb29sIGFkZHJlc3Nlcywgc2V0IHZpYSBgc2V0X2FkbWluX3Bvb2xgLgAAAAAAAAlBZG1pblBvb2wAAAAAAAAAAAAANU11bHRpLXNpZyBhcHByb3ZhbCB0aHJlc2hvbGQsIHNldCBhbG9uZ3NpZGUgdGhlIHBvb2wuAAAAAAAACVRocmVzaG9sZAAAAAAAAAEAAAAvR292ZXJuYW5jZSBwcm9wb3NhbCBkYXRhLCBrZXllZCBieSBwcm9wb3NhbCBJRC4AAAAACFByb3Bvc2FsAAAAAQAAAAYAAAAAAAAAK0F1dG8taW5jcmVtZW50aW5nIGNvdW50ZXIgZm9yIHByb3Bvc2FsIElEcy4AAAAAEVByb3Bvc2FsSWRDb3VudGVyAAAAAAAAAQAAAOpNYXBzIGEgcXVvcmF0ZSBwcm9wb3NhbCBJRCB0byB0aGUgdW5peCB0aW1lc3RhbXAgKHNlY29uZHMpIGF0IHdoaWNoIGl0cwptYW5kYXRvcnkgdGltZWxvY2sgZXhwaXJlcyBhbmQgZXhlY3V0aW9uIG1heSBwcm9jZWVkLiBSZWNvcmRlZCBvbmNlLAp3aGVuIHRoZSBhcHByb3ZhbCB0aHJlc2hvbGQgaXMgZmlyc3QgbWV0OyBhYnNlbnQgd2hpbGUgdGhlIHByb3Bvc2FsIGlzCnN0aWxsIHNob3J0IG9mIHF1b3J1bS4AAAAAABBQcm9wb3NhbFRpbWVsb2NrAAAAAQAAAAYAAAABAAAARlN1cGVyLWFkbWluIG1hcHBpbmcgcG9wdWxhdGVkIGJ5IGBtaWdyYXRlX2FkbWluYCBmb3IgbGVnYWN5IGNvbnRyYWN0cy4AAAAAAApTdXBlckFkbWluAAAAAAABAAAAEwAAAAEAAAE/TXVsdGktc2lnIFdBU00gdXBncmFkZSBwcm9wb3NhbCBzdGF0ZSwga2V5ZWQgYnkgdXBncmFkZSBwcm9wb3NhbCBJRC4KTGl2ZXMgaW4gYHBlcnNpc3RlbnQoKWAgKHVubGlrZSBbYEFkbWluS2V5OjpQcm9wb3NhbGBdKSBzbyBlYWNoIHByb3Bvc2FsCmNhcnJpZXMgaXRzIG93biBUVEwgaW5zdGVhZCBvZiByaWRpbmcgdGhlIHNoYXJlZCBpbnN0YW5jZSBUVEwsIGFuZCBzbyBhCmdyb3dpbmcgc2V0IG9mIHByb3Bvc2FscyBkb2VzIG5vdCBpbmZsYXRlIHRoZSBpbnN0YW5jZSBlbnRyeSB0aGF0IGV2ZXJ5Cmludm9jYXRpb24gbG9hZHMgYW5kIHdyaXRlcyBiYWNrLgAAAAAPVXBncmFkZVByb3Bvc2FsAAAAAAEAAAAGAAAAAAAAAIxBdXRvLWluY3JlbWVudGluZyBjb3VudGVyIGZvciB1cGdyYWRlIHByb3Bvc2FsIElEcy4gRGlzdGluY3QgZnJvbQpbYEFkbWluS2V5OjpQcm9wb3NhbElkQ291bnRlcmBdLCBzbyB0aGUgdHdvIGZsb3dzIG5ldmVyIHNoYXJlIGFuIElEIHNwYWNlLgAAABhVcGdyYWRlUHJvcG9zYWxJZENvdW50ZXIAAAABAAAAzlRoZSBsaXZlIHByaXZpbGVnZWQtYWN0aW9uIHByb3Bvc2FsIGZvciBhIGdpdmVuIGFjdGlvbiBraW5kICgjOTE0KS4KT25lIGVudHJ5IHBlciBhY3Rpb24gKGZlZSBjb25maWcsIG93bmVyc2hpcCB0cmFuc2ZlcikgaW4gYHBlcnNpc3RlbnQoKWAKc3RvcmFnZSBzbyBhIHBlbmRpbmcgcHJvcG9zYWwncyBjbG9jayBzdXJ2aXZlcyBpbnN0YW5jZSBhcmNoaXZpbmcuAAAAAAARUHJpdmlsZWdlUHJvcG9zYWwAAAAAAAABAAAH0AAAAA9Qcml2aWxlZ2VBY3Rpb24AAAAAAQAAAdVNYXBzIGFuIGFkZHJlc3MgdG8gaXRzIHJvbGUgYml0bWFzazogYml0IGBpYCBpcyBzZXQgd2hlbiB0aGUgYWRkcmVzcwpob2xkcyB0aGUgcm9sZSB3aG9zZSBiaXQgaXMgYDEgPDwgaWAgKHNlZSBbYFJPTEVfQklUX0FETUlOYF0gYW5kCmZyaWVuZHMpLiBPbmUgbGVkZ2VyIGVudHJ5IHBlciBhZGRyZXNzOyBncmFudHMgYW5kIHJldm9rZXMgYXJlIGEKbG9hZCAvIGJpdHdpc2UtT1IgLyBzdG9yZSBvbiB0aGlzIGVudHJ5LgoKU3VwZXJzZWRlcyBbYEFkbWluS2V5OjpSb2xlKFJvbGUsIEFkZHJlc3MpYF0sIHdoaWNoIGlzIHJldGFpbmVkIG9ubHkgc28KcHJldmlvdXNseSBwZXJzaXN0ZWQga2V5cyBrZWVwIGRlY29kaW5nOyBlbnRyaWVzIHVuZGVyIHRoZSBsZWdhY3kga2V5CmFyZSBtaWdyYXRlZCBpbnRvIHRoZSBtYXNrIG9uIGZpcnN0IHdyaXRlIGFuZCBhcmUgc3RpbGwgcmVhZCBhcyBhCmZhbGxiYWNrIHVudGlsIHRoZW4uAAAAAAAACFJvbGVNYXNrAAAAAQAAABMAAAABAAAA4U1hcmtzIGEgV0FTTSBoYXNoIGFzIGluc3RhbGxlZCBvbiB0aGUgbGVkZ2VyICh1cGxvYWRlZCB2aWEKYGVudi5kZXBsb3llcigpLnVwbG9hZF9jb250cmFjdF93YXNtYCBhbmQgcmVnaXN0ZXJlZCBieSBhbiBhZG1pbiksCm1ha2luZyBpdCBlbGlnaWJsZSB0byBiZSByZWZlcmVuY2VkIGJ5IGFuIHVwZ3JhZGUgcHJvcG9zYWwuIENoZWNrZWQgYnkKW2ByZXF1aXJlX3ZhbGlkX3dhc21faGFzaGBdLgAAAAAAABFJbnN0YWxsZWRXYXNtSGFzaAAAAAAAAAEAAAPuAAAAIAAAAAAAAAENTGVkZ2VyIHNlcXVlbmNlIHJlY29yZGVkIHdoZW4gdGhpcyBjb250cmFjdCBleHRlbmRzIGluc3RhbmNlIFRUTC4KR3Vlc3QgV0FTTSBvbiBzb3JvYmFuLXNkayAyMi4wLjExIGNhbm5vdCByZWFkIHRoZSBob3N0IGluc3RhbmNlIFRUTCwgc28KW2BnZXRfaW5zdGFuY2VfdHRsYF0gZGVyaXZlcyBhIG5vbi1uZWdhdGl2ZSByZW1haW5pbmcgbGlmZXRpbWUgZnJvbSB0aGlzCnZhbHVlLiBJdCBpcyBub3Qgb25lIG9mIHRoZSBmaXZlIG1vbml0b3JlZCBzaW5nbGV0b24ga2V5cy4AAAAAAAARSW5zdGFuY2VMaXZlVW50aWwAAAAAAAABAAAAhFJvbGUgZ3JhbnQgYWN0aW9uIGF0dGFjaGVkIHRvIGEgbGVnYWN5IHByb3Bvc2FsLCBrZXllZCBieSBwcm9wb3NhbCBJRC4KQXBwZW5kZWQgdG8gcHJlc2VydmUgZXZlcnkgZXhpc3Rpbmcgc3RvcmFnZS1rZXkgZGlzY3JpbWluYW50LgAAABFSb2xlR3JhbnRQcm9wb3NhbAAAAAAAAAEAAAAG", + "AAAABAAAAOVFcnJvcnMgcmV0dXJuZWQgYnkgdGhlIGFkbWluIGFjY2Vzcy1jb250cm9sIG1vZHVsZS4KCkB0aXRsZSBBZG1pbkVycm9yCkBub3RpY2UgRW51bWVyYXRlcyB0aGUgZXJyb3IgY29kZXMgcmV0dXJuZWQgYnkgdGhlIGFkbWluIGFjY2Vzcy1jb250cm9sIG1vZHVsZS4KQGRldiBEaXNjcmltaW5hbnRzIGFyZSBBQkktc3RhYmxlOyBhcHBlbmQgbmV3IHZhcmlhbnRzIHJhdGhlciB0aGFuIHJlb3JkZXJpbmcuAAAAAAAAAAAAAApBZG1pbkVycm9yAAAAAAAfAAAAQ1VudXNlZDsga2VwdCBmb3IgQUJJIHN0YWJpbGl0eS4gUHJlZmVyIFtgQWRtaW5FcnJvcjo6Um9sZU5vdEhlbGRgXS4AAAAADlJvbGVOb3RHcmFudGVkAAAAAAABAAAAVUFuIGFkZHJlc3MgZG9lcyBub3QgaG9sZCB0aGUgcmVxdWlyZWQgcm9sZSAoZS5nLiBgcmV2b2tlX3JvbGVgIGNhbGxlZCBvbiBub24taG9sZGVyKS4AAAAAAAALUm9sZU5vdEhlbGQAAAAAAgAAAEhgcmVxdWlyZV9yb2xlX2d1YXJkYCBmYWlsZWQ6IHRoZSBjYWxsZXIgaXMgbm90IGF1dGhvcml6ZWQgZm9yIHRoaXMgcm9sZS4AAAAQVW5hdXRob3JpemVkUm9sZQAAAAMAAAA7QW4gb3BlcmF0aW9uIHdhcyBhdHRlbXB0ZWQgd2l0aCB0aGUgY2Fub25pY2FsIHplcm8gYWRkcmVzcy4AAAAADkludmFsaWRBZGRyZXNzAAAAAAAEAAAAQkEgcm9sZSB2YWx1ZSB0aGF0IGlzIG5vdCByZWNvZ25pemVkIGJ5IHRoaXMgY29udHJhY3Qgd2FzIHN1cHBsaWVkLgAAAAAAC0ludmFsaWRSb2xlAAAAAAUAAABXVGhlIGNvbnRyYWN0IGhhcyBhbHJlYWR5IGJlZW4gaW5pdGlhbGl6ZWQ7IGNhbGxpbmcgYGluaXRfc3RvcmFnZWAgYWdhaW4KaXMgbm90IGFsbG93ZWQuAAAAABJBbHJlYWR5SW5pdGlhbGl6ZWQAAAAAAAYAAAA+VGhlIGFwcHJvdmFsIHRocmVzaG9sZCBpcyB6ZXJvIG9yIGV4Y2VlZHMgdGhlIGFkbWluLXBvb2wgc2l6ZS4AAAAAABBJbnZhbGlkVGhyZXNob2xkAAAABwAAADFUaGUgcmVxdWVzdGVkIGdvdmVybmFuY2UgcHJvcG9zYWwgZG9lcyBub3QgZXhpc3QuAAAAAAAAEFByb3Bvc2FsTm90Rm91bmQAAAAIAAAAPFRoZSByZXF1ZXN0ZWQgZ292ZXJuYW5jZSBwcm9wb3NhbCBoYXMgYWxyZWFkeSBiZWVuIGV4ZWN1dGVkLgAAABdQcm9wb3NhbEFscmVhZHlFeGVjdXRlZAAAAAAJAAAAQVRoZSBhZG1pbiBoYXMgYWxyZWFkeSBhcHByb3ZlZCB0aGUgcmVxdWVzdGVkIGdvdmVybmFuY2UgcHJvcG9zYWwuAAAAAAAAF1Byb3Bvc2FsQWxyZWFkeUFwcHJvdmVkAAAAAAoAAAA/VGhlIGdvdmVybmFuY2UgcHJvcG9zYWwgaGFzIG5vdCByZWFjaGVkIGl0cyBhcHByb3ZhbCB0aHJlc2hvbGQuAAAAAA9UaHJlc2hvbGROb3RNZXQAAAAACwAAAEJUaGUgcHJvcG9zYWwgaGFzIG5vdCBnYXRoZXJlZCBlbm91Z2ggYXBwcm92YWxzIHRvIG1lZXQgdGhlIHF1b3J1bS4AAAAAAAxRdW9ydW1Ob3RNZXQAAAAMAAAAg1RoZSBtYW5kYXRvcnkgdGltZWxvY2sgZGVsYXkgaGFzIG5vdCBlbGFwc2VkIHlldDogdGhlIGN1cnJlbnQgbGVkZ2VyCnRpbWVzdGFtcCBpcyBzdGlsbCBiZWZvcmUgdGhlIHByb3Bvc2FsJ3MgcmVjb3JkZWQgdW5sb2NrIHRpbWUuAAAAAA5UaW1lbG9ja0FjdGl2ZQAAAAAADQAAAGlBIHN1cHBsaWVkIFdBU00gaGFzaCBmYWlsZWQgW2ByZXF1aXJlX3ZhbGlkX3dhc21faGFzaGBdOiBpdCBpcyBub3QKcmVnaXN0ZXJlZCBhcyBpbnN0YWxsZWQgb24gdGhlIGxlZGdlci4AAAAAAAAPSW52YWxpZFdhc21IYXNoAAAAAA4AAAB0YGNhbmNlbF9wcm9wb3NhbGAgd2FzIGNhbGxlZCBieSBhbiBhZGRyZXNzIG90aGVyIHRoYW4gdGhlCltgVXBncmFkZVByb3Bvc2FsOjpwcm9wb3NlcmBdIHRoYXQgc3VibWl0dGVkIHRoZSBwcm9wb3NhbC4AAAALTm90UHJvcG9zZXIAAAAADwAAAKpgY2FuY2VsX3Byb3Bvc2FsYCB3YXMgY2FsbGVkIG9uIGEgcHJvcG9zYWwgd2hvc2Ugc3RhdHVzIGlzIGFscmVhZHkKdGVybWluYWwgYW5kIG5vdCBgRXhlY3V0ZWRgIChpLmUuIGFscmVhZHkgYENhbmNlbGxlZGAgb3IgYEV4cGlyZWRgKTsKdGhlcmUgaXMgbm90aGluZyBsZWZ0IHRvIHdpdGhkcmF3LgAAAAAAFlByb3Bvc2FsTm90Q2FuY2VsbGFibGUAAAAAABAAAAA8QSBXQVNNIHVwZ3JhZGUgcHJvcG9zYWwgd2l0aCB0aGUgc3VwcGxpZWQgSUQgZG9lcyBub3QgZXhpc3QuAAAAF1VwZ3JhZGVQcm9wb3NhbE5vdEZvdW5kAAAAABEAAACKVGhlIHByb3Bvc2FsIGlzIG5vdCBpbiBhIHN0YXRlIHRoYXQgYWNjZXB0cyB2b3RlcyAoaXQgaXMgYEFwcHJvdmVkYCwKYEV4ZWN1dGVkYCwgYENhbmNlbGxlZGAsIGBFeHBpcmVkYCwgb3IgaXRzIHZvdGluZyB3aW5kb3cgaGFzIGNsb3NlZCkuAAAAAAASUHJvcG9zYWxOb3RQZW5kaW5nAAAAAAASAAAAOFRoZSBjYWxsZXIgYWxyZWFkeSBjYXN0IGEgdm90ZSBvbiB0aGlzIHVwZ3JhZGUgcHJvcG9zYWwuAAAADUR1cGxpY2F0ZVZvdGUAAAAAAAATAAAAuUdlbmVyYWwgYXV0aG9yaXphdGlvbiBmYWlsdXJlOiB0aGUgY2FsbGVyIGlzIG5vdCBwZXJtaXR0ZWQgdG8gcGVyZm9ybQp0aGUgcmVxdWVzdGVkIG9wZXJhdGlvbi4gRGlzdGluY3QgZnJvbSBbYEFkbWluRXJyb3I6OlVuYXV0aG9yaXplZFJvbGVgXSwKd2hpY2ggaXMgc3BlY2lmaWMgdG8gYSByb2xlLWd1YXJkIGZhaWx1cmUuAAAAAAAADFVuYXV0aG9yaXplZAAAABQAAABcYGV4ZWN1dGVfdXBncmFkZV9iYXRjaGAgd2FzIGNhbGxlZCB3aXRoIHByb3Bvc2FsIElEIGFuZCBXQVNNIGhhc2ggdmVjdG9ycwpvZiB1bmVxdWFsIGxlbmd0aC4AAAATQmF0Y2hMZW5ndGhNaXNtYXRjaAAAAAAVAAAAP1RoZSB0YXJnZXQgYWRkcmVzcyBhbHJlYWR5IGhvbGRzIHRoZSByb2xlIGJlaW5nIGdyYW50ZWQgKCM3NjgpLgAAAAASUm9sZUFscmVhZHlHcmFudGVkAAAAAAAWAAAAiFRoZSBwcm9wb3NhbCdzIGV4cGlyeSBsZWRnZXIgaGFzIHBhc3NlZDogaXQgY2FuIG5vIGxvbmdlciBleGVjdXRlLgpQcm9wb3NhbHMgbGl2ZSBmb3IgW2BQUk9QT1NBTF9FWFBJUllfTEVER0VSU2BdIGxlZGdlcnMgZnJvbSBjcmVhdGlvbi4AAAAPUHJvcG9zYWxFeHBpcmVkAAAAABcAAABxVGhlIHByb3Bvc2FsIHdhcyB3aXRoZHJhd24gYnkgaXRzIGNyZWF0b3IgdmlhIGBjYW5jZWxfbGVnYWN5X3Byb3Bvc2FsYAphbmQgY2FuIG5vIGxvbmdlciBiZSBhcHByb3ZlZCBvciBleGVjdXRlZC4AAAAAAAARUHJvcG9zYWxDYW5jZWxsZWQAAAAAAAAYAAAAe0EgcHJpdmlsZWdlZCBhY3Rpb24gKGZlZS1jb25maWcgY2hhbmdlLCBvd25lcnNoaXAgdHJhbnNmZXIpIHdhcwpwcm9wb3NlZCBidXQgaXRzIHRpbWVsb2NrIGRlbGF5IGhhcyBub3QgZWxhcHNlZCB5ZXQgKCM5MTQpLgAAAAAXUHJpdmlsZWdlVGltZWxvY2tBY3RpdmUAAAAAGQAAAGVUaGUgcHJpdmlsZWdlZC1hY3Rpb24gcHJvcG9zYWwgZG9lcyBub3QgZXhpc3Qgb3Igd2FzIGFscmVhZHkgY29uc3VtZWQKKGV4ZWN1dGVkIG9yIGNhbmNlbGxlZCkgKCM5MTQpLgAAAAAAABlQcml2aWxlZ2VQcm9wb3NhbE5vdEZvdW5kAAAAAAAAGgAAAHBUaGUgcHJpdmlsZWdlZC1hY3Rpb24gcHJvcG9zYWwgd2FzIHN1Ym1pdHRlZCBieSBhIGRpZmZlcmVudCBjYWxsZXIKdGhhbiB0aGUgb25lIG5vdyB0cnlpbmcgdG8gZXhlY3V0ZSBpdCAoIzkxNCkuAAAAGVByaXZpbGVnZVByb3Bvc2FsTm90T3duZXIAAAAAAAAbAAAARmByZW5vdW5jZV9yb2xlYCB3YXMgY2FsbGVkIGZvciBhIHJvbGUgdGhlIGNhbGxlciBkb2VzIG5vdCBob2xkICgjOTE1KS4AAAAAABZSb2xlTm90SGVsZEZvclJlbm91bmNlAAAAAAAcAAAAR1RoZSBsYXN0IFN1cGVyQWRtaW4gdHJpZWQgdG8gcmVub3VuY2U7IGF0IGxlYXN0IG9uZSBtdXN0IHJlbWFpbiAoIzkxNSkuAAAAAA5MYXN0U3VwZXJBZG1pbgAAAAAAHQAAAEFBIHJvbGUgcHJvcG9zYWwgY291bGQgbm90IGJlIGZvdW5kIGZvciB0aGUgcmVxdWVzdGVkIHByb3Bvc2FsIElELgAAAAAAABRSb2xlUHJvcG9zYWxOb3RGb3VuZAAAAB4AAABBQSByb2xlIHByb3Bvc2FsIG11c3QgYmUgZXhlY3V0ZWQgdGhyb3VnaCBgZXhlY3V0ZV9yb2xlX3Byb3Bvc2FsYC4AAAAAAAAdUm9sZVByb3Bvc2FsUmVxdWlyZXNFeGVjdXRpb24AAAAAAAAf", "AAAAAQAABABJbnN0YW5jZSBUVEwgYW5kIHRoZSBjb3VudCBvZiBrbm93biBzaW5nbGV0b24gYWRtaW4ga2V5cy4KCmBpbnN0YW5jZV90dGxgIGlzIHRoZSByZW1haW5pbmcgbGlmZXRpbWUsIGluIGxlZGdlcnMsIGltcGxpZWQgYnkgdGhlCmxpdmUtdW50aWwgbGVkZ2VyIHRoaXMgY29udHJhY3Qgc3RvcmVkIHRoZSBsYXN0IHRpbWUgaXQgZXh0ZW5kZWQgaW5zdGFuY2UKVFRMIChgc3RvcmVkX2xpdmVfdW50aWwuc2F0dXJhdGluZ19zdWIoY3VycmVudF9sZWRnZXIpYCkuIEl0IGlzIGAwYCBiZWZvcmUKYW55IHN1Y2ggZXh0ZW5zaW9uLiBzb3JvYmFuLXNkayAyMi4wLjExIGNhbm5vdCByZWFkIHRoZSBob3N0J3MgaW5zdGFuY2UgVFRMCmZyb20gZ3Vlc3QgV0FTTSAoYEluc3RhbmNlOjpnZXRfdHRsYCBpcyBgdGVzdHV0aWxzYC1vbmx5IGFuZCBjYWxscyBhIGhvc3QKZnVuY3Rpb24gdGhhdCBpcyBub3QgYXZhaWxhYmxlIHRvIGNvbnRyYWN0cyksIGFuZCAyMi4wLjExIGlzIHRoZSBsYXN0CnJlbGVhc2Ugb24gdGhlIDIyIGxpbmUsIHNvIHRoaXMgZmllbGQgaXMgdGhhdCByZWNvcmRlZCByZW1haW5kZXIgcmF0aGVyCnRoYW4gdGhlIGF1dGhvcml0YXRpdmUgaG9zdCBUVEwuIEl0IGNhbiBiZSBoaWdoZXIgb3IgbG93ZXIgdGhhbiB0aGUgaG9zdAp2YWx1ZSBpZiBzb21ldGhpbmcgZWxzZSBleHRlbmRzIHRoZSBpbnN0YW5jZSwgb3IgaWYgdGhlIGluc3RhbmNlIHdhcwpjcmVhdGVkIHdpdGggYSBkaWZmZXJlbnQgaW5pdGlhbCBsaWZldGltZS4KCmBpbnN0YW5jZV9rZXlzYCBjb3VudHMgb25seSB0aGUgc2luZ2xldG9uIFtgQWRtaW5LZXlgXSB2YXJpYW50cyBzdG9yZWQgaW4KaW5zdGFuY2Ugc3RvcmFnZSAoYEFkbWluYCwgYEFkbWluUG9vbGAsIGBUaHJlc2hvbGRgLCBgUHJvcG9zYWxJZENvdW50ZXJgLApgVXBncmFkZVByb3Bvc2FsSWRDb3VudGVyYCkuIFtgQWRtaW5LZXk6Okluc3RhbmNlTGl2ZVVudGlsYF0sIHBlcnNpc3RlbnQKZW50cmllcywgYW5kIHBhcmFtZXRlcml6ZWQga2V5cyBhcmUgb21pdHRlZCBzbyB0AAAAAAAAAAtTdG9yYWdlSW5mbwAAAAACAAAAAAAAAA1pbnN0YW5jZV9rZXlzAAAAAAAABAAAAAAAAAAMaW5zdGFuY2VfdHRsAAAABA==", "AAAAAgAAA2dSb2xlcyByZWNvZ25pemVkIGJ5IHRoZSBhY2Nlc3MtY29udHJvbCBsYXllci4KCk5ldyB2YXJpYW50cyBtdXN0IGJlIGFwcGVuZGVkLCBuZXZlciBpbnNlcnRlZCwgc28gdGhhdCBwcmV2aW91c2x5CnBlcnNpc3RlZCBgQWRtaW5LZXk6OlJvbGUoUm9sZSwgQWRkcmVzcylgIGVudHJpZXMga2VlcCBkZWNvZGluZyB0byB0aGUKc2FtZSB2YXJpYW50IHRoZXkgd2VyZSB3cml0dGVuIHdpdGguCgpAdGl0bGUgUm9sZQpAbm90aWNlIEVudW1lcmF0ZXMgdGhlIHJvbGVzIHJlY29nbml6ZWQgYnkgdGhlIGFjY2Vzcy1jb250cm9sIGxheWVyLgpAZGV2IEFwcGVuZCBuZXcgdmFyaWFudHMgb25seTsgaW5zZXJ0aW5nIHdvdWxkIHJlbWFwIHByZXZpb3VzbHkgcGVyc2lzdGVkIHJvbGUgZW50cmllcy4KQGN1c3RvbTpzdG9yYWdlLWZvcm1hdCBSb2xlcyBhcmUgcGVyc2lzdGVkIHBlci1hZGRyZXNzIGFzIGEgYHUzMmAgYml0bWFzawp1bmRlciBgQWRtaW5LZXk6OlJvbGVNYXNrKEFkZHJlc3MpYDsgZWFjaCB2YXJpYW50IG1hcHMgdG8gYSBzaW5nbGUgYml0IOKAlApgQWRtaW5gID0gYDEgPDwgMGAgKDEpLCBgTWludGVyYCA9IGAxIDw8IDFgICgyKSwgYFN1cGVyQWRtaW5gID0gYDEgPDwgMmAKKDQpLCBgUGF1c2VyYCA9IGAxIDw8IDNgICg4KSDigJQgc2VlIFtgUk9MRV9CSVRfQURNSU5gXSwgW2BST0xFX0JJVF9NSU5URVJgXSwKW2BST0xFX0JJVF9TVVBFUl9BRE1JTmBdIGFuZCBbYFJPTEVfQklUX1BBVVNFUmBdLgpAY3VzdG9tOmJpdG1hc2staGVscGVyIFVzZSBbYG1hc2tfaGFzX3JvbGVgXSB0byB0ZXN0IGEgYml0LCBbYG1hc2tfd2l0aF9yb2xlYF0KdG8gc2V0IG9uZSwgYW5kIFtgbWFza193aXRob3V0X3JvbGVgXSB0byBjbGVhciBvbmUuAAAAAAAAAAAEUm9sZQAAAAQAAAAAAAAANEZ1bGwgYWRtaW5pc3RyYXRpdmUgY29udHJvbCBncmFudGVkIHZpYSBgc2V0X2FkbWluYC4AAAAFQWRtaW4AAAAAAAAAAAAAHlBlcm1pc3Npb24gdG8gbWludCBuZXcgdG9rZW5zLgAAAAAABk1pbnRlcgAAAAAAAAAAADxIaWdoZXN0LXByaXZpbGVnZSByb2xlLCByZXNlcnZlZCBmb3Igb3duZXItbGV2ZWwgb3BlcmF0aW9ucy4AAAAKU3VwZXJBZG1pbgAAAAAAAAAAADVSb2xlIGFsbG93aW5nIGVtZXJnZW5jeSBwYXVzZSBhbmQgdW5wYXVzZSBvcGVyYXRpb25zLgAAAAAAAAZQYXVzZXIAAA==", "AAAAAwAAARhCaXRmbGFncyByZXByZXNlbnRhdGlvbiBvZiByb2xlcyBmb3IgZWZmaWNpZW50IGJpdHdpc2Ugb3BlcmF0aW9ucy4KCkVhY2ggcm9sZSBpcyBhc3NpZ25lZCBhIHVuaXF1ZSBiaXQgcG9zaXRpb24sIGFsbG93aW5nIG11bHRpcGxlIHJvbGVzIHRvIGJlCmNvbWJpbmVkIGFuZCBjaGVja2VkIHVzaW5nIGJpdHdpc2UgQU5EL09SIG9wZXJhdGlvbnMuIFRoaXMgaXMgdXNlZnVsIGZvcgpiYXRjaCByb2xlIHZhbGlkYXRpb24gYW5kIGNoZWNraW5nIGlmIGEgc2V0IG9mIHJvbGVzIGlzIGdyYW50ZWQuAAAAAAAAAAlSb2xlRmxhZ3MAAAAAAAAEAAAANEZ1bGwgYWRtaW5pc3RyYXRpdmUgY29udHJvbCBncmFudGVkIHZpYSBgc2V0X2FkbWluYC4AAAAFQWRtaW4AAAAAAAABAAAAHlBlcm1pc3Npb24gdG8gbWludCBuZXcgdG9rZW5zLgAAAAAABk1pbnRlcgAAAAAAAgAAADxIaWdoZXN0LXByaXZpbGVnZSByb2xlLCByZXNlcnZlZCBmb3Igb3duZXItbGV2ZWwgb3BlcmF0aW9ucy4AAAAKU3VwZXJBZG1pbgAAAAAABAAAADVSb2xlIGFsbG93aW5nIGVtZXJnZW5jeSBwYXVzZSBhbmQgdW5wYXVzZSBvcGVyYXRpb25zLgAAAAAAAAZQYXVzZXIAAAAAAAg=", "AAAAAQAAAM9BIG11bHRpLXNpZyBnb3Zlcm5hbmNlIHByb3Bvc2FsLgoKQHRpdGxlIFByb3Bvc2FsCkBub3RpY2UgSG9sZHMgdGhlIHN0YXRlIG9mIGEgZ292ZXJuYW5jZSBwcm9wb3NhbCBhd2FpdGluZyBhcHByb3ZhbCBhbmQgZXhlY3V0aW9uLgpAZGV2IFBlcnNpc3RlZCB1bmRlciBgQWRtaW5LZXk6OlByb3Bvc2FsKHByb3Bvc2FsX2lkKWAgaW4gaW5zdGFuY2Ugc3RvcmFnZS4AAAAAAAAAAAhQcm9wb3NhbAAAAAYAAAA5QWRkcmVzc2VzIG9mIHBvb2wgYWRtaW5zIHRoYXQgaGF2ZSBhcHByb3ZlZCB0aGUgcHJvcG9zYWwuAAAAAAAACWFwcHJvdmFscwAAAAAAA+oAAAATAAAANFdoZXRoZXIgdGhlIGNyZWF0b3Igd2l0aGRyZXcgdGhlIHByb3Bvc2FsLiBUZXJtaW5hbC4AAAAJY2FuY2VsbGVkAAAAAAAAAQAAACZUaGUgYWRkcmVzcyB0aGF0IGNyZWF0ZWQgdGhlIHByb3Bvc2FsLgAAAAAAB2NyZWF0b3IAAAAAEwAAACtIdW1hbi1yZWFkYWJsZSBkZXNjcmlwdGlvbiBvZiB0aGUgcHJvcG9zYWwuAAAAAAtkZXNjcmlwdGlvbgAAAAAQAAAAJ1doZXRoZXIgdGhlIHByb3Bvc2FsIGhhcyBiZWVuIGV4ZWN1dGVkLgAAAAAIZXhlY3V0ZWQAAAABAAAAbUxhc3QgbGVkZ2VyIGF0IHdoaWNoIHRoZSBwcm9wb3NhbCBtYXkgZXhlY3V0ZS4gYE5vbmVgIG1lYW5zIHRoZQpwcm9wb3NhbCBwcmVkYXRlcyBleHBpcnkgYW5kIGRvZXMgbm90IGV4cGlyZS4AAAAAAAANZXhwaXJ5X2xlZGdlcgAAAAAAA+gAAAAE", "AAAAAgAAAz1MaWZlY3ljbGUgc3RhdGUgb2YgYW4gW2BVcGdyYWRlUHJvcG9zYWxgXS4KCkEgc2luZ2xlIGVudW0gcmF0aGVyIHRoYW4gYSBzZXQgb2YgYm9vbGVhbnM6IHRoZSB1cGdyYWRlIGZsb3cgbmVlZHMKZXhlY3V0ZWQsIGNhbmNlbGxlZCBhbmQgZXhwaXJlZCwgd2hpY2ggYXMgdGhyZWUgZmxhZ3Mgd291bGQgYWRtaXQgZm91cgpub25zZW5zaWNhbCBjb21iaW5hdGlvbnMgKGBleGVjdXRlZCAmJiBjYW5jZWxsZWRgLCBhbmQgc28gb24pLiBPbmUgZmllbGQKbWFrZXMgdGhvc2UgdW5yZXByZXNlbnRhYmxlIGFuZCBldmVyeSB0cmFuc2l0aW9uIGEgc2luZ2xlIGxlZGdlciB3cml0ZS4KCmBFeGVjdXRlZGAsIGBDYW5jZWxsZWRgIGFuZCBgRXhwaXJlZGAgYXJlIHRlcm1pbmFsOyBgUGVuZGluZ2AgYW5kCmBBcHByb3ZlZGAgYXJlIG5vdC4KCkB0aXRsZSBQcm9wb3NhbFN0YXR1cwpAbm90aWNlIEVudW1lcmF0ZXMgdGhlIGxpZmVjeWNsZSBzdGF0ZXMgb2YgYSBtdWx0aS1zaWcgdXBncmFkZSBwcm9wb3NhbC4KQGRldiBgI1tjb250cmFjdHR5cGVdYCBlbmNvZGVzIGEgdW5pdCB2YXJpYW50IGJ5IGl0cyBOQU1FIHN5bWJvbCwgbm90IGJ5IGEKZGlzY3JpbWluYW50LCBzbyByZW9yZGVyaW5nIG9yIGluc2VydGluZyB2YXJpYW50cyBpcyBzYWZlIGFuZCByZW5hbWluZwpvbmUgaXMgdGhlIGJyZWFraW5nIGVkaXQ6IGV2ZXJ5IHByb3Bvc2FsIGFscmVhZHkgcGVyc2lzdGVkIGtlZXBzIHRoZSBvbGQKc3ltYm9sIGFuZCBzdG9wcyBkZWNvZGluZy4gYHRlc3RfcHJvcG9zYWxfc3RhdHVzX3ZhcmlhbnRfbmFtZXNfYXJlX2Zyb3plbmAKaG9sZHMgdGhlIGVuY29kZWQgbmFtZXMuAAAAAAAAAAAAAA5Qcm9wb3NhbFN0YXR1cwAAAAAABQAAAAAAAAAlU3VibWl0dGVkIGFuZCBzdGlsbCBjb2xsZWN0aW5nIHZvdGVzLgAAAAAAAAdQZW5kaW5nAAAAAAAAAABDVGhlIHdlaWdodGVkIHRhbGx5IHJlYWNoZWQgYHF1b3J1bWA7IHRoZSBwcm9wb3NhbCBhd2FpdHMgZXhlY3V0aW9uLgAAAAAIQXBwcm92ZWQAAAAAAAAAIlRoZSB1cGdyYWRlIHdhcyBhcHBsaWVkLiBUZXJtaW5hbC4AAAAAAAhFeGVjdXRlZAAAAAAAAAA1V2l0aGRyYXduIGJ5IHRoZSBwcm9wb3NlciBiZWZvcmUgZXhlY3V0aW9uLiBUZXJtaW5hbC4AAAAAAAAJQ2FuY2VsbGVkAAAAAAAAAAAAAYlUaGUgdm90aW5nIHdpbmRvdyBjbG9zZWQgYmVmb3JlIHF1b3J1bSB3YXMgcmVhY2hlZCwgc28gdGhlIHByb3Bvc2FsIGlzCnJlYWNoYWJsZSBoZXJlIG9ubHkgZnJvbSBgUGVuZGluZ2AuIFRlcm1pbmFsLgoKQW4gYEFwcHJvdmVkYCBwcm9wb3NhbCB0aGF0IGlzIG5ldmVyIGV4ZWN1dGVkIGlzIE5PVCBleHBpcmVkIGJ5IHRoaXMKdmFyaWFudDogcG9zdC1xdW9ydW0gc3RhbGVuZXNzIG5lZWRzIGFuIGV4ZWN1dGlvbiBkZWFkbGluZSwgd2hpY2ggaXMKdGltZWxvY2sgc3RhdGUgb3duZWQgYnkgIzY2MCBhbmQgZGVsaWJlcmF0ZWx5IGFic2VudCBmcm9tIHRoaXMgc3RydWN0LgpgZXhwaXJlX3Byb3Bvc2FsYCAoIzY2MykgdGhlcmVmb3JlIG9ubHkgZXZlciBtb3ZlcyBgUGVuZGluZ2AgaGVyZS4AAAAAAAAHRXhwaXJlZAA=", + "AAAAAQAAAGBSb2xlIGdyYW50IGJvdW5kIHRvIGEgbGVnYWN5IG11bHRpc2lnIHByb3Bvc2FsIHdpdGhvdXQgY2hhbmdpbmcgdGhlCnBlcnNpc3RlZCBgUHJvcG9zYWxgIGxheW91dC4AAAAAAAAAD1JvbGVHcmFudEFjdGlvbgAAAAACAAAAAAAAAARyb2xlAAAH0AAAAARSb2xlAAAAAAAAAAZ0YXJnZXQAAAAAABM=", "AAAAAQAABABBIG11bHRpLXNpZyBwcm9wb3NhbCB0byB1cGdyYWRlIHRoZSBXQVNNIG9mIG9uZSBvciBtb3JlIGNvbnRyYWN0cy4KCkRlbGliZXJhdGVseSBzZXBhcmF0ZSBmcm9tIFtgUHJvcG9zYWxgXSByYXRoZXIgdGhhbiBhbiBleHRlbnNpb24gb2YgaXQ6CmBQcm9wb3NhbGAgZW50cmllcyBhcmUgYWxyZWFkeSB3cml0dGVuIHRvIGxlZGdlciwgYW5kIGFkZGluZyBvciByZXR5cGluZwpmaWVsZHMgb24gYSBgI1tjb250cmFjdHR5cGVdYCBzdHJ1Y3QgYnJlYWtzIHRoZSBkZWNvZGUgb2YgZXZlcnkgZXhpc3RpbmcKZW50cnkuIFRoaXMgdHlwZSBpcyBwdXJlbHkgYWRkaXRpdmUgYW5kIG5lZWRzIG5vIG1pZ3JhdGlvbi4KClN0b3JlZCB1bmRlciBbYEFkbWluS2V5OjpVcGdyYWRlUHJvcG9zYWxgXSBpbiBgcGVyc2lzdGVudCgpYCBzdG9yYWdlLiBFdmVyeQpyZWFkIGFuZCB3cml0ZSBtdXN0IGV4dGVuZCB0aGF0IGVudHJ5J3MgVFRMIHBhc3QgdGhlIGVuZCBvZiBpdHMgdm90aW5nCndpbmRvdywgb3RoZXJ3aXNlIGEgcHJvcG9zYWwgdGhhdCBzaXRzIGlkbGUgY2FuIGJlIGFyY2hpdmVkIGJlZm9yZSBpdCBjYW4gYmUKdm90ZWQgb24gb3IgZXhwaXJlZC4gVGhlIGV4dGVuc2lvbiBoYXMgdG8gY292ZXIgdGhlIHJlbWFpbmluZyB3aW5kb3csIHNvIGl0CmlzIG5vdCB0aGUgZml4ZWQgYnVtcCB0aGlzIG1vZHVsZSBhcHBsaWVzIHRvIGJhbGFuY2Utc2hhcGVkIGVudHJpZXMuCgpUaGUgcHJvcG9zYWwgSUQgaXMgdGhlIGxlZGdlciBrZXksIG5vdCBhIGZpZWxkOiBhIGtleWVkIHJlYWQgY2FuIG9ubHkgcmV0dXJuCndoYXQgd2FzIHdyaXR0ZW4gdW5kZXIgdGhhdCBrZXksIHNvIGFuIGBpZGAgaW5zaWRlIHRoZSB2YWx1ZSB3b3VsZCBhZGQgYQpzZWNvbmQgY29weSB0aGF0IG5vdGhpbmcgY2FuIHZhbGlkYXRlIGFuZCB0aGF0IGNhbiBzaWxlbnRseSBkaXNhZ3JlZS4KCkB0aXRsZSBVcGdyYWRlUHJvcG9zYWwKQG5vdGljZSBIb2xkcyB0aGUgc3RhdGUgb2YgYSBXQVNNIHVwZ3JhZGUgcHJvcG9zYWwgYXdhaXRpbmcgdm90AAAAAAAAAA9VcGdyYWRlUHJvcG9zYWwAAAAABwAAAWZDbG9zZSBvZiB0aGUgVk9USU5HIHdpbmRvdywgYXMgYW4gYWJzb2x1dGUgdW5peCB0aW1lc3RhbXAgaW4gc2Vjb25kcwpmcm9tIGBlbnYubGVkZ2VyKCkudGltZXN0YW1wKClgLiBBYnNvbHV0ZSByYXRoZXIgdGhhbiBhIGNyZWF0aW9uIHRpbWUKcGx1cyBhIGdsb2JhbCB3aW5kb3cgc28gdGhlIHBvbGljeSBpcyBzbmFwc2hvdHRlZCBhdCBzdWJtaXNzaW9uLiBUaGlzIGlzCnRoZSBwcmUtcXVvcnVtIGNsb2NrIG9ubHk6IGl0IGRlY2lkZXMgYFBlbmRpbmdgIHRvIGBFeHBpcmVkYCBhbmQgbm90aGluZwplbHNlLiBBbnkgcG9zdC1xdW9ydW0gZXhlY3V0aW9uIGRlYWRsaW5lIGlzIHRpbWVsb2NrIHN0YXRlIG93bmVkIGJ5ICM2NjAuAAAAAAAKZXhwaXJlc19hdAAAAAAABgAAAFdUaGUgYWRkcmVzcyB0aGF0IHN1Ym1pdHRlZCB0aGUgcHJvcG9zYWwsIGFuZCB0aGUgb25seSBhZGRyZXNzIHBlcm1pdHRlZAp0byB3aXRoZHJhdyBpdC4AAAAACHByb3Bvc2VyAAAAEwAAAPtBcHByb3ZhbCB0aHJlc2hvbGQgc25hcHNob3R0ZWQgYXQgc3VibWlzc2lvbiwgc28gYSBsYXRlciBwb29sIG9yCnRocmVzaG9sZCBjaGFuZ2UgY2Fubm90IHJldHJvYWN0aXZlbHkgbW92ZSB0aGUgYmFyIGZvciBhbiBpbi1mbGlnaHQKcHJvcG9zYWwuIGB1NjRgIHJhdGhlciB0aGFuIGB1MzJgIHRvIG1hdGNoIHRoZSBzdW1tZWQgd2VpZ2h0ZWQgdGFsbHksIHNvCnRoZSBjb21wYXJpc29uIGFnYWluc3QgaXQgY2FuIG5ldmVyIHRydW5jYXRlLgAAAAAGcXVvcnVtAAAAAAAGAAAAMEN1cnJlbnQgbGlmZWN5Y2xlIHN0YXRlLiBTZWUgW2BQcm9wb3NhbFN0YXR1c2BdLgAAAAZzdGF0dXMAAAAAB9AAAAAOUHJvcG9zYWxTdGF0dXMAAAAAAQVUaGUgY29udHJhY3QgSURzIHRoaXMgcHJvcG9zYWwgdXBncmFkZXMuIElEcyBvbmx5LCBuZXZlciBXQVNNIGhhc2hlczoKdGhlIGhhc2ggZm9yIGVhY2ggdGFyZ2V0IGlzIHJlc29sdmVkIGZyb20gdGhlIGNvbnRyYWN0LXRvLWhhc2ggbWFwIGF0CmV4ZWN1dGlvbiB0aW1lLiBMZWRnZXIga2V5cyBhcmUgbm90IGVudW1lcmFibGUsIHNvIHRoaXMgbGlzdCBpcyB0aGUgb25seQpyZWNvcmQgb2Ygd2hhdCBhbiBleGVjdXRpb24gaGFzIHRvIGl0ZXJhdGUgb3Zlci4AAAAAAAAHdGFyZ2V0cwAAAAPqAAAAEwAAAPpVbml4IHRpbWVzdGFtcCAoc2Vjb25kcykgd2hlbiB0aGUgcG9zdC1xdW9ydW0gZXhlY3V0aW9uIHRpbWVsb2NrIGV4cGlyZXMuCmBOb25lYCB3aGlsZSB0aGUgcHJvcG9zYWwgaGFzIG5vdCB5ZXQgcmVhY2hlZCBxdW9ydW07IHNldCB0bwpgZW52LmxlZGdlcigpLnRpbWVzdGFtcCgpICsgVElNRUxPQ0tfREVMQVlfU0VDU2AgdGhlIG1vbWVudCBxdW9ydW0gaXMKZmlyc3QgcmVhY2hlZCBhbmQgbmV2ZXIgcmVzZXQgYnkgbGF0ZXIgdm90ZXMuAAAAAAATdGltZWxvY2tfZXhwaXJlc19hdAAAAAPoAAAABgAAAX5Wb3RlciBhZGRyZXNzIHRvIHRoZSB2b3RlIHdlaWdodCByZWNvcmRlZCBhdCB0aGUgbW9tZW50IHRoZSB2b3RlIHdhcwpjYXN0LiBLZXllZCBieSBhZGRyZXNzIHNvIG9uZS12b3RlLXBlci1hZGRyZXNzIGlzIHN0cnVjdHVyYWwgcmF0aGVyIHRoYW4KYSBkaXNjaXBsaW5lIGV2ZXJ5IGNhbGwgc2l0ZSBoYXMgdG8gcmVtZW1iZXIsIGFuZCBzbyBhIHJldm9jYXRpb24Kc3VidHJhY3RzIGV4YWN0bHkgdGhlIHdlaWdodCB0aGUgdm90ZSBhZGRlZCBldmVuIGlmIHRoZSB2b3RlcidzIHdlaWdodApoYXMgc2luY2UgY2hhbmdlZC4gV2l0aCBubyB3ZWlnaHQgY29uZmlndXJhdGlvbiBldmVyeSBlbnRyeSBpcyBgMWAgYW5kCnRoZSB0YWxseSBpcyB0aGUgYXBwcm92YWwgY291bnQuAAAAAAAFdm90ZXMAAAAAAAPsAAAAEwAAAAQ=", "AAAAAQAAAQpQZW5kaW5nICsgYXBwcm92ZWQtbm90LWV4ZWN1dGVkIElEIGxpc3RzIGZvciBvbmUgcGFnZSBvZiB0aGUgbGVnYWN5CltgUHJvcG9zYWxgXSBmbG93ICgjOTE3KS4KCmBuZXh0X2N1cnNvcmAgaXMgYFNvbWUoaWQpYCB3aGVuIHRoZSBjb3VudGVyIGV4Y2VlZGVkIHRoZSBzY2FuIGNhcDsgcGFzcyBpdApiYWNrIGFzIGBzdGFydF9hZnRlcmAgdG8gZmV0Y2ggdGhlIG5leHQgcGFnZS4gYE5vbmVgIG1lYW5zIHRoZSB3aG9sZSBJRApzcGFjZSBoYXMgYmVlbiBzY2FubmVkLgAAAAAAAAAAABNMZWdhY3lQcm9wb3NhbExpc3RzAAAAAAMAAABIUHJvcG9zYWxzIGF0L2Fib3ZlIHRocmVzaG9sZCBidXQgbm90IHlldCBleGVjdXRlZCwgY2FuY2VsbGVkIG9yIGV4cGlyZWQuAAAADGFwcHJvdmVkX2lkcwAAA+oAAAAGAAAAO1Jlc3VtZSB0b2tlbjogdGhlIG5leHQgYHN0YXJ0X2FmdGVyYCB2YWx1ZSwgd2hlbiB0cnVuY2F0ZWQuAAAAAAtuZXh0X2N1cnNvcgAAAAPoAAAABgAAADpQcm9wb3NhbHMgc3RpbGwgY29sbGVjdGluZyBhcHByb3ZhbHMgKHF1b3J1bSBub3QgeWV0IG1ldCkuAAAAAAALcGVuZGluZ19pZHMAAAAD6gAAAAY=", "AAAAAQAAAJJQZW5kaW5nICsgYXBwcm92ZWQtbm90LWV4ZWN1dGVkIElEIGxpc3RzIGZvciBvbmUgcGFnZSBvZiB0aGUKW2BVcGdyYWRlUHJvcG9zYWxgXSBmbG93ICgjOTE3KS4KClNhbWUgY3Vyc29yaW5nIGNvbnRyYWN0IGFzIFtgTGVnYWN5UHJvcG9zYWxMaXN0c2BdLgAAAAAAAAAAABRVcGdyYWRlUHJvcG9zYWxMaXN0cwAAAAMAAABGUHJvcG9zYWxzIHBhc3QgcXVvcnVtIGF3YWl0aW5nIGV4ZWN1dGlvbiAoYFByb3Bvc2FsU3RhdHVzOjpBcHByb3ZlZGApLgAAAAAADGFwcHJvdmVkX2lkcwAAA+oAAAAGAAAAO1Jlc3VtZSB0b2tlbjogdGhlIG5leHQgYHN0YXJ0X2FmdGVyYCB2YWx1ZSwgd2hlbiB0cnVuY2F0ZWQuAAAAAAtuZXh0X2N1cnNvcgAAAAPoAAAABgAAAMRQcm9wb3NhbHMgc3RpbGwgaW5zaWRlIHRoZWlyIHZvdGluZyB3aW5kb3cgKGBQcm9wb3NhbFN0YXR1czo6UGVuZGluZ2AKd2l0aCBgZXhwaXJlc19hdGAgaW4gdGhlIGZ1dHVyZSkuIENsb3NlZC13aW5kb3cgYFBlbmRpbmdgIGVudHJpZXMgYXJlCm9taXR0ZWQgdW50aWwgYGV4cGlyZV9wcm9wb3NhbGAgbW92ZXMgdGhlbSB0byBgRXhwaXJlZGAuAAAAC3BlbmRpbmdfaWRzAAAAA+oAAAAG", + "AAAAAQAAADlSb2xlIHByb3Bvc2FsIGluZm9ybWF0aW9uIG5lZWRlZCBieSB0aGUgdm90aW5nIGludGVyZmFjZS4AAAAAAAAAAAAAGFJvbGVHcmFudFByb3Bvc2FsRGV0YWlscwAAAAYAAAAAAAAACWFwcHJvdmFscwAAAAAAAAQAAAAAAAAAC2Rlc2NyaXB0aW9uAAAAABAAAAAAAAAACGV4ZWN1dGVkAAAAAQAAAAAAAAAGcXVvcnVtAAAAAAAEAAAAAAAAAARyb2xlAAAH0AAAAARSb2xlAAAAAAAAAAZ0YXJnZXQAAAAAABM=", "AAAAAQAAAPtPbmUgYWRkcmVzcydzIHJvbGUgbWVtYmVyc2hpcCBhY3Jvc3MgdGhlIHdob2xlIGhpZXJhcmNoeSwgaW4gb25lIGNhbGwuCgpgYWRtaW5faW1wbGllc19hbGxgIG1pcnJvcnMgYGdldF9yb2xlc19iaXRtYXNrYDogdGhlIGNvbmZpZ3VyZWQgYWRtaW4KaW1wbGljaXRseSBob2xkcyBldmVyeSByb2xlLCBzbyBhIFVJIHJlYWRpbmcgdGhpcyBxdWVyeSBzZWVzIHRoZSBmdWxsCnRydXRoIHJhdGhlciB0aGFuIHRoZSByYXcgc3RvcmFnZSBiaXRzLgAAAAAAAAAADVJvbGVIaWVyYXJjaHkAAAAAAAAFAAAAAAAAAAdhZGRyZXNzAAAAABMAAAAAAAAACGlzX2FkbWluAAAAAQAAAAAAAAAJaXNfbWludGVyAAAAAAAAAQAAAAAAAAAJaXNfcGF1c2VyAAAAAAAAAQAAAAAAAAAOaXNfc3VwZXJfYWRtaW4AAAAAAAE=", "AAAAAgAAAQtUaGUgcHJpdmlsZWdlZCBhY3Rpb24gYSBwcm9wb3NhbCB3aWxsIHBlcmZvcm0gb25jZSBpdHMgdGltZWxvY2sgZXhwaXJlcy4KCkVuY29kZWQgYXMgYSBgI1tjb250cmFjdHR5cGVdYCBzbyB0aGUgc3RvcmVkIHByb3Bvc2FsIHN1cnZpdmVzCnNlcmlhbGl6YXRpb24gdW5jaGFuZ2VkLCBhbmQgc28gYWRkaW5nIGEgbmV3IGFjdGlvbiB2YXJpYW50IGxhdGVyIGlzIGFuCmFkZGl0aXZlIGNoYW5nZSAobmV3IGVudW0gbWVtYmVyKSByYXRoZXIgdGhhbiBhIHJlLWVuY29kZS4AAAAAAAAAAA9Qcml2aWxlZ2VBY3Rpb24AAAAAAgAAAAAAAAApQXBwbHkgYGZlZV9jb25maWdgIHRvIHRoZSB0b2tlbiBjb250cmFjdC4AAAAAAAAMU2V0RmVlQ29uZmlnAAAAAQAAADNUcmFuc2ZlciBjb250cmFjdCBvd25lcnNoaXAgKGFkbWluKSB0byBgbmV3X2FkbWluYC4AAAAAEVRyYW5zZmVyT3duZXJzaGlwAAAAAAAAAQAAABM=", "AAAAAQAAADNBIHByb3Bvc2VkIHByaXZpbGVnZWQgYWN0aW9uIGF3YWl0aW5nIGl0cyB0aW1lbG9jay4AAAAAAAAAABFQcml2aWxlZ2VQcm9wb3NhbAAAAAAAAAUAAAAWVGhlIGFjdGlvbiB0byBwZXJmb3JtLgAAAAAABmFjdGlvbgAAAAAH0AAAAA9Qcml2aWxlZ2VBY3Rpb24AAAAAPFdoZXRoZXIgdGhlIGFjdGlvbiB3YXMgY2FuY2VsbGVkIGJ5IGl0cyBzdWJtaXR0ZXIuIFRlcm1pbmFsLgAAAAljYW5jZWxsZWQAAAAAAAABAAAAg1VuaXggdGltZXN0YW1wIChzZWNvbmRzKSB3aGVuIHRoZSBhY3Rpb24gbWF5IGV4ZWN1dGUuIFJlY29yZGVkIG9uY2UgYXQKc3VibWlzc2lvbjsgcmVzdWJtaXR0aW5nIHRoZSBzYW1lIGFjdGlvbiByZXN0YXJ0cyB0aGUgY2xvY2suAAAAAA1leGVjdXRhYmxlX2F0AAAAAAAABgAAAC9XaGV0aGVyIHRoZSBhY3Rpb24gaGFzIGJlZW4gZXhlY3V0ZWQuIFRlcm1pbmFsLgAAAAAIZXhlY3V0ZWQAAAABAAAAX0FkbWluIHRoYXQgc3VibWl0dGVkIHRoZSBhY3Rpb24uIE9ubHkgdGhpcyBhZGRyZXNzIChvciBhIGxhdGVyIGFkbWluKQptYXkgZXhlY3V0ZSBvciBjYW5jZWwgaXQuAAAAAAlzdWJtaXR0ZXIAAAAAAAAT" ]), @@ -1418,23 +1528,30 @@ export class Client extends ContractClient { unpause: this.txFromJSON>, upgrade: this.txFromJSON>, decimals: this.txFromJSON, + has_role: this.txFromJSON, pause_as: this.txFromJSON>, transfer: this.txFromJSON, allowance: this.txFromJSON, burn_from: this.txFromJSON, get_nonce: this.txFromJSON, + is_paused: this.txFromJSON, batch_mint: this.txFromJSON>, + grant_role: this.txFromJSON, initialize: this.txFromJSON>, unpause_as: this.txFromJSON>, lock_tokens: this.txFromJSON>, + revoke_role: this.txFromJSON>, update_name: this.txFromJSON>, + get_proposal: this.txFromJSON>, get_treasury: this.txFromJSON>, set_metadata: this.txFromJSON>, set_treasury: this.txFromJSON>, + get_threshold: this.txFromJSON, rescue_tokens: this.txFromJSON>, transfer_from: this.txFromJSON, update_symbol: this.txFromJSON>, batch_transfer: this.txFromJSON>, + get_admin_pool: this.txFromJSON>, get_fee_config: this.txFromJSON>, get_max_supply: this.txFromJSON, set_admin_pool: this.txFromJSON, @@ -1445,11 +1562,15 @@ export class Client extends ContractClient { update_metadata: this.txFromJSON>, withdraw_locked: this.txFromJSON>, approve_proposal: this.txFromJSON, + get_role_proposal: this.txFromJSON>, is_proposal_ready: this.txFromJSON, set_fee_exemption: this.txFromJSON>, transfer_ownership: this.txFromJSON>, + create_role_proposal: this.txFromJSON, remove_fee_exemption: this.txFromJSON>, execute_from_contract: this.txFromJSON>, + execute_role_proposal: this.txFromJSON>, + list_legacy_proposals: this.txFromJSON, get_privilege_proposal: this.txFromJSON>, cancel_privilege_action: this.txFromJSON>, propose_privilege_action: this.txFromJSON>, diff --git a/wasm-budget.json b/wasm-budget.json index 64151ae1..3ddaf96d 100644 --- a/wasm-budget.json +++ b/wasm-budget.json @@ -1,11 +1,11 @@ { - "_comment": "Per-contract WASM size budgets for the release build (#956). Budget = measured size + 5% headroom. The token budget reflects lock_tokens and withdraw_locked (#1076, #1077); vesting links the token crate, so that same lockup code is included in its WASM. The rate-limit and split budgets are raised by #914/#918 as well: both contracts link the bc-forge-admin crate, whose privileged-action timelock, role renounce, and proposal listing additions compile into their WASMs.", - "_measured_on": "cargo 1.96.0, wasm32-unknown-unknown, --release, zero warnings. #914/#918 re-measured on 1.94.0; rate-limit/split re-measured on 1.96.0.", + "_comment": "Per-contract WASM size budgets for the release build (#956). Budget = measured size + 5% headroom. The token and vesting budgets are raised by #778 for submit_upgrade_proposal multi-sig WASM upgrade support (#653).", + "_measured_on": "cargo 1.96.0, wasm32-unknown-unknown, --release, zero warnings.", "budgets": { - "bc_forge_rate_limit.wasm": 54603, - "bc_forge_split.wasm": 94692, - "bc_forge_token.wasm": 186000, - "bc_forge_vesting.wasm": 221000, + "bc_forge_rate_limit.wasm": 58000, + "bc_forge_split.wasm": 98000, + "bc_forge_token.wasm": 205000, + "bc_forge_vesting.wasm": 240000, "bc_forge_wrapper.wasm": 140000, "bc_forge_yield_vault.wasm": 76765 }