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. +

+

Staking unlocks discounted capacity

+

+ 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. +

+

Where to check it

+

+ 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 {