diff --git a/apps/web/app/about/page.tsx b/apps/web/app/about/page.tsx index 31bcff8..a4ab212 100644 --- a/apps/web/app/about/page.tsx +++ b/apps/web/app/about/page.tsx @@ -26,9 +26,9 @@ export default function AboutPage() { open SDK, an MCP server, and pay-per-job settlement over x402.
- The current service provides live, managed NVIDIA L40S capacity. A provider - program for operator-owned infrastructure is in technical onboarding and is not yet - available for production leases. + The current service provides live NVIDIA capacity across several card classes, sourced + from vetted providers. Operator-owned hardware is not part of the service today, so every + machine a customer rents is brokered, and the trust class on each offer says so.
@@ -45,7 +45,38 @@ export default function AboutPage() {Workspaces are fresh containers, not confidential computing, so the infrastructure provider remains inside their trust boundary. Each vault item names the weakest workspace class it may be released into, and the default is above what the network can currently serve.
-+ PRISM is the network's access token, not its currency. Compute is quoted and paid + in USDG or USDC, so a renter never has to hold PRISM to buy a GPU. What PRISM buys is a + cheaper rate on part of the fleet. +
+
+ Operators can reserve a machine for stakers. Those offers are marked{" "}
+ staker_only and priced below open capacity: today they run at 177 base
+ units per second against 222 elsewhere, about 20 percent lower, and a wallet that has
+ not staked is refused rather than charged the higher rate. Stake matures before it
+ counts and unwinds through a cooldown, both enforced by the contract.
+
+ The token is{" "} + + 0x0A1e0Cc7 + {" "} + and the staking contract is{" "} + + 0x7c4060e0 + + , both on Robinhood Chain. The staking contract is source-verified and has no owner, no + pause and no upgrade path, so the terms it was deployed with are the terms it keeps. + Live capacity and which offers are staker-only are published on the{" "} + offers endpoint. +
+Prism's protocol, smart contracts, service architecture, and application code are developed in the open. Architecture and operational contracts are diff --git a/inference/gateway.mjs b/inference/gateway.mjs index 34ccdda..23c0398 100644 --- a/inference/gateway.mjs +++ b/inference/gateway.mjs @@ -111,7 +111,7 @@ const TX_HASH = /^0x[0-9a-f]{64}$/i; // pays first, so its key is the transaction hash. The exact scheme authorizes // first, so its key is the payer and the authorization nonce, which is also // what the token contract itself refuses to reuse. -const PAYMENT_KEY = /^(0x[0-9a-f]{64}|0x[0-9a-f]{40}:0x[0-9a-f]{64})$/i; +const PAYMENT_KEY = /^([a-z0-9:-]+\|)?(0x[0-9a-f]{64}|0x[0-9a-f]{40}:0x[0-9a-f]{64})$/i; const ROUTES = { single: { @@ -285,6 +285,15 @@ export const USDC_BASE_DOMAIN = { name: "USD Coin", version: "2" }; /// on-chain DOMAIN_SEPARATOR. A client that signs against the wrong domain /// produces a well-formed signature the token rejects. export const USDG_ROBINHOOD_DOMAIN = { name: "Global Dollar", version: "1" }; +/// USDC is Arc's gas token, exposed both as an 18-decimal native balance and as +/// a 6-decimal ERC-20 at this predeploy. x402 amounts are ERC-20 units, so the +/// payload is unchanged; anything reading a native balance for the same money is +/// off by 10^12. +export const USDC_ARC = "0x3600000000000000000000000000000000000000"; +/// Read off the testnet predeploy on 2026-09-14, and it is not Base's domain: Arc's +/// `name()` is "USDC" where Base returns "USD Coin". Signing Base's domain here +/// produces a well-formed signature that recovers to nobody. +export const USDC_ARC_DOMAIN = { name: "USDC", version: "2" }; export function loadConsumed(file) { const set = new Set(); @@ -302,6 +311,9 @@ export function createGateway({ models, payTo, basePayTo = null, + arcPayTo = null, + arcNetwork = "eip155:5042", + arcTestnet = false, exact = null, originUrl = "https://api.prismnetwork.tech/inference", // Carried in every 402 so an agent that arrives cold learns the price and how @@ -661,7 +673,8 @@ export function createGateway({ detail, state: phase(), retry_after_seconds: seconds, - retry: "nothing was charged; send the same payment header again.", + retry: "nothing was charged; send the same payment header again, or sign a " + + "fresh one if its validBefore has passed while you waited.", }, }; } @@ -678,7 +691,8 @@ export function createGateway({ error, detail, state: phase(), - retry: "nothing was charged; retry with the same payment header", + retry: "nothing was charged; retry with the same payment header, or sign a " + + "fresh one if its validBefore has passed while you waited", }, }; } @@ -742,6 +756,36 @@ export function createGateway({ extra: { ...USDC_BASE_DOMAIN, assetTransferMethod: "eip3009" }, }); } + if (arcPayTo) { + list.push({ + scheme: "exact", + network: arcNetwork, + asset: USDC_ARC, + payTo: arcPayTo, + amount: amount.toString(), + resource: `${originUrl}${route.path}`, + description: + `${route.unit} ${route.where}, paid in USDC on Arc${arcTestnet ? " testnet" : ""}. ` + + "Sign an EIP-3009 transferWithAuthorization for the quoted amount and send it as the " + + "payment header. You need no gas: the authorization is broadcast for you." + + // The other rails in this array settle on mainnets. A quote that lists + // a test chain beside them, priced the same and labelled only by its + // id, invites a caller to pick the wrong one and spend real money. + (arcTestnet ? " TEST NETWORK: this rail settles in play money and buys nothing." : ""), + mimeType: "application/json", + maxTimeoutSeconds: 60, + ...(shape ? { outputSchema: shape } : {}), + // v2 strips `description` from an accepts entry and keeps `extra`, so a + // warning that only lives in the prose never reaches a v2 client. This + // rail sits beside mainnet rails priced identically, and its chain id is + // the only other thing telling them apart. + extra: { + ...USDC_ARC_DOMAIN, + assetTransferMethod: "eip3009", + ...(arcTestnet ? { testnet: true } : {}), + }, + }); + } list.push({ scheme: "exact", network: "eip155:4663", @@ -810,9 +854,6 @@ export function createGateway({ if (typeof from !== "string" || typeof nonce !== "string") { return { ok: false, reason: "invalid_payload" }; } - const key = `${from}:${nonce}`.toLowerCase(); - if (!PAYMENT_KEY.test(key)) return { ok: false, reason: "invalid_payload" }; - // The requirement we quoted, not the one the client echoed back: a payer // who rewrites the amount or the recipient must fail, and comparing their // copy against itself would always pass. @@ -823,10 +864,26 @@ export function createGateway({ ); if (!want) return { ok: false, reason: "invalid_network" }; + // Namespaced by chain: a payer whose client derives nonces deterministically + // pays the same nonce on two rails, and an un-namespaced key refuses the + // second as a replay. The token's own authorizationState is per chain + // already, so this only guards the local set. + const key = `${want.network}|${from}:${nonce}`.toLowerCase(); + if (!PAYMENT_KEY.test(key)) return { ok: false, reason: "invalid_payload" }; + // Checked before the spent-payment cache is consulted. The authorization // and its signature are broadcast on chain to settle, so a payer and nonce // read off a block would otherwise redeem the answer they bought. - const verdict = await exact.verify(parsed, want); + // An unreachable chain is our fault, not the payer's, but 402 is the only + // answer that lets them retry or pick another rail. Letting it throw would + // take the process down and every warm lease with it. + let verdict; + try { + verdict = await exact.verify(parsed, want); + } catch (error) { + log(`verify failed on ${want.network}: ${describe(error)}`); + return { ok: false, reason: "facilitator_unavailable" }; + } if (!verdict.isValid) return { ok: false, reason: verdict.invalidReason }; if (!reservePayment(key)) { diff --git a/inference/gateway.test.mjs b/inference/gateway.test.mjs index 0b66205..e882aad 100644 --- a/inference/gateway.test.mjs +++ b/inference/gateway.test.mjs @@ -3,7 +3,7 @@ import { test } from "node:test"; import { recoverMessageAddress } from "viem"; import { privateKeyToAccount } from "viem/accounts"; import { boundMessage, hashRequest } from "@prismnetwork/x402/codec"; -import { createGateway, DEFAULT_PRICING, priceFor, SERVED_TTL_MS } from "./gateway.mjs"; +import { createGateway, DEFAULT_PRICING, priceFor, SERVED_TTL_MS, USDC_ARC } from "./gateway.mjs"; // What a lease costs and what it produces. The rate is the network's, read off // /v1/offers and confirmed by settled receipts (900s billed 199,800 micros). @@ -812,3 +812,102 @@ test("a spent payment answers the request it bought and no other", async () => { assert.equal(resigned.body.error, "payment_reused"); assert.equal(deps.calls.generations.length, 2, "the second request must not be served from the first"); }); + +const ARC_PAY_TO = "0xe67a61f8e2aC4057aa22e64306107E7120078447"; + +test("Arc is offered only when it is configured, and never displaces the other rails", async () => { + const without = build(fakeDeps(), { basePayTo: BASE_PAY_TO, exact: fakeExact() }); + const bare = (await without.handleInference({ model: "llama3.2:3b", prompt: "hi" }, undefined, 2)).body.accepts; + assert.deepEqual(bare.map((a) => a.network), ["eip155:8453", "eip155:4663"]); + + const withArc = build(fakeDeps(), { + basePayTo: BASE_PAY_TO, + arcPayTo: ARC_PAY_TO, + arcNetwork: "eip155:5042", + exact: fakeExact(), + }); + const offered = (await withArc.handleInference({ model: "llama3.2:3b", prompt: "hi" }, undefined, 2)).body.accepts; + // Base stays the headline: validators read accepts[0], and leading with a + // chain they do not index makes a payable endpoint look unsupported. + assert.deepEqual(offered.map((a) => a.network), ["eip155:8453", "eip155:5042", "eip155:4663"]); + assert.equal(offered[0].amount, offered[1].amount, "the same work costs the same on either chain"); +}); + +test("the Arc quote carries Arc's own EIP-712 domain, not Base's", async () => { + const gateway = build(fakeDeps(), { + arcPayTo: ARC_PAY_TO, + arcNetwork: "eip155:5042", + exact: fakeExact(), + }); + const arc = (await gateway.handleInference({ model: "llama3.2:3b", prompt: "hi" }, undefined, 2)).body.accepts.find((a) => a.network.startsWith("eip155:5042")); + assert.equal(arc.extra.name, "USDC"); + assert.equal(arc.extra.version, "2"); + assert.equal(arc.extra.assetTransferMethod, "eip3009"); + assert.equal(arc.asset, USDC_ARC); + assert.equal(arc.payTo, ARC_PAY_TO); +}); + +test("the quoted Arc network is the one configured, so a testnet quote cannot read as mainnet", async () => { + const gateway = build(fakeDeps(), { + arcPayTo: ARC_PAY_TO, + arcNetwork: "eip155:5042002", + exact: fakeExact(), + }); + const arc = (await gateway.handleInference({ model: "llama3.2:3b", prompt: "hi" }, undefined, 2)).body.accepts.find((a) => a.network.startsWith("eip155:5042")); + assert.equal(arc.network, "eip155:5042002"); +}); + +test("a chain that cannot be reached answers 402 rather than taking the process down", async () => { + const unreachable = { + handles: () => true, + verify: async () => { throw new Error("HTTP request failed: 403"); }, + settle: async () => { throw new Error("unreachable"); }, + }; + const gateway = build(fakeDeps(), { + arcPayTo: ARC_PAY_TO, + arcNetwork: "eip155:5042", + exact: unreachable, + }); + const quote = (await gateway.handleInference({ model: "llama3.2:3b", prompt: "hi" }, undefined, 2)).body; + const arc = quote.accepts.find((a) => a.network === "eip155:5042"); + const header = Buffer.from(JSON.stringify({ + x402Version: 2, + accepted: { scheme: "exact", network: arc.network, asset: arc.asset, payTo: arc.payTo }, + payload: { authorization: { from: PAYER, to: arc.payTo, value: arc.amount, + validAfter: "0", validBefore: String(Math.floor(Date.now() / 1000) + 3600), nonce: `0x${"11".repeat(32)}` }, + signature: `0x${"22".repeat(65)}` }, + }), "utf8").toString("base64"); + + const answer = await gateway.handleInference({ model: "llama3.2:3b", prompt: "hi" }, header, 2); + assert.equal(answer.status, 402, "an unreachable rail is a 402, not a crash"); + assert.equal(answer.body.error, "facilitator_unavailable"); +}); + + +test("a test network says so in the quote, because it sits beside rails that spend real money", async () => { + const gateway = build(fakeDeps(), { + basePayTo: BASE_PAY_TO, + arcPayTo: ARC_PAY_TO, + arcNetwork: "eip155:5042002", + arcTestnet: true, + exact: fakeExact(), + }); + const offered = (await gateway.handleInference({ model: "llama3.2:3b", prompt: "hi" }, undefined, 2)).body.accepts; + const arc = offered.find((a) => a.network === "eip155:5042002"); + // v2 drops `description`, so the marker has to survive in `extra`. + assert.equal(arc.extra.testnet, true); + // The mainnet rails beside it must stay unmarked, or the warning means nothing. + for (const other of offered.filter((a) => a !== arc)) { + assert.equal(other.extra?.testnet, undefined, `${other.network} is not a test network`); + } +}); + +test("the mainnet Arc rail carries no test warning", async () => { + const gateway = build(fakeDeps(), { + arcPayTo: ARC_PAY_TO, arcNetwork: "eip155:5042", exact: fakeExact(), + }); + const arc = (await gateway.handleInference({ model: "llama3.2:3b", prompt: "hi" }, undefined, 2)) + .body.accepts.find((a) => a.network === "eip155:5042"); + assert.equal(arc.extra.testnet, undefined); + assert.equal(arc.extra.name, "USDC"); +}); diff --git a/inference/server.mjs b/inference/server.mjs index f2b2fb4..076f14d 100644 --- a/inference/server.mjs +++ b/inference/server.mjs @@ -11,16 +11,18 @@ import { createServer } from "node:http"; import { Readable } from "node:stream"; import { pipeline } from "node:stream/promises"; -import { createPublicClient, getAddress, http, recoverMessageAddress } from "viem"; +import { createPublicClient, fallback, getAddress, http, recoverMessageAddress } from "viem"; import { DEFAULT_IMAGE, PrismAgent, robinhoodChain, USDG } from "@prismnetwork/agent-sdk"; import { createExactEvm } from "@prismnetwork/x402/exact-evm"; import { createCdpFacilitator, routeByNetwork } from "@prismnetwork/x402/cdp-facilitator"; import { bazaar, boundMessage, detect, hashRequest } from "@prismnetwork/x402/codec"; import { authorized, listener } from "@prismnetwork/x402/listen"; -import { base as baseChain } from "viem/chains"; +import { arc as arcChain, arcTestnet as arcTestnetChain, base as baseChain } from "viem/chains"; import { createGateway, MAX_CONFIDENTIAL_BODY_BYTES, + USDC_ARC, + USDC_ARC_DOMAIN, USDC_BASE, USDC_BASE_DOMAIN, USDG_ROBINHOOD_DOMAIN, @@ -113,7 +115,25 @@ try { // read the receipt back. baseRpcUrl: (process.env.X402_BASE_RPC_URL ?? "https://base.drpc.org,https://1rpc.io/base") .split(",").map((u) => u.trim()).filter(Boolean), + arcPayTo: process.env.X402_ARC_PAY_TO ? getAddress(process.env.X402_ARC_PAY_TO) : null, + arcChain: /^testnet$/i.test((process.env.PRISM_ARC_CHAIN ?? "").trim()) ? arcTestnetChain : arcChain, + arcRpcUrl: (process.env.X402_ARC_RPC_URL ?? "").split(",").map((u) => u.trim()).filter(Boolean), }; + // Arc mainnet publishes no publicly resolvable RPC, so viem ships that chain + // without one. Guessing a hostname here would advertise a rail that cannot + // settle, which costs a payer a signature and a wait for nothing. + if (config.arcPayTo && !config.arcRpcUrl.length) { + if (!config.arcChain.rpcUrls?.default?.http?.length) { + throw new Error( + `X402_ARC_PAY_TO is set for chain ${config.arcChain.id}, which publishes no default RPC. ` + + "Set X402_ARC_RPC_URL, or leave X402_ARC_PAY_TO unset to stop offering Arc.", + ); + } + config.arcRpcUrl = [...config.arcChain.rpcUrls.default.http]; + } + if (config.arcPayTo && !process.env.PRISM_X402_COLLECTOR_KEY) { + throw new Error("X402_ARC_PAY_TO is set but PRISM_X402_COLLECTOR_KEY is not, so nothing can broadcast an authorization"); + } if (config.basePayTo && !process.env.PRISM_X402_COLLECTOR_KEY) { throw new Error("X402_BASE_PAY_TO is set but PRISM_X402_COLLECTOR_KEY is not, so nothing can broadcast an authorization"); } @@ -195,6 +215,22 @@ const fetchOllama = (slot, path, init) => fetch(`http://127.0.0.1:${config.tunne // Robinhood Chain is always verifiable: the agent key that leases GPUs also // holds the gas to broadcast an authorization there. Base is offered only when // there is somewhere to collect it. +const TOKEN_DOMAIN_ABI = [ + { name: "name", type: "function", stateMutability: "view", inputs: [], outputs: [{ type: "string" }] }, + { name: "version", type: "function", stateMutability: "view", inputs: [], outputs: [{ type: "string" }] }, +]; + +// Checked before the network table is built, so a rail that cannot settle is +// never quoted. Arc alone is dropped: Base and Robinhood do not care that +// Circle's chain is unreachable, and taking them down with it would turn a +// misconfigured extra into an outage. +try { + await confirmArcRail(); +} catch (error) { + console.error(`arc not offered: ${error.message}`); + config.arcPayTo = null; +} + const exactNetworks = { "eip155:4663": { chain: robinhoodChain, @@ -202,6 +238,18 @@ const exactNetworks = { privateKey: process.env.PRISM_AGENT_KEY, assets: { [USDG]: USDG_ROBINHOOD_DOMAIN }, }, + // Gas and takings are the same asset here, so the collector only refills + // itself when it is also arcPayTo. + ...(config.arcPayTo + ? { + [`eip155:${config.arcChain.id}`]: { + chain: config.arcChain, + rpcUrl: config.arcRpcUrl, + privateKey: process.env.PRISM_X402_COLLECTOR_KEY, + assets: { [USDC_ARC]: USDC_ARC_DOMAIN }, + }, + } + : {}), ...(config.basePayTo ? { "eip155:8453": { @@ -222,6 +270,40 @@ const exactNetworks = { const localExact = createExactEvm(exactNetworks); +/// Confirm the Arc rail points where it claims before a payer signs anything. +/// +/// Two things can be quietly wrong. PRISM_ARC_CHAIN picks the chain while +/// X402_ARC_RPC_URL picks the endpoint, and nothing ties them together, so a +/// leftover testnet URL under a mainnet chain id quotes a rail that can never +/// settle. And the EIP-712 domain is a constant read off testnet; if mainnet's +/// USDC reports anything else, every signature verifies against nobody. + +async function confirmArcRail() { + if (!config.arcPayTo) return; + const client = createPublicClient({ + chain: config.arcChain, + transport: fallback(config.arcRpcUrl.map((url) => http(url))), + }); + const [id, name, version] = await Promise.all([ + client.getChainId(), + client.readContract({ address: USDC_ARC, abi: TOKEN_DOMAIN_ABI, functionName: "name" }), + client.readContract({ address: USDC_ARC, abi: TOKEN_DOMAIN_ABI, functionName: "version" }), + ]); + if (id !== config.arcChain.id) { + throw new Error( + `X402_ARC_RPC_URL answers chain ${id} but Arc is configured as ${config.arcChain.id}. ` + + "Set PRISM_ARC_CHAIN=testnet for the test network, or point the RPC at mainnet.", + ); + } + if (name !== USDC_ARC_DOMAIN.name || version !== USDC_ARC_DOMAIN.version) { + throw new Error( + `Arc USDC at ${USDC_ARC} reports domain ${JSON.stringify({ name, version })}, ` + + `not ${JSON.stringify(USDC_ARC_DOMAIN)}. Every payment would be refused, so Arc is not offered.`, + ); + } +} + + // Base settles at Coinbase when a key is configured, because the Bazaar only // indexes endpoints its own facilitator has settled for. Everything else, and // Base itself when no key is set, stays on ours. @@ -352,6 +434,9 @@ const gateway = createGateway({ models: config.models, payTo: config.payTo, basePayTo: config.basePayTo, + arcPayTo: config.arcPayTo, + arcNetwork: `eip155:${config.arcChain.id}`, + arcTestnet: Boolean(config.arcChain.testnet), exact, schemas: inferenceSchemas, batchSchemas, @@ -404,6 +489,17 @@ const server = createServer(async (req, res) => { // The confidential tier as an aggregator's provider monitor reads a // catalogue. Free, and assembled from live pricing and the live spend cap so // it says the same thing the 402 does. + // The commit the enclave runs moves whenever the upstream redeploys, twice in + // four days so far, and a pin that only lives in a published package refuses + // every call until each client upgrades. A client may read the accepted + // commits here instead; none does yet, so this is the server half. + if (req.method === "GET" && url.pathname === "/v1/confidential/workload") { + return json(res, 200, { + repo_url: "https://github.com/Dstack-TEE/private-ai-gateway.git", + repo_commits: (process.env.PRISM_CONFIDENTIAL_COMMITS ?? "") + .split(",").map((c) => c.trim().toLowerCase()).filter((c) => /^[0-9a-f]{40}$/.test(c)), + }, { "cache-control": "public, max-age=60" }); + } if (req.method === "GET" && url.pathname === "/v1/provider/models") { const catalogue = providerModels({ confidential: gateway.confidential(), @@ -435,7 +531,7 @@ const server = createServer(async (req, res) => { x402Version: 1, name: "Prism Network managed inference", description: - "Pay-per-generation LLM inference on rented GPUs. Pay in USDC on Base or USDG on Robinhood " + + "Pay-per-generation LLM inference on rented GPUs. Pay in USDC on Base or Arc, or USDG on Robinhood " + "Chain; an unpaid request answers 402 with the exact price on each. The serving lease " + "settles onchain with a public receipt." + (confidential diff --git a/python-sdk/prismnetwork/__init__.py b/python-sdk/prismnetwork/__init__.py index 3c5dcab..2bcb224 100644 --- a/python-sdk/prismnetwork/__init__.py +++ b/python-sdk/prismnetwork/__init__.py @@ -92,4 +92,4 @@ "keyset_digest", "report_data", ] -__version__ = "0.4.0" +__version__ = "0.4.2" diff --git a/python-sdk/prismnetwork/_inference.py b/python-sdk/prismnetwork/_inference.py index 98799e4..632f375 100644 --- a/python-sdk/prismnetwork/_inference.py +++ b/python-sdk/prismnetwork/_inference.py @@ -82,7 +82,7 @@ "c083ff9e6a5ddf10f6c9e9bb1f74cc618deebecfea5208b563c574399db4637c", "repo_url": "https://github.com/Dstack-TEE/private-ai-gateway.git", "os_image_hash": "bd369a8c2f9edb2b52dad48ac8e0b32dde5f1337c423a506b48d07403a7d8033", - "repo_commit": "b6b5c1b82f6fc59490db5a5255bf4493805e66c6", + "repo_commit": "3e56bd30dd459d0df90afeb6d63eca7a919bc22f", } _ERC20_TRANSFER = [ @@ -414,6 +414,28 @@ class Gate: skipped: bool = False +def _accepted_commits(expected) -> set: + """Every commit this check will accept. + + The pin exists because a TDX quote alone says nothing about which code was + measured. The commit inside it moves whenever the upstream redeploys, which + is not our schedule and has happened twice in four days, and a pin that + lives only in a published package leaves every installed client refusing to + serve until it upgrades. + + So the commit, and only the commit, can also come from ``repo_commits`` in + the expected workload, which a caller may refresh from + ``/v1/confidential/workload``. The launcher image digest and the OS image + hash stay where they are, compiled in. Those identify the binary, so the + worst a wrong list can do here is refuse a workload that was fine. + """ + commits = {expected.get("repo_commit")} if expected.get("repo_commit") else set() + extra = expected.get("repo_commits") + if isinstance(extra, (list, tuple, set)): + commits |= {c for c in extra if isinstance(c, str)} + return commits + + def _measured_workload(app_compose) -> dict: """What the measured compose says it runs. Every value here is inside the bytes that hash to the measured compose-hash, so none of it is the report's @@ -459,9 +481,11 @@ def gate_workload_identity(app_compose, os_image_hash, provenance, expected) -> f"this SDK pins {expected.get('repo_url')}") if measured["repo_commit"] is None: problems.append("the measured compose pins no single source commit") - elif expected.get("repo_commit") and measured["repo_commit"] != str(expected["repo_commit"]).lower(): - problems.append(f"the measured commit is {measured['repo_commit']}, " - f"this SDK pins {expected['repo_commit']}") + else: + accepted = {str(c).lower() for c in _accepted_commits(expected) if c} + if accepted and measured["repo_commit"] not in accepted: + problems.append(f"the measured commit is {measured['repo_commit']}, " + f"this SDK accepts {', '.join(sorted(accepted))}") # A declaration that is not an object declares nothing to contradict the # measured compose with, and the measured compose is the authority anyway. diff --git a/python-sdk/pyproject.toml b/python-sdk/pyproject.toml index 27b6722..6e6dcac 100644 --- a/python-sdk/pyproject.toml +++ b/python-sdk/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "hatchling.build" [project] name = "prismnetwork" -version = "0.4.0" +version = "0.4.2" description = "Headless GPU leasing and metered confidential inference on Prism Network for autonomous agents. Wallet-signature auth, on-chain USDG payment, SSH." readme = "README.md" requires-python = ">=3.10" diff --git a/python-sdk/tests/test_inference.py b/python-sdk/tests/test_inference.py index 0dcdfea..d053c5d 100644 --- a/python-sdk/tests/test_inference.py +++ b/python-sdk/tests/test_inference.py @@ -42,6 +42,7 @@ seal_field, ) from prismnetwork._inference import ( + _accepted_commits, DSTACK_RUNTIME_EVENT, EXPECTED_WORKLOAD, ConfidentialError, @@ -932,17 +933,21 @@ class CapturedReportTest(unittest.TestCase): """One live report from the public attestation endpoint, as the offline vector for the replay and binding checks. - Its ``app_compose`` travels base64 in the fixture, because the measured - compose is a shell script whose paths a secret scanner reads as leaked local - ones, and is restored here byte for byte: the whole point of the check is - that those bytes hash to the measurement. + The measured compose is a shell script whose paths a secret scanner reads as + leaked local ones, so the fixture stores it base64 and restores it byte for + byte here. The endpoint used to return it encoded and now returns it plain, + so a recapture has to be re-encoded before it lands in the repo. The whole + point of the check is that those bytes hash to the measurement. """ @classmethod def setUpClass(cls): capture = json.loads(FIXTURE.read_text()) evidence = capture["report"]["attestation"]["evidence"] - evidence["app_compose"] = base64.b64decode(evidence["app_compose_b64"]).decode("utf-8") + # Captures taken before 2026-09 carry the compose base64-encoded; the + # endpoint returns it as text now. + if "app_compose" not in evidence: + evidence["app_compose"] = base64.b64decode(evidence["app_compose_b64"]).decode("utf-8") cls.report = capture["report"] cls.nonce = capture["nonce"] # Before the key set's not_after, which is what the capture is a @@ -1728,5 +1733,36 @@ def test_a_failure_after_funding_that_is_not_ours_is_still_a_funded_lease(self): self.assertEqual(caught.exception.broadcast, TX) +class RefreshableCommitTest(unittest.TestCase): + """The commit moves on the upstream's schedule, so it can be refreshed + without a release. Nothing else in the pin can.""" + + def test_a_refreshed_commit_is_accepted_alongside_the_baked_in_one(self): + expected = dict(EXPECTED_WORKLOAD) + expected["repo_commits"] = ["a" * 40] + accepted = _accepted_commits(expected) + self.assertIn(EXPECTED_WORKLOAD["repo_commit"], accepted) + self.assertIn("a" * 40, accepted) + + def test_the_baked_in_commit_survives_an_empty_or_junk_refresh(self): + for junk in (None, [], "not-a-list", 7, {}): + expected = dict(EXPECTED_WORKLOAD, repo_commits=junk) + self.assertEqual( + _accepted_commits(expected), + {EXPECTED_WORKLOAD["repo_commit"]}, + f"a {type(junk).__name__} refresh must not widen or empty the pin", + ) + + def test_the_image_and_os_hash_are_not_refreshable(self): + expected = dict(EXPECTED_WORKLOAD) + expected["repo_commits"] = ["b" * 40] + # Only the commit is drawn from the refreshable set; a served list has no + # way to name a different launcher image or OS image. + self.assertNotIn(expected["launcher_image"], _accepted_commits(expected)) + self.assertNotIn(expected["os_image_hash"], _accepted_commits(expected)) + + if __name__ == "__main__": unittest.main() + + diff --git a/scripts/check-prism-health.py b/scripts/check-prism-health.py index 8b9404d..79e2561 100755 --- a/scripts/check-prism-health.py +++ b/scripts/check-prism-health.py @@ -26,6 +26,9 @@ import urllib.error import urllib.request +# Kept in step with EXPECTED_WORKLOAD in sdk/attest.mjs and _inference.py. +PINNED_WORKLOAD_COMMIT = "3e56bd30dd459d0df90afeb6d63eca7a919bc22f" + DEFAULT_STATE = "/var/lib/prism/health-state.json" REPEAT_SECONDS = 6 * 60 * 60 # The RPC sits behind a CDN that answers urllib's default agent with a 403. @@ -310,14 +313,51 @@ def check_canary(alarms, path, stale_seconds): ) +def check_workload_pin(alarms, attestation_url, pinned_commit): + """The SDK pins the exact commit the enclave must be running, and refuses + every end-to-end encrypted call when the measurement disagrees. Upstream + redeploys on their own schedule, so the pin goes stale without anything on + our side changing, and the paid upstream probe above will not notice: + it talks to the provider directly and never exercises the sealed path our + customers use. Reading the live provenance costs nothing and catches the + drift the moment it happens.""" + if not pinned_commit: + alarms.append(Alarm("workload_pin_config", "no pinned commit to compare against")) + return + report = json.loads(get(attestation_url, timeout=30)) + measured = (((report.get("attestation") or {}).get("source_provenance") or {}) + .get("repo_commit")) + if not measured: + alarms.append(Alarm("workload_pin", "the attestation published no repo_commit")) + return + if measured != pinned_commit: + alarms.append( + Alarm( + "workload_pin", + f"the enclave now measures {measured}, the SDK pins {pinned_commit}; " + "every end-to-end encrypted call fails closed until the accepted " + "commits are updated", + ) + ) + + def check_reconciliation(alarms, url): """The monitor already reconciles leases against the escrow. Read its answers rather than asking the same questions a second way.""" - try: - body = get(url, timeout=10) - except (urllib.error.URLError, OSError) as error: - alarms.append(Alarm("reconcile", f"reconciliation monitor is unreachable: {error}")) - return + # A local scrape that sometimes runs past its budget under load. One slow + # read is not an outage, and paging on it produced an unreachable/recovered + # pair every few minutes carrying no news about the leases it watches. + for attempt in range(2): + try: + body = get(url, timeout=20) + break + except (urllib.error.URLError, OSError) as error: + if attempt: + alarms.append( + Alarm("reconcile", f"reconciliation monitor is unreachable on two tries: {error}") + ) + return + time.sleep(3) readings = {} for line in body.splitlines(): @@ -431,6 +471,17 @@ def main(): os.environ.get("PRISM_CONFIDENTIAL_PROBE_MODEL", "openai/gpt-oss-20b"), ), ), + ( + "workload_pin", + lambda: check_workload_pin( + alarms, + os.environ.get( + "PRISM_CONFIDENTIAL_ATTESTATION_URL", + "https://tee.redpill.ai/v1/aci/attestation", + ), + os.environ.get("PRISM_CONFIDENTIAL_PINNED_COMMIT", PINNED_WORKLOAD_COMMIT), + ), + ), ("reconcile", lambda: check_reconciliation(alarms, metrics_url)), ("canary", lambda: check_canary(alarms, canary_path, canary_stale)), ) diff --git a/sdk/attest.mjs b/sdk/attest.mjs index e6a5f9b..9b35141 100644 --- a/sdk/attest.mjs +++ b/sdk/attest.mjs @@ -56,7 +56,7 @@ export const EXPECTED_WORKLOAD = { "ghcr.io/redpill-ai/private-ai-launcher@sha256:c083ff9e6a5ddf10f6c9e9bb1f74cc618deebecfea5208b563c574399db4637c", repoUrl: "https://github.com/Dstack-TEE/private-ai-gateway.git", osImageHash: "bd369a8c2f9edb2b52dad48ac8e0b32dde5f1337c423a506b48d07403a7d8033", - repoCommit: "b6b5c1b82f6fc59490db5a5255bf4493805e66c6", + repoCommit: "3e56bd30dd459d0df90afeb6d63eca7a919bc22f", }; const NRAS_ATTEST_URL = "https://nras.attestation.nvidia.com/v3/attest/gpu"; diff --git a/sdk/attest.test.mjs b/sdk/attest.test.mjs index ed187db..f50446c 100644 --- a/sdk/attest.test.mjs +++ b/sdk/attest.test.mjs @@ -60,10 +60,14 @@ const specReceipt = { ...JSON.parse(RECEIPT_JCS), signature: RECEIPT_SIGNATURE } // because the whole point of the check is that those bytes hash to the // measurement. const capture = JSON.parse(readFileSync(new URL("./fixtures/aci-attestation.json", import.meta.url), "utf8")); -capture.report.attestation.evidence.app_compose = Buffer.from( - capture.report.attestation.evidence.app_compose_b64, - "base64", -).toString("utf8"); +// Captures taken before 2026-09 carry the compose base64-encoded; the endpoint +// returns it as text now. +if (capture.report.attestation.evidence.app_compose === undefined) { + capture.report.attestation.evidence.app_compose = Buffer.from( + capture.report.attestation.evidence.app_compose_b64, + "base64", + ).toString("utf8"); +} const binding = JSON.parse(readFileSync(new URL("./fixtures/gpu-evidence-binding.json", import.meta.url), "utf8")); test("canonicalization is member order independent and reproduces the vector digest", async () => { diff --git a/sdk/fixtures/aci-attestation.json b/sdk/fixtures/aci-attestation.json index e991d85..95c0c22 100644 --- a/sdk/fixtures/aci-attestation.json +++ b/sdk/fixtures/aci-attestation.json @@ -1 +1 @@ -{"captured_at":"2026-08-25","endpoint":"https://tee.redpill.ai/v1/aci/attestation","nonce":"ba657b23327cfce615f28e54565d7b2f2717ab6e0b93e1625075dead38ae3d24","report":{"api_version":"aci/1","workload_keyset_digest":"sha256:fa47ae4c27d5df35d063dd6e0cbd258b8cff1a83b3b974b66ca7cb9fea2d1ec9","attestation":{"tee_type":"tdx","workload_keyset":{"subject":null,"not_after":1790174801,"receipt_signing_keys":[{"key_id":"dstack-kms-receipt-ed25519-v1","algo":"ed25519","public_key":"110f3824daeeef29dbeba9677a5794ffed257b1082d9fd4599b3c0819953aa0a"}],"e2ee_public_keys":[{"key_id":"dstack-kms-e2ee-v1","algo":"secp256k1-aes-256-gcm-hkdf-sha256","public_key":"04943cea0b4babf60f6e2031e9a00866a37c4ae696fb45895b3a9b38ab8cbb898f42c85b704aceaa0a396cf26f7fdf79d83205be7e11d3a5d70419a68277158c3d"},{"key_id":"dstack-kms-e2ee-x25519-v1","algo":"x25519-aes-256-gcm-hkdf-sha256","public_key":"408e82d159832cfae15007781bcade0badee7d50e9f76d50eaa1777464006537"}],"tls_public_keys":[{"spki_sha256":"22ad6f73dd10547af55d06825c8015413968a439b8f76adc3a6aba9a32e6c71b","domain":"tee.redpill.ai"},{"spki_sha256":"8bafb8e6ddc55e3e662b6385a2820494fc6e90c64688136860b1851a81b7ee06","domain":"inference.phala.com"},{"spki_sha256":"c68585e7dc00a55d3082a9c860cb916e1788c5daec51505e413d27ab94f7d4c7","domain":"api.redpill.ai"}]},"report_data":"2de4c658f762db2cb8a103b2dad429597e409de8bdd6a5934ba829dcf0cf368b","source_provenance":{"repo_url":"https://github.com/Dstack-TEE/private-ai-gateway.git","repo_commit":"b6b5c1b82f6fc59490db5a5255bf4493805e66c6","image_digest":null,"image_provenance":null},"evidence":{"quote":"040002008100000000000000939a7233f79c4ca9940a0db3957f06074d79685452a1c5725d6ff7f9d09c91b4000000000b0105000000000000000000000000007bf063280e94fb051f5dd7b1fc59ce9aac42bb961df8d44b709c9b0ff87a7b4df648657ba6d1189589feab1d5a3c9a9d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000702000000000000f06dfda6dce1cf904d4e2bab1dc370634cf95cefa2ceb2de2eee127c9382698090d7a4a13e14c536ec6c9c3c8fa8707701ce26ab560d466475b6778456f406dd73da55a3f94dbd1cffc141db63527d3bd8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d6118f0eeb30e9d9178d2b9106dddd002d979b6fa79bdec415051afae2021384c29a32d2f6454fa369617598378ffb5e07e6f51aa763abfe75c3ddfbf4f425fe3f0ceff66d807a75e049303dce9addf68e7218729bd419638af63a370f65878cdf67e467e60edc1737bcf8e682d48131bfb427f523226aa7f197a7608e9b3784783fa759ef5b28191fa12f9ddb36b858f23282cbe6b24708467cc26eca437111e3bed80a2f35bbba448ecee37d3de70407232a8534b9df5635a5646cacd9bbcb2de4c658f762db2cb8a103b2dad429597e409de8bdd6a5934ba829dcf0cf368b0000000000000000000000000000000000000000000000000000000000000000cc100000693becb9e6526657ab40a384eee3b04101f51be3edd3d24453b7891bcdbc22a25bbefb8a7f7db0eb3c45b34a924219e7dc0d5780f3aa68c6efb18c13ee3268c2f0bfa28939a048d1d67a664ae6595ec4514829a10a01f7fc10230dd75c44697bf80c2e1e89a20ca66c1f76795d1cf5553a394c311bcc4601b9231b111d70d6b506004610000005050a0a05ff00020000000000000000000000000000000000000000000000000000000000000000000000000000000015000000000000000700000000000000e5a3a7b5d830c2953b98534c6c59a3a34fdc34e933f7f5898f0a85cf08846bca0000000000000000000000000000000000000000000000000000000000000000dc9e2a7c6f948f17474e34a7fc43ed030f7c1563f1babddf6340c82e0e54a8c5000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020006000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009c1dc25ab6fd4ae8afb815c1c46f6d3f9bbe7ab053e699d259bf9136751037b20000000000000000000000000000000000000000000000000000000000000000a233764b3a84792c1aa7f165b48fd0eb5e05077a8672b35ad8242d9c544f0d638082a3002dc29b09308131db2a205e5d0782a72a03278473accd29f17c0806442000000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f05005e0e00002d2d2d2d2d424547494e2043455254494649434154452d2d2d2d2d0a4d49494538544343424a656741774942416749555359617753595541735374766a483236625541434d506e6f6a797777436759494b6f5a497a6a3045417749770a634445694d434147413155454177775a535735305a577767553064594946424453794251624746305a6d397962534244515445614d42674741315545436777520a535735305a577767513239796347397959585270623234784644415342674e564241634d43314e68626e526849454e7359584a684d51737743515944565151490a44414a445154454c4d416b474131554542684d4356564d774868634e4d6a59774d7a49784d4463304e5455795768634e4d7a4d774d7a49784d4463304e5455790a576a42774d534977494159445651514444426c4a626e526c624342545231676755454e4c49454e6c636e52705a6d6c6a5958526c4d526f77474159445651514b0a4442464a626e526c6243424462334a7762334a6864476c76626a45554d424947413155454277774c553246756447456751327868636d4578437a414a42674e560a4241674d416b4e424d517377435159445651514745774a56557a425a4d424d4742797147534d34394167454743437147534d34394177454841304941424747690a41664533764c54435150696e5470685047695854516c645948654f6f657257516d4b66745141787939446c63353469446b4b537852786e7a38474f7a466f65690a6b584e532b44374575464864666b476a754e796a67674d4e4d4949444354416642674e5648534d4547444157674253566231334e765276683655424a796454300a4d383442567776655644427242674e56485238455a4442694d47436758714263686c706f64485277637a6f764c32467761533530636e567a6447566b633256790a646d6c6a5a584d75615735305a577775593239744c334e6e6543396a5a584a3061575a7059324630615739754c3359304c33426a61324e796244396a595431770a624746305a6d397962535a6c626d4e765a476c755a7a316b5a584977485159445652304f42425945464c6d495a7555304e42506c79336e757041556f41396f590a73625a514d41344741315564447745422f775145417749477744414d42674e5648524d4241663845416a41414d4949434f67594a4b6f5a496876684e415130420a424949434b7a4343416963774867594b4b6f5a496876684e415130424151515162536e396a546e656c37306e456e776e523951666554434341575147436971470a534962345451454e41514977676746554d42414743797147534962345451454e41514942416745464d42414743797147534962345451454e41514943416745460a4d42414743797147534962345451454e41514944416745434d42414743797147534962345451454e41514945416745434d42414743797147534962345451454e0a41514946416745464d42454743797147534962345451454e41514947416749412f7a415142677371686b69472b453042445145434277494241444151426773710a686b69472b4530424451454343414942416a415142677371686b69472b45304244514543435149424144415142677371686b69472b45304244514543436749420a4144415142677371686b69472b45304244514543437749424144415142677371686b69472b45304244514543444149424144415142677371686b69472b4530420a44514543445149424144415142677371686b69472b45304244514543446749424144415142677371686b69472b453042445145434477494241444151426773710a686b69472b45304244514543454149424144415142677371686b69472b45304244514543455149424454416642677371686b69472b45304244514543456751510a425155434167582f4141494141414141414141414144415142676f71686b69472b45304244514544424149414144415542676f71686b69472b453042445145450a424159676f473841414141774477594b4b6f5a496876684e4151304242516f424154416542676f71686b69472b453042445145474242414e78727a30753075620a48784e354e3964353631576d4d45514743697147534962345451454e415163774e6a415142677371686b69472b45304244514548415145422f7a4151426773710a686b69472b45304244514548416745422f7a415142677371686b69472b45304244514548417745422f7a414b42676771686b6a4f5051514441674e49414442460a4169454131305850553751764338564a743949654f724a366c4430744b58462b54746a4e422f6f7a62635235517477434944576e57773946484e7351745359420a70394c5463792f5670376f517367417076763332732f4236576b73760a2d2d2d2d2d454e442043455254494649434154452d2d2d2d2d0a2d2d2d2d2d424547494e2043455254494649434154452d2d2d2d2d0a4d4949436c6a4343416a32674177494241674956414a567658633239472b487051456e4a3150517a7a674658433935554d416f4743437147534d343942414d430a4d476778476a415942674e5642414d4d45556c756447567349464e48574342536232393049454e424d526f77474159445651514b4442464a626e526c624342440a62334a7762334a6864476c76626a45554d424947413155454277774c553246756447456751327868636d4578437a414a42674e564241674d416b4e424d5173770a435159445651514745774a56557a4165467730784f4441314d6a45784d4455774d5442614677307a4d7a41314d6a45784d4455774d5442614d484178496a41670a42674e5642414d4d47556c756447567349464e4857434251513073675547786864475a76636d306751304578476a415942674e5642416f4d45556c75644756730a49454e76636e4276636d4630615739754d5251774567594456515148444174545957353059534244624746795954454c4d416b474131554543417743513045780a437a414a42674e5642415954416c56544d466b77457759484b6f5a497a6a3043415159494b6f5a497a6a304441516344516741454e53422f377432316c58534f0a3243757a7078773734654a423732457944476757357258437478327456544c7136684b6b367a2b5569525a436e71523770734f766771466553786c6d546c4a6c0a65546d693257597a33714f42757a43427544416642674e5648534d4547444157674251695a517a575770303069664f44744a5653763141624f536347724442530a42674e5648523845537a424a4d45656752614244686b466f64485277637a6f764c324e6c636e52705a6d6c6a5958526c63793530636e567a6447566b633256790a646d6c6a5a584d75615735305a577775593239744c306c756447567355306459556d397664454e424c6d526c636a416442674e5648513445466751556c5739640a7a62306234656c4153636e553944504f4156634c336c517744675944565230504151482f42415144416745474d42494741315564457745422f7751494d4159420a4166384341514177436759494b6f5a497a6a30454177494452774177524149675873566b6930772b6936565947573355462f32327561586530594a446a3155650a6e412b546a44316169356343494359623153416d4435786b66545670766f34556f79695359787244574c6d5552344349394e4b7966504e2b0a2d2d2d2d2d454e442043455254494649434154452d2d2d2d2d0a2d2d2d2d2d424547494e2043455254494649434154452d2d2d2d2d0a4d4949436a7a4343416a53674177494241674955496d554d316c71644e496e7a6737535655723951477a6b6e42717777436759494b6f5a497a6a3045417749770a614445614d4267474131554541777752535735305a5777675530645949464a766233516751304578476a415942674e5642416f4d45556c756447567349454e760a636e4276636d4630615739754d5251774567594456515148444174545957353059534244624746795954454c4d416b47413155454341774351304578437a414a0a42674e5642415954416c56544d423458445445344d4455794d5445774e4455784d466f58445451354d54497a4d54497a4e546b314f566f77614445614d4267470a4131554541777752535735305a5777675530645949464a766233516751304578476a415942674e5642416f4d45556c756447567349454e76636e4276636d46300a615739754d5251774567594456515148444174545957353059534244624746795954454c4d416b47413155454341774351304578437a414a42674e56424159540a416c56544d466b77457759484b6f5a497a6a3043415159494b6f5a497a6a3044415163445167414543366e45774d4449595a4f6a2f69505773437a61454b69370a314f694f534c52466857476a626e42564a66566e6b59347533496a6b4459594c304d784f346d717379596a6c42616c54565978465032734a424b357a6c4b4f420a757a43427544416642674e5648534d4547444157674251695a517a575770303069664f44744a5653763141624f5363477244425342674e5648523845537a424a0a4d45656752614244686b466f64485277637a6f764c324e6c636e52705a6d6c6a5958526c63793530636e567a6447566b63325679646d6c6a5a584d75615735300a5a577775593239744c306c756447567355306459556d397664454e424c6d526c636a416442674e564851344546675155496d554d316c71644e496e7a673753560a55723951477a6b6e4271777744675944565230504151482f42415144416745474d42494741315564457745422f7751494d4159424166384341514577436759490a4b6f5a497a6a3045417749445351417752674968414f572f35516b522b533943695344634e6f6f774c7550524c735747662f59693747535839344267775477670a41694541344a306c72486f4d732b586f356f2f7358364f39515778485241765a55474f6452513763767152586171493d0a2d2d2d2d2d454e442043455254494649434154452d2d2d2d2d0a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","quote_report_data":"2de4c658f762db2cb8a103b2dad429597e409de8bdd6a5934ba829dcf0cf368b0000000000000000000000000000000000000000000000000000000000000000","event_log":"[{\"imr\":0,\"event_type\":2147483659,\"digest\":\"5fe4f9ee465a361d077a6892f6bc4d19a82b272fea2e3c2c1ef9c33b4d9050115fca0c6dc7a7f68f91c623de38c48226\",\"event\":\"\",\"event_payload\":\"095464785461626c65000100000000000000af96bb93f2b9b84e9462e0ba745642360090800000000000\"},{\"imr\":0,\"event_type\":2147483658,\"digest\":\"344bc51c980ba621aaa00da3ed7436f7d6e549197dfe699515dfa2c6583d95e6412af21c097d473155875ffd561d6790\",\"event\":\"\",\"event_payload\":\"2946762858585858585858582d585858582d585858582d585858582d58585858585858585858585829000000c0ff000000000040080000000000\"},{\"imr\":0,\"event_type\":2147483649,\"digest\":\"9dc3a1f80bcec915391dcda5ffbb15e7419f77eab462bbf72b42166fb70d50325e37b36f93537a863769bcf9bedae6fb\",\"event\":\"\",\"event_payload\":\"61dfe48bca93d211aa0d00e098032b8c0a00000000000000000000000000000053006500630075007200650042006f006f007400\"},{\"imr\":0,\"event_type\":2147483649,\"digest\":\"6f2e3cbc14f9def86980f5f66fd85e99d63e69a73014ed8a5633ce56eca5b64b692108c56110e22acadcef58c3250f1b\",\"event\":\"\",\"event_payload\":\"61dfe48bca93d211aa0d00e098032b8c0200000000000000000000000000000050004b00\"},{\"imr\":0,\"event_type\":2147483649,\"digest\":\"d607c0efb41c0d757d69bca0615c3a9ac0b1db06c557d992e906c6b7dee40e0e031640c7bfd7bcd35844ef9edeadc6f9\",\"event\":\"\",\"event_payload\":\"61dfe48bca93d211aa0d00e098032b8c030000000000000000000000000000004b0045004b00\"},{\"imr\":0,\"event_type\":2147483649,\"digest\":\"08a74f8963b337acb6c93682f934496373679dd26af1089cb4eaf0c30cf260a12e814856385ab8843e56a9acea19e127\",\"event\":\"\",\"event_payload\":\"cbb219d73a3d9645a3bcdad00e67656f0200000000000000000000000000000064006200\"},{\"imr\":0,\"event_type\":2147483649,\"digest\":\"18cc6e01f0c6ea99aa23f8a280423e94ad81d96d0aeb5180504fc0f7a40cb3619dd39bd6a95ec1680a86ed6ab0f9828d\",\"event\":\"\",\"event_payload\":\"cbb219d73a3d9645a3bcdad00e67656f03000000000000000000000000000000640062007800\"},{\"imr\":0,\"event_type\":4,\"digest\":\"394341b7182cd227c5c6b07ef8000cdfd86136c4292b8e576573ad7ed9ae41019f5818b4b971c9effc60e1ad9f1289f0\",\"event\":\"\",\"event_payload\":\"00000000\"},{\"imr\":0,\"event_type\":10,\"digest\":\"2058afc033c14a2558b6b3ce664343eeb2b7941427251330e66ff3f12eb5c5706a9c651eee49d656c38ba3090b29ff43\",\"event\":\"\",\"event_payload\":\"414350492044415441\"},{\"imr\":0,\"event_type\":10,\"digest\":\"2012337df782407ca9495fe820c6744e398a60731d13a2d11d3cdec1c9541e0946b928b929ff28715cc40bcfd71d92b9\",\"event\":\"\",\"event_payload\":\"414350492044415441\"},{\"imr\":0,\"event_type\":10,\"digest\":\"98731e9fce9603662dba3c4f225a117489960615cb2d893e913c903daeaf09528096875ea94610fdb7eba69a5c20e9e3\",\"event\":\"\",\"event_payload\":\"414350492044415441\"},{\"imr\":1,\"event_type\":2147483651,\"digest\":\"90e278aa4d688f4f05bf76f1786fea174abcea0d6b44e81cea5b3327f3f211e5c465a9c34b513283bed2512bca6d4a19\",\"event\":\"\",\"event_payload\":\"1860fd7a0000000000c485000000000000000000000000002a000000000000000403140072f728144ab61e44b8c39ebdd7f893c7040412006b00650072006e0065006c0000007fff0400\"},{\"imr\":0,\"event_type\":2147483650,\"digest\":\"1dd6f7b457ad880d840d41c961283bab688e94e4b59359ea45686581e90feccea3c624b1226113f824f315eb60ae0a7c\",\"event\":\"\",\"event_payload\":\"61dfe48bca93d211aa0d00e098032b8c0900000000000000020000000000000042006f006f0074004f0072006400650072000000\"},{\"imr\":0,\"event_type\":2147483650,\"digest\":\"23ada07f5261f12f34a0bd8e46760962d6b4d576a416f1fea1c64bc656b1d28eacf7047ae6e967c58fd2a98bfa74c298\",\"event\":\"\",\"event_payload\":\"61dfe48bca93d211aa0d00e098032b8c08000000000000003e0000000000000042006f006f0074003000300030003000090100002c0055006900410070007000000004071400c9bdb87cebf8344faaea3ee4af6516a10406140021aa2c4614760345836e8ab6f46623317fff0400\"},{\"imr\":1,\"event_type\":2147483655,\"digest\":\"77a0dab2312b4e1e57a84d865a21e5b2ee8d677a21012ada819d0a98988078d3d740f6346bfe0abaa938ca20439a8d71\",\"event\":\"\",\"event_payload\":\"43616c6c696e6720454649204170706c69636174696f6e2066726f6d20426f6f74204f7074696f6e\"},{\"imr\":1,\"event_type\":4,\"digest\":\"394341b7182cd227c5c6b07ef8000cdfd86136c4292b8e576573ad7ed9ae41019f5818b4b971c9effc60e1ad9f1289f0\",\"event\":\"\",\"event_payload\":\"00000000\"},{\"imr\":2,\"event_type\":6,\"digest\":\"9c824b958dbbef07ec732fd79727e995d5eca309dbc6d62e4fd2840f267c5e87108b5fe25c7997c67801ff391fb67ffc\",\"event\":\"\",\"event_payload\":\"ed223b8f1a0000004c4f414445445f494d4147453a3a4c6f61644f7074696f6e7300\"},{\"imr\":2,\"event_type\":6,\"digest\":\"5eb4f34f2ec49071551c5562ebaab9f86408f4a0eadaa3d7f05157e37ab04a1f040a82eaae94015d628a7ea4aa482cd2\",\"event\":\"\",\"event_payload\":\"ec223b8f0d0000004c696e757820696e6974726400\"},{\"imr\":1,\"event_type\":2147483655,\"digest\":\"214b0bef1379756011344877743fdc2a5382bac6e70362d624ccf3f654407c1b4badf7d8f9295dd3dabdef65b27677e0\",\"event\":\"\",\"event_payload\":\"4578697420426f6f7420536572766963657320496e766f636174696f6e\"},{\"imr\":1,\"event_type\":2147483655,\"digest\":\"0a2e01c85deae718a530ad8c6d20a84009babe6c8989269e950d8cf440c6e997695e64d455c4174a652cd080f6230b74\",\"event\":\"\",\"event_payload\":\"4578697420426f6f742053657276696365732052657475726e656420776974682053756363657373\"},{\"imr\":3,\"event_type\":134217729,\"digest\":\"f9974020ef507068183313d0ca808e0d1ca9b2d1ad0c61f5784e7157c362c06536f5ddacdad4451693f48fcc72fff624\",\"event\":\"system-preparing\",\"event_payload\":\"\"},{\"imr\":3,\"event_type\":134217729,\"digest\":\"8562fc3980258ea5119a31356844547c42ba696d73f6ecdc7d29732beef0083f22674ce14349a8a1400254466e851407\",\"event\":\"app-id\",\"event_payload\":\"fdb7a14e5a6675f752e2cb69c9067a98ca402918\"},{\"imr\":3,\"event_type\":134217729,\"digest\":\"3b496ff216c671138e922080e66deabce8a85c8cb628789afa4a93f47566d842d55308dd8cc0f92ab38f1a2578563ee7\",\"event\":\"compose-hash\",\"event_payload\":\"ce26ab560d466475b6778456f406dd73da55a3f94dbd1cffc141db63527d3bd8\"},{\"imr\":3,\"event_type\":134217729,\"digest\":\"dbb7d7c2c2ce19938fb5989949f2c4bba6829ced5cd7b8c0d98696c293ac1c5dc8b1bfb9bc95b61e2ff778a3686651eb\",\"event\":\"instance-id\",\"event_payload\":\"15e847e02a22706121de347498427469d2e7c379\"},{\"imr\":3,\"event_type\":134217729,\"digest\":\"98bd7e6bd3952720b65027fd494834045d06b4a714bf737a06b874638b3ea00ff402f7f583e3e3b05e921c8570433ac6\",\"event\":\"boot-mr-done\",\"event_payload\":\"\"},{\"imr\":3,\"event_type\":134217729,\"digest\":\"65828c6f922910fd0e272501a8b2bb6b03e24c99bb19d1cd530586061d8738f9dd0564752db23d556a6b381cbf465a85\",\"event\":\"mr-kms\",\"event_payload\":\"692afc6d7a86a32cfc1ebd9cad1a576aab012bab46986ba609bc8d6407270572\"},{\"imr\":3,\"event_type\":134217729,\"digest\":\"c936f709860155a455c519b505fe29bde21d1b778534a8f0b41b706b0f789eae2ea899e224fedb2331c18324aab4db93\",\"event\":\"os-image-hash\",\"event_payload\":\"bd369a8c2f9edb2b52dad48ac8e0b32dde5f1337c423a506b48d07403a7d8033\"},{\"imr\":3,\"event_type\":134217729,\"digest\":\"83368b43a0fc6f824f5a9220592df85fd30e2d405ecbd253a5c6354af63e6c9b41aec557c38a38e348ab87f9ac8fc68c\",\"event\":\"key-provider\",\"event_payload\":\"7b226e616d65223a226b6d73222c226964223a223330353933303133303630373261383634386365336430323031303630383261383634386365336430333031303730333432303030343838343465623432636364663863353266643466313734663336326663623962626431396334356664343866316564656332643866316361323335333665633161373430323162346365653631306330373466383239346434333162326237666565326333396535333333666461663061343532326434336662313539643966227d\"},{\"imr\":3,\"event_type\":134217729,\"digest\":\"ba51104636900268b0e059fa3d266419d079d1e94aea26fb9fcbb8d764bf4c89a67ac271b8a0d1a3989945132a111fc7\",\"event\":\"storage-fs\",\"event_payload\":\"7a6673\"},{\"imr\":3,\"event_type\":134217729,\"digest\":\"1a76b2a80a0be71eae59f80945d876351a7a3fb8e9fd1ff1cede5734aa84ea11fd72b4edfbb6f04e5a85edd114c751bd\",\"event\":\"system-ready\",\"event_payload\":\"\"}]","vm_config":"{\"os_image_hash\":\"bd369a8c2f9edb2b52dad48ac8e0b32dde5f1337c423a506b48d07403a7d8033\",\"cpu_count\":16,\"memory_size\":34359738368,\"qemu_version\":\"8.2.2\",\"pci_hole64_size\":0,\"hugepages\":false,\"num_gpus\":0,\"num_nvswitches\":0,\"hotplug_off\":false,\"image\":\"dstack-0.5.9-bd369a8c\",\"host_share_mode\":\"9p\",\"spec_version\":1}","key_custody":{"provider":"dstack-kms","keys":[{"role":"receipt","path":"aci/receipt-ed25519/v1","purpose":"aci.receipt.ed25519.v1","algo":"ed25519","public_key":"110f3824daeeef29dbeba9677a5794ffed257b1082d9fd4599b3c0819953aa0a","kms_public_key":"02f7fb3ed8c352d316dfdc19458a9f29c06eb7e74130b3808d784e2fd401a2c12d","signature_chain":["d1f59335effc2688acdf502ee34d8d3373b0e7e6be493075383714ce5673a29973f224690437c483ae3fdd37172df3abad82877c4023ed7c5a64d5acaf18477c00","5c2fe36bdb1e434c0a371579bcbce07c4e7b89eba45affa089191baec84f23ad77b24a594aa28427b6b7a5f348b0ecf5597abfd9a2add05ddb55c521ba38a38501"]},{"role":"e2ee-secp256k1","path":"aci/e2ee/v1","purpose":"aci.e2ee.v1","algo":"secp256k1-aes-256-gcm-hkdf-sha256","public_key":"04943cea0b4babf60f6e2031e9a00866a37c4ae696fb45895b3a9b38ab8cbb898f42c85b704aceaa0a396cf26f7fdf79d83205be7e11d3a5d70419a68277158c3d","kms_public_key":"03943cea0b4babf60f6e2031e9a00866a37c4ae696fb45895b3a9b38ab8cbb898f","signature_chain":["452d6f86a807fef0ce0d65e6c5cd25a0a249b1fd8608d26c3efe17fc10346f4c2d3dfb8969d10dc1feac1d595b3816f63faa40ac370a3a233ce1d712d418c89701","5c2fe36bdb1e434c0a371579bcbce07c4e7b89eba45affa089191baec84f23ad77b24a594aa28427b6b7a5f348b0ecf5597abfd9a2add05ddb55c521ba38a38501"]},{"role":"e2ee-x25519","path":"aci/e2ee-x25519/v1","purpose":"aci.e2ee.x25519.v1","algo":"x25519-aes-256-gcm-hkdf-sha256","public_key":"408e82d159832cfae15007781bcade0badee7d50e9f76d50eaa1777464006537","kms_public_key":"03892f86b3f55f78cc0760cec933cf8e2a92862fb173c2d221cc25895847cbb5eb","signature_chain":["358cd661ca4f5e986ed950ca083bf7bcfef6ab4b839ca11a953b156d64f82b1c51a213730d5777b4c845170827680d41e8220c2f950a38081025ff16eb3789ba00","5c2fe36bdb1e434c0a371579bcbce07c4e7b89eba45affa089191baec84f23ad77b24a594aa28427b6b7a5f348b0ecf5597abfd9a2add05ddb55c521ba38a38501"]}]},"downstream_tls_binding":{"domain":"tee.redpill.ai","spki_sha256":"22ad6f73dd10547af55d06825c8015413968a439b8f76adc3a6aba9a32e6c71b"},"app_compose_b64":"eyJhbGxvd2VkX2VudnMiOlsiUFJJVkFURV9BSV9HQVRFV0FZX0FETUlOX1RPS0VOIiwiUFJJVkFURV9BSV9HQVRFV0FZX0NPTlRST0xfVVJMIiwiUFJJVkFURV9BSV9HQVRFV0FZX0NPTlRST0xfVE9LRU4iLCJEU1RBQ0tfUk9PVF9QVUJMSUNfS0VZIiwiQ0xPVURGTEFSRV9BUElfVE9LRU4iLCJDRVJUQk9UX0VNQUlMIiwiTk9ERV9FWFBPUlRFUl9VU0VSIiwiTk9ERV9FWFBPUlRFUl9QQVNTV09SRF9IQVNIIl0sImRvY2tlcl9jb21wb3NlX2ZpbGUiOiIjIGRzdGFjayAvIFBoYWxhIGRlcGxveW1lbnQgbWFuaWZlc3QgZm9yIHRoZSBwcml2YXRlLWFpLWdhdGV3YXkgc3RhY2sgdmlhIHRoZSBsYXVuY2hlci5cbiNcbiMgVGhlIGxhdW5jaGVyIGltYWdlIGlzIHRoZSBtZWFzdXJlZCB0cnVzdC1yb290OiBwaW4gaXQgYnkgQHNoYTI1NiBkaWdlc3QgKHRoZVxuIyBkaWdlc3QgKyB0aGlzIGZpbGUgYXJlIGhhc2hlZCBpbnRvIHRoZSBURFggcXVvdGUpLiBUaGUgbGF1bmNoZXIgY2xvbmVzK2J1aWxkc1xuIyB0aGUgZ2F0ZXdheSBmcm9tIHNvdXJjZSBhdCBib290OyB0aGUgYXR0ZXN0YXRpb24gdmVyaWZpZXIgaXNcbiMgdGhlIGdhdGV3YXkncyB2ZW5kb3JlZCBjb25maWRlbnRpYWxfdmVyaWZpZXIgcGFja2FnZSwgc28gaXQgbmVlZHMgbm8gc2VwYXJhdGUgcGluLlxuI1xuIyBUaGUgZ2F0ZXdheSdzIHNvdXJjZSBwaW4gKyBzdGF0aWMgY29uZmlnIGFyZSBpbmxpbmVkIGFzIGNvbXBvc2UgYGNvbmZpZ3M6YFxuIyAobWVhc3VyZWQgaW50byB0aGUgYXR0ZXN0YXRpb24pOiB0aGUgbGF1bmNoZXIgY2xvbmVzIHRoZSBwaW4gYW5kIHRoZSBnYXRld2F5XG4jIHJlYWRzIHRoZSBjb25maWcgZnJvbSBtb3VudGVkIGZpbGVzLiBTZWNyZXQgdmFsdWVzIGFyZSBzdXBwbGllZCBhcyBkc3RhY2tcbiMgRU5DUllQVEVEIFNFQ1JFVFMgYW5kIHJlZmVyZW5jZWQgYXMgJHtWQVJ9IHNvIGRzdGFjayBpbmplY3RzIHRoZW0g4oCUIG9ubHkgdGhlXG4jIHZhcmlhYmxlIG5hbWVzIGFwcGVhciBpbiB0aGlzIHB1YmxpYyBmaWxlLCBuZXZlciB0aGUgdmFsdWVzLlxuXG5zZXJ2aWNlczpcbiAgIyBUTFMtdGVybWluYXRpbmcgaW5ncmVzczogcmVxdWVzdHMgQ0FBLXBpbm5lZCBMZXQncyBFbmNyeXB0IGNlcnRzIHZpYSBDbG91ZGZsYXJlXG4gICMgRE5TLTAxLCByZWdpc3RlcnMgdW5kZXIgdGhlIGRzdGFjayBnYXRld2F5IGRvbWFpbiwgYW5kIHJldmVyc2UtcHJveGllcyBpbmJvdW5kXG4gICMgNDQzIHRvIHRoZSBsYXVuY2hlcidzIGdhdGV3YXkgb24gOjgwODYuIFBpbiBieSBAc2hhMjU2IGRpZ2VzdCBsaWtlIHRoZSBsYXVuY2hlci5cbiAgZHN0YWNrLWluZ3Jlc3M6XG4gICAgaW1hZ2U6IGRzdGFja3RlZS9kc3RhY2staW5ncmVzczoyLjJAc2hhMjU2OmQwNWE3YjM0M2MzN2MxY2NhMWJiYThkYmY3ZThmM2M2ZDIxMTgxNThhZjJkNDFjNDU1MTAzNzk2ZGI0ZjY3ZjBcbiAgICByZXN0YXJ0OiB1bmxlc3Mtc3RvcHBlZFxuICAgIHBvcnRzOlxuICAgICAgLSBcIjQ0Mzo0NDNcIlxuICAgIGVudmlyb25tZW50OlxuICAgICAgIyAtLS0gcHVibGljIGNvbmZpZzogbGl0ZXJhbHMsIG1lYXN1cmVkIGludG8gdGhlIGF0dGVzdGF0aW9uIC0tLVxuICAgICAgRE5TX1BST1ZJREVSOiBjbG91ZGZsYXJlXG4gICAgICBHQVRFV0FZX0RPTUFJTjogXy4ke0RTVEFDS19HQVRFV0FZX0RPTUFJTn1cbiAgICAgIFNFVF9DQUE6IFwidHJ1ZVwiXG4gICAgICAjIE11bHRpLWRvbWFpbiBUTFMuIFRoZSBpbmdyZXNzIGlzIGFuIEw0IChUQ1ApIHByb3h5OiBpdCB0ZXJtaW5hdGVzIFRMUyBmb3JcbiAgICAgICMgZWFjaCBob3N0bmFtZSBhbmQgZm9yd2FyZHMgdGhlIERFQ1JZUFRFRCBzdHJlYW0gdW50b3VjaGVkLCBzbyB0aGUgY2xpZW50J3NcbiAgICAgICMgb3JpZ2luYWwgSFRUUCBIb3N0IHN1cnZpdmVzLiBUaGUgZ2F0ZXdheSB1c2VzIHRoYXQgSG9zdCB0byBwaWNrIHRoZVxuICAgICAgIyBtYXRjaGluZyBkb3duc3RyZWFtX3Rsc19iaW5kaW5nLiBCb3RoIHB1YmxpYyBob3N0bmFtZXMgcm91dGUgYnkgU05JIHRvIHRoZVxuICAgICAgIyBzYW1lIGdhdGV3YXkgbGlzdGVuZXIgKGNvbXBvc2Ugc2VydmljZSBuYW1lLCBub3QgbG9jYWxob3N0KS5cbiAgICAgIERPTUFJTlM6IHxcbiAgICAgICAgdGVlLnJlZHBpbGwuYWlcbiAgICAgICAgaW5mZXJlbmNlLnBoYWxhLmNvbVxuICAgICAgICBhcGkucmVkcGlsbC5haVxuICAgICAgUk9VVElOR19NQVA6IHxcbiAgICAgICAgdGVlLnJlZHBpbGwuYWk9bGF1bmNoZXI6ODA4NlxuICAgICAgICBpbmZlcmVuY2UucGhhbGEuY29tPWxhdW5jaGVyOjgwODZcbiAgICAgICAgYXBpLnJlZHBpbGwuYWk9bGF1bmNoZXI6ODA4NlxuICAgICAgIyAtLS0gc2VjcmV0czogdmFsdWVzIGNvbWUgZnJvbSBkc3RhY2sgRW5jcnlwdGVkIFNlY3JldHMgKG5ldmVyIGNvbW1pdCB2YWx1ZXMpIC0tLVxuICAgICAgIyBOT1RFOiB0aGlzIHNpbmdsZSBDbG91ZGZsYXJlIHRva2VuIG11c3QgaGF2ZSBETlMtZWRpdCAoYW5kIENBQSkgcmlnaHRzIG9uXG4gICAgICAjIEJPVEggdGhlIHJlZHBpbGwuYWkgYW5kIHBoYWxhLmNvbSB6b25lcywgb3IgY2VydCBpc3N1YW5jZSBmb3Igb25lIGZhaWxzLlxuICAgICAgQ0xPVURGTEFSRV9BUElfVE9LRU46ICR7Q0xPVURGTEFSRV9BUElfVE9LRU59XG4gICAgICBDRVJUQk9UX0VNQUlMOiAke0NFUlRCT1RfRU1BSUx9XG4gICAgdm9sdW1lczpcbiAgICAgIC0gL3Zhci9ydW4vZHN0YWNrLnNvY2s6L3Zhci9ydW4vZHN0YWNrLnNvY2tcbiAgICAgIC0gL3Zhci9ydW4vdGFwcGQuc29jazovdmFyL3J1bi90YXBwZC5zb2NrXG4gICAgICAtIGNlcnQtZGF0YTovZXRjL2xldHNlbmNyeXB0XG4gICAgICAjIFBlci1kb21haW4gbGVhZiBjZXJ0cyAoY2VydC08ZG9tYWluPi5wZW0pIHRoZSBnYXRld2F5IHJlYWRzIHRvIGJpbmQgU1BLSS5cbiAgICAgIC0gZXZpZGVuY2VzOi9ldmlkZW5jZXNcblxuICBsYXVuY2hlcjpcbiAgICBpbWFnZTogZ2hjci5pby9yZWRwaWxsLWFpL3ByaXZhdGUtYWktbGF1bmNoZXJAc2hhMjU2OmMwODNmZjllNmE1ZGRmMTBmNmM5ZTliYjFmNzRjYzYxOGRlZWJlY2ZlYTUyMDhiNTYzYzU3NDM5OWRiNDYzN2NcbiAgICByZXN0YXJ0OiBhbHdheXNcbiAgICAjIFRoZSBnYXRld2F5IG9wZW5zIG1hbnkgZmRzIChpbmJvdW5kIGNvbm5zLCBwZXItdXBzdHJlYW0gcG9vbHMsIGNvbnRyb2wtcGxhbmVcbiAgICAjICsgdmVyaWZpZXIgY2FsbHMpLiBEb2NrZXIncyBkZWZhdWx0IG5vZmlsZSAob2Z0ZW4gMTAyNCkgaXMgZmFyIHRvbyBsb3c6IHVuZGVyXG4gICAgIyBsb2FkIGl0IGhpdCBFTUZJTEUgKFwiVG9vIG1hbnkgb3BlbiBmaWxlc1wiKSwgd2hpY2gga2lsbGVkIHRoZSBnYXRld2F5J3MgYWNjZXB0XG4gICAgIyBsb29wLiBSYWlzZSB0aGUgbGltaXQgd2VsbCBhYm92ZSBwZWFrIGNvbmN1cnJlbmN5LlxuICAgIHVsaW1pdHM6XG4gICAgICBub2ZpbGU6XG4gICAgICAgIHNvZnQ6IDY1NTM2XG4gICAgICAgIGhhcmQ6IDY1NTM2XG4gICAgIyBzdXBlcnZpc29yZCBzdHJlYW1zIHRoZSBnYXRld2F5IGxvZ3MgdG8gdGhlIGNvbnRhaW5lciBzdGRvdXQ7IGNhcCB0aGVcbiAgICAjIHJ1bnRpbWUgbG9nIG9uIGRpc2sgc28gaXQgY2FuJ3QgZ3JvdyB1bmJvdW5kZWQgKH41R0IgdG90YWwsIHJvdGF0ZWQpLlxuICAgICMgU2l6ZWQgZm9yIHRoZSBnYXRld2F5J3MgYWx3YXlzLW9uIHJlcXVlc3Rfb3V0Y29tZSBmYWlsdXJlIGxvZ2dpbmc6XG4gICAgIyByb3VnaGx5IGEgbW9udGggb2YgcmV0ZW50aW9uIG9uIHRoZSBwZXJzaXN0ZW50IHZvbHVtZSBmb3IgaW5jaWRlbnRcbiAgICAjIGZvcmVuc2ljcy5cbiAgICBsb2dnaW5nOlxuICAgICAgZHJpdmVyOiBqc29uLWZpbGVcbiAgICAgIG9wdGlvbnM6XG4gICAgICAgIG1heC1zaXplOiBcIjUwMG1cIlxuICAgICAgICBtYXgtZmlsZTogXCIxMFwiXG4gICAgIyBubyBob3N0IHBvcnQ6IHRyYWZmaWMgZW50ZXJzIHZpYSBkc3RhY2staW5ncmVzcyAoNDQzKSBhbmQgcmVhY2hlcyB0aGVcbiAgICAjIGdhdGV3YXkgb3ZlciB0aGUgY29tcG9zZSBuZXR3b3JrIGFzIGh0dHA6Ly9sYXVuY2hlcjo4MDg2LlxuICAgIGV4cG9zZTpcbiAgICAgIC0gXCI4MDg2XCJcbiAgICB2b2x1bWVzOlxuICAgICAgLSAvdmFyL3J1bi9kc3RhY2suc29jazovdmFyL3J1bi9kc3RhY2suc29jayAgICMgb25seSB0aGUgZ2F0ZXdheSB1c2VzIHRoaXNcbiAgICAgIC0gcGFsLWNhY2hlOi92YXIvbGliL3BhZy9jYWNoZSAgICAgICAgICAgICAgICAgIyBjYXJnby91diBidWlsZCBjYWNoZSAoc3BlZWRzIHJlYm9vdHMpXG4gICAgICAtIHBhbC1zdGF0ZTovdmFyL2xpYi9wYWcvc3RhdGUgICAgICAgICAgICAgICAgICMgbXV0YWJsZSB1cHN0cmVhbXMuanNvbiArIHNlc3Npb25zLmpzb25sXG4gICAgICAtIGV2aWRlbmNlczovZXZpZGVuY2VzOnJvICAgICAgICAgICAgICAgICAgICAgICMgaW5ncmVzcy1taW50ZWQgcGVyLWRvbWFpbiBsZWFmIGNlcnRzIChjZXJ0LTxkb21haW4+LnBlbSlcbiAgICAjIFN0YXRpYyBnYXRld2F5IGNvbmZpZyArIHVwc3RyZWFtIHNlZWQgYXJlIG1vdW50ZWQgZnJvbSB0aGUgYGNvbmZpZ3M6YCBibG9ja1xuICAgICMgYXQgdGhlIGJvdHRvbSAobWVhc3VyZWQgaW50byB0aGUgYXR0ZXN0YXRpb24pLiBUaGUgc291cmNlIHBpbiBpcyBwYXNzZWQgdmlhXG4gICAgIyBgZW52aXJvbm1lbnQ6YCBpbnN0ZWFkIChzZWUgYmVsb3cpLlxuICAgIGNvbmZpZ3M6XG4gICAgICAtIHNvdXJjZTogZ2F0ZXdheS1jb25maWdcbiAgICAgICAgdGFyZ2V0OiAvZXRjL3ByaXZhdGUtYWktZ2F0ZXdheS9nYXRld2F5LmNvbmZpZy5qc29uXG4gICAgICAtIHNvdXJjZTogZ2F0ZXdheS11cHN0cmVhbXNcbiAgICAgICAgdGFyZ2V0OiAvZXRjL3ByaXZhdGUtYWktZ2F0ZXdheS91cHN0cmVhbXMuc2VlZC5qc29uXG4gICAgZW52aXJvbm1lbnQ6XG4gICAgICAjIFRoZSBnYXRld2F5IHJlYWRzIGl0cyB3aG9sZSBwb2xpY3kgZnJvbSB0aGlzIG1vdW50ZWQgc3RhdGljIGNvbmZpZyBmaWxlXG4gICAgICAjIChzZWUgYGNvbmZpZ3M6YCBhYm92ZSk7IENPTkZJR19QQVRIIGlzIHRoZSBvbmx5IGdhdGV3YXktZmFjaW5nIGVudiB2YXIuXG4gICAgICAtIFBSSVZBVEVfQUlfR0FURVdBWV9DT05GSUdfUEFUSD0vZXRjL3ByaXZhdGUtYWktZ2F0ZXdheS9nYXRld2F5LmNvbmZpZy5qc29uXG4gICAgICAjIFRyYWNpbmcgZmlsdGVyLiBgcmVxdWVzdF9vdXRjb21lPWRlYnVnYCB0dXJucyBvbiB0aGUgcmF3IGVycm9yLWRldGFpbFxuICAgICAgIyBmaWVsZCBvZiB0aGUgcGVyLXJlcXVlc3QgZmFpbHVyZSBsb2cg4oCUIGEgZGVsaWJlcmF0ZSBvcGVyYXRvciBjaG9pY2U6XG4gICAgICAjIHVwc3RyZWFtIGVycm9yIGJvZGllcyBtYXkgZWNobyByZXF1ZXN0IGZyYWdtZW50cyBpbnRvIHRoZXNlXG4gICAgICAjIG9wZXJhdG9yLXZpc2libGUgbG9ncy4gRHJvcCB0aGUgYHJlcXVlc3Rfb3V0Y29tZT1kZWJ1Z2AgcGFydCB0byBmYWxsXG4gICAgICAjIGJhY2sgdG8gY29udGVudC1mcmVlIGZhaWx1cmUgbG9nZ2luZyBvbmx5LlxuICAgICAgLSBSVVNUX0xPRz1pbmZvLHJlcXVlc3Rfb3V0Y29tZT1kZWJ1Z1xuICAgICAgIyBHYXRld2F5IHNvdXJjZSBwaW4uIFRoZXNlIGxpdGVyYWxzIGFyZSBtZWFzdXJlZCBpbnRvIHRoZSBhdHRlc3RhdGlvbiwgYW5kXG4gICAgICAjIGJlY2F1c2UgdGhleSBsaXZlIGluIGBlbnZpcm9ubWVudDpgIChwYXJ0IG9mIENvbXBvc2UncyBjb25maWctaGFzaCkgYVxuICAgICAgIyBDT01NSVRfU0hBIGJ1bXAgZm9yY2VzIGEgY29udGFpbmVyIHJlY3JlYXRlIG9uIGBwaGFsYSBkZXBsb3lgIOKAlCBzbyB0aGUgbmV3XG4gICAgICAjIHBpbiBhY3R1YWxseSB0YWtlcyBlZmZlY3QuIChBIGBjb25maWdzOmAtZmlsZSBwaW4gd291bGQgbm90OiBDb21wb3NlIGlnbm9yZXNcbiAgICAgICMgY29uZmlnIGNvbnRlbnQgd2hlbiBkZWNpZGluZyB0byByZWNyZWF0ZSwgc28gdGhlIGNoYW5nZSB3b3VsZCBuZXZlciBhcHBseS4pXG4gICAgICAjIGVudHJ5cG9pbnQuc2ggd3JpdGVzIC9ldGMvZ2l0LWxhdW5jaGVyL2dhdGV3YXkuY29uZiBmcm9tIHRoZXNlLCBhbmQgdGhlXG4gICAgICAjIGdhdGV3YXkgcmVhZHMgdGhhdCBmaWxlIGFzIGl0cyBhdHRlc3RlZCBzb3VyY2UgcHJvdmVuYW5jZS5cbiAgICAgIC0gUFJJVkFURV9BSV9HQVRFV0FZX1JFUE9fVVJMPWh0dHBzOi8vZ2l0aHViLmNvbS9Ec3RhY2stVEVFL3ByaXZhdGUtYWktZ2F0ZXdheS5naXRcbiAgICAgIC0gUFJJVkFURV9BSV9HQVRFV0FZX1JFUE9fQ09NTUlUPWI2YjVjMWI4MmY2ZmM1OTQ5MGRiNWE1MjU1YmY0NDkzODA1ZTY2YzZcbiAgICAgICMgTkVBUiBBSSB2ZXJpZmljYXRpb24gcG9zdHMgVERYIHF1b3RlcyB0byB0aGUgZHN0YWNrLXZlcmlmaWVyIHNpZGVjYXIgYmVsb3c7XG4gICAgICAjIHJlYWNoIGl0IGJ5IGNvbXBvc2Ugc2VydmljZSBuYW1lIChsb2NhbGhvc3Qgd291bGQgYmUgdGhlIGxhdW5jaGVyIGl0c2VsZikuXG4gICAgICAtIERTVEFDS19WRVJJRklFUl9VUkw9aHR0cDovL2RzdGFjay12ZXJpZmllcjo4MDgwXG4gICAgICAjIC0tLSBzZWNyZXRzOiB2YWx1ZXMgY29tZSBmcm9tIGRzdGFjayBFbmNyeXB0ZWQgU2VjcmV0cyAobmV2ZXIgY29tbWl0IHZhbHVlcykgLS0tXG4gICAgICAjIENvbnRyb2wtcGxhbmUgY3JlZGVudGlhbHMuIFRoZSBnYXRld2F5J3MgaW4tcHJvY2VzcyBtaWRkbGV3YXJlIHJlYWRzIHRoZXNlXG4gICAgICAjIGZyb20gdGhlIGBtaWRkbGV3YXJlYCBjb25maWcgc2VjdGlvbiBiZWxvdyAocmVuZGVyZWQgZnJvbSB0aGUgc2FtZSBzZWNyZXRzKS5cbiAgICAgIC0gUFJJVkFURV9BSV9HQVRFV0FZX0NPTlRST0xfVVJMPSR7UFJJVkFURV9BSV9HQVRFV0FZX0NPTlRST0xfVVJMfVxuICAgICAgLSBQUklWQVRFX0FJX0dBVEVXQVlfQ09OVFJPTF9UT0tFTj0ke1BSSVZBVEVfQUlfR0FURVdBWV9DT05UUk9MX1RPS0VOfVxuXG4gICMgVERYIHF1b3RlIHZlcmlmaWVyIGZvciB0aGUgTkVBUiBBSSBwYXRoIChyZXByb2R1Y2VzIEFDUEkvYm9vdCBtZWFzdXJlbWVudHMgdmlhXG4gICMgUUVNVSkuIFRoZSBnYXRld2F5IHJlYWNoZXMgaXQgYXQgaHR0cDovL2RzdGFjay12ZXJpZmllcjo4MDgwIChEU1RBQ0tfVkVSSUZJRVJfVVJMKS5cbiAgZHN0YWNrLXZlcmlmaWVyOlxuICAgIGltYWdlOiBkc3RhY2t0ZWUvZHN0YWNrLXZlcmlmaWVyOjAuNS4xMUBzaGEyNTY6MDZhMjBiNzc3ZTU5MTk2YzdmNTRiMGNkMDJmZmU1NjdkZjZkMDVhZTM5YTBiMmZlYTljYjA2NDJmYjIzYzFmZFxuICAgIHJlc3RhcnQ6IHVubGVzcy1zdG9wcGVkXG4gICAgbG9nZ2luZzpcbiAgICAgIGRyaXZlcjoganNvbi1maWxlXG4gICAgICBvcHRpb25zOlxuICAgICAgICBtYXgtc2l6ZTogXCI1MG1cIlxuICAgICAgICBtYXgtZmlsZTogXCI1XCJcblxuICAjIEhvc3QtbWV0cmljcyBleHBvcnRlciBmb3Igb2JzZXJ2aW5nIHRoaXMgQ1ZNIChDUFUvbWVtL2Rpc2svbmV0L2ZkKS4gSW5zaWRlIGFcbiAgIyBDVk0gdGhlIGNvbnRhaW5lcidzIC8sIC9wcm9jLCAvc3lzIEFSRSB0aGUgZ3Vlc3Qncywgc28gbm9kZS1leHBvcnRlciByZXBvcnRzXG4gICMgdGhlIENWTSdzIG93biBzdGF0ZS4gUGlubmVkIGJ5IEBzaGEyNTYgbGlrZSB0aGUgb3RoZXIgaW1hZ2VzIChtZWFzdXJlZCBpbnRvXG4gICMgdGhlIGF0dGVzdGF0aW9uKS4gRXhwb3NlZCBvbiA5MTAwIChyZWFjaGVkIHZpYSB0aGUgZHN0YWNrIGdhdGV3YXkpIGFuZCBndWFyZGVkXG4gICMgYnkgSFRUUCBiYXNpYyBhdXRoIOKAlCBib3RoIHVzZXJuYW1lIGFuZCB0aGUgYmNyeXB0IHBhc3N3b3JkIEhBU0ggYXJlIGluamVjdGVkIGFzXG4gICMgZHN0YWNrIEVuY3J5cHRlZCBTZWNyZXRzLCBzbyBuZWl0aGVyIGFwcGVhcnMgaW4gdGhpcyBtZWFzdXJlZCBmaWxlLlxuICBub2RlLWV4cG9ydGVyOlxuICAgIGltYWdlOiBwcm9tL25vZGUtZXhwb3J0ZXI6djEuOC4yQHNoYTI1Njo0MDMyYzZkNWJmZDc1MjM0MmMzZTYzMWMyZjFkZTkzYmE2Yjg2YzQxZGI2YjE2N2I5YTM1MzcyYzEzOWU3NzA2XG4gICAgcmVzdGFydDogdW5sZXNzLXN0b3BwZWRcbiAgICBwaWQ6IGhvc3RcbiAgICBjb21tYW5kOlxuICAgICAgLSAnLS1wYXRoLnJvb3Rmcz0vaG9zdCdcbiAgICAgIC0gJy0tcGF0aC5wcm9jZnM9L2hvc3QvcHJvYydcbiAgICAgIC0gJy0tcGF0aC5zeXNmcz0vaG9zdC9zeXMnXG4gICAgICAtICctLXdlYi5jb25maWcuZmlsZT0vZXRjL25vZGUtZXhwb3J0ZXIvd2ViLWNvbmZpZy55bWwnXG4gICAgdm9sdW1lczpcbiAgICAgIC0gLzovaG9zdDpybyxyc2xhdmVcbiAgICBjb25maWdzOlxuICAgICAgLSBzb3VyY2U6IG5vZGUtZXhwb3J0ZXItd2ViLWNvbmZpZ1xuICAgICAgICB0YXJnZXQ6IC9ldGMvbm9kZS1leHBvcnRlci93ZWItY29uZmlnLnltbFxuICAgIHBvcnRzOlxuICAgICAgLSBcIjkxMDA6OTEwMFwiXG4gICAgbG9nZ2luZzpcbiAgICAgIGRyaXZlcjoganNvbi1maWxlXG4gICAgICBvcHRpb25zOlxuICAgICAgICBtYXgtc2l6ZTogXCIxMG1cIlxuICAgICAgICBtYXgtZmlsZTogXCIzXCJcblxudm9sdW1lczpcbiAgcGFsLWNhY2hlOlxuICBwYWwtc3RhdGU6XG4gIGNlcnQtZGF0YTogICAjIExldCdzIEVuY3J5cHQgY2VydHMva2V5cyBwZXJzaXN0ZWQgZm9yIGRzdGFjay1pbmdyZXNzXG4gIGV2aWRlbmNlczogICAjIGluZ3Jlc3MgYXR0ZXN0YXRpb24gZXZpZGVuY2UgKyBwZXItZG9tYWluIGxlYWYgY2VydHMsIHNoYXJlZCByZWFkLW9ubHkgd2l0aCB0aGUgZ2F0ZXdheVxuXG4jIElubGluZWQsIG1lYXN1cmVkIGludG8gdGhlIGF0dGVzdGF0aW9uLiBQdWJsaWMgcGlucyB1c2UgTElURVJBTCB2YWx1ZXMgc28gdGhlXG4jIGNvZGUgdmVyc2lvbiBpcyBib3VuZCBpbnRvIGNvbXBvc2VfaGFzaDsgb25seSBzZWNyZXRzIHVzZSAke1ZBUn0gKGluamVjdGVkIGJ5XG4jIGRzdGFjaywgbmV2ZXIgbWVhc3VyZWQpLlxuY29uZmlnczpcbiAgIyBTdGF0aWMgZ2F0ZXdheSBjb25maWcuIGBhZG1pbl90b2tlbmAgYW5kIHRoZSBjb250cm9sLXBsYW5lIGNyZWRlbnRpYWxzIGFyZSB0aGVcbiAgIyBvbmx5IHNlY3JldHMgaGVyZSDigJQgJHtWQVJ9IGtlZXBzIHRoZW0gb3V0IG9mIHRoZSBtZWFzdXJlZCBjb21wb3NlLiBUaGVcbiAgIyBgbWlkZGxld2FyZWAgc2VjdGlvbiBydW5zIHRoZSBpbi1wcm9jZXNzIG1pZGRsZXdhcmUsIHdoaWNoIGNvbnN1bHRzIHRoZSBjb250cm9sXG4gICMgcGxhbmUgYXQgYGNvbnRyb2xfdXJsYC5cbiAgZ2F0ZXdheS1jb25maWc6XG4gICAgY29udGVudDogfFxuICAgICAge1xuICAgICAgICBcImJpbmRcIjogXCIwLjAuMC4wOjgwODZcIixcbiAgICAgICAgXCJzdGF0ZV9kaXJcIjogXCIvdmFyL2xpYi9wYWcvc3RhdGVcIixcbiAgICAgICAgXCJ1cHN0cmVhbV9jb25maWdfc2VlZF9wYXRoXCI6IFwiL2V0Yy9wcml2YXRlLWFpLWdhdGV3YXkvdXBzdHJlYW1zLnNlZWQuanNvblwiLFxuICAgICAgICBcImFkbWluX3Rva2VuXCI6IFwiJHtQUklWQVRFX0FJX0dBVEVXQVlfQURNSU5fVE9LRU46P3NldCBQUklWQVRFX0FJX0dBVEVXQVlfQURNSU5fVE9LRU59XCIsXG4gICAgICAgIFwidGxzXCI6IHtcbiAgICAgICAgICBcImRvbWFpbl9jZXJ0aWZpY2F0ZXNcIjogW1xuICAgICAgICAgICAgeyBcImRvbWFpblwiOiBcInRlZS5yZWRwaWxsLmFpXCIsIFwiY2VydGlmaWNhdGVfcGF0aFwiOiBcIi9ldmlkZW5jZXMvY2VydC10ZWUucmVkcGlsbC5haS5wZW1cIiB9LFxuICAgICAgICAgICAgeyBcImRvbWFpblwiOiBcImluZmVyZW5jZS5waGFsYS5jb21cIiwgXCJjZXJ0aWZpY2F0ZV9wYXRoXCI6IFwiL2V2aWRlbmNlcy9jZXJ0LWluZmVyZW5jZS5waGFsYS5jb20ucGVtXCIgfSxcbiAgICAgICAgICAgIHsgXCJkb21haW5cIjogXCJhcGkucmVkcGlsbC5haVwiLCBcImNlcnRpZmljYXRlX3BhdGhcIjogXCIvZXZpZGVuY2VzL2NlcnQtYXBpLnJlZHBpbGwuYWkucGVtXCIgfVxuICAgICAgICAgIF1cbiAgICAgICAgfSxcbiAgICAgICAgXCJtaWRkbGV3YXJlXCI6IHtcbiAgICAgICAgICBcImNvbnRyb2xfdXJsXCI6IFwiJHtQUklWQVRFX0FJX0dBVEVXQVlfQ09OVFJPTF9VUkw6P3NldCBQUklWQVRFX0FJX0dBVEVXQVlfQ09OVFJPTF9VUkx9XCIsXG4gICAgICAgICAgXCJjb250cm9sX3Rva2VuXCI6IFwiJHtQUklWQVRFX0FJX0dBVEVXQVlfQ09OVFJPTF9UT0tFTjo/c2V0IFBSSVZBVEVfQUlfR0FURVdBWV9DT05UUk9MX1RPS0VOfVwiLFxuICAgICAgICAgIFwidGVlX29ubHlfZG9tYWluc1wiOiBbXCJ0ZWUucmVkcGlsbC5haVwiLCBcImluZmVyZW5jZS5waGFsYS5jb21cIl1cbiAgICAgICAgfVxuICAgICAgfVxuICAjIEluaXRpYWwgdXBzdHJlYW0gcm91dGVzOiBzZWVkZWQgaW50byA8c3RhdGVfZGlyPi91cHN0cmVhbXMuanNvbiBvbmx5IHdoZW4gZW1wdHksXG4gICMgdGhlbiBtYW5hZ2VkIGF0IHJ1bnRpbWUgdmlhIFBVVCAvdjEvYWRtaW4vdXBzdHJlYW1zIChkb2VzIG5vdCB0b3VjaCB0aGlzIGZpbGUpLlxuICBnYXRld2F5LXVwc3RyZWFtczpcbiAgICBjb250ZW50OiB8XG4gICAgICBbXVxuICAjIG5vZGUtZXhwb3J0ZXIgYmFzaWMtYXV0aCBjcmVkZW50aWFscy4gZXhwb3J0ZXItdG9vbGtpdCdzIGJhc2ljX2F1dGhfdXNlcnMgbWFwc1xuICAjIHVzZXJuYW1lIC0+IGJjcnlwdCBoYXNoOyBib3RoIGFyZSAke1ZBUn0gc28gZHN0YWNrIHN1YnN0aXR1dGVzIHRoZSBpbmplY3RlZFxuICAjIHNlY3JldCB2YWx1ZXMgd2hlbiByZW5kZXJpbmcgdGhpcyBmaWxlIGludG8gdGhlIGNvbnRhaW5lciDigJQgb25seSB0aGUgbGl0ZXJhbHNcbiAgIyBhcmUgbWVhc3VyZWQuIE5PREVfRVhQT1JURVJfUEFTU1dPUkRfSEFTSCBtdXN0IGJlIGEgYmNyeXB0IGhhc2hcbiAgIyAoYGh0cGFzc3dkIC1uQkMgMTAgXCJcIiB8IHRyIC1kICc6XFxuJ2ApLCBOT1QgdGhlIHBsYWludGV4dCBwYXNzd29yZDsgdGhlIHBsYWludGV4dFxuICAjIGdvZXMgdG8gdGhlIGV4dGVybmFsIFByb21ldGhldXMgc2NyYXBlIGNvbmZpZy5cbiAgbm9kZS1leHBvcnRlci13ZWItY29uZmlnOlxuICAgIGNvbnRlbnQ6IHxcbiAgICAgIGJhc2ljX2F1dGhfdXNlcnM6XG4gICAgICAgICR7Tk9ERV9FWFBPUlRFUl9VU0VSOj9zZXQgTk9ERV9FWFBPUlRFUl9VU0VSfTogJHtOT0RFX0VYUE9SVEVSX1BBU1NXT1JEX0hBU0g6P3NldCBOT0RFX0VYUE9SVEVSX1BBU1NXT1JEX0hBU0h9XG4iLCJmZWF0dXJlcyI6WyJrbXMiLCJ0cHJveHktbmV0Il0sImdhdGV3YXlfZW5hYmxlZCI6dHJ1ZSwia21zX2VuYWJsZWQiOnRydWUsImxvY2FsX2tleV9wcm92aWRlcl9lbmFibGVkIjpmYWxzZSwibWFuaWZlc3RfdmVyc2lvbiI6MiwibmFtZSI6IiIsIm5vX2luc3RhbmNlX2lkIjpmYWxzZSwicHJlX2xhdW5jaF9zY3JpcHQiOiIjIS9iaW4vYmFzaFxuZWNobyBcIi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cIlxuZWNobyBcIlJ1bm5pbmcgUGhhbGEgQ2xvdWQgUHJlLUxhdW5jaCBTY3JpcHQgdjAuMC4xNVwiXG5lY2hvIFwiLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVwiXG5zZXQgLWVcblxuIyBGdW5jdGlvbjogbm90aWZ5IGhvc3Rcblxubm90aWZ5X2hvc3QoKSB7XG4gICAgaWYgY29tbWFuZCAtdiBkc3RhY2stdXRpbCA+L2Rldi9udWxsIDI+JjE7IHRoZW5cbiAgICAgICAgZHN0YWNrLXV0aWwgbm90aWZ5LWhvc3QgLWUgXCIkMVwiIC1kIFwiJDJcIlxuICAgIGVsc2VcbiAgICAgICAgdGR4Y3RsIG5vdGlmeS1ob3N0IC1lIFwiJDFcIiAtZCBcIiQyXCJcbiAgICBmaVxufVxuXG5ub3RpZnlfaG9zdF9ob290X2luZm8oKSB7XG4gICAgbm90aWZ5X2hvc3QgXCJib290LnByb2dyZXNzXCIgXCIkMVwiXG59XG5cbm5vdGlmeV9ob3N0X2hvb3RfZXJyb3IoKSB7XG4gICAgbm90aWZ5X2hvc3QgXCJib290LmVycm9yXCIgXCIkMVwiXG59XG5cbiMgRnVuY3Rpb246IFBlcmZvcm0gRG9ja2VyIGNsZWFudXBcbnBlcmZvcm1fY2xlYW51cCgpIHtcbiAgICBlY2hvIFwiUHJ1bmluZyB1bnVzZWQgaW1hZ2VzXCJcbiAgICBkb2NrZXIgaW1hZ2UgcHJ1bmUgLWFmXG4gICAgZWNobyBcIlBydW5pbmcgdW51c2VkIHZvbHVtZXNcIlxuICAgIGRvY2tlciB2b2x1bWUgcHJ1bmUgLWZcbiAgICBub3RpZnlfaG9zdF9ob290X2luZm8gXCJkb2NrZXIgY2xlYW51cCBjb21wbGV0ZWRcIlxufVxuXG4jIEZ1bmN0aW9uOiBDaGVjayBEb2NrZXIgbG9naW4gc3RhdHVzIHdpdGhvdXQgZXhwb3NpbmcgY3JlZGVudGlhbHNcbmNoZWNrX2RvY2tlcl9sb2dpbigpIHtcbiAgICBsb2NhbCByZWdpc3RyeT1cIiQxXCJcblxuICAgICMgV2hlbiByZWdpc3RyeSBpcyBzcGVjaWZpZWQsIGNoZWNrIGF1dGggZW50cnkgZm9yIHRoYXQgcmVnaXN0cnkgaW4gRG9ja2VyIGNvbmZpZ1xuICAgIGlmIFtbIC1uIFwiJHJlZ2lzdHJ5XCIgXV07IHRoZW5cbiAgICAgICAgbG9jYWwgZG9ja2VyX2NvbmZpZ19wYXRoPVwiJHtET0NLRVJfQ09ORklHOi0kSE9NRS8uZG9ja2VyfS9jb25maWcuanNvblwiXG4gICAgICAgIGlmIFtbIC1mIFwiJGRvY2tlcl9jb25maWdfcGF0aFwiIF1dICYmIGdyZXAgLXEgXCIkcmVnaXN0cnlcIiBcIiRkb2NrZXJfY29uZmlnX3BhdGhcIjsgdGhlblxuICAgICAgICAgICAgcmV0dXJuIDBcbiAgICAgICAgZWxzZVxuICAgICAgICAgICAgcmV0dXJuIDFcbiAgICAgICAgZmlcbiAgICBmaVxuXG4gICAgIyBGYWxsYmFjayBjaGVjayB3aGVuIG5vIGV4cGxpY2l0IHJlZ2lzdHJ5IGlzIHByb3ZpZGVkXG4gICAgaWYgZG9ja2VyIGluZm8gMj4vZGV2L251bGwgfCBncmVwIC1xIFwiVXNlcm5hbWVcIjsgdGhlblxuICAgICAgICByZXR1cm4gMFxuICAgIGVsc2VcbiAgICAgICAgcmV0dXJuIDFcbiAgICBmaVxufVxuXG4jIE1haW4gbG9naWMgc3RhcnRzIGhlcmVcbmVjaG8gXCJTdGFydGluZyBsb2dpbiBwcm9jZXNzLi4uXCJcblxuIyBDaGVjayBpZiBEb2NrZXIgY3JlZGVudGlhbHMgZXhpc3RcbmlmIFtbIC1uIFwiJERTVEFDS19ET0NLRVJfVVNFUk5BTUVcIiAmJiAtbiBcIiREU1RBQ0tfRE9DS0VSX1BBU1NXT1JEXCIgXV07IHRoZW5cbiAgICBlY2hvIFwiRG9ja2VyIGNyZWRlbnRpYWxzIGZvdW5kXCJcbiAgICBET0NLRVJfUkVHSVNUUllfVEFSR0VUPVwiJHtEU1RBQ0tfRE9DS0VSX1JFR0lTVFJZOi1kb2NrZXIuaW99XCJcbiAgICBlY2hvIFwiVGFyZ2V0IERvY2tlciByZWdpc3RyeTogJERPQ0tFUl9SRUdJU1RSWV9UQVJHRVRcIlxuXG4gICAgIyBDaGVjayBpZiBhbHJlYWR5IGxvZ2dlZCBpblxuICAgIGlmIGNoZWNrX2RvY2tlcl9sb2dpbiBcIiREU1RBQ0tfRE9DS0VSX1JFR0lTVFJZXCI7IHRoZW5cbiAgICAgICAgZWNobyBcIkFscmVhZHkgbG9nZ2VkIGluIHRvIERvY2tlciByZWdpc3RyeTogJERPQ0tFUl9SRUdJU1RSWV9UQVJHRVRcIlxuICAgIGVsc2VcbiAgICAgICAgZWNobyBcIkxvZ2dpbmcgaW4gdG8gRG9ja2VyIHJlZ2lzdHJ5OiAkRE9DS0VSX1JFR0lTVFJZX1RBUkdFVFwiXG4gICAgICAgICMgTG9naW4gd2l0aG91dCBleHBvc2luZyBwYXNzd29yZCBpbiBwcm9jZXNzIGxpc3RcbiAgICAgICAgaWYgW1sgLW4gXCIkRFNUQUNLX0RPQ0tFUl9SRUdJU1RSWVwiIF1dOyB0aGVuXG4gICAgICAgICAgICBlY2hvIFwiJERTVEFDS19ET0NLRVJfUEFTU1dPUkRcIiB8IGRvY2tlciBsb2dpbiAtdSBcIiREU1RBQ0tfRE9DS0VSX1VTRVJOQU1FXCIgLS1wYXNzd29yZC1zdGRpbiBcIiREU1RBQ0tfRE9DS0VSX1JFR0lTVFJZXCJcbiAgICAgICAgZWxzZVxuICAgICAgICAgICAgZWNobyBcIiREU1RBQ0tfRE9DS0VSX1BBU1NXT1JEXCIgfCBkb2NrZXIgbG9naW4gLXUgXCIkRFNUQUNLX0RPQ0tFUl9VU0VSTkFNRVwiIC0tcGFzc3dvcmQtc3RkaW5cbiAgICAgICAgZmlcblxuICAgICAgICBpZiBbICQ/IC1lcSAwIF07IHRoZW5cbiAgICAgICAgICAgIGVjaG8gXCJEb2NrZXIgbG9naW4gc3VjY2Vzc2Z1bDogJERPQ0tFUl9SRUdJU1RSWV9UQVJHRVRcIlxuICAgICAgICBlbHNlXG4gICAgICAgICAgICBlY2hvIFwiRG9ja2VyIGxvZ2luIGZhaWxlZDogJERPQ0tFUl9SRUdJU1RSWV9UQVJHRVRcIlxuICAgICAgICAgICAgbm90aWZ5X2hvc3RfaG9vdF9lcnJvciBcImRvY2tlciBsb2dpbiBmYWlsZWRcIlxuICAgICAgICAgICAgZXhpdCAxXG4gICAgICAgIGZpXG4gICAgZmlcbiMgQ2hlY2sgaWYgQVdTIEVDUiBjcmVkZW50aWFscyBleGlzdFxuZWxpZiBbWyAtbiBcIiREU1RBQ0tfQVdTX0FDQ0VTU19LRVlfSURcIiAmJiAtbiBcIiREU1RBQ0tfQVdTX1NFQ1JFVF9BQ0NFU1NfS0VZXCIgJiYgLW4gXCIkRFNUQUNLX0FXU19SRUdJT05cIiAmJiAtbiBcIiREU1RBQ0tfQVdTX0VDUl9SRUdJU1RSWVwiIF1dOyB0aGVuXG4gICAgZWNobyBcIkFXUyBFQ1IgY3JlZGVudGlhbHMgZm91bmRcIlxuXG4gICAgIyBDaGVjayBpZiBBV1MgQ0xJIGlzIGluc3RhbGxlZFxuICAgIGlmIFsgISAtZiBcIi4vYXdzL2Rpc3QvYXdzXCIgXTsgdGhlblxuICAgICAgICBub3RpZnlfaG9zdF9ob290X2luZm8gXCJhd3NjbGkgbm90IGluc3RhbGxlZCwgaW5zdGFsbGluZy4uLlwiXG4gICAgICAgIGVjaG8gXCJBV1MgQ0xJIG5vdCBpbnN0YWxsZWQsIGluc3RhbGxpbmcuLi5cIlxuICAgICAgICBjdXJsIFwiaHR0cHM6Ly9hd3NjbGkuYW1hem9uYXdzLmNvbS9hd3NjbGktZXhlLWxpbnV4LXg4Nl82NC0yLjI0LjE0LnppcFwiIC1vIFwiYXdzY2xpdjIuemlwXCJcbiAgICAgICAgZWNobyBcIjZmZjAzMWEyNmRmN2RhZWJiZmEzY2NkZGM5YWYxNDUwIGF3c2NsaXYyLnppcFwiIHwgbWQ1c3VtIC1jXG4gICAgICAgIGlmIFsgJD8gLW5lIDAgXTsgdGhlblxuICAgICAgICAgICAgZWNobyBcIk1ENSBjaGVja3N1bSBmYWlsZWRcIlxuICAgICAgICAgICAgbm90aWZ5X2hvc3RfaG9vdF9lcnJvciBcImF3c2NsaSBpbnN0YWxsIGZhaWxlZFwiXG4gICAgICAgICAgICBleGl0IDFcbiAgICAgICAgZmlcbiAgICAgICAgdW56aXAgYXdzY2xpdjIuemlwICY+IC9kZXYvbnVsbFxuICAgIGVsc2VcbiAgICAgICAgZWNobyBcIkFXUyBDTEkgaXMgYWxyZWFkeSBpbnN0YWxsZWQ6IC4vYXdzL2Rpc3QvYXdzXCJcbiAgICBmaVxuXG4gICAgIyBTZXQgQVdTIGNyZWRlbnRpYWxzIGFzIGVudmlyb25tZW50IHZhcmlhYmxlc1xuICAgIGV4cG9ydCBBV1NfQUNDRVNTX0tFWV9JRD1cIiREU1RBQ0tfQVdTX0FDQ0VTU19LRVlfSURcIlxuICAgIGV4cG9ydCBBV1NfU0VDUkVUX0FDQ0VTU19LRVk9XCIkRFNUQUNLX0FXU19TRUNSRVRfQUNDRVNTX0tFWVwiXG4gICAgZXhwb3J0IEFXU19ERUZBVUxUX1JFR0lPTj1cIiREU1RBQ0tfQVdTX1JFR0lPTlwiXG5cbiAgICAjIFNldCBzZXNzaW9uIHRva2VuIGlmIHByb3ZpZGVkIChmb3IgdGVtcG9yYXJ5IGNyZWRlbnRpYWxzKVxuICAgIGlmIFtbIC1uIFwiJERTVEFDS19BV1NfU0VTU0lPTl9UT0tFTlwiIF1dOyB0aGVuXG4gICAgICAgIGVjaG8gXCJBV1Mgc2Vzc2lvbiB0b2tlbiBmb3VuZCwgdXNpbmcgdGVtcG9yYXJ5IGNyZWRlbnRpYWxzXCJcbiAgICAgICAgZXhwb3J0IEFXU19TRVNTSU9OX1RPS0VOPVwiJERTVEFDS19BV1NfU0VTU0lPTl9UT0tFTlwiXG4gICAgZmlcblxuICAgICMgVGVzdCBBV1MgY3JlZGVudGlhbHMgYmVmb3JlIGF0dGVtcHRpbmcgRUNSIGxvZ2luXG4gICAgZWNobyBcIlRlc3RpbmcgQVdTIGNyZWRlbnRpYWxzLi4uXCJcbiAgICBpZiAhIC4vYXdzL2Rpc3QvYXdzIHN0cyBnZXQtY2FsbGVyLWlkZW50aXR5ICY+IC9kZXYvbnVsbDsgdGhlblxuICAgICAgICBlY2hvIFwiQVdTIGNyZWRlbnRpYWxzIHRlc3QgZmFpbGVkXCJcbiAgICAgICAgIyBGb3Igc2Vzc2lvbiB0b2tlbiBjcmVkZW50aWFscywgdGhpcyBtaWdodCBiZSBleHBlY3RlZCBpZiB0aGV5J3JlIGV4cGlyZWRcbiAgICAgICAgIyBMb2cgd2FybmluZyBidXQgZG9uJ3QgZmFpbCBzdGFydHVwXG4gICAgICAgIGlmIFtbIC1uIFwiJERTVEFDS19BV1NfU0VTU0lPTl9UT0tFTlwiIF1dOyB0aGVuXG4gICAgICAgICAgICBlY2hvIFwiV2FybmluZzogQVdTIHRlbXBvcmFyeSBjcmVkZW50aWFscyBtYXkgaGF2ZSBleHBpcmVkLCBjb250aW51aW5nIHN0YXJ0dXBcIlxuICAgICAgICAgICAgbm90aWZ5X2hvc3RfaG9vdF9pbmZvIFwiQVdTIHRlbXBvcmFyeSBjcmVkZW50aWFscyBtYXkgaGF2ZSBleHBpcmVkXCJcbiAgICAgICAgZWxzZVxuICAgICAgICAgICAgZWNobyBcIkFXUyBjcmVkZW50aWFscyB0ZXN0IGZhaWxlZFwiXG4gICAgICAgICAgICBub3RpZnlfaG9zdF9ob290X2Vycm9yIFwiSW52YWxpZCBBV1MgY3JlZGVudGlhbHNcIlxuICAgICAgICAgICAgZXhpdCAxXG4gICAgICAgIGZpXG4gICAgZWxzZVxuICAgICAgICBlY2hvIFwiTG9nZ2luZyBpbiB0byBBV1MgRUNSLi4uXCJcbiAgICAgICAgLi9hd3MvZGlzdC9hd3MgZWNyIGdldC1sb2dpbi1wYXNzd29yZCAtLXJlZ2lvbiAkRFNUQUNLX0FXU19SRUdJT04gfCBkb2NrZXIgbG9naW4gLS11c2VybmFtZSBBV1MgLS1wYXNzd29yZC1zdGRpbiBcIiREU1RBQ0tfQVdTX0VDUl9SRUdJU1RSWVwiXG4gICAgICAgIGlmIFsgJD8gLWVxIDAgXTsgdGhlblxuICAgICAgICAgICAgZWNobyBcIkFXUyBFQ1IgbG9naW4gc3VjY2Vzc2Z1bFwiXG4gICAgICAgICAgICBub3RpZnlfaG9zdF9ob290X2luZm8gXCJBV1MgRUNSIGxvZ2luIHN1Y2Nlc3NmdWxcIlxuICAgICAgICBlbHNlXG4gICAgICAgICAgICBlY2hvIFwiQVdTIEVDUiBsb2dpbiBmYWlsZWRcIlxuICAgICAgICAgICAgIyBGb3Igc2Vzc2lvbiB0b2tlbiBjcmVkZW50aWFscywgZG9uJ3QgZmFpbCBzdGFydHVwIGlmIGxvZ2luIGZhaWxzXG4gICAgICAgICAgICBpZiBbWyAtbiBcIiREU1RBQ0tfQVdTX1NFU1NJT05fVE9LRU5cIiBdXTsgdGhlblxuICAgICAgICAgICAgICAgIGVjaG8gXCJXYXJuaW5nOiBBV1MgRUNSIGxvZ2luIGZhaWxlZCB3aXRoIHRlbXBvcmFyeSBjcmVkZW50aWFscywgY29udGludWluZyBzdGFydHVwXCJcbiAgICAgICAgICAgICAgICBub3RpZnlfaG9zdF9ob290X2luZm8gXCJBV1MgRUNSIGxvZ2luIGZhaWxlZCB3aXRoIHRlbXBvcmFyeSBjcmVkZW50aWFsc1wiXG4gICAgICAgICAgICBlbHNlXG4gICAgICAgICAgICAgICAgbm90aWZ5X2hvc3RfaG9vdF9lcnJvciBcIkFXUyBFQ1IgbG9naW4gZmFpbGVkXCJcbiAgICAgICAgICAgICAgICBleGl0IDFcbiAgICAgICAgICAgIGZpXG4gICAgICAgIGZpXG4gICAgZmlcbmZpXG5cbnBlcmZvcm1fY2xlYW51cFxuXG4jXG4jIEdIQ1IgaW1hZ2UgcHVsbCBhY2Nlc3MgdmVyaWZpY2F0aW9uIChwdXJlIEhUVFAsIG5vIGRvY2tlciBkYWVtb24pXG4jXG5pZiBbWyBcIiRET0NLRVJfUkVHSVNUUllfVEFSR0VUXCIgPT0gXCJnaGNyLmlvXCIgJiYgLW4gXCIkRFNUQUNLX0RPQ0tFUl9VU0VSTkFNRVwiICYmIC1uIFwiJERTVEFDS19ET0NLRVJfUEFTU1dPUkRcIiBdXTsgdGhlblxuICAgIENPTVBPU0VfSU1BR0VTPSQoZ3JlcCAnaW1hZ2U6JyAvZHN0YWNrL2RvY2tlci1jb21wb3NlLnlhbWwgMj4vZGV2L251bGwgfCBhd2sgJ3twcmludCAkMn0nIHwgdHIgLWQgJ1wiJ1wiJ1wiIHx8IHRydWUpXG4gICAgZm9yIGltZyBpbiAkQ09NUE9TRV9JTUFHRVM7IGRvXG4gICAgICAgIFtbIFwiJGltZ1wiICE9IGdoY3IuaW8vKiBdXSAmJiBjb250aW51ZVxuICAgICAgICByZXBvPVwiJHtpbWcjZ2hjci5pby99XCI7IHJlcG89XCIke3JlcG8lJToqfVwiXG4gICAgICAgIHRhZz1cIiR7aW1nIyMqOn1cIjsgW1sgXCIkdGFnXCIgPT0gXCIkaW1nXCIgfHwgXCIkdGFnXCIgPT0gXCIkcmVwb1wiIF1dICYmIHRhZz1cImxhdGVzdFwiXG4gICAgICAgIGVjaG8gXCJWZXJpZnlpbmcgR0hDUiBwdWxsIGFjY2VzczogJGltZ1wiXG4gICAgICAgIHRva2VuPSQoY3VybCAtc2YgLXUgXCIkRFNUQUNLX0RPQ0tFUl9VU0VSTkFNRTokRFNUQUNLX0RPQ0tFUl9QQVNTV09SRFwiICAgICAgICAgICAgIFwiaHR0cHM6Ly9naGNyLmlvL3Rva2VuP3NlcnZpY2U9Z2hjci5pbyZzY29wZT1yZXBvc2l0b3J5OiR7cmVwb306cHVsbFwiIHwganEgLXIgJy50b2tlbiAvLyBlbXB0eScgfHwgdHJ1ZSlcbiAgICAgICAgaWYgW1sgLXogXCIkdG9rZW5cIiBdXTsgdGhlblxuICAgICAgICAgICAgZWNobyBcIkVSUk9SOiBHSENSIHRva2VuIGV4Y2hhbmdlIGZhaWxlZCBmb3IgJGltZ1wiXG4gICAgICAgICAgICBub3RpZnlfaG9zdF9ob290X2Vycm9yIFwiR0hDUiB0b2tlbiBleGNoYW5nZSBmYWlsZWQ6ICRpbWdcIlxuICAgICAgICAgICAgZXhpdCAxXG4gICAgICAgIGZpXG4gICAgICAgIGh0dHBfY29kZT0kKGN1cmwgLXMgLW8gL2Rldi9udWxsIC13IFwiJXtodHRwX2NvZGV9XCIgLUggXCJBdXRob3JpemF0aW9uOiBCZWFyZXIgJHRva2VuXCIgICAgICAgICAgICAgLUggXCJBY2NlcHQ6IGFwcGxpY2F0aW9uL3ZuZC5vY2kuaW1hZ2UuaW5kZXgudjEranNvbixhcHBsaWNhdGlvbi92bmQub2NpLmltYWdlLm1hbmlmZXN0LnYxK2pzb24sYXBwbGljYXRpb24vdm5kLmRvY2tlci5kaXN0cmlidXRpb24ubWFuaWZlc3QubGlzdC52Mitqc29uLGFwcGxpY2F0aW9uL3ZuZC5kb2NrZXIuZGlzdHJpYnV0aW9uLm1hbmlmZXN0LnYyK2pzb25cIiAgICAgICAgICAgICBcImh0dHBzOi8vZ2hjci5pby92Mi8ke3JlcG99L21hbmlmZXN0cy8ke3RhZ31cIilcbiAgICAgICAgaWYgW1sgXCIkaHR0cF9jb2RlXCIgIT0gXCIyMDBcIiBdXTsgdGhlblxuICAgICAgICAgICAgZWNobyBcIkVSUk9SOiBHSENSIHB1bGwgYWNjZXNzIGRlbmllZCBmb3IgJGltZyAoSFRUUCAkaHR0cF9jb2RlKVwiXG4gICAgICAgICAgICBub3RpZnlfaG9zdF9ob290X2Vycm9yIFwiR0hDUiBwdWxsIGFjY2VzcyBkZW5pZWQ6ICRpbWcgKEhUVFAgJGh0dHBfY29kZSlcIlxuICAgICAgICAgICAgZXhpdCAxXG4gICAgICAgIGZpXG4gICAgICAgIGVjaG8gXCJHSENSIHB1bGwgYWNjZXNzIE9LOiAkaW1nXCJcbiAgICBkb25lXG5maVxuXG4jXG4jIFB1bGwgbGF0ZXN0IGltYWdlcyBmcm9tIGRvY2tlci1jb21wb3NlLnlhbWwgc28gZXhpc3RpbmcgQ1ZNcyBwaWNrIHVwIG5ldyB0YWdzLlxuIyBQdWxsIGlzIGZhaWwtc29mdDogc2hvcnQtbGl2ZWQgdG9rZW5zIG1heSBleHBpcmUgYmV0d2VlbiBsb2dpbiBhbmQgcHVsbCwgYnV0XG4jIGZhbGxpbmcgYmFjayB0byBhbHJlYWR5LWNhY2hlZCBpbWFnZXMgaXMgcHJlZmVyYWJsZSB0byBibG9ja2luZyBib290LlxuI1xuZWNobyBcIkltYWdlcyBiZWZvcmUgcHVsbDpcIlxuZG9ja2VyIGltYWdlcyAtLWZvcm1hdCAne3suUmVwb3NpdG9yeX19Ont7LlRhZ319IHt7LklEfX0gKHt7LkNyZWF0ZWRTaW5jZX19KSdcblxuZWNobyBcIlB1bGxpbmcgbGF0ZXN0IGltYWdlcyBmcm9tIC9kc3RhY2svZG9ja2VyLWNvbXBvc2UueWFtbC4uLlwiXG5pZiBkb2NrZXIgY29tcG9zZSAtZiAvZHN0YWNrL2RvY2tlci1jb21wb3NlLnlhbWwgcHVsbDsgdGhlblxuICAgIGVjaG8gXCJkb2NrZXIgY29tcG9zZSBwdWxsIGNvbXBsZXRlZFwiXG4gICAgbm90aWZ5X2hvc3RfaG9vdF9pbmZvIFwiZG9ja2VyIGNvbXBvc2UgcHVsbCBjb21wbGV0ZWRcIlxuZWxzZVxuICAgIGVjaG8gXCJXQVJOSU5HOiBkb2NrZXIgY29tcG9zZSBwdWxsIGZhaWxlZDsgY29udGludWluZyB3aXRoIGV4aXN0aW5nIGltYWdlc1wiXG4gICAgbm90aWZ5X2hvc3RfaG9vdF9pbmZvIFwiZG9ja2VyIGNvbXBvc2UgcHVsbCBmYWlsZWQ7IHVzaW5nIGV4aXN0aW5nIGltYWdlc1wiXG5maVxuXG5lY2hvIFwiSW1hZ2VzIGFmdGVyIHB1bGw6XCJcbmRvY2tlciBpbWFnZXMgLS1mb3JtYXQgJ3t7LlJlcG9zaXRvcnl9fTp7ey5UYWd9fSB7ey5JRH19ICh7ey5DcmVhdGVkU2luY2V9fSknXG5cbiNcbiMgU2V0IHJvb3QgcGFzc3dvcmQuXG4jXG5lY2hvIFwiU2V0dGluZyByb290IHBhc3N3b3JkLi5cIlxuXG4jIENoZWNrIGlmIHBhc3N3b3JkIGZpbGVzIGFyZSB3cml0YWJsZVxuUEFTU1dEX1dSSVRBQkxFPXRydWVcbmlmIFsgISAtdyAvZXRjL3Bhc3N3ZCBdOyB0aGVuXG4gICAgZWNobyBcIldhcm5pbmc6IC9ldGMvcGFzc3dkIGlzIHJlYWQtb25seVwiXG4gICAgUEFTU1dEX1dSSVRBQkxFPWZhbHNlXG5maVxuaWYgWyAhIC13IC9ldGMvc2hhZG93IF07IHRoZW5cbiAgICBlY2hvIFwiV2FybmluZzogL2V0Yy9zaGFkb3cgaXMgcmVhZC1vbmx5XCJcbiAgICBQQVNTV0RfV1JJVEFCTEU9ZmFsc2VcbmZpXG5cbmlmIFsgXCIkUEFTU1dEX1dSSVRBQkxFXCIgPSBcImZhbHNlXCIgXTsgdGhlblxuICAgIGVjaG8gXCJTa2lwcGluZyBwYXNzd29yZCBzZXR1cCBkdWUgdG8gcmVhZC1vbmx5IGZpbGUgc3lzdGVtXCJcbmVsc2VcbiAgICAjIENoZWNrIGlmIGNocGFzc3dkIGlzIGF2YWlsYWJsZVxuICAgIGlmIGNvbW1hbmQgLXYgY2hwYXNzd2QgPi9kZXYvbnVsbCAyPiYxOyB0aGVuXG4gICAgICAgIGVjaG8gXCJVc2luZyBjaHBhc3N3ZCBtZXRob2RcIlxuXG4gICAgICAgIGlmIFsgLW4gXCIkRFNUQUNLX1JPT1RfUEFTU1dPUkRcIiBdOyB0aGVuXG4gICAgICAgICAgICBlY2hvIFwiU2V0dGluZyByb290IHBhc3N3b3JkIGZyb20gdXNlci4uXCJcbiAgICAgICAgICAgIGVjaG8gXCJyb290OiREU1RBQ0tfUk9PVF9QQVNTV09SRFwiIHwgY2hwYXNzd2RcbiAgICAgICAgICAgIHVuc2V0IERTVEFDS19ST09UX1BBU1NXT1JEXG4gICAgICAgICAgICBlY2hvIFwiUm9vdCBwYXNzd29yZCBzZXQvdXBkYXRlZCBmcm9tIERTVEFDS19ST09UX1BBU1NXT1JEXCJcbiAgICAgICAgZWxpZiBbIC16IFwiJChncmVwICdecm9vdDonIC9ldGMvc2hhZG93IDI+L2Rldi9udWxsIHwgY3V0IC1kOiAtZjIpXCIgXTsgdGhlblxuICAgICAgICAgICAgZWNobyBcIlNldHRpbmcgcmFuZG9tIHJvb3QgcGFzc3dvcmQuLlwiXG4gICAgICAgICAgICBEU1RBQ0tfUk9PVF9QQVNTV09SRD0kKFxuICAgICAgICAgICAgICAgIExDX0FMTD1DIHRyIC1kYyAnQS1aYS16MC05JyA8IC9kZXYvdXJhbmRvbSB8IGRkIGJzPTEgY291bnQ9MzIgMj4vZGV2L251bGxcbiAgICAgICAgICAgIClcbiAgICAgICAgICAgIGVjaG8gXCJyb290OiREU1RBQ0tfUk9PVF9QQVNTV09SRFwiIHwgY2hwYXNzd2RcbiAgICAgICAgICAgIHVuc2V0IERTVEFDS19ST09UX1BBU1NXT1JEXG4gICAgICAgICAgICBlY2hvIFwiUm9vdCBwYXNzd29yZCBzZXQgKHJhbmRvbSBhdXRvLWluaXQpXCJcbiAgICAgICAgZWxzZVxuICAgICAgICAgICAgZWNobyBcIlJvb3QgcGFzc3dvcmQgYWxyZWFkeSBzZXQ7IG5vIGNoYW5nZXMuXCJcbiAgICAgICAgZmlcbiAgICBlbHNlXG4gICAgICAgIGVjaG8gXCJVc2luZyBwYXNzd2QgbWV0aG9kXCJcblxuICAgICAgICBpZiBbIC1uIFwiJERTVEFDS19ST09UX1BBU1NXT1JEXCIgXTsgdGhlblxuICAgICAgICAgICAgZWNobyBcIlNldHRpbmcgcm9vdCBwYXNzd29yZCBmcm9tIHVzZXIuLlwiXG4gICAgICAgICAgICBlY2hvIFwiJERTVEFDS19ST09UX1BBU1NXT1JEXCIgfCBwYXNzd2QgLS1zdGRpbiByb290IDI+L2Rldi9udWxsICAgICAgICAgICAgICAgICB8fCBwcmludGYgJyVzXG4lc1xuJyBcIiREU1RBQ0tfUk9PVF9QQVNTV09SRFwiIFwiJERTVEFDS19ST09UX1BBU1NXT1JEXCIgfCBwYXNzd2Qgcm9vdFxuICAgICAgICAgICAgdW5zZXQgRFNUQUNLX1JPT1RfUEFTU1dPUkRcbiAgICAgICAgICAgIGVjaG8gXCJSb290IHBhc3N3b3JkIHNldC91cGRhdGVkIGZyb20gRFNUQUNLX1JPT1RfUEFTU1dPUkRcIlxuICAgICAgICBlbGlmIFsgLXogXCIkKGdyZXAgJ15yb290OicgL2V0Yy9zaGFkb3cgMj4vZGV2L251bGwgfCBjdXQgLWQ6IC1mMilcIiBdOyB0aGVuXG4gICAgICAgICAgICBlY2hvIFwiU2V0dGluZyByYW5kb20gcm9vdCBwYXNzd29yZC4uXCJcbiAgICAgICAgICAgIERTVEFDS19ST09UX1BBU1NXT1JEPSQoXG4gICAgICAgICAgICAgICAgTENfQUxMPUMgdHIgLWRjICdBLVphLXowLTknIDwgL2Rldi91cmFuZG9tIHwgZGQgYnM9MSBjb3VudD0zMiAyPi9kZXYvbnVsbFxuICAgICAgICAgICAgKVxuICAgICAgICAgICAgZWNobyBcIiREU1RBQ0tfUk9PVF9QQVNTV09SRFwiIHwgcGFzc3dkIC0tc3RkaW4gcm9vdCAyPi9kZXYvbnVsbCAgICAgICAgICAgICAgICAgfHwgcHJpbnRmICclc1xuJXNcbicgXCIkRFNUQUNLX1JPT1RfUEFTU1dPUkRcIiBcIiREU1RBQ0tfUk9PVF9QQVNTV09SRFwiIHwgcGFzc3dkIHJvb3RcbiAgICAgICAgICAgIHVuc2V0IERTVEFDS19ST09UX1BBU1NXT1JEXG4gICAgICAgICAgICBlY2hvIFwiUm9vdCBwYXNzd29yZCBzZXQgKHJhbmRvbSBhdXRvLWluaXQpXCJcbiAgICAgICAgZWxzZVxuICAgICAgICAgICAgZWNobyBcIlJvb3QgcGFzc3dvcmQgYWxyZWFkeSBzZXQ7IG5vIGNoYW5nZXMuXCJcbiAgICAgICAgZmlcbiAgICBmaVxuZmlcblxuI1xuIyBTZXQgU1NIIGF1dGhvcml6ZWQga2V5c1xuI1xuaWYgbWtkaXIgLXAgL2hvbWUvcm9vdC8uc3NoIDI+L2Rldi9udWxsOyB0aGVuXG4gICAgaWYgW1sgLW4gXCIkRFNUQUNLX1JPT1RfUFVCTElDX0tFWVwiIF1dOyB0aGVuXG4gICAgICAgIGVjaG8gXCIkRFNUQUNLX1JPT1RfUFVCTElDX0tFWVwiID4gL2hvbWUvcm9vdC8uc3NoL2F1dGhvcml6ZWRfa2V5c1xuICAgICAgICB1bnNldCAkRFNUQUNLX1JPT1RfUFVCTElDX0tFWVxuICAgICAgICBlY2hvIFwiUm9vdCBwdWJsaWMga2V5IHNldFwiXG4gICAgZmlcbiAgICBpZiBbWyAtbiBcIiREU1RBQ0tfQVVUSE9SSVpFRF9LRVlTXCIgXV07IHRoZW5cbiAgICAgICAgZWNobyBcIiREU1RBQ0tfQVVUSE9SSVpFRF9LRVlTXCIgPiAvaG9tZS9yb290Ly5zc2gvYXV0aG9yaXplZF9rZXlzXG4gICAgICAgIHVuc2V0ICREU1RBQ0tfQVVUSE9SSVpFRF9LRVlTXG4gICAgICAgIGVjaG8gXCJSb290IGF1dGhvcml6ZWRfa2V5cyBzZXRcIlxuICAgIGZpXG5cbiAgICBpZiBbWyAtZiAvZHN0YWNrL3VzZXJfY29uZmlnIF1dICYmIGpxIGVtcHR5IC9kc3RhY2svdXNlcl9jb25maWcgMj4vZGV2L251bGw7IHRoZW5cbiAgICAgICAgaWYgW1sgJChqcSAnaGFzKFwic3NoX2F1dGhvcml6ZWRfa2V5c1wiKScgL2RzdGFjay91c2VyX2NvbmZpZyAyPi9kZXYvbnVsbCkgPT0gXCJ0cnVlXCIgXV07IHRoZW5cbiAgICAgICAgICAgIGpxIC1qICcuc3NoX2F1dGhvcml6ZWRfa2V5cycgL2RzdGFjay91c2VyX2NvbmZpZyA+PiAvaG9tZS9yb290Ly5zc2gvYXV0aG9yaXplZF9rZXlzXG4gICAgICAgICAgICAjIFJlbW92ZSBkdXBsaWNhdGVzIGlmIHRoZXJlIGFyZSBtdWx0aXBsZSBrZXlzXG4gICAgICAgICAgICBpZiBbWyAkKGNhdCAvaG9tZS9yb290Ly5zc2gvYXV0aG9yaXplZF9rZXlzIHwgd2MgLWwpIC1ndCAxIF1dOyB0aGVuXG4gICAgICAgICAgICAgICAgc29ydCAtdSAvaG9tZS9yb290Ly5zc2gvYXV0aG9yaXplZF9rZXlzID4gL2hvbWUvcm9vdC8uc3NoL2F1dGhvcml6ZWRfa2V5cy50bXBcbiAgICAgICAgICAgICAgICBtdiAvaG9tZS9yb290Ly5zc2gvYXV0aG9yaXplZF9rZXlzLnRtcCAvaG9tZS9yb290Ly5zc2gvYXV0aG9yaXplZF9rZXlzXG4gICAgICAgICAgICBmaVxuICAgICAgICAgICAgZWNobyBcIlNldCByb290IGF1dGhvcml6ZWRfa2V5cyBmcm9tIHVzZXIgcHJlZmVyZW5jZXMsIHRvdGFsXCIgJChjYXQgL2hvbWUvcm9vdC8uc3NoL2F1dGhvcml6ZWRfa2V5cyB8IHdjIC1sKSBcImtleXNcIlxuICAgICAgICBmaVxuICAgIGZpXG5lbHNlXG4gICAgZWNobyBcIldhcm5pbmc6IENhbm5vdCBjcmVhdGUgL2hvbWUvcm9vdC8uc3NoIGRpcmVjdG9yeSAocmVhZC1vbmx5IGZpbGUgc3lzdGVtPylcIlxuICAgIGVjaG8gXCJTa2lwcGluZyBTU0gga2V5IHNldHVwXCJcbmZpXG5cbmlmIFtbIC1TIC92YXIvcnVuL2RzdGFjay5zb2NrIF1dOyB0aGVuXG4gICAgZXhwb3J0IERTVEFDS19BUFBfSUQ9JChjdXJsIC1zIC0tdW5peC1zb2NrZXQgL3Zhci9ydW4vZHN0YWNrLnNvY2sgaHR0cDovL2RzdGFjay9JbmZvIHwganEgLWogLmFwcF9pZClcbmVsaWYgW1sgLVMgL3Zhci9ydW4vdGFwcGQuc29jayBdXTsgdGhlblxuICAgIGV4cG9ydCBEU1RBQ0tfQVBQX0lEPSQoY3VybCAtcyAtLXVuaXgtc29ja2V0IC92YXIvcnVuL3RhcHBkLnNvY2sgaHR0cDovL2RzdGFjay9wcnBjL1RhcHBkLkluZm8gfCBqcSAtaiAuYXBwX2lkKVxuZmlcbiMgQ2hlY2sgaWYgRFNUQUNLX0dBVEVXQVlfRE9NQUlOIGlzIG5vdCBzZXQsIHRyeSB0byBnZXQgaXQgZnJvbSB1c2VyX2NvbmZpZyBvciBhcHAtY29tcG9zZS5qc29uXG4jIFByaW9yaXR5OiB1c2VyX2NvbmZpZyA+IGFwcC1jb21wb3NlLmpzb25cbmlmIFtbIC16IFwiJERTVEFDS19HQVRFV0FZX0RPTUFJTlwiIF1dOyB0aGVuXG4gICAgIyBGaXJzdCB0cnkgdG8gZ2V0IGZyb20gL2RzdGFjay91c2VyX2NvbmZpZyBpZiBpdCBleGlzdHMgYW5kIGlzIHZhbGlkIEpTT05cbiAgICBpZiBbWyAtZiAvZHN0YWNrL3VzZXJfY29uZmlnIF1dICYmIGpxIGVtcHR5IC9kc3RhY2svdXNlcl9jb25maWcgMj4vZGV2L251bGw7IHRoZW5cbiAgICAgICAgaWYgW1sgJChqcSAnaGFzKFwiZGVmYXVsdF9nYXRld2F5X2RvbWFpblwiKScgL2RzdGFjay91c2VyX2NvbmZpZyAyPi9kZXYvbnVsbCkgPT0gXCJ0cnVlXCIgXV07IHRoZW5cbiAgICAgICAgICAgIGV4cG9ydCBEU1RBQ0tfR0FURVdBWV9ET01BSU49JChqcSAtaiAnLmRlZmF1bHRfZ2F0ZXdheV9kb21haW4nIC9kc3RhY2svdXNlcl9jb25maWcpXG4gICAgICAgIGZpXG4gICAgZmlcblxuICAgICMgSWYgc3RpbGwgbm90IHNldCwgdHJ5IHRvIGdldCBmcm9tIGFwcC1jb21wb3NlLmpzb25cbiAgICBpZiBbWyAteiBcIiREU1RBQ0tfR0FURVdBWV9ET01BSU5cIiBdXSAmJiBbWyAkKGpxICdoYXMoXCJkZWZhdWx0X2dhdGV3YXlfZG9tYWluXCIpJyBhcHAtY29tcG9zZS5qc29uKSA9PSBcInRydWVcIiBdXTsgdGhlblxuICAgICAgICBleHBvcnQgRFNUQUNLX0dBVEVXQVlfRE9NQUlOPSQoanEgLWogJy5kZWZhdWx0X2dhdGV3YXlfZG9tYWluJyBhcHAtY29tcG9zZS5qc29uKVxuICAgIGZpXG5maVxuaWYgW1sgLW4gXCIkRFNUQUNLX0dBVEVXQVlfRE9NQUlOXCIgXV07IHRoZW5cbiAgICBleHBvcnQgRFNUQUNLX0FQUF9ET01BSU49JERTVEFDS19BUFBfSURcIi5cIiREU1RBQ0tfR0FURVdBWV9ET01BSU5cbmZpXG5cbmVjaG8gXCItLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXCJcbmVjaG8gXCJTY3JpcHQgZXhlY3V0aW9uIGNvbXBsZXRlZFwiXG5lY2hvIFwiLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVwiXG4iLCJwdWJsaWNfbG9ncyI6dHJ1ZSwicHVibGljX3N5c2luZm8iOnRydWUsInB1YmxpY190Y2JpbmZvIjp0cnVlLCJydW5uZXIiOiJkb2NrZXItY29tcG9zZSIsInNlY3VyZV90aW1lIjpmYWxzZSwic3RvcmFnZV9mcyI6InpmcyIsInRwcm94eV9lbmFibGVkIjp0cnVlfQ=="}},"service_capabilities":{"supported_e2ee_versions":["2"],"serving":"aggregator"}},"note":"app_compose is held base64-encoded: the measured compose is a shell script full of paths, and the repository secret scanner reads those as leaked local paths. The test decodes it before hashing."} \ No newline at end of file +{"captured_at": "2026-09-14", "endpoint": "https://tee.redpill.ai/v1/aci/attestation", "nonce": "74823bb0e609a4595fe7e6b166e23522d9da5fddec467ede0f1e1c4508de6856", "note": "app_compose is held base64-encoded: the measured compose is a shell script full of paths, and the repository secret scanner reads those as leaked local paths. The test decodes it before hashing.", "report": {"api_version": "aci/1", "workload_keyset_digest": "sha256:9223dbe01170f56efeae9a72b0df74eeb3b30befecb3ec24d9c11413d1a25510", "attestation": {"tee_type": "tdx", "workload_keyset": {"subject": null, "not_after": 1791969683, "receipt_signing_keys": [{"key_id": "dstack-kms-receipt-ed25519-v1", "algo": "ed25519", "public_key": "110f3824daeeef29dbeba9677a5794ffed257b1082d9fd4599b3c0819953aa0a"}], "e2ee_public_keys": [{"key_id": "dstack-kms-e2ee-v1", "algo": "secp256k1-aes-256-gcm-hkdf-sha256", "public_key": "04943cea0b4babf60f6e2031e9a00866a37c4ae696fb45895b3a9b38ab8cbb898f42c85b704aceaa0a396cf26f7fdf79d83205be7e11d3a5d70419a68277158c3d"}, {"key_id": "dstack-kms-e2ee-x25519-v1", "algo": "x25519-aes-256-gcm-hkdf-sha256", "public_key": "408e82d159832cfae15007781bcade0badee7d50e9f76d50eaa1777464006537"}], "tls_public_keys": [{"spki_sha256": "22ad6f73dd10547af55d06825c8015413968a439b8f76adc3a6aba9a32e6c71b", "domain": "tee.redpill.ai"}, {"spki_sha256": "8bafb8e6ddc55e3e662b6385a2820494fc6e90c64688136860b1851a81b7ee06", "domain": "inference.phala.com"}, {"spki_sha256": "c68585e7dc00a55d3082a9c860cb916e1788c5daec51505e413d27ab94f7d4c7", "domain": "api.redpill.ai"}, {"spki_sha256": "29a17c8e20ffed55893f6d729a75a7cf34637961d268e870842d1f2f7badd7e5", "domain": "openrouter.phala.com"}]}, "report_data": "67ca10d6bbd2c38b006f26f1dd4db0d7a84cf9fa44e81efc6b277bf7e19edcc2", "source_provenance": {"repo_url": "https://github.com/Dstack-TEE/private-ai-gateway.git", "repo_commit": "3e56bd30dd459d0df90afeb6d63eca7a919bc22f", "image_digest": null, "image_provenance": null}, "evidence": {"quote": "040002008100000000000000939a7233f79c4ca9940a0db3957f06074d79685452a1c5725d6ff7f9d09c91b4000000000b0105000000000000000000000000007bf063280e94fb051f5dd7b1fc59ce9aac42bb961df8d44b709c9b0ff87a7b4df648657ba6d1189589feab1d5a3c9a9d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000702000000000000f06dfda6dce1cf904d4e2bab1dc370634cf95cefa2ceb2de2eee127c9382698090d7a4a13e14c536ec6c9c3c8fa87077011a23b6cc9d265648b3feb11a2a23453e84cf847953fb406b4b4bfd368083567c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000046a83f6bbbeaa274aaf04861ef47d7e8898d4e699126b642f72f582e8d7f5349cb266a188bbabf619940d4fece06594b07e6f51aa763abfe75c3ddfbf4f425fe3f0ceff66d807a75e049303dce9addf68e7218729bd419638af63a370f65878cdf67e467e60edc1737bcf8e682d48131bfb427f523226aa7f197a7608e9b3784783fa759ef5b28191fa12f9ddb36b85819d97a9f6d54660386dddd1892775007e47134c704e91b2654b056fb2174fa5d547fb0d76bf67e75aaafdd641b182e1367ca10d6bbd2c38b006f26f1dd4db0d7a84cf9fa44e81efc6b277bf7e19edcc20000000000000000000000000000000000000000000000000000000000000000cc100000a7a18da0806034774b872a4fcf4dee8ee566b6af0a55f83acbfc76ba5befe2c5108b444149b24e6520ab118a982f953ac52c809f9dce9ee47a8cebbf53fa4916f0bfa28939a048d1d67a664ae6595ec4514829a10a01f7fc10230dd75c44697bf80c2e1e89a20ca66c1f76795d1cf5553a394c311bcc4601b9231b111d70d6b506004610000005050a0a05ff00020000000000000000000000000000000000000000000000000000000000000000000000000000000015000000000000000700000000000000e5a3a7b5d830c2953b98534c6c59a3a34fdc34e933f7f5898f0a85cf08846bca0000000000000000000000000000000000000000000000000000000000000000dc9e2a7c6f948f17474e34a7fc43ed030f7c1563f1babddf6340c82e0e54a8c5000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020006000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009c1dc25ab6fd4ae8afb815c1c46f6d3f9bbe7ab053e699d259bf9136751037b20000000000000000000000000000000000000000000000000000000000000000a83b9d22a44e8d08fb7c247a64a52059f3b6b832995038b1a3b6578b0fc6fd488012210fe4a3762e3019de96ee5eb63bf1977043834cab40034ee81d35efd4082000000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f05005e0e00002d2d2d2d2d424547494e2043455254494649434154452d2d2d2d2d0a4d49494538544343424a656741774942416749555359617753595541735374766a483236625541434d506e6f6a797777436759494b6f5a497a6a3045417749770a634445694d434147413155454177775a535735305a577767553064594946424453794251624746305a6d397962534244515445614d42674741315545436777520a535735305a577767513239796347397959585270623234784644415342674e564241634d43314e68626e526849454e7359584a684d51737743515944565151490a44414a445154454c4d416b474131554542684d4356564d774868634e4d6a59774d7a49784d4463304e5455795768634e4d7a4d774d7a49784d4463304e5455790a576a42774d534977494159445651514444426c4a626e526c624342545231676755454e4c49454e6c636e52705a6d6c6a5958526c4d526f77474159445651514b0a4442464a626e526c6243424462334a7762334a6864476c76626a45554d424947413155454277774c553246756447456751327868636d4578437a414a42674e560a4241674d416b4e424d517377435159445651514745774a56557a425a4d424d4742797147534d34394167454743437147534d34394177454841304941424747690a41664533764c54435150696e5470685047695854516c645948654f6f657257516d4b66745141787939446c63353469446b4b537852786e7a38474f7a466f65690a6b584e532b44374575464864666b476a754e796a67674d4e4d4949444354416642674e5648534d4547444157674253566231334e765276683655424a796454300a4d383442567776655644427242674e56485238455a4442694d47436758714263686c706f64485277637a6f764c32467761533530636e567a6447566b633256790a646d6c6a5a584d75615735305a577775593239744c334e6e6543396a5a584a3061575a7059324630615739754c3359304c33426a61324e796244396a595431770a624746305a6d397962535a6c626d4e765a476c755a7a316b5a584977485159445652304f42425945464c6d495a7555304e42506c79336e757041556f41396f590a73625a514d41344741315564447745422f775145417749477744414d42674e5648524d4241663845416a41414d4949434f67594a4b6f5a496876684e415130420a424949434b7a4343416963774867594b4b6f5a496876684e415130424151515162536e396a546e656c37306e456e776e523951666554434341575147436971470a534962345451454e41514977676746554d42414743797147534962345451454e41514942416745464d42414743797147534962345451454e41514943416745460a4d42414743797147534962345451454e41514944416745434d42414743797147534962345451454e41514945416745434d42414743797147534962345451454e0a41514946416745464d42454743797147534962345451454e41514947416749412f7a415142677371686b69472b453042445145434277494241444151426773710a686b69472b4530424451454343414942416a415142677371686b69472b45304244514543435149424144415142677371686b69472b45304244514543436749420a4144415142677371686b69472b45304244514543437749424144415142677371686b69472b45304244514543444149424144415142677371686b69472b4530420a44514543445149424144415142677371686b69472b45304244514543446749424144415142677371686b69472b453042445145434477494241444151426773710a686b69472b45304244514543454149424144415142677371686b69472b45304244514543455149424454416642677371686b69472b45304244514543456751510a425155434167582f4141494141414141414141414144415142676f71686b69472b45304244514544424149414144415542676f71686b69472b453042445145450a424159676f473841414141774477594b4b6f5a496876684e4151304242516f424154416542676f71686b69472b453042445145474242414e78727a30753075620a48784e354e3964353631576d4d45514743697147534962345451454e415163774e6a415142677371686b69472b45304244514548415145422f7a4151426773710a686b69472b45304244514548416745422f7a415142677371686b69472b45304244514548417745422f7a414b42676771686b6a4f5051514441674e49414442460a4169454131305850553751764338564a743949654f724a366c4430744b58462b54746a4e422f6f7a62635235517477434944576e57773946484e7351745359420a70394c5463792f5670376f517367417076763332732f4236576b73760a2d2d2d2d2d454e442043455254494649434154452d2d2d2d2d0a2d2d2d2d2d424547494e2043455254494649434154452d2d2d2d2d0a4d4949436c6a4343416a32674177494241674956414a567658633239472b487051456e4a3150517a7a674658433935554d416f4743437147534d343942414d430a4d476778476a415942674e5642414d4d45556c756447567349464e48574342536232393049454e424d526f77474159445651514b4442464a626e526c624342440a62334a7762334a6864476c76626a45554d424947413155454277774c553246756447456751327868636d4578437a414a42674e564241674d416b4e424d5173770a435159445651514745774a56557a4165467730784f4441314d6a45784d4455774d5442614677307a4d7a41314d6a45784d4455774d5442614d484178496a41670a42674e5642414d4d47556c756447567349464e4857434251513073675547786864475a76636d306751304578476a415942674e5642416f4d45556c75644756730a49454e76636e4276636d4630615739754d5251774567594456515148444174545957353059534244624746795954454c4d416b474131554543417743513045780a437a414a42674e5642415954416c56544d466b77457759484b6f5a497a6a3043415159494b6f5a497a6a304441516344516741454e53422f377432316c58534f0a3243757a7078773734654a423732457944476757357258437478327456544c7136684b6b367a2b5569525a436e71523770734f766771466553786c6d546c4a6c0a65546d693257597a33714f42757a43427544416642674e5648534d4547444157674251695a517a575770303069664f44744a5653763141624f536347724442530a42674e5648523845537a424a4d45656752614244686b466f64485277637a6f764c324e6c636e52705a6d6c6a5958526c63793530636e567a6447566b633256790a646d6c6a5a584d75615735305a577775593239744c306c756447567355306459556d397664454e424c6d526c636a416442674e5648513445466751556c5739640a7a62306234656c4153636e553944504f4156634c336c517744675944565230504151482f42415144416745474d42494741315564457745422f7751494d4159420a4166384341514177436759494b6f5a497a6a30454177494452774177524149675873566b6930772b6936565947573355462f32327561586530594a446a3155650a6e412b546a44316169356343494359623153416d4435786b66545670766f34556f79695359787244574c6d5552344349394e4b7966504e2b0a2d2d2d2d2d454e442043455254494649434154452d2d2d2d2d0a2d2d2d2d2d424547494e2043455254494649434154452d2d2d2d2d0a4d4949436a7a4343416a53674177494241674955496d554d316c71644e496e7a6737535655723951477a6b6e42717777436759494b6f5a497a6a3045417749770a614445614d4267474131554541777752535735305a5777675530645949464a766233516751304578476a415942674e5642416f4d45556c756447567349454e760a636e4276636d4630615739754d5251774567594456515148444174545957353059534244624746795954454c4d416b47413155454341774351304578437a414a0a42674e5642415954416c56544d423458445445344d4455794d5445774e4455784d466f58445451354d54497a4d54497a4e546b314f566f77614445614d4267470a4131554541777752535735305a5777675530645949464a766233516751304578476a415942674e5642416f4d45556c756447567349454e76636e4276636d46300a615739754d5251774567594456515148444174545957353059534244624746795954454c4d416b47413155454341774351304578437a414a42674e56424159540a416c56544d466b77457759484b6f5a497a6a3043415159494b6f5a497a6a3044415163445167414543366e45774d4449595a4f6a2f69505773437a61454b69370a314f694f534c52466857476a626e42564a66566e6b59347533496a6b4459594c304d784f346d717379596a6c42616c54565978465032734a424b357a6c4b4f420a757a43427544416642674e5648534d4547444157674251695a517a575770303069664f44744a5653763141624f5363477244425342674e5648523845537a424a0a4d45656752614244686b466f64485277637a6f764c324e6c636e52705a6d6c6a5958526c63793530636e567a6447566b63325679646d6c6a5a584d75615735300a5a577775593239744c306c756447567355306459556d397664454e424c6d526c636a416442674e564851344546675155496d554d316c71644e496e7a673753560a55723951477a6b6e4271777744675944565230504151482f42415144416745474d42494741315564457745422f7751494d4159424166384341514577436759490a4b6f5a497a6a3045417749445351417752674968414f572f35516b522b533943695344634e6f6f774c7550524c735747662f59693747535839344267775477670a41694541344a306c72486f4d732b586f356f2f7358364f39515778485241765a55474f6452513763767152586171493d0a2d2d2d2d2d454e442043455254494649434154452d2d2d2d2d0a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "quote_report_data": "67ca10d6bbd2c38b006f26f1dd4db0d7a84cf9fa44e81efc6b277bf7e19edcc20000000000000000000000000000000000000000000000000000000000000000", "event_log": "[{\"imr\":0,\"event_type\":2147483659,\"digest\":\"5fe4f9ee465a361d077a6892f6bc4d19a82b272fea2e3c2c1ef9c33b4d9050115fca0c6dc7a7f68f91c623de38c48226\",\"event\":\"\",\"event_payload\":\"095464785461626c65000100000000000000af96bb93f2b9b84e9462e0ba745642360090800000000000\"},{\"imr\":0,\"event_type\":2147483658,\"digest\":\"344bc51c980ba621aaa00da3ed7436f7d6e549197dfe699515dfa2c6583d95e6412af21c097d473155875ffd561d6790\",\"event\":\"\",\"event_payload\":\"2946762858585858585858582d585858582d585858582d585858582d58585858585858585858585829000000c0ff000000000040080000000000\"},{\"imr\":0,\"event_type\":2147483649,\"digest\":\"9dc3a1f80bcec915391dcda5ffbb15e7419f77eab462bbf72b42166fb70d50325e37b36f93537a863769bcf9bedae6fb\",\"event\":\"\",\"event_payload\":\"61dfe48bca93d211aa0d00e098032b8c0a00000000000000000000000000000053006500630075007200650042006f006f007400\"},{\"imr\":0,\"event_type\":2147483649,\"digest\":\"6f2e3cbc14f9def86980f5f66fd85e99d63e69a73014ed8a5633ce56eca5b64b692108c56110e22acadcef58c3250f1b\",\"event\":\"\",\"event_payload\":\"61dfe48bca93d211aa0d00e098032b8c0200000000000000000000000000000050004b00\"},{\"imr\":0,\"event_type\":2147483649,\"digest\":\"d607c0efb41c0d757d69bca0615c3a9ac0b1db06c557d992e906c6b7dee40e0e031640c7bfd7bcd35844ef9edeadc6f9\",\"event\":\"\",\"event_payload\":\"61dfe48bca93d211aa0d00e098032b8c030000000000000000000000000000004b0045004b00\"},{\"imr\":0,\"event_type\":2147483649,\"digest\":\"08a74f8963b337acb6c93682f934496373679dd26af1089cb4eaf0c30cf260a12e814856385ab8843e56a9acea19e127\",\"event\":\"\",\"event_payload\":\"cbb219d73a3d9645a3bcdad00e67656f0200000000000000000000000000000064006200\"},{\"imr\":0,\"event_type\":2147483649,\"digest\":\"18cc6e01f0c6ea99aa23f8a280423e94ad81d96d0aeb5180504fc0f7a40cb3619dd39bd6a95ec1680a86ed6ab0f9828d\",\"event\":\"\",\"event_payload\":\"cbb219d73a3d9645a3bcdad00e67656f03000000000000000000000000000000640062007800\"},{\"imr\":0,\"event_type\":4,\"digest\":\"394341b7182cd227c5c6b07ef8000cdfd86136c4292b8e576573ad7ed9ae41019f5818b4b971c9effc60e1ad9f1289f0\",\"event\":\"\",\"event_payload\":\"00000000\"},{\"imr\":0,\"event_type\":10,\"digest\":\"febfba94a148ef74278a30ed690856a468636b51f619d44025c4f9dc0212068369895d35c67157ccd2149cd049f3761c\",\"event\":\"\",\"event_payload\":\"414350492044415441\"},{\"imr\":0,\"event_type\":10,\"digest\":\"5427470ec5de45a3ad085101e7567c7f0b4aa4b0147d9aa583f067fdcb15155fc52a22bd23fd8ea10d045751f8e52337\",\"event\":\"\",\"event_payload\":\"414350492044415441\"},{\"imr\":0,\"event_type\":10,\"digest\":\"2194a807023a3ce948e26538252c046bce7c76293a3750ac22a41d1c2a3584bd53cc95bbdbde2d0c9f3a906f2663840f\",\"event\":\"\",\"event_payload\":\"414350492044415441\"},{\"imr\":1,\"event_type\":2147483651,\"digest\":\"90e278aa4d688f4f05bf76f1786fea174abcea0d6b44e81cea5b3327f3f211e5c465a9c34b513283bed2512bca6d4a19\",\"event\":\"\",\"event_payload\":\"1860fd7a0000000000c485000000000000000000000000002a000000000000000403140072f728144ab61e44b8c39ebdd7f893c7040412006b00650072006e0065006c0000007fff0400\"},{\"imr\":0,\"event_type\":2147483650,\"digest\":\"1dd6f7b457ad880d840d41c961283bab688e94e4b59359ea45686581e90feccea3c624b1226113f824f315eb60ae0a7c\",\"event\":\"\",\"event_payload\":\"61dfe48bca93d211aa0d00e098032b8c0900000000000000020000000000000042006f006f0074004f0072006400650072000000\"},{\"imr\":0,\"event_type\":2147483650,\"digest\":\"23ada07f5261f12f34a0bd8e46760962d6b4d576a416f1fea1c64bc656b1d28eacf7047ae6e967c58fd2a98bfa74c298\",\"event\":\"\",\"event_payload\":\"61dfe48bca93d211aa0d00e098032b8c08000000000000003e0000000000000042006f006f0074003000300030003000090100002c0055006900410070007000000004071400c9bdb87cebf8344faaea3ee4af6516a10406140021aa2c4614760345836e8ab6f46623317fff0400\"},{\"imr\":1,\"event_type\":2147483655,\"digest\":\"77a0dab2312b4e1e57a84d865a21e5b2ee8d677a21012ada819d0a98988078d3d740f6346bfe0abaa938ca20439a8d71\",\"event\":\"\",\"event_payload\":\"43616c6c696e6720454649204170706c69636174696f6e2066726f6d20426f6f74204f7074696f6e\"},{\"imr\":1,\"event_type\":4,\"digest\":\"394341b7182cd227c5c6b07ef8000cdfd86136c4292b8e576573ad7ed9ae41019f5818b4b971c9effc60e1ad9f1289f0\",\"event\":\"\",\"event_payload\":\"00000000\"},{\"imr\":2,\"event_type\":6,\"digest\":\"9c824b958dbbef07ec732fd79727e995d5eca309dbc6d62e4fd2840f267c5e87108b5fe25c7997c67801ff391fb67ffc\",\"event\":\"\",\"event_payload\":\"ed223b8f1a0000004c4f414445445f494d4147453a3a4c6f61644f7074696f6e7300\"},{\"imr\":2,\"event_type\":6,\"digest\":\"5eb4f34f2ec49071551c5562ebaab9f86408f4a0eadaa3d7f05157e37ab04a1f040a82eaae94015d628a7ea4aa482cd2\",\"event\":\"\",\"event_payload\":\"ec223b8f0d0000004c696e757820696e6974726400\"},{\"imr\":1,\"event_type\":2147483655,\"digest\":\"214b0bef1379756011344877743fdc2a5382bac6e70362d624ccf3f654407c1b4badf7d8f9295dd3dabdef65b27677e0\",\"event\":\"\",\"event_payload\":\"4578697420426f6f7420536572766963657320496e766f636174696f6e\"},{\"imr\":1,\"event_type\":2147483655,\"digest\":\"0a2e01c85deae718a530ad8c6d20a84009babe6c8989269e950d8cf440c6e997695e64d455c4174a652cd080f6230b74\",\"event\":\"\",\"event_payload\":\"4578697420426f6f742053657276696365732052657475726e656420776974682053756363657373\"},{\"imr\":3,\"event_type\":134217729,\"digest\":\"f9974020ef507068183313d0ca808e0d1ca9b2d1ad0c61f5784e7157c362c06536f5ddacdad4451693f48fcc72fff624\",\"event\":\"system-preparing\",\"event_payload\":\"\"},{\"imr\":3,\"event_type\":134217729,\"digest\":\"8562fc3980258ea5119a31356844547c42ba696d73f6ecdc7d29732beef0083f22674ce14349a8a1400254466e851407\",\"event\":\"app-id\",\"event_payload\":\"fdb7a14e5a6675f752e2cb69c9067a98ca402918\"},{\"imr\":3,\"event_type\":134217729,\"digest\":\"5edb4d5fbf301c47c77faa3de6edbcb97b93521b7c63ac6a8d8028d2f1891bd8517d76285f6e724cf28451acaac6c89e\",\"event\":\"compose-hash\",\"event_payload\":\"1a23b6cc9d265648b3feb11a2a23453e84cf847953fb406b4b4bfd368083567c\"},{\"imr\":3,\"event_type\":134217729,\"digest\":\"dbb7d7c2c2ce19938fb5989949f2c4bba6829ced5cd7b8c0d98696c293ac1c5dc8b1bfb9bc95b61e2ff778a3686651eb\",\"event\":\"instance-id\",\"event_payload\":\"15e847e02a22706121de347498427469d2e7c379\"},{\"imr\":3,\"event_type\":134217729,\"digest\":\"98bd7e6bd3952720b65027fd494834045d06b4a714bf737a06b874638b3ea00ff402f7f583e3e3b05e921c8570433ac6\",\"event\":\"boot-mr-done\",\"event_payload\":\"\"},{\"imr\":3,\"event_type\":134217729,\"digest\":\"65828c6f922910fd0e272501a8b2bb6b03e24c99bb19d1cd530586061d8738f9dd0564752db23d556a6b381cbf465a85\",\"event\":\"mr-kms\",\"event_payload\":\"692afc6d7a86a32cfc1ebd9cad1a576aab012bab46986ba609bc8d6407270572\"},{\"imr\":3,\"event_type\":134217729,\"digest\":\"c936f709860155a455c519b505fe29bde21d1b778534a8f0b41b706b0f789eae2ea899e224fedb2331c18324aab4db93\",\"event\":\"os-image-hash\",\"event_payload\":\"bd369a8c2f9edb2b52dad48ac8e0b32dde5f1337c423a506b48d07403a7d8033\"},{\"imr\":3,\"event_type\":134217729,\"digest\":\"83368b43a0fc6f824f5a9220592df85fd30e2d405ecbd253a5c6354af63e6c9b41aec557c38a38e348ab87f9ac8fc68c\",\"event\":\"key-provider\",\"event_payload\":\"7b226e616d65223a226b6d73222c226964223a223330353933303133303630373261383634386365336430323031303630383261383634386365336430333031303730333432303030343838343465623432636364663863353266643466313734663336326663623962626431396334356664343866316564656332643866316361323335333665633161373430323162346365653631306330373466383239346434333162326237666565326333396535333333666461663061343532326434336662313539643966227d\"},{\"imr\":3,\"event_type\":134217729,\"digest\":\"ba51104636900268b0e059fa3d266419d079d1e94aea26fb9fcbb8d764bf4c89a67ac271b8a0d1a3989945132a111fc7\",\"event\":\"storage-fs\",\"event_payload\":\"7a6673\"},{\"imr\":3,\"event_type\":134217729,\"digest\":\"1a76b2a80a0be71eae59f80945d876351a7a3fb8e9fd1ff1cede5734aa84ea11fd72b4edfbb6f04e5a85edd114c751bd\",\"event\":\"system-ready\",\"event_payload\":\"\"}]", "vm_config": "{\"os_image_hash\":\"bd369a8c2f9edb2b52dad48ac8e0b32dde5f1337c423a506b48d07403a7d8033\",\"cpu_count\":32,\"memory_size\":34359738368,\"qemu_version\":\"8.2.2\",\"pci_hole64_size\":0,\"hugepages\":false,\"num_gpus\":0,\"num_nvswitches\":0,\"hotplug_off\":false,\"image\":\"dstack-0.5.9-bd369a8c\",\"host_share_mode\":\"9p\",\"spec_version\":1}", "key_custody": {"provider": "dstack-kms", "keys": [{"role": "receipt", "path": "aci/receipt-ed25519/v1", "purpose": "aci.receipt.ed25519.v1", "algo": "ed25519", "public_key": "110f3824daeeef29dbeba9677a5794ffed257b1082d9fd4599b3c0819953aa0a", "kms_public_key": "02f7fb3ed8c352d316dfdc19458a9f29c06eb7e74130b3808d784e2fd401a2c12d", "signature_chain": ["d1f59335effc2688acdf502ee34d8d3373b0e7e6be493075383714ce5673a29973f224690437c483ae3fdd37172df3abad82877c4023ed7c5a64d5acaf18477c00", "5c2fe36bdb1e434c0a371579bcbce07c4e7b89eba45affa089191baec84f23ad77b24a594aa28427b6b7a5f348b0ecf5597abfd9a2add05ddb55c521ba38a38501"]}, {"role": "e2ee-secp256k1", "path": "aci/e2ee/v1", "purpose": "aci.e2ee.v1", "algo": "secp256k1-aes-256-gcm-hkdf-sha256", "public_key": "04943cea0b4babf60f6e2031e9a00866a37c4ae696fb45895b3a9b38ab8cbb898f42c85b704aceaa0a396cf26f7fdf79d83205be7e11d3a5d70419a68277158c3d", "kms_public_key": "03943cea0b4babf60f6e2031e9a00866a37c4ae696fb45895b3a9b38ab8cbb898f", "signature_chain": ["452d6f86a807fef0ce0d65e6c5cd25a0a249b1fd8608d26c3efe17fc10346f4c2d3dfb8969d10dc1feac1d595b3816f63faa40ac370a3a233ce1d712d418c89701", "5c2fe36bdb1e434c0a371579bcbce07c4e7b89eba45affa089191baec84f23ad77b24a594aa28427b6b7a5f348b0ecf5597abfd9a2add05ddb55c521ba38a38501"]}, {"role": "e2ee-x25519", "path": "aci/e2ee-x25519/v1", "purpose": "aci.e2ee.x25519.v1", "algo": "x25519-aes-256-gcm-hkdf-sha256", "public_key": "408e82d159832cfae15007781bcade0badee7d50e9f76d50eaa1777464006537", "kms_public_key": "03892f86b3f55f78cc0760cec933cf8e2a92862fb173c2d221cc25895847cbb5eb", "signature_chain": ["358cd661ca4f5e986ed950ca083bf7bcfef6ab4b839ca11a953b156d64f82b1c51a213730d5777b4c845170827680d41e8220c2f950a38081025ff16eb3789ba00", "5c2fe36bdb1e434c0a371579bcbce07c4e7b89eba45affa089191baec84f23ad77b24a594aa28427b6b7a5f348b0ecf5597abfd9a2add05ddb55c521ba38a38501"]}]}, "downstream_tls_binding": {"domain": "tee.redpill.ai", "spki_sha256": "22ad6f73dd10547af55d06825c8015413968a439b8f76adc3a6aba9a32e6c71b"}, "app_compose_b64": "eyJhbGxvd2VkX2VudnMiOlsiUFJJVkFURV9BSV9HQVRFV0FZX0FETUlOX1RPS0VOIiwiUFJJVkFURV9BSV9HQVRFV0FZX0NPTlRST0xfVVJMIiwiUFJJVkFURV9BSV9HQVRFV0FZX0NPTlRST0xfVE9LRU4iLCJEU1RBQ0tfUk9PVF9QVUJMSUNfS0VZIiwiQ0xPVURGTEFSRV9BUElfVE9LRU4iLCJDRVJUQk9UX0VNQUlMIiwiTk9ERV9FWFBPUlRFUl9VU0VSIiwiTk9ERV9FWFBPUlRFUl9QQVNTV09SRF9IQVNIIiwiUFJJVkFURV9BSV9HQVRFV0FZX1BVTExfVE9LRU4iXSwiZG9ja2VyX2NvbXBvc2VfZmlsZSI6IiMgZHN0YWNrIC8gUGhhbGEgZGVwbG95bWVudCBtYW5pZmVzdCBmb3IgdGhlIHByaXZhdGUtYWktZ2F0ZXdheSBzdGFjayB2aWEgdGhlIGxhdW5jaGVyLlxuI1xuIyBUaGUgbGF1bmNoZXIgaW1hZ2UgaXMgdGhlIG1lYXN1cmVkIHRydXN0LXJvb3Q6IHBpbiBpdCBieSBAc2hhMjU2IGRpZ2VzdCAodGhlXG4jIGRpZ2VzdCArIHRoaXMgZmlsZSBhcmUgaGFzaGVkIGludG8gdGhlIFREWCBxdW90ZSkuIFRoZSBsYXVuY2hlciBjbG9uZXMrYnVpbGRzXG4jIHRoZSBnYXRld2F5IGZyb20gc291cmNlIGF0IGJvb3Q7IHRoZSBhdHRlc3RhdGlvbiB2ZXJpZmllciBpc1xuIyB0aGUgZ2F0ZXdheSdzIHZlbmRvcmVkIGNvbmZpZGVudGlhbF92ZXJpZmllciBwYWNrYWdlLCBzbyBpdCBuZWVkcyBubyBzZXBhcmF0ZSBwaW4uXG4jXG4jIFRoZSBnYXRld2F5J3Mgc291cmNlIHBpbiArIHN0YXRpYyBjb25maWcgYXJlIGlubGluZWQgYXMgY29tcG9zZSBgY29uZmlnczpgXG4jIChtZWFzdXJlZCBpbnRvIHRoZSBhdHRlc3RhdGlvbik6IHRoZSBsYXVuY2hlciBjbG9uZXMgdGhlIHBpbiBhbmQgdGhlIGdhdGV3YXlcbiMgcmVhZHMgdGhlIGNvbmZpZyBmcm9tIG1vdW50ZWQgZmlsZXMuIFNlY3JldCB2YWx1ZXMgYXJlIHN1cHBsaWVkIGFzIGRzdGFja1xuIyBFTkNSWVBURUQgU0VDUkVUUyBhbmQgcmVmZXJlbmNlZCBhcyAke1ZBUn0gc28gZHN0YWNrIGluamVjdHMgdGhlbSDigJQgb25seSB0aGVcbiMgdmFyaWFibGUgbmFtZXMgYXBwZWFyIGluIHRoaXMgcHVibGljIGZpbGUsIG5ldmVyIHRoZSB2YWx1ZXMuXG5cbnNlcnZpY2VzOlxuICAjIFRMUy10ZXJtaW5hdGluZyBpbmdyZXNzOiByZXF1ZXN0cyBDQUEtcGlubmVkIExldCdzIEVuY3J5cHQgY2VydHMgdmlhIENsb3VkZmxhcmVcbiAgIyBETlMtMDEsIHJlZ2lzdGVycyB1bmRlciB0aGUgZHN0YWNrIGdhdGV3YXkgZG9tYWluLCBhbmQgcmV2ZXJzZS1wcm94aWVzIGluYm91bmRcbiAgIyA0NDMgdG8gdGhlIGxhdW5jaGVyJ3MgZ2F0ZXdheSBvbiA6ODA4Ni4gUGluIGJ5IEBzaGEyNTYgZGlnZXN0IGxpa2UgdGhlIGxhdW5jaGVyLlxuICBkc3RhY2staW5ncmVzczpcbiAgICBpbWFnZTogZHN0YWNrdGVlL2RzdGFjay1pbmdyZXNzOjIuMkBzaGEyNTY6ZDA1YTdiMzQzYzM3YzFjY2ExYmJhOGRiZjdlOGYzYzZkMjExODE1OGFmMmQ0MWM0NTUxMDM3OTZkYjRmNjdmMFxuICAgIHJlc3RhcnQ6IHVubGVzcy1zdG9wcGVkXG4gICAgIyBUaGUgaW5ncmVzcyBpcyBhbiBMNCBUQ1AgcHJveHk6IGV2ZXJ5IGNsaWVudCBjb25uZWN0aW9uIG1hcHMgMToxIHRvIGFcbiAgICAjIGJhY2tlbmQgY29ubmVjdGlvbiB0byB0aGUgZ2F0ZXdheSwgc28gaXQgaG9sZHMgMiBmZHMgcGVyIGxpdmUgY29ubmVjdGlvbi5cbiAgICAjIGhhcHJveHkgaGFzIG5vIGB1bGltaXQtbmAgaW4gaXRzIGNvbmZpZzsgaXQgZGVyaXZlcyBhbiBmZCBuZWVkIGZyb20gTUFYQ09OTlxuICAgICMgYW5kIHJhaXNlcyBpdHMgT1dOIHNvZnQgbm9maWxlIGZyb20gdGhlIGNvbnRhaW5lciBoYXJkIGxpbWl0LiBQaW4gdGhlIGhhcmRcbiAgICAjIGxpbWl0IGhlcmUgKGxpa2UgYGxhdW5jaGVyYCkgc28gTUFYQ09OTiBpcyBuZXZlciBzaWxlbnRseSBjYXBwZWQgYnkgd2hhdGV2ZXJcbiAgICAjIHRoZSBkb2NrZXIgZGFlbW9uIGRlZmF1bHQgaGFwcGVucyB0byBiZS4gNjU1MzYgY29tZm9ydGFibHkgY292ZXJzXG4gICAgIyBNQVhDT05OIDE2Mzg0ICh+MzNrIGZkcykgd2l0aCBoZWFkcm9vbS5cbiAgICB1bGltaXRzOlxuICAgICAgbm9maWxlOlxuICAgICAgICBzb2Z0OiA2NTUzNlxuICAgICAgICBoYXJkOiA2NTUzNlxuICAgIHBvcnRzOlxuICAgICAgLSBcIjQ0Mzo0NDNcIlxuICAgIGVudmlyb25tZW50OlxuICAgICAgIyAtLS0gcHVibGljIGNvbmZpZzogbGl0ZXJhbHMsIG1lYXN1cmVkIGludG8gdGhlIGF0dGVzdGF0aW9uIC0tLVxuICAgICAgRE5TX1BST1ZJREVSOiBjbG91ZGZsYXJlXG4gICAgICBHQVRFV0FZX0RPTUFJTjogXy4ke0RTVEFDS19HQVRFV0FZX0RPTUFJTn1cbiAgICAgIFNFVF9DQUE6IFwidHJ1ZVwiXG4gICAgICAjIENvbmN1cnJlbnQtY29ubmVjdGlvbiBjZWlsaW5nLiBUaGUgaW1hZ2UgZGVmYXVsdCBpcyA0MDk2OyB1bmRlciByZWFsXG4gICAgICAjIHN0cmVhbWluZyBsb2FkIHRoZSBpbmdyZXNzIHNhdCBwaW5uZWQgYXQgdGhhdCBjZWlsaW5nIH44NCUgb2YgdGhlIHRpbWVcbiAgICAgICMgKGF2ZyB+MzcyMCBjb25jdXJyZW50KSwgc28gb25jZSBhIGJ1cnN0IHB1c2hlZCBwYXN0IDQwOTYgaGFwcm94eSBzdG9wcGVkXG4gICAgICAjIGFjY2VwdGluZyBhbmQgY2xpZW50cyBzYXcgYSBoYW5nLiBTdHJlYW1pbmcgTExNIHRyYWZmaWMga2VlcHMgdGhvdXNhbmRzIG9mXG4gICAgICAjIGxvbmctbGl2ZWQgY29ubmVjdGlvbnMgb3BlbiBhdCBvbmNlLCBzbyBnaXZlIGEgNHggaGVhZHJvb20uIE11c3Qgc3RheSB3ZWxsXG4gICAgICAjIHVuZGVyIHRoZSBub2ZpbGUgaGFyZCBsaW1pdCBhYm92ZSAoMiBmZHMvY29ubiBpbiBUQ1AgbW9kZSkuXG4gICAgICBNQVhDT05OOiBcIjE2Mzg0XCJcbiAgICAgICMgSWRsZSAobm8tZGF0YSkgdGltZW91dCwgcmVzZXQgb24gYW55IGJ5dGUgaW4gZWl0aGVyIGRpcmVjdGlvbi4gVGhlIGltYWdlXG4gICAgICAjIGRlZmF1bHQgaXMgODY0MDBzICgyNGgpOiBhIGNsaWVudCB0aGF0IHN0b3BzIHJlYWRpbmcsIG9yIGFuIHVwc3RyZWFtIHRoYXRcbiAgICAgICMgZ29lcyBzaWxlbnQsIGtlZXBzIGl0cyBzbG90IGZvciBhIGZ1bGwgZGF5LCB3aGljaCBpcyBob3cgc2xvdHMgbGVha2VkXG4gICAgICAjIHRvd2FyZCB0aGUgY2VpbGluZy4gMTgwMHMgcmVhcHMgYSBnZW51aW5lbHkgaWRsZS9zdGFsbGVkIGNvbm5lY3Rpb24gd2hpbGVcbiAgICAgICMgbmV2ZXIgdG91Y2hpbmcgYSBzdHJlYW0gdGhhdCBpcyBzdGlsbCBmbG93aW5nIChldmVuIGEgc2xvdyBvbmUpLiBOT1RFOlxuICAgICAgIyB0aGlzIGlzIHRoZSBvbmUgdmFsdWUgdG8gY29uZmlybSBhZ2FpbnN0IHRoZSBsb25nZXN0IGxlZ2l0aW1hdGUgc2lsZW50XG4gICAgICAjIGdhcCBhIHJlcXVlc3QgY2FuIGhhdmUg4oCUIGUuZy4gYSByZWFzb25pbmcgbW9kZWwgdGhhdCB0aGlua3MgPjMwIG1pbiBiZWZvcmVcbiAgICAgICMgaXRzIGZpcnN0IHRva2VuIHdvdWxkIGJlIGN1dC4gUmFpc2UgaWYgc3VjaCByZXF1ZXN0cyBhcmUgZXhwZWN0ZWQuXG4gICAgICBUSU1FT1VUX0NMSUVOVDogMTgwMHNcbiAgICAgIFRJTUVPVVRfU0VSVkVSOiAxODAwc1xuICAgICAgIyBNdWx0aS1kb21haW4gVExTLiBUaGUgaW5ncmVzcyBpcyBhbiBMNCAoVENQKSBwcm94eTogaXQgdGVybWluYXRlcyBUTFMgZm9yXG4gICAgICAjIGVhY2ggaG9zdG5hbWUgYW5kIGZvcndhcmRzIHRoZSBERUNSWVBURUQgc3RyZWFtIHVudG91Y2hlZCwgc28gdGhlIGNsaWVudCdzXG4gICAgICAjIG9yaWdpbmFsIEhUVFAgSG9zdCBzdXJ2aXZlcy4gVGhlIGdhdGV3YXkgdXNlcyB0aGF0IEhvc3QgdG8gcGljayB0aGVcbiAgICAgICMgbWF0Y2hpbmcgZG93bnN0cmVhbV90bHNfYmluZGluZy4gQWxsIHB1YmxpYyBob3N0bmFtZXMgcm91dGUgYnkgU05JIHRvIHRoZVxuICAgICAgIyBzYW1lIGdhdGV3YXkgbGlzdGVuZXIgKGNvbXBvc2Ugc2VydmljZSBuYW1lLCBub3QgbG9jYWxob3N0KS4gdGVlLnJlZHBpbGwuYWlcbiAgICAgICMgYW5kIGluZmVyZW5jZS5waGFsYS5jb20gYXJlIHRoZSBURUUtb25seSBkb21haW5zIChzZWUgYHRlZV9vbmx5X2RvbWFpbnNgXG4gICAgICAjIGJlbG93KTsgYXBpLnJlZHBpbGwuYWkgYW5kIG9wZW5yb3V0ZXIucGhhbGEuY29tIGFyZSB0aGUgbm9uLVRFRSBkb21haW5zLlxuICAgICAgRE9NQUlOUzogfFxuICAgICAgICB0ZWUucmVkcGlsbC5haVxuICAgICAgICBpbmZlcmVuY2UucGhhbGEuY29tXG4gICAgICAgIGFwaS5yZWRwaWxsLmFpXG4gICAgICAgIG9wZW5yb3V0ZXIucGhhbGEuY29tXG4gICAgICBST1VUSU5HX01BUDogfFxuICAgICAgICB0ZWUucmVkcGlsbC5haT1sYXVuY2hlcjo4MDg2XG4gICAgICAgIGluZmVyZW5jZS5waGFsYS5jb209bGF1bmNoZXI6ODA4NlxuICAgICAgICBhcGkucmVkcGlsbC5haT1sYXVuY2hlcjo4MDg2XG4gICAgICAgIG9wZW5yb3V0ZXIucGhhbGEuY29tPWxhdW5jaGVyOjgwODZcbiAgICAgICMgLS0tIHNlY3JldHM6IHZhbHVlcyBjb21lIGZyb20gZHN0YWNrIEVuY3J5cHRlZCBTZWNyZXRzIChuZXZlciBjb21taXQgdmFsdWVzKSAtLS1cbiAgICAgICMgTk9URTogdGhpcyBzaW5nbGUgQ2xvdWRmbGFyZSB0b2tlbiBtdXN0IGhhdmUgRE5TLWVkaXQgKGFuZCBDQUEpIHJpZ2h0cyBvblxuICAgICAgIyBCT1RIIHRoZSByZWRwaWxsLmFpIGFuZCBwaGFsYS5jb20gem9uZXMsIG9yIGNlcnQgaXNzdWFuY2UgZm9yIG9uZSBmYWlscy5cbiAgICAgIENMT1VERkxBUkVfQVBJX1RPS0VOOiAke0NMT1VERkxBUkVfQVBJX1RPS0VOfVxuICAgICAgQ0VSVEJPVF9FTUFJTDogJHtDRVJUQk9UX0VNQUlMfVxuICAgIHZvbHVtZXM6XG4gICAgICAtIC92YXIvcnVuL2RzdGFjay5zb2NrOi92YXIvcnVuL2RzdGFjay5zb2NrXG4gICAgICAtIC92YXIvcnVuL3RhcHBkLnNvY2s6L3Zhci9ydW4vdGFwcGQuc29ja1xuICAgICAgLSBjZXJ0LWRhdGE6L2V0Yy9sZXRzZW5jcnlwdFxuICAgICAgIyBQZXItZG9tYWluIGxlYWYgY2VydHMgKGNlcnQtPGRvbWFpbj4ucGVtKSB0aGUgZ2F0ZXdheSByZWFkcyB0byBiaW5kIFNQS0kuXG4gICAgICAtIGV2aWRlbmNlczovZXZpZGVuY2VzXG5cbiAgbGF1bmNoZXI6XG4gICAgaW1hZ2U6IGdoY3IuaW8vcmVkcGlsbC1haS9wcml2YXRlLWFpLWxhdW5jaGVyQHNoYTI1NjpjMDgzZmY5ZTZhNWRkZjEwZjZjOWU5YmIxZjc0Y2M2MThkZWViZWNmZWE1MjA4YjU2M2M1NzQzOTlkYjQ2MzdjXG4gICAgcmVzdGFydDogYWx3YXlzXG4gICAgIyBUaGUgZ2F0ZXdheSBvcGVucyBtYW55IGZkcyAoaW5ib3VuZCBjb25ucywgcGVyLXVwc3RyZWFtIHBvb2xzLCBjb250cm9sLXBsYW5lXG4gICAgIyArIHZlcmlmaWVyIGNhbGxzKS4gRG9ja2VyJ3MgZGVmYXVsdCBub2ZpbGUgKG9mdGVuIDEwMjQpIGlzIGZhciB0b28gbG93OiB1bmRlclxuICAgICMgbG9hZCBpdCBoaXQgRU1GSUxFIChcIlRvbyBtYW55IG9wZW4gZmlsZXNcIiksIHdoaWNoIGtpbGxlZCB0aGUgZ2F0ZXdheSdzIGFjY2VwdFxuICAgICMgbG9vcC4gUmFpc2UgdGhlIGxpbWl0IHdlbGwgYWJvdmUgcGVhayBjb25jdXJyZW5jeS5cbiAgICB1bGltaXRzOlxuICAgICAgbm9maWxlOlxuICAgICAgICBzb2Z0OiA2NTUzNlxuICAgICAgICBoYXJkOiA2NTUzNlxuICAgICMgc3VwZXJ2aXNvcmQgc3RyZWFtcyB0aGUgZ2F0ZXdheSBsb2dzIHRvIHRoZSBjb250YWluZXIgc3Rkb3V0OyBjYXAgdGhlXG4gICAgIyBydW50aW1lIGxvZyBvbiBkaXNrIHNvIGl0IGNhbid0IGdyb3cgdW5ib3VuZGVkICh+NUdCIHRvdGFsLCByb3RhdGVkKS5cbiAgICAjIFNpemVkIGZvciB0aGUgZ2F0ZXdheSdzIGFsd2F5cy1vbiByZXF1ZXN0X291dGNvbWUgZmFpbHVyZSBsb2dnaW5nOlxuICAgICMgcm91Z2hseSBhIG1vbnRoIG9mIHJldGVudGlvbiBvbiB0aGUgcGVyc2lzdGVudCB2b2x1bWUgZm9yIGluY2lkZW50XG4gICAgIyBmb3JlbnNpY3MuXG4gICAgbG9nZ2luZzpcbiAgICAgIGRyaXZlcjoganNvbi1maWxlXG4gICAgICBvcHRpb25zOlxuICAgICAgICBtYXgtc2l6ZTogXCI1MDBtXCJcbiAgICAgICAgbWF4LWZpbGU6IFwiMTBcIlxuICAgICMgbm8gaG9zdCBwb3J0OiB0cmFmZmljIGVudGVycyB2aWEgZHN0YWNrLWluZ3Jlc3MgKDQ0MykgYW5kIHJlYWNoZXMgdGhlXG4gICAgIyBnYXRld2F5IG92ZXIgdGhlIGNvbXBvc2UgbmV0d29yayBhcyBodHRwOi8vbGF1bmNoZXI6ODA4Ni5cbiAgICBleHBvc2U6XG4gICAgICAtIFwiODA4NlwiXG4gICAgdm9sdW1lczpcbiAgICAgIC0gL3Zhci9ydW4vZHN0YWNrLnNvY2s6L3Zhci9ydW4vZHN0YWNrLnNvY2sgICAjIG9ubHkgdGhlIGdhdGV3YXkgdXNlcyB0aGlzXG4gICAgICAtIHBhbC1jYWNoZTovdmFyL2xpYi9wYWcvY2FjaGUgICAgICAgICAgICAgICAgICMgY2FyZ28vdXYgYnVpbGQgY2FjaGUgKHNwZWVkcyByZWJvb3RzKVxuICAgICAgLSBwYWwtc3RhdGU6L3Zhci9saWIvcGFnL3N0YXRlICAgICAgICAgICAgICAgICAjIG11dGFibGUgdXBzdHJlYW1zLmpzb24gKyBzZXNzaW9ucy5qc29ubFxuICAgICAgLSBldmlkZW5jZXM6L2V2aWRlbmNlczpybyAgICAgICAgICAgICAgICAgICAgICAjIGluZ3Jlc3MtbWludGVkIHBlci1kb21haW4gbGVhZiBjZXJ0cyAoY2VydC08ZG9tYWluPi5wZW0pXG4gICAgIyBTdGF0aWMgZ2F0ZXdheSBjb25maWcgKyB1cHN0cmVhbSBzZWVkIGFyZSBtb3VudGVkIGZyb20gdGhlIGBjb25maWdzOmAgYmxvY2tcbiAgICAjIGF0IHRoZSBib3R0b20gKG1lYXN1cmVkIGludG8gdGhlIGF0dGVzdGF0aW9uKS4gVGhlIHNvdXJjZSBwaW4gaXMgcGFzc2VkIHZpYVxuICAgICMgYGVudmlyb25tZW50OmAgaW5zdGVhZCAoc2VlIGJlbG93KS5cbiAgICBjb25maWdzOlxuICAgICAgLSBzb3VyY2U6IGdhdGV3YXktY29uZmlnXG4gICAgICAgIHRhcmdldDogL2V0Yy9wcml2YXRlLWFpLWdhdGV3YXkvZ2F0ZXdheS5jb25maWcuanNvblxuICAgICAgLSBzb3VyY2U6IGdhdGV3YXktdXBzdHJlYW1zXG4gICAgICAgIHRhcmdldDogL2V0Yy9wcml2YXRlLWFpLWdhdGV3YXkvdXBzdHJlYW1zLnNlZWQuanNvblxuICAgIGVudmlyb25tZW50OlxuICAgICAgIyBUaGUgZ2F0ZXdheSByZWFkcyBpdHMgd2hvbGUgcG9saWN5IGZyb20gdGhpcyBtb3VudGVkIHN0YXRpYyBjb25maWcgZmlsZVxuICAgICAgIyAoc2VlIGBjb25maWdzOmAgYWJvdmUpOyBDT05GSUdfUEFUSCBpcyB0aGUgb25seSBnYXRld2F5LWZhY2luZyBlbnYgdmFyLlxuICAgICAgLSBQUklWQVRFX0FJX0dBVEVXQVlfQ09ORklHX1BBVEg9L2V0Yy9wcml2YXRlLWFpLWdhdGV3YXkvZ2F0ZXdheS5jb25maWcuanNvblxuICAgICAgIyBUcmFjaW5nIGZpbHRlci4gYHJlcXVlc3Rfb3V0Y29tZT1kZWJ1Z2AgdHVybnMgb24gdGhlIHJhdyBlcnJvci1kZXRhaWxcbiAgICAgICMgZmllbGQgb2YgdGhlIHBlci1yZXF1ZXN0IGZhaWx1cmUgbG9nIOKAlCBhIGRlbGliZXJhdGUgb3BlcmF0b3IgY2hvaWNlOlxuICAgICAgIyB1cHN0cmVhbSBlcnJvciBib2RpZXMgbWF5IGVjaG8gcmVxdWVzdCBmcmFnbWVudHMgaW50byB0aGVzZVxuICAgICAgIyBvcGVyYXRvci12aXNpYmxlIGxvZ3MuIERyb3AgdGhlIGByZXF1ZXN0X291dGNvbWU9ZGVidWdgIHBhcnQgdG8gZmFsbFxuICAgICAgIyBiYWNrIHRvIGNvbnRlbnQtZnJlZSBmYWlsdXJlIGxvZ2dpbmcgb25seS5cbiAgICAgIC0gUlVTVF9MT0c9aW5mbyxyZXF1ZXN0X291dGNvbWU9ZGVidWdcbiAgICAgICMgR2F0ZXdheSBzb3VyY2UgcGluLiBUaGVzZSBsaXRlcmFscyBhcmUgbWVhc3VyZWQgaW50byB0aGUgYXR0ZXN0YXRpb24sIGFuZFxuICAgICAgIyBiZWNhdXNlIHRoZXkgbGl2ZSBpbiBgZW52aXJvbm1lbnQ6YCAocGFydCBvZiBDb21wb3NlJ3MgY29uZmlnLWhhc2gpIGFcbiAgICAgICMgQ09NTUlUX1NIQSBidW1wIGZvcmNlcyBhIGNvbnRhaW5lciByZWNyZWF0ZSBvbiBgcGhhbGEgZGVwbG95YCDigJQgc28gdGhlIG5ld1xuICAgICAgIyBwaW4gYWN0dWFsbHkgdGFrZXMgZWZmZWN0LiAoQSBgY29uZmlnczpgLWZpbGUgcGluIHdvdWxkIG5vdDogQ29tcG9zZSBpZ25vcmVzXG4gICAgICAjIGNvbmZpZyBjb250ZW50IHdoZW4gZGVjaWRpbmcgdG8gcmVjcmVhdGUsIHNvIHRoZSBjaGFuZ2Ugd291bGQgbmV2ZXIgYXBwbHkuKVxuICAgICAgIyBlbnRyeXBvaW50LnNoIHdyaXRlcyAvZXRjL2dpdC1sYXVuY2hlci9nYXRld2F5LmNvbmYgZnJvbSB0aGVzZSwgYW5kIHRoZVxuICAgICAgIyBnYXRld2F5IHJlYWRzIHRoYXQgZmlsZSBhcyBpdHMgYXR0ZXN0ZWQgc291cmNlIHByb3ZlbmFuY2UuXG4gICAgICAtIFBSSVZBVEVfQUlfR0FURVdBWV9SRVBPX1VSTD1odHRwczovL2dpdGh1Yi5jb20vRHN0YWNrLVRFRS9wcml2YXRlLWFpLWdhdGV3YXkuZ2l0XG4gICAgICAtIFBSSVZBVEVfQUlfR0FURVdBWV9SRVBPX0NPTU1JVD0zZTU2YmQzMGRkNDU5ZDBkZjkwYWZlYjZkNjNlY2E3YTkxOWJjMjJmXG4gICAgICAjIE5FQVIgQUkgdmVyaWZpY2F0aW9uIHBvc3RzIFREWCBxdW90ZXMgdG8gdGhlIGRzdGFjay12ZXJpZmllciBzaWRlY2FyIGJlbG93O1xuICAgICAgIyByZWFjaCBpdCBieSBjb21wb3NlIHNlcnZpY2UgbmFtZSAobG9jYWxob3N0IHdvdWxkIGJlIHRoZSBsYXVuY2hlciBpdHNlbGYpLlxuICAgICAgLSBEU1RBQ0tfVkVSSUZJRVJfVVJMPWh0dHA6Ly9kc3RhY2stdmVyaWZpZXI6ODA4MFxuICAgICAgIyAtLS0gc2VjcmV0czogdmFsdWVzIGNvbWUgZnJvbSBkc3RhY2sgRW5jcnlwdGVkIFNlY3JldHMgKG5ldmVyIGNvbW1pdCB2YWx1ZXMpIC0tLVxuICAgICAgIyBDb250cm9sLXBsYW5lIGNyZWRlbnRpYWxzLiBUaGUgZ2F0ZXdheSdzIGluLXByb2Nlc3MgbWlkZGxld2FyZSByZWFkcyB0aGVzZVxuICAgICAgIyBmcm9tIHRoZSBgbWlkZGxld2FyZWAgY29uZmlnIHNlY3Rpb24gYmVsb3cgKHJlbmRlcmVkIGZyb20gdGhlIHNhbWUgc2VjcmV0cykuXG4gICAgICAtIFBSSVZBVEVfQUlfR0FURVdBWV9DT05UUk9MX1VSTD0ke1BSSVZBVEVfQUlfR0FURVdBWV9DT05UUk9MX1VSTH1cbiAgICAgIC0gUFJJVkFURV9BSV9HQVRFV0FZX0NPTlRST0xfVE9LRU49JHtQUklWQVRFX0FJX0dBVEVXQVlfQ09OVFJPTF9UT0tFTn1cblxuICAjIFREWCBxdW90ZSB2ZXJpZmllciBmb3IgdGhlIE5FQVIgQUkgcGF0aCAocmVwcm9kdWNlcyBBQ1BJL2Jvb3QgbWVhc3VyZW1lbnRzIHZpYVxuICAjIFFFTVUpLiBUaGUgZ2F0ZXdheSByZWFjaGVzIGl0IGF0IGh0dHA6Ly9kc3RhY2stdmVyaWZpZXI6ODA4MCAoRFNUQUNLX1ZFUklGSUVSX1VSTCkuXG4gIGRzdGFjay12ZXJpZmllcjpcbiAgICBpbWFnZTogZHN0YWNrdGVlL2RzdGFjay12ZXJpZmllcjowLjYuMC1yYzNAc2hhMjU2OjBlZDYxZDYwZjZlMGQ0NGNmNDY2ZTE1ZGM2ODk0ZjM3MTUyZDg1NjdjZmE3NmJkODc4NWE5MjFiMmQ5MDZjMzhcbiAgICByZXN0YXJ0OiB1bmxlc3Mtc3RvcHBlZFxuICAgIGxvZ2dpbmc6XG4gICAgICBkcml2ZXI6IGpzb24tZmlsZVxuICAgICAgb3B0aW9uczpcbiAgICAgICAgbWF4LXNpemU6IFwiNTBtXCJcbiAgICAgICAgbWF4LWZpbGU6IFwiNVwiXG5cbiAgIyBIb3N0LW1ldHJpY3MgZXhwb3J0ZXIgZm9yIG9ic2VydmluZyB0aGlzIENWTSAoQ1BVL21lbS9kaXNrL25ldC9mZCkuIEluc2lkZSBhXG4gICMgQ1ZNIHRoZSBjb250YWluZXIncyAvLCAvcHJvYywgL3N5cyBBUkUgdGhlIGd1ZXN0J3MsIHNvIG5vZGUtZXhwb3J0ZXIgcmVwb3J0c1xuICAjIHRoZSBDVk0ncyBvd24gc3RhdGUuIFBpbm5lZCBieSBAc2hhMjU2IGxpa2UgdGhlIG90aGVyIGltYWdlcyAobWVhc3VyZWQgaW50b1xuICAjIHRoZSBhdHRlc3RhdGlvbikuIEV4cG9zZWQgb24gOTEwMCAocmVhY2hlZCB2aWEgdGhlIGRzdGFjayBnYXRld2F5KSBhbmQgZ3VhcmRlZFxuICAjIGJ5IEhUVFAgYmFzaWMgYXV0aCDigJQgYm90aCB1c2VybmFtZSBhbmQgdGhlIGJjcnlwdCBwYXNzd29yZCBIQVNIIGFyZSBpbmplY3RlZCBhc1xuICAjIGRzdGFjayBFbmNyeXB0ZWQgU2VjcmV0cywgc28gbmVpdGhlciBhcHBlYXJzIGluIHRoaXMgbWVhc3VyZWQgZmlsZS5cbiAgbm9kZS1leHBvcnRlcjpcbiAgICBpbWFnZTogcHJvbS9ub2RlLWV4cG9ydGVyOnYxLjguMkBzaGEyNTY6NDAzMmM2ZDViZmQ3NTIzNDJjM2U2MzFjMmYxZGU5M2JhNmI4NmM0MWRiNmIxNjdiOWEzNTM3MmMxMzllNzcwNlxuICAgIHJlc3RhcnQ6IHVubGVzcy1zdG9wcGVkXG4gICAgcGlkOiBob3N0XG4gICAgY29tbWFuZDpcbiAgICAgIC0gJy0tcGF0aC5yb290ZnM9L2hvc3QnXG4gICAgICAtICctLXBhdGgucHJvY2ZzPS9ob3N0L3Byb2MnXG4gICAgICAtICctLXBhdGguc3lzZnM9L2hvc3Qvc3lzJ1xuICAgICAgLSAnLS13ZWIuY29uZmlnLmZpbGU9L2V0Yy9ub2RlLWV4cG9ydGVyL3dlYi1jb25maWcueW1sJ1xuICAgIHZvbHVtZXM6XG4gICAgICAtIC86L2hvc3Q6cm8scnNsYXZlXG4gICAgY29uZmlnczpcbiAgICAgIC0gc291cmNlOiBub2RlLWV4cG9ydGVyLXdlYi1jb25maWdcbiAgICAgICAgdGFyZ2V0OiAvZXRjL25vZGUtZXhwb3J0ZXIvd2ViLWNvbmZpZy55bWxcbiAgICBwb3J0czpcbiAgICAgIC0gXCI5MTAwOjkxMDBcIlxuICAgIGxvZ2dpbmc6XG4gICAgICBkcml2ZXI6IGpzb24tZmlsZVxuICAgICAgb3B0aW9uczpcbiAgICAgICAgbWF4LXNpemU6IFwiMTBtXCJcbiAgICAgICAgbWF4LWZpbGU6IFwiM1wiXG5cbnZvbHVtZXM6XG4gIHBhbC1jYWNoZTpcbiAgcGFsLXN0YXRlOlxuICBjZXJ0LWRhdGE6ICAgIyBMZXQncyBFbmNyeXB0IGNlcnRzL2tleXMgcGVyc2lzdGVkIGZvciBkc3RhY2staW5ncmVzc1xuICBldmlkZW5jZXM6ICAgIyBpbmdyZXNzIGF0dGVzdGF0aW9uIGV2aWRlbmNlICsgcGVyLWRvbWFpbiBsZWFmIGNlcnRzLCBzaGFyZWQgcmVhZC1vbmx5IHdpdGggdGhlIGdhdGV3YXlcblxuIyBJbmxpbmVkLCBtZWFzdXJlZCBpbnRvIHRoZSBhdHRlc3RhdGlvbi4gUHVibGljIHBpbnMgdXNlIExJVEVSQUwgdmFsdWVzIHNvIHRoZVxuIyBjb2RlIHZlcnNpb24gaXMgYm91bmQgaW50byBjb21wb3NlX2hhc2g7IG9ubHkgc2VjcmV0cyB1c2UgJHtWQVJ9IChpbmplY3RlZCBieVxuIyBkc3RhY2ssIG5ldmVyIG1lYXN1cmVkKS5cbmNvbmZpZ3M6XG4gICMgU3RhdGljIGdhdGV3YXkgY29uZmlnLiBgYWRtaW5fdG9rZW5gLCB0aGUgZGVkaWNhdGVkIHVwc3RyZWFtIHB1bGwgdG9rZW4sIGFuZFxuICAjIHRoZSBjb250cm9sLXBsYW5lIGNyZWRlbnRpYWxzIGFyZSBzZWNyZXRzIOKAlCAke1ZBUn0ga2VlcHMgdGhlaXIgdmFsdWVzIG91dCBvZlxuICAjIHRoZSBtZWFzdXJlZCBjb21wb3NlIHdoaWxlIHRoZSBwcmVzZW5jZSBhbmQgZGVzdGluYXRpb24gc3RheSBtZWFzdXJlZC4gVGhlXG4gICMgYG1pZGRsZXdhcmVgIHNlY3Rpb24gcnVucyB0aGUgaW4tcHJvY2VzcyBtaWRkbGV3YXJlLCB3aGljaCBjb25zdWx0cyB0aGUgY29udHJvbFxuICAjIHBsYW5lIGF0IGBjb250cm9sX3VybGAuXG4gIGdhdGV3YXktY29uZmlnOlxuICAgIGNvbnRlbnQ6IHxcbiAgICAgIHtcbiAgICAgICAgXCJiaW5kXCI6IFwiMC4wLjAuMDo4MDg2XCIsXG4gICAgICAgIFwic3RhdGVfZGlyXCI6IFwiL3Zhci9saWIvcGFnL3N0YXRlXCIsXG4gICAgICAgIFwidXBzdHJlYW1fY29uZmlnX3NlZWRfcGF0aFwiOiBcIi9ldGMvcHJpdmF0ZS1haS1nYXRld2F5L3Vwc3RyZWFtcy5zZWVkLmpzb25cIixcbiAgICAgICAgXCJ1cHN0cmVhbV9wdWxsXCI6IHtcbiAgICAgICAgICBcInVybFwiOiBcImh0dHBzOi8vc2VydmljZS5yZWRwaWxsLmFpL2FwaS9hZG1pbi9nYXRld2F5LXVwc3RyZWFtcy9jb25maWdcIixcbiAgICAgICAgICBcInRva2VuXCI6IFwiJHtQUklWQVRFX0FJX0dBVEVXQVlfUFVMTF9UT0tFTjo/c2V0IFBSSVZBVEVfQUlfR0FURVdBWV9QVUxMX1RPS0VOfVwiLFxuICAgICAgICAgIFwicmVmcmVzaF9zZWNvbmRzXCI6IDMwMCxcbiAgICAgICAgICBcInJlcXVlc3RfdGltZW91dF9zZWNvbmRzXCI6IDkwXG4gICAgICAgIH0sXG4gICAgICAgIFwiYWRtaW5fdG9rZW5cIjogXCIke1BSSVZBVEVfQUlfR0FURVdBWV9BRE1JTl9UT0tFTjo/c2V0IFBSSVZBVEVfQUlfR0FURVdBWV9BRE1JTl9UT0tFTn1cIixcbiAgICAgICAgXCJ0bHNcIjoge1xuICAgICAgICAgIFwiZG9tYWluX2NlcnRpZmljYXRlc1wiOiBbXG4gICAgICAgICAgICB7IFwiZG9tYWluXCI6IFwidGVlLnJlZHBpbGwuYWlcIiwgXCJjZXJ0aWZpY2F0ZV9wYXRoXCI6IFwiL2V2aWRlbmNlcy9jZXJ0LXRlZS5yZWRwaWxsLmFpLnBlbVwiIH0sXG4gICAgICAgICAgICB7IFwiZG9tYWluXCI6IFwiaW5mZXJlbmNlLnBoYWxhLmNvbVwiLCBcImNlcnRpZmljYXRlX3BhdGhcIjogXCIvZXZpZGVuY2VzL2NlcnQtaW5mZXJlbmNlLnBoYWxhLmNvbS5wZW1cIiB9LFxuICAgICAgICAgICAgeyBcImRvbWFpblwiOiBcImFwaS5yZWRwaWxsLmFpXCIsIFwiY2VydGlmaWNhdGVfcGF0aFwiOiBcIi9ldmlkZW5jZXMvY2VydC1hcGkucmVkcGlsbC5haS5wZW1cIiB9LFxuICAgICAgICAgICAgeyBcImRvbWFpblwiOiBcIm9wZW5yb3V0ZXIucGhhbGEuY29tXCIsIFwiY2VydGlmaWNhdGVfcGF0aFwiOiBcIi9ldmlkZW5jZXMvY2VydC1vcGVucm91dGVyLnBoYWxhLmNvbS5wZW1cIiB9XG4gICAgICAgICAgXVxuICAgICAgICB9LFxuICAgICAgICBcIm1pZGRsZXdhcmVcIjoge1xuICAgICAgICAgIFwiY29udHJvbF91cmxcIjogXCIke1BSSVZBVEVfQUlfR0FURVdBWV9DT05UUk9MX1VSTDo/c2V0IFBSSVZBVEVfQUlfR0FURVdBWV9DT05UUk9MX1VSTH1cIixcbiAgICAgICAgICBcImNvbnRyb2xfdG9rZW5cIjogXCIke1BSSVZBVEVfQUlfR0FURVdBWV9DT05UUk9MX1RPS0VOOj9zZXQgUFJJVkFURV9BSV9HQVRFV0FZX0NPTlRST0xfVE9LRU59XCIsXG4gICAgICAgICAgXCJ0ZWVfb25seV9kb21haW5zXCI6IFtcInRlZS5yZWRwaWxsLmFpXCIsIFwiaW5mZXJlbmNlLnBoYWxhLmNvbVwiXVxuICAgICAgICB9XG4gICAgICB9XG4gICMgSW5pdGlhbCB1cHN0cmVhbSByb3V0ZXM6IHNlZWRlZCBpbnRvIDxzdGF0ZV9kaXI+L3Vwc3RyZWFtcy5qc29uIG9ubHkgd2hlbiBlbXB0eSxcbiAgIyB0aGVuIG1hbmFnZWQgYXQgcnVudGltZSB2aWEgUFVUIC92MS9hZG1pbi91cHN0cmVhbXMgKGRvZXMgbm90IHRvdWNoIHRoaXMgZmlsZSkuXG4gIGdhdGV3YXktdXBzdHJlYW1zOlxuICAgIGNvbnRlbnQ6IHxcbiAgICAgIFtdXG4gICMgbm9kZS1leHBvcnRlciBiYXNpYy1hdXRoIGNyZWRlbnRpYWxzLiBleHBvcnRlci10b29sa2l0J3MgYmFzaWNfYXV0aF91c2VycyBtYXBzXG4gICMgdXNlcm5hbWUgLT4gYmNyeXB0IGhhc2g7IGJvdGggYXJlICR7VkFSfSBzbyBkc3RhY2sgc3Vic3RpdHV0ZXMgdGhlIGluamVjdGVkXG4gICMgc2VjcmV0IHZhbHVlcyB3aGVuIHJlbmRlcmluZyB0aGlzIGZpbGUgaW50byB0aGUgY29udGFpbmVyIOKAlCBvbmx5IHRoZSBsaXRlcmFsc1xuICAjIGFyZSBtZWFzdXJlZC4gTk9ERV9FWFBPUlRFUl9QQVNTV09SRF9IQVNIIG11c3QgYmUgYSBiY3J5cHQgaGFzaFxuICAjIChgaHRwYXNzd2QgLW5CQyAxMCBcIlwiIHwgdHIgLWQgJzpcXG4nYCksIE5PVCB0aGUgcGxhaW50ZXh0IHBhc3N3b3JkOyB0aGUgcGxhaW50ZXh0XG4gICMgZ29lcyB0byB0aGUgZXh0ZXJuYWwgUHJvbWV0aGV1cyBzY3JhcGUgY29uZmlnLlxuICBub2RlLWV4cG9ydGVyLXdlYi1jb25maWc6XG4gICAgY29udGVudDogfFxuICAgICAgYmFzaWNfYXV0aF91c2VyczpcbiAgICAgICAgJHtOT0RFX0VYUE9SVEVSX1VTRVI6P3NldCBOT0RFX0VYUE9SVEVSX1VTRVJ9OiAke05PREVfRVhQT1JURVJfUEFTU1dPUkRfSEFTSDo/c2V0IE5PREVfRVhQT1JURVJfUEFTU1dPUkRfSEFTSH1cbiIsImZlYXR1cmVzIjpbImttcyIsInRwcm94eS1uZXQiXSwiZ2F0ZXdheV9lbmFibGVkIjp0cnVlLCJrbXNfZW5hYmxlZCI6dHJ1ZSwibG9jYWxfa2V5X3Byb3ZpZGVyX2VuYWJsZWQiOmZhbHNlLCJtYW5pZmVzdF92ZXJzaW9uIjoyLCJuYW1lIjoiIiwibm9faW5zdGFuY2VfaWQiOmZhbHNlLCJwcmVfbGF1bmNoX3NjcmlwdCI6IiMhL2Jpbi9iYXNoXG5lY2hvIFwiLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVwiXG5lY2hvIFwiUnVubmluZyBQaGFsYSBDbG91ZCBQcmUtTGF1bmNoIFNjcmlwdCB2MC4wLjE1XCJcbmVjaG8gXCItLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXCJcbnNldCAtZVxuXG4jIEZ1bmN0aW9uOiBub3RpZnkgaG9zdFxuXG5ub3RpZnlfaG9zdCgpIHtcbiAgICBpZiBjb21tYW5kIC12IGRzdGFjay11dGlsID4vZGV2L251bGwgMj4mMTsgdGhlblxuICAgICAgICBkc3RhY2stdXRpbCBub3RpZnktaG9zdCAtZSBcIiQxXCIgLWQgXCIkMlwiXG4gICAgZWxzZVxuICAgICAgICB0ZHhjdGwgbm90aWZ5LWhvc3QgLWUgXCIkMVwiIC1kIFwiJDJcIlxuICAgIGZpXG59XG5cbm5vdGlmeV9ob3N0X2hvb3RfaW5mbygpIHtcbiAgICBub3RpZnlfaG9zdCBcImJvb3QucHJvZ3Jlc3NcIiBcIiQxXCJcbn1cblxubm90aWZ5X2hvc3RfaG9vdF9lcnJvcigpIHtcbiAgICBub3RpZnlfaG9zdCBcImJvb3QuZXJyb3JcIiBcIiQxXCJcbn1cblxuIyBGdW5jdGlvbjogUGVyZm9ybSBEb2NrZXIgY2xlYW51cFxucGVyZm9ybV9jbGVhbnVwKCkge1xuICAgIGVjaG8gXCJQcnVuaW5nIHVudXNlZCBpbWFnZXNcIlxuICAgIGRvY2tlciBpbWFnZSBwcnVuZSAtYWZcbiAgICBlY2hvIFwiUHJ1bmluZyB1bnVzZWQgdm9sdW1lc1wiXG4gICAgZG9ja2VyIHZvbHVtZSBwcnVuZSAtZlxuICAgIG5vdGlmeV9ob3N0X2hvb3RfaW5mbyBcImRvY2tlciBjbGVhbnVwIGNvbXBsZXRlZFwiXG59XG5cbiMgRnVuY3Rpb246IENoZWNrIERvY2tlciBsb2dpbiBzdGF0dXMgd2l0aG91dCBleHBvc2luZyBjcmVkZW50aWFsc1xuY2hlY2tfZG9ja2VyX2xvZ2luKCkge1xuICAgIGxvY2FsIHJlZ2lzdHJ5PVwiJDFcIlxuXG4gICAgIyBXaGVuIHJlZ2lzdHJ5IGlzIHNwZWNpZmllZCwgY2hlY2sgYXV0aCBlbnRyeSBmb3IgdGhhdCByZWdpc3RyeSBpbiBEb2NrZXIgY29uZmlnXG4gICAgaWYgW1sgLW4gXCIkcmVnaXN0cnlcIiBdXTsgdGhlblxuICAgICAgICBsb2NhbCBkb2NrZXJfY29uZmlnX3BhdGg9XCIke0RPQ0tFUl9DT05GSUc6LSRIT01FLy5kb2NrZXJ9L2NvbmZpZy5qc29uXCJcbiAgICAgICAgaWYgW1sgLWYgXCIkZG9ja2VyX2NvbmZpZ19wYXRoXCIgXV0gJiYgZ3JlcCAtcSBcIiRyZWdpc3RyeVwiIFwiJGRvY2tlcl9jb25maWdfcGF0aFwiOyB0aGVuXG4gICAgICAgICAgICByZXR1cm4gMFxuICAgICAgICBlbHNlXG4gICAgICAgICAgICByZXR1cm4gMVxuICAgICAgICBmaVxuICAgIGZpXG5cbiAgICAjIEZhbGxiYWNrIGNoZWNrIHdoZW4gbm8gZXhwbGljaXQgcmVnaXN0cnkgaXMgcHJvdmlkZWRcbiAgICBpZiBkb2NrZXIgaW5mbyAyPi9kZXYvbnVsbCB8IGdyZXAgLXEgXCJVc2VybmFtZVwiOyB0aGVuXG4gICAgICAgIHJldHVybiAwXG4gICAgZWxzZVxuICAgICAgICByZXR1cm4gMVxuICAgIGZpXG59XG5cbiMgTWFpbiBsb2dpYyBzdGFydHMgaGVyZVxuZWNobyBcIlN0YXJ0aW5nIGxvZ2luIHByb2Nlc3MuLi5cIlxuXG4jIENoZWNrIGlmIERvY2tlciBjcmVkZW50aWFscyBleGlzdFxuaWYgW1sgLW4gXCIkRFNUQUNLX0RPQ0tFUl9VU0VSTkFNRVwiICYmIC1uIFwiJERTVEFDS19ET0NLRVJfUEFTU1dPUkRcIiBdXTsgdGhlblxuICAgIGVjaG8gXCJEb2NrZXIgY3JlZGVudGlhbHMgZm91bmRcIlxuICAgIERPQ0tFUl9SRUdJU1RSWV9UQVJHRVQ9XCIke0RTVEFDS19ET0NLRVJfUkVHSVNUUlk6LWRvY2tlci5pb31cIlxuICAgIGVjaG8gXCJUYXJnZXQgRG9ja2VyIHJlZ2lzdHJ5OiAkRE9DS0VSX1JFR0lTVFJZX1RBUkdFVFwiXG5cbiAgICAjIENoZWNrIGlmIGFscmVhZHkgbG9nZ2VkIGluXG4gICAgaWYgY2hlY2tfZG9ja2VyX2xvZ2luIFwiJERTVEFDS19ET0NLRVJfUkVHSVNUUllcIjsgdGhlblxuICAgICAgICBlY2hvIFwiQWxyZWFkeSBsb2dnZWQgaW4gdG8gRG9ja2VyIHJlZ2lzdHJ5OiAkRE9DS0VSX1JFR0lTVFJZX1RBUkdFVFwiXG4gICAgZWxzZVxuICAgICAgICBlY2hvIFwiTG9nZ2luZyBpbiB0byBEb2NrZXIgcmVnaXN0cnk6ICRET0NLRVJfUkVHSVNUUllfVEFSR0VUXCJcbiAgICAgICAgIyBMb2dpbiB3aXRob3V0IGV4cG9zaW5nIHBhc3N3b3JkIGluIHByb2Nlc3MgbGlzdFxuICAgICAgICBpZiBbWyAtbiBcIiREU1RBQ0tfRE9DS0VSX1JFR0lTVFJZXCIgXV07IHRoZW5cbiAgICAgICAgICAgIGVjaG8gXCIkRFNUQUNLX0RPQ0tFUl9QQVNTV09SRFwiIHwgZG9ja2VyIGxvZ2luIC11IFwiJERTVEFDS19ET0NLRVJfVVNFUk5BTUVcIiAtLXBhc3N3b3JkLXN0ZGluIFwiJERTVEFDS19ET0NLRVJfUkVHSVNUUllcIlxuICAgICAgICBlbHNlXG4gICAgICAgICAgICBlY2hvIFwiJERTVEFDS19ET0NLRVJfUEFTU1dPUkRcIiB8IGRvY2tlciBsb2dpbiAtdSBcIiREU1RBQ0tfRE9DS0VSX1VTRVJOQU1FXCIgLS1wYXNzd29yZC1zdGRpblxuICAgICAgICBmaVxuXG4gICAgICAgIGlmIFsgJD8gLWVxIDAgXTsgdGhlblxuICAgICAgICAgICAgZWNobyBcIkRvY2tlciBsb2dpbiBzdWNjZXNzZnVsOiAkRE9DS0VSX1JFR0lTVFJZX1RBUkdFVFwiXG4gICAgICAgIGVsc2VcbiAgICAgICAgICAgIGVjaG8gXCJEb2NrZXIgbG9naW4gZmFpbGVkOiAkRE9DS0VSX1JFR0lTVFJZX1RBUkdFVFwiXG4gICAgICAgICAgICBub3RpZnlfaG9zdF9ob290X2Vycm9yIFwiZG9ja2VyIGxvZ2luIGZhaWxlZFwiXG4gICAgICAgICAgICBleGl0IDFcbiAgICAgICAgZmlcbiAgICBmaVxuIyBDaGVjayBpZiBBV1MgRUNSIGNyZWRlbnRpYWxzIGV4aXN0XG5lbGlmIFtbIC1uIFwiJERTVEFDS19BV1NfQUNDRVNTX0tFWV9JRFwiICYmIC1uIFwiJERTVEFDS19BV1NfU0VDUkVUX0FDQ0VTU19LRVlcIiAmJiAtbiBcIiREU1RBQ0tfQVdTX1JFR0lPTlwiICYmIC1uIFwiJERTVEFDS19BV1NfRUNSX1JFR0lTVFJZXCIgXV07IHRoZW5cbiAgICBlY2hvIFwiQVdTIEVDUiBjcmVkZW50aWFscyBmb3VuZFwiXG5cbiAgICAjIENoZWNrIGlmIEFXUyBDTEkgaXMgaW5zdGFsbGVkXG4gICAgaWYgWyAhIC1mIFwiLi9hd3MvZGlzdC9hd3NcIiBdOyB0aGVuXG4gICAgICAgIG5vdGlmeV9ob3N0X2hvb3RfaW5mbyBcImF3c2NsaSBub3QgaW5zdGFsbGVkLCBpbnN0YWxsaW5nLi4uXCJcbiAgICAgICAgZWNobyBcIkFXUyBDTEkgbm90IGluc3RhbGxlZCwgaW5zdGFsbGluZy4uLlwiXG4gICAgICAgIGN1cmwgXCJodHRwczovL2F3c2NsaS5hbWF6b25hd3MuY29tL2F3c2NsaS1leGUtbGludXgteDg2XzY0LTIuMjQuMTQuemlwXCIgLW8gXCJhd3NjbGl2Mi56aXBcIlxuICAgICAgICBlY2hvIFwiNmZmMDMxYTI2ZGY3ZGFlYmJmYTNjY2RkYzlhZjE0NTAgYXdzY2xpdjIuemlwXCIgfCBtZDVzdW0gLWNcbiAgICAgICAgaWYgWyAkPyAtbmUgMCBdOyB0aGVuXG4gICAgICAgICAgICBlY2hvIFwiTUQ1IGNoZWNrc3VtIGZhaWxlZFwiXG4gICAgICAgICAgICBub3RpZnlfaG9zdF9ob290X2Vycm9yIFwiYXdzY2xpIGluc3RhbGwgZmFpbGVkXCJcbiAgICAgICAgICAgIGV4aXQgMVxuICAgICAgICBmaVxuICAgICAgICB1bnppcCBhd3NjbGl2Mi56aXAgJj4gL2Rldi9udWxsXG4gICAgZWxzZVxuICAgICAgICBlY2hvIFwiQVdTIENMSSBpcyBhbHJlYWR5IGluc3RhbGxlZDogLi9hd3MvZGlzdC9hd3NcIlxuICAgIGZpXG5cbiAgICAjIFNldCBBV1MgY3JlZGVudGlhbHMgYXMgZW52aXJvbm1lbnQgdmFyaWFibGVzXG4gICAgZXhwb3J0IEFXU19BQ0NFU1NfS0VZX0lEPVwiJERTVEFDS19BV1NfQUNDRVNTX0tFWV9JRFwiXG4gICAgZXhwb3J0IEFXU19TRUNSRVRfQUNDRVNTX0tFWT1cIiREU1RBQ0tfQVdTX1NFQ1JFVF9BQ0NFU1NfS0VZXCJcbiAgICBleHBvcnQgQVdTX0RFRkFVTFRfUkVHSU9OPVwiJERTVEFDS19BV1NfUkVHSU9OXCJcblxuICAgICMgU2V0IHNlc3Npb24gdG9rZW4gaWYgcHJvdmlkZWQgKGZvciB0ZW1wb3JhcnkgY3JlZGVudGlhbHMpXG4gICAgaWYgW1sgLW4gXCIkRFNUQUNLX0FXU19TRVNTSU9OX1RPS0VOXCIgXV07IHRoZW5cbiAgICAgICAgZWNobyBcIkFXUyBzZXNzaW9uIHRva2VuIGZvdW5kLCB1c2luZyB0ZW1wb3JhcnkgY3JlZGVudGlhbHNcIlxuICAgICAgICBleHBvcnQgQVdTX1NFU1NJT05fVE9LRU49XCIkRFNUQUNLX0FXU19TRVNTSU9OX1RPS0VOXCJcbiAgICBmaVxuXG4gICAgIyBUZXN0IEFXUyBjcmVkZW50aWFscyBiZWZvcmUgYXR0ZW1wdGluZyBFQ1IgbG9naW5cbiAgICBlY2hvIFwiVGVzdGluZyBBV1MgY3JlZGVudGlhbHMuLi5cIlxuICAgIGlmICEgLi9hd3MvZGlzdC9hd3Mgc3RzIGdldC1jYWxsZXItaWRlbnRpdHkgJj4gL2Rldi9udWxsOyB0aGVuXG4gICAgICAgIGVjaG8gXCJBV1MgY3JlZGVudGlhbHMgdGVzdCBmYWlsZWRcIlxuICAgICAgICAjIEZvciBzZXNzaW9uIHRva2VuIGNyZWRlbnRpYWxzLCB0aGlzIG1pZ2h0IGJlIGV4cGVjdGVkIGlmIHRoZXkncmUgZXhwaXJlZFxuICAgICAgICAjIExvZyB3YXJuaW5nIGJ1dCBkb24ndCBmYWlsIHN0YXJ0dXBcbiAgICAgICAgaWYgW1sgLW4gXCIkRFNUQUNLX0FXU19TRVNTSU9OX1RPS0VOXCIgXV07IHRoZW5cbiAgICAgICAgICAgIGVjaG8gXCJXYXJuaW5nOiBBV1MgdGVtcG9yYXJ5IGNyZWRlbnRpYWxzIG1heSBoYXZlIGV4cGlyZWQsIGNvbnRpbnVpbmcgc3RhcnR1cFwiXG4gICAgICAgICAgICBub3RpZnlfaG9zdF9ob290X2luZm8gXCJBV1MgdGVtcG9yYXJ5IGNyZWRlbnRpYWxzIG1heSBoYXZlIGV4cGlyZWRcIlxuICAgICAgICBlbHNlXG4gICAgICAgICAgICBlY2hvIFwiQVdTIGNyZWRlbnRpYWxzIHRlc3QgZmFpbGVkXCJcbiAgICAgICAgICAgIG5vdGlmeV9ob3N0X2hvb3RfZXJyb3IgXCJJbnZhbGlkIEFXUyBjcmVkZW50aWFsc1wiXG4gICAgICAgICAgICBleGl0IDFcbiAgICAgICAgZmlcbiAgICBlbHNlXG4gICAgICAgIGVjaG8gXCJMb2dnaW5nIGluIHRvIEFXUyBFQ1IuLi5cIlxuICAgICAgICAuL2F3cy9kaXN0L2F3cyBlY3IgZ2V0LWxvZ2luLXBhc3N3b3JkIC0tcmVnaW9uICREU1RBQ0tfQVdTX1JFR0lPTiB8IGRvY2tlciBsb2dpbiAtLXVzZXJuYW1lIEFXUyAtLXBhc3N3b3JkLXN0ZGluIFwiJERTVEFDS19BV1NfRUNSX1JFR0lTVFJZXCJcbiAgICAgICAgaWYgWyAkPyAtZXEgMCBdOyB0aGVuXG4gICAgICAgICAgICBlY2hvIFwiQVdTIEVDUiBsb2dpbiBzdWNjZXNzZnVsXCJcbiAgICAgICAgICAgIG5vdGlmeV9ob3N0X2hvb3RfaW5mbyBcIkFXUyBFQ1IgbG9naW4gc3VjY2Vzc2Z1bFwiXG4gICAgICAgIGVsc2VcbiAgICAgICAgICAgIGVjaG8gXCJBV1MgRUNSIGxvZ2luIGZhaWxlZFwiXG4gICAgICAgICAgICAjIEZvciBzZXNzaW9uIHRva2VuIGNyZWRlbnRpYWxzLCBkb24ndCBmYWlsIHN0YXJ0dXAgaWYgbG9naW4gZmFpbHNcbiAgICAgICAgICAgIGlmIFtbIC1uIFwiJERTVEFDS19BV1NfU0VTU0lPTl9UT0tFTlwiIF1dOyB0aGVuXG4gICAgICAgICAgICAgICAgZWNobyBcIldhcm5pbmc6IEFXUyBFQ1IgbG9naW4gZmFpbGVkIHdpdGggdGVtcG9yYXJ5IGNyZWRlbnRpYWxzLCBjb250aW51aW5nIHN0YXJ0dXBcIlxuICAgICAgICAgICAgICAgIG5vdGlmeV9ob3N0X2hvb3RfaW5mbyBcIkFXUyBFQ1IgbG9naW4gZmFpbGVkIHdpdGggdGVtcG9yYXJ5IGNyZWRlbnRpYWxzXCJcbiAgICAgICAgICAgIGVsc2VcbiAgICAgICAgICAgICAgICBub3RpZnlfaG9zdF9ob290X2Vycm9yIFwiQVdTIEVDUiBsb2dpbiBmYWlsZWRcIlxuICAgICAgICAgICAgICAgIGV4aXQgMVxuICAgICAgICAgICAgZmlcbiAgICAgICAgZmlcbiAgICBmaVxuZmlcblxucGVyZm9ybV9jbGVhbnVwXG5cbiNcbiMgR0hDUiBpbWFnZSBwdWxsIGFjY2VzcyB2ZXJpZmljYXRpb24gKHB1cmUgSFRUUCwgbm8gZG9ja2VyIGRhZW1vbilcbiNcbmlmIFtbIFwiJERPQ0tFUl9SRUdJU1RSWV9UQVJHRVRcIiA9PSBcImdoY3IuaW9cIiAmJiAtbiBcIiREU1RBQ0tfRE9DS0VSX1VTRVJOQU1FXCIgJiYgLW4gXCIkRFNUQUNLX0RPQ0tFUl9QQVNTV09SRFwiIF1dOyB0aGVuXG4gICAgQ09NUE9TRV9JTUFHRVM9JChncmVwICdpbWFnZTonIC9kc3RhY2svZG9ja2VyLWNvbXBvc2UueWFtbCAyPi9kZXYvbnVsbCB8IGF3ayAne3ByaW50ICQyfScgfCB0ciAtZCAnXCInXCInXCIgfHwgdHJ1ZSlcbiAgICBmb3IgaW1nIGluICRDT01QT1NFX0lNQUdFUzsgZG9cbiAgICAgICAgW1sgXCIkaW1nXCIgIT0gZ2hjci5pby8qIF1dICYmIGNvbnRpbnVlXG4gICAgICAgIHJlcG89XCIke2ltZyNnaGNyLmlvL31cIjsgcmVwbz1cIiR7cmVwbyUlOip9XCJcbiAgICAgICAgdGFnPVwiJHtpbWcjIyo6fVwiOyBbWyBcIiR0YWdcIiA9PSBcIiRpbWdcIiB8fCBcIiR0YWdcIiA9PSBcIiRyZXBvXCIgXV0gJiYgdGFnPVwibGF0ZXN0XCJcbiAgICAgICAgZWNobyBcIlZlcmlmeWluZyBHSENSIHB1bGwgYWNjZXNzOiAkaW1nXCJcbiAgICAgICAgdG9rZW49JChjdXJsIC1zZiAtdSBcIiREU1RBQ0tfRE9DS0VSX1VTRVJOQU1FOiREU1RBQ0tfRE9DS0VSX1BBU1NXT1JEXCIgICAgICAgICAgICAgXCJodHRwczovL2doY3IuaW8vdG9rZW4/c2VydmljZT1naGNyLmlvJnNjb3BlPXJlcG9zaXRvcnk6JHtyZXBvfTpwdWxsXCIgfCBqcSAtciAnLnRva2VuIC8vIGVtcHR5JyB8fCB0cnVlKVxuICAgICAgICBpZiBbWyAteiBcIiR0b2tlblwiIF1dOyB0aGVuXG4gICAgICAgICAgICBlY2hvIFwiRVJST1I6IEdIQ1IgdG9rZW4gZXhjaGFuZ2UgZmFpbGVkIGZvciAkaW1nXCJcbiAgICAgICAgICAgIG5vdGlmeV9ob3N0X2hvb3RfZXJyb3IgXCJHSENSIHRva2VuIGV4Y2hhbmdlIGZhaWxlZDogJGltZ1wiXG4gICAgICAgICAgICBleGl0IDFcbiAgICAgICAgZmlcbiAgICAgICAgaHR0cF9jb2RlPSQoY3VybCAtcyAtbyAvZGV2L251bGwgLXcgXCIle2h0dHBfY29kZX1cIiAtSCBcIkF1dGhvcml6YXRpb246IEJlYXJlciAkdG9rZW5cIiAgICAgICAgICAgICAtSCBcIkFjY2VwdDogYXBwbGljYXRpb24vdm5kLm9jaS5pbWFnZS5pbmRleC52MStqc29uLGFwcGxpY2F0aW9uL3ZuZC5vY2kuaW1hZ2UubWFuaWZlc3QudjEranNvbixhcHBsaWNhdGlvbi92bmQuZG9ja2VyLmRpc3RyaWJ1dGlvbi5tYW5pZmVzdC5saXN0LnYyK2pzb24sYXBwbGljYXRpb24vdm5kLmRvY2tlci5kaXN0cmlidXRpb24ubWFuaWZlc3QudjIranNvblwiICAgICAgICAgICAgIFwiaHR0cHM6Ly9naGNyLmlvL3YyLyR7cmVwb30vbWFuaWZlc3RzLyR7dGFnfVwiKVxuICAgICAgICBpZiBbWyBcIiRodHRwX2NvZGVcIiAhPSBcIjIwMFwiIF1dOyB0aGVuXG4gICAgICAgICAgICBlY2hvIFwiRVJST1I6IEdIQ1IgcHVsbCBhY2Nlc3MgZGVuaWVkIGZvciAkaW1nIChIVFRQICRodHRwX2NvZGUpXCJcbiAgICAgICAgICAgIG5vdGlmeV9ob3N0X2hvb3RfZXJyb3IgXCJHSENSIHB1bGwgYWNjZXNzIGRlbmllZDogJGltZyAoSFRUUCAkaHR0cF9jb2RlKVwiXG4gICAgICAgICAgICBleGl0IDFcbiAgICAgICAgZmlcbiAgICAgICAgZWNobyBcIkdIQ1IgcHVsbCBhY2Nlc3MgT0s6ICRpbWdcIlxuICAgIGRvbmVcbmZpXG5cbiNcbiMgUHVsbCBsYXRlc3QgaW1hZ2VzIGZyb20gZG9ja2VyLWNvbXBvc2UueWFtbCBzbyBleGlzdGluZyBDVk1zIHBpY2sgdXAgbmV3IHRhZ3MuXG4jIFB1bGwgaXMgZmFpbC1zb2Z0OiBzaG9ydC1saXZlZCB0b2tlbnMgbWF5IGV4cGlyZSBiZXR3ZWVuIGxvZ2luIGFuZCBwdWxsLCBidXRcbiMgZmFsbGluZyBiYWNrIHRvIGFscmVhZHktY2FjaGVkIGltYWdlcyBpcyBwcmVmZXJhYmxlIHRvIGJsb2NraW5nIGJvb3QuXG4jXG5lY2hvIFwiSW1hZ2VzIGJlZm9yZSBwdWxsOlwiXG5kb2NrZXIgaW1hZ2VzIC0tZm9ybWF0ICd7ey5SZXBvc2l0b3J5fX06e3suVGFnfX0ge3suSUR9fSAoe3suQ3JlYXRlZFNpbmNlfX0pJ1xuXG5lY2hvIFwiUHVsbGluZyBsYXRlc3QgaW1hZ2VzIGZyb20gL2RzdGFjay9kb2NrZXItY29tcG9zZS55YW1sLi4uXCJcbmlmIGRvY2tlciBjb21wb3NlIC1mIC9kc3RhY2svZG9ja2VyLWNvbXBvc2UueWFtbCBwdWxsOyB0aGVuXG4gICAgZWNobyBcImRvY2tlciBjb21wb3NlIHB1bGwgY29tcGxldGVkXCJcbiAgICBub3RpZnlfaG9zdF9ob290X2luZm8gXCJkb2NrZXIgY29tcG9zZSBwdWxsIGNvbXBsZXRlZFwiXG5lbHNlXG4gICAgZWNobyBcIldBUk5JTkc6IGRvY2tlciBjb21wb3NlIHB1bGwgZmFpbGVkOyBjb250aW51aW5nIHdpdGggZXhpc3RpbmcgaW1hZ2VzXCJcbiAgICBub3RpZnlfaG9zdF9ob290X2luZm8gXCJkb2NrZXIgY29tcG9zZSBwdWxsIGZhaWxlZDsgdXNpbmcgZXhpc3RpbmcgaW1hZ2VzXCJcbmZpXG5cbmVjaG8gXCJJbWFnZXMgYWZ0ZXIgcHVsbDpcIlxuZG9ja2VyIGltYWdlcyAtLWZvcm1hdCAne3suUmVwb3NpdG9yeX19Ont7LlRhZ319IHt7LklEfX0gKHt7LkNyZWF0ZWRTaW5jZX19KSdcblxuI1xuIyBTZXQgcm9vdCBwYXNzd29yZC5cbiNcbmVjaG8gXCJTZXR0aW5nIHJvb3QgcGFzc3dvcmQuLlwiXG5cbiMgQ2hlY2sgaWYgcGFzc3dvcmQgZmlsZXMgYXJlIHdyaXRhYmxlXG5QQVNTV0RfV1JJVEFCTEU9dHJ1ZVxuaWYgWyAhIC13IC9ldGMvcGFzc3dkIF07IHRoZW5cbiAgICBlY2hvIFwiV2FybmluZzogL2V0Yy9wYXNzd2QgaXMgcmVhZC1vbmx5XCJcbiAgICBQQVNTV0RfV1JJVEFCTEU9ZmFsc2VcbmZpXG5pZiBbICEgLXcgL2V0Yy9zaGFkb3cgXTsgdGhlblxuICAgIGVjaG8gXCJXYXJuaW5nOiAvZXRjL3NoYWRvdyBpcyByZWFkLW9ubHlcIlxuICAgIFBBU1NXRF9XUklUQUJMRT1mYWxzZVxuZmlcblxuaWYgWyBcIiRQQVNTV0RfV1JJVEFCTEVcIiA9IFwiZmFsc2VcIiBdOyB0aGVuXG4gICAgZWNobyBcIlNraXBwaW5nIHBhc3N3b3JkIHNldHVwIGR1ZSB0byByZWFkLW9ubHkgZmlsZSBzeXN0ZW1cIlxuZWxzZVxuICAgICMgQ2hlY2sgaWYgY2hwYXNzd2QgaXMgYXZhaWxhYmxlXG4gICAgaWYgY29tbWFuZCAtdiBjaHBhc3N3ZCA+L2Rldi9udWxsIDI+JjE7IHRoZW5cbiAgICAgICAgZWNobyBcIlVzaW5nIGNocGFzc3dkIG1ldGhvZFwiXG5cbiAgICAgICAgaWYgWyAtbiBcIiREU1RBQ0tfUk9PVF9QQVNTV09SRFwiIF07IHRoZW5cbiAgICAgICAgICAgIGVjaG8gXCJTZXR0aW5nIHJvb3QgcGFzc3dvcmQgZnJvbSB1c2VyLi5cIlxuICAgICAgICAgICAgZWNobyBcInJvb3Q6JERTVEFDS19ST09UX1BBU1NXT1JEXCIgfCBjaHBhc3N3ZFxuICAgICAgICAgICAgdW5zZXQgRFNUQUNLX1JPT1RfUEFTU1dPUkRcbiAgICAgICAgICAgIGVjaG8gXCJSb290IHBhc3N3b3JkIHNldC91cGRhdGVkIGZyb20gRFNUQUNLX1JPT1RfUEFTU1dPUkRcIlxuICAgICAgICBlbGlmIFsgLXogXCIkKGdyZXAgJ15yb290OicgL2V0Yy9zaGFkb3cgMj4vZGV2L251bGwgfCBjdXQgLWQ6IC1mMilcIiBdOyB0aGVuXG4gICAgICAgICAgICBlY2hvIFwiU2V0dGluZyByYW5kb20gcm9vdCBwYXNzd29yZC4uXCJcbiAgICAgICAgICAgIERTVEFDS19ST09UX1BBU1NXT1JEPSQoXG4gICAgICAgICAgICAgICAgTENfQUxMPUMgdHIgLWRjICdBLVphLXowLTknIDwgL2Rldi91cmFuZG9tIHwgZGQgYnM9MSBjb3VudD0zMiAyPi9kZXYvbnVsbFxuICAgICAgICAgICAgKVxuICAgICAgICAgICAgZWNobyBcInJvb3Q6JERTVEFDS19ST09UX1BBU1NXT1JEXCIgfCBjaHBhc3N3ZFxuICAgICAgICAgICAgdW5zZXQgRFNUQUNLX1JPT1RfUEFTU1dPUkRcbiAgICAgICAgICAgIGVjaG8gXCJSb290IHBhc3N3b3JkIHNldCAocmFuZG9tIGF1dG8taW5pdClcIlxuICAgICAgICBlbHNlXG4gICAgICAgICAgICBlY2hvIFwiUm9vdCBwYXNzd29yZCBhbHJlYWR5IHNldDsgbm8gY2hhbmdlcy5cIlxuICAgICAgICBmaVxuICAgIGVsc2VcbiAgICAgICAgZWNobyBcIlVzaW5nIHBhc3N3ZCBtZXRob2RcIlxuXG4gICAgICAgIGlmIFsgLW4gXCIkRFNUQUNLX1JPT1RfUEFTU1dPUkRcIiBdOyB0aGVuXG4gICAgICAgICAgICBlY2hvIFwiU2V0dGluZyByb290IHBhc3N3b3JkIGZyb20gdXNlci4uXCJcbiAgICAgICAgICAgIGVjaG8gXCIkRFNUQUNLX1JPT1RfUEFTU1dPUkRcIiB8IHBhc3N3ZCAtLXN0ZGluIHJvb3QgMj4vZGV2L251bGwgICAgICAgICAgICAgICAgIHx8IHByaW50ZiAnJXNcbiVzXG4nIFwiJERTVEFDS19ST09UX1BBU1NXT1JEXCIgXCIkRFNUQUNLX1JPT1RfUEFTU1dPUkRcIiB8IHBhc3N3ZCByb290XG4gICAgICAgICAgICB1bnNldCBEU1RBQ0tfUk9PVF9QQVNTV09SRFxuICAgICAgICAgICAgZWNobyBcIlJvb3QgcGFzc3dvcmQgc2V0L3VwZGF0ZWQgZnJvbSBEU1RBQ0tfUk9PVF9QQVNTV09SRFwiXG4gICAgICAgIGVsaWYgWyAteiBcIiQoZ3JlcCAnXnJvb3Q6JyAvZXRjL3NoYWRvdyAyPi9kZXYvbnVsbCB8IGN1dCAtZDogLWYyKVwiIF07IHRoZW5cbiAgICAgICAgICAgIGVjaG8gXCJTZXR0aW5nIHJhbmRvbSByb290IHBhc3N3b3JkLi5cIlxuICAgICAgICAgICAgRFNUQUNLX1JPT1RfUEFTU1dPUkQ9JChcbiAgICAgICAgICAgICAgICBMQ19BTEw9QyB0ciAtZGMgJ0EtWmEtejAtOScgPCAvZGV2L3VyYW5kb20gfCBkZCBicz0xIGNvdW50PTMyIDI+L2Rldi9udWxsXG4gICAgICAgICAgICApXG4gICAgICAgICAgICBlY2hvIFwiJERTVEFDS19ST09UX1BBU1NXT1JEXCIgfCBwYXNzd2QgLS1zdGRpbiByb290IDI+L2Rldi9udWxsICAgICAgICAgICAgICAgICB8fCBwcmludGYgJyVzXG4lc1xuJyBcIiREU1RBQ0tfUk9PVF9QQVNTV09SRFwiIFwiJERTVEFDS19ST09UX1BBU1NXT1JEXCIgfCBwYXNzd2Qgcm9vdFxuICAgICAgICAgICAgdW5zZXQgRFNUQUNLX1JPT1RfUEFTU1dPUkRcbiAgICAgICAgICAgIGVjaG8gXCJSb290IHBhc3N3b3JkIHNldCAocmFuZG9tIGF1dG8taW5pdClcIlxuICAgICAgICBlbHNlXG4gICAgICAgICAgICBlY2hvIFwiUm9vdCBwYXNzd29yZCBhbHJlYWR5IHNldDsgbm8gY2hhbmdlcy5cIlxuICAgICAgICBmaVxuICAgIGZpXG5maVxuXG4jXG4jIFNldCBTU0ggYXV0aG9yaXplZCBrZXlzXG4jXG5pZiBta2RpciAtcCAvaG9tZS9yb290Ly5zc2ggMj4vZGV2L251bGw7IHRoZW5cbiAgICBpZiBbWyAtbiBcIiREU1RBQ0tfUk9PVF9QVUJMSUNfS0VZXCIgXV07IHRoZW5cbiAgICAgICAgZWNobyBcIiREU1RBQ0tfUk9PVF9QVUJMSUNfS0VZXCIgPiAvaG9tZS9yb290Ly5zc2gvYXV0aG9yaXplZF9rZXlzXG4gICAgICAgIHVuc2V0ICREU1RBQ0tfUk9PVF9QVUJMSUNfS0VZXG4gICAgICAgIGVjaG8gXCJSb290IHB1YmxpYyBrZXkgc2V0XCJcbiAgICBmaVxuICAgIGlmIFtbIC1uIFwiJERTVEFDS19BVVRIT1JJWkVEX0tFWVNcIiBdXTsgdGhlblxuICAgICAgICBlY2hvIFwiJERTVEFDS19BVVRIT1JJWkVEX0tFWVNcIiA+IC9ob21lL3Jvb3QvLnNzaC9hdXRob3JpemVkX2tleXNcbiAgICAgICAgdW5zZXQgJERTVEFDS19BVVRIT1JJWkVEX0tFWVNcbiAgICAgICAgZWNobyBcIlJvb3QgYXV0aG9yaXplZF9rZXlzIHNldFwiXG4gICAgZmlcblxuICAgIGlmIFtbIC1mIC9kc3RhY2svdXNlcl9jb25maWcgXV0gJiYganEgZW1wdHkgL2RzdGFjay91c2VyX2NvbmZpZyAyPi9kZXYvbnVsbDsgdGhlblxuICAgICAgICBpZiBbWyAkKGpxICdoYXMoXCJzc2hfYXV0aG9yaXplZF9rZXlzXCIpJyAvZHN0YWNrL3VzZXJfY29uZmlnIDI+L2Rldi9udWxsKSA9PSBcInRydWVcIiBdXTsgdGhlblxuICAgICAgICAgICAganEgLWogJy5zc2hfYXV0aG9yaXplZF9rZXlzJyAvZHN0YWNrL3VzZXJfY29uZmlnID4+IC9ob21lL3Jvb3QvLnNzaC9hdXRob3JpemVkX2tleXNcbiAgICAgICAgICAgICMgUmVtb3ZlIGR1cGxpY2F0ZXMgaWYgdGhlcmUgYXJlIG11bHRpcGxlIGtleXNcbiAgICAgICAgICAgIGlmIFtbICQoY2F0IC9ob21lL3Jvb3QvLnNzaC9hdXRob3JpemVkX2tleXMgfCB3YyAtbCkgLWd0IDEgXV07IHRoZW5cbiAgICAgICAgICAgICAgICBzb3J0IC11IC9ob21lL3Jvb3QvLnNzaC9hdXRob3JpemVkX2tleXMgPiAvaG9tZS9yb290Ly5zc2gvYXV0aG9yaXplZF9rZXlzLnRtcFxuICAgICAgICAgICAgICAgIG12IC9ob21lL3Jvb3QvLnNzaC9hdXRob3JpemVkX2tleXMudG1wIC9ob21lL3Jvb3QvLnNzaC9hdXRob3JpemVkX2tleXNcbiAgICAgICAgICAgIGZpXG4gICAgICAgICAgICBlY2hvIFwiU2V0IHJvb3QgYXV0aG9yaXplZF9rZXlzIGZyb20gdXNlciBwcmVmZXJlbmNlcywgdG90YWxcIiAkKGNhdCAvaG9tZS9yb290Ly5zc2gvYXV0aG9yaXplZF9rZXlzIHwgd2MgLWwpIFwia2V5c1wiXG4gICAgICAgIGZpXG4gICAgZmlcbmVsc2VcbiAgICBlY2hvIFwiV2FybmluZzogQ2Fubm90IGNyZWF0ZSAvaG9tZS9yb290Ly5zc2ggZGlyZWN0b3J5IChyZWFkLW9ubHkgZmlsZSBzeXN0ZW0/KVwiXG4gICAgZWNobyBcIlNraXBwaW5nIFNTSCBrZXkgc2V0dXBcIlxuZmlcblxuaWYgW1sgLVMgL3Zhci9ydW4vZHN0YWNrLnNvY2sgXV07IHRoZW5cbiAgICBleHBvcnQgRFNUQUNLX0FQUF9JRD0kKGN1cmwgLXMgLS11bml4LXNvY2tldCAvdmFyL3J1bi9kc3RhY2suc29jayBodHRwOi8vZHN0YWNrL0luZm8gfCBqcSAtaiAuYXBwX2lkKVxuZWxpZiBbWyAtUyAvdmFyL3J1bi90YXBwZC5zb2NrIF1dOyB0aGVuXG4gICAgZXhwb3J0IERTVEFDS19BUFBfSUQ9JChjdXJsIC1zIC0tdW5peC1zb2NrZXQgL3Zhci9ydW4vdGFwcGQuc29jayBodHRwOi8vZHN0YWNrL3BycGMvVGFwcGQuSW5mbyB8IGpxIC1qIC5hcHBfaWQpXG5maVxuIyBDaGVjayBpZiBEU1RBQ0tfR0FURVdBWV9ET01BSU4gaXMgbm90IHNldCwgdHJ5IHRvIGdldCBpdCBmcm9tIHVzZXJfY29uZmlnIG9yIGFwcC1jb21wb3NlLmpzb25cbiMgUHJpb3JpdHk6IHVzZXJfY29uZmlnID4gYXBwLWNvbXBvc2UuanNvblxuaWYgW1sgLXogXCIkRFNUQUNLX0dBVEVXQVlfRE9NQUlOXCIgXV07IHRoZW5cbiAgICAjIEZpcnN0IHRyeSB0byBnZXQgZnJvbSAvZHN0YWNrL3VzZXJfY29uZmlnIGlmIGl0IGV4aXN0cyBhbmQgaXMgdmFsaWQgSlNPTlxuICAgIGlmIFtbIC1mIC9kc3RhY2svdXNlcl9jb25maWcgXV0gJiYganEgZW1wdHkgL2RzdGFjay91c2VyX2NvbmZpZyAyPi9kZXYvbnVsbDsgdGhlblxuICAgICAgICBpZiBbWyAkKGpxICdoYXMoXCJkZWZhdWx0X2dhdGV3YXlfZG9tYWluXCIpJyAvZHN0YWNrL3VzZXJfY29uZmlnIDI+L2Rldi9udWxsKSA9PSBcInRydWVcIiBdXTsgdGhlblxuICAgICAgICAgICAgZXhwb3J0IERTVEFDS19HQVRFV0FZX0RPTUFJTj0kKGpxIC1qICcuZGVmYXVsdF9nYXRld2F5X2RvbWFpbicgL2RzdGFjay91c2VyX2NvbmZpZylcbiAgICAgICAgZmlcbiAgICBmaVxuXG4gICAgIyBJZiBzdGlsbCBub3Qgc2V0LCB0cnkgdG8gZ2V0IGZyb20gYXBwLWNvbXBvc2UuanNvblxuICAgIGlmIFtbIC16IFwiJERTVEFDS19HQVRFV0FZX0RPTUFJTlwiIF1dICYmIFtbICQoanEgJ2hhcyhcImRlZmF1bHRfZ2F0ZXdheV9kb21haW5cIiknIGFwcC1jb21wb3NlLmpzb24pID09IFwidHJ1ZVwiIF1dOyB0aGVuXG4gICAgICAgIGV4cG9ydCBEU1RBQ0tfR0FURVdBWV9ET01BSU49JChqcSAtaiAnLmRlZmF1bHRfZ2F0ZXdheV9kb21haW4nIGFwcC1jb21wb3NlLmpzb24pXG4gICAgZmlcbmZpXG5pZiBbWyAtbiBcIiREU1RBQ0tfR0FURVdBWV9ET01BSU5cIiBdXTsgdGhlblxuICAgIGV4cG9ydCBEU1RBQ0tfQVBQX0RPTUFJTj0kRFNUQUNLX0FQUF9JRFwiLlwiJERTVEFDS19HQVRFV0FZX0RPTUFJTlxuZmlcblxuZWNobyBcIi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cIlxuZWNobyBcIlNjcmlwdCBleGVjdXRpb24gY29tcGxldGVkXCJcbmVjaG8gXCItLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXCJcbiIsInB1YmxpY19sb2dzIjp0cnVlLCJwdWJsaWNfc3lzaW5mbyI6dHJ1ZSwicHVibGljX3RjYmluZm8iOnRydWUsInJ1bm5lciI6ImRvY2tlci1jb21wb3NlIiwic2VjdXJlX3RpbWUiOmZhbHNlLCJzdG9yYWdlX2ZzIjoiemZzIiwidHByb3h5X2VuYWJsZWQiOnRydWV9"}}, "service_capabilities": {"supported_e2ee_versions": ["2"], "serving": "aggregator"}}} \ No newline at end of file diff --git a/sdk/package.json b/sdk/package.json index 78b58c4..3e091d4 100644 --- a/sdk/package.json +++ b/sdk/package.json @@ -1,6 +1,6 @@ { "name": "@prismnetwork/agent-sdk", - "version": "0.7.8", + "version": "0.7.10", "description": "Headless GPU leasing and renter-encrypted storage on Prism Network for wallet-holding agents.", "type": "module", "main": "prism.mjs", diff --git a/x402/exact-evm.mjs b/x402/exact-evm.mjs index f93daa7..55e2f1b 100644 --- a/x402/exact-evm.mjs +++ b/x402/exact-evm.mjs @@ -52,6 +52,10 @@ const REASON = { recipient: "invalid_exact_evm_payload_recipient_mismatch", funds: "insufficient_funds", state: "invalid_transaction_state", + // The protocol folds a spent nonce into invalid_transaction_state, alongside + // every other reason a transfer will not simulate. They need different + // answers: a replay is fixed by signing a new authorization, a revert is not. + spent: "payment_already_redeemed", // Not in the protocol's list, because the protocol assumes a facilitator can // read what it broadcast. Ours must survive an rpc that cannot. unconfirmed: "settlement_unconfirmed", @@ -208,7 +212,7 @@ export function createExactEvm(networks) { ]); // A spent nonce is the contract reporting this exact authorization already // settled, which is a replay rather than a malformed payload. - if (used) return { isValid: false, invalidReason: REASON.state, payer }; + if (used) return { isValid: false, invalidReason: REASON.spent, payer }; if (balance < value) return { isValid: false, invalidReason: REASON.funds, payer }; try {