From c5bf4b57e4f42c05a4939350ac23255d1a333618 Mon Sep 17 00:00:00 2001 From: ivanhelloprint Date: Tue, 3 Mar 2026 16:55:22 +0100 Subject: [PATCH] Add use-figma skill with Figma API tool scripts Includes 6 Node.js scripts for extracting design specs from Figma (layout, typography, colors, screenshots, tokens, code connect map). README explains API token setup. --- use-figma/README.md | 45 ++ use-figma/SKILL.md | 119 +++++ use-figma/scripts/get-code-connect-map.mjs | 390 ++++++++++++++ use-figma/scripts/get-design-context.mjs | 484 ++++++++++++++++++ use-figma/scripts/get-metadata.mjs | 469 +++++++++++++++++ use-figma/scripts/get-screenshot.mjs | 387 ++++++++++++++ .../scripts/get-variable-definitions.mjs | 404 +++++++++++++++ use-figma/scripts/whoami.mjs | 276 ++++++++++ 8 files changed, 2574 insertions(+) create mode 100644 use-figma/README.md create mode 100644 use-figma/SKILL.md create mode 100755 use-figma/scripts/get-code-connect-map.mjs create mode 100755 use-figma/scripts/get-design-context.mjs create mode 100755 use-figma/scripts/get-metadata.mjs create mode 100755 use-figma/scripts/get-screenshot.mjs create mode 100755 use-figma/scripts/get-variable-definitions.mjs create mode 100755 use-figma/scripts/whoami.mjs diff --git a/use-figma/README.md b/use-figma/README.md new file mode 100644 index 0000000..0312d8f --- /dev/null +++ b/use-figma/README.md @@ -0,0 +1,45 @@ +# use-figma + +Figma design tools for extracting specs and implementing pixel-perfect designs. + +## Setup + +### 1. Get a Figma API token + +1. Go to [Figma Account Settings](https://www.figma.com/developers/api#access-tokens) +2. Generate a new **Personal Access Token** +3. Required scopes: `file_read` +4. Optional scopes: `file_variables:read` (needed for `get-variable-definitions`) + +### 2. Configure the token + +Create a `.env.tools` file in your project root: + +``` +FIGMA_ACCESS_TOKEN=your_token_here +``` + +Make sure `.env.tools` is in your `.gitignore` — never commit tokens. + +### 3. Verify it works + +```bash +node use-figma/scripts/whoami.mjs --verbose +``` + +You should see your Figma user info if the token is valid. + +## Available Scripts + +| Script | Description | +|---|---| +| `whoami.mjs` | Verify API token authentication | +| `get-design-context.mjs` | Extract layout, spacing, colors, typography | +| `get-metadata.mjs` | Get node hierarchy and constraints | +| `get-screenshot.mjs` | Generate visual screenshots from designs | +| `get-code-connect-map.mjs` | Check which components are linked to code | +| `get-variable-definitions.mjs` | Extract design tokens (colors, spacing, typography) | + +## Usage + +See `SKILL.md` for the full workflow on how these tools are used together. diff --git a/use-figma/SKILL.md b/use-figma/SKILL.md new file mode 100644 index 0000000..8ba9f88 --- /dev/null +++ b/use-figma/SKILL.md @@ -0,0 +1,119 @@ +--- +name: use-figma +description: > + Fetch Figma design specs for pixel-perfect implementation. Triggers - Figma URL provided, + match the design, implement this Figma, from the mockup, design specs, pixel-perfect, + exact spacing/typography/colors needed. +--- + +# Figma Design Tools + +This skill ships with Figma helper scripts under `use-figma/scripts/`. + +## Prerequisites + +- Set `FIGMA_ACCESS_TOKEN` in a `.env.tools` file at the project root (see `use-figma/README.md`). +- Use the scripts from this skill directory (do not assume a `js/bin` folder). + +## When to use this skill + +Use when: + +- The user provides a **Figma URL** (design / node / section link) +- The request says "match Figma" / "implement this design" / "pixel-perfect" +- You need **exact spacing/typography/colors/states** (not "close enough") + +## Workflow + +### When a Figma URL is provided + +1. **Extract EXACT Specifications** (MANDATORY) + + Run the tools in sequence: + + ```bash + # 1. Verify token works + node use-figma/scripts/whoami.mjs --verbose + + # 2. Get layout, spacing, colors, typography + node use-figma/scripts/get-design-context.mjs \ + --url "https://www.figma.com/design/..." \ + --include-images \ + --verbose + + # 3. Get node hierarchy and constraints + node use-figma/scripts/get-metadata.mjs \ + --url "https://www.figma.com/design/..." \ + --verbose + + # 4. Get a visual screenshot for reference + node use-figma/scripts/get-screenshot.mjs \ + --url "https://www.figma.com/design/..." \ + --format png \ + --scale 2 \ + --verbose + ``` + + **Output handling (required)** + - If the output includes an `errors` array, it must be empty before using the data. + - Capture a short "design spec note" before coding: + - typography (fontSize/fontWeight/lineHeight) + - spacing (padding/margins/gaps) + - colors (tokens/variables or exact values) + - border radius, shadows + - states (hover/focus/active/disabled/empty/loading) + +2. **Document ALL Measurements Before Writing Code** + + Extract and note: + - **Typography**: `fontSize`, `fontWeight`, `lineHeight` for EVERY text element + - **Spacing**: Exact margins, paddings, gaps from auto-layout values + - **Colors**: Hex/RGB values — no approximations + - **Dimensions**: Precise width/height/aspect-ratio values + - **Border radius**: `cornerRadius` values + - **Shadows**: `effects` array for box shadows + - **States**: Document hover, focus, active, disabled, empty states + +3. **Check Existing Patterns** + + Before implementing, check if similar components exist: + + ```bash + # Check which Figma components are already linked to code + node use-figma/scripts/get-code-connect-map.mjs \ + --file-key \ + --verbose + ``` + +4. **Implement with EXACT Values** + + - Use exact Figma values, not approximations + - Prefer existing design tokens; if no token exists, use the exact value and leave a short comment referencing the Figma node / measurement + - Implement ALL interactive states from the design + +5. **Validate** + + Before finishing: + - [ ] Typography matches Figma exactly (font size, weight, line height) + - [ ] Spacing matches Figma exactly (margins, padding, gaps) + - [ ] Colors match Figma exactly (use hex values from design) + - [ ] All interactive states implemented (hover, focus, active, disabled) + - [ ] Responsive behavior matches design intent + +## Additional Commands + +```bash +# Get design tokens (colors, spacing, typography variables) +node use-figma/scripts/get-variable-definitions.mjs \ + --file-key \ + --include-styles true \ + --verbose +``` + +## Rules + +- **NEVER approximate** — use exact values from Figma +- **ALWAYS document measurements** before writing any code +- **Check `errors` array** is empty before using response data +- **Ask for clarification** if the design is ambiguous or states are missing +- **Reference existing patterns** before creating new components diff --git a/use-figma/scripts/get-code-connect-map.mjs b/use-figma/scripts/get-code-connect-map.mjs new file mode 100755 index 0000000..2ccc01d --- /dev/null +++ b/use-figma/scripts/get-code-connect-map.mjs @@ -0,0 +1,390 @@ +#!/usr/bin/env node + +// coding-tools/figma-tools/js/src/get-code-connect-map.ts +import { readFile } from "node:fs/promises"; +import path from "node:path"; + +// coding-tools/figma-tools/js/src/_utils/cli-args.ts +function parseArgs(argv = process.argv.slice(2)) { + const args = { _: [] }; + for (let i = 0; i < argv.length; i += 1) { + const arg = argv[i]; + if (!arg.startsWith("-") || arg === "-") { + args._.push(arg); + continue; + } + if (arg === "--") { + const remaining = argv.slice(i + 1); + args._.push(...remaining); + break; + } + const [rawKey, inlineValue] = arg.split("=", 2); + const normalisedKey = rawKey.replace(/^-+/, ""); + let value; + if (inlineValue !== void 0) { + value = inlineValue; + } else { + const next = argv[i + 1]; + if (next !== void 0 && !next.startsWith("-")) { + value = next; + i += 1; + } else { + value = true; + } + } + args[normalisedKey] = value; + } + return args; +} + +// coding-tools/figma-tools/js/src/_utils/url-parse.ts +var FILE_KEY_REGEX = /figma\.com\/(?:file|design)\/([A-Za-z0-9]+)\//i; +function parseFigmaUrl(input) { + if (!input) return { fileKey: null, nodeId: null }; + try { + const url = new URL(input); + const match = url.href.match(FILE_KEY_REGEX); + const fileKey = match ? match[1] : null; + const nodeParam = url.searchParams.get("node-id"); + const nodeId = nodeParam ? ensureNodeId(nodeParam) : null; + return { fileKey, nodeId }; + } catch { + return { fileKey: null, nodeId: null }; + } +} +function ensureNodeId(value) { + if (!value) return null; + const decoded = decodeURIComponent(value); + if (decoded.includes(":")) return decoded; + if (/^[0-9]+-[0-9]+$/.test(decoded)) { + const [left, right] = decoded.split("-", 2); + return `${left}:${right}`; + } + return decoded; +} + +// coding-tools/figma-tools/js/src/_utils/config.ts +var config_default = { + schemaVersion: "1.0.0", + source: "agentic-coding-templates/figma-tools", + http: { + maxAttempts: 5, + initialDelayMs: 250 + } +}; + +// coding-tools/figma-tools/js/src/_utils/envelope.ts +function buildRateLimitMeta(rateLimit = {}) { + return { + remaining: rateLimit.remaining ?? null, + resetAt: rateLimit.resetAt ?? null, + attempts: rateLimit.attempts ?? 1, + lastWaitMs: rateLimit.lastWaitMs ?? 0 + }; +} +function createEnvelope({ + tool, + input = {}, + data = {}, + warnings = [], + errors = [], + rateLimit, + schemaVersion +}) { + return { + schemaVersion: schemaVersion ?? config_default.schemaVersion, + tool, + input, + meta: { + generatedAt: (/* @__PURE__ */ new Date()).toISOString(), + source: config_default.source, + rateLimit: buildRateLimitMeta(rateLimit) + }, + data, + warnings, + errors + }; +} + +// coding-tools/figma-tools/js/src/_utils/errors.ts +var ERROR_EXIT_CODES = { + INPUT_INVALID: 1, + CONFIG_INVALID: 1, + FIGMA_AUTH: 1, + FIGMA_NOT_FOUND: 2, + FIGMA_RATE_LIMIT: 2, + NETWORK: 2, + INTERNAL: 3 +}; +function createError(code, message, detail) { + return { + code, + message, + detail: detail ?? null + }; +} +function getExitCode(errors = []) { + if (!errors.length) { + return 0; + } + return errors.reduce((max, error) => { + const exitCode = ERROR_EXIT_CODES[error.code] ?? 1; + return Math.max(max, exitCode); + }, 0); +} + +// coding-tools/figma-tools/js/src/_utils/http-client.ts +var BASE_URL = "https://api.figma.com"; +function sleep(ms) { + return new Promise((resolve) => setTimeout(resolve, ms)); +} +function parseJsonSafely(text) { + try { + return text ? JSON.parse(text) : {}; + } catch { + return { raw: text }; + } +} +function parseRateLimit(headers, attempts, lastWaitMs) { + const remainingHeader = headers.get("x-ratelimit-remaining"); + const resetHeader = headers.get("x-ratelimit-reset"); + let remaining = null; + if (remainingHeader !== null && remainingHeader !== void 0) { + const parsed = Number(remainingHeader); + remaining = Number.isNaN(parsed) ? null : parsed; + } + let resetAt = null; + if (resetHeader) { + const numericReset = Number(resetHeader); + if (!Number.isNaN(numericReset)) { + resetAt = new Date(numericReset * 1e3).toISOString(); + } else { + const date = new Date(resetHeader); + if (!Number.isNaN(date.valueOf())) { + resetAt = date.toISOString(); + } + } + } + return { + remaining, + resetAt, + attempts, + lastWaitMs + }; +} +function computeBackoffMs(attempt, initialDelayMs) { + return initialDelayMs * 2 ** (attempt - 1); +} +async function figmaRequest(options) { + const { + path: path2, + method = "GET", + token, + headers = {}, + body, + searchParams, + maxAttempts = config_default.http?.maxAttempts ?? 5, + initialDelayMs = config_default.http?.initialDelayMs ?? 250 + } = options; + if (!token) { + return { + ok: false, + error: createError("FIGMA_AUTH", "FIGMA_ACCESS_TOKEN is missing from the environment."), + status: null, + rateLimit: null + }; + } + const url = new URL(path2, BASE_URL); + if (searchParams) { + Object.entries(searchParams).forEach(([key, value]) => { + if (value === void 0 || value === null) return; + url.searchParams.append(key, String(value)); + }); + } + let attempt = 0; + let lastWaitMs = 0; + while (attempt < maxAttempts) { + attempt += 1; + const response = await fetch(url, { + method, + headers: { + "Content-Type": "application/json", + "X-Figma-Token": token, + ...headers + }, + body: body ? JSON.stringify(body) : void 0 + }); + const text = await response.text(); + const payload = parseJsonSafely(text); + const rateLimit = parseRateLimit(response.headers, attempt, lastWaitMs); + if (response.ok) { + return { ok: true, data: payload, rateLimit }; + } + const status = response.status; + if (status === 401 || status === 403) { + return { ok: false, error: createError("FIGMA_AUTH", payload?.message ?? "Figma token is unauthorized.", { status }), status, rateLimit }; + } + if (status === 404) { + return { ok: false, error: createError("FIGMA_NOT_FOUND", payload?.message ?? "Resource not found.", { status }), status, rateLimit }; + } + if (status === 429 || status >= 500) { + if (attempt >= maxAttempts) { + return { + ok: false, + error: createError(status === 429 ? "FIGMA_RATE_LIMIT" : "NETWORK", payload?.message ?? "Figma request failed after maximum retries.", { status }), + status, + rateLimit + }; + } + let waitMs = computeBackoffMs(attempt, initialDelayMs); + const resetHeader = response.headers.get("x-ratelimit-reset"); + if (resetHeader) { + const asNumber = Number(resetHeader); + if (!Number.isNaN(asNumber)) { + const resetMs = asNumber * 1e3; + const delta = resetMs - Date.now(); + if (delta > 0) waitMs = Math.max(waitMs, delta); + } + } + const jitter = Math.floor(Math.random() * 100); + lastWaitMs = waitMs + jitter; + await sleep(lastWaitMs); + continue; + } + return { ok: false, error: createError("INTERNAL", payload?.message ?? "Unexpected error from Figma API.", { status }), status, rateLimit }; + } + return { + ok: false, + error: createError("NETWORK", "Unable to reach Figma API."), + status: null, + rateLimit: { remaining: null, resetAt: null, attempts: maxAttempts, lastWaitMs } + }; +} + +// coding-tools/figma-tools/js/src/get-code-connect-map.ts +var TOOL_NAME = "get-code-connect-map"; +function log(message, verbose) { + if (verbose) process.stderr.write(`[${TOOL_NAME}] ${message} +`); +} +function toOptionalString(value) { + return typeof value === "string" && value.length > 0 ? value : null; +} +function exitWithEnvelope(envelope, errors = []) { + process.stdout.write(`${JSON.stringify(envelope, null, 2)} +`); + process.exit(getExitCode(errors)); +} +async function readRepoConfig() { + try { + const configPath = path.resolve("config/code-connect-map.json"); + const content = await readFile(configPath, "utf8"); + const parsed = JSON.parse(content); + if (parsed && Array.isArray(parsed.components)) return parsed; + return { version: "0.1", components: [] }; + } catch { + return { version: "0.1", components: [] }; + } +} +async function main() { + const args = parseArgs(); + const verbose = Boolean(args.verbose ?? args.v); + const schemaVersion = toOptionalString(args["schema-version"]) ?? void 0; + const warnings = []; + const errors = []; + let repoConfig = { version: "0.1", components: [] }; + try { + repoConfig = await readRepoConfig(); + } catch (error) { + warnings.push(error instanceof Error ? error.message : String(error)); + } + const token = process.env.FIGMA_ACCESS_TOKEN; + if (!token || !token.trim()) { + errors.push(createError("FIGMA_AUTH", "FIGMA_ACCESS_TOKEN is required but was not provided.")); + const envelope2 = createEnvelope({ tool: TOOL_NAME, input: { fileKey: null, nodeId: null }, warnings, errors, schemaVersion, data: {} }); + exitWithEnvelope(envelope2, errors); + } + const urlInput = toOptionalString(args.url) ?? toOptionalString(args.u); + let fileKey = toOptionalString(args["file-key"]) ?? void 0; + const nodeIdInput = ensureNodeId(toOptionalString(args["node-id"])); + if (urlInput) { + const parsed = parseFigmaUrl(urlInput); + fileKey = fileKey || parsed.fileKey || void 0; + } + const input = { fileKey: fileKey ?? null, nodeId: nodeIdInput ?? null }; + if (!fileKey) errors.push(createError("INPUT_INVALID", "A valid Figma file key is required (--file-key or --url).")); + if (errors.length) { + const envelope2 = createEnvelope({ tool: TOOL_NAME, input, warnings, errors, data: {}, schemaVersion }); + exitWithEnvelope(envelope2, errors); + } + const resolvedFileKey = fileKey; + log("Fetching dev resources", verbose); + const devResourcesResponse = await figmaRequest({ path: `/v1/files/${resolvedFileKey}/devresources`, token }); + log("Fetching components", verbose); + const componentsResponse = await figmaRequest({ path: `/v1/files/${resolvedFileKey}/components`, token }); + if (!devResourcesResponse.ok) { + errors.push(devResourcesResponse.error ?? createError("INTERNAL", "Failed to fetch dev resources.")); + const envelope2 = createEnvelope({ tool: TOOL_NAME, input, warnings, errors, rateLimit: devResourcesResponse.rateLimit ?? void 0, schemaVersion, data: {} }); + exitWithEnvelope(envelope2, errors); + } + if (!componentsResponse.ok) warnings.push(componentsResponse.error?.message ?? "Failed to fetch components."); + const devResources = devResourcesResponse.data?.dev_resources ?? []; + const componentsMap = componentsResponse.ok ? componentsResponse.data?.components ?? {} : {}; + const repoMappings = repoConfig.components ?? []; + const normalisedResources = devResources.map((resource) => ({ + id: resource.id, + name: resource.name, + description: resource.description ?? null, + url: resource.url ?? null, + nodeId: resource.node_id ?? null, + componentId: resource.component_id ?? null, + fileKey: resource.file_key ?? resolvedFileKey, + status: resource.status ?? null, + createdAt: resource.created_at ?? null, + updatedAt: resource.updated_at ?? null + })); + const normalisedComponents = Object.entries(componentsMap).map(([componentId, component]) => ({ + id: componentId, + key: component.key, + name: component.name, + description: component.description ?? null, + fileKey: component.file_key ?? resolvedFileKey, + nodeId: component.node_id ?? null + })); + const findRepoMapping = (name) => { + if (!name) return null; + return repoMappings.find((m) => m.name === name || m.component === name) ?? null; + }; + const mappings = normalisedResources.map((resource) => { + const component = resource.componentId ? normalisedComponents.find((entry) => entry.id === resource.componentId) : null; + const repoMapping = findRepoMapping(component?.name ?? resource.name); + if (!repoMapping) { + warnings.push(`Node ${resource.nodeId ?? component?.nodeId ?? "unknown"} (${resource.name ?? component?.name ?? "unnamed"}) has no mapping in config/code-connect-map.json.`); + } + return { + nodeId: resource.nodeId ?? component?.nodeId ?? null, + componentId: resource.componentId ?? component?.id ?? null, + componentKey: component?.key ?? null, + componentName: component?.name ?? resource.name ?? null, + repoComponent: repoMapping?.component ?? null, + repoPath: repoMapping?.path ?? null, + props: repoMapping?.props ?? null, + description: component?.description ?? resource.description ?? null, + status: resource.status ?? null, + sourceUrl: resource.url ?? null + }; + }); + const data = { file: { key: resolvedFileKey }, mappings, components: normalisedComponents, devResources: normalisedResources }; + const envelope = createEnvelope({ tool: TOOL_NAME, input, data, warnings, errors, rateLimit: devResourcesResponse.rateLimit ?? void 0, schemaVersion }); + process.stdout.write(`${JSON.stringify(envelope, null, 2)} +`); + process.exit(getExitCode(errors)); +} +main().catch((error) => { + const message = error instanceof Error ? error.message : "Unknown error"; + const envelope = createEnvelope({ tool: TOOL_NAME, input: { fileKey: null, nodeId: null }, errors: [createError("INTERNAL", message, { stack: error instanceof Error ? error.stack : void 0 })], data: {} }); + process.stdout.write(`${JSON.stringify(envelope, null, 2)} +`); + process.exit(3); +}); +//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiLi4vc3JjL2dldC1jb2RlLWNvbm5lY3QtbWFwLnRzIiwgIi4uL3NyYy9fdXRpbHMvY2xpLWFyZ3MudHMiLCAiLi4vc3JjL191dGlscy91cmwtcGFyc2UudHMiLCAiLi4vc3JjL191dGlscy9jb25maWcudHMiLCAiLi4vc3JjL191dGlscy9lbnZlbG9wZS50cyIsICIuLi9zcmMvX3V0aWxzL2Vycm9ycy50cyIsICIuLi9zcmMvX3V0aWxzL2h0dHAtY2xpZW50LnRzIl0sCiAgInNvdXJjZXNDb250ZW50IjogWyIjIS91c3IvYmluL2VudiBub2RlXG5cbmltcG9ydCB7IHJlYWRGaWxlIH0gZnJvbSAnbm9kZTpmcy9wcm9taXNlcydcbmltcG9ydCBwYXRoIGZyb20gJ25vZGU6cGF0aCdcbmltcG9ydCB7IHBhcnNlQXJncywgdHlwZSBDbGlBcmdzIH0gZnJvbSAnLi9fdXRpbHMvY2xpLWFyZ3MudHMnXG5pbXBvcnQgeyBwYXJzZUZpZ21hVXJsLCBlbnN1cmVOb2RlSWQgfSBmcm9tICcuL191dGlscy91cmwtcGFyc2UudHMnXG5pbXBvcnQgeyBjcmVhdGVFbnZlbG9wZSwgdHlwZSBUb29sRW52ZWxvcGUgfSBmcm9tICcuL191dGlscy9lbnZlbG9wZS50cydcbmltcG9ydCB7IGNyZWF0ZUVycm9yLCBnZXRFeGl0Q29kZSwgdHlwZSBUb29sRXJyb3IgfSBmcm9tICcuL191dGlscy9lcnJvcnMudHMnXG5pbXBvcnQgeyBmaWdtYVJlcXVlc3QgfSBmcm9tICcuL191dGlscy9odHRwLWNsaWVudC50cydcblxuY29uc3QgVE9PTF9OQU1FID0gJ2dldC1jb2RlLWNvbm5lY3QtbWFwJ1xudHlwZSBFbXB0eURhdGEgPSBSZWNvcmQ8c3RyaW5nLCBuZXZlcj5cblxuaW50ZXJmYWNlIFRvb2xJbnB1dCBleHRlbmRzIFJlY29yZDxzdHJpbmcsIHVua25vd24+IHsgZmlsZUtleTogc3RyaW5nIHwgbnVsbDsgbm9kZUlkOiBzdHJpbmcgfCBudWxsIH1cblxuaW50ZXJmYWNlIFJlcG9Db21wb25lbnRNYXBwaW5nIHsgbmFtZT86IHN0cmluZzsgY29tcG9uZW50Pzogc3RyaW5nOyBwYXRoPzogc3RyaW5nOyBwcm9wcz86IFJlY29yZDxzdHJpbmcsIHVua25vd24+IH1cbmludGVyZmFjZSBSZXBvQ29uZmlnIHsgdmVyc2lvbj86IHN0cmluZzsgY29tcG9uZW50cz86IFJlcG9Db21wb25lbnRNYXBwaW5nW10gfVxuXG5pbnRlcmZhY2UgRGV2UmVzb3VyY2VQYXlsb2FkIHsgZGV2X3Jlc291cmNlcz86IERldlJlc291cmNlW10gfVxuaW50ZXJmYWNlIERldlJlc291cmNlIHsgaWQ6IHN0cmluZzsgbmFtZT86IHN0cmluZzsgZGVzY3JpcHRpb24/OiBzdHJpbmc7IHVybD86IHN0cmluZzsgbm9kZV9pZD86IHN0cmluZzsgY29tcG9uZW50X2lkPzogc3RyaW5nOyBmaWxlX2tleT86IHN0cmluZzsgc3RhdHVzPzogc3RyaW5nOyBjcmVhdGVkX2F0Pzogc3RyaW5nOyB1cGRhdGVkX2F0Pzogc3RyaW5nIH1cbmludGVyZmFjZSBOb3JtYWxpc2VkRGV2UmVzb3VyY2UgeyBpZDogc3RyaW5nOyBuYW1lPzogc3RyaW5nOyBkZXNjcmlwdGlvbjogc3RyaW5nIHwgbnVsbDsgdXJsOiBzdHJpbmcgfCBudWxsOyBub2RlSWQ6IHN0cmluZyB8IG51bGw7IGNvbXBvbmVudElkOiBzdHJpbmcgfCBudWxsOyBmaWxlS2V5OiBzdHJpbmc7IHN0YXR1czogc3RyaW5nIHwgbnVsbDsgY3JlYXRlZEF0OiBzdHJpbmcgfCBudWxsOyB1cGRhdGVkQXQ6IHN0cmluZyB8IG51bGwgfVxuXG5pbnRlcmZhY2UgQ29tcG9uZW50TWV0YSB7IGtleT86IHN0cmluZzsgbmFtZT86IHN0cmluZzsgZGVzY3JpcHRpb24/OiBzdHJpbmc7IGZpbGVfa2V5Pzogc3RyaW5nOyBub2RlX2lkPzogc3RyaW5nIH1cbmludGVyZmFjZSBDb21wb25lbnRzUGF5bG9hZCB7IGNvbXBvbmVudHM/OiBSZWNvcmQ8c3RyaW5nLCBDb21wb25lbnRNZXRhPiB9XG5pbnRlcmZhY2UgTm9ybWFsaXNlZENvbXBvbmVudCB7IGlkOiBzdHJpbmc7IGtleT86IHN0cmluZzsgbmFtZT86IHN0cmluZzsgZGVzY3JpcHRpb246IHN0cmluZyB8IG51bGw7IGZpbGVLZXk6IHN0cmluZzsgbm9kZUlkOiBzdHJpbmcgfCBudWxsIH1cblxuaW50ZXJmYWNlIE1hcHBpbmcgeyBub2RlSWQ6IHN0cmluZyB8IG51bGw7IGNvbXBvbmVudElkOiBzdHJpbmcgfCBudWxsOyBjb21wb25lbnRLZXk6IHN0cmluZyB8IG51bGw7IGNvbXBvbmVudE5hbWU6IHN0cmluZyB8IG51bGw7IHJlcG9Db21wb25lbnQ6IHN0cmluZyB8IG51bGw7IHJlcG9QYXRoOiBzdHJpbmcgfCBudWxsOyBwcm9wczogUmVjb3JkPHN0cmluZywgdW5rbm93bj4gfCBudWxsOyBkZXNjcmlwdGlvbjogc3RyaW5nIHwgbnVsbDsgc3RhdHVzOiBzdHJpbmcgfCBudWxsOyBzb3VyY2VVcmw6IHN0cmluZyB8IG51bGwgfVxuXG5pbnRlcmZhY2UgQ29kZUNvbm5lY3REYXRhIHsgZmlsZTogeyBrZXk6IHN0cmluZyB9OyBtYXBwaW5nczogTWFwcGluZ1tdOyBjb21wb25lbnRzOiBOb3JtYWxpc2VkQ29tcG9uZW50W107IGRldlJlc291cmNlczogTm9ybWFsaXNlZERldlJlc291cmNlW10gfVxuXG5mdW5jdGlvbiBsb2cobWVzc2FnZTogc3RyaW5nLCB2ZXJib3NlOiBib29sZWFuKTogdm9pZCB7IGlmICh2ZXJib3NlKSBwcm9jZXNzLnN0ZGVyci53cml0ZShgWyR7VE9PTF9OQU1FfV0gJHttZXNzYWdlfVxcbmApIH1cbmZ1bmN0aW9uIHRvT3B0aW9uYWxTdHJpbmcodmFsdWU6IENsaUFyZ3Nbc3RyaW5nXSk6IHN0cmluZyB8IG51bGwgeyByZXR1cm4gdHlwZW9mIHZhbHVlID09PSAnc3RyaW5nJyAmJiB2YWx1ZS5sZW5ndGggPiAwID8gdmFsdWUgOiBudWxsIH1cbmZ1bmN0aW9uIGV4aXRXaXRoRW52ZWxvcGUoZW52ZWxvcGU6IFRvb2xFbnZlbG9wZTxUb29sSW5wdXQsIENvZGVDb25uZWN0RGF0YSB8IEVtcHR5RGF0YT4sIGVycm9yczogVG9vbEVycm9yW10gPSBbXSk6IG5ldmVyIHsgcHJvY2Vzcy5zdGRvdXQud3JpdGUoYCR7SlNPTi5zdHJpbmdpZnkoZW52ZWxvcGUsIG51bGwsIDIpfVxcbmApOyBwcm9jZXNzLmV4aXQoZ2V0RXhpdENvZGUoZXJyb3JzKSkgfVxuXG5hc3luYyBmdW5jdGlvbiByZWFkUmVwb0NvbmZpZygpOiBQcm9taXNlPFJlcG9Db25maWc+IHtcbiAgdHJ5IHtcbiAgICBjb25zdCBjb25maWdQYXRoID0gcGF0aC5yZXNvbHZlKCdjb25maWcvY29kZS1jb25uZWN0LW1hcC5qc29uJylcbiAgICBjb25zdCBjb250ZW50ID0gYXdhaXQgcmVhZEZpbGUoY29uZmlnUGF0aCwgJ3V0ZjgnKVxuICAgIGNvbnN0IHBhcnNlZCA9IEpTT04ucGFyc2UoY29udGVudClcbiAgICBpZiAocGFyc2VkICYmIEFycmF5LmlzQXJyYXkocGFyc2VkLmNvbXBvbmVudHMpKSByZXR1cm4gcGFyc2VkXG4gICAgcmV0dXJuIHsgdmVyc2lvbjogJzAuMScsIGNvbXBvbmVudHM6IFtdIH1cbiAgfSBjYXRjaCB7XG4gICAgcmV0dXJuIHsgdmVyc2lvbjogJzAuMScsIGNvbXBvbmVudHM6IFtdIH1cbiAgfVxufVxuXG5hc3luYyBmdW5jdGlvbiBtYWluKCk6IFByb21pc2U8dm9pZD4ge1xuICBjb25zdCBhcmdzID0gcGFyc2VBcmdzKClcbiAgY29uc3QgdmVyYm9zZSA9IEJvb2xlYW4oYXJncy52ZXJib3NlID8/IGFyZ3MudilcbiAgY29uc3Qgc2NoZW1hVmVyc2lvbiA9IHRvT3B0aW9uYWxTdHJpbmcoYXJnc1snc2NoZW1hLXZlcnNpb24nXSkgPz8gdW5kZWZpbmVkXG5cbiAgY29uc3Qgd2FybmluZ3M6IHN0cmluZ1tdID0gW11cbiAgY29uc3QgZXJyb3JzOiBUb29sRXJyb3JbXSA9IFtdXG5cbiAgbGV0IHJlcG9Db25maWc6IFJlcG9Db25maWcgPSB7IHZlcnNpb246ICcwLjEnLCBjb21wb25lbnRzOiBbXSB9XG4gIHRyeSB7IHJlcG9Db25maWcgPSBhd2FpdCByZWFkUmVwb0NvbmZpZygpIH0gY2F0Y2ggKGVycm9yKSB7IHdhcm5pbmdzLnB1c2goZXJyb3IgaW5zdGFuY2VvZiBFcnJvciA/IGVycm9yLm1lc3NhZ2UgOiBTdHJpbmcoZXJyb3IpKSB9XG5cbiAgY29uc3QgdG9rZW4gPSBwcm9jZXNzLmVudi5GSUdNQV9BQ0NFU1NfVE9LRU5cbiAgaWYgKCF0b2tlbiB8fCAhdG9rZW4udHJpbSgpKSB7XG4gICAgZXJyb3JzLnB1c2goY3JlYXRlRXJyb3IoJ0ZJR01BX0FVVEgnLCAnRklHTUFfQUNDRVNTX1RPS0VOIGlzIHJlcXVpcmVkIGJ1dCB3YXMgbm90IHByb3ZpZGVkLicpKVxuICAgIGNvbnN0IGVudmVsb3BlID0gY3JlYXRlRW52ZWxvcGU8VG9vbElucHV0LCBFbXB0eURhdGE+KHsgdG9vbDogVE9PTF9OQU1FLCBpbnB1dDogeyBmaWxlS2V5OiBudWxsLCBub2RlSWQ6IG51bGwgfSwgd2FybmluZ3MsIGVycm9ycywgc2NoZW1hVmVyc2lvbiwgZGF0YToge30gYXMgRW1wdHlEYXRhIH0pXG4gICAgZXhpdFdpdGhFbnZlbG9wZShlbnZlbG9wZSwgZXJyb3JzKVxuICB9XG5cbiAgY29uc3QgdXJsSW5wdXQgPSB0b09wdGlvbmFsU3RyaW5nKGFyZ3MudXJsKSA/PyB0b09wdGlvbmFsU3RyaW5nKGFyZ3MudSlcbiAgbGV0IGZpbGVLZXkgPSB0b09wdGlvbmFsU3RyaW5nKGFyZ3NbJ2ZpbGUta2V5J10pID8/IHVuZGVmaW5lZFxuICBjb25zdCBub2RlSWRJbnB1dCA9IGVuc3VyZU5vZGVJZCh0b09wdGlvbmFsU3RyaW5nKGFyZ3NbJ25vZGUtaWQnXSkpXG4gIGlmICh1cmxJbnB1dCkgeyBjb25zdCBwYXJzZWQgPSBwYXJzZUZpZ21hVXJsKHVybElucHV0KTsgZmlsZUtleSA9IGZpbGVLZXkgfHwgcGFyc2VkLmZpbGVLZXkgfHwgdW5kZWZpbmVkIH1cblxuICBjb25zdCBpbnB1dDogVG9vbElucHV0ID0geyBmaWxlS2V5OiBmaWxlS2V5ID8/IG51bGwsIG5vZGVJZDogbm9kZUlkSW5wdXQgPz8gbnVsbCB9XG4gIGlmICghZmlsZUtleSkgZXJyb3JzLnB1c2goY3JlYXRlRXJyb3IoJ0lOUFVUX0lOVkFMSUQnLCAnQSB2YWxpZCBGaWdtYSBmaWxlIGtleSBpcyByZXF1aXJlZCAoLS1maWxlLWtleSBvciAtLXVybCkuJykpXG4gIGlmIChlcnJvcnMubGVuZ3RoKSB7IGNvbnN0IGVudmVsb3BlID0gY3JlYXRlRW52ZWxvcGU8VG9vbElucHV0LCBFbXB0eURhdGE+KHsgdG9vbDogVE9PTF9OQU1FLCBpbnB1dCwgd2FybmluZ3MsIGVycm9ycywgZGF0YToge30gYXMgRW1wdHlEYXRhLCBzY2hlbWFWZXJzaW9uIH0pOyBleGl0V2l0aEVudmVsb3BlKGVudmVsb3BlLCBlcnJvcnMpIH1cblxuICBjb25zdCByZXNvbHZlZEZpbGVLZXkgPSBmaWxlS2V5IGFzIHN0cmluZ1xuXG4gIGxvZygnRmV0Y2hpbmcgZGV2IHJlc291cmNlcycsIHZlcmJvc2UpXG4gIGNvbnN0IGRldlJlc291cmNlc1Jlc3BvbnNlID0gYXdhaXQgZmlnbWFSZXF1ZXN0PERldlJlc291cmNlUGF5bG9hZD4oeyBwYXRoOiBgL3YxL2ZpbGVzLyR7cmVzb2x2ZWRGaWxlS2V5fS9kZXZyZXNvdXJjZXNgLCB0b2tlbiB9KVxuICBsb2coJ0ZldGNoaW5nIGNvbXBvbmVudHMnLCB2ZXJib3NlKVxuICBjb25zdCBjb21wb25lbnRzUmVzcG9uc2UgPSBhd2FpdCBmaWdtYVJlcXVlc3Q8Q29tcG9uZW50c1BheWxvYWQ+KHsgcGF0aDogYC92MS9maWxlcy8ke3Jlc29sdmVkRmlsZUtleX0vY29tcG9uZW50c2AsIHRva2VuIH0pXG5cbiAgaWYgKCFkZXZSZXNvdXJjZXNSZXNwb25zZS5vaykge1xuICAgIGVycm9ycy5wdXNoKGRldlJlc291cmNlc1Jlc3BvbnNlLmVycm9yID8/IGNyZWF0ZUVycm9yKCdJTlRFUk5BTCcsICdGYWlsZWQgdG8gZmV0Y2ggZGV2IHJlc291cmNlcy4nKSlcbiAgICBjb25zdCBlbnZlbG9wZSA9IGNyZWF0ZUVudmVsb3BlPFRvb2xJbnB1dCwgRW1wdHlEYXRhPih7IHRvb2w6IFRPT0xfTkFNRSwgaW5wdXQsIHdhcm5pbmdzLCBlcnJvcnMsIHJhdGVMaW1pdDogZGV2UmVzb3VyY2VzUmVzcG9uc2UucmF0ZUxpbWl0ID8/IHVuZGVmaW5lZCwgc2NoZW1hVmVyc2lvbiwgZGF0YToge30gYXMgRW1wdHlEYXRhIH0pXG4gICAgZXhpdFdpdGhFbnZlbG9wZShlbnZlbG9wZSwgZXJyb3JzKVxuICB9XG4gIGlmICghY29tcG9uZW50c1Jlc3BvbnNlLm9rKSB3YXJuaW5ncy5wdXNoKGNvbXBvbmVudHNSZXNwb25zZS5lcnJvcj8ubWVzc2FnZSA/PyAnRmFpbGVkIHRvIGZldGNoIGNvbXBvbmVudHMuJylcblxuICBjb25zdCBkZXZSZXNvdXJjZXMgPSBkZXZSZXNvdXJjZXNSZXNwb25zZS5kYXRhPy5kZXZfcmVzb3VyY2VzID8/IFtdXG4gIGNvbnN0IGNvbXBvbmVudHNNYXA6IFJlY29yZDxzdHJpbmcsIENvbXBvbmVudE1ldGE+ID0gY29tcG9uZW50c1Jlc3BvbnNlLm9rID8gY29tcG9uZW50c1Jlc3BvbnNlLmRhdGE/LmNvbXBvbmVudHMgPz8ge30gOiB7fVxuICBjb25zdCByZXBvTWFwcGluZ3MgPSByZXBvQ29uZmlnLmNvbXBvbmVudHMgPz8gW11cblxuICBjb25zdCBub3JtYWxpc2VkUmVzb3VyY2VzOiBOb3JtYWxpc2VkRGV2UmVzb3VyY2VbXSA9IGRldlJlc291cmNlcy5tYXAoKHJlc291cmNlOiBEZXZSZXNvdXJjZSkgPT4gKHtcbiAgICBpZDogcmVzb3VyY2UuaWQsXG4gICAgbmFtZTogcmVzb3VyY2UubmFtZSxcbiAgICBkZXNjcmlwdGlvbjogcmVzb3VyY2UuZGVzY3JpcHRpb24gPz8gbnVsbCxcbiAgICB1cmw6IHJlc291cmNlLnVybCA/PyBudWxsLFxuICAgIG5vZGVJZDogcmVzb3VyY2Uubm9kZV9pZCA/PyBudWxsLFxuICAgIGNvbXBvbmVudElkOiByZXNvdXJjZS5jb21wb25lbnRfaWQgPz8gbnVsbCxcbiAgICBmaWxlS2V5OiByZXNvdXJjZS5maWxlX2tleSA/PyByZXNvbHZlZEZpbGVLZXksXG4gICAgc3RhdHVzOiByZXNvdXJjZS5zdGF0dXMgPz8gbnVsbCxcbiAgICBjcmVhdGVkQXQ6IHJlc291cmNlLmNyZWF0ZWRfYXQgPz8gbnVsbCxcbiAgICB1cGRhdGVkQXQ6IHJlc291cmNlLnVwZGF0ZWRfYXQgPz8gbnVsbCxcbiAgfSkpXG5cbiAgY29uc3Qgbm9ybWFsaXNlZENvbXBvbmVudHM6IE5vcm1hbGlzZWRDb21wb25lbnRbXSA9IE9iamVjdC5lbnRyaWVzKGNvbXBvbmVudHNNYXApLm1hcCgoW2NvbXBvbmVudElkLCBjb21wb25lbnRdKSA9PiAoe1xuICAgIGlkOiBjb21wb25lbnRJZCxcbiAgICBrZXk6IGNvbXBvbmVudC5rZXksXG4gICAgbmFtZTogY29tcG9uZW50Lm5hbWUsXG4gICAgZGVzY3JpcHRpb246IGNvbXBvbmVudC5kZXNjcmlwdGlvbiA/PyBudWxsLFxuICAgIGZpbGVLZXk6IGNvbXBvbmVudC5maWxlX2tleSA/PyByZXNvbHZlZEZpbGVLZXksXG4gICAgbm9kZUlkOiBjb21wb25lbnQubm9kZV9pZCA/PyBudWxsLFxuICB9KSlcblxuICBjb25zdCBmaW5kUmVwb01hcHBpbmcgPSAobmFtZT86IHN0cmluZyB8IG51bGwpID0+IHtcbiAgICBpZiAoIW5hbWUpIHJldHVybiBudWxsXG4gICAgcmV0dXJuIHJlcG9NYXBwaW5ncy5maW5kKChtKSA9PiBtLm5hbWUgPT09IG5hbWUgfHwgbS5jb21wb25lbnQgPT09IG5hbWUpID8/IG51bGxcbiAgfVxuXG4gIGNvbnN0IG1hcHBpbmdzOiBNYXBwaW5nW10gPSBub3JtYWxpc2VkUmVzb3VyY2VzLm1hcCgocmVzb3VyY2UpID0+IHtcbiAgICBjb25zdCBjb21wb25lbnQgPSByZXNvdXJjZS5jb21wb25lbnRJZCA/IG5vcm1hbGlzZWRDb21wb25lbnRzLmZpbmQoKGVudHJ5KSA9PiBlbnRyeS5pZCA9PT0gcmVzb3VyY2UuY29tcG9uZW50SWQpIDogbnVsbFxuICAgIGNvbnN0IHJlcG9NYXBwaW5nID0gZmluZFJlcG9NYXBwaW5nKGNvbXBvbmVudD8ubmFtZSA/PyByZXNvdXJjZS5uYW1lKVxuICAgIGlmICghcmVwb01hcHBpbmcpIHtcbiAgICAgIHdhcm5pbmdzLnB1c2goYE5vZGUgJHtyZXNvdXJjZS5ub2RlSWQgPz8gY29tcG9uZW50Py5ub2RlSWQgPz8gJ3Vua25vd24nfSAoJHtyZXNvdXJjZS5uYW1lID8/IGNvbXBvbmVudD8ubmFtZSA/PyAndW5uYW1lZCd9KSBoYXMgbm8gbWFwcGluZyBpbiBjb25maWcvY29kZS1jb25uZWN0LW1hcC5qc29uLmApXG4gICAgfVxuICAgIHJldHVybiB7XG4gICAgICBub2RlSWQ6IHJlc291cmNlLm5vZGVJZCA/PyBjb21wb25lbnQ/Lm5vZGVJZCA/PyBudWxsLFxuICAgICAgY29tcG9uZW50SWQ6IHJlc291cmNlLmNvbXBvbmVudElkID8/IGNvbXBvbmVudD8uaWQgPz8gbnVsbCxcbiAgICAgIGNvbXBvbmVudEtleTogY29tcG9uZW50Py5rZXkgPz8gbnVsbCxcbiAgICAgIGNvbXBvbmVudE5hbWU6IGNvbXBvbmVudD8ubmFtZSA/PyByZXNvdXJjZS5uYW1lID8/IG51bGwsXG4gICAgICByZXBvQ29tcG9uZW50OiByZXBvTWFwcGluZz8uY29tcG9uZW50ID8/IG51bGwsXG4gICAgICByZXBvUGF0aDogcmVwb01hcHBpbmc/LnBhdGggPz8gbnVsbCxcbiAgICAgIHByb3BzOiByZXBvTWFwcGluZz8ucHJvcHMgPz8gbnVsbCxcbiAgICAgIGRlc2NyaXB0aW9uOiBjb21wb25lbnQ/LmRlc2NyaXB0aW9uID8/IHJlc291cmNlLmRlc2NyaXB0aW9uID8/IG51bGwsXG4gICAgICBzdGF0dXM6IHJlc291cmNlLnN0YXR1cyA/PyBudWxsLFxuICAgICAgc291cmNlVXJsOiByZXNvdXJjZS51cmwgPz8gbnVsbCxcbiAgICB9XG4gIH0pXG5cbiAgY29uc3QgZGF0YTogQ29kZUNvbm5lY3REYXRhID0geyBmaWxlOiB7IGtleTogcmVzb2x2ZWRGaWxlS2V5IH0sIG1hcHBpbmdzLCBjb21wb25lbnRzOiBub3JtYWxpc2VkQ29tcG9uZW50cywgZGV2UmVzb3VyY2VzOiBub3JtYWxpc2VkUmVzb3VyY2VzIH1cblxuICBjb25zdCBlbnZlbG9wZSA9IGNyZWF0ZUVudmVsb3BlPFRvb2xJbnB1dCwgQ29kZUNvbm5lY3REYXRhPih7IHRvb2w6IFRPT0xfTkFNRSwgaW5wdXQsIGRhdGEsIHdhcm5pbmdzLCBlcnJvcnMsIHJhdGVMaW1pdDogZGV2UmVzb3VyY2VzUmVzcG9uc2UucmF0ZUxpbWl0ID8/IHVuZGVmaW5lZCwgc2NoZW1hVmVyc2lvbiB9KVxuICBwcm9jZXNzLnN0ZG91dC53cml0ZShgJHtKU09OLnN0cmluZ2lmeShlbnZlbG9wZSwgbnVsbCwgMil9XFxuYClcbiAgcHJvY2Vzcy5leGl0KGdldEV4aXRDb2RlKGVycm9ycykpXG59XG5cbm1haW4oKS5jYXRjaCgoZXJyb3I6IHVua25vd24pID0+IHtcbiAgY29uc3QgbWVzc2FnZSA9IGVycm9yIGluc3RhbmNlb2YgRXJyb3IgPyBlcnJvci5tZXNzYWdlIDogJ1Vua25vd24gZXJyb3InXG4gIGNvbnN0IGVudmVsb3BlID0gY3JlYXRlRW52ZWxvcGU8VG9vbElucHV0LCBFbXB0eURhdGE+KHsgdG9vbDogVE9PTF9OQU1FLCBpbnB1dDogeyBmaWxlS2V5OiBudWxsLCBub2RlSWQ6IG51bGwgfSwgZXJyb3JzOiBbY3JlYXRlRXJyb3IoJ0lOVEVSTkFMJywgbWVzc2FnZSwgeyBzdGFjazogZXJyb3IgaW5zdGFuY2VvZiBFcnJvciA/IGVycm9yLnN0YWNrIDogdW5kZWZpbmVkIH0pXSwgZGF0YToge30gYXMgRW1wdHlEYXRhIH0pXG4gIHByb2Nlc3Muc3Rkb3V0LndyaXRlKGAke0pTT04uc3RyaW5naWZ5KGVudmVsb3BlLCBudWxsLCAyKX1cXG5gKVxuICBwcm9jZXNzLmV4aXQoMylcbn0pXG5cbiIsICJleHBvcnQgdHlwZSBDbGlBcmdWYWx1ZSA9IHN0cmluZyB8IGJvb2xlYW47XG5cbmV4cG9ydCBpbnRlcmZhY2UgQ2xpQXJncyB7XG4gIF86IHN0cmluZ1tdO1xuICBba2V5OiBzdHJpbmddOiBDbGlBcmdWYWx1ZSB8IHN0cmluZ1tdO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gcGFyc2VBcmdzKGFyZ3Y6IHN0cmluZ1tdID0gcHJvY2Vzcy5hcmd2LnNsaWNlKDIpKTogQ2xpQXJncyB7XG4gIGNvbnN0IGFyZ3M6IENsaUFyZ3MgPSB7IF86IFtdIH07XG5cbiAgZm9yIChsZXQgaSA9IDA7IGkgPCBhcmd2Lmxlbmd0aDsgaSArPSAxKSB7XG4gICAgY29uc3QgYXJnID0gYXJndltpXTtcblxuICAgIGlmICghYXJnLnN0YXJ0c1dpdGgoJy0nKSB8fCBhcmcgPT09ICctJykge1xuICAgICAgYXJncy5fLnB1c2goYXJnKTtcbiAgICAgIGNvbnRpbnVlO1xuICAgIH1cblxuICAgIGlmIChhcmcgPT09ICctLScpIHtcbiAgICAgIGNvbnN0IHJlbWFpbmluZyA9IGFyZ3Yuc2xpY2UoaSArIDEpO1xuICAgICAgYXJncy5fLnB1c2goLi4ucmVtYWluaW5nKTtcbiAgICAgIGJyZWFrO1xuICAgIH1cblxuICAgIGNvbnN0IFtyYXdLZXksIGlubGluZVZhbHVlXSA9IGFyZy5zcGxpdCgnPScsIDIpO1xuICAgIGNvbnN0IG5vcm1hbGlzZWRLZXkgPSByYXdLZXkucmVwbGFjZSgvXi0rLywgJycpO1xuXG4gICAgbGV0IHZhbHVlOiBDbGlBcmdWYWx1ZTtcbiAgICBpZiAoaW5saW5lVmFsdWUgIT09IHVuZGVmaW5lZCkge1xuICAgICAgdmFsdWUgPSBpbmxpbmVWYWx1ZTtcbiAgICB9IGVsc2Uge1xuICAgICAgY29uc3QgbmV4dCA9IGFyZ3ZbaSArIDFdO1xuICAgICAgaWYgKG5leHQgIT09IHVuZGVmaW5lZCAmJiAhbmV4dC5zdGFydHNXaXRoKCctJykpIHtcbiAgICAgICAgdmFsdWUgPSBuZXh0O1xuICAgICAgICBpICs9IDE7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICB2YWx1ZSA9IHRydWU7XG4gICAgICB9XG4gICAgfVxuXG4gICAgYXJnc1tub3JtYWxpc2VkS2V5XSA9IHZhbHVlO1xuICB9XG5cbiAgcmV0dXJuIGFyZ3M7XG59XG5cbiIsICJjb25zdCBGSUxFX0tFWV9SRUdFWCA9IC9maWdtYVxcLmNvbVxcLyg/OmZpbGV8ZGVzaWduKVxcLyhbQS1aYS16MC05XSspXFwvL2k7XG5cbmV4cG9ydCBpbnRlcmZhY2UgUGFyc2VkRmlnbWFVcmwge1xuICBmaWxlS2V5OiBzdHJpbmcgfCBudWxsO1xuICBub2RlSWQ6IHN0cmluZyB8IG51bGw7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBwYXJzZUZpZ21hVXJsKGlucHV0OiBzdHJpbmcgfCBudWxsIHwgdW5kZWZpbmVkKTogUGFyc2VkRmlnbWFVcmwge1xuICBpZiAoIWlucHV0KSByZXR1cm4geyBmaWxlS2V5OiBudWxsLCBub2RlSWQ6IG51bGwgfTtcbiAgdHJ5IHtcbiAgICBjb25zdCB1cmwgPSBuZXcgVVJMKGlucHV0KTtcbiAgICBjb25zdCBtYXRjaCA9IHVybC5ocmVmLm1hdGNoKEZJTEVfS0VZX1JFR0VYKTtcbiAgICBjb25zdCBmaWxlS2V5ID0gbWF0Y2ggPyBtYXRjaFsxXSA6IG51bGw7XG4gICAgY29uc3Qgbm9kZVBhcmFtID0gdXJsLnNlYXJjaFBhcmFtcy5nZXQoJ25vZGUtaWQnKTtcbiAgICBjb25zdCBub2RlSWQgPSBub2RlUGFyYW0gPyBlbnN1cmVOb2RlSWQobm9kZVBhcmFtKSA6IG51bGw7XG4gICAgcmV0dXJuIHsgZmlsZUtleSwgbm9kZUlkIH07XG4gIH0gY2F0Y2gge1xuICAgIHJldHVybiB7IGZpbGVLZXk6IG51bGwsIG5vZGVJZDogbnVsbCB9O1xuICB9XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBlbnN1cmVOb2RlSWQodmFsdWU6IHN0cmluZyB8IG51bGwgfCB1bmRlZmluZWQpOiBzdHJpbmcgfCBudWxsIHtcbiAgaWYgKCF2YWx1ZSkgcmV0dXJuIG51bGw7XG4gIGNvbnN0IGRlY29kZWQgPSBkZWNvZGVVUklDb21wb25lbnQodmFsdWUpO1xuICBpZiAoZGVjb2RlZC5pbmNsdWRlcygnOicpKSByZXR1cm4gZGVjb2RlZDtcbiAgaWYgKC9eWzAtOV0rLVswLTldKyQvLnRlc3QoZGVjb2RlZCkpIHtcbiAgICBjb25zdCBbbGVmdCwgcmlnaHRdID0gZGVjb2RlZC5zcGxpdCgnLScsIDIpO1xuICAgIHJldHVybiBgJHtsZWZ0fToke3JpZ2h0fWA7XG4gIH1cbiAgcmV0dXJuIGRlY29kZWQ7XG59XG5cbiIsICJleHBvcnQgZGVmYXVsdCB7XG4gIHNjaGVtYVZlcnNpb246ICcxLjAuMCcsXG4gIHNvdXJjZTogJ2FnZW50aWMtY29kaW5nLXRlbXBsYXRlcy9maWdtYS10b29scycsXG4gIGh0dHA6IHtcbiAgICBtYXhBdHRlbXB0czogNSxcbiAgICBpbml0aWFsRGVsYXlNczogMjUwLFxuICB9LFxufSBhcyBjb25zdDtcblxuIiwgImltcG9ydCBjb25maWcgZnJvbSAnLi9jb25maWcudHMnO1xuaW1wb3J0IHR5cGUgeyBUb29sRXJyb3IgfSBmcm9tICcuL2Vycm9ycy50cyc7XG5cbmV4cG9ydCBpbnRlcmZhY2UgUmF0ZUxpbWl0TWV0YSB7XG4gIHJlbWFpbmluZzogbnVtYmVyIHwgbnVsbDtcbiAgcmVzZXRBdDogc3RyaW5nIHwgbnVsbDtcbiAgYXR0ZW1wdHM6IG51bWJlcjtcbiAgbGFzdFdhaXRNczogbnVtYmVyO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIFRvb2xFbnZlbG9wZTxcbiAgVElucHV0IGV4dGVuZHMgUmVjb3JkPHN0cmluZywgdW5rbm93bj4gPSBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPixcbiAgVERhdGEgPSB1bmtub3duXG4+IHtcbiAgc2NoZW1hVmVyc2lvbjogc3RyaW5nO1xuICB0b29sOiBzdHJpbmc7XG4gIGlucHV0OiBUSW5wdXQ7XG4gIG1ldGE6IHtcbiAgICBnZW5lcmF0ZWRBdDogc3RyaW5nO1xuICAgIHNvdXJjZTogc3RyaW5nO1xuICAgIHJhdGVMaW1pdDogUmF0ZUxpbWl0TWV0YTtcbiAgfTtcbiAgZGF0YTogVERhdGE7XG4gIHdhcm5pbmdzOiBzdHJpbmdbXTtcbiAgZXJyb3JzOiBUb29sRXJyb3JbXTtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBDcmVhdGVFbnZlbG9wZU9wdGlvbnM8XG4gIFRJbnB1dCBleHRlbmRzIFJlY29yZDxzdHJpbmcsIHVua25vd24+ID0gUmVjb3JkPHN0cmluZywgdW5rbm93bj4sXG4gIFREYXRhID0gdW5rbm93blxuPiB7XG4gIHRvb2w6IHN0cmluZztcbiAgaW5wdXQ/OiBUSW5wdXQ7XG4gIGRhdGE/OiBURGF0YTtcbiAgd2FybmluZ3M/OiBzdHJpbmdbXTtcbiAgZXJyb3JzPzogVG9vbEVycm9yW107XG4gIHJhdGVMaW1pdD86IFBhcnRpYWw8UmF0ZUxpbWl0TWV0YT47XG4gIHNjaGVtYVZlcnNpb24/OiBzdHJpbmc7XG59XG5cbmZ1bmN0aW9uIGJ1aWxkUmF0ZUxpbWl0TWV0YShyYXRlTGltaXQ6IFBhcnRpYWw8UmF0ZUxpbWl0TWV0YT4gPSB7fSk6IFJhdGVMaW1pdE1ldGEge1xuICByZXR1cm4ge1xuICAgIHJlbWFpbmluZzogcmF0ZUxpbWl0LnJlbWFpbmluZyA/PyBudWxsLFxuICAgIHJlc2V0QXQ6IHJhdGVMaW1pdC5yZXNldEF0ID8/IG51bGwsXG4gICAgYXR0ZW1wdHM6IHJhdGVMaW1pdC5hdHRlbXB0cyA/PyAxLFxuICAgIGxhc3RXYWl0TXM6IHJhdGVMaW1pdC5sYXN0V2FpdE1zID8/IDAsXG4gIH07XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBjcmVhdGVFbnZlbG9wZTxcbiAgVElucHV0IGV4dGVuZHMgUmVjb3JkPHN0cmluZywgdW5rbm93bj4gPSBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPixcbiAgVERhdGEgPSB1bmtub3duXG4+KHtcbiAgdG9vbCxcbiAgaW5wdXQgPSB7fSBhcyBUSW5wdXQsXG4gIGRhdGEgPSB7fSBhcyBURGF0YSxcbiAgd2FybmluZ3MgPSBbXSxcbiAgZXJyb3JzID0gW10sXG4gIHJhdGVMaW1pdCxcbiAgc2NoZW1hVmVyc2lvbixcbn06IENyZWF0ZUVudmVsb3BlT3B0aW9uczxUSW5wdXQsIFREYXRhPik6IFRvb2xFbnZlbG9wZTxUSW5wdXQsIFREYXRhPiB7XG4gIHJldHVybiB7XG4gICAgc2NoZW1hVmVyc2lvbjogc2NoZW1hVmVyc2lvbiA/PyBjb25maWcuc2NoZW1hVmVyc2lvbixcbiAgICB0b29sLFxuICAgIGlucHV0LFxuICAgIG1ldGE6IHtcbiAgICAgIGdlbmVyYXRlZEF0OiBuZXcgRGF0ZSgpLnRvSVNPU3RyaW5nKCksXG4gICAgICBzb3VyY2U6IGNvbmZpZy5zb3VyY2UsXG4gICAgICByYXRlTGltaXQ6IGJ1aWxkUmF0ZUxpbWl0TWV0YShyYXRlTGltaXQpLFxuICAgIH0sXG4gICAgZGF0YSxcbiAgICB3YXJuaW5ncyxcbiAgICBlcnJvcnMsXG4gIH07XG59XG5cbiIsICJleHBvcnQgY29uc3QgRVJST1JfRVhJVF9DT0RFUyA9IHtcbiAgSU5QVVRfSU5WQUxJRDogMSxcbiAgQ09ORklHX0lOVkFMSUQ6IDEsXG4gIEZJR01BX0FVVEg6IDEsXG4gIEZJR01BX05PVF9GT1VORDogMixcbiAgRklHTUFfUkFURV9MSU1JVDogMixcbiAgTkVUV09SSzogMixcbiAgSU5URVJOQUw6IDMsXG59IGFzIGNvbnN0O1xuXG5leHBvcnQgdHlwZSBFcnJvckNvZGUgPSBrZXlvZiB0eXBlb2YgRVJST1JfRVhJVF9DT0RFUztcblxuZXhwb3J0IGludGVyZmFjZSBUb29sRXJyb3I8VERldGFpbCA9IHVua25vd24+IHtcbiAgY29kZTogRXJyb3JDb2RlIHwgc3RyaW5nO1xuICBtZXNzYWdlOiBzdHJpbmc7XG4gIGRldGFpbD86IFREZXRhaWwgfCBudWxsO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gY3JlYXRlRXJyb3I8VERldGFpbCA9IHVua25vd24+KFxuICBjb2RlOiBFcnJvckNvZGUgfCBzdHJpbmcsXG4gIG1lc3NhZ2U6IHN0cmluZyxcbiAgZGV0YWlsPzogVERldGFpbCB8IG51bGxcbik6IFRvb2xFcnJvcjxURGV0YWlsPiB7XG4gIHJldHVybiB7XG4gICAgY29kZSxcbiAgICBtZXNzYWdlLFxuICAgIGRldGFpbDogZGV0YWlsID8/IG51bGwsXG4gIH07XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBnZXRFeGl0Q29kZShlcnJvcnM6IFRvb2xFcnJvcltdID0gW10pOiBudW1iZXIge1xuICBpZiAoIWVycm9ycy5sZW5ndGgpIHtcbiAgICByZXR1cm4gMDtcbiAgfVxuXG4gIHJldHVybiBlcnJvcnMucmVkdWNlKChtYXgsIGVycm9yKSA9PiB7XG4gICAgY29uc3QgZXhpdENvZGUgPSBFUlJPUl9FWElUX0NPREVTW2Vycm9yLmNvZGUgYXMgRXJyb3JDb2RlXSA/PyAxO1xuICAgIHJldHVybiBNYXRoLm1heChtYXgsIGV4aXRDb2RlKTtcbiAgfSwgMCk7XG59XG5cbiIsICJpbXBvcnQgY29uZmlnIGZyb20gJy4vY29uZmlnLnRzJztcbmltcG9ydCB7IGNyZWF0ZUVycm9yIH0gZnJvbSAnLi9lcnJvcnMudHMnO1xuaW1wb3J0IHR5cGUgeyBUb29sRXJyb3IgfSBmcm9tICcuL2Vycm9ycy50cyc7XG5pbXBvcnQgdHlwZSB7IFJhdGVMaW1pdE1ldGEgfSBmcm9tICcuL2VudmVsb3BlLnRzJztcblxuY29uc3QgQkFTRV9VUkwgPSAnaHR0cHM6Ly9hcGkuZmlnbWEuY29tJztcblxudHlwZSBTZWFyY2hQYXJhbXMgPSBSZWNvcmQ8c3RyaW5nLCBzdHJpbmcgfCBudW1iZXIgfCBib29sZWFuIHwgbnVsbCB8IHVuZGVmaW5lZD47XG5cbmludGVyZmFjZSBGaWdtYVJlcXVlc3RPcHRpb25zIHtcbiAgcGF0aDogc3RyaW5nO1xuICBtZXRob2Q/OiBzdHJpbmc7XG4gIHRva2VuPzogc3RyaW5nO1xuICBoZWFkZXJzPzogUmVjb3JkPHN0cmluZywgc3RyaW5nPjtcbiAgYm9keT86IHVua25vd247XG4gIHNlYXJjaFBhcmFtcz86IFNlYXJjaFBhcmFtcztcbiAgbWF4QXR0ZW1wdHM/OiBudW1iZXI7XG4gIGluaXRpYWxEZWxheU1zPzogbnVtYmVyO1xufVxuXG5pbnRlcmZhY2UgRmlnbWFTdWNjZXNzPFREYXRhPiB7XG4gIG9rOiB0cnVlO1xuICBkYXRhOiBURGF0YTtcbiAgcmF0ZUxpbWl0OiBSYXRlTGltaXRNZXRhO1xufVxuXG5pbnRlcmZhY2UgRmlnbWFGYWlsdXJlIHtcbiAgb2s6IGZhbHNlO1xuICBlcnJvcjogVG9vbEVycm9yPHsgc3RhdHVzPzogbnVtYmVyIH0+O1xuICBzdGF0dXM/OiBudW1iZXIgfCBudWxsO1xuICByYXRlTGltaXQ6IFJhdGVMaW1pdE1ldGEgfCBudWxsO1xufVxuXG5leHBvcnQgdHlwZSBGaWdtYVJlc3BvbnNlPFREYXRhPiA9IEZpZ21hU3VjY2VzczxURGF0YT4gfCBGaWdtYUZhaWx1cmU7XG5cbmZ1bmN0aW9uIHNsZWVwKG1zOiBudW1iZXIpOiBQcm9taXNlPHZvaWQ+IHtcbiAgcmV0dXJuIG5ldyBQcm9taXNlKChyZXNvbHZlKSA9PiBzZXRUaW1lb3V0KHJlc29sdmUsIG1zKSk7XG59XG5cbmZ1bmN0aW9uIHBhcnNlSnNvblNhZmVseSh0ZXh0OiBzdHJpbmcpOiB1bmtub3duIHtcbiAgdHJ5IHtcbiAgICByZXR1cm4gdGV4dCA/IEpTT04ucGFyc2UodGV4dCkgOiB7fTtcbiAgfSBjYXRjaCB7XG4gICAgcmV0dXJuIHsgcmF3OiB0ZXh0IH07XG4gIH1cbn1cblxuZnVuY3Rpb24gcGFyc2VSYXRlTGltaXQoaGVhZGVyczogSGVhZGVycywgYXR0ZW1wdHM6IG51bWJlciwgbGFzdFdhaXRNczogbnVtYmVyKTogUmF0ZUxpbWl0TWV0YSB7XG4gIGNvbnN0IHJlbWFpbmluZ0hlYWRlciA9IGhlYWRlcnMuZ2V0KCd4LXJhdGVsaW1pdC1yZW1haW5pbmcnKTtcbiAgY29uc3QgcmVzZXRIZWFkZXIgPSBoZWFkZXJzLmdldCgneC1yYXRlbGltaXQtcmVzZXQnKTtcblxuICBsZXQgcmVtYWluaW5nOiBudW1iZXIgfCBudWxsID0gbnVsbDtcbiAgaWYgKHJlbWFpbmluZ0hlYWRlciAhPT0gbnVsbCAmJiByZW1haW5pbmdIZWFkZXIgIT09IHVuZGVmaW5lZCkge1xuICAgIGNvbnN0IHBhcnNlZCA9IE51bWJlcihyZW1haW5pbmdIZWFkZXIpO1xuICAgIHJlbWFpbmluZyA9IE51bWJlci5pc05hTihwYXJzZWQpID8gbnVsbCA6IHBhcnNlZDtcbiAgfVxuXG4gIGxldCByZXNldEF0OiBzdHJpbmcgfCBudWxsID0gbnVsbDtcbiAgaWYgKHJlc2V0SGVhZGVyKSB7XG4gICAgY29uc3QgbnVtZXJpY1Jlc2V0ID0gTnVtYmVyKHJlc2V0SGVhZGVyKTtcbiAgICBpZiAoIU51bWJlci5pc05hTihudW1lcmljUmVzZXQpKSB7XG4gICAgICByZXNldEF0ID0gbmV3IERhdGUobnVtZXJpY1Jlc2V0ICogMTAwMCkudG9JU09TdHJpbmcoKTtcbiAgICB9IGVsc2Uge1xuICAgICAgY29uc3QgZGF0ZSA9IG5ldyBEYXRlKHJlc2V0SGVhZGVyKTtcbiAgICAgIGlmICghTnVtYmVyLmlzTmFOKGRhdGUudmFsdWVPZigpKSkge1xuICAgICAgICByZXNldEF0ID0gZGF0ZS50b0lTT1N0cmluZygpO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIHJldHVybiB7XG4gICAgcmVtYWluaW5nLFxuICAgIHJlc2V0QXQsXG4gICAgYXR0ZW1wdHMsXG4gICAgbGFzdFdhaXRNcyxcbiAgfTtcbn1cblxuZnVuY3Rpb24gY29tcHV0ZUJhY2tvZmZNcyhhdHRlbXB0OiBudW1iZXIsIGluaXRpYWxEZWxheU1zOiBudW1iZXIpOiBudW1iZXIge1xuICByZXR1cm4gaW5pdGlhbERlbGF5TXMgKiAyICoqIChhdHRlbXB0IC0gMSk7XG59XG5cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBmaWdtYVJlcXVlc3Q8VERhdGEgPSB1bmtub3duPihcbiAgb3B0aW9uczogRmlnbWFSZXF1ZXN0T3B0aW9uc1xuKTogUHJvbWlzZTxGaWdtYVJlc3BvbnNlPFREYXRhPj4ge1xuICBjb25zdCB7XG4gICAgcGF0aCxcbiAgICBtZXRob2QgPSAnR0VUJyxcbiAgICB0b2tlbixcbiAgICBoZWFkZXJzID0ge30sXG4gICAgYm9keSxcbiAgICBzZWFyY2hQYXJhbXMsXG4gICAgbWF4QXR0ZW1wdHMgPSBjb25maWcuaHR0cD8ubWF4QXR0ZW1wdHMgPz8gNSxcbiAgICBpbml0aWFsRGVsYXlNcyA9IGNvbmZpZy5odHRwPy5pbml0aWFsRGVsYXlNcyA/PyAyNTAsXG4gIH0gPSBvcHRpb25zO1xuXG4gIGlmICghdG9rZW4pIHtcbiAgICByZXR1cm4ge1xuICAgICAgb2s6IGZhbHNlLFxuICAgICAgZXJyb3I6IGNyZWF0ZUVycm9yKCdGSUdNQV9BVVRIJywgJ0ZJR01BX0FDQ0VTU19UT0tFTiBpcyBtaXNzaW5nIGZyb20gdGhlIGVudmlyb25tZW50LicpLFxuICAgICAgc3RhdHVzOiBudWxsLFxuICAgICAgcmF0ZUxpbWl0OiBudWxsLFxuICAgIH07XG4gIH1cblxuICBjb25zdCB1cmwgPSBuZXcgVVJMKHBhdGgsIEJBU0VfVVJMKTtcblxuICBpZiAoc2VhcmNoUGFyYW1zKSB7XG4gICAgT2JqZWN0LmVudHJpZXMoc2VhcmNoUGFyYW1zKS5mb3JFYWNoKChba2V5LCB2YWx1ZV0pID0+IHtcbiAgICAgIGlmICh2YWx1ZSA9PT0gdW5kZWZpbmVkIHx8IHZhbHVlID09PSBudWxsKSByZXR1cm47XG4gICAgICB1cmwuc2VhcmNoUGFyYW1zLmFwcGVuZChrZXksIFN0cmluZyh2YWx1ZSkpO1xuICAgIH0pO1xuICB9XG5cbiAgbGV0IGF0dGVtcHQgPSAwO1xuICBsZXQgbGFzdFdhaXRNcyA9IDA7XG5cbiAgd2hpbGUgKGF0dGVtcHQgPCBtYXhBdHRlbXB0cykge1xuICAgIGF0dGVtcHQgKz0gMTtcblxuICAgIGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgZmV0Y2godXJsLCB7XG4gICAgICBtZXRob2QsXG4gICAgICBoZWFkZXJzOiB7XG4gICAgICAgICdDb250ZW50LVR5cGUnOiAnYXBwbGljYXRpb24vanNvbicsXG4gICAgICAgICdYLUZpZ21hLVRva2VuJzogdG9rZW4sXG4gICAgICAgIC4uLmhlYWRlcnMsXG4gICAgICB9LFxuICAgICAgYm9keTogYm9keSA/IEpTT04uc3RyaW5naWZ5KGJvZHkpIDogdW5kZWZpbmVkLFxuICAgIH0pO1xuXG4gICAgY29uc3QgdGV4dCA9IGF3YWl0IHJlc3BvbnNlLnRleHQoKTtcbiAgICBjb25zdCBwYXlsb2FkID0gcGFyc2VKc29uU2FmZWx5KHRleHQpIGFzIHsgbWVzc2FnZT86IHN0cmluZyB9O1xuICAgIGNvbnN0IHJhdGVMaW1pdCA9IHBhcnNlUmF0ZUxpbWl0KHJlc3BvbnNlLmhlYWRlcnMsIGF0dGVtcHQsIGxhc3RXYWl0TXMpO1xuXG4gICAgaWYgKHJlc3BvbnNlLm9rKSB7XG4gICAgICByZXR1cm4geyBvazogdHJ1ZSwgZGF0YTogcGF5bG9hZCBhcyBURGF0YSwgcmF0ZUxpbWl0IH07XG4gICAgfVxuXG4gICAgY29uc3Qgc3RhdHVzID0gcmVzcG9uc2Uuc3RhdHVzO1xuXG4gICAgaWYgKHN0YXR1cyA9PT0gNDAxIHx8IHN0YXR1cyA9PT0gNDAzKSB7XG4gICAgICByZXR1cm4geyBvazogZmFsc2UsIGVycm9yOiBjcmVhdGVFcnJvcignRklHTUFfQVVUSCcsIHBheWxvYWQ/Lm1lc3NhZ2UgPz8gJ0ZpZ21hIHRva2VuIGlzIHVuYXV0aG9yaXplZC4nLCB7IHN0YXR1cyB9KSwgc3RhdHVzLCByYXRlTGltaXQgfTtcbiAgICB9XG5cbiAgICBpZiAoc3RhdHVzID09PSA0MDQpIHtcbiAgICAgIHJldHVybiB7IG9rOiBmYWxzZSwgZXJyb3I6IGNyZWF0ZUVycm9yKCdGSUdNQV9OT1RfRk9VTkQnLCBwYXlsb2FkPy5tZXNzYWdlID8/ICdSZXNvdXJjZSBub3QgZm91bmQuJywgeyBzdGF0dXMgfSksIHN0YXR1cywgcmF0ZUxpbWl0IH07XG4gICAgfVxuXG4gICAgaWYgKHN0YXR1cyA9PT0gNDI5IHx8IHN0YXR1cyA+PSA1MDApIHtcbiAgICAgIGlmIChhdHRlbXB0ID49IG1heEF0dGVtcHRzKSB7XG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgb2s6IGZhbHNlLFxuICAgICAgICAgIGVycm9yOiBjcmVhdGVFcnJvcihzdGF0dXMgPT09IDQyOSA/ICdGSUdNQV9SQVRFX0xJTUlUJyA6ICdORVRXT1JLJywgcGF5bG9hZD8ubWVzc2FnZSA/PyAnRmlnbWEgcmVxdWVzdCBmYWlsZWQgYWZ0ZXIgbWF4aW11bSByZXRyaWVzLicsIHsgc3RhdHVzIH0pLFxuICAgICAgICAgIHN0YXR1cyxcbiAgICAgICAgICByYXRlTGltaXQsXG4gICAgICAgIH07XG4gICAgICB9XG5cbiAgICAgIGxldCB3YWl0TXMgPSBjb21wdXRlQmFja29mZk1zKGF0dGVtcHQsIGluaXRpYWxEZWxheU1zKTtcbiAgICAgIGNvbnN0IHJlc2V0SGVhZGVyID0gcmVzcG9uc2UuaGVhZGVycy5nZXQoJ3gtcmF0ZWxpbWl0LXJlc2V0Jyk7XG4gICAgICBpZiAocmVzZXRIZWFkZXIpIHtcbiAgICAgICAgY29uc3QgYXNOdW1iZXIgPSBOdW1iZXIocmVzZXRIZWFkZXIpO1xuICAgICAgICBpZiAoIU51bWJlci5pc05hTihhc051bWJlcikpIHtcbiAgICAgICAgICBjb25zdCByZXNldE1zID0gYXNOdW1iZXIgKiAxMDAwO1xuICAgICAgICAgIGNvbnN0IGRlbHRhID0gcmVzZXRNcyAtIERhdGUubm93KCk7XG4gICAgICAgICAgaWYgKGRlbHRhID4gMCkgd2FpdE1zID0gTWF0aC5tYXgod2FpdE1zLCBkZWx0YSk7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgY29uc3Qgaml0dGVyID0gTWF0aC5mbG9vcihNYXRoLnJhbmRvbSgpICogMTAwKTtcbiAgICAgIGxhc3RXYWl0TXMgPSB3YWl0TXMgKyBqaXR0ZXI7XG4gICAgICBhd2FpdCBzbGVlcChsYXN0V2FpdE1zKTtcbiAgICAgIGNvbnRpbnVlO1xuICAgIH1cblxuICAgIHJldHVybiB7IG9rOiBmYWxzZSwgZXJyb3I6IGNyZWF0ZUVycm9yKCdJTlRFUk5BTCcsIHBheWxvYWQ/Lm1lc3NhZ2UgPz8gJ1VuZXhwZWN0ZWQgZXJyb3IgZnJvbSBGaWdtYSBBUEkuJywgeyBzdGF0dXMgfSksIHN0YXR1cywgcmF0ZUxpbWl0IH07XG4gIH1cblxuICByZXR1cm4ge1xuICAgIG9rOiBmYWxzZSxcbiAgICBlcnJvcjogY3JlYXRlRXJyb3IoJ05FVFdPUksnLCAnVW5hYmxlIHRvIHJlYWNoIEZpZ21hIEFQSS4nKSxcbiAgICBzdGF0dXM6IG51bGwsXG4gICAgcmF0ZUxpbWl0OiB7IHJlbWFpbmluZzogbnVsbCwgcmVzZXRBdDogbnVsbCwgYXR0ZW1wdHM6IG1heEF0dGVtcHRzLCBsYXN0V2FpdE1zIH0sXG4gIH07XG59XG5cbiJdLAogICJtYXBwaW5ncyI6ICI7OztBQUVBLFNBQVMsZ0JBQWdCO0FBQ3pCLE9BQU8sVUFBVTs7O0FDSVYsU0FBUyxVQUFVLE9BQWlCLFFBQVEsS0FBSyxNQUFNLENBQUMsR0FBWTtBQUN6RSxRQUFNLE9BQWdCLEVBQUUsR0FBRyxDQUFDLEVBQUU7QUFFOUIsV0FBUyxJQUFJLEdBQUcsSUFBSSxLQUFLLFFBQVEsS0FBSyxHQUFHO0FBQ3ZDLFVBQU0sTUFBTSxLQUFLLENBQUM7QUFFbEIsUUFBSSxDQUFDLElBQUksV0FBVyxHQUFHLEtBQUssUUFBUSxLQUFLO0FBQ3ZDLFdBQUssRUFBRSxLQUFLLEdBQUc7QUFDZjtBQUFBLElBQ0Y7QUFFQSxRQUFJLFFBQVEsTUFBTTtBQUNoQixZQUFNLFlBQVksS0FBSyxNQUFNLElBQUksQ0FBQztBQUNsQyxXQUFLLEVBQUUsS0FBSyxHQUFHLFNBQVM7QUFDeEI7QUFBQSxJQUNGO0FBRUEsVUFBTSxDQUFDLFFBQVEsV0FBVyxJQUFJLElBQUksTUFBTSxLQUFLLENBQUM7QUFDOUMsVUFBTSxnQkFBZ0IsT0FBTyxRQUFRLE9BQU8sRUFBRTtBQUU5QyxRQUFJO0FBQ0osUUFBSSxnQkFBZ0IsUUFBVztBQUM3QixjQUFRO0FBQUEsSUFDVixPQUFPO0FBQ0wsWUFBTSxPQUFPLEtBQUss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 diff --git a/use-figma/scripts/get-design-context.mjs b/use-figma/scripts/get-design-context.mjs new file mode 100755 index 0000000..825361e --- /dev/null +++ b/use-figma/scripts/get-design-context.mjs @@ -0,0 +1,484 @@ +#!/usr/bin/env node + +// coding-tools/figma-tools/js/src/get-design-context.ts +import { createHash } from "node:crypto"; + +// coding-tools/figma-tools/js/src/_utils/cli-args.ts +function parseArgs(argv = process.argv.slice(2)) { + const args = { _: [] }; + for (let i = 0; i < argv.length; i += 1) { + const arg = argv[i]; + if (!arg.startsWith("-") || arg === "-") { + args._.push(arg); + continue; + } + if (arg === "--") { + const remaining = argv.slice(i + 1); + args._.push(...remaining); + break; + } + const [rawKey, inlineValue] = arg.split("=", 2); + const normalisedKey = rawKey.replace(/^-+/, ""); + let value; + if (inlineValue !== void 0) { + value = inlineValue; + } else { + const next = argv[i + 1]; + if (next !== void 0 && !next.startsWith("-")) { + value = next; + i += 1; + } else { + value = true; + } + } + args[normalisedKey] = value; + } + return args; +} + +// coding-tools/figma-tools/js/src/_utils/config.ts +var config_default = { + schemaVersion: "1.0.0", + source: "agentic-coding-templates/figma-tools", + http: { + maxAttempts: 5, + initialDelayMs: 250 + } +}; + +// coding-tools/figma-tools/js/src/_utils/envelope.ts +function buildRateLimitMeta(rateLimit = {}) { + return { + remaining: rateLimit.remaining ?? null, + resetAt: rateLimit.resetAt ?? null, + attempts: rateLimit.attempts ?? 1, + lastWaitMs: rateLimit.lastWaitMs ?? 0 + }; +} +function createEnvelope({ + tool, + input = {}, + data = {}, + warnings = [], + errors = [], + rateLimit, + schemaVersion +}) { + return { + schemaVersion: schemaVersion ?? config_default.schemaVersion, + tool, + input, + meta: { + generatedAt: (/* @__PURE__ */ new Date()).toISOString(), + source: config_default.source, + rateLimit: buildRateLimitMeta(rateLimit) + }, + data, + warnings, + errors + }; +} + +// coding-tools/figma-tools/js/src/_utils/errors.ts +var ERROR_EXIT_CODES = { + INPUT_INVALID: 1, + CONFIG_INVALID: 1, + FIGMA_AUTH: 1, + FIGMA_NOT_FOUND: 2, + FIGMA_RATE_LIMIT: 2, + NETWORK: 2, + INTERNAL: 3 +}; +function createError(code, message, detail) { + return { + code, + message, + detail: detail ?? null + }; +} +function getExitCode(errors = []) { + if (!errors.length) { + return 0; + } + return errors.reduce((max, error) => { + const exitCode = ERROR_EXIT_CODES[error.code] ?? 1; + return Math.max(max, exitCode); + }, 0); +} + +// coding-tools/figma-tools/js/src/_utils/http-client.ts +var BASE_URL = "https://api.figma.com"; +function sleep(ms) { + return new Promise((resolve) => setTimeout(resolve, ms)); +} +function parseJsonSafely(text) { + try { + return text ? JSON.parse(text) : {}; + } catch { + return { raw: text }; + } +} +function parseRateLimit(headers, attempts, lastWaitMs) { + const remainingHeader = headers.get("x-ratelimit-remaining"); + const resetHeader = headers.get("x-ratelimit-reset"); + let remaining = null; + if (remainingHeader !== null && remainingHeader !== void 0) { + const parsed = Number(remainingHeader); + remaining = Number.isNaN(parsed) ? null : parsed; + } + let resetAt = null; + if (resetHeader) { + const numericReset = Number(resetHeader); + if (!Number.isNaN(numericReset)) { + resetAt = new Date(numericReset * 1e3).toISOString(); + } else { + const date = new Date(resetHeader); + if (!Number.isNaN(date.valueOf())) { + resetAt = date.toISOString(); + } + } + } + return { + remaining, + resetAt, + attempts, + lastWaitMs + }; +} +function computeBackoffMs(attempt, initialDelayMs) { + return initialDelayMs * 2 ** (attempt - 1); +} +async function figmaRequest(options) { + const { + path, + method = "GET", + token, + headers = {}, + body, + searchParams, + maxAttempts = config_default.http?.maxAttempts ?? 5, + initialDelayMs = config_default.http?.initialDelayMs ?? 250 + } = options; + if (!token) { + return { + ok: false, + error: createError("FIGMA_AUTH", "FIGMA_ACCESS_TOKEN is missing from the environment."), + status: null, + rateLimit: null + }; + } + const url = new URL(path, BASE_URL); + if (searchParams) { + Object.entries(searchParams).forEach(([key, value]) => { + if (value === void 0 || value === null) return; + url.searchParams.append(key, String(value)); + }); + } + let attempt = 0; + let lastWaitMs = 0; + while (attempt < maxAttempts) { + attempt += 1; + const response = await fetch(url, { + method, + headers: { + "Content-Type": "application/json", + "X-Figma-Token": token, + ...headers + }, + body: body ? JSON.stringify(body) : void 0 + }); + const text = await response.text(); + const payload = parseJsonSafely(text); + const rateLimit = parseRateLimit(response.headers, attempt, lastWaitMs); + if (response.ok) { + return { ok: true, data: payload, rateLimit }; + } + const status = response.status; + if (status === 401 || status === 403) { + return { ok: false, error: createError("FIGMA_AUTH", payload?.message ?? "Figma token is unauthorized.", { status }), status, rateLimit }; + } + if (status === 404) { + return { ok: false, error: createError("FIGMA_NOT_FOUND", payload?.message ?? "Resource not found.", { status }), status, rateLimit }; + } + if (status === 429 || status >= 500) { + if (attempt >= maxAttempts) { + return { + ok: false, + error: createError(status === 429 ? "FIGMA_RATE_LIMIT" : "NETWORK", payload?.message ?? "Figma request failed after maximum retries.", { status }), + status, + rateLimit + }; + } + let waitMs = computeBackoffMs(attempt, initialDelayMs); + const resetHeader = response.headers.get("x-ratelimit-reset"); + if (resetHeader) { + const asNumber = Number(resetHeader); + if (!Number.isNaN(asNumber)) { + const resetMs = asNumber * 1e3; + const delta = resetMs - Date.now(); + if (delta > 0) waitMs = Math.max(waitMs, delta); + } + } + const jitter = Math.floor(Math.random() * 100); + lastWaitMs = waitMs + jitter; + await sleep(lastWaitMs); + continue; + } + return { ok: false, error: createError("INTERNAL", payload?.message ?? "Unexpected error from Figma API.", { status }), status, rateLimit }; + } + return { + ok: false, + error: createError("NETWORK", "Unable to reach Figma API."), + status: null, + rateLimit: { remaining: null, resetAt: null, attempts: maxAttempts, lastWaitMs } + }; +} + +// coding-tools/figma-tools/js/src/_utils/url-parse.ts +var FILE_KEY_REGEX = /figma\.com\/(?:file|design)\/([A-Za-z0-9]+)\//i; +function parseFigmaUrl(input) { + if (!input) return { fileKey: null, nodeId: null }; + try { + const url = new URL(input); + const match = url.href.match(FILE_KEY_REGEX); + const fileKey = match ? match[1] : null; + const nodeParam = url.searchParams.get("node-id"); + const nodeId = nodeParam ? ensureNodeId(nodeParam) : null; + return { fileKey, nodeId }; + } catch { + return { fileKey: null, nodeId: null }; + } +} +function ensureNodeId(value) { + if (!value) return null; + const decoded = decodeURIComponent(value); + if (decoded.includes(":")) return decoded; + if (/^[0-9]+-[0-9]+$/.test(decoded)) { + const [left, right] = decoded.split("-", 2); + return `${left}:${right}`; + } + return decoded; +} + +// coding-tools/figma-tools/js/src/get-design-context.ts +var TOOL_NAME = "get-design-context"; +var VALID_IMAGE_FORMATS = ["png", "jpg", "jpeg", "svg"]; +function log(message, verbose) { + if (verbose) { + process.stderr.write(`[${TOOL_NAME}] ${message} +`); + } +} +function toOptionalString(value) { + return typeof value === "string" && value.length > 0 ? value : null; +} +function exitWithEnvelope(envelope, errors = []) { + process.stdout.write(`${JSON.stringify(envelope, null, 2)} +`); + process.exit(getExitCode(errors)); +} +function mapLayoutNode(node) { + const children = Array.isArray(node.children) ? node.children.map(mapLayoutNode) : []; + const bbox = node.absoluteBoundingBox; + const layout = bbox ? { x: bbox.x ?? 0, y: bbox.y ?? 0, width: bbox.width ?? 0, height: bbox.height ?? 0 } : null; + return { + id: node.id, + name: node.name, + type: node.type, + visible: node.visible ?? true, + layout, + rotation: node.rotation ?? 0, + clipsContent: node.clipsContent ?? false, + characters: node.characters ?? null, + fills: node.fills ?? [], + strokes: node.strokes ?? [], + effects: node.effects ?? [], + tailwindSuggestion: null, + children + }; +} +function buildStyleTokens(node) { + const cornerRadius = Array.isArray(node.rectangleCornerRadii) && node.rectangleCornerRadii.length > 0 ? node.rectangleCornerRadii : node.cornerRadius ?? null; + return { + fills: node.fills ?? [], + strokes: node.strokes ?? [], + effects: node.effects ?? [], + backgroundColor: node.backgroundColor ?? null, + textStyle: node.style ?? null, + styles: node.styles ?? {}, + cornerRadius + }; +} +function buildSelectionSummary(node, components, componentSets) { + const componentId = node.componentId ?? null; + const componentSetId = node.componentSetId ?? null; + const componentMeta = componentId ? components[componentId] ?? null : null; + const componentSetMeta = componentSetId ? componentSets[componentSetId] ?? null : null; + return { + id: node.id, + name: node.name, + type: node.type, + componentId, + componentKey: componentMeta?.key ?? null, + componentName: componentMeta?.name ?? null, + componentSetId, + componentSetName: componentSetMeta?.name ?? null, + variantProperties: node.variantProperties ?? null + }; +} +function computeLayoutHash(layoutTree) { + const json = JSON.stringify(layoutTree); + return createHash("sha1").update(json).digest("hex"); +} +async function fetchPreviewImage(fileKey, nodeId, token, imageFormat, scale, warnings, verbose) { + const format = VALID_IMAGE_FORMATS.includes(imageFormat) ? imageFormat : "png"; + const scaleClamped = Number.isFinite(scale) && scale > 0 ? scale : 1; + log(`Requesting preview image format=${format}, scale=${scaleClamped}`, verbose); + const imageResponse = await figmaRequest({ + path: `/v1/images/${fileKey}`, + token, + searchParams: { ids: nodeId, format, scale: scaleClamped } + }); + if (!imageResponse.ok) { + warnings.push(imageResponse.error?.message ?? "Failed to request preview image."); + return null; + } + const url = imageResponse.data?.images?.[nodeId]; + if (!url) return null; + return { url, format, size: `${scaleClamped}x` }; +} +async function main() { + const args = parseArgs(); + const verbose = Boolean(args.verbose ?? args.v); + const schemaVersion = toOptionalString(args["schema-version"]) ?? void 0; + const warnings = []; + const errors = []; + const token = process.env.FIGMA_ACCESS_TOKEN; + if (!token || !token.trim()) { + errors.push(createError("FIGMA_AUTH", "FIGMA_ACCESS_TOKEN is required but was not provided.")); + const envelope2 = createEnvelope({ + tool: TOOL_NAME, + input: { fileKey: null, nodeId: null, includeImages: false, imageFormat: "png", scale: 1 }, + warnings, + errors, + schemaVersion, + data: {} + }); + exitWithEnvelope(envelope2, errors); + } + const urlInput = toOptionalString(args.url) ?? toOptionalString(args.u); + let fileKey = toOptionalString(args["file-key"]) ?? void 0; + let nodeId = ensureNodeId(toOptionalString(args["node-id"])); + if (urlInput) { + const parsed = parseFigmaUrl(urlInput); + fileKey = fileKey || parsed.fileKey || void 0; + nodeId = nodeId || parsed.nodeId; + } + const includeImages = args["include-images"] !== "false"; + const imageFormatInput = String(args["image-format"] ?? "png").toLowerCase(); + const imageFormat = VALID_IMAGE_FORMATS.includes(imageFormatInput) ? imageFormatInput : "png"; + const scaleInput = Number(args.scale ?? 1); + const imageScale = Number.isFinite(scaleInput) && scaleInput > 0 ? scaleInput : 1; + const input = { + fileKey: fileKey ?? null, + nodeId: nodeId ?? null, + includeImages, + imageFormat, + scale: imageScale + }; + if (!fileKey) { + errors.push(createError("INPUT_INVALID", "A valid Figma file key is required (--file-key or --url).")); + } + if (!nodeId) { + errors.push(createError("INPUT_INVALID", "A valid Figma node id is required (--node-id or --url with node-id).")); + } + if (errors.length) { + const envelope2 = createEnvelope({ tool: TOOL_NAME, input, warnings, errors, data: {}, schemaVersion }); + exitWithEnvelope(envelope2, errors); + } + const resolvedFileKey = fileKey; + const resolvedNodeId = nodeId; + log(`Fetching node ${resolvedNodeId} from file ${resolvedFileKey}`, verbose); + const nodeResponse = await figmaRequest({ + path: `/v1/files/${resolvedFileKey}/nodes`, + token, + searchParams: { ids: resolvedNodeId } + }); + if (!nodeResponse.ok) { + errors.push(nodeResponse.error ?? createError("INTERNAL", "Failed to fetch node data.")); + const envelope2 = createEnvelope({ + tool: TOOL_NAME, + input, + warnings, + errors, + rateLimit: nodeResponse.rateLimit ?? void 0, + data: {}, + schemaVersion + }); + exitWithEnvelope(envelope2, errors); + } + const nodePayload = nodeResponse.data ?? {}; + const nodesMap = nodePayload.nodes ?? {}; + const nodeWrapper = nodesMap[resolvedNodeId]; + if (!nodeWrapper || !nodeWrapper.document) { + errors.push(createError("FIGMA_NOT_FOUND", `Node ${resolvedNodeId} was not found in file ${resolvedFileKey}.`)); + const envelope2 = createEnvelope({ tool: TOOL_NAME, input, warnings, errors, rateLimit: nodeResponse.rateLimit ?? void 0, data: {}, schemaVersion }); + exitWithEnvelope(envelope2, errors); + } + const node = nodeWrapper.document; + const components = nodeWrapper.components ?? {}; + const componentSets = nodeWrapper.componentSets ?? {}; + const selectionSummary = buildSelectionSummary(node, components, componentSets); + const layoutTree = mapLayoutNode(node); + const styleTokens = buildStyleTokens(node); + const layoutHash = computeLayoutHash(layoutTree); + let preview = null; + if (includeImages) { + preview = await fetchPreviewImage( + resolvedFileKey, + resolvedNodeId, + token, + imageFormat, + imageScale, + warnings, + verbose + ); + } + const data = { + file: { + key: resolvedFileKey, + name: nodePayload?.name ?? null, + lastModified: nodePayload?.lastModified ?? null + }, + selectionSummary, + layoutTree, + styleTokens, + layoutHash, + images: preview ? { preview } : null + }; + const envelope = createEnvelope({ + tool: TOOL_NAME, + input, + data, + warnings, + errors, + rateLimit: nodeResponse.rateLimit ?? void 0, + schemaVersion + }); + process.stdout.write(`${JSON.stringify(envelope, null, 2)} +`); + process.exit(getExitCode(errors)); +} +main().catch((error) => { + const message = error instanceof Error ? error.message : "Unknown error"; + const envelope = createEnvelope({ + tool: TOOL_NAME, + input: { fileKey: null, nodeId: null, includeImages: false, imageFormat: "png", scale: 1 }, + errors: [createError("INTERNAL", message, { stack: error instanceof Error ? error.stack : void 0 })], + data: {} + }); + process.stdout.write(`${JSON.stringify(envelope, null, 2)} +`); + process.exit(3); +}); +//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiLi4vc3JjL2dldC1kZXNpZ24tY29udGV4dC50cyIsICIuLi9zcmMvX3V0aWxzL2NsaS1hcmdzLnRzIiwgIi4uL3NyYy9fdXRpbHMvY29uZmlnLnRzIiwgIi4uL3NyYy9fdXRpbHMvZW52ZWxvcGUudHMiLCAiLi4vc3JjL191dGlscy9lcnJvcnMudHMiLCAiLi4vc3JjL191dGlscy9odHRwLWNsaWVudC50cyIsICIuLi9zcmMvX3V0aWxzL3VybC1wYXJzZS50cyJdLAogICJzb3VyY2VzQ29udGVudCI6IFsiIyEvdXNyL2Jpbi9lbnYgbm9kZVxuXG5pbXBvcnQgeyBjcmVhdGVIYXNoIH0gZnJvbSAnbm9kZTpjcnlwdG8nXG5pbXBvcnQgeyBwYXJzZUFyZ3MsIHR5cGUgQ2xpQXJncyB9IGZyb20gJy4vX3V0aWxzL2NsaS1hcmdzLnRzJ1xuaW1wb3J0IHsgY3JlYXRlRW52ZWxvcGUsIHR5cGUgVG9vbEVudmVsb3BlIH0gZnJvbSAnLi9fdXRpbHMvZW52ZWxvcGUudHMnXG5pbXBvcnQgeyBjcmVhdGVFcnJvciwgZ2V0RXhpdENvZGUsIHR5cGUgVG9vbEVycm9yIH0gZnJvbSAnLi9fdXRpbHMvZXJyb3JzLnRzJ1xuaW1wb3J0IHsgZmlnbWFSZXF1ZXN0IH0gZnJvbSAnLi9fdXRpbHMvaHR0cC1jbGllbnQudHMnXG5pbXBvcnQgeyBwYXJzZUZpZ21hVXJsLCBlbnN1cmVOb2RlSWQgfSBmcm9tICcuL191dGlscy91cmwtcGFyc2UudHMnXG5cbmNvbnN0IFRPT0xfTkFNRSA9ICdnZXQtZGVzaWduLWNvbnRleHQnXG5jb25zdCBWQUxJRF9JTUFHRV9GT1JNQVRTID0gWydwbmcnLCAnanBnJywgJ2pwZWcnLCAnc3ZnJ11cblxudHlwZSBFbXB0eURhdGEgPSBSZWNvcmQ8c3RyaW5nLCBuZXZlcj5cblxuaW50ZXJmYWNlIFRvb2xJbnB1dCBleHRlbmRzIFJlY29yZDxzdHJpbmcsIHVua25vd24+IHtcbiAgZmlsZUtleTogc3RyaW5nIHwgbnVsbFxuICBub2RlSWQ6IHN0cmluZyB8IG51bGxcbiAgaW5jbHVkZUltYWdlczogYm9vbGVhblxuICBpbWFnZUZvcm1hdDogc3RyaW5nXG4gIHNjYWxlOiBudW1iZXJcbn1cblxuaW50ZXJmYWNlIERlc2lnbkNvbnRleHREYXRhIHtcbiAgZmlsZToge1xuICAgIGtleTogc3RyaW5nXG4gICAgbmFtZTogc3RyaW5nIHwgbnVsbFxuICAgIGxhc3RNb2RpZmllZDogc3RyaW5nIHwgbnVsbFxuICB9XG4gIHNlbGVjdGlvblN1bW1hcnk6IFNlbGVjdGlvblN1bW1hcnlcbiAgbGF5b3V0VHJlZTogTGF5b3V0Tm9kZVxuICBzdHlsZVRva2VuczogU3R5bGVUb2tlbnNcbiAgbGF5b3V0SGFzaDogc3RyaW5nIHwgbnVsbFxuICBpbWFnZXM6IHsgcHJldmlldzogUHJldmlld0ltYWdlIH0gfCBudWxsXG59XG5cbmludGVyZmFjZSBGaWdtYUNvbXBvbmVudE1ldGEge1xuICBrZXk/OiBzdHJpbmdcbiAgbmFtZT86IHN0cmluZ1xuICBkZXNjcmlwdGlvbj86IHN0cmluZ1xufVxuXG5pbnRlcmZhY2UgRmlnbWFDb21wb25lbnRTZXRNZXRhIHtcbiAgbmFtZT86IHN0cmluZ1xuICBjb21wb25lbnRTZXRQcm9wZXJ0aWVzPzogUmVjb3JkPHN0cmluZywgdW5rbm93bj5cbn1cblxuaW50ZXJmYWNlIEZpZ21hTm9kZSB7XG4gIGlkOiBzdHJpbmdcbiAgbmFtZT86IHN0cmluZ1xuICB0eXBlPzogc3RyaW5nXG4gIGNvbXBvbmVudElkPzogc3RyaW5nXG4gIGNvbXBvbmVudFNldElkPzogc3RyaW5nXG4gIHZhcmlhbnRQcm9wZXJ0aWVzPzogUmVjb3JkPHN0cmluZywgdW5rbm93bj5cbiAgYWJzb2x1dGVCb3VuZGluZ0JveD86IHsgeD86IG51bWJlcjsgeT86IG51bWJlcjsgd2lkdGg/OiBudW1iZXI7IGhlaWdodD86IG51bWJlciB9XG4gIGNoaWxkcmVuPzogRmlnbWFOb2RlW11cbiAgdmlzaWJsZT86IGJvb2xlYW5cbiAgcm90YXRpb24/OiBudW1iZXJcbiAgY2xpcHNDb250ZW50PzogYm9vbGVhblxuICBjaGFyYWN0ZXJzPzogc3RyaW5nXG4gIGZpbGxzPzogdW5rbm93bltdXG4gIHN0cm9rZXM/OiB1bmtub3duW11cbiAgZWZmZWN0cz86IHVua25vd25bXVxuICBzdHlsZT86IFJlY29yZDxzdHJpbmcsIHVua25vd24+XG4gIHN0eWxlcz86IFJlY29yZDxzdHJpbmcsIHVua25vd24+XG4gIGJhY2tncm91bmRDb2xvcj86IFJlY29yZDxzdHJpbmcsIHVua25vd24+XG4gIGNvcm5lclJhZGl1cz86IG51bWJlclxuICByZWN0YW5nbGVDb3JuZXJSYWRpaT86IG51bWJlcltdXG59XG5cbmludGVyZmFjZSBOb2RlV3JhcHBlciB7XG4gIGRvY3VtZW50PzogRmlnbWFOb2RlXG4gIGNvbXBvbmVudHM/OiBSZWNvcmQ8c3RyaW5nLCBGaWdtYUNvbXBvbmVudE1ldGE+XG4gIGNvbXBvbmVudFNldHM/OiBSZWNvcmQ8c3RyaW5nLCBGaWdtYUNvbXBvbmVudFNldE1ldGE+XG59XG5cbmludGVyZmFjZSBOb2Rlc1Jlc3BvbnNlIHtcbiAgbmFtZT86IHN0cmluZ1xuICBsYXN0TW9kaWZpZWQ/OiBzdHJpbmdcbiAgbm9kZXM/OiBSZWNvcmQ8c3RyaW5nLCBOb2RlV3JhcHBlcj5cbn1cblxuaW50ZXJmYWNlIEltYWdlUmVzcG9uc2Uge1xuICBpbWFnZXM/OiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+XG59XG5cbmludGVyZmFjZSBTZWxlY3Rpb25TdW1tYXJ5IHtcbiAgaWQ6IHN0cmluZ1xuICBuYW1lPzogc3RyaW5nXG4gIHR5cGU/OiBzdHJpbmdcbiAgY29tcG9uZW50SWQ/OiBzdHJpbmcgfCBudWxsXG4gIGNvbXBvbmVudEtleT86IHN0cmluZyB8IG51bGxcbiAgY29tcG9uZW50TmFtZT86IHN0cmluZyB8IG51bGxcbiAgY29tcG9uZW50U2V0SWQ/OiBzdHJpbmcgfCBudWxsXG4gIGNvbXBvbmVudFNldE5hbWU/OiBzdHJpbmcgfCBudWxsXG4gIHZhcmlhbnRQcm9wZXJ0aWVzPzogUmVjb3JkPHN0cmluZywgdW5rbm93bj4gfCBudWxsXG59XG5cbmludGVyZmFjZSBMYXlvdXROb2RlIHtcbiAgaWQ6IHN0cmluZ1xuICBuYW1lPzogc3RyaW5nXG4gIHR5cGU/OiBzdHJpbmdcbiAgdmlzaWJsZTogYm9vbGVhblxuICBsYXlvdXQ6IHsgeDogbnVtYmVyOyB5OiBudW1iZXI7IHdpZHRoOiBudW1iZXI7IGhlaWdodDogbnVtYmVyIH0gfCBudWxsXG4gIHJvdGF0aW9uOiBudW1iZXJcbiAgY2xpcHNDb250ZW50OiBib29sZWFuXG4gIGNoYXJhY3RlcnM6IHN0cmluZyB8IG51bGxcbiAgZmlsbHM6IHVua25vd25bXVxuICBzdHJva2VzOiB1bmtub3duW11cbiAgZWZmZWN0czogdW5rbm93bltdXG4gIHRhaWx3aW5kU3VnZ2VzdGlvbjogbnVsbFxuICBjaGlsZHJlbjogTGF5b3V0Tm9kZVtdXG59XG5cbmludGVyZmFjZSBTdHlsZVRva2VucyB7XG4gIGZpbGxzOiB1bmtub3duW11cbiAgc3Ryb2tlczogdW5rbm93bltdXG4gIGVmZmVjdHM6IHVua25vd25bXVxuICBiYWNrZ3JvdW5kQ29sb3I6IFJlY29yZDxzdHJpbmcsIHVua25vd24+IHwgbnVsbFxuICB0ZXh0U3R5bGU6IFJlY29yZDxzdHJpbmcsIHVua25vd24+IHwgbnVsbFxuICBzdHlsZXM6IFJlY29yZDxzdHJpbmcsIHVua25vd24+XG4gIGNvcm5lclJhZGl1czogbnVtYmVyIHwgbnVtYmVyW10gfCBudWxsXG59XG5cbmludGVyZmFjZSBQcmV2aWV3SW1hZ2Uge1xuICB1cmw6IHN0cmluZ1xuICBmb3JtYXQ6IHN0cmluZ1xuICBzaXplOiBzdHJpbmdcbn1cblxuZnVuY3Rpb24gbG9nKG1lc3NhZ2U6IHN0cmluZywgdmVyYm9zZTogYm9vbGVhbik6IHZvaWQge1xuICBpZiAodmVyYm9zZSkge1xuICAgIHByb2Nlc3Muc3RkZXJyLndyaXRlKGBbJHtUT09MX05BTUV9XSAke21lc3NhZ2V9XFxuYClcbiAgfVxufVxuXG5mdW5jdGlvbiB0b09wdGlvbmFsU3RyaW5nKHZhbHVlOiBDbGlBcmdzW3N0cmluZ10pOiBzdHJpbmcgfCBudWxsIHtcbiAgcmV0dXJuIHR5cGVvZiB2YWx1ZSA9PT0gJ3N0cmluZycgJiYgdmFsdWUubGVuZ3RoID4gMCA/IHZhbHVlIDogbnVsbFxufVxuXG5mdW5jdGlvbiBleGl0V2l0aEVudmVsb3BlKFxuICBlbnZlbG9wZTogVG9vbEVudmVsb3BlPFRvb2xJbnB1dCwgRGVzaWduQ29udGV4dERhdGEgfCBFbXB0eURhdGE+LFxuICBlcnJvcnM6IFRvb2xFcnJvcltdID0gW11cbik6IG5ldmVyIHtcbiAgcHJvY2Vzcy5zdGRvdXQud3JpdGUoYCR7SlNPTi5zdHJpbmdpZnkoZW52ZWxvcGUsIG51bGwsIDIpfVxcbmApXG4gIHByb2Nlc3MuZXhpdChnZXRFeGl0Q29kZShlcnJvcnMpKVxufVxuXG5mdW5jdGlvbiBtYXBMYXlvdXROb2RlKG5vZGU6IEZpZ21hTm9kZSk6IExheW91dE5vZGUge1xuICBjb25zdCBjaGlsZHJlbiA9IEFycmF5LmlzQXJyYXkobm9kZS5jaGlsZHJlbikgPyBub2RlLmNoaWxkcmVuLm1hcChtYXBMYXlvdXROb2RlKSA6IFtdXG4gIGNvbnN0IGJib3ggPSBub2RlLmFic29sdXRlQm91bmRpbmdCb3hcbiAgY29uc3QgbGF5b3V0ID0gYmJveFxuICAgID8geyB4OiBiYm94LnggPz8gMCwgeTogYmJveC55ID8/IDAsIHdpZHRoOiBiYm94LndpZHRoID8/IDAsIGhlaWdodDogYmJveC5oZWlnaHQgPz8gMCB9XG4gICAgOiBudWxsXG5cbiAgcmV0dXJuIHtcbiAgICBpZDogbm9kZS5pZCxcbiAgICBuYW1lOiBub2RlLm5hbWUsXG4gICAgdHlwZTogbm9kZS50eXBlLFxuICAgIHZpc2libGU6IG5vZGUudmlzaWJsZSA/PyB0cnVlLFxuICAgIGxheW91dCxcbiAgICByb3RhdGlvbjogbm9kZS5yb3RhdGlvbiA/PyAwLFxuICAgIGNsaXBzQ29udGVudDogbm9kZS5jbGlwc0NvbnRlbnQgPz8gZmFsc2UsXG4gICAgY2hhcmFjdGVyczogbm9kZS5jaGFyYWN0ZXJzID8/IG51bGwsXG4gICAgZmlsbHM6IG5vZGUuZmlsbHMgPz8gW10sXG4gICAgc3Ryb2tlczogbm9kZS5zdHJva2VzID8/IFtdLFxuICAgIGVmZmVjdHM6IG5vZGUuZWZmZWN0cyA/PyBbXSxcbiAgICB0YWlsd2luZFN1Z2dlc3Rpb246IG51bGwsXG4gICAgY2hpbGRyZW4sXG4gIH1cbn1cblxuZnVuY3Rpb24gYnVpbGRTdHlsZVRva2Vucyhub2RlOiBGaWdtYU5vZGUpOiBTdHlsZVRva2VucyB7XG4gIGNvbnN0IGNvcm5lclJhZGl1czogbnVtYmVyIHwgbnVtYmVyW10gfCBudWxsID1cbiAgICAoQXJyYXkuaXNBcnJheShub2RlLnJlY3RhbmdsZUNvcm5lclJhZGlpKSAmJiBub2RlLnJlY3RhbmdsZUNvcm5lclJhZGlpLmxlbmd0aCA+IDApXG4gICAgICA/IG5vZGUucmVjdGFuZ2xlQ29ybmVyUmFkaWlcbiAgICAgIDogKG5vZGUuY29ybmVyUmFkaXVzID8/IG51bGwpXG5cbiAgcmV0dXJuIHtcbiAgICBmaWxsczogbm9kZS5maWxscyA/PyBbXSxcbiAgICBzdHJva2VzOiBub2RlLnN0cm9rZXMgPz8gW10sXG4gICAgZWZmZWN0czogbm9kZS5lZmZlY3RzID8/IFtdLFxuICAgIGJhY2tncm91bmRDb2xvcjogbm9kZS5iYWNrZ3JvdW5kQ29sb3IgPz8gbnVsbCxcbiAgICB0ZXh0U3R5bGU6IG5vZGUuc3R5bGUgPz8gbnVsbCxcbiAgICBzdHlsZXM6IG5vZGUuc3R5bGVzID8/IHt9LFxuICAgIGNvcm5lclJhZGl1cyxcbiAgfVxufVxuXG5mdW5jdGlvbiBidWlsZFNlbGVjdGlvblN1bW1hcnkoXG4gIG5vZGU6IEZpZ21hTm9kZSxcbiAgY29tcG9uZW50czogUmVjb3JkPHN0cmluZywgRmlnbWFDb21wb25lbnRNZXRhPixcbiAgY29tcG9uZW50U2V0czogUmVjb3JkPHN0cmluZywgRmlnbWFDb21wb25lbnRTZXRNZXRhPlxuKTogU2VsZWN0aW9uU3VtbWFyeSB7XG4gIGNvbnN0IGNvbXBvbmVudElkID0gbm9kZS5jb21wb25lbnRJZCA/PyBudWxsXG4gIGNvbnN0IGNvbXBvbmVudFNldElkID0gbm9kZS5jb21wb25lbnRTZXRJZCA/PyBudWxsXG4gIGNvbnN0IGNvbXBvbmVudE1ldGEgPSBjb21wb25lbnRJZCA/IGNvbXBvbmVudHNbY29tcG9uZW50SWRdID8/IG51bGwgOiBudWxsXG4gIGNvbnN0IGNvbXBvbmVudFNldE1ldGEgPSBjb21wb25lbnRTZXRJZCA/IGNvbXBvbmVudFNldHNbY29tcG9uZW50U2V0SWRdID8/IG51bGwgOiBudWxsXG5cbiAgcmV0dXJuIHtcbiAgICBpZDogbm9kZS5pZCxcbiAgICBuYW1lOiBub2RlLm5hbWUsXG4gICAgdHlwZTogbm9kZS50eXBlLFxuICAgIGNvbXBvbmVudElkLFxuICAgIGNvbXBvbmVudEtleTogY29tcG9uZW50TWV0YT8ua2V5ID8/IG51bGwsXG4gICAgY29tcG9uZW50TmFtZTogY29tcG9uZW50TWV0YT8ubmFtZSA/PyBudWxsLFxuICAgIGNvbXBvbmVudFNldElkLFxuICAgIGNvbXBvbmVudFNldE5hbWU6IGNvbXBvbmVudFNldE1ldGE/Lm5hbWUgPz8gbnVsbCxcbiAgICB2YXJpYW50UHJvcGVydGllczogbm9kZS52YXJpYW50UHJvcGVydGllcyA/PyBudWxsLFxuICB9XG59XG5cbmZ1bmN0aW9uIGNvbXB1dGVMYXlvdXRIYXNoKGxheW91dFRyZWU6IExheW91dE5vZGUpOiBzdHJpbmcge1xuICBjb25zdCBqc29uID0gSlNPTi5zdHJpbmdpZnkobGF5b3V0VHJlZSlcbiAgcmV0dXJuIGNyZWF0ZUhhc2goJ3NoYTEnKS51cGRhdGUoanNvbikuZGlnZXN0KCdoZXgnKVxufVxuXG5hc3luYyBmdW5jdGlvbiBmZXRjaFByZXZpZXdJbWFnZShcbiAgZmlsZUtleTogc3RyaW5nLFxuICBub2RlSWQ6IHN0cmluZyxcbiAgdG9rZW46IHN0cmluZyxcbiAgaW1hZ2VGb3JtYXQ6IHN0cmluZyxcbiAgc2NhbGU6IG51bWJlcixcbiAgd2FybmluZ3M6IHN0cmluZ1tdLFxuICB2ZXJib3NlOiBib29sZWFuXG4pOiBQcm9taXNlPFByZXZpZXdJbWFnZSB8IG51bGw+IHtcbiAgY29uc3QgZm9ybWF0ID0gVkFMSURfSU1BR0VfRk9STUFUUy5pbmNsdWRlcyhpbWFnZUZvcm1hdCkgPyBpbWFnZUZvcm1hdCA6ICdwbmcnXG4gIGNvbnN0IHNjYWxlQ2xhbXBlZCA9IE51bWJlci5pc0Zpbml0ZShzY2FsZSkgJiYgc2NhbGUgPiAwID8gc2NhbGUgOiAxXG5cbiAgbG9nKGBSZXF1ZXN0aW5nIHByZXZpZXcgaW1hZ2UgZm9ybWF0PSR7Zm9ybWF0fSwgc2NhbGU9JHtzY2FsZUNsYW1wZWR9YCwgdmVyYm9zZSlcbiAgY29uc3QgaW1hZ2VSZXNwb25zZSA9IGF3YWl0IGZpZ21hUmVxdWVzdDxJbWFnZVJlc3BvbnNlPih7XG4gICAgcGF0aDogYC92MS9pbWFnZXMvJHtmaWxlS2V5fWAsXG4gICAgdG9rZW4sXG4gICAgc2VhcmNoUGFyYW1zOiB7IGlkczogbm9kZUlkLCBmb3JtYXQsIHNjYWxlOiBzY2FsZUNsYW1wZWQgfSxcbiAgfSlcblxuICBpZiAoIWltYWdlUmVzcG9uc2Uub2spIHtcbiAgICB3YXJuaW5ncy5wdXNoKGltYWdlUmVzcG9uc2UuZXJyb3I/Lm1lc3NhZ2UgPz8gJ0ZhaWxlZCB0byByZXF1ZXN0IHByZXZpZXcgaW1hZ2UuJylcbiAgICByZXR1cm4gbnVsbFxuICB9XG5cbiAgY29uc3QgdXJsID0gaW1hZ2VSZXNwb25zZS5kYXRhPy5pbWFnZXM/Lltub2RlSWRdXG4gIGlmICghdXJsKSByZXR1cm4gbnVsbFxuICByZXR1cm4geyB1cmwsIGZvcm1hdCwgc2l6ZTogYCR7c2NhbGVDbGFtcGVkfXhgIH1cbn1cblxuYXN5bmMgZnVuY3Rpb24gbWFpbigpOiBQcm9taXNlPHZvaWQ+IHtcbiAgY29uc3QgYXJncyA9IHBhcnNlQXJncygpXG4gIGNvbnN0IHZlcmJvc2UgPSBCb29sZWFuKGFyZ3MudmVyYm9zZSA/PyBhcmdzLnYpXG4gIGNvbnN0IHNjaGVtYVZlcnNpb24gPSB0b09wdGlvbmFsU3RyaW5nKGFyZ3NbJ3NjaGVtYS12ZXJzaW9uJ10pID8/IHVuZGVmaW5lZFxuXG4gIGNvbnN0IHdhcm5pbmdzOiBzdHJpbmdbXSA9IFtdXG4gIGNvbnN0IGVycm9yczogVG9vbEVycm9yW10gPSBbXVxuXG4gIGNvbnN0IHRva2VuID0gcHJvY2Vzcy5lbnYuRklHTUFfQUNDRVNTX1RPS0VOXG4gIGlmICghdG9rZW4gfHwgIXRva2VuLnRyaW0oKSkge1xuICAgIGVycm9ycy5wdXNoKGNyZWF0ZUVycm9yKCdGSUdNQV9BVVRIJywgJ0ZJR01BX0FDQ0VTU19UT0tFTiBpcyByZXF1aXJlZCBidXQgd2FzIG5vdCBwcm92aWRlZC4nKSlcbiAgICBjb25zdCBlbnZlbG9wZSA9IGNyZWF0ZUVudmVsb3BlPFRvb2xJbnB1dCwgRW1wdHlEYXRhPih7XG4gICAgICB0b29sOiBUT09MX05BTUUsXG4gICAgICBpbnB1dDogeyBmaWxlS2V5OiBudWxsLCBub2RlSWQ6IG51bGwsIGluY2x1ZGVJbWFnZXM6IGZhbHNlLCBpbWFnZUZvcm1hdDogJ3BuZycsIHNjYWxlOiAxIH0sXG4gICAgICB3YXJuaW5ncyxcbiAgICAgIGVycm9ycyxcbiAgICAgIHNjaGVtYVZlcnNpb24sXG4gICAgICBkYXRhOiB7fSBhcyBFbXB0eURhdGEsXG4gICAgfSlcbiAgICBleGl0V2l0aEVudmVsb3BlKGVudmVsb3BlLCBlcnJvcnMpXG4gIH1cblxuICBjb25zdCB1cmxJbnB1dCA9IHRvT3B0aW9uYWxTdHJpbmcoYXJncy51cmwpID8/IHRvT3B0aW9uYWxTdHJpbmcoYXJncy51KVxuICBsZXQgZmlsZUtleSA9IHRvT3B0aW9uYWxTdHJpbmcoYXJnc1snZmlsZS1rZXknXSkgPz8gdW5kZWZpbmVkXG4gIGxldCBub2RlSWQgPSBlbnN1cmVOb2RlSWQodG9PcHRpb25hbFN0cmluZyhhcmdzWydub2RlLWlkJ10pKVxuXG4gIGlmICh1cmxJbnB1dCkge1xuICAgIGNvbnN0IHBhcnNlZCA9IHBhcnNlRmlnbWFVcmwodXJsSW5wdXQpXG4gICAgZmlsZUtleSA9IGZpbGVLZXkgfHwgcGFyc2VkLmZpbGVLZXkgfHwgdW5kZWZpbmVkXG4gICAgbm9kZUlkID0gbm9kZUlkIHx8IHBhcnNlZC5ub2RlSWRcbiAgfVxuXG4gIGNvbnN0IGluY2x1ZGVJbWFnZXMgPSBhcmdzWydpbmNsdWRlLWltYWdlcyddICE9PSAnZmFsc2UnXG4gIGNvbnN0IGltYWdlRm9ybWF0SW5wdXQgPSBTdHJpbmcoYXJnc1snaW1hZ2UtZm9ybWF0J10gPz8gJ3BuZycpLnRvTG93ZXJDYXNlKClcbiAgY29uc3QgaW1hZ2VGb3JtYXQgPSBWQUxJRF9JTUFHRV9GT1JNQVRTLmluY2x1ZGVzKGltYWdlRm9ybWF0SW5wdXQpID8gaW1hZ2VGb3JtYXRJbnB1dCA6ICdwbmcnXG5cbiAgY29uc3Qgc2NhbGVJbnB1dCA9IE51bWJlcihhcmdzLnNjYWxlID8/IDEpXG4gIGNvbnN0IGltYWdlU2NhbGUgPSBOdW1iZXIuaXNGaW5pdGUoc2NhbGVJbnB1dCkgJiYgc2NhbGVJbnB1dCA+IDAgPyBzY2FsZUlucHV0IDogMVxuXG4gIGNvbnN0IGlucHV0OiBUb29sSW5wdXQgPSB7XG4gICAgZmlsZUtleTogZmlsZUtleSA/PyBudWxsLFxuICAgIG5vZGVJZDogbm9kZUlkID8/IG51bGwsXG4gICAgaW5jbHVkZUltYWdlcyxcbiAgICBpbWFnZUZvcm1hdCxcbiAgICBzY2FsZTogaW1hZ2VTY2FsZSxcbiAgfVxuXG4gIGlmICghZmlsZUtleSkge1xuICAgIGVycm9ycy5wdXNoKGNyZWF0ZUVycm9yKCdJTlBVVF9JTlZBTElEJywgJ0EgdmFsaWQgRmlnbWEgZmlsZSBrZXkgaXMgcmVxdWlyZWQgKC0tZmlsZS1rZXkgb3IgLS11cmwpLicpKVxuICB9XG4gIGlmICghbm9kZUlkKSB7XG4gICAgZXJyb3JzLnB1c2goY3JlYXRlRXJyb3IoJ0lOUFVUX0lOVkFMSUQnLCAnQSB2YWxpZCBGaWdtYSBub2RlIGlkIGlzIHJlcXVpcmVkICgtLW5vZGUtaWQgb3IgLS11cmwgd2l0aCBub2RlLWlkKS4nKSlcbiAgfVxuICBpZiAoZXJyb3JzLmxlbmd0aCkge1xuICAgIGNvbnN0IGVudmVsb3BlID0gY3JlYXRlRW52ZWxvcGU8VG9vbElucHV0LCBFbXB0eURhdGE+KHsgdG9vbDogVE9PTF9OQU1FLCBpbnB1dCwgd2FybmluZ3MsIGVycm9ycywgZGF0YToge30gYXMgRW1wdHlEYXRhLCBzY2hlbWFWZXJzaW9uIH0pXG4gICAgZXhpdFdpdGhFbnZlbG9wZShlbnZlbG9wZSwgZXJyb3JzKVxuICB9XG5cbiAgY29uc3QgcmVzb2x2ZWRGaWxlS2V5ID0gZmlsZUtleSBhcyBzdHJpbmdcbiAgY29uc3QgcmVzb2x2ZWROb2RlSWQgPSBub2RlSWQgYXMgc3RyaW5nXG5cbiAgbG9nKGBGZXRjaGluZyBub2RlICR7cmVzb2x2ZWROb2RlSWR9IGZyb20gZmlsZSAke3Jlc29sdmVkRmlsZUtleX1gLCB2ZXJib3NlKVxuICBjb25zdCBub2RlUmVzcG9uc2UgPSBhd2FpdCBmaWdtYVJlcXVlc3Q8Tm9kZXNSZXNwb25zZT4oe1xuICAgIHBhdGg6IGAvdjEvZmlsZXMvJHtyZXNvbHZlZEZpbGVLZXl9L25vZGVzYCxcbiAgICB0b2tlbixcbiAgICBzZWFyY2hQYXJhbXM6IHsgaWRzOiByZXNvbHZlZE5vZGVJZCB9LFxuICB9KVxuXG4gIGlmICghbm9kZVJlc3BvbnNlLm9rKSB7XG4gICAgZXJyb3JzLnB1c2gobm9kZVJlc3BvbnNlLmVycm9yID8/IGNyZWF0ZUVycm9yKCdJTlRFUk5BTCcsICdGYWlsZWQgdG8gZmV0Y2ggbm9kZSBkYXRhLicpKVxuICAgIGNvbnN0IGVudmVsb3BlID0gY3JlYXRlRW52ZWxvcGU8VG9vbElucHV0LCBFbXB0eURhdGE+KHtcbiAgICAgIHRvb2w6IFRPT0xfTkFNRSxcbiAgICAgIGlucHV0LFxuICAgICAgd2FybmluZ3MsXG4gICAgICBlcnJvcnMsXG4gICAgICByYXRlTGltaXQ6IG5vZGVSZXNwb25zZS5yYXRlTGltaXQgPz8gdW5kZWZpbmVkLFxuICAgICAgZGF0YToge30gYXMgRW1wdHlEYXRhLFxuICAgICAgc2NoZW1hVmVyc2lvbixcbiAgICB9KVxuICAgIGV4aXRXaXRoRW52ZWxvcGUoZW52ZWxvcGUsIGVycm9ycylcbiAgfVxuXG4gIGNvbnN0IG5vZGVQYXlsb2FkID0gbm9kZVJlc3BvbnNlLmRhdGEgPz8ge31cbiAgY29uc3Qgbm9kZXNNYXAgPSBub2RlUGF5bG9hZC5ub2RlcyA/PyB7fVxuICBjb25zdCBub2RlV3JhcHBlciA9IG5vZGVzTWFwW3Jlc29sdmVkTm9kZUlkXVxuICBpZiAoIW5vZGVXcmFwcGVyIHx8ICFub2RlV3JhcHBlci5kb2N1bWVudCkge1xuICAgIGVycm9ycy5wdXNoKGNyZWF0ZUVycm9yKCdGSUdNQV9OT1RfRk9VTkQnLCBgTm9kZSAke3Jlc29sdmVkTm9kZUlkfSB3YXMgbm90IGZvdW5kIGluIGZpbGUgJHtyZXNvbHZlZEZpbGVLZXl9LmApKVxuICAgIGNvbnN0IGVudmVsb3BlID0gY3JlYXRlRW52ZWxvcGU8VG9vbElucHV0LCBFbXB0eURhdGE+KHsgdG9vbDogVE9PTF9OQU1FLCBpbnB1dCwgd2FybmluZ3MsIGVycm9ycywgcmF0ZUxpbWl0OiBub2RlUmVzcG9uc2UucmF0ZUxpbWl0ID8/IHVuZGVmaW5lZCwgZGF0YToge30gYXMgRW1wdHlEYXRhLCBzY2hlbWFWZXJzaW9uIH0pXG4gICAgZXhpdFdpdGhFbnZlbG9wZShlbnZlbG9wZSwgZXJyb3JzKVxuICB9XG5cbiAgY29uc3Qgbm9kZSA9IG5vZGVXcmFwcGVyLmRvY3VtZW50XG4gIGNvbnN0IGNvbXBvbmVudHMgPSBub2RlV3JhcHBlci5jb21wb25lbnRzID8/IHt9XG4gIGNvbnN0IGNvbXBvbmVudFNldHMgPSBub2RlV3JhcHBlci5jb21wb25lbnRTZXRzID8/IHt9XG5cbiAgY29uc3Qgc2VsZWN0aW9uU3VtbWFyeSA9IGJ1aWxkU2VsZWN0aW9uU3VtbWFyeShub2RlLCBjb21wb25lbnRzLCBjb21wb25lbnRTZXRzKVxuICBjb25zdCBsYXlvdXRUcmVlID0gbWFwTGF5b3V0Tm9kZShub2RlKVxuICBjb25zdCBzdHlsZVRva2VucyA9IGJ1aWxkU3R5bGVUb2tlbnMobm9kZSlcbiAgY29uc3QgbGF5b3V0SGFzaCA9IGNvbXB1dGVMYXlvdXRIYXNoKGxheW91dFRyZWUpXG5cbiAgbGV0IHByZXZpZXc6IFByZXZpZXdJbWFnZSB8IG51bGwgPSBudWxsXG4gIGlmIChpbmNsdWRlSW1hZ2VzKSB7XG4gICAgcHJldmlldyA9IGF3YWl0IGZldGNoUHJldmlld0ltYWdlKFxuICAgICAgcmVzb2x2ZWRGaWxlS2V5LFxuICAgICAgcmVzb2x2ZWROb2RlSWQsXG4gICAgICB0b2tlbixcbiAgICAgIGltYWdlRm9ybWF0LFxuICAgICAgaW1hZ2VTY2FsZSxcbiAgICAgIHdhcm5pbmdzLFxuICAgICAgdmVyYm9zZVxuICAgIClcbiAgfVxuXG4gIGNvbnN0IGRhdGEgPSB7XG4gICAgZmlsZToge1xuICAgICAga2V5OiByZXNvbHZlZEZpbGVLZXksXG4gICAgICBuYW1lOiBub2RlUGF5bG9hZD8ubmFtZSA/PyBudWxsLFxuICAgICAgbGFzdE1vZGlmaWVkOiBub2RlUGF5bG9hZD8ubGFzdE1vZGlmaWVkID8/IG51bGwsXG4gICAgfSxcbiAgICBzZWxlY3Rpb25TdW1tYXJ5LFxuICAgIGxheW91dFRyZWUsXG4gICAgc3R5bGVUb2tlbnMsXG4gICAgbGF5b3V0SGFzaCxcbiAgICBpbWFnZXM6IHByZXZpZXcgPyB7IHByZXZpZXcgfSA6IG51bGwsXG4gIH1cblxuICBjb25zdCBlbnZlbG9wZSA9IGNyZWF0ZUVudmVsb3BlPFRvb2xJbnB1dCwgRGVzaWduQ29udGV4dERhdGE+KHtcbiAgICB0b29sOiBUT09MX05BTUUsXG4gICAgaW5wdXQsXG4gICAgZGF0YSxcbiAgICB3YXJuaW5ncyxcbiAgICBlcnJvcnMsXG4gICAgcmF0ZUxpbWl0OiBub2RlUmVzcG9uc2UucmF0ZUxpbWl0ID8/IHVuZGVmaW5lZCxcbiAgICBzY2hlbWFWZXJzaW9uLFxuICB9KVxuXG4gIHByb2Nlc3Muc3Rkb3V0LndyaXRlKGAke0pTT04uc3RyaW5naWZ5KGVudmVsb3BlLCBudWxsLCAyKX1cXG5gKVxuICBwcm9jZXNzLmV4aXQoZ2V0RXhpdENvZGUoZXJyb3JzKSlcbn1cblxubWFpbigpLmNhdGNoKChlcnJvcjogdW5rbm93bikgPT4ge1xuICBjb25zdCBtZXNzYWdlID0gZXJyb3IgaW5zdGFuY2VvZiBFcnJvciA/IGVycm9yLm1lc3NhZ2UgOiAnVW5rbm93biBlcnJvcidcbiAgY29uc3QgZW52ZWxvcGUgPSBjcmVhdGVFbnZlbG9wZTxUb29sSW5wdXQsIEVtcHR5RGF0YT4oe1xuICAgIHRvb2w6IFRPT0xfTkFNRSxcbiAgICBpbnB1dDogeyBmaWxlS2V5OiBudWxsLCBub2RlSWQ6IG51bGwsIGluY2x1ZGVJbWFnZXM6IGZhbHNlLCBpbWFnZUZvcm1hdDogJ3BuZycsIHNjYWxlOiAxIH0sXG4gICAgZXJyb3JzOiBbY3JlYXRlRXJyb3IoJ0lOVEVSTkFMJywgbWVzc2FnZSwgeyBzdGFjazogZXJyb3IgaW5zdGFuY2VvZiBFcnJvciA/IGVycm9yLnN0YWNrIDogdW5kZWZpbmVkIH0pXSxcbiAgICBkYXRhOiB7fSBhcyBFbXB0eURhdGEsXG4gIH0pXG4gIHByb2Nlc3Muc3Rkb3V0LndyaXRlKGAke0pTT04uc3RyaW5naWZ5KGVudmVsb3BlLCBudWxsLCAyKX1cXG5gKVxuICBwcm9jZXNzLmV4aXQoMylcbn0pXG5cbiIsICJleHBvcnQgdHlwZSBDbGlBcmdWYWx1ZSA9IHN0cmluZyB8IGJvb2xlYW47XG5cbmV4cG9ydCBpbnRlcmZhY2UgQ2xpQXJncyB7XG4gIF86IHN0cmluZ1tdO1xuICBba2V5OiBzdHJpbmddOiBDbGlBcmdWYWx1ZSB8IHN0cmluZ1tdO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gcGFyc2VBcmdzKGFyZ3Y6IHN0cmluZ1tdID0gcHJvY2Vzcy5hcmd2LnNsaWNlKDIpKTogQ2xpQXJncyB7XG4gIGNvbnN0IGFyZ3M6IENsaUFyZ3MgPSB7IF86IFtdIH07XG5cbiAgZm9yIChsZXQgaSA9IDA7IGkgPCBhcmd2Lmxlbmd0aDsgaSArPSAxKSB7XG4gICAgY29uc3QgYXJnID0gYXJndltpXTtcblxuICAgIGlmICghYXJnLnN0YXJ0c1dpdGgoJy0nKSB8fCBhcmcgPT09ICctJykge1xuICAgICAgYXJncy5fLnB1c2goYXJnKTtcbiAgICAgIGNvbnRpbnVlO1xuICAgIH1cblxuICAgIGlmIChhcmcgPT09ICctLScpIHtcbiAgICAgIGNvbnN0IHJlbWFpbmluZyA9IGFyZ3Yuc2xpY2UoaSArIDEpO1xuICAgICAgYXJncy5fLnB1c2goLi4ucmVtYWluaW5nKTtcbiAgICAgIGJyZWFrO1xuICAgIH1cblxuICAgIGNvbnN0IFtyYXdLZXksIGlubGluZVZhbHVlXSA9IGFyZy5zcGxpdCgnPScsIDIpO1xuICAgIGNvbnN0IG5vcm1hbGlzZWRLZXkgPSByYXdLZXkucmVwbGFjZSgvXi0rLywgJycpO1xuXG4gICAgbGV0IHZhbHVlOiBDbGlBcmdWYWx1ZTtcbiAgICBpZiAoaW5saW5lVmFsdWUgIT09IHVuZGVmaW5lZCkge1xuICAgICAgdmFsdWUgPSBpbmxpbmVWYWx1ZTtcbiAgICB9IGVsc2Uge1xuICAgICAgY29uc3QgbmV4dCA9IGFyZ3ZbaSArIDFdO1xuICAgICAgaWYgKG5leHQgIT09IHVuZGVmaW5lZCAmJiAhbmV4dC5zdGFydHNXaXRoKCctJykpIHtcbiAgICAgICAgdmFsdWUgPSBuZXh0O1xuICAgICAgICBpICs9IDE7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICB2YWx1ZSA9IHRydWU7XG4gICAgICB9XG4gICAgfVxuXG4gICAgYXJnc1tub3JtYWxpc2VkS2V5XSA9IHZhbHVlO1xuICB9XG5cbiAgcmV0dXJuIGFyZ3M7XG59XG5cbiIsICJleHBvcnQgZGVmYXVsdCB7XG4gIHNjaGVtYVZlcnNpb246ICcxLjAuMCcsXG4gIHNvdXJjZTogJ2FnZW50aWMtY29kaW5nLXRlbXBsYXRlcy9maWdtYS10b29scycsXG4gIGh0dHA6IHtcbiAgICBtYXhBdHRlbXB0czogNSxcbiAgICBpbml0aWFsRGVsYXlNczogMjUwLFxuICB9LFxufSBhcyBjb25zdDtcblxuIiwgImltcG9ydCBjb25maWcgZnJvbSAnLi9jb25maWcudHMnO1xuaW1wb3J0IHR5cGUgeyBUb29sRXJyb3IgfSBmcm9tICcuL2Vycm9ycy50cyc7XG5cbmV4cG9ydCBpbnRlcmZhY2UgUmF0ZUxpbWl0TWV0YSB7XG4gIHJlbWFpbmluZzogbnVtYmVyIHwgbnVsbDtcbiAgcmVzZXRBdDogc3RyaW5nIHwgbnVsbDtcbiAgYXR0ZW1wdHM6IG51bWJlcjtcbiAgbGFzdFdhaXRNczogbnVtYmVyO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIFRvb2xFbnZlbG9wZTxcbiAgVElucHV0IGV4dGVuZHMgUmVjb3JkPHN0cmluZywgdW5rbm93bj4gPSBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPixcbiAgVERhdGEgPSB1bmtub3duXG4+IHtcbiAgc2NoZW1hVmVyc2lvbjogc3RyaW5nO1xuICB0b29sOiBzdHJpbmc7XG4gIGlucHV0OiBUSW5wdXQ7XG4gIG1ldGE6IHtcbiAgICBnZW5lcmF0ZWRBdDogc3RyaW5nO1xuICAgIHNvdXJjZTogc3RyaW5nO1xuICAgIHJhdGVMaW1pdDogUmF0ZUxpbWl0TWV0YTtcbiAgfTtcbiAgZGF0YTogVERhdGE7XG4gIHdhcm5pbmdzOiBzdHJpbmdbXTtcbiAgZXJyb3JzOiBUb29sRXJyb3JbXTtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBDcmVhdGVFbnZlbG9wZU9wdGlvbnM8XG4gIFRJbnB1dCBleHRlbmRzIFJlY29yZDxzdHJpbmcsIHVua25vd24+ID0gUmVjb3JkPHN0cmluZywgdW5rbm93bj4sXG4gIFREYXRhID0gdW5rbm93blxuPiB7XG4gIHRvb2w6IHN0cmluZztcbiAgaW5wdXQ/OiBUSW5wdXQ7XG4gIGRhdGE/OiBURGF0YTtcbiAgd2FybmluZ3M/OiBzdHJpbmdbXTtcbiAgZXJyb3JzPzogVG9vbEVycm9yW107XG4gIHJhdGVMaW1pdD86IFBhcnRpYWw8UmF0ZUxpbWl0TWV0YT47XG4gIHNjaGVtYVZlcnNpb24/OiBzdHJpbmc7XG59XG5cbmZ1bmN0aW9uIGJ1aWxkUmF0ZUxpbWl0TWV0YShyYXRlTGltaXQ6IFBhcnRpYWw8UmF0ZUxpbWl0TWV0YT4gPSB7fSk6IFJhdGVMaW1pdE1ldGEge1xuICByZXR1cm4ge1xuICAgIHJlbWFpbmluZzogcmF0ZUxpbWl0LnJlbWFpbmluZyA/PyBudWxsLFxuICAgIHJlc2V0QXQ6IHJhdGVMaW1pdC5yZXNldEF0ID8/IG51bGwsXG4gICAgYXR0ZW1wdHM6IHJhdGVMaW1pdC5hdHRlbXB0cyA/PyAxLFxuICAgIGxhc3RXYWl0TXM6IHJhdGVMaW1pdC5sYXN0V2FpdE1zID8/IDAsXG4gIH07XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBjcmVhdGVFbnZlbG9wZTxcbiAgVElucHV0IGV4dGVuZHMgUmVjb3JkPHN0cmluZywgdW5rbm93bj4gPSBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPixcbiAgVERhdGEgPSB1bmtub3duXG4+KHtcbiAgdG9vbCxcbiAgaW5wdXQgPSB7fSBhcyBUSW5wdXQsXG4gIGRhdGEgPSB7fSBhcyBURGF0YSxcbiAgd2FybmluZ3MgPSBbXSxcbiAgZXJyb3JzID0gW10sXG4gIHJhdGVMaW1pdCxcbiAgc2NoZW1hVmVyc2lvbixcbn06IENyZWF0ZUVudmVsb3BlT3B0aW9uczxUSW5wdXQsIFREYXRhPik6IFRvb2xFbnZlbG9wZTxUSW5wdXQsIFREYXRhPiB7XG4gIHJldHVybiB7XG4gICAgc2NoZW1hVmVyc2lvbjogc2NoZW1hVmVyc2lvbiA/PyBjb25maWcuc2NoZW1hVmVyc2lvbixcbiAgICB0b29sLFxuICAgIGlucHV0LFxuICAgIG1ldGE6IHtcbiAgICAgIGdlbmVyYXRlZEF0OiBuZXcgRGF0ZSgpLnRvSVNPU3RyaW5nKCksXG4gICAgICBzb3VyY2U6IGNvbmZpZy5zb3VyY2UsXG4gICAgICByYXRlTGltaXQ6IGJ1aWxkUmF0ZUxpbWl0TWV0YShyYXRlTGltaXQpLFxuICAgIH0sXG4gICAgZGF0YSxcbiAgICB3YXJuaW5ncyxcbiAgICBlcnJvcnMsXG4gIH07XG59XG5cbiIsICJleHBvcnQgY29uc3QgRVJST1JfRVhJVF9DT0RFUyA9IHtcbiAgSU5QVVRfSU5WQUxJRDogMSxcbiAgQ09ORklHX0lOVkFMSUQ6IDEsXG4gIEZJR01BX0FVVEg6IDEsXG4gIEZJR01BX05PVF9GT1VORDogMixcbiAgRklHTUFfUkFURV9MSU1JVDogMixcbiAgTkVUV09SSzogMixcbiAgSU5URVJOQUw6IDMsXG59IGFzIGNvbnN0O1xuXG5leHBvcnQgdHlwZSBFcnJvckNvZGUgPSBrZXlvZiB0eXBlb2YgRVJST1JfRVhJVF9DT0RFUztcblxuZXhwb3J0IGludGVyZmFjZSBUb29sRXJyb3I8VERldGFpbCA9IHVua25vd24+IHtcbiAgY29kZTogRXJyb3JDb2RlIHwgc3RyaW5nO1xuICBtZXNzYWdlOiBzdHJpbmc7XG4gIGRldGFpbD86IFREZXRhaWwgfCBudWxsO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gY3JlYXRlRXJyb3I8VERldGFpbCA9IHVua25vd24+KFxuICBjb2RlOiBFcnJvckNvZGUgfCBzdHJpbmcsXG4gIG1lc3NhZ2U6IHN0cmluZyxcbiAgZGV0YWlsPzogVERldGFpbCB8IG51bGxcbik6IFRvb2xFcnJvcjxURGV0YWlsPiB7XG4gIHJldHVybiB7XG4gICAgY29kZSxcbiAgICBtZXNzYWdlLFxuICAgIGRldGFpbDogZGV0YWlsID8/IG51bGwsXG4gIH07XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBnZXRFeGl0Q29kZShlcnJvcnM6IFRvb2xFcnJvcltdID0gW10pOiBudW1iZXIge1xuICBpZiAoIWVycm9ycy5sZW5ndGgpIHtcbiAgICByZXR1cm4gMDtcbiAgfVxuXG4gIHJldHVybiBlcnJvcnMucmVkdWNlKChtYXgsIGVycm9yKSA9PiB7XG4gICAgY29uc3QgZXhpdENvZGUgPSBFUlJPUl9FWElUX0NPREVTW2Vycm9yLmNvZGUgYXMgRXJyb3JDb2RlXSA/PyAxO1xuICAgIHJldHVybiBNYXRoLm1heChtYXgsIGV4aXRDb2RlKTtcbiAgfSwgMCk7XG59XG5cbiIsICJpbXBvcnQgY29uZmlnIGZyb20gJy4vY29uZmlnLnRzJztcbmltcG9ydCB7IGNyZWF0ZUVycm9yIH0gZnJvbSAnLi9lcnJvcnMudHMnO1xuaW1wb3J0IHR5cGUgeyBUb29sRXJyb3IgfSBmcm9tICcuL2Vycm9ycy50cyc7XG5pbXBvcnQgdHlwZSB7IFJhdGVMaW1pdE1ldGEgfSBmcm9tICcuL2VudmVsb3BlLnRzJztcblxuY29uc3QgQkFTRV9VUkwgPSAnaHR0cHM6Ly9hcGkuZmlnbWEuY29tJztcblxudHlwZSBTZWFyY2hQYXJhbXMgPSBSZWNvcmQ8c3RyaW5nLCBzdHJpbmcgfCBudW1iZXIgfCBib29sZWFuIHwgbnVsbCB8IHVuZGVmaW5lZD47XG5cbmludGVyZmFjZSBGaWdtYVJlcXVlc3RPcHRpb25zIHtcbiAgcGF0aDogc3RyaW5nO1xuICBtZXRob2Q/OiBzdHJpbmc7XG4gIHRva2VuPzogc3RyaW5nO1xuICBoZWFkZXJzPzogUmVjb3JkPHN0cmluZywgc3RyaW5nPjtcbiAgYm9keT86IHVua25vd247XG4gIHNlYXJjaFBhcmFtcz86IFNlYXJjaFBhcmFtcztcbiAgbWF4QXR0ZW1wdHM/OiBudW1iZXI7XG4gIGluaXRpYWxEZWxheU1zPzogbnVtYmVyO1xufVxuXG5pbnRlcmZhY2UgRmlnbWFTdWNjZXNzPFREYXRhPiB7XG4gIG9rOiB0cnVlO1xuICBkYXRhOiBURGF0YTtcbiAgcmF0ZUxpbWl0OiBSYXRlTGltaXRNZXRhO1xufVxuXG5pbnRlcmZhY2UgRmlnbWFGYWlsdXJlIHtcbiAgb2s6IGZhbHNlO1xuICBlcnJvcjogVG9vbEVycm9yPHsgc3RhdHVzPzogbnVtYmVyIH0+O1xuICBzdGF0dXM/OiBudW1iZXIgfCBudWxsO1xuICByYXRlTGltaXQ6IFJhdGVMaW1pdE1ldGEgfCBudWxsO1xufVxuXG5leHBvcnQgdHlwZSBGaWdtYVJlc3BvbnNlPFREYXRhPiA9IEZpZ21hU3VjY2VzczxURGF0YT4gfCBGaWdtYUZhaWx1cmU7XG5cbmZ1bmN0aW9uIHNsZWVwKG1zOiBudW1iZXIpOiBQcm9taXNlPHZvaWQ+IHtcbiAgcmV0dXJuIG5ldyBQcm9taXNlKChyZXNvbHZlKSA9PiBzZXRUaW1lb3V0KHJlc29sdmUsIG1zKSk7XG59XG5cbmZ1bmN0aW9uIHBhcnNlSnNvblNhZmVseSh0ZXh0OiBzdHJpbmcpOiB1bmtub3duIHtcbiAgdHJ5IHtcbiAgICByZXR1cm4gdGV4dCA/IEpTT04ucGFyc2UodGV4dCkgOiB7fTtcbiAgfSBjYXRjaCB7XG4gICAgcmV0dXJuIHsgcmF3OiB0ZXh0IH07XG4gIH1cbn1cblxuZnVuY3Rpb24gcGFyc2VSYXRlTGltaXQoaGVhZGVyczogSGVhZGVycywgYXR0ZW1wdHM6IG51bWJlciwgbGFzdFdhaXRNczogbnVtYmVyKTogUmF0ZUxpbWl0TWV0YSB7XG4gIGNvbnN0IHJlbWFpbmluZ0hlYWRlciA9IGhlYWRlcnMuZ2V0KCd4LXJhdGVsaW1pdC1yZW1haW5pbmcnKTtcbiAgY29uc3QgcmVzZXRIZWFkZXIgPSBoZWFkZXJzLmdldCgneC1yYXRlbGltaXQtcmVzZXQnKTtcblxuICBsZXQgcmVtYWluaW5nOiBudW1iZXIgfCBudWxsID0gbnVsbDtcbiAgaWYgKHJlbWFpbmluZ0hlYWRlciAhPT0gbnVsbCAmJiByZW1haW5pbmdIZWFkZXIgIT09IHVuZGVmaW5lZCkge1xuICAgIGNvbnN0IHBhcnNlZCA9IE51bWJlcihyZW1haW5pbmdIZWFkZXIpO1xuICAgIHJlbWFpbmluZyA9IE51bWJlci5pc05hTihwYXJzZWQpID8gbnVsbCA6IHBhcnNlZDtcbiAgfVxuXG4gIGxldCByZXNldEF0OiBzdHJpbmcgfCBudWxsID0gbnVsbDtcbiAgaWYgKHJlc2V0SGVhZGVyKSB7XG4gICAgY29uc3QgbnVtZXJpY1Jlc2V0ID0gTnVtYmVyKHJlc2V0SGVhZGVyKTtcbiAgICBpZiAoIU51bWJlci5pc05hTihudW1lcmljUmVzZXQpKSB7XG4gICAgICByZXNldEF0ID0gbmV3IERhdGUobnVtZXJpY1Jlc2V0ICogMTAwMCkudG9JU09TdHJpbmcoKTtcbiAgICB9IGVsc2Uge1xuICAgICAgY29uc3QgZGF0ZSA9IG5ldyBEYXRlKHJlc2V0SGVhZGVyKTtcbiAgICAgIGlmICghTnVtYmVyLmlzTmFOKGRhdGUudmFsdWVPZigpKSkge1xuICAgICAgICByZXNldEF0ID0gZGF0ZS50b0lTT1N0cmluZygpO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIHJldHVybiB7XG4gICAgcmVtYWluaW5nLFxuICAgIHJlc2V0QXQsXG4gICAgYXR0ZW1wdHMsXG4gICAgbGFzdFdhaXRNcyxcbiAgfTtcbn1cblxuZnVuY3Rpb24gY29tcHV0ZUJhY2tvZmZNcyhhdHRlbXB0OiBudW1iZXIsIGluaXRpYWxEZWxheU1zOiBudW1iZXIpOiBudW1iZXIge1xuICByZXR1cm4gaW5pdGlhbERlbGF5TXMgKiAyICoqIChhdHRlbXB0IC0gMSk7XG59XG5cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBmaWdtYVJlcXVlc3Q8VERhdGEgPSB1bmtub3duPihcbiAgb3B0aW9uczogRmlnbWFSZXF1ZXN0T3B0aW9uc1xuKTogUHJvbWlzZTxGaWdtYVJlc3BvbnNlPFREYXRhPj4ge1xuICBjb25zdCB7XG4gICAgcGF0aCxcbiAgICBtZXRob2QgPSAnR0VUJyxcbiAgICB0b2tlbixcbiAgICBoZWFkZXJzID0ge30sXG4gICAgYm9keSxcbiAgICBzZWFyY2hQYXJhbXMsXG4gICAgbWF4QXR0ZW1wdHMgPSBjb25maWcuaHR0cD8ubWF4QXR0ZW1wdHMgPz8gNSxcbiAgICBpbml0aWFsRGVsYXlNcyA9IGNvbmZpZy5odHRwPy5pbml0aWFsRGVsYXlNcyA/PyAyNTAsXG4gIH0gPSBvcHRpb25zO1xuXG4gIGlmICghdG9rZW4pIHtcbiAgICByZXR1cm4ge1xuICAgICAgb2s6IGZhbHNlLFxuICAgICAgZXJyb3I6IGNyZWF0ZUVycm9yKCdGSUdNQV9BVVRIJywgJ0ZJR01BX0FDQ0VTU19UT0tFTiBpcyBtaXNzaW5nIGZyb20gdGhlIGVudmlyb25tZW50LicpLFxuICAgICAgc3RhdHVzOiBudWxsLFxuICAgICAgcmF0ZUxpbWl0OiBudWxsLFxuICAgIH07XG4gIH1cblxuICBjb25zdCB1cmwgPSBuZXcgVVJMKHBhdGgsIEJBU0VfVVJMKTtcblxuICBpZiAoc2VhcmNoUGFyYW1zKSB7XG4gICAgT2JqZWN0LmVudHJpZXMoc2VhcmNoUGFyYW1zKS5mb3JFYWNoKChba2V5LCB2YWx1ZV0pID0+IHtcbiAgICAgIGlmICh2YWx1ZSA9PT0gdW5kZWZpbmVkIHx8IHZhbHVlID09PSBudWxsKSByZXR1cm47XG4gICAgICB1cmwuc2VhcmNoUGFyYW1zLmFwcGVuZChrZXksIFN0cmluZyh2YWx1ZSkpO1xuICAgIH0pO1xuICB9XG5cbiAgbGV0IGF0dGVtcHQgPSAwO1xuICBsZXQgbGFzdFdhaXRNcyA9IDA7XG5cbiAgd2hpbGUgKGF0dGVtcHQgPCBtYXhBdHRlbXB0cykge1xuICAgIGF0dGVtcHQgKz0gMTtcblxuICAgIGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgZmV0Y2godXJsLCB7XG4gICAgICBtZXRob2QsXG4gICAgICBoZWFkZXJzOiB7XG4gICAgICAgICdDb250ZW50LVR5cGUnOiAnYXBwbGljYXRpb24vanNvbicsXG4gICAgICAgICdYLUZpZ21hLVRva2VuJzogdG9rZW4sXG4gICAgICAgIC4uLmhlYWRlcnMsXG4gICAgICB9LFxuICAgICAgYm9keTogYm9keSA/IEpTT04uc3RyaW5naWZ5KGJvZHkpIDogdW5kZWZpbmVkLFxuICAgIH0pO1xuXG4gICAgY29uc3QgdGV4dCA9IGF3YWl0IHJlc3BvbnNlLnRleHQoKTtcbiAgICBjb25zdCBwYXlsb2FkID0gcGFyc2VKc29uU2FmZWx5KHRleHQpIGFzIHsgbWVzc2FnZT86IHN0cmluZyB9O1xuICAgIGNvbnN0IHJhdGVMaW1pdCA9IHBhcnNlUmF0ZUxpbWl0KHJlc3BvbnNlLmhlYWRlcnMsIGF0dGVtcHQsIGxhc3RXYWl0TXMpO1xuXG4gICAgaWYgKHJlc3BvbnNlLm9rKSB7XG4gICAgICByZXR1cm4geyBvazogdHJ1ZSwgZGF0YTogcGF5bG9hZCBhcyBURGF0YSwgcmF0ZUxpbWl0IH07XG4gICAgfVxuXG4gICAgY29uc3Qgc3RhdHVzID0gcmVzcG9uc2Uuc3RhdHVzO1xuXG4gICAgaWYgKHN0YXR1cyA9PT0gNDAxIHx8IHN0YXR1cyA9PT0gNDAzKSB7XG4gICAgICByZXR1cm4geyBvazogZmFsc2UsIGVycm9yOiBjcmVhdGVFcnJvcignRklHTUFfQVVUSCcsIHBheWxvYWQ/Lm1lc3NhZ2UgPz8gJ0ZpZ21hIHRva2VuIGlzIHVuYXV0aG9yaXplZC4nLCB7IHN0YXR1cyB9KSwgc3RhdHVzLCByYXRlTGltaXQgfTtcbiAgICB9XG5cbiAgICBpZiAoc3RhdHVzID09PSA0MDQpIHtcbiAgICAgIHJldHVybiB7IG9rOiBmYWxzZSwgZXJyb3I6IGNyZWF0ZUVycm9yKCdGSUdNQV9OT1RfRk9VTkQnLCBwYXlsb2FkPy5tZXNzYWdlID8/ICdSZXNvdXJjZSBub3QgZm91bmQuJywgeyBzdGF0dXMgfSksIHN0YXR1cywgcmF0ZUxpbWl0IH07XG4gICAgfVxuXG4gICAgaWYgKHN0YXR1cyA9PT0gNDI5IHx8IHN0YXR1cyA+PSA1MDApIHtcbiAgICAgIGlmIChhdHRlbXB0ID49IG1heEF0dGVtcHRzKSB7XG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgb2s6IGZhbHNlLFxuICAgICAgICAgIGVycm9yOiBjcmVhdGVFcnJvcihzdGF0dXMgPT09IDQyOSA/ICdGSUdNQV9SQVRFX0xJTUlUJyA6ICdORVRXT1JLJywgcGF5bG9hZD8ubWVzc2FnZSA/PyAnRmlnbWEgcmVxdWVzdCBmYWlsZWQgYWZ0ZXIgbWF4aW11bSByZXRyaWVzLicsIHsgc3RhdHVzIH0pLFxuICAgICAgICAgIHN0YXR1cyxcbiAgICAgICAgICByYXRlTGltaXQsXG4gICAgICAgIH07XG4gICAgICB9XG5cbiAgICAgIGxldCB3YWl0TXMgPSBjb21wdXRlQmFja29mZk1zKGF0dGVtcHQsIGluaXRpYWxEZWxheU1zKTtcbiAgICAgIGNvbnN0IHJlc2V0SGVhZGVyID0gcmVzcG9uc2UuaGVhZGVycy5nZXQoJ3gtcmF0ZWxpbWl0LXJlc2V0Jyk7XG4gICAgICBpZiAocmVzZXRIZWFkZXIpIHtcbiAgICAgICAgY29uc3QgYXNOdW1iZXIgPSBOdW1iZXIocmVzZXRIZWFkZXIpO1xuICAgICAgICBpZiAoIU51bWJlci5pc05hTihhc051bWJlcikpIHtcbiAgICAgICAgICBjb25zdCByZXNldE1zID0gYXNOdW1iZXIgKiAxMDAwO1xuICAgICAgICAgIGNvbnN0IGRlbHRhID0gcmVzZXRNcyAtIERhdGUubm93KCk7XG4gICAgICAgICAgaWYgKGRlbHRhID4gMCkgd2FpdE1zID0gTWF0aC5tYXgod2FpdE1zLCBkZWx0YSk7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgY29uc3Qgaml0dGVyID0gTWF0aC5mbG9vcihNYXRoLnJhbmRvbSgpICogMTAwKTtcbiAgICAgIGxhc3RXYWl0TXMgPSB3YWl0TXMgKyBqaXR0ZXI7XG4gICAgICBhd2FpdCBzbGVlcChsYXN0V2FpdE1zKTtcbiAgICAgIGNvbnRpbnVlO1xuICAgIH1cblxuICAgIHJldHVybiB7IG9rOiBmYWxzZSwgZXJyb3I6IGNyZWF0ZUVycm9yKCdJTlRFUk5BTCcsIHBheWxvYWQ/Lm1lc3NhZ2UgPz8gJ1VuZXhwZWN0ZWQgZXJyb3IgZnJvbSBGaWdtYSBBUEkuJywgeyBzdGF0dXMgfSksIHN0YXR1cywgcmF0ZUxpbWl0IH07XG4gIH1cblxuICByZXR1cm4ge1xuICAgIG9rOiBmYWxzZSxcbiAgICBlcnJvcjogY3JlYXRlRXJyb3IoJ05FVFdPUksnLCAnVW5hYmxlIHRvIHJlYWNoIEZpZ21hIEFQSS4nKSxcbiAgICBzdGF0dXM6IG51bGwsXG4gICAgcmF0ZUxpbWl0OiB7IHJlbWFpbmluZzogbnVsbCwgcmVzZXRBdDogbnVsbCwgYXR0ZW1wdHM6IG1heEF0dGVtcHRzLCBsYXN0V2FpdE1zIH0sXG4gIH07XG59XG5cbiIsICJjb25zdCBGSUxFX0tFWV9SRUdFWCA9IC9maWdtYVxcLmNvbVxcLyg/OmZpbGV8ZGVzaWduKVxcLyhbQS1aYS16MC05XSspXFwvL2k7XG5cbmV4cG9ydCBpbnRlcmZhY2UgUGFyc2VkRmlnbWFVcmwge1xuICBmaWxlS2V5OiBzdHJpbmcgfCBudWxsO1xuICBub2RlSWQ6IHN0cmluZyB8IG51bGw7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBwYXJzZUZpZ21hVXJsKGlucHV0OiBzdHJpbmcgfCBudWxsIHwgdW5kZWZpbmVkKTogUGFyc2VkRmlnbWFVcmwge1xuICBpZiAoIWlucHV0KSByZXR1cm4geyBmaWxlS2V5OiBudWxsLCBub2RlSWQ6IG51bGwgfTtcbiAgdHJ5IHtcbiAgICBjb25zdCB1cmwgPSBuZXcgVVJMKGlucHV0KTtcbiAgICBjb25zdCBtYXRjaCA9IHVybC5ocmVmLm1hdGNoKEZJTEVfS0VZX1JFR0VYKTtcbiAgICBjb25zdCBmaWxlS2V5ID0gbWF0Y2ggPyBtYXRjaFsxXSA6IG51bGw7XG4gICAgY29uc3Qgbm9kZVBhcmFtID0gdXJsLnNlYXJjaFBhcmFtcy5nZXQoJ25vZGUtaWQnKTtcbiAgICBjb25zdCBub2RlSWQgPSBub2RlUGFyYW0gPyBlbnN1cmVOb2RlSWQobm9kZVBhcmFtKSA6IG51bGw7XG4gICAgcmV0dXJuIHsgZmlsZUtleSwgbm9kZUlkIH07XG4gIH0gY2F0Y2gge1xuICAgIHJldHVybiB7IGZpbGVLZXk6IG51bGwsIG5vZGVJZDogbnVsbCB9O1xuICB9XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBlbnN1cmVOb2RlSWQodmFsdWU6IHN0cmluZyB8IG51bGwgfCB1bmRlZmluZWQpOiBzdHJpbmcgfCBudWxsIHtcbiAgaWYgKCF2YWx1ZSkgcmV0dXJuIG51bGw7XG4gIGNvbnN0IGRlY29kZWQgPSBkZWNvZGVVUklDb21wb25lbnQodmFsdWUpO1xuICBpZiAoZGVjb2RlZC5pbmNsdWRlcygnOicpKSByZXR1cm4gZGVjb2RlZDtcbiAgaWYgKC9eWzAtOV0rLVswLTldKyQvLnRlc3QoZGVjb2RlZCkpIHtcbiAgICBjb25zdCBbbGVmdCwgcmlnaHRdID0gZGVjb2RlZC5zcGxpdCgnLScsIDIpO1xuICAgIHJldHVybiBgJHtsZWZ0fToke3JpZ2h0fWA7XG4gIH1cbiAgcmV0dXJuIGRl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 diff --git a/use-figma/scripts/get-metadata.mjs b/use-figma/scripts/get-metadata.mjs new file mode 100755 index 0000000..32da120 --- /dev/null +++ b/use-figma/scripts/get-metadata.mjs @@ -0,0 +1,469 @@ +#!/usr/bin/env node + +// coding-tools/figma-tools/js/src/_utils/cli-args.ts +function parseArgs(argv = process.argv.slice(2)) { + const args = { _: [] }; + for (let i = 0; i < argv.length; i += 1) { + const arg = argv[i]; + if (!arg.startsWith("-") || arg === "-") { + args._.push(arg); + continue; + } + if (arg === "--") { + const remaining = argv.slice(i + 1); + args._.push(...remaining); + break; + } + const [rawKey, inlineValue] = arg.split("=", 2); + const normalisedKey = rawKey.replace(/^-+/, ""); + let value; + if (inlineValue !== void 0) { + value = inlineValue; + } else { + const next = argv[i + 1]; + if (next !== void 0 && !next.startsWith("-")) { + value = next; + i += 1; + } else { + value = true; + } + } + args[normalisedKey] = value; + } + return args; +} + +// coding-tools/figma-tools/js/src/_utils/url-parse.ts +var FILE_KEY_REGEX = /figma\.com\/(?:file|design)\/([A-Za-z0-9]+)\//i; +function parseFigmaUrl(input) { + if (!input) return { fileKey: null, nodeId: null }; + try { + const url = new URL(input); + const match = url.href.match(FILE_KEY_REGEX); + const fileKey = match ? match[1] : null; + const nodeParam = url.searchParams.get("node-id"); + const nodeId = nodeParam ? ensureNodeId(nodeParam) : null; + return { fileKey, nodeId }; + } catch { + return { fileKey: null, nodeId: null }; + } +} +function ensureNodeId(value) { + if (!value) return null; + const decoded = decodeURIComponent(value); + if (decoded.includes(":")) return decoded; + if (/^[0-9]+-[0-9]+$/.test(decoded)) { + const [left, right] = decoded.split("-", 2); + return `${left}:${right}`; + } + return decoded; +} + +// coding-tools/figma-tools/js/src/_utils/config.ts +var config_default = { + schemaVersion: "1.0.0", + source: "agentic-coding-templates/figma-tools", + http: { + maxAttempts: 5, + initialDelayMs: 250 + } +}; + +// coding-tools/figma-tools/js/src/_utils/envelope.ts +function buildRateLimitMeta(rateLimit = {}) { + return { + remaining: rateLimit.remaining ?? null, + resetAt: rateLimit.resetAt ?? null, + attempts: rateLimit.attempts ?? 1, + lastWaitMs: rateLimit.lastWaitMs ?? 0 + }; +} +function createEnvelope({ + tool, + input = {}, + data = {}, + warnings = [], + errors = [], + rateLimit, + schemaVersion +}) { + return { + schemaVersion: schemaVersion ?? config_default.schemaVersion, + tool, + input, + meta: { + generatedAt: (/* @__PURE__ */ new Date()).toISOString(), + source: config_default.source, + rateLimit: buildRateLimitMeta(rateLimit) + }, + data, + warnings, + errors + }; +} + +// coding-tools/figma-tools/js/src/_utils/errors.ts +var ERROR_EXIT_CODES = { + INPUT_INVALID: 1, + CONFIG_INVALID: 1, + FIGMA_AUTH: 1, + FIGMA_NOT_FOUND: 2, + FIGMA_RATE_LIMIT: 2, + NETWORK: 2, + INTERNAL: 3 +}; +function createError(code, message, detail) { + return { + code, + message, + detail: detail ?? null + }; +} +function getExitCode(errors = []) { + if (!errors.length) { + return 0; + } + return errors.reduce((max, error) => { + const exitCode = ERROR_EXIT_CODES[error.code] ?? 1; + return Math.max(max, exitCode); + }, 0); +} + +// coding-tools/figma-tools/js/src/_utils/http-client.ts +var BASE_URL = "https://api.figma.com"; +function sleep(ms) { + return new Promise((resolve) => setTimeout(resolve, ms)); +} +function parseJsonSafely(text) { + try { + return text ? JSON.parse(text) : {}; + } catch { + return { raw: text }; + } +} +function parseRateLimit(headers, attempts, lastWaitMs) { + const remainingHeader = headers.get("x-ratelimit-remaining"); + const resetHeader = headers.get("x-ratelimit-reset"); + let remaining = null; + if (remainingHeader !== null && remainingHeader !== void 0) { + const parsed = Number(remainingHeader); + remaining = Number.isNaN(parsed) ? null : parsed; + } + let resetAt = null; + if (resetHeader) { + const numericReset = Number(resetHeader); + if (!Number.isNaN(numericReset)) { + resetAt = new Date(numericReset * 1e3).toISOString(); + } else { + const date = new Date(resetHeader); + if (!Number.isNaN(date.valueOf())) { + resetAt = date.toISOString(); + } + } + } + return { + remaining, + resetAt, + attempts, + lastWaitMs + }; +} +function computeBackoffMs(attempt, initialDelayMs) { + return initialDelayMs * 2 ** (attempt - 1); +} +async function figmaRequest(options) { + const { + path, + method = "GET", + token, + headers = {}, + body, + searchParams, + maxAttempts = config_default.http?.maxAttempts ?? 5, + initialDelayMs = config_default.http?.initialDelayMs ?? 250 + } = options; + if (!token) { + return { + ok: false, + error: createError("FIGMA_AUTH", "FIGMA_ACCESS_TOKEN is missing from the environment."), + status: null, + rateLimit: null + }; + } + const url = new URL(path, BASE_URL); + if (searchParams) { + Object.entries(searchParams).forEach(([key, value]) => { + if (value === void 0 || value === null) return; + url.searchParams.append(key, String(value)); + }); + } + let attempt = 0; + let lastWaitMs = 0; + while (attempt < maxAttempts) { + attempt += 1; + const response = await fetch(url, { + method, + headers: { + "Content-Type": "application/json", + "X-Figma-Token": token, + ...headers + }, + body: body ? JSON.stringify(body) : void 0 + }); + const text = await response.text(); + const payload = parseJsonSafely(text); + const rateLimit = parseRateLimit(response.headers, attempt, lastWaitMs); + if (response.ok) { + return { ok: true, data: payload, rateLimit }; + } + const status = response.status; + if (status === 401 || status === 403) { + return { ok: false, error: createError("FIGMA_AUTH", payload?.message ?? "Figma token is unauthorized.", { status }), status, rateLimit }; + } + if (status === 404) { + return { ok: false, error: createError("FIGMA_NOT_FOUND", payload?.message ?? "Resource not found.", { status }), status, rateLimit }; + } + if (status === 429 || status >= 500) { + if (attempt >= maxAttempts) { + return { + ok: false, + error: createError(status === 429 ? "FIGMA_RATE_LIMIT" : "NETWORK", payload?.message ?? "Figma request failed after maximum retries.", { status }), + status, + rateLimit + }; + } + let waitMs = computeBackoffMs(attempt, initialDelayMs); + const resetHeader = response.headers.get("x-ratelimit-reset"); + if (resetHeader) { + const asNumber = Number(resetHeader); + if (!Number.isNaN(asNumber)) { + const resetMs = asNumber * 1e3; + const delta = resetMs - Date.now(); + if (delta > 0) waitMs = Math.max(waitMs, delta); + } + } + const jitter = Math.floor(Math.random() * 100); + lastWaitMs = waitMs + jitter; + await sleep(lastWaitMs); + continue; + } + return { ok: false, error: createError("INTERNAL", payload?.message ?? "Unexpected error from Figma API.", { status }), status, rateLimit }; + } + return { + ok: false, + error: createError("NETWORK", "Unable to reach Figma API."), + status: null, + rateLimit: { remaining: null, resetAt: null, attempts: maxAttempts, lastWaitMs } + }; +} + +// coding-tools/figma-tools/js/src/get-metadata.ts +var TOOL_NAME = "get-metadata"; +function log(message, verbose) { + if (verbose) { + process.stderr.write(`[${TOOL_NAME}] ${message} +`); + } +} +function toOptionalString(value) { + return typeof value === "string" && value.length > 0 ? value : null; +} +function exitWithEnvelope(envelope, errors = []) { + process.stdout.write(`${JSON.stringify(envelope, null, 2)} +`); + process.exit(getExitCode(errors)); +} +function mapNode(node, index = 0, parentId = null) { + const children = Array.isArray(node.children) ? node.children.map((child, idx) => mapNode(child, idx, node.id)) : []; + return { + id: node.id, + name: node.name, + type: node.type, + visible: node.visible ?? true, + locked: node.locked ?? false, + index, + parentId, + characters: node.characters ?? null, + blendMode: node.blendMode ?? null, + opacity: node.opacity ?? 1, + isMask: node.isMask ?? false, + relativeTransform: node.relativeTransform ?? null, + absoluteBoundingBox: node.absoluteBoundingBox ?? null, + size: node.size ?? null, + fills: node.fills ?? [], + strokes: node.strokes ?? [], + strokeWeight: node.strokeWeight ?? null, + strokeAlign: node.strokeAlign ?? null, + effects: node.effects ?? [], + constraints: node.constraints ?? null, + layoutAlign: node.layoutAlign ?? null, + layoutGrow: node.layoutGrow ?? null, + layoutMode: node.layoutMode ?? null, + primaryAxisSizingMode: node.primaryAxisSizingMode ?? null, + counterAxisSizingMode: node.counterAxisSizingMode ?? null, + primaryAxisAlignItems: node.primaryAxisAlignItems ?? null, + counterAxisAlignItems: node.counterAxisAlignItems ?? null, + itemSpacing: node.itemSpacing ?? null, + paddingLeft: node.paddingLeft ?? null, + paddingRight: node.paddingRight ?? null, + paddingTop: node.paddingTop ?? null, + paddingBottom: node.paddingBottom ?? null, + clipsContent: node.clipsContent ?? false, + layoutGrids: node.layoutGrids ?? [], + exportSettings: node.exportSettings ?? [], + transitionNodeID: node.transitionNodeID ?? null, + overlayPositionType: node.overlayPositionType ?? null, + overlayRelativePosition: node.overlayRelativePosition ?? null, + children + }; +} +function escapeXml(value) { + return value.replace(/&/g, "&").replace(//g, ">").replace(/\"/g, """).replace(/'/g, "'"); +} +function nodeToXml(node) { + const attrs = [ + `id="${escapeXml(node.id)}"`, + node.type ? `type="${escapeXml(node.type)}"` : null, + node.name ? `name="${escapeXml(node.name)}"` : null, + node.visible === false ? 'visible="false"' : null, + node.locked ? 'locked="true"' : null, + node.parentId ? `parentId="${escapeXml(node.parentId)}"` : null, + node.absoluteBoundingBox ? `x="${node.absoluteBoundingBox.x ?? 0}" y="${node.absoluteBoundingBox.y ?? 0}" width="${node.absoluteBoundingBox.width ?? 0}" height="${node.absoluteBoundingBox.height ?? 0}"` : null + ].filter(Boolean); + const childXml = node.children.map(nodeToXml).join(""); + return `${childXml}`; +} +async function main() { + const args = parseArgs(); + const verbose = Boolean(args.verbose ?? args.v); + const schemaVersion = toOptionalString(args["schema-version"]) ?? void 0; + const warnings = []; + const errors = []; + const token = process.env.FIGMA_ACCESS_TOKEN; + if (!token || !token.trim()) { + errors.push(createError("FIGMA_AUTH", "FIGMA_ACCESS_TOKEN is required but was not provided.")); + const envelope2 = createEnvelope({ + tool: TOOL_NAME, + input: { fileKey: null, nodeId: null, format: "json" }, + warnings, + errors, + schemaVersion, + data: {} + }); + exitWithEnvelope(envelope2, errors); + } + const urlInput = toOptionalString(args.url) ?? toOptionalString(args.u); + let fileKey = toOptionalString(args["file-key"]) ?? void 0; + let nodeId = ensureNodeId(toOptionalString(args["node-id"])); + if (urlInput) { + const parsed = parseFigmaUrl(urlInput); + fileKey = fileKey || parsed.fileKey || void 0; + nodeId = nodeId || parsed.nodeId; + } + let format = String(args.format ?? "json").toLowerCase(); + let outputMode; + if (format === "json" || format === "xml" || format === "both") { + outputMode = format; + } else { + warnings.push(`Unknown format "${format}". Defaulting to json.`); + outputMode = "json"; + } + const input = { + fileKey: fileKey ?? null, + nodeId: nodeId ?? null, + format: outputMode + }; + if (!fileKey) { + errors.push(createError("INPUT_INVALID", "A valid Figma file key is required (--file-key or --url).")); + } + if (!nodeId) { + errors.push(createError("INPUT_INVALID", "A valid Figma node id is required (--node-id or --url with node-id).")); + } + if (errors.length) { + const envelope2 = createEnvelope({ + tool: TOOL_NAME, + input, + warnings, + errors, + data: {}, + schemaVersion + }); + exitWithEnvelope(envelope2, errors); + } + const resolvedFileKey = fileKey; + const resolvedNodeId = nodeId; + log(`Fetching metadata for node ${resolvedNodeId} in file ${resolvedFileKey}`, verbose); + const nodeResponse = await figmaRequest({ + path: `/v1/files/${resolvedFileKey}/nodes`, + token, + searchParams: { ids: resolvedNodeId } + }); + if (!nodeResponse.ok) { + errors.push(nodeResponse.error ?? createError("INTERNAL", "Failed to fetch node metadata.")); + const envelope2 = createEnvelope({ + tool: TOOL_NAME, + input, + warnings, + errors, + rateLimit: nodeResponse.rateLimit ?? void 0, + data: {}, + schemaVersion + }); + exitWithEnvelope(envelope2, errors); + } + const nodesMap = nodeResponse.data?.nodes ?? {}; + const nodeWrapper = nodesMap[resolvedNodeId]; + if (!nodeWrapper || !nodeWrapper.document) { + errors.push(createError("FIGMA_NOT_FOUND", `Node ${resolvedNodeId} was not found in file ${resolvedFileKey}.`)); + const envelope2 = createEnvelope({ + tool: TOOL_NAME, + input, + warnings, + errors, + rateLimit: nodeResponse.rateLimit ?? void 0, + data: {}, + schemaVersion + }); + exitWithEnvelope(envelope2, errors); + } + const rootNode = nodeWrapper.document; + const metadataTree = mapNode(rootNode); + let xmlDocument; + if (outputMode === "xml" || outputMode === "both") { + xmlDocument = `${nodeToXml(metadataTree)}`; + } + const data = { + file: { + key: resolvedFileKey, + name: nodeResponse.data?.name ?? null, + lastModified: nodeResponse.data?.lastModified ?? null + }, + metadata: metadataTree, + xml: xmlDocument + }; + const envelope = createEnvelope({ + tool: TOOL_NAME, + input, + data, + warnings, + errors, + rateLimit: nodeResponse.rateLimit ?? void 0, + schemaVersion + }); + process.stdout.write(`${JSON.stringify(envelope, null, 2)} +`); + process.exit(getExitCode(errors)); +} +main().catch((error) => { + const message = error instanceof Error ? error.message : "Unknown error"; + const envelope = createEnvelope({ + tool: TOOL_NAME, + input: { fileKey: null, nodeId: null, format: "json" }, + errors: [createError("INTERNAL", message, { stack: error instanceof Error ? error.stack : void 0 })], + data: {} + }); + process.stdout.write(`${JSON.stringify(envelope, null, 2)} +`); + process.exit(3); +}); +//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiLi4vc3JjL191dGlscy9jbGktYXJncy50cyIsICIuLi9zcmMvX3V0aWxzL3VybC1wYXJzZS50cyIsICIuLi9zcmMvX3V0aWxzL2NvbmZpZy50cyIsICIuLi9zcmMvX3V0aWxzL2VudmVsb3BlLnRzIiwgIi4uL3NyYy9fdXRpbHMvZXJyb3JzLnRzIiwgIi4uL3NyYy9fdXRpbHMvaHR0cC1jbGllbnQudHMiLCAiLi4vc3JjL2dldC1tZXRhZGF0YS50cyJdLAogICJzb3VyY2VzQ29udGVudCI6IFsiZXhwb3J0IHR5cGUgQ2xpQXJnVmFsdWUgPSBzdHJpbmcgfCBib29sZWFuO1xuXG5leHBvcnQgaW50ZXJmYWNlIENsaUFyZ3Mge1xuICBfOiBzdHJpbmdbXTtcbiAgW2tleTogc3RyaW5nXTogQ2xpQXJnVmFsdWUgfCBzdHJpbmdbXTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIHBhcnNlQXJncyhhcmd2OiBzdHJpbmdbXSA9IHByb2Nlc3MuYXJndi5zbGljZSgyKSk6IENsaUFyZ3Mge1xuICBjb25zdCBhcmdzOiBDbGlBcmdzID0geyBfOiBbXSB9O1xuXG4gIGZvciAobGV0IGkgPSAwOyBpIDwgYXJndi5sZW5ndGg7IGkgKz0gMSkge1xuICAgIGNvbnN0IGFyZyA9IGFyZ3ZbaV07XG5cbiAgICBpZiAoIWFyZy5zdGFydHNXaXRoKCctJykgfHwgYXJnID09PSAnLScpIHtcbiAgICAgIGFyZ3MuXy5wdXNoKGFyZyk7XG4gICAgICBjb250aW51ZTtcbiAgICB9XG5cbiAgICBpZiAoYXJnID09PSAnLS0nKSB7XG4gICAgICBjb25zdCByZW1haW5pbmcgPSBhcmd2LnNsaWNlKGkgKyAxKTtcbiAgICAgIGFyZ3MuXy5wdXNoKC4uLnJlbWFpbmluZyk7XG4gICAgICBicmVhaztcbiAgICB9XG5cbiAgICBjb25zdCBbcmF3S2V5LCBpbmxpbmVWYWx1ZV0gPSBhcmcuc3BsaXQoJz0nLCAyKTtcbiAgICBjb25zdCBub3JtYWxpc2VkS2V5ID0gcmF3S2V5LnJlcGxhY2UoL14tKy8sICcnKTtcblxuICAgIGxldCB2YWx1ZTogQ2xpQXJnVmFsdWU7XG4gICAgaWYgKGlubGluZVZhbHVlICE9PSB1bmRlZmluZWQpIHtcbiAgICAgIHZhbHVlID0gaW5saW5lVmFsdWU7XG4gICAgfSBlbHNlIHtcbiAgICAgIGNvbnN0IG5leHQgPSBhcmd2W2kgKyAxXTtcbiAgICAgIGlmIChuZXh0ICE9PSB1bmRlZmluZWQgJiYgIW5leHQuc3RhcnRzV2l0aCgnLScpKSB7XG4gICAgICAgIHZhbHVlID0gbmV4dDtcbiAgICAgICAgaSArPSAxO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgdmFsdWUgPSB0cnVlO1xuICAgICAgfVxuICAgIH1cblxuICAgIGFyZ3Nbbm9ybWFsaXNlZEtleV0gPSB2YWx1ZTtcbiAgfVxuXG4gIHJldHVybiBhcmdzO1xufVxuXG4iLCAiY29uc3QgRklMRV9LRVlfUkVHRVggPSAvZmlnbWFcXC5jb21cXC8oPzpmaWxlfGRlc2lnbilcXC8oW0EtWmEtejAtOV0rKVxcLy9pO1xuXG5leHBvcnQgaW50ZXJmYWNlIFBhcnNlZEZpZ21hVXJsIHtcbiAgZmlsZUtleTogc3RyaW5nIHwgbnVsbDtcbiAgbm9kZUlkOiBzdHJpbmcgfCBudWxsO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gcGFyc2VGaWdtYVVybChpbnB1dDogc3RyaW5nIHwgbnVsbCB8IHVuZGVmaW5lZCk6IFBhcnNlZEZpZ21hVXJsIHtcbiAgaWYgKCFpbnB1dCkgcmV0dXJuIHsgZmlsZUtleTogbnVsbCwgbm9kZUlkOiBudWxsIH07XG4gIHRyeSB7XG4gICAgY29uc3QgdXJsID0gbmV3IFVSTChpbnB1dCk7XG4gICAgY29uc3QgbWF0Y2ggPSB1cmwuaHJlZi5tYXRjaChGSUxFX0tFWV9SRUdFWCk7XG4gICAgY29uc3QgZmlsZUtleSA9IG1hdGNoID8gbWF0Y2hbMV0gOiBudWxsO1xuICAgIGNvbnN0IG5vZGVQYXJhbSA9IHVybC5zZWFyY2hQYXJhbXMuZ2V0KCdub2RlLWlkJyk7XG4gICAgY29uc3Qgbm9kZUlkID0gbm9kZVBhcmFtID8gZW5zdXJlTm9kZUlkKG5vZGVQYXJhbSkgOiBudWxsO1xuICAgIHJldHVybiB7IGZpbGVLZXksIG5vZGVJZCB9O1xuICB9IGNhdGNoIHtcbiAgICByZXR1cm4geyBmaWxlS2V5OiBudWxsLCBub2RlSWQ6IG51bGwgfTtcbiAgfVxufVxuXG5leHBvcnQgZnVuY3Rpb24gZW5zdXJlTm9kZUlkKHZhbHVlOiBzdHJpbmcgfCBudWxsIHwgdW5kZWZpbmVkKTogc3RyaW5nIHwgbnVsbCB7XG4gIGlmICghdmFsdWUpIHJldHVybiBudWxsO1xuICBjb25zdCBkZWNvZGVkID0gZGVjb2RlVVJJQ29tcG9uZW50KHZhbHVlKTtcbiAgaWYgKGRlY29kZWQuaW5jbHVkZXMoJzonKSkgcmV0dXJuIGRlY29kZWQ7XG4gIGlmICgvXlswLTldKy1bMC05XSskLy50ZXN0KGRlY29kZWQpKSB7XG4gICAgY29uc3QgW2xlZnQsIHJpZ2h0XSA9IGRlY29kZWQuc3BsaXQoJy0nLCAyKTtcbiAgICByZXR1cm4gYCR7bGVmdH06JHtyaWdodH1gO1xuICB9XG4gIHJldHVybiBkZWNvZGVkO1xufVxuXG4iLCAiZXhwb3J0IGRlZmF1bHQge1xuICBzY2hlbWFWZXJzaW9uOiAnMS4wLjAnLFxuICBzb3VyY2U6ICdhZ2VudGljLWNvZGluZy10ZW1wbGF0ZXMvZmlnbWEtdG9vbHMnLFxuICBodHRwOiB7XG4gICAgbWF4QXR0ZW1wdHM6IDUsXG4gICAgaW5pdGlhbERlbGF5TXM6IDI1MCxcbiAgfSxcbn0gYXMgY29uc3Q7XG5cbiIsICJpbXBvcnQgY29uZmlnIGZyb20gJy4vY29uZmlnLnRzJztcbmltcG9ydCB0eXBlIHsgVG9vbEVycm9yIH0gZnJvbSAnLi9lcnJvcnMudHMnO1xuXG5leHBvcnQgaW50ZXJmYWNlIFJhdGVMaW1pdE1ldGEge1xuICByZW1haW5pbmc6IG51bWJlciB8IG51bGw7XG4gIHJlc2V0QXQ6IHN0cmluZyB8IG51bGw7XG4gIGF0dGVtcHRzOiBudW1iZXI7XG4gIGxhc3RXYWl0TXM6IG51bWJlcjtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBUb29sRW52ZWxvcGU8XG4gIFRJbnB1dCBleHRlbmRzIFJlY29yZDxzdHJpbmcsIHVua25vd24+ID0gUmVjb3JkPHN0cmluZywgdW5rbm93bj4sXG4gIFREYXRhID0gdW5rbm93blxuPiB7XG4gIHNjaGVtYVZlcnNpb246IHN0cmluZztcbiAgdG9vbDogc3RyaW5nO1xuICBpbnB1dDogVElucHV0O1xuICBtZXRhOiB7XG4gICAgZ2VuZXJhdGVkQXQ6IHN0cmluZztcbiAgICBzb3VyY2U6IHN0cmluZztcbiAgICByYXRlTGltaXQ6IFJhdGVMaW1pdE1ldGE7XG4gIH07XG4gIGRhdGE6IFREYXRhO1xuICB3YXJuaW5nczogc3RyaW5nW107XG4gIGVycm9yczogVG9vbEVycm9yW107XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgQ3JlYXRlRW52ZWxvcGVPcHRpb25zPFxuICBUSW5wdXQgZXh0ZW5kcyBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPiA9IFJlY29yZDxzdHJpbmcsIHVua25vd24+LFxuICBURGF0YSA9IHVua25vd25cbj4ge1xuICB0b29sOiBzdHJpbmc7XG4gIGlucHV0PzogVElucHV0O1xuICBkYXRhPzogVERhdGE7XG4gIHdhcm5pbmdzPzogc3RyaW5nW107XG4gIGVycm9ycz86IFRvb2xFcnJvcltdO1xuICByYXRlTGltaXQ/OiBQYXJ0aWFsPFJhdGVMaW1pdE1ldGE+O1xuICBzY2hlbWFWZXJzaW9uPzogc3RyaW5nO1xufVxuXG5mdW5jdGlvbiBidWlsZFJhdGVMaW1pdE1ldGEocmF0ZUxpbWl0OiBQYXJ0aWFsPFJhdGVMaW1pdE1ldGE+ID0ge30pOiBSYXRlTGltaXRNZXRhIHtcbiAgcmV0dXJuIHtcbiAgICByZW1haW5pbmc6IHJhdGVMaW1pdC5yZW1haW5pbmcgPz8gbnVsbCxcbiAgICByZXNldEF0OiByYXRlTGltaXQucmVzZXRBdCA/PyBudWxsLFxuICAgIGF0dGVtcHRzOiByYXRlTGltaXQuYXR0ZW1wdHMgPz8gMSxcbiAgICBsYXN0V2FpdE1zOiByYXRlTGltaXQubGFzdFdhaXRNcyA/PyAwLFxuICB9O1xufVxuXG5leHBvcnQgZnVuY3Rpb24gY3JlYXRlRW52ZWxvcGU8XG4gIFRJbnB1dCBleHRlbmRzIFJlY29yZDxzdHJpbmcsIHVua25vd24+ID0gUmVjb3JkPHN0cmluZywgdW5rbm93bj4sXG4gIFREYXRhID0gdW5rbm93blxuPih7XG4gIHRvb2wsXG4gIGlucHV0ID0ge30gYXMgVElucHV0LFxuICBkYXRhID0ge30gYXMgVERhdGEsXG4gIHdhcm5pbmdzID0gW10sXG4gIGVycm9ycyA9IFtdLFxuICByYXRlTGltaXQsXG4gIHNjaGVtYVZlcnNpb24sXG59OiBDcmVhdGVFbnZlbG9wZU9wdGlvbnM8VElucHV0LCBURGF0YT4pOiBUb29sRW52ZWxvcGU8VElucHV0LCBURGF0YT4ge1xuICByZXR1cm4ge1xuICAgIHNjaGVtYVZlcnNpb246IHNjaGVtYVZlcnNpb24gPz8gY29uZmlnLnNjaGVtYVZlcnNpb24sXG4gICAgdG9vbCxcbiAgICBpbnB1dCxcbiAgICBtZXRhOiB7XG4gICAgICBnZW5lcmF0ZWRBdDogbmV3IERhdGUoKS50b0lTT1N0cmluZygpLFxuICAgICAgc291cmNlOiBjb25maWcuc291cmNlLFxuICAgICAgcmF0ZUxpbWl0OiBidWlsZFJhdGVMaW1pdE1ldGEocmF0ZUxpbWl0KSxcbiAgICB9LFxuICAgIGRhdGEsXG4gICAgd2FybmluZ3MsXG4gICAgZXJyb3JzLFxuICB9O1xufVxuXG4iLCAiZXhwb3J0IGNvbnN0IEVSUk9SX0VYSVRfQ09ERVMgPSB7XG4gIElOUFVUX0lOVkFMSUQ6IDEsXG4gIENPTkZJR19JTlZBTElEOiAxLFxuICBGSUdNQV9BVVRIOiAxLFxuICBGSUdNQV9OT1RfRk9VTkQ6IDIsXG4gIEZJR01BX1JBVEVfTElNSVQ6IDIsXG4gIE5FVFdPUks6IDIsXG4gIElOVEVSTkFMOiAzLFxufSBhcyBjb25zdDtcblxuZXhwb3J0IHR5cGUgRXJyb3JDb2RlID0ga2V5b2YgdHlwZW9mIEVSUk9SX0VYSVRfQ09ERVM7XG5cbmV4cG9ydCBpbnRlcmZhY2UgVG9vbEVycm9yPFREZXRhaWwgPSB1bmtub3duPiB7XG4gIGNvZGU6IEVycm9yQ29kZSB8IHN0cmluZztcbiAgbWVzc2FnZTogc3RyaW5nO1xuICBkZXRhaWw/OiBURGV0YWlsIHwgbnVsbDtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGNyZWF0ZUVycm9yPFREZXRhaWwgPSB1bmtub3duPihcbiAgY29kZTogRXJyb3JDb2RlIHwgc3RyaW5nLFxuICBtZXNzYWdlOiBzdHJpbmcsXG4gIGRldGFpbD86IFREZXRhaWwgfCBudWxsXG4pOiBUb29sRXJyb3I8VERldGFpbD4ge1xuICByZXR1cm4ge1xuICAgIGNvZGUsXG4gICAgbWVzc2FnZSxcbiAgICBkZXRhaWw6IGRldGFpbCA/PyBudWxsLFxuICB9O1xufVxuXG5leHBvcnQgZnVuY3Rpb24gZ2V0RXhpdENvZGUoZXJyb3JzOiBUb29sRXJyb3JbXSA9IFtdKTogbnVtYmVyIHtcbiAgaWYgKCFlcnJvcnMubGVuZ3RoKSB7XG4gICAgcmV0dXJuIDA7XG4gIH1cblxuICByZXR1cm4gZXJyb3JzLnJlZHVjZSgobWF4LCBlcnJvcikgPT4ge1xuICAgIGNvbnN0IGV4aXRDb2RlID0gRVJST1JfRVhJVF9DT0RFU1tlcnJvci5jb2RlIGFzIEVycm9yQ29kZV0gPz8gMTtcbiAgICByZXR1cm4gTWF0aC5tYXgobWF4LCBleGl0Q29kZSk7XG4gIH0sIDApO1xufVxuXG4iLCAiaW1wb3J0IGNvbmZpZyBmcm9tICcuL2NvbmZpZy50cyc7XG5pbXBvcnQgeyBjcmVhdGVFcnJvciB9IGZyb20gJy4vZXJyb3JzLnRzJztcbmltcG9ydCB0eXBlIHsgVG9vbEVycm9yIH0gZnJvbSAnLi9lcnJvcnMudHMnO1xuaW1wb3J0IHR5cGUgeyBSYXRlTGltaXRNZXRhIH0gZnJvbSAnLi9lbnZlbG9wZS50cyc7XG5cbmNvbnN0IEJBU0VfVVJMID0gJ2h0dHBzOi8vYXBpLmZpZ21hLmNvbSc7XG5cbnR5cGUgU2VhcmNoUGFyYW1zID0gUmVjb3JkPHN0cmluZywgc3RyaW5nIHwgbnVtYmVyIHwgYm9vbGVhbiB8IG51bGwgfCB1bmRlZmluZWQ+O1xuXG5pbnRlcmZhY2UgRmlnbWFSZXF1ZXN0T3B0aW9ucyB7XG4gIHBhdGg6IHN0cmluZztcbiAgbWV0aG9kPzogc3RyaW5nO1xuICB0b2tlbj86IHN0cmluZztcbiAgaGVhZGVycz86IFJlY29yZDxzdHJpbmcsIHN0cmluZz47XG4gIGJvZHk/OiB1bmtub3duO1xuICBzZWFyY2hQYXJhbXM/OiBTZWFyY2hQYXJhbXM7XG4gIG1heEF0dGVtcHRzPzogbnVtYmVyO1xuICBpbml0aWFsRGVsYXlNcz86IG51bWJlcjtcbn1cblxuaW50ZXJmYWNlIEZpZ21hU3VjY2VzczxURGF0YT4ge1xuICBvazogdHJ1ZTtcbiAgZGF0YTogVERhdGE7XG4gIHJhdGVMaW1pdDogUmF0ZUxpbWl0TWV0YTtcbn1cblxuaW50ZXJmYWNlIEZpZ21hRmFpbHVyZSB7XG4gIG9rOiBmYWxzZTtcbiAgZXJyb3I6IFRvb2xFcnJvcjx7IHN0YXR1cz86IG51bWJlciB9PjtcbiAgc3RhdHVzPzogbnVtYmVyIHwgbnVsbDtcbiAgcmF0ZUxpbWl0OiBSYXRlTGltaXRNZXRhIHwgbnVsbDtcbn1cblxuZXhwb3J0IHR5cGUgRmlnbWFSZXNwb25zZTxURGF0YT4gPSBGaWdtYVN1Y2Nlc3M8VERhdGE+IHwgRmlnbWFGYWlsdXJlO1xuXG5mdW5jdGlvbiBzbGVlcChtczogbnVtYmVyKTogUHJvbWlzZTx2b2lkPiB7XG4gIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSkgPT4gc2V0VGltZW91dChyZXNvbHZlLCBtcykpO1xufVxuXG5mdW5jdGlvbiBwYXJzZUpzb25TYWZlbHkodGV4dDogc3RyaW5nKTogdW5rbm93biB7XG4gIHRyeSB7XG4gICAgcmV0dXJuIHRleHQgPyBKU09OLnBhcnNlKHRleHQpIDoge307XG4gIH0gY2F0Y2gge1xuICAgIHJldHVybiB7IHJhdzogdGV4dCB9O1xuICB9XG59XG5cbmZ1bmN0aW9uIHBhcnNlUmF0ZUxpbWl0KGhlYWRlcnM6IEhlYWRlcnMsIGF0dGVtcHRzOiBudW1iZXIsIGxhc3RXYWl0TXM6IG51bWJlcik6IFJhdGVMaW1pdE1ldGEge1xuICBjb25zdCByZW1haW5pbmdIZWFkZXIgPSBoZWFkZXJzLmdldCgneC1yYXRlbGltaXQtcmVtYWluaW5nJyk7XG4gIGNvbnN0IHJlc2V0SGVhZGVyID0gaGVhZGVycy5nZXQoJ3gtcmF0ZWxpbWl0LXJlc2V0Jyk7XG5cbiAgbGV0IHJlbWFpbmluZzogbnVtYmVyIHwgbnVsbCA9IG51bGw7XG4gIGlmIChyZW1haW5pbmdIZWFkZXIgIT09IG51bGwgJiYgcmVtYWluaW5nSGVhZGVyICE9PSB1bmRlZmluZWQpIHtcbiAgICBjb25zdCBwYXJzZWQgPSBOdW1iZXIocmVtYWluaW5nSGVhZGVyKTtcbiAgICByZW1haW5pbmcgPSBOdW1iZXIuaXNOYU4ocGFyc2VkKSA/IG51bGwgOiBwYXJzZWQ7XG4gIH1cblxuICBsZXQgcmVzZXRBdDogc3RyaW5nIHwgbnVsbCA9IG51bGw7XG4gIGlmIChyZXNldEhlYWRlcikge1xuICAgIGNvbnN0IG51bWVyaWNSZXNldCA9IE51bWJlcihyZXNldEhlYWRlcik7XG4gICAgaWYgKCFOdW1iZXIuaXNOYU4obnVtZXJpY1Jlc2V0KSkge1xuICAgICAgcmVzZXRBdCA9IG5ldyBEYXRlKG51bWVyaWNSZXNldCAqIDEwMDApLnRvSVNPU3RyaW5nKCk7XG4gICAgfSBlbHNlIHtcbiAgICAgIGNvbnN0IGRhdGUgPSBuZXcgRGF0ZShyZXNldEhlYWRlcik7XG4gICAgICBpZiAoIU51bWJlci5pc05hTihkYXRlLnZhbHVlT2YoKSkpIHtcbiAgICAgICAgcmVzZXRBdCA9IGRhdGUudG9JU09TdHJpbmcoKTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICByZXR1cm4ge1xuICAgIHJlbWFpbmluZyxcbiAgICByZXNldEF0LFxuICAgIGF0dGVtcHRzLFxuICAgIGxhc3RXYWl0TXMsXG4gIH07XG59XG5cbmZ1bmN0aW9uIGNvbXB1dGVCYWNrb2ZmTXMoYXR0ZW1wdDogbnVtYmVyLCBpbml0aWFsRGVsYXlNczogbnVtYmVyKTogbnVtYmVyIHtcbiAgcmV0dXJuIGluaXRpYWxEZWxheU1zICogMiAqKiAoYXR0ZW1wdCAtIDEpO1xufVxuXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gZmlnbWFSZXF1ZXN0PFREYXRhID0gdW5rbm93bj4oXG4gIG9wdGlvbnM6IEZpZ21hUmVxdWVzdE9wdGlvbnNcbik6IFByb21pc2U8RmlnbWFSZXNwb25zZTxURGF0YT4+IHtcbiAgY29uc3Qge1xuICAgIHBhdGgsXG4gICAgbWV0aG9kID0gJ0dFVCcsXG4gICAgdG9rZW4sXG4gICAgaGVhZGVycyA9IHt9LFxuICAgIGJvZHksXG4gICAgc2VhcmNoUGFyYW1zLFxuICAgIG1heEF0dGVtcHRzID0gY29uZmlnLmh0dHA/Lm1heEF0dGVtcHRzID8/IDUsXG4gICAgaW5pdGlhbERlbGF5TXMgPSBjb25maWcuaHR0cD8uaW5pdGlhbERlbGF5TXMgPz8gMjUwLFxuICB9ID0gb3B0aW9ucztcblxuICBpZiAoIXRva2VuKSB7XG4gICAgcmV0dXJuIHtcbiAgICAgIG9rOiBmYWxzZSxcbiAgICAgIGVycm9yOiBjcmVhdGVFcnJvcignRklHTUFfQVVUSCcsICdGSUdNQV9BQ0NFU1NfVE9LRU4gaXMgbWlzc2luZyBmcm9tIHRoZSBlbnZpcm9ubWVudC4nKSxcbiAgICAgIHN0YXR1czogbnVsbCxcbiAgICAgIHJhdGVMaW1pdDogbnVsbCxcbiAgICB9O1xuICB9XG5cbiAgY29uc3QgdXJsID0gbmV3IFVSTChwYXRoLCBCQVNFX1VSTCk7XG5cbiAgaWYgKHNlYXJjaFBhcmFtcykge1xuICAgIE9iamVjdC5lbnRyaWVzKHNlYXJjaFBhcmFtcykuZm9yRWFjaCgoW2tleSwgdmFsdWVdKSA9PiB7XG4gICAgICBpZiAodmFsdWUgPT09IHVuZGVmaW5lZCB8fCB2YWx1ZSA9PT0gbnVsbCkgcmV0dXJuO1xuICAgICAgdXJsLnNlYXJjaFBhcmFtcy5hcHBlbmQoa2V5LCBTdHJpbmcodmFsdWUpKTtcbiAgICB9KTtcbiAgfVxuXG4gIGxldCBhdHRlbXB0ID0gMDtcbiAgbGV0IGxhc3RXYWl0TXMgPSAwO1xuXG4gIHdoaWxlIChhdHRlbXB0IDwgbWF4QXR0ZW1wdHMpIHtcbiAgICBhdHRlbXB0ICs9IDE7XG5cbiAgICBjb25zdCByZXNwb25zZSA9IGF3YWl0IGZldGNoKHVybCwge1xuICAgICAgbWV0aG9kLFxuICAgICAgaGVhZGVyczoge1xuICAgICAgICAnQ29udGVudC1UeXBlJzogJ2FwcGxpY2F0aW9uL2pzb24nLFxuICAgICAgICAnWC1GaWdtYS1Ub2tlbic6IHRva2VuLFxuICAgICAgICAuLi5oZWFkZXJzLFxuICAgICAgfSxcbiAgICAgIGJvZHk6IGJvZHkgPyBKU09OLnN0cmluZ2lmeShib2R5KSA6IHVuZGVmaW5lZCxcbiAgICB9KTtcblxuICAgIGNvbnN0IHRleHQgPSBhd2FpdCByZXNwb25zZS50ZXh0KCk7XG4gICAgY29uc3QgcGF5bG9hZCA9IHBhcnNlSnNvblNhZmVseSh0ZXh0KSBhcyB7IG1lc3NhZ2U/OiBzdHJpbmcgfTtcbiAgICBjb25zdCByYXRlTGltaXQgPSBwYXJzZVJhdGVMaW1pdChyZXNwb25zZS5oZWFkZXJzLCBhdHRlbXB0LCBsYXN0V2FpdE1zKTtcblxuICAgIGlmIChyZXNwb25zZS5vaykge1xuICAgICAgcmV0dXJuIHsgb2s6IHRydWUsIGRhdGE6IHBheWxvYWQgYXMgVERhdGEsIHJhdGVMaW1pdCB9O1xuICAgIH1cblxuICAgIGNvbnN0IHN0YXR1cyA9IHJlc3BvbnNlLnN0YXR1cztcblxuICAgIGlmIChzdGF0dXMgPT09IDQwMSB8fCBzdGF0dXMgPT09IDQwMykge1xuICAgICAgcmV0dXJuIHsgb2s6IGZhbHNlLCBlcnJvcjogY3JlYXRlRXJyb3IoJ0ZJR01BX0FVVEgnLCBwYXlsb2FkPy5tZXNzYWdlID8/ICdGaWdtYSB0b2tlbiBpcyB1bmF1dGhvcml6ZWQuJywgeyBzdGF0dXMgfSksIHN0YXR1cywgcmF0ZUxpbWl0IH07XG4gICAgfVxuXG4gICAgaWYgKHN0YXR1cyA9PT0gNDA0KSB7XG4gICAgICByZXR1cm4geyBvazogZmFsc2UsIGVycm9yOiBjcmVhdGVFcnJvcignRklHTUFfTk9UX0ZPVU5EJywgcGF5bG9hZD8ubWVzc2FnZSA/PyAnUmVzb3VyY2Ugbm90IGZvdW5kLicsIHsgc3RhdHVzIH0pLCBzdGF0dXMsIHJhdGVMaW1pdCB9O1xuICAgIH1cblxuICAgIGlmIChzdGF0dXMgPT09IDQyOSB8fCBzdGF0dXMgPj0gNTAwKSB7XG4gICAgICBpZiAoYXR0ZW1wdCA+PSBtYXhBdHRlbXB0cykge1xuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgIG9rOiBmYWxzZSxcbiAgICAgICAgICBlcnJvcjogY3JlYXRlRXJyb3Ioc3RhdHVzID09PSA0MjkgPyAnRklHTUFfUkFURV9MSU1JVCcgOiAnTkVUV09SSycsIHBheWxvYWQ/Lm1lc3NhZ2UgPz8gJ0ZpZ21hIHJlcXVlc3QgZmFpbGVkIGFmdGVyIG1heGltdW0gcmV0cmllcy4nLCB7IHN0YXR1cyB9KSxcbiAgICAgICAgICBzdGF0dXMsXG4gICAgICAgICAgcmF0ZUxpbWl0LFxuICAgICAgICB9O1xuICAgICAgfVxuXG4gICAgICBsZXQgd2FpdE1zID0gY29tcHV0ZUJhY2tvZmZNcyhhdHRlbXB0LCBpbml0aWFsRGVsYXlNcyk7XG4gICAgICBjb25zdCByZXNldEhlYWRlciA9IHJlc3BvbnNlLmhlYWRlcnMuZ2V0KCd4LXJhdGVsaW1pdC1yZXNldCcpO1xuICAgICAgaWYgKHJlc2V0SGVhZGVyKSB7XG4gICAgICAgIGNvbnN0IGFzTnVtYmVyID0gTnVtYmVyKHJlc2V0SGVhZGVyKTtcbiAgICAgICAgaWYgKCFOdW1iZXIuaXNOYU4oYXNOdW1iZXIpKSB7XG4gICAgICAgICAgY29uc3QgcmVzZXRNcyA9IGFzTnVtYmVyICogMTAwMDtcbiAgICAgICAgICBjb25zdCBkZWx0YSA9IHJlc2V0TXMgLSBEYXRlLm5vdygpO1xuICAgICAgICAgIGlmIChkZWx0YSA+IDApIHdhaXRNcyA9IE1hdGgubWF4KHdhaXRNcywgZGVsdGEpO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IGppdHRlciA9IE1hdGguZmxvb3IoTWF0aC5yYW5kb20oKSAqIDEwMCk7XG4gICAgICBsYXN0V2FpdE1zID0gd2FpdE1zICsgaml0dGVyO1xuICAgICAgYXdhaXQgc2xlZXAobGFzdFdhaXRNcyk7XG4gICAgICBjb250aW51ZTtcbiAgICB9XG5cbiAgICByZXR1cm4geyBvazogZmFsc2UsIGVycm9yOiBjcmVhdGVFcnJvcignSU5URVJOQUwnLCBwYXlsb2FkPy5tZXNzYWdlID8/ICdVbmV4cGVjdGVkIGVycm9yIGZyb20gRmlnbWEgQVBJLicsIHsgc3RhdHVzIH0pLCBzdGF0dXMsIHJhdGVMaW1pdCB9O1xuICB9XG5cbiAgcmV0dXJuIHtcbiAgICBvazogZmFsc2UsXG4gICAgZXJyb3I6IGNyZWF0ZUVycm9yKCdORVRXT1JLJywgJ1VuYWJsZSB0byByZWFjaCBGaWdtYSBBUEkuJyksXG4gICAgc3RhdHVzOiBudWxsLFxuICAgIHJhdGVMaW1pdDogeyByZW1haW5pbmc6IG51bGwsIHJlc2V0QXQ6IG51bGwsIGF0dGVtcHRzOiBtYXhBdHRlbXB0cywgbGFzdFdhaXRNcyB9LFxuICB9O1xufVxuXG4iLCAiIyEvdXNyL2Jpbi9lbnYgbm9kZVxuXG5pbXBvcnQgeyBwYXJzZUFyZ3MsIHR5cGUgQ2xpQXJncyB9IGZyb20gJy4vX3V0aWxzL2NsaS1hcmdzLnRzJ1xuaW1wb3J0IHsgcGFyc2VGaWdtYVVybCwgZW5zdXJlTm9kZUlkIH0gZnJvbSAnLi9fdXRpbHMvdXJsLXBhcnNlLnRzJ1xuaW1wb3J0IHsgY3JlYXRlRW52ZWxvcGUsIHR5cGUgVG9vbEVudmVsb3BlIH0gZnJvbSAnLi9fdXRpbHMvZW52ZWxvcGUudHMnXG5pbXBvcnQgeyBjcmVhdGVFcnJvciwgZ2V0RXhpdENvZGUsIHR5cGUgVG9vbEVycm9yIH0gZnJvbSAnLi9fdXRpbHMvZXJyb3JzLnRzJ1xuaW1wb3J0IHsgZmlnbWFSZXF1ZXN0IH0gZnJvbSAnLi9fdXRpbHMvaHR0cC1jbGllbnQudHMnXG5cbmNvbnN0IFRPT0xfTkFNRSA9ICdnZXQtbWV0YWRhdGEnXG50eXBlIEVtcHR5RGF0YSA9IFJlY29yZDxzdHJpbmcsIG5ldmVyPlxuXG5pbnRlcmZhY2UgVG9vbElucHV0IGV4dGVuZHMgUmVjb3JkPHN0cmluZywgdW5rbm93bj4ge1xuICBmaWxlS2V5OiBzdHJpbmcgfCBudWxsXG4gIG5vZGVJZDogc3RyaW5nIHwgbnVsbFxuICBmb3JtYXQ6IHN0cmluZ1xufVxuXG5pbnRlcmZhY2UgRmlnbWFOb2RlIHtcbiAgaWQ6IHN0cmluZ1xuICBuYW1lPzogc3RyaW5nXG4gIHR5cGU/OiBzdHJpbmdcbiAgdmlzaWJsZT86IGJvb2xlYW5cbiAgbG9ja2VkPzogYm9vbGVhblxuICBjaGFyYWN0ZXJzPzogc3RyaW5nXG4gIGJsZW5kTW9kZT86IHN0cmluZ1xuICBvcGFjaXR5PzogbnVtYmVyXG4gIGlzTWFzaz86IGJvb2xlYW5cbiAgcmVsYXRpdmVUcmFuc2Zvcm0/OiB1bmtub3duXG4gIGFic29sdXRlQm91bmRpbmdCb3g/OiB7IHg/OiBudW1iZXI7IHk/OiBudW1iZXI7IHdpZHRoPzogbnVtYmVyOyBoZWlnaHQ/OiBudW1iZXIgfVxuICBzaXplPzogdW5rbm93blxuICBmaWxscz86IHVua25vd25bXVxuICBzdHJva2VzPzogdW5rbm93bltdXG4gIHN0cm9rZVdlaWdodD86IG51bWJlclxuICBzdHJva2VBbGlnbj86IHN0cmluZ1xuICBlZmZlY3RzPzogdW5rbm93bltdXG4gIGNvbnN0cmFpbnRzPzogdW5rbm93blxuICBsYXlvdXRBbGlnbj86IHN0cmluZ1xuICBsYXlvdXRHcm93PzogbnVtYmVyXG4gIGxheW91dE1vZGU/OiBzdHJpbmdcbiAgcHJpbWFyeUF4aXNTaXppbmdNb2RlPzogc3RyaW5nXG4gIGNvdW50ZXJBeGlzU2l6aW5nTW9kZT86IHN0cmluZ1xuICBwcmltYXJ5QXhpc0FsaWduSXRlbXM/OiBzdHJpbmdcbiAgY291bnRlckF4aXNBbGlnbkl0ZW1zPzogc3RyaW5nXG4gIGl0ZW1TcGFjaW5nPzogbnVtYmVyXG4gIHBhZGRpbmdMZWZ0PzogbnVtYmVyXG4gIHBhZGRpbmdSaWdodD86IG51bWJlclxuICBwYWRkaW5nVG9wPzogbnVtYmVyXG4gIHBhZGRpbmdCb3R0b20/OiBudW1iZXJcbiAgY2xpcHNDb250ZW50PzogYm9vbGVhblxuICBsYXlvdXRHcmlkcz86IHVua25vd25bXVxuICBleHBvcnRTZXR0aW5ncz86IHVua25vd25bXVxuICB0cmFuc2l0aW9uTm9kZUlEPzogc3RyaW5nXG4gIG92ZXJsYXlQb3NpdGlvblR5cGU/OiBzdHJpbmdcbiAgb3ZlcmxheVJlbGF0aXZlUG9zaXRpb24/OiB1bmtub3duXG4gIGNoaWxkcmVuPzogRmlnbWFOb2RlW11cbn1cblxuaW50ZXJmYWNlIE5vZGVzUmVzcG9uc2VQYXlsb2FkIHtcbiAgbmFtZT86IHN0cmluZ1xuICBsYXN0TW9kaWZpZWQ/OiBzdHJpbmdcbiAgbm9kZXM/OiBSZWNvcmQ8c3RyaW5nLCB7IGRvY3VtZW50PzogRmlnbWFOb2RlIH0+XG59XG5cbmludGVyZmFjZSBNZXRhZGF0YU5vZGUge1xuICBpZDogc3RyaW5nXG4gIG5hbWU/OiBzdHJpbmdcbiAgdHlwZT86IHN0cmluZ1xuICB2aXNpYmxlOiBib29sZWFuXG4gIGxvY2tlZDogYm9vbGVhblxuICBpbmRleDogbnVtYmVyXG4gIHBhcmVudElkOiBzdHJpbmcgfCBudWxsXG4gIGNoYXJhY3RlcnM6IHN0cmluZyB8IG51bGxcbiAgYmxlbmRNb2RlOiBzdHJpbmcgfCBudWxsXG4gIG9wYWNpdHk6IG51bWJlclxuICBpc01hc2s6IGJvb2xlYW5cbiAgcmVsYXRpdmVUcmFuc2Zvcm06IHVua25vd25cbiAgYWJzb2x1dGVCb3VuZGluZ0JveDogeyB4PzogbnVtYmVyOyB5PzogbnVtYmVyOyB3aWR0aD86IG51bWJlcjsgaGVpZ2h0PzogbnVtYmVyIH0gfCBudWxsXG4gIHNpemU6IHVua25vd25cbiAgZmlsbHM6IHVua25vd25bXVxuICBzdHJva2VzOiB1bmtub3duW11cbiAgc3Ryb2tlV2VpZ2h0OiBudW1iZXIgfCBudWxsXG4gIHN0cm9rZUFsaWduOiBzdHJpbmcgfCBudWxsXG4gIGVmZmVjdHM6IHVua25vd25bXVxuICBjb25zdHJhaW50czogdW5rbm93blxuICBsYXlvdXRBbGlnbjogc3RyaW5nIHwgbnVsbFxuICBsYXlvdXRHcm93OiBudW1iZXIgfCBudWxsXG4gIGxheW91dE1vZGU6IHN0cmluZyB8IG51bGxcbiAgcHJpbWFyeUF4aXNTaXppbmdNb2RlOiBzdHJpbmcgfCBudWxsXG4gIGNvdW50ZXJBeGlzU2l6aW5nTW9kZTogc3RyaW5nIHwgbnVsbFxuICBwcmltYXJ5QXhpc0FsaWduSXRlbXM6IHN0cmluZyB8IG51bGxcbiAgY291bnRlckF4aXNBbGlnbkl0ZW1zOiBzdHJpbmcgfCBudWxsXG4gIGl0ZW1TcGFjaW5nOiBudW1iZXIgfCBudWxsXG4gIHBhZGRpbmdMZWZ0OiBudW1iZXIgfCBudWxsXG4gIHBhZGRpbmdSaWdodDogbnVtYmVyIHwgbnVsbFxuICBwYWRkaW5nVG9wOiBudW1iZXIgfCBudWxsXG4gIHBhZGRpbmdCb3R0b206IG51bWJlciB8IG51bGxcbiAgY2xpcHNDb250ZW50OiBib29sZWFuXG4gIGxheW91dEdyaWRzOiB1bmtub3duW11cbiAgZXhwb3J0U2V0dGluZ3M6IHVua25vd25bXVxuICB0cmFuc2l0aW9uTm9kZUlEOiBzdHJpbmcgfCBudWxsXG4gIG92ZXJsYXlQb3NpdGlvblR5cGU6IHN0cmluZyB8IG51bGxcbiAgb3ZlcmxheVJlbGF0aXZlUG9zaXRpb246IHVua25vd25cbiAgY2hpbGRyZW46IE1ldGFkYXRhTm9kZVtdXG59XG5cbmludGVyZmFjZSBNZXRhZGF0YURhdGEge1xuICBmaWxlOiB7XG4gICAga2V5OiBzdHJpbmdcbiAgICBuYW1lOiBzdHJpbmcgfCBudWxsXG4gICAgbGFzdE1vZGlmaWVkOiBzdHJpbmcgfCBudWxsXG4gIH1cbiAgbWV0YWRhdGE6IE1ldGFkYXRhTm9kZVxuICB4bWw/OiBzdHJpbmdcbn1cblxuZnVuY3Rpb24gbG9nKG1lc3NhZ2U6IHN0cmluZywgdmVyYm9zZTogYm9vbGVhbik6IHZvaWQge1xuICBpZiAodmVyYm9zZSkge1xuICAgIHByb2Nlc3Muc3RkZXJyLndyaXRlKGBbJHtUT09MX05BTUV9XSAke21lc3NhZ2V9XFxuYClcbiAgfVxufVxuXG5mdW5jdGlvbiB0b09wdGlvbmFsU3RyaW5nKHZhbHVlOiBDbGlBcmdzW3N0cmluZ10pOiBzdHJpbmcgfCBudWxsIHtcbiAgcmV0dXJuIHR5cGVvZiB2YWx1ZSA9PT0gJ3N0cmluZycgJiYgdmFsdWUubGVuZ3RoID4gMCA/IHZhbHVlIDogbnVsbFxufVxuXG5mdW5jdGlvbiBleGl0V2l0aEVudmVsb3BlKFxuICBlbnZlbG9wZTogVG9vbEVudmVsb3BlPFRvb2xJbnB1dCwgTWV0YWRhdGFEYXRhIHwgRW1wdHlEYXRhPixcbiAgZXJyb3JzOiBUb29sRXJyb3JbXSA9IFtdXG4pOiBuZXZlciB7XG4gIHByb2Nlc3Muc3Rkb3V0LndyaXRlKGAke0pTT04uc3RyaW5naWZ5KGVudmVsb3BlLCBudWxsLCAyKX1cXG5gKVxuICBwcm9jZXNzLmV4aXQoZ2V0RXhpdENvZGUoZXJyb3JzKSlcbn1cblxuZnVuY3Rpb24gbWFwTm9kZShub2RlOiBGaWdtYU5vZGUsIGluZGV4ID0gMCwgcGFyZW50SWQ6IHN0cmluZyB8IG51bGwgPSBudWxsKTogTWV0YWRhdGFOb2RlIHtcbiAgY29uc3QgY2hpbGRyZW4gPSBBcnJheS5pc0FycmF5KG5vZGUuY2hpbGRyZW4pXG4gICAgPyBub2RlLmNoaWxkcmVuLm1hcCgoY2hpbGQsIGlkeCkgPT4gbWFwTm9kZShjaGlsZCwgaWR4LCBub2RlLmlkKSlcbiAgICA6IFtdXG5cbiAgcmV0dXJuIHtcbiAgICBpZDogbm9kZS5pZCxcbiAgICBuYW1lOiBub2RlLm5hbWUsXG4gICAgdHlwZTogbm9kZS50eXBlLFxuICAgIHZpc2libGU6IG5vZGUudmlzaWJsZSA/PyB0cnVlLFxuICAgIGxvY2tlZDogbm9kZS5sb2NrZWQgPz8gZmFsc2UsXG4gICAgaW5kZXgsXG4gICAgcGFyZW50SWQsXG4gICAgY2hhcmFjdGVyczogbm9kZS5jaGFyYWN0ZXJzID8/IG51bGwsXG4gICAgYmxlbmRNb2RlOiBub2RlLmJsZW5kTW9kZSA/PyBudWxsLFxuICAgIG9wYWNpdHk6IG5vZGUub3BhY2l0eSA/PyAxLFxuICAgIGlzTWFzazogbm9kZS5pc01hc2sgPz8gZmFsc2UsXG4gICAgcmVsYXRpdmVUcmFuc2Zvcm06IG5vZGUucmVsYXRpdmVUcmFuc2Zvcm0gPz8gbnVsbCxcbiAgICBhYnNvbHV0ZUJvdW5kaW5nQm94OiBub2RlLmFic29sdXRlQm91bmRpbmdCb3ggPz8gbnVsbCxcbiAgICBzaXplOiBub2RlLnNpemUgPz8gbnVsbCxcbiAgICBmaWxsczogbm9kZS5maWxscyA/PyBbXSxcbiAgICBzdHJva2VzOiBub2RlLnN0cm9rZXMgPz8gW10sXG4gICAgc3Ryb2tlV2VpZ2h0OiBub2RlLnN0cm9rZVdlaWdodCA/PyBudWxsLFxuICAgIHN0cm9rZUFsaWduOiBub2RlLnN0cm9rZUFsaWduID8/IG51bGwsXG4gICAgZWZmZWN0czogbm9kZS5lZmZlY3RzID8/IFtdLFxuICAgIGNvbnN0cmFpbnRzOiBub2RlLmNvbnN0cmFpbnRzID8/IG51bGwsXG4gICAgbGF5b3V0QWxpZ246IG5vZGUubGF5b3V0QWxpZ24gPz8gbnVsbCxcbiAgICBsYXlvdXRHcm93OiBub2RlLmxheW91dEdyb3cgPz8gbnVsbCxcbiAgICBsYXlvdXRNb2RlOiBub2RlLmxheW91dE1vZGUgPz8gbnVsbCxcbiAgICBwcmltYXJ5QXhpc1NpemluZ01vZGU6IG5vZGUucHJpbWFyeUF4aXNTaXppbmdNb2RlID8/IG51bGwsXG4gICAgY291bnRlckF4aXNTaXppbmdNb2RlOiBub2RlLmNvdW50ZXJBeGlzU2l6aW5nTW9kZSA/PyBudWxsLFxuICAgIHByaW1hcnlBeGlzQWxpZ25JdGVtczogbm9kZS5wcmltYXJ5QXhpc0FsaWduSXRlbXMgPz8gbnVsbCxcbiAgICBjb3VudGVyQXhpc0FsaWduSXRlbXM6IG5vZGUuY291bnRlckF4aXNBbGlnbkl0ZW1zID8/IG51bGwsXG4gICAgaXRlbVNwYWNpbmc6IG5vZGUuaXRlbVNwYWNpbmcgPz8gbnVsbCxcbiAgICBwYWRkaW5nTGVmdDogbm9kZS5wYWRkaW5nTGVmdCA/PyBudWxsLFxuICAgIHBhZGRpbmdSaWdodDogbm9kZS5wYWRkaW5nUmlnaHQgPz8gbnVsbCxcbiAgICBwYWRkaW5nVG9wOiBub2RlLnBhZGRpbmdUb3AgPz8gbnVsbCxcbiAgICBwYWRkaW5nQm90dG9tOiBub2RlLnBhZGRpbmdCb3R0b20gPz8gbnVsbCxcbiAgICBjbGlwc0NvbnRlbnQ6IG5vZGUuY2xpcHNDb250ZW50ID8/IGZhbHNlLFxuICAgIGxheW91dEdyaWRzOiBub2RlLmxheW91dEdyaWRzID8/IFtdLFxuICAgIGV4cG9ydFNldHRpbmdzOiBub2RlLmV4cG9ydFNldHRpbmdzID8/IFtdLFxuICAgIHRyYW5zaXRpb25Ob2RlSUQ6IG5vZGUudHJhbnNpdGlvbk5vZGVJRCA/PyBudWxsLFxuICAgIG92ZXJsYXlQb3NpdGlvblR5cGU6IG5vZGUub3ZlcmxheVBvc2l0aW9uVHlwZSA/PyBudWxsLFxuICAgIG92ZXJsYXlSZWxhdGl2ZVBvc2l0aW9uOiBub2RlLm92ZXJsYXlSZWxhdGl2ZVBvc2l0aW9uID8/IG51bGwsXG4gICAgY2hpbGRyZW4sXG4gIH1cbn1cblxuZnVuY3Rpb24gZXNjYXBlWG1sKHZhbHVlOiBzdHJpbmcpOiBzdHJpbmcge1xuICByZXR1cm4gdmFsdWVcbiAgICAucmVwbGFjZSgvJi9nLCAnJmFtcDsnKVxuICAgIC5yZXBsYWNlKC88L2csICcmbHQ7JylcbiAgICAucmVwbGFjZSgvPi9nLCAnJmd0OycpXG4gICAgLnJlcGxhY2UoL1xcXCIvZywgJyZxdW90OycpXG4gICAgLnJlcGxhY2UoLycvZywgJyZhcG9zOycpXG59XG5cbmZ1bmN0aW9uIG5vZGVUb1htbChub2RlOiBNZXRhZGF0YU5vZGUpOiBzdHJpbmcge1xuICBjb25zdCBhdHRycyA9IFtcbiAgICBgaWQ9XFxcIiR7ZXNjYXBlWG1sKG5vZGUuaWQpfVxcXCJgLFxuICAgIG5vZGUudHlwZSA/IGB0eXBlPVxcXCIke2VzY2FwZVhtbChub2RlLnR5cGUpfVxcXCJgIDogbnVsbCxcbiAgICBub2RlLm5hbWUgPyBgbmFtZT1cXFwiJHtlc2NhcGVYbWwobm9kZS5uYW1lKX1cXFwiYCA6IG51bGwsXG4gICAgbm9kZS52aXNpYmxlID09PSBmYWxzZSA/ICd2aXNpYmxlPVxcXCJmYWxzZVxcXCInIDogbnVsbCxcbiAgICBub2RlLmxvY2tlZCA/ICdsb2NrZWQ9XFxcInRydWVcXFwiJyA6IG51bGwsXG4gICAgbm9kZS5wYXJlbnRJZCA/IGBwYXJlbnRJZD1cXFwiJHtlc2NhcGVYbWwobm9kZS5wYXJlbnRJZCl9XFxcImAgOiBudWxsLFxuICAgIG5vZGUuYWJzb2x1dGVCb3VuZGluZ0JveFxuICAgICAgPyBgeD1cXFwiJHtub2RlLmFic29sdXRlQm91bmRpbmdCb3gueCA/PyAwfVxcXCIgeT1cXFwiJHtub2RlLmFic29sdXRlQm91bmRpbmdCb3gueSA/PyAwfVxcXCIgd2lkdGg9XFxcIiR7bm9kZS5hYnNvbHV0ZUJvdW5kaW5nQm94LndpZHRoID8/IDB9XFxcIiBoZWlnaHQ9XFxcIiR7bm9kZS5hYnNvbHV0ZUJvdW5kaW5nQm94LmhlaWdodCA/PyAwfVxcXCJgXG4gICAgICA6IG51bGwsXG4gIF0uZmlsdGVyKEJvb2xlYW4pXG5cbiAgY29uc3QgY2hpbGRYbWwgPSBub2RlLmNoaWxkcmVuLm1hcChub2RlVG9YbWwpLmpvaW4oJycpXG4gIHJldHVybiBgPG5vZGUgJHthdHRycy5qb2luKCcgJyl9PiR7Y2hpbGRYbWx9PC9ub2RlPmBcbn1cblxuYXN5bmMgZnVuY3Rpb24gbWFpbigpOiBQcm9taXNlPHZvaWQ+IHtcbiAgY29uc3QgYXJncyA9IHBhcnNlQXJncygpXG4gIGNvbnN0IHZlcmJvc2UgPSBCb29sZWFuKGFyZ3MudmVyYm9zZSA/PyBhcmdzLnYpXG4gIGNvbnN0IHNjaGVtYVZlcnNpb24gPSB0b09wdGlvbmFsU3RyaW5nKGFyZ3NbJ3NjaGVtYS12ZXJzaW9uJ10pID8/IHVuZGVmaW5lZFxuXG4gIGNvbnN0IHdhcm5pbmdzOiBzdHJpbmdbXSA9IFtdXG4gIGNvbnN0IGVycm9yczogVG9vbEVycm9yW10gPSBbXVxuXG4gIGNvbnN0IHRva2VuID0gcHJvY2Vzcy5lbnYuRklHTUFfQUNDRVNTX1RPS0VOXG5cbiAgaWYgKCF0b2tlbiB8fCAhdG9rZW4udHJpbSgpKSB7XG4gICAgZXJyb3JzLnB1c2goY3JlYXRlRXJyb3IoJ0ZJR01BX0FVVEgnLCAnRklHTUFfQUNDRVNTX1RPS0VOIGlzIHJlcXVpcmVkIGJ1dCB3YXMgbm90IHByb3ZpZGVkLicpKVxuICAgIGNvbnN0IGVudmVsb3BlID0gY3JlYXRlRW52ZWxvcGU8VG9vbElucHV0LCBFbXB0eURhdGE+KHtcbiAgICAgIHRvb2w6IFRPT0xfTkFNRSxcbiAgICAgIGlucHV0OiB7IGZpbGVLZXk6IG51bGwsIG5vZGVJZDogbnVsbCwgZm9ybWF0OiAnanNvbicgfSxcbiAgICAgIHdhcm5pbmdzLFxuICAgICAgZXJyb3JzLFxuICAgICAgc2NoZW1hVmVyc2lvbixcbiAgICAgIGRhdGE6IHt9IGFzIEVtcHR5RGF0YSxcbiAgICB9KVxuICAgIGV4aXRXaXRoRW52ZWxvcGUoZW52ZWxvcGUsIGVycm9ycylcbiAgfVxuXG4gIGNvbnN0IHVybElucHV0ID0gdG9PcHRpb25hbFN0cmluZyhhcmdzLnVybCkgPz8gdG9PcHRpb25hbFN0cmluZyhhcmdzLnUpXG4gIGxldCBmaWxlS2V5ID0gdG9PcHRpb25hbFN0cmluZyhhcmdzWydmaWxlLWtleSddKSA/PyB1bmRlZmluZWRcbiAgbGV0IG5vZGVJZCA9IGVuc3VyZU5vZGVJZCh0b09wdGlvbmFsU3RyaW5nKGFyZ3NbJ25vZGUtaWQnXSkpXG5cbiAgaWYgKHVybElucHV0KSB7XG4gICAgY29uc3QgcGFyc2VkID0gcGFyc2VGaWdtYVVybCh1cmxJbnB1dClcbiAgICBmaWxlS2V5ID0gZmlsZUtleSB8fCBwYXJzZWQuZmlsZUtleSB8fCB1bmRlZmluZWRcbiAgICBub2RlSWQgPSBub2RlSWQgfHwgcGFyc2VkLm5vZGVJZFxuICB9XG5cbiAgbGV0IGZvcm1hdCA9IFN0cmluZyhhcmdzLmZvcm1hdCA/PyAnanNvbicpLnRvTG93ZXJDYXNlKClcbiAgbGV0IG91dHB1dE1vZGU6ICdqc29uJyB8ICd4bWwnIHwgJ2JvdGgnXG4gIGlmIChmb3JtYXQgPT09ICdqc29uJyB8fCBmb3JtYXQgPT09ICd4bWwnIHx8IGZvcm1hdCA9PT0gJ2JvdGgnKSB7XG4gICAgb3V0cHV0TW9kZSA9IGZvcm1hdCBhcyAnanNvbicgfCAneG1sJyB8ICdib3RoJ1xuICB9IGVsc2Uge1xuICAgIHdhcm5pbmdzLnB1c2goYFVua25vd24gZm9ybWF0IFxcXCIke2Zvcm1hdH1cXFwiLiBEZWZhdWx0aW5nIHRvIGpzb24uYClcbiAgICBvdXRwdXRNb2RlID0gJ2pzb24nXG4gIH1cblxuICBjb25zdCBpbnB1dDogVG9vbElucHV0ID0ge1xuICAgIGZpbGVLZXk6IGZpbGVLZXkgPz8gbnVsbCxcbiAgICBub2RlSWQ6IG5vZGVJZCA/PyBudWxsLFxuICAgIGZvcm1hdDogb3V0cHV0TW9kZSxcbiAgfVxuXG4gIGlmICghZmlsZUtleSkge1xuICAgIGVycm9ycy5wdXNoKGNyZWF0ZUVycm9yKCdJTlBVVF9JTlZBTElEJywgJ0EgdmFsaWQgRmlnbWEgZmlsZSBrZXkgaXMgcmVxdWlyZWQgKC0tZmlsZS1rZXkgb3IgLS11cmwpLicpKVxuICB9XG5cbiAgaWYgKCFub2RlSWQpIHtcbiAgICBlcnJvcnMucHVzaChjcmVhdGVFcnJvcignSU5QVVRfSU5WQUxJRCcsICdBIHZhbGlkIEZpZ21hIG5vZGUgaWQgaXMgcmVxdWlyZWQgKC0tbm9kZS1pZCBvciAtLXVybCB3aXRoIG5vZGUtaWQpLicpKVxuICB9XG5cbiAgaWYgKGVycm9ycy5sZW5ndGgpIHtcbiAgICBjb25zdCBlbnZlbG9wZSA9IGNyZWF0ZUVudmVsb3BlPFRvb2xJbnB1dCwgRW1wdHlEYXRhPih7XG4gICAgICB0b29sOiBUT09MX05BTUUsXG4gICAgICBpbnB1dCxcbiAgICAgIHdhcm5pbmdzLFxuICAgICAgZXJyb3JzLFxuICAgICAgZGF0YToge30gYXMgRW1wdHlEYXRhLFxuICAgICAgc2NoZW1hVmVyc2lvbixcbiAgICB9KVxuICAgIGV4aXRXaXRoRW52ZWxvcGUoZW52ZWxvcGUsIGVycm9ycylcbiAgfVxuXG4gIGNvbnN0IHJlc29sdmVkRmlsZUtleSA9IGZpbGVLZXkgYXMgc3RyaW5nXG4gIGNvbnN0IHJlc29sdmVkTm9kZUlkID0gbm9kZUlkIGFzIHN0cmluZ1xuXG4gIGxvZyhgRmV0Y2hpbmcgbWV0YWRhdGEgZm9yIG5vZGUgJHtyZXNvbHZlZE5vZGVJZH0gaW4gZmlsZSAke3Jlc29sdmVkRmlsZUtleX1gLCB2ZXJib3NlKVxuXG4gIGNvbnN0IG5vZGVSZXNwb25zZSA9IGF3YWl0IGZpZ21hUmVxdWVzdDxOb2Rlc1Jlc3BvbnNlUGF5bG9hZD4oe1xuICAgIHBhdGg6IGAvdjEvZmlsZXMvJHtyZXNvbHZlZEZpbGVLZXl9L25vZGVzYCxcbiAgICB0b2tlbixcbiAgICBzZWFyY2hQYXJhbXM6IHsgaWRzOiByZXNvbHZlZE5vZGVJZCB9LFxuICB9KVxuXG4gIGlmICghbm9kZVJlc3BvbnNlLm9rKSB7XG4gICAgZXJyb3JzLnB1c2gobm9kZVJlc3BvbnNlLmVycm9yID8/IGNyZWF0ZUVycm9yKCdJTlRFUk5BTCcsICdGYWlsZWQgdG8gZmV0Y2ggbm9kZSBtZXRhZGF0YS4nKSlcbiAgICBjb25zdCBlbnZlbG9wZSA9IGNyZWF0ZUVudmVsb3BlPFRvb2xJbnB1dCwgRW1wdHlEYXRhPih7XG4gICAgICB0b29sOiBUT09MX05BTUUsXG4gICAgICBpbnB1dCxcbiAgICAgIHdhcm5pbmdzLFxuICAgICAgZXJyb3JzLFxuICAgICAgcmF0ZUxpbWl0OiBub2RlUmVzcG9uc2UucmF0ZUxpbWl0ID8/IHVuZGVmaW5lZCxcbiAgICAgIGRhdGE6IHt9IGFzIEVtcHR5RGF0YSxcbiAgICAgIHNjaGVtYVZlcnNpb24sXG4gICAgfSlcbiAgICBleGl0V2l0aEVudmVsb3BlKGVudmVsb3BlLCBlcnJvcnMpXG4gIH1cblxuICBjb25zdCBub2Rlc01hcCA9IG5vZGVSZXNwb25zZS5kYXRhPy5ub2RlcyA/PyB7fVxuICBjb25zdCBub2RlV3JhcHBlciA9IG5vZGVzTWFwW3Jlc29sdmVkTm9kZUlkXVxuXG4gIGlmICghbm9kZVdyYXBwZXIgfHwgIW5vZGVXcmFwcGVyLmRvY3VtZW50KSB7XG4gICAgZXJyb3JzLnB1c2goY3JlYXRlRXJyb3IoJ0ZJR01BX05PVF9GT1VORCcsIGBOb2RlICR7cmVzb2x2ZWROb2RlSWR9IHdhcyBub3QgZm91bmQgaW4gZmlsZSAke3Jlc29sdmVkRmlsZUtleX0uYCkpXG4gICAgY29uc3QgZW52ZWxvcGUgPSBjcmVhdGVFbnZlbG9wZTxUb29sSW5wdXQsIEVtcHR5RGF0YT4oe1xuICAgICAgdG9vbDogVE9PTF9OQU1FLFxuICAgICAgaW5wdXQsXG4gICAgICB3YXJuaW5ncyxcbiAgICAgIGVycm9ycyxcbiAgICAgIHJhdGVMaW1pdDogbm9kZVJlc3BvbnNlLnJhdGVMaW1pdCA/PyB1bmRlZmluZWQsXG4gICAgICBkYXRhOiB7fSBhcyBFbXB0eURhdGEsXG4gICAgICBzY2hlbWFWZXJzaW9uLFxuICAgIH0pXG4gICAgZXhpdFdpdGhFbnZlbG9wZShlbnZlbG9wZSwgZXJyb3JzKVxuICB9XG5cbiAgY29uc3Qgcm9vdE5vZGUgPSBub2RlV3JhcHBlci5kb2N1bWVudFxuICBjb25zdCBtZXRhZGF0YVRyZWUgPSBtYXBOb2RlKHJvb3ROb2RlKVxuXG4gIGxldCB4bWxEb2N1bWVudDogc3RyaW5nIHwgdW5kZWZpbmVkXG4gIGlmIChvdXRwdXRNb2RlID09PSAneG1sJyB8fCBvdXRwdXRNb2RlID09PSAnYm90aCcpIHtcbiAgICB4bWxEb2N1bWVudCA9IGA8ZmlnbWFNZXRhZGF0YSB2ZXJzaW9uPVxcXCIxLjBcXFwiPiR7bm9kZVRvWG1sKG1ldGFkYXRhVHJlZSl9PC9maWdtYU1ldGFkYXRhPmBcbiAgfVxuXG4gIGNvbnN0IGRhdGE6IE1ldGFkYXRhRGF0YSA9IHtcbiAgICBmaWxlOiB7XG4gICAgICBrZXk6IHJlc29sdmVkRmlsZUtleSxcbiAgICAgIG5hbWU6IG5vZGVSZXNwb25zZS5kYXRhPy5uYW1lID8/IG51bGwsXG4gICAgICBsYXN0TW9kaWZpZWQ6IG5vZGVSZXNwb25zZS5kYXRhPy5sYXN0TW9kaWZpZWQgPz8gbnVsbCxcbiAgICB9LFxuICAgIG1ldGFkYXRhOiBtZXRhZGF0YVRyZWUsXG4gICAgeG1sOiB4bWxEb2N1bWVudCxcbiAgfVxuXG4gIGNvbnN0IGVudmVsb3BlID0gY3JlYXRlRW52ZWxvcGU8VG9vbElucHV0LCBNZXRhZGF0YURhdGE+KHtcbiAgICB0b29sOiBUT09MX05BTUUsXG4gICAgaW5wdXQsXG4gICAgZGF0YSxcbiAgICB3YXJuaW5ncyxcbiAgICBlcnJvcnMsXG4gICAgcmF0ZUxpbWl0OiBub2RlUmVzcG9uc2UucmF0ZUxpbWl0ID8/IHVuZGVmaW5lZCxcbiAgICBzY2hlbWFWZXJzaW9uLFxuICB9KVxuXG4gIHByb2Nlc3Muc3Rkb3V0LndyaXRlKGAke0pTT04uc3RyaW5naWZ5KGVudmVsb3BlLCBudWxsLCAyKX1cXG5gKVxuICBwcm9jZXNzLmV4aXQoZ2V0RXhpdENvZGUoZXJyb3JzKSlcbn1cblxubWFpbigpLmNhdGNoKChlcnJvcjogdW5rbm93bikgPT4ge1xuICBjb25zdCBtZXNzYWdlID0gZXJyb3IgaW5zdGFuY2VvZiBFcnJvciA/IGVycm9yLm1lc3NhZ2UgOiAnVW5rbm93biBlcnJvcidcbiAgY29uc3QgZW52ZWxvcGUgPSBjcmVhdGVFbnZlbG9wZTxUb29sSW5wdXQsIEVtcHR5RGF0YT4oe1xuICAgIHRvb2w6IFRPT0xfTkFNRSxcbiAgICBpbnB1dDogeyBmaWxlS2V5OiBudWxsLCBub2RlSWQ6IG51bGwsIGZvcm1hdDogJ2pzb24nIH0sXG4gICAgZXJyb3JzOiBbY3JlYXRlRXJyb3IoJ0lOVEVSTkFMJywgbWVzc2FnZSwgeyBzdGFjazogZXJyb3IgaW5zdGFuY2VvZiBFcnJvciA/IGVycm9yLnN0YWNrIDogdW5kZWZpbmVkIH0pXSxcbiAgICBkYXRhOiB7fSBhcyBFbXB0eURhdGEsXG4gIH0pXG4gIHByb2Nlc3Muc3Rkb3V0LndyaXRlKGAke0pTT04uc3RyaW5naWZ5KGVudmVsb3BlLCBudWxsLCAyKX1cXG5gKVxuICBwcm9jZXNzLmV4aXQoMylcbn0pXG5cbiJdLAogICJtYXBwaW5ncyI6ICI7OztBQU9PLFNBQVMsVUFBVSxPQUFpQixRQUFRLEtBQUssTUFBTSxDQUFDLEdBQVk7QUFDekUsUUFBTSxPQUFnQixFQUFFLEdBQUcsQ0FBQyxFQUFFO0FBRTlCLFdBQVMsSUFBSSxHQUFHLElBQUksS0FBSyxRQUFRLEtBQUssR0FBRztBQUN2QyxVQUFNLE1BQU0sS0FBSyxDQUFDO0FBRWxCLFFBQUksQ0FBQyxJQUFJLFdBQVcsR0FBRyxLQUFLLFFBQVEsS0FBSztBQUN2QyxXQUFLLEVBQUUsS0FBSyxHQUFHO0FBQ2Y7QUFBQSxJQUNGO0FBRUEsUUFBSSxRQUFRLE1BQU07QUFDaEIsWUFBTSxZQUFZLEtBQUssTUFBTSxJQUFJLENBQUM7QUFDbEMsV0FBSyxFQUFFLEtBQUssR0FBRyxTQUFTO0FBQ3hCO0FBQUEsSUFDRjtBQUVBLFVBQU0sQ0FBQyxRQUFRLFdBQVcsSUFBSSxJQUFJLE1BQU0sS0FBSyxDQUFDO0FBQzlDLFVBQU0sZ0JBQWdCLE9BQU8sUUFBUSxPQUFPLEVBQUU7QUFFOUMsUUFBSTtBQUNKLFFBQUksZ0JBQWdCLFFBQVc7QUFDN0IsY0FBUTtBQUFBLElBQ1YsT0FBTztBQUNMLFlBQU0sT0FBTyxLQUFLLElBQUksQ0FBQztBQUN2QixVQUFJLFNBQVMsVUFBYSxDQUFDLEtBQUssV0FBVyxHQUFHLEdBQUc7QUFDL0MsZ0JBQVE7QUFDUixhQUFLO0FBQUEsTUFDUCxPQUFPO0FBQ0wsZ0JBQVE7QUFBQSxNQUNWO0FBQUEsSUFDRjtBQUVBLFNBQUssYUFBYSxJQUFJO0FBQUEsRUFDeEI7QUFFQSxTQUFPO0FBQ1Q7OztBQzVDQSxJQUFNLGlCQUFpQjtBQU9oQixTQUFTLGNBQWMsT0FBa0Q7QUFDOUUsTUFBSSxDQUFDLE1BQU8sUUFB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 diff --git a/use-figma/scripts/get-screenshot.mjs b/use-figma/scripts/get-screenshot.mjs new file mode 100755 index 0000000..ae014b4 --- /dev/null +++ b/use-figma/scripts/get-screenshot.mjs @@ -0,0 +1,387 @@ +#!/usr/bin/env node + +// coding-tools/figma-tools/js/src/get-screenshot.ts +import { mkdir, writeFile } from "node:fs/promises"; +import path from "node:path"; + +// coding-tools/figma-tools/js/src/_utils/cli-args.ts +function parseArgs(argv = process.argv.slice(2)) { + const args = { _: [] }; + for (let i = 0; i < argv.length; i += 1) { + const arg = argv[i]; + if (!arg.startsWith("-") || arg === "-") { + args._.push(arg); + continue; + } + if (arg === "--") { + const remaining = argv.slice(i + 1); + args._.push(...remaining); + break; + } + const [rawKey, inlineValue] = arg.split("=", 2); + const normalisedKey = rawKey.replace(/^-+/, ""); + let value; + if (inlineValue !== void 0) { + value = inlineValue; + } else { + const next = argv[i + 1]; + if (next !== void 0 && !next.startsWith("-")) { + value = next; + i += 1; + } else { + value = true; + } + } + args[normalisedKey] = value; + } + return args; +} + +// coding-tools/figma-tools/js/src/_utils/url-parse.ts +var FILE_KEY_REGEX = /figma\.com\/(?:file|design)\/([A-Za-z0-9]+)\//i; +function parseFigmaUrl(input) { + if (!input) return { fileKey: null, nodeId: null }; + try { + const url = new URL(input); + const match = url.href.match(FILE_KEY_REGEX); + const fileKey = match ? match[1] : null; + const nodeParam = url.searchParams.get("node-id"); + const nodeId = nodeParam ? ensureNodeId(nodeParam) : null; + return { fileKey, nodeId }; + } catch { + return { fileKey: null, nodeId: null }; + } +} +function ensureNodeId(value) { + if (!value) return null; + const decoded = decodeURIComponent(value); + if (decoded.includes(":")) return decoded; + if (/^[0-9]+-[0-9]+$/.test(decoded)) { + const [left, right] = decoded.split("-", 2); + return `${left}:${right}`; + } + return decoded; +} + +// coding-tools/figma-tools/js/src/_utils/config.ts +var config_default = { + schemaVersion: "1.0.0", + source: "agentic-coding-templates/figma-tools", + http: { + maxAttempts: 5, + initialDelayMs: 250 + } +}; + +// coding-tools/figma-tools/js/src/_utils/envelope.ts +function buildRateLimitMeta(rateLimit = {}) { + return { + remaining: rateLimit.remaining ?? null, + resetAt: rateLimit.resetAt ?? null, + attempts: rateLimit.attempts ?? 1, + lastWaitMs: rateLimit.lastWaitMs ?? 0 + }; +} +function createEnvelope({ + tool, + input = {}, + data = {}, + warnings = [], + errors = [], + rateLimit, + schemaVersion +}) { + return { + schemaVersion: schemaVersion ?? config_default.schemaVersion, + tool, + input, + meta: { + generatedAt: (/* @__PURE__ */ new Date()).toISOString(), + source: config_default.source, + rateLimit: buildRateLimitMeta(rateLimit) + }, + data, + warnings, + errors + }; +} + +// coding-tools/figma-tools/js/src/_utils/errors.ts +var ERROR_EXIT_CODES = { + INPUT_INVALID: 1, + CONFIG_INVALID: 1, + FIGMA_AUTH: 1, + FIGMA_NOT_FOUND: 2, + FIGMA_RATE_LIMIT: 2, + NETWORK: 2, + INTERNAL: 3 +}; +function createError(code, message, detail) { + return { + code, + message, + detail: detail ?? null + }; +} +function getExitCode(errors = []) { + if (!errors.length) { + return 0; + } + return errors.reduce((max, error) => { + const exitCode = ERROR_EXIT_CODES[error.code] ?? 1; + return Math.max(max, exitCode); + }, 0); +} + +// coding-tools/figma-tools/js/src/_utils/http-client.ts +var BASE_URL = "https://api.figma.com"; +function sleep(ms) { + return new Promise((resolve) => setTimeout(resolve, ms)); +} +function parseJsonSafely(text) { + try { + return text ? JSON.parse(text) : {}; + } catch { + return { raw: text }; + } +} +function parseRateLimit(headers, attempts, lastWaitMs) { + const remainingHeader = headers.get("x-ratelimit-remaining"); + const resetHeader = headers.get("x-ratelimit-reset"); + let remaining = null; + if (remainingHeader !== null && remainingHeader !== void 0) { + const parsed = Number(remainingHeader); + remaining = Number.isNaN(parsed) ? null : parsed; + } + let resetAt = null; + if (resetHeader) { + const numericReset = Number(resetHeader); + if (!Number.isNaN(numericReset)) { + resetAt = new Date(numericReset * 1e3).toISOString(); + } else { + const date = new Date(resetHeader); + if (!Number.isNaN(date.valueOf())) { + resetAt = date.toISOString(); + } + } + } + return { + remaining, + resetAt, + attempts, + lastWaitMs + }; +} +function computeBackoffMs(attempt, initialDelayMs) { + return initialDelayMs * 2 ** (attempt - 1); +} +async function figmaRequest(options) { + const { + path: path2, + method = "GET", + token, + headers = {}, + body, + searchParams, + maxAttempts = config_default.http?.maxAttempts ?? 5, + initialDelayMs = config_default.http?.initialDelayMs ?? 250 + } = options; + if (!token) { + return { + ok: false, + error: createError("FIGMA_AUTH", "FIGMA_ACCESS_TOKEN is missing from the environment."), + status: null, + rateLimit: null + }; + } + const url = new URL(path2, BASE_URL); + if (searchParams) { + Object.entries(searchParams).forEach(([key, value]) => { + if (value === void 0 || value === null) return; + url.searchParams.append(key, String(value)); + }); + } + let attempt = 0; + let lastWaitMs = 0; + while (attempt < maxAttempts) { + attempt += 1; + const response = await fetch(url, { + method, + headers: { + "Content-Type": "application/json", + "X-Figma-Token": token, + ...headers + }, + body: body ? JSON.stringify(body) : void 0 + }); + const text = await response.text(); + const payload = parseJsonSafely(text); + const rateLimit = parseRateLimit(response.headers, attempt, lastWaitMs); + if (response.ok) { + return { ok: true, data: payload, rateLimit }; + } + const status = response.status; + if (status === 401 || status === 403) { + return { ok: false, error: createError("FIGMA_AUTH", payload?.message ?? "Figma token is unauthorized.", { status }), status, rateLimit }; + } + if (status === 404) { + return { ok: false, error: createError("FIGMA_NOT_FOUND", payload?.message ?? "Resource not found.", { status }), status, rateLimit }; + } + if (status === 429 || status >= 500) { + if (attempt >= maxAttempts) { + return { + ok: false, + error: createError(status === 429 ? "FIGMA_RATE_LIMIT" : "NETWORK", payload?.message ?? "Figma request failed after maximum retries.", { status }), + status, + rateLimit + }; + } + let waitMs = computeBackoffMs(attempt, initialDelayMs); + const resetHeader = response.headers.get("x-ratelimit-reset"); + if (resetHeader) { + const asNumber = Number(resetHeader); + if (!Number.isNaN(asNumber)) { + const resetMs = asNumber * 1e3; + const delta = resetMs - Date.now(); + if (delta > 0) waitMs = Math.max(waitMs, delta); + } + } + const jitter = Math.floor(Math.random() * 100); + lastWaitMs = waitMs + jitter; + await sleep(lastWaitMs); + continue; + } + return { ok: false, error: createError("INTERNAL", payload?.message ?? "Unexpected error from Figma API.", { status }), status, rateLimit }; + } + return { + ok: false, + error: createError("NETWORK", "Unable to reach Figma API."), + status: null, + rateLimit: { remaining: null, resetAt: null, attempts: maxAttempts, lastWaitMs } + }; +} + +// coding-tools/figma-tools/js/src/get-screenshot.ts +var TOOL_NAME = "get-screenshot"; +var SUPPORTED_FORMATS = ["png", "jpg", "jpeg", "svg"]; +var SCREENSHOT_DIR = ".tmp/figma-tools/screenshots"; +function log(message, verbose) { + if (verbose) process.stderr.write(`[${TOOL_NAME}] ${message} +`); +} +function toOptionalString(value) { + return typeof value === "string" && value.length > 0 ? value : null; +} +function exitWithEnvelope(envelope, errors = []) { + process.stdout.write(`${JSON.stringify(envelope, null, 2)} +`); + process.exit(getExitCode(errors)); +} +async function ensureDirExists(dirPath) { + await mkdir(dirPath, { recursive: true }); +} +async function main() { + const args = parseArgs(); + const verbose = Boolean(args.verbose ?? args.v); + const schemaVersion = toOptionalString(args["schema-version"]) ?? void 0; + const warnings = []; + const errors = []; + const token = process.env.FIGMA_ACCESS_TOKEN; + if (!token || !token.trim()) { + errors.push(createError("FIGMA_AUTH", "FIGMA_ACCESS_TOKEN is required but was not provided.")); + const envelope2 = createEnvelope({ tool: TOOL_NAME, input: { fileKey: null, nodeId: null, format: "jpg", scale: 1, bounds: "selection", background: "canvas" }, warnings, errors, schemaVersion, data: {} }); + exitWithEnvelope(envelope2, errors); + } + const urlInput = toOptionalString(args.url) ?? toOptionalString(args.u); + let fileKey = toOptionalString(args["file-key"]) ?? void 0; + let nodeId = ensureNodeId(toOptionalString(args["node-id"])); + if (urlInput) { + const parsed = parseFigmaUrl(urlInput); + fileKey = fileKey || parsed.fileKey || void 0; + nodeId = nodeId || parsed.nodeId; + } + if (!fileKey) errors.push(createError("INPUT_INVALID", "A valid Figma file key is required (--file-key or --url).")); + if (!nodeId) errors.push(createError("INPUT_INVALID", "A valid Figma node id is required (--node-id or --url with node-id).")); + let format = String(args.format ?? "jpg").toLowerCase(); + if (!SUPPORTED_FORMATS.includes(format)) { + warnings.push(`Unsupported format "${format}". Falling back to jpg.`); + format = "jpg"; + } + if (format === "jpeg") format = "jpg"; + const scaleInput = Number(args.scale ?? 1); + const scale = Number.isFinite(scaleInput) ? Math.min(Math.max(scaleInput, 0.01), 1) : 1; + const boundsInput = String(args.bounds ?? "selection").toLowerCase(); + const bounds = ["selection", "frame", "node"].includes(boundsInput) ? boundsInput : "selection"; + const useAbsoluteBounds = bounds === "frame"; + const backgroundInput = String(args.background ?? "canvas").toLowerCase(); + let backgroundParam; + if (backgroundInput === "transparent") backgroundParam = "00000000"; + else if (/^[0-9a-f]{6,8}$/i.test(backgroundInput)) { + const value = backgroundInput.toUpperCase(); + backgroundParam = value.length >= 6 ? value.slice(0, 8).padEnd(8, "F") : void 0; + } else if (backgroundInput.startsWith("#")) backgroundParam = backgroundInput.replace("#", "").slice(0, 8).padEnd(8, "F"); + const input = { fileKey: fileKey ?? null, nodeId: nodeId ?? null, format, scale, bounds, background: backgroundInput }; + if (errors.length) { + const envelope2 = createEnvelope({ tool: TOOL_NAME, input, warnings, errors, data: {}, schemaVersion }); + exitWithEnvelope(envelope2, errors); + } + const resolvedFileKey = fileKey; + const resolvedNodeId = nodeId; + log(`Requesting image for ${resolvedNodeId} (${format}, scale ${scale})`, verbose); + const imageResponse = await figmaRequest({ + path: `/v1/images/${resolvedFileKey}`, + token, + searchParams: { ids: resolvedNodeId, format, scale, use_absolute_bounds: useAbsoluteBounds ? "true" : void 0, background: backgroundParam } + }); + if (!imageResponse.ok) { + errors.push(imageResponse.error ?? createError("INTERNAL", "Failed to request image export.")); + const envelope2 = createEnvelope({ tool: TOOL_NAME, input, warnings, errors, rateLimit: imageResponse.rateLimit ?? void 0, data: {}, schemaVersion }); + exitWithEnvelope(envelope2, errors); + } + const imageUrl = imageResponse.data?.images?.[resolvedNodeId]; + if (!imageUrl) { + errors.push(createError("FIGMA_NOT_FOUND", "Figma did not return an image URL for the requested node.")); + const envelope2 = createEnvelope({ tool: TOOL_NAME, input, warnings, errors, rateLimit: imageResponse.rateLimit ?? void 0, data: {}, schemaVersion }); + exitWithEnvelope(envelope2, errors); + } + log("Downloading image", verbose); + let buffer = null; + let contentType = null; + try { + const res = await fetch(imageUrl); + if (!res.ok) errors.push(createError("NETWORK", `Unable to download image (status ${res.status}).`)); + else { + contentType = res.headers.get("content-type"); + buffer = format === "svg" ? Buffer.from(await res.text()) : Buffer.from(await res.arrayBuffer()); + } + } catch (error) { + const message = error instanceof Error ? error.message : "Unknown download error"; + errors.push(createError("NETWORK", `Unable to download image: ${message}`)); + } + if (!buffer || errors.length) { + const envelope2 = createEnvelope({ tool: TOOL_NAME, input, warnings, errors, rateLimit: imageResponse.rateLimit ?? void 0, data: {}, schemaVersion }); + exitWithEnvelope(envelope2, errors); + } + const sanitizedNodeId = resolvedNodeId.replace(/[^a-zA-Z0-9-_]/g, "_"); + const baseDir = path.resolve(SCREENSHOT_DIR, resolvedFileKey); + await ensureDirExists(baseDir); + const extension = format === "jpg" ? "jpg" : format; + const filePath = path.join(baseDir, `${sanitizedNodeId}.${extension}`); + await writeFile(filePath, buffer); + const data = { + file: { key: resolvedFileKey, nodeId: resolvedNodeId }, + screenshot: { path: filePath, url: imageUrl, format: extension, scale, bounds, background: backgroundInput, contentType } + }; + const envelope = createEnvelope({ tool: TOOL_NAME, input, data, warnings, errors, rateLimit: imageResponse.rateLimit ?? void 0, schemaVersion }); + process.stdout.write(`${JSON.stringify(envelope, null, 2)} +`); + process.exit(getExitCode(errors)); +} +main().catch((error) => { + const message = error instanceof Error ? error.message : "Unknown error"; + const envelope = createEnvelope({ tool: TOOL_NAME, input: { fileKey: null, nodeId: null, format: "jpg", scale: 1, bounds: "selection", background: "canvas" }, errors: [createError("INTERNAL", message, { stack: error instanceof Error ? error.stack : void 0 })], data: {} }); + process.stdout.write(`${JSON.stringify(envelope, null, 2)} +`); + process.exit(3); +}); +//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiLi4vc3JjL2dldC1zY3JlZW5zaG90LnRzIiwgIi4uL3NyYy9fdXRpbHMvY2xpLWFyZ3MudHMiLCAiLi4vc3JjL191dGlscy91cmwtcGFyc2UudHMiLCAiLi4vc3JjL191dGlscy9jb25maWcudHMiLCAiLi4vc3JjL191dGlscy9lbnZlbG9wZS50cyIsICIuLi9zcmMvX3V0aWxzL2Vycm9ycy50cyIsICIuLi9zcmMvX3V0aWxzL2h0dHAtY2xpZW50LnRzIl0sCiAgInNvdXJjZXNDb250ZW50IjogWyIjIS91c3IvYmluL2VudiBub2RlXG5cbmltcG9ydCB7IG1rZGlyLCB3cml0ZUZpbGUgfSBmcm9tICdub2RlOmZzL3Byb21pc2VzJ1xuaW1wb3J0IHBhdGggZnJvbSAnbm9kZTpwYXRoJ1xuaW1wb3J0IHsgcGFyc2VBcmdzLCB0eXBlIENsaUFyZ3MgfSBmcm9tICcuL191dGlscy9jbGktYXJncy50cydcbmltcG9ydCB7IHBhcnNlRmlnbWFVcmwsIGVuc3VyZU5vZGVJZCB9IGZyb20gJy4vX3V0aWxzL3VybC1wYXJzZS50cydcbmltcG9ydCB7IGNyZWF0ZUVudmVsb3BlLCB0eXBlIFRvb2xFbnZlbG9wZSB9IGZyb20gJy4vX3V0aWxzL2VudmVsb3BlLnRzJ1xuaW1wb3J0IHsgY3JlYXRlRXJyb3IsIGdldEV4aXRDb2RlLCB0eXBlIFRvb2xFcnJvciB9IGZyb20gJy4vX3V0aWxzL2Vycm9ycy50cydcbmltcG9ydCB7IGZpZ21hUmVxdWVzdCB9IGZyb20gJy4vX3V0aWxzL2h0dHAtY2xpZW50LnRzJ1xuXG5jb25zdCBUT09MX05BTUUgPSAnZ2V0LXNjcmVlbnNob3QnXG5jb25zdCBTVVBQT1JURURfRk9STUFUUyA9IFsncG5nJywgJ2pwZycsICdqcGVnJywgJ3N2ZyddXG5jb25zdCBTQ1JFRU5TSE9UX0RJUiA9ICcudG1wL2ZpZ21hLXRvb2xzL3NjcmVlbnNob3RzJ1xudHlwZSBFbXB0eURhdGEgPSBSZWNvcmQ8c3RyaW5nLCBuZXZlcj5cblxuaW50ZXJmYWNlIFRvb2xJbnB1dCBleHRlbmRzIFJlY29yZDxzdHJpbmcsIHVua25vd24+IHtcbiAgZmlsZUtleTogc3RyaW5nIHwgbnVsbFxuICBub2RlSWQ6IHN0cmluZyB8IG51bGxcbiAgZm9ybWF0OiBzdHJpbmdcbiAgc2NhbGU6IG51bWJlclxuICBib3VuZHM6IHN0cmluZ1xuICBiYWNrZ3JvdW5kOiBzdHJpbmdcbn1cblxuaW50ZXJmYWNlIEltYWdlRXhwb3J0UmVzcG9uc2UgeyBpbWFnZXM/OiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+IH1cblxuaW50ZXJmYWNlIFNjcmVlbnNob3REYXRhIHtcbiAgZmlsZTogeyBrZXk6IHN0cmluZzsgbm9kZUlkOiBzdHJpbmcgfVxuICBzY3JlZW5zaG90OiB7XG4gICAgcGF0aDogc3RyaW5nXG4gICAgdXJsOiBzdHJpbmdcbiAgICBmb3JtYXQ6IHN0cmluZ1xuICAgIHNjYWxlOiBudW1iZXJcbiAgICBib3VuZHM6IHN0cmluZ1xuICAgIGJhY2tncm91bmQ6IHN0cmluZ1xuICAgIGNvbnRlbnRUeXBlOiBzdHJpbmcgfCBudWxsXG4gIH1cbn1cblxuZnVuY3Rpb24gbG9nKG1lc3NhZ2U6IHN0cmluZywgdmVyYm9zZTogYm9vbGVhbik6IHZvaWQge1xuICBpZiAodmVyYm9zZSkgcHJvY2Vzcy5zdGRlcnIud3JpdGUoYFske1RPT0xfTkFNRX1dICR7bWVzc2FnZX1cXG5gKVxufVxuXG5mdW5jdGlvbiB0b09wdGlvbmFsU3RyaW5nKHZhbHVlOiBDbGlBcmdzW3N0cmluZ10pOiBzdHJpbmcgfCBudWxsIHtcbiAgcmV0dXJuIHR5cGVvZiB2YWx1ZSA9PT0gJ3N0cmluZycgJiYgdmFsdWUubGVuZ3RoID4gMCA/IHZhbHVlIDogbnVsbFxufVxuXG5mdW5jdGlvbiBleGl0V2l0aEVudmVsb3BlKFxuICBlbnZlbG9wZTogVG9vbEVudmVsb3BlPFRvb2xJbnB1dCwgU2NyZWVuc2hvdERhdGEgfCBFbXB0eURhdGE+LFxuICBlcnJvcnM6IFRvb2xFcnJvcltdID0gW11cbik6IG5ldmVyIHtcbiAgcHJvY2Vzcy5zdGRvdXQud3JpdGUoYCR7SlNPTi5zdHJpbmdpZnkoZW52ZWxvcGUsIG51bGwsIDIpfVxcbmApXG4gIHByb2Nlc3MuZXhpdChnZXRFeGl0Q29kZShlcnJvcnMpKVxufVxuXG5hc3luYyBmdW5jdGlvbiBlbnN1cmVEaXJFeGlzdHMoZGlyUGF0aDogc3RyaW5nKTogUHJvbWlzZTx2b2lkPiB7IGF3YWl0IG1rZGlyKGRpclBhdGgsIHsgcmVjdXJzaXZlOiB0cnVlIH0pIH1cblxuYXN5bmMgZnVuY3Rpb24gbWFpbigpOiBQcm9taXNlPHZvaWQ+IHtcbiAgY29uc3QgYXJncyA9IHBhcnNlQXJncygpXG4gIGNvbnN0IHZlcmJvc2UgPSBCb29sZWFuKGFyZ3MudmVyYm9zZSA/PyBhcmdzLnYpXG4gIGNvbnN0IHNjaGVtYVZlcnNpb24gPSB0b09wdGlvbmFsU3RyaW5nKGFyZ3NbJ3NjaGVtYS12ZXJzaW9uJ10pID8/IHVuZGVmaW5lZFxuXG4gIGNvbnN0IHdhcm5pbmdzOiBzdHJpbmdbXSA9IFtdXG4gIGNvbnN0IGVycm9yczogVG9vbEVycm9yW10gPSBbXVxuXG4gIGNvbnN0IHRva2VuID0gcHJvY2Vzcy5lbnYuRklHTUFfQUNDRVNTX1RPS0VOXG4gIGlmICghdG9rZW4gfHwgIXRva2VuLnRyaW0oKSkge1xuICAgIGVycm9ycy5wdXNoKGNyZWF0ZUVycm9yKCdGSUdNQV9BVVRIJywgJ0ZJR01BX0FDQ0VTU19UT0tFTiBpcyByZXF1aXJlZCBidXQgd2FzIG5vdCBwcm92aWRlZC4nKSlcbiAgICBjb25zdCBlbnZlbG9wZSA9IGNyZWF0ZUVudmVsb3BlPFRvb2xJbnB1dCwgRW1wdHlEYXRhPih7IHRvb2w6IFRPT0xfTkFNRSwgaW5wdXQ6IHsgZmlsZUtleTogbnVsbCwgbm9kZUlkOiBudWxsLCBmb3JtYXQ6ICdqcGcnLCBzY2FsZTogMSwgYm91bmRzOiAnc2VsZWN0aW9uJywgYmFja2dyb3VuZDogJ2NhbnZhcycgfSwgd2FybmluZ3MsIGVycm9ycywgc2NoZW1hVmVyc2lvbiwgZGF0YToge30gYXMgRW1wdHlEYXRhIH0pXG4gICAgZXhpdFdpdGhFbnZlbG9wZShlbnZlbG9wZSwgZXJyb3JzKVxuICB9XG5cbiAgY29uc3QgdXJsSW5wdXQgPSB0b09wdGlvbmFsU3RyaW5nKGFyZ3MudXJsKSA/PyB0b09wdGlvbmFsU3RyaW5nKGFyZ3MudSlcbiAgbGV0IGZpbGVLZXkgPSB0b09wdGlvbmFsU3RyaW5nKGFyZ3NbJ2ZpbGUta2V5J10pID8/IHVuZGVmaW5lZFxuICBsZXQgbm9kZUlkID0gZW5zdXJlTm9kZUlkKHRvT3B0aW9uYWxTdHJpbmcoYXJnc1snbm9kZS1pZCddKSlcbiAgaWYgKHVybElucHV0KSB7XG4gICAgY29uc3QgcGFyc2VkID0gcGFyc2VGaWdtYVVybCh1cmxJbnB1dClcbiAgICBmaWxlS2V5ID0gZmlsZUtleSB8fCBwYXJzZWQuZmlsZUtleSB8fCB1bmRlZmluZWRcbiAgICBub2RlSWQgPSBub2RlSWQgfHwgcGFyc2VkLm5vZGVJZFxuICB9XG5cbiAgaWYgKCFmaWxlS2V5KSBlcnJvcnMucHVzaChjcmVhdGVFcnJvcignSU5QVVRfSU5WQUxJRCcsICdBIHZhbGlkIEZpZ21hIGZpbGUga2V5IGlzIHJlcXVpcmVkICgtLWZpbGUta2V5IG9yIC0tdXJsKS4nKSlcbiAgaWYgKCFub2RlSWQpIGVycm9ycy5wdXNoKGNyZWF0ZUVycm9yKCdJTlBVVF9JTlZBTElEJywgJ0EgdmFsaWQgRmlnbWEgbm9kZSBpZCBpcyByZXF1aXJlZCAoLS1ub2RlLWlkIG9yIC0tdXJsIHdpdGggbm9kZS1pZCkuJykpXG5cbiAgbGV0IGZvcm1hdCA9IFN0cmluZyhhcmdzLmZvcm1hdCA/PyAnanBnJykudG9Mb3dlckNhc2UoKVxuICBpZiAoIVNVUFBPUlRFRF9GT1JNQVRTLmluY2x1ZGVzKGZvcm1hdCkpIHsgd2FybmluZ3MucHVzaChgVW5zdXBwb3J0ZWQgZm9ybWF0IFwiJHtmb3JtYXR9XCIuIEZhbGxpbmcgYmFjayB0byBqcGcuYCk7IGZvcm1hdCA9ICdqcGcnIH1cbiAgaWYgKGZvcm1hdCA9PT0gJ2pwZWcnKSBmb3JtYXQgPSAnanBnJ1xuXG4gIGNvbnN0IHNjYWxlSW5wdXQgPSBOdW1iZXIoYXJncy5zY2FsZSA/PyAxKVxuICBjb25zdCBzY2FsZSA9IE51bWJlci5pc0Zpbml0ZShzY2FsZUlucHV0KSA/IE1hdGgubWluKE1hdGgubWF4KHNjYWxlSW5wdXQsIDAuMDEpLCAxKSA6IDFcblxuICBjb25zdCBib3VuZHNJbnB1dCA9IFN0cmluZyhhcmdzLmJvdW5kcyA/PyAnc2VsZWN0aW9uJykudG9Mb3dlckNhc2UoKVxuICBjb25zdCBib3VuZHMgPSBbJ3NlbGVjdGlvbicsICdmcmFtZScsICdub2RlJ10uaW5jbHVkZXMoYm91bmRzSW5wdXQpID8gYm91bmRzSW5wdXQgOiAnc2VsZWN0aW9uJ1xuICBjb25zdCB1c2VBYnNvbHV0ZUJvdW5kcyA9IGJvdW5kcyA9PT0gJ2ZyYW1lJ1xuXG4gIGNvbnN0IGJhY2tncm91bmRJbnB1dCA9IFN0cmluZyhhcmdzLmJhY2tncm91bmQgPz8gJ2NhbnZhcycpLnRvTG93ZXJDYXNlKClcbiAgbGV0IGJhY2tncm91bmRQYXJhbTogc3RyaW5nIHwgdW5kZWZpbmVkXG4gIGlmIChiYWNrZ3JvdW5kSW5wdXQgPT09ICd0cmFuc3BhcmVudCcpIGJhY2tncm91bmRQYXJhbSA9ICcwMDAwMDAwMCdcbiAgZWxzZSBpZiAoL15bMC05YS1mXXs2LDh9JC9pLnRlc3QoYmFja2dyb3VuZElucHV0KSkgeyBjb25zdCB2YWx1ZSA9IGJhY2tncm91bmRJbnB1dC50b1VwcGVyQ2FzZSgpOyBiYWNrZ3JvdW5kUGFyYW0gPSB2YWx1ZS5sZW5ndGggPj0gNiA/IHZhbHVlLnNsaWNlKDAsIDgpLnBhZEVuZCg4LCAnRicpIDogdW5kZWZpbmVkIH1cbiAgZWxzZSBpZiAoYmFja2dyb3VuZElucHV0LnN0YXJ0c1dpdGgoJyMnKSkgYmFja2dyb3VuZFBhcmFtID0gYmFja2dyb3VuZElucHV0LnJlcGxhY2UoJyMnLCAnJykuc2xpY2UoMCwgOCkucGFkRW5kKDgsICdGJylcblxuICBjb25zdCBpbnB1dDogVG9vbElucHV0ID0geyBmaWxlS2V5OiBmaWxlS2V5ID8/IG51bGwsIG5vZGVJZDogbm9kZUlkID8/IG51bGwsIGZvcm1hdCwgc2NhbGUsIGJvdW5kcywgYmFja2dyb3VuZDogYmFja2dyb3VuZElucHV0IH1cbiAgaWYgKGVycm9ycy5sZW5ndGgpIHsgY29uc3QgZW52ZWxvcGUgPSBjcmVhdGVFbnZlbG9wZTxUb29sSW5wdXQsIEVtcHR5RGF0YT4oeyB0b29sOiBUT09MX05BTUUsIGlucHV0LCB3YXJuaW5ncywgZXJyb3JzLCBkYXRhOiB7fSBhcyBFbXB0eURhdGEsIHNjaGVtYVZlcnNpb24gfSk7IGV4aXRXaXRoRW52ZWxvcGUoZW52ZWxvcGUsIGVycm9ycykgfVxuXG4gIGNvbnN0IHJlc29sdmVkRmlsZUtleSA9IGZpbGVLZXkgYXMgc3RyaW5nXG4gIGNvbnN0IHJlc29sdmVkTm9kZUlkID0gbm9kZUlkIGFzIHN0cmluZ1xuXG4gIGxvZyhgUmVxdWVzdGluZyBpbWFnZSBmb3IgJHtyZXNvbHZlZE5vZGVJZH0gKCR7Zm9ybWF0fSwgc2NhbGUgJHtzY2FsZX0pYCwgdmVyYm9zZSlcbiAgY29uc3QgaW1hZ2VSZXNwb25zZSA9IGF3YWl0IGZpZ21hUmVxdWVzdDxJbWFnZUV4cG9ydFJlc3BvbnNlPih7XG4gICAgcGF0aDogYC92MS9pbWFnZXMvJHtyZXNvbHZlZEZpbGVLZXl9YCxcbiAgICB0b2tlbixcbiAgICBzZWFyY2hQYXJhbXM6IHsgaWRzOiByZXNvbHZlZE5vZGVJZCwgZm9ybWF0LCBzY2FsZSwgdXNlX2Fic29sdXRlX2JvdW5kczogdXNlQWJzb2x1dGVCb3VuZHMgPyAndHJ1ZScgOiB1bmRlZmluZWQsIGJhY2tncm91bmQ6IGJhY2tncm91bmRQYXJhbSB9LFxuICB9KVxuXG4gIGlmICghaW1hZ2VSZXNwb25zZS5vaykge1xuICAgIGVycm9ycy5wdXNoKGltYWdlUmVzcG9uc2UuZXJyb3IgPz8gY3JlYXRlRXJyb3IoJ0lOVEVSTkFMJywgJ0ZhaWxlZCB0byByZXF1ZXN0IGltYWdlIGV4cG9ydC4nKSlcbiAgICBjb25zdCBlbnZlbG9wZSA9IGNyZWF0ZUVudmVsb3BlPFRvb2xJbnB1dCwgRW1wdHlEYXRhPih7IHRvb2w6IFRPT0xfTkFNRSwgaW5wdXQsIHdhcm5pbmdzLCBlcnJvcnMsIHJhdGVMaW1pdDogaW1hZ2VSZXNwb25zZS5yYXRlTGltaXQgPz8gdW5kZWZpbmVkLCBkYXRhOiB7fSBhcyBFbXB0eURhdGEsIHNjaGVtYVZlcnNpb24gfSlcbiAgICBleGl0V2l0aEVudmVsb3BlKGVudmVsb3BlLCBlcnJvcnMpXG4gIH1cblxuICBjb25zdCBpbWFnZVVybCA9IGltYWdlUmVzcG9uc2UuZGF0YT8uaW1hZ2VzPy5bcmVzb2x2ZWROb2RlSWRdXG4gIGlmICghaW1hZ2VVcmwpIHtcbiAgICBlcnJvcnMucHVzaChjcmVhdGVFcnJvcignRklHTUFfTk9UX0ZPVU5EJywgJ0ZpZ21hIGRpZCBub3QgcmV0dXJuIGFuIGltYWdlIFVSTCBmb3IgdGhlIHJlcXVlc3RlZCBub2RlLicpKVxuICAgIGNvbnN0IGVudmVsb3BlID0gY3JlYXRlRW52ZWxvcGU8VG9vbElucHV0LCBFbXB0eURhdGE+KHsgdG9vbDogVE9PTF9OQU1FLCBpbnB1dCwgd2FybmluZ3MsIGVycm9ycywgcmF0ZUxpbWl0OiBpbWFnZVJlc3BvbnNlLnJhdGVMaW1pdCA/PyB1bmRlZmluZWQsIGRhdGE6IHt9IGFzIEVtcHR5RGF0YSwgc2NoZW1hVmVyc2lvbiB9KVxuICAgIGV4aXRXaXRoRW52ZWxvcGUoZW52ZWxvcGUsIGVycm9ycylcbiAgfVxuXG4gIGxvZygnRG93bmxvYWRpbmcgaW1hZ2UnLCB2ZXJib3NlKVxuICBsZXQgYnVmZmVyOiBCdWZmZXIgfCBudWxsID0gbnVsbFxuICBsZXQgY29udGVudFR5cGU6IHN0cmluZyB8IG51bGwgPSBudWxsXG4gIHRyeSB7XG4gICAgY29uc3QgcmVzID0gYXdhaXQgZmV0Y2goaW1hZ2VVcmwpXG4gICAgaWYgKCFyZXMub2spIGVycm9ycy5wdXNoKGNyZWF0ZUVycm9yKCdORVRXT1JLJywgYFVuYWJsZSB0byBkb3dubG9hZCBpbWFnZSAoc3RhdHVzICR7cmVzLnN0YXR1c30pLmApKVxuICAgIGVsc2UgeyBjb250ZW50VHlwZSA9IHJlcy5oZWFkZXJzLmdldCgnY29udGVudC10eXBlJyk7IGJ1ZmZlciA9IChmb3JtYXQgPT09ICdzdmcnKSA/IEJ1ZmZlci5mcm9tKGF3YWl0IHJlcy50ZXh0KCkpIDogQnVmZmVyLmZyb20oYXdhaXQgcmVzLmFycmF5QnVmZmVyKCkpIH1cbiAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICBjb25zdCBtZXNzYWdlID0gZXJyb3IgaW5zdGFuY2VvZiBFcnJvciA/IGVycm9yLm1lc3NhZ2UgOiAnVW5rbm93biBkb3dubG9hZCBlcnJvcidcbiAgICBlcnJvcnMucHVzaChjcmVhdGVFcnJvcignTkVUV09SSycsIGBVbmFibGUgdG8gZG93bmxvYWQgaW1hZ2U6ICR7bWVzc2FnZX1gKSlcbiAgfVxuXG4gIGlmICghYnVmZmVyIHx8IGVycm9ycy5sZW5ndGgpIHtcbiAgICBjb25zdCBlbnZlbG9wZSA9IGNyZWF0ZUVudmVsb3BlPFRvb2xJbnB1dCwgRW1wdHlEYXRhPih7IHRvb2w6IFRPT0xfTkFNRSwgaW5wdXQsIHdhcm5pbmdzLCBlcnJvcnMsIHJhdGVMaW1pdDogaW1hZ2VSZXNwb25zZS5yYXRlTGltaXQgPz8gdW5kZWZpbmVkLCBkYXRhOiB7fSBhcyBFbXB0eURhdGEsIHNjaGVtYVZlcnNpb24gfSlcbiAgICBleGl0V2l0aEVudmVsb3BlKGVudmVsb3BlLCBlcnJvcnMpXG4gIH1cblxuICBjb25zdCBzYW5pdGl6ZWROb2RlSWQgPSByZXNvbHZlZE5vZGVJZC5yZXBsYWNlKC9bXmEtekEtWjAtOS1fXS9nLCAnXycpXG4gIGNvbnN0IGJhc2VEaXIgPSBwYXRoLnJlc29sdmUoU0NSRUVOU0hPVF9ESVIsIHJlc29sdmVkRmlsZUtleSlcbiAgYXdhaXQgZW5zdXJlRGlyRXhpc3RzKGJhc2VEaXIpXG4gIGNvbnN0IGV4dGVuc2lvbiA9IGZvcm1hdCA9PT0gJ2pwZycgPyAnanBnJyA6IGZvcm1hdFxuICBjb25zdCBmaWxlUGF0aCA9IHBhdGguam9pbihiYXNlRGlyLCBgJHtzYW5pdGl6ZWROb2RlSWR9LiR7ZXh0ZW5zaW9ufWApXG4gIGF3YWl0IHdyaXRlRmlsZShmaWxlUGF0aCwgYnVmZmVyKVxuXG4gIGNvbnN0IGRhdGE6IFNjcmVlbnNob3REYXRhID0ge1xuICAgIGZpbGU6IHsga2V5OiByZXNvbHZlZEZpbGVLZXksIG5vZGVJZDogcmVzb2x2ZWROb2RlSWQgfSxcbiAgICBzY3JlZW5zaG90OiB7IHBhdGg6IGZpbGVQYXRoLCB1cmw6IGltYWdlVXJsLCBmb3JtYXQ6IGV4dGVuc2lvbiwgc2NhbGUsIGJvdW5kcywgYmFja2dyb3VuZDogYmFja2dyb3VuZElucHV0LCBjb250ZW50VHlwZSB9LFxuICB9XG5cbiAgY29uc3QgZW52ZWxvcGUgPSBjcmVhdGVFbnZlbG9wZTxUb29sSW5wdXQsIFNjcmVlbnNob3REYXRhPih7IHRvb2w6IFRPT0xfTkFNRSwgaW5wdXQsIGRhdGEsIHdhcm5pbmdzLCBlcnJvcnMsIHJhdGVMaW1pdDogaW1hZ2VSZXNwb25zZS5yYXRlTGltaXQgPz8gdW5kZWZpbmVkLCBzY2hlbWFWZXJzaW9uIH0pXG4gIHByb2Nlc3Muc3Rkb3V0LndyaXRlKGAke0pTT04uc3RyaW5naWZ5KGVudmVsb3BlLCBudWxsLCAyKX1cXG5gKVxuICBwcm9jZXNzLmV4aXQoZ2V0RXhpdENvZGUoZXJyb3JzKSlcbn1cblxubWFpbigpLmNhdGNoKChlcnJvcjogdW5rbm93bikgPT4ge1xuICBjb25zdCBtZXNzYWdlID0gZXJyb3IgaW5zdGFuY2VvZiBFcnJvciA/IGVycm9yLm1lc3NhZ2UgOiAnVW5rbm93biBlcnJvcidcbiAgY29uc3QgZW52ZWxvcGUgPSBjcmVhdGVFbnZlbG9wZTxUb29sSW5wdXQsIEVtcHR5RGF0YT4oeyB0b29sOiBUT09MX05BTUUsIGlucHV0OiB7IGZpbGVLZXk6IG51bGwsIG5vZGVJZDogbnVsbCwgZm9ybWF0OiAnanBnJywgc2NhbGU6IDEsIGJvdW5kczogJ3NlbGVjdGlvbicsIGJhY2tncm91bmQ6ICdjYW52YXMnIH0sIGVycm9yczogW2NyZWF0ZUVycm9yKCdJTlRFUk5BTCcsIG1lc3NhZ2UsIHsgc3RhY2s6IGVycm9yIGluc3RhbmNlb2YgRXJyb3IgPyBlcnJvci5zdGFjayA6IHVuZGVmaW5lZCB9KV0sIGRhdGE6IHt9IGFzIEVtcHR5RGF0YSB9KVxuICBwcm9jZXNzLnN0ZG91dC53cml0ZShgJHtKU09OLnN0cmluZ2lmeShlbnZlbG9wZSwgbnVsbCwgMil9XFxuYClcbiAgcHJvY2Vzcy5leGl0KDMpXG59KVxuIiwgImV4cG9ydCB0eXBlIENsaUFyZ1ZhbHVlID0gc3RyaW5nIHwgYm9vbGVhbjtcblxuZXhwb3J0IGludGVyZmFjZSBDbGlBcmdzIHtcbiAgXzogc3RyaW5nW107XG4gIFtrZXk6IHN0cmluZ106IENsaUFyZ1ZhbHVlIHwgc3RyaW5nW107XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBwYXJzZUFyZ3MoYXJndjogc3RyaW5nW10gPSBwcm9jZXNzLmFyZ3Yuc2xpY2UoMikpOiBDbGlBcmdzIHtcbiAgY29uc3QgYXJnczogQ2xpQXJncyA9IHsgXzogW10gfTtcblxuICBmb3IgKGxldCBpID0gMDsgaSA8IGFyZ3YubGVuZ3RoOyBpICs9IDEpIHtcbiAgICBjb25zdCBhcmcgPSBhcmd2W2ldO1xuXG4gICAgaWYgKCFhcmcuc3RhcnRzV2l0aCgnLScpIHx8IGFyZyA9PT0gJy0nKSB7XG4gICAgICBhcmdzLl8ucHVzaChhcmcpO1xuICAgICAgY29udGludWU7XG4gICAgfVxuXG4gICAgaWYgKGFyZyA9PT0gJy0tJykge1xuICAgICAgY29uc3QgcmVtYWluaW5nID0gYXJndi5zbGljZShpICsgMSk7XG4gICAgICBhcmdzLl8ucHVzaCguLi5yZW1haW5pbmcpO1xuICAgICAgYnJlYWs7XG4gICAgfVxuXG4gICAgY29uc3QgW3Jhd0tleSwgaW5saW5lVmFsdWVdID0gYXJnLnNwbGl0KCc9JywgMik7XG4gICAgY29uc3Qgbm9ybWFsaXNlZEtleSA9IHJhd0tleS5yZXBsYWNlKC9eLSsvLCAnJyk7XG5cbiAgICBsZXQgdmFsdWU6IENsaUFyZ1ZhbHVlO1xuICAgIGlmIChpbmxpbmVWYWx1ZSAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICB2YWx1ZSA9IGlubGluZVZhbHVlO1xuICAgIH0gZWxzZSB7XG4gICAgICBjb25zdCBuZXh0ID0gYXJndltpICsgMV07XG4gICAgICBpZiAobmV4dCAhPT0gdW5kZWZpbmVkICYmICFuZXh0LnN0YXJ0c1dpdGgoJy0nKSkge1xuICAgICAgICB2YWx1ZSA9IG5leHQ7XG4gICAgICAgIGkgKz0gMTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHZhbHVlID0gdHJ1ZTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICBhcmdzW25vcm1hbGlzZWRLZXldID0gdmFsdWU7XG4gIH1cblxuICByZXR1cm4gYXJncztcbn1cblxuIiwgImNvbnN0IEZJTEVfS0VZX1JFR0VYID0gL2ZpZ21hXFwuY29tXFwvKD86ZmlsZXxkZXNpZ24pXFwvKFtBLVphLXowLTldKylcXC8vaTtcblxuZXhwb3J0IGludGVyZmFjZSBQYXJzZWRGaWdtYVVybCB7XG4gIGZpbGVLZXk6IHN0cmluZyB8IG51bGw7XG4gIG5vZGVJZDogc3RyaW5nIHwgbnVsbDtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIHBhcnNlRmlnbWFVcmwoaW5wdXQ6IHN0cmluZyB8IG51bGwgfCB1bmRlZmluZWQpOiBQYXJzZWRGaWdtYVVybCB7XG4gIGlmICghaW5wdXQpIHJldHVybiB7IGZpbGVLZXk6IG51bGwsIG5vZGVJZDogbnVsbCB9O1xuICB0cnkge1xuICAgIGNvbnN0IHVybCA9IG5ldyBVUkwoaW5wdXQpO1xuICAgIGNvbnN0IG1hdGNoID0gdXJsLmhyZWYubWF0Y2goRklMRV9LRVlfUkVHRVgpO1xuICAgIGNvbnN0IGZpbGVLZXkgPSBtYXRjaCA/IG1hdGNoWzFdIDogbnVsbDtcbiAgICBjb25zdCBub2RlUGFyYW0gPSB1cmwuc2VhcmNoUGFyYW1zLmdldCgnbm9kZS1pZCcpO1xuICAgIGNvbnN0IG5vZGVJZCA9IG5vZGVQYXJhbSA/IGVuc3VyZU5vZGVJZChub2RlUGFyYW0pIDogbnVsbDtcbiAgICByZXR1cm4geyBmaWxlS2V5LCBub2RlSWQgfTtcbiAgfSBjYXRjaCB7XG4gICAgcmV0dXJuIHsgZmlsZUtleTogbnVsbCwgbm9kZUlkOiBudWxsIH07XG4gIH1cbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGVuc3VyZU5vZGVJZCh2YWx1ZTogc3RyaW5nIHwgbnVsbCB8IHVuZGVmaW5lZCk6IHN0cmluZyB8IG51bGwge1xuICBpZiAoIXZhbHVlKSByZXR1cm4gbnVsbDtcbiAgY29uc3QgZGVjb2RlZCA9IGRlY29kZVVSSUNvbXBvbmVudCh2YWx1ZSk7XG4gIGlmIChkZWNvZGVkLmluY2x1ZGVzKCc6JykpIHJldHVybiBkZWNvZGVkO1xuICBpZiAoL15bMC05XSstWzAtOV0rJC8udGVzdChkZWNvZGVkKSkge1xuICAgIGNvbnN0IFtsZWZ0LCByaWdodF0gPSBkZWNvZGVkLnNwbGl0KCctJywgMik7XG4gICAgcmV0dXJuIGAke2xlZnR9OiR7cmlnaHR9YDtcbiAgfVxuICByZXR1cm4gZGVjb2RlZDtcbn1cblxuIiwgImV4cG9ydCBkZWZhdWx0IHtcbiAgc2NoZW1hVmVyc2lvbjogJzEuMC4wJyxcbiAgc291cmNlOiAnYWdlbnRpYy1jb2RpbmctdGVtcGxhdGVzL2ZpZ21hLXRvb2xzJyxcbiAgaHR0cDoge1xuICAgIG1heEF0dGVtcHRzOiA1LFxuICAgIGluaXRpYWxEZWxheU1zOiAyNTAsXG4gIH0sXG59IGFzIGNvbnN0O1xuXG4iLCAiaW1wb3J0IGNvbmZpZyBmcm9tICcuL2NvbmZpZy50cyc7XG5pbXBvcnQgdHlwZSB7IFRvb2xFcnJvciB9IGZyb20gJy4vZXJyb3JzLnRzJztcblxuZXhwb3J0IGludGVyZmFjZSBSYXRlTGltaXRNZXRhIHtcbiAgcmVtYWluaW5nOiBudW1iZXIgfCBudWxsO1xuICByZXNldEF0OiBzdHJpbmcgfCBudWxsO1xuICBhdHRlbXB0czogbnVtYmVyO1xuICBsYXN0V2FpdE1zOiBudW1iZXI7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgVG9vbEVudmVsb3BlPFxuICBUSW5wdXQgZXh0ZW5kcyBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPiA9IFJlY29yZDxzdHJpbmcsIHVua25vd24+LFxuICBURGF0YSA9IHVua25vd25cbj4ge1xuICBzY2hlbWFWZXJzaW9uOiBzdHJpbmc7XG4gIHRvb2w6IHN0cmluZztcbiAgaW5wdXQ6IFRJbnB1dDtcbiAgbWV0YToge1xuICAgIGdlbmVyYXRlZEF0OiBzdHJpbmc7XG4gICAgc291cmNlOiBzdHJpbmc7XG4gICAgcmF0ZUxpbWl0OiBSYXRlTGltaXRNZXRhO1xuICB9O1xuICBkYXRhOiBURGF0YTtcbiAgd2FybmluZ3M6IHN0cmluZ1tdO1xuICBlcnJvcnM6IFRvb2xFcnJvcltdO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIENyZWF0ZUVudmVsb3BlT3B0aW9uczxcbiAgVElucHV0IGV4dGVuZHMgUmVjb3JkPHN0cmluZywgdW5rbm93bj4gPSBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPixcbiAgVERhdGEgPSB1bmtub3duXG4+IHtcbiAgdG9vbDogc3RyaW5nO1xuICBpbnB1dD86IFRJbnB1dDtcbiAgZGF0YT86IFREYXRhO1xuICB3YXJuaW5ncz86IHN0cmluZ1tdO1xuICBlcnJvcnM/OiBUb29sRXJyb3JbXTtcbiAgcmF0ZUxpbWl0PzogUGFydGlhbDxSYXRlTGltaXRNZXRhPjtcbiAgc2NoZW1hVmVyc2lvbj86IHN0cmluZztcbn1cblxuZnVuY3Rpb24gYnVpbGRSYXRlTGltaXRNZXRhKHJhdGVMaW1pdDogUGFydGlhbDxSYXRlTGltaXRNZXRhPiA9IHt9KTogUmF0ZUxpbWl0TWV0YSB7XG4gIHJldHVybiB7XG4gICAgcmVtYWluaW5nOiByYXRlTGltaXQucmVtYWluaW5nID8/IG51bGwsXG4gICAgcmVzZXRBdDogcmF0ZUxpbWl0LnJlc2V0QXQgPz8gbnVsbCxcbiAgICBhdHRlbXB0czogcmF0ZUxpbWl0LmF0dGVtcHRzID8/IDEsXG4gICAgbGFzdFdhaXRNczogcmF0ZUxpbWl0Lmxhc3RXYWl0TXMgPz8gMCxcbiAgfTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGNyZWF0ZUVudmVsb3BlPFxuICBUSW5wdXQgZXh0ZW5kcyBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPiA9IFJlY29yZDxzdHJpbmcsIHVua25vd24+LFxuICBURGF0YSA9IHVua25vd25cbj4oe1xuICB0b29sLFxuICBpbnB1dCA9IHt9IGFzIFRJbnB1dCxcbiAgZGF0YSA9IHt9IGFzIFREYXRhLFxuICB3YXJuaW5ncyA9IFtdLFxuICBlcnJvcnMgPSBbXSxcbiAgcmF0ZUxpbWl0LFxuICBzY2hlbWFWZXJzaW9uLFxufTogQ3JlYXRlRW52ZWxvcGVPcHRpb25zPFRJbnB1dCwgVERhdGE+KTogVG9vbEVudmVsb3BlPFRJbnB1dCwgVERhdGE+IHtcbiAgcmV0dXJuIHtcbiAgICBzY2hlbWFWZXJzaW9uOiBzY2hlbWFWZXJzaW9uID8/IGNvbmZpZy5zY2hlbWFWZXJzaW9uLFxuICAgIHRvb2wsXG4gICAgaW5wdXQsXG4gICAgbWV0YToge1xuICAgICAgZ2VuZXJhdGVkQXQ6IG5ldyBEYXRlKCkudG9JU09TdHJpbmcoKSxcbiAgICAgIHNvdXJjZTogY29uZmlnLnNvdXJjZSxcbiAgICAgIHJhdGVMaW1pdDogYnVpbGRSYXRlTGltaXRNZXRhKHJhdGVMaW1pdCksXG4gICAgfSxcbiAgICBkYXRhLFxuICAgIHdhcm5pbmdzLFxuICAgIGVycm9ycyxcbiAgfTtcbn1cblxuIiwgImV4cG9ydCBjb25zdCBFUlJPUl9FWElUX0NPREVTID0ge1xuICBJTlBVVF9JTlZBTElEOiAxLFxuICBDT05GSUdfSU5WQUxJRDogMSxcbiAgRklHTUFfQVVUSDogMSxcbiAgRklHTUFfTk9UX0ZPVU5EOiAyLFxuICBGSUdNQV9SQVRFX0xJTUlUOiAyLFxuICBORVRXT1JLOiAyLFxuICBJTlRFUk5BTDogMyxcbn0gYXMgY29uc3Q7XG5cbmV4cG9ydCB0eXBlIEVycm9yQ29kZSA9IGtleW9mIHR5cGVvZiBFUlJPUl9FWElUX0NPREVTO1xuXG5leHBvcnQgaW50ZXJmYWNlIFRvb2xFcnJvcjxURGV0YWlsID0gdW5rbm93bj4ge1xuICBjb2RlOiBFcnJvckNvZGUgfCBzdHJpbmc7XG4gIG1lc3NhZ2U6IHN0cmluZztcbiAgZGV0YWlsPzogVERldGFpbCB8IG51bGw7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBjcmVhdGVFcnJvcjxURGV0YWlsID0gdW5rbm93bj4oXG4gIGNvZGU6IEVycm9yQ29kZSB8IHN0cmluZyxcbiAgbWVzc2FnZTogc3RyaW5nLFxuICBkZXRhaWw/OiBURGV0YWlsIHwgbnVsbFxuKTogVG9vbEVycm9yPFREZXRhaWw+IHtcbiAgcmV0dXJuIHtcbiAgICBjb2RlLFxuICAgIG1lc3NhZ2UsXG4gICAgZGV0YWlsOiBkZXRhaWwgPz8gbnVsbCxcbiAgfTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGdldEV4aXRDb2RlKGVycm9yczogVG9vbEVycm9yW10gPSBbXSk6IG51bWJlciB7XG4gIGlmICghZXJyb3JzLmxlbmd0aCkge1xuICAgIHJldHVybiAwO1xuICB9XG5cbiAgcmV0dXJuIGVycm9ycy5yZWR1Y2UoKG1heCwgZXJyb3IpID0+IHtcbiAgICBjb25zdCBleGl0Q29kZSA9IEVSUk9SX0VYSVRfQ09ERVNbZXJyb3IuY29kZSBhcyBFcnJvckNvZGVdID8/IDE7XG4gICAgcmV0dXJuIE1hdGgubWF4KG1heCwgZXhpdENvZGUpO1xuICB9LCAwKTtcbn1cblxuIiwgImltcG9ydCBjb25maWcgZnJvbSAnLi9jb25maWcudHMnO1xuaW1wb3J0IHsgY3JlYXRlRXJyb3IgfSBmcm9tICcuL2Vycm9ycy50cyc7XG5pbXBvcnQgdHlwZSB7IFRvb2xFcnJvciB9IGZyb20gJy4vZXJyb3JzLnRzJztcbmltcG9ydCB0eXBlIHsgUmF0ZUxpbWl0TWV0YSB9IGZyb20gJy4vZW52ZWxvcGUudHMnO1xuXG5jb25zdCBCQVNFX1VSTCA9ICdodHRwczovL2FwaS5maWdtYS5jb20nO1xuXG50eXBlIFNlYXJjaFBhcmFtcyA9IFJlY29yZDxzdHJpbmcsIHN0cmluZyB8IG51bWJlciB8IGJvb2xlYW4gfCBudWxsIHwgdW5kZWZpbmVkPjtcblxuaW50ZXJmYWNlIEZpZ21hUmVxdWVzdE9wdGlvbnMge1xuICBwYXRoOiBzdHJpbmc7XG4gIG1ldGhvZD86IHN0cmluZztcbiAgdG9rZW4/OiBzdHJpbmc7XG4gIGhlYWRlcnM/OiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+O1xuICBib2R5PzogdW5rbm93bjtcbiAgc2VhcmNoUGFyYW1zPzogU2VhcmNoUGFyYW1zO1xuICBtYXhBdHRlbXB0cz86IG51bWJlcjtcbiAgaW5pdGlhbERlbGF5TXM/OiBudW1iZXI7XG59XG5cbmludGVyZmFjZSBGaWdtYVN1Y2Nlc3M8VERhdGE+IHtcbiAgb2s6IHRydWU7XG4gIGRhdGE6IFREYXRhO1xuICByYXRlTGltaXQ6IFJhdGVMaW1pdE1ldGE7XG59XG5cbmludGVyZmFjZSBGaWdtYUZhaWx1cmUge1xuICBvazogZmFsc2U7XG4gIGVycm9yOiBUb29sRXJyb3I8eyBzdGF0dXM/OiBudW1iZXIgfT47XG4gIHN0YXR1cz86IG51bWJlciB8IG51bGw7XG4gIHJhdGVMaW1pdDogUmF0ZUxpbWl0TWV0YSB8IG51bGw7XG59XG5cbmV4cG9ydCB0eXBlIEZpZ21hUmVzcG9uc2U8VERhdGE+ID0gRmlnbWFTdWNjZXNzPFREYXRhPiB8IEZpZ21hRmFpbHVyZTtcblxuZnVuY3Rpb24gc2xlZXAobXM6IG51bWJlcik6IFByb21pc2U8dm9pZD4ge1xuICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUpID0+IHNldFRpbWVvdXQocmVzb2x2ZSwgbXMpKTtcbn1cblxuZnVuY3Rpb24gcGFyc2VKc29uU2FmZWx5KHRleHQ6IHN0cmluZyk6IHVua25vd24ge1xuICB0cnkge1xuICAgIHJldHVybiB0ZXh0ID8gSlNPTi5wYXJzZSh0ZXh0KSA6IHt9O1xuICB9IGNhdGNoIHtcbiAgICByZXR1cm4geyByYXc6IHRleHQgfTtcbiAgfVxufVxuXG5mdW5jdGlvbiBwYXJzZVJhdGVMaW1pdChoZWFkZXJzOiBIZWFkZXJzLCBhdHRlbXB0czogbnVtYmVyLCBsYXN0V2FpdE1zOiBudW1iZXIpOiBSYXRlTGltaXRNZXRhIHtcbiAgY29uc3QgcmVtYWluaW5nSGVhZGVyID0gaGVhZGVycy5nZXQoJ3gtcmF0ZWxpbWl0LXJlbWFpbmluZycpO1xuICBjb25zdCByZXNldEhlYWRlciA9IGhlYWRlcnMuZ2V0KCd4LXJhdGVsaW1pdC1yZXNldCcpO1xuXG4gIGxldCByZW1haW5pbmc6IG51bWJlciB8IG51bGwgPSBudWxsO1xuICBpZiAocmVtYWluaW5nSGVhZGVyICE9PSBudWxsICYmIHJlbWFpbmluZ0hlYWRlciAhPT0gdW5kZWZpbmVkKSB7XG4gICAgY29uc3QgcGFyc2VkID0gTnVtYmVyKHJlbWFpbmluZ0hlYWRlcik7XG4gICAgcmVtYWluaW5nID0gTnVtYmVyLmlzTmFOKHBhcnNlZCkgPyBudWxsIDogcGFyc2VkO1xuICB9XG5cbiAgbGV0IHJlc2V0QXQ6IHN0cmluZyB8IG51bGwgPSBudWxsO1xuICBpZiAocmVzZXRIZWFkZXIpIHtcbiAgICBjb25zdCBudW1lcmljUmVzZXQgPSBOdW1iZXIocmVzZXRIZWFkZXIpO1xuICAgIGlmICghTnVtYmVyLmlzTmFOKG51bWVyaWNSZXNldCkpIHtcbiAgICAgIHJlc2V0QXQgPSBuZXcgRGF0ZShudW1lcmljUmVzZXQgKiAxMDAwKS50b0lTT1N0cmluZygpO1xuICAgIH0gZWxzZSB7XG4gICAgICBjb25zdCBkYXRlID0gbmV3IERhdGUocmVzZXRIZWFkZXIpO1xuICAgICAgaWYgKCFOdW1iZXIuaXNOYU4oZGF0ZS52YWx1ZU9mKCkpKSB7XG4gICAgICAgIHJlc2V0QXQgPSBkYXRlLnRvSVNPU3RyaW5nKCk7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgcmV0dXJuIHtcbiAgICByZW1haW5pbmcsXG4gICAgcmVzZXRBdCxcbiAgICBhdHRlbXB0cyxcbiAgICBsYXN0V2FpdE1zLFxuICB9O1xufVxuXG5mdW5jdGlvbiBjb21wdXRlQmFja29mZk1zKGF0dGVtcHQ6IG51bWJlciwgaW5pdGlhbERlbGF5TXM6IG51bWJlcik6IG51bWJlciB7XG4gIHJldHVybiBpbml0aWFsRGVsYXlNcyAqIDIgKiogKGF0dGVtcHQgLSAxKTtcbn1cblxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGZpZ21hUmVxdWVzdDxURGF0YSA9IHVua25vd24+KFxuICBvcHRpb25zOiBGaWdtYVJlcXVlc3RPcHRpb25zXG4pOiBQcm9taXNlPEZpZ21hUmVzcG9uc2U8VERhdGE+PiB7XG4gIGNvbnN0IHtcbiAgICBwYXRoLFxuICAgIG1ldGhvZCA9ICdHRVQnLFxuICAgIHRva2VuLFxuICAgIGhlYWRlcnMgPSB7fSxcbiAgICBib2R5LFxuICAgIHNlYXJjaFBhcmFtcyxcbiAgICBtYXhBdHRlbXB0cyA9IGNvbmZpZy5odHRwPy5tYXhBdHRlbXB0cyA/PyA1LFxuICAgIGluaXRpYWxEZWxheU1zID0gY29uZmlnLmh0dHA/LmluaXRpYWxEZWxheU1zID8/IDI1MCxcbiAgfSA9IG9wdGlvbnM7XG5cbiAgaWYgKCF0b2tlbikge1xuICAgIHJldHVybiB7XG4gICAgICBvazogZmFsc2UsXG4gICAgICBlcnJvcjogY3JlYXRlRXJyb3IoJ0ZJR01BX0FVVEgnLCAnRklHTUFfQUNDRVNTX1RPS0VOIGlzIG1pc3NpbmcgZnJvbSB0aGUgZW52aXJvbm1lbnQuJyksXG4gICAgICBzdGF0dXM6IG51bGwsXG4gICAgICByYXRlTGltaXQ6IG51bGwsXG4gICAgfTtcbiAgfVxuXG4gIGNvbnN0IHVybCA9IG5ldyBVUkwocGF0aCwgQkFTRV9VUkwpO1xuXG4gIGlmIChzZWFyY2hQYXJhbXMpIHtcbiAgICBPYmplY3QuZW50cmllcyhzZWFyY2hQYXJhbXMpLmZvckVhY2goKFtrZXksIHZhbHVlXSkgPT4ge1xuICAgICAgaWYgKHZhbHVlID09PSB1bmRlZmluZWQgfHwgdmFsdWUgPT09IG51bGwpIHJldHVybjtcbiAgICAgIHVybC5zZWFyY2hQYXJhbXMuYXBwZW5kKGtleSwgU3RyaW5nKHZhbHVlKSk7XG4gICAgfSk7XG4gIH1cblxuICBsZXQgYXR0ZW1wdCA9IDA7XG4gIGxldCBsYXN0V2FpdE1zID0gMDtcblxuICB3aGlsZSAoYXR0ZW1wdCA8IG1heEF0dGVtcHRzKSB7XG4gICAgYXR0ZW1wdCArPSAxO1xuXG4gICAgY29uc3QgcmVzcG9uc2UgPSBhd2FpdCBmZXRjaCh1cmwsIHtcbiAgICAgIG1ldGhvZCxcbiAgICAgIGhlYWRlcnM6IHtcbiAgICAgICAgJ0NvbnRlbnQtVHlwZSc6ICdhcHBsaWNhdGlvbi9qc29uJyxcbiAgICAgICAgJ1gtRmlnbWEtVG9rZW4nOiB0b2tlbixcbiAgICAgICAgLi4uaGVhZGVycyxcbiAgICAgIH0sXG4gICAgICBib2R5OiBib2R5ID8gSlNPTi5zdHJpbmdpZnkoYm9keSkgOiB1bmRlZmluZWQsXG4gICAgfSk7XG5cbiAgICBjb25zdCB0ZXh0ID0gYXdhaXQgcmVzcG9uc2UudGV4dCgpO1xuICAgIGNvbnN0IHBheWxvYWQgPSBwYXJzZUpzb25TYWZlbHkodGV4dCkgYXMgeyBtZXNzYWdlPzogc3RyaW5nIH07XG4gICAgY29uc3QgcmF0ZUxpbWl0ID0gcGFyc2VSYXRlTGltaXQocmVzcG9uc2UuaGVhZGVycywgYXR0ZW1wdCwgbGFzdFdhaXRNcyk7XG5cbiAgICBpZiAocmVzcG9uc2Uub2spIHtcbiAgICAgIHJldHVybiB7IG9rOiB0cnVlLCBkYXRhOiBwYXlsb2FkIGFzIFREYXRhLCByYXRlTGltaXQgfTtcbiAgICB9XG5cbiAgICBjb25zdCBzdGF0dXMgPSByZXNwb25zZS5zdGF0dXM7XG5cbiAgICBpZiAoc3RhdHVzID09PSA0MDEgfHwgc3RhdHVzID09PSA0MDMpIHtcbiAgICAgIHJldHVybiB7IG9rOiBmYWxzZSwgZXJyb3I6IGNyZWF0ZUVycm9yKCdGSUdNQV9BVVRIJywgcGF5bG9hZD8ubWVzc2FnZSA/PyAnRmlnbWEgdG9rZW4gaXMgdW5hdXRob3JpemVkLicsIHsgc3RhdHVzIH0pLCBzdGF0dXMsIHJhdGVMaW1pdCB9O1xuICAgIH1cblxuICAgIGlmIChzdGF0dXMgPT09IDQwNCkge1xuICAgICAgcmV0dXJuIHsgb2s6IGZhbHNlLCBlcnJvcjogY3JlYXRlRXJyb3IoJ0ZJR01BX05PVF9GT1VORCcsIHBheWxvYWQ/Lm1lc3NhZ2UgPz8gJ1Jlc291cmNlIG5vdCBmb3VuZC4nLCB7IHN0YXR1cyB9KSwgc3RhdHVzLCByYXRlTGltaXQgfTtcbiAgICB9XG5cbiAgICBpZiAoc3RhdHVzID09PSA0MjkgfHwgc3RhdHVzID49IDUwMCkge1xuICAgICAgaWYgKGF0dGVtcHQgPj0gbWF4QXR0ZW1wdHMpIHtcbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICBvazogZmFsc2UsXG4gICAgICAgICAgZXJyb3I6IGNyZWF0ZUVycm9yKHN0YXR1cyA9PT0gNDI5ID8gJ0ZJR01BX1JBVEVfTElNSVQnIDogJ05FVFdPUksnLCBwYXlsb2FkPy5tZXNzYWdlID8/ICdGaWdtYSByZXF1ZXN0IGZhaWxlZCBhZnRlciBtYXhpbXVtIHJldHJpZXMuJywgeyBzdGF0dXMgfSksXG4gICAgICAgICAgc3RhdHVzLFxuICAgICAgICAgIHJhdGVMaW1pdCxcbiAgICAgICAgfTtcbiAgICAgIH1cblxuICAgICAgbGV0IHdhaXRNcyA9IGNvbXB1dGVCYWNrb2ZmTXMoYXR0ZW1wdCwgaW5pdGlhbERlbGF5TXMpO1xuICAgICAgY29uc3QgcmVzZXRIZWFkZXIgPSByZXNwb25zZS5oZWFkZXJzLmdldCgneC1yYXRlbGltaXQtcmVzZXQnKTtcbiAgICAgIGlmIChyZXNldEhlYWRlcikge1xuICAgICAgICBjb25zdCBhc051bWJlciA9IE51bWJlcihyZXNldEhlYWRlcik7XG4gICAgICAgIGlmICghTnVtYmVyLmlzTmFOKGFzTnVtYmVyKSkge1xuICAgICAgICAgIGNvbnN0IHJlc2V0TXMgPSBhc051bWJlciAqIDEwMDA7XG4gICAgICAgICAgY29uc3QgZGVsdGEgPSByZXNldE1zIC0gRGF0ZS5ub3coKTtcbiAgICAgICAgICBpZiAoZGVsdGEgPiAwKSB3YWl0TXMgPSBNYXRoLm1heCh3YWl0TXMsIGRlbHRhKTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICBjb25zdCBqaXR0ZXIgPSBNYXRoLmZsb29yKE1hdGgucmFuZG9tKCkgKiAxMDApO1xuICAgICAgbGFzdFdhaXRNcyA9IHdhaXRNcyArIGppdHRlcjtcbiAgICAgIGF3YWl0IHNsZWVwKGxhc3RXYWl0TXMpO1xuICAgICAgY29udGludWU7XG4gICAgfVxuXG4gICAgcmV0dXJuIHsgb2s6IGZhbHNlLCBlcnJvcjogY3JlYXRlRXJyb3IoJ0lOVEVSTkFMJywgcGF5bG9hZD8ubWVzc2FnZSA/PyAnVW5leHBlY3RlZCBlcnJvciBmcm9tIEZpZ21hIEFQSS4nLCB7IHN0YXR1cyB9KSwgc3RhdHVzLCByYXRlTGltaXQgfTtcbiAgfVxuXG4gIHJldHVybiB7XG4gICAgb2s6IGZhbHNlLFxuICAgIGVycm9yOiBjcmVhdGVFcnJvcignTkVUV09SSycsICdVbmFibGUgdG8gcmVhY2ggRmlnbWEgQVBJLicpLFxuICAgIHN0YXR1czogbnVsbCxcbiAgICByYXRlTGltaXQ6IHsgcmVtYWluaW5nOiBudWxsLCByZXNldEF0OiBudWxsLCBhdHRlbXB0czogbWF4QXR0ZW1wdHMsIGxhc3RXYWl0TXMgfSxcbiAgfTtcbn1cblxuIl0sCiAgIm1hcHBpbmdzIjogIjs7O0FBRUEsU0FBUyxPQUFPLGlCQUFpQjtBQUNqQyxPQUFPLFVBQVU7OztBQ0lWLFNBQVMsVUFBVSxPQUFpQixRQUFRLEtBQUssTUFBTSxDQUFDLEdBQVk7QUFDekUsUUFBTSxPQUFnQixFQUFFLEdBQUcsQ0FBQyxFQUFFO0FBRTlCLFdBQVMsSUFBSSxHQUFHLElBQUksS0FBSyxRQUFRLEtBQUssR0FBRztBQUN2QyxVQUFNLE1BQU0sS0FBSyxDQUFDO0FBRWxCLFFBQUksQ0FBQyxJQUFJLFdBQVcsR0FBRyxLQUFLLFFBQVEsS0FBSztBQUN2QyxXQUFLLEVBQUUsS0FBSyxHQUFHO0FBQ2Y7QUFBQSxJQUNGO0FBRUEsUUFBSSxRQUFRLE1BQU07QUFDaEIsWUFBTSxZQUFZLEtBQUssTUFBTSxJQUFJLENBQUM7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SyxNQUFNLElBQUksS0FBSyxDQUFDLElBQUksT0FBTyxLQUFLLE1BQU0sSUFBSSxZQUFZLENBQUM7QUFBQSxJQUFFO0FBQUEsRUFDM0osU0FBUyxPQUFPO0FBQ2QsVUFBTSxVQUFVLGlCQUFpQixRQUFRLE1BQU0sVUFBVTtBQUN6RCxXQUFPLEtBQUssWUFBWSxXQUFXLDZCQUE2QixPQUFPLEVBQUUsQ0FBQztBQUFBLEVBQzVFO0FBRUEsTUFBSSxDQUFDLFVBQVUsT0FBTyxRQUFRO0FBQzVCLFVBQU1BLFlBQVcsZUFBcUMsRUFBRSxNQUFNLFdBQVcsT0FBTyxVQUFVLFFBQVEsV0FBVyxjQUFjLGFBQWEsUUFBVyxNQUFNLENBQUMsR0FBZ0IsY0FBYyxDQUFDO0FBQ3pMLHFCQUFpQkEsV0FBVSxNQUFNO0FBQUEsRUFDbkM7QUFFQSxRQUFNLGtCQUFrQixlQUFlLFFBQVEsbUJBQW1CLEdBQUc7QUFDckUsUUFBTSxVQUFVLEtBQUssUUFBUSxnQkFBZ0IsZUFBZTtBQUM1RCxRQUFNLGdCQUFnQixPQUFPO0FBQzdCLFFBQU0sWUFBWSxXQUFXLFFBQVEsUUFBUTtBQUM3QyxRQUFNLFdBQVcsS0FBSyxLQUFLLFNBQVMsR0FBRyxlQUFlLElBQUksU0FBUyxFQUFFO0FBQ3JFLFFBQU0sVUFBVSxVQUFVLE1BQU07QUFFaEMsUUFBTSxPQUF1QjtBQUFBLElBQzNCLE1BQU0sRUFBRSxLQUFLLGlCQUFpQixRQUFRLGVBQWU7QUFBQSxJQUNyRCxZQUFZLEVBQUUsTUFBTSxVQUFVLEtBQUssVUFBVSxRQUFRLFdBQVcsT0FBTyxRQUFRLFlBQVksaUJBQWlCLFlBQVk7QUFBQSxFQUMxSDtBQUVBLFFBQU0sV0FBVyxlQUEwQyxFQUFFLE1BQU0sV0FBVyxPQUFPLE1BQU0sVUFBVSxRQUFRLFdBQVcsY0FBYyxhQUFhLFFBQVcsY0FBYyxDQUFDO0FBQzdLLFVBQVEsT0FBTyxNQUFNLEdBQUcsS0FBSyxVQUFVLFVBQVUsTUFBTSxDQUFDLENBQUM7QUFBQSxDQUFJO0FBQzdELFVBQVEsS0FBSyxZQUFZLE1BQU0sQ0FBQztBQUNsQztBQUVBLEtBQUssRUFBRSxNQUFNLENBQUMsVUFBbUI7QUFDL0IsUUFBTSxVQUFVLGlCQUFpQixRQUFRLE1BQU0sVUFBVTtBQUN6RCxRQUFNLFdBQVcsZUFBcUMsRUFBRSxNQUFNLFdBQVcsT0FBTyxFQUFFLFNBQVMsTUFBTSxRQUFRLE1BQU0sUUFBUSxPQUFPLE9BQU8sR0FBRyxRQUFRLGFBQWEsWUFBWSxTQUFTLEdBQUcsUUFBUSxDQUFDLFlBQVksWUFBWSxTQUFTLEVBQUUsT0FBTyxpQkFBaUIsUUFBUSxNQUFNLFFBQVEsT0FBVSxDQUFDLENBQUMsR0FBRyxNQUFNLENBQUMsRUFBZSxDQUFDO0FBQ3JULFVBQVEsT0FBTyxNQUFNLEdBQUcsS0FBSyxVQUFVLFVBQVUsTUFBTSxDQUFDLENBQUM7QUFBQSxDQUFJO0FBQzdELFVBQVEsS0FBSyxDQUFDO0FBQ2hCLENBQUM7IiwKICAibmFtZXMiOiBbInBhdGgiLCAiZW52ZWxvcGUiXQp9Cg== diff --git a/use-figma/scripts/get-variable-definitions.mjs b/use-figma/scripts/get-variable-definitions.mjs new file mode 100755 index 0000000..d4fa4f4 --- /dev/null +++ b/use-figma/scripts/get-variable-definitions.mjs @@ -0,0 +1,404 @@ +#!/usr/bin/env node + +// coding-tools/figma-tools/js/src/_utils/cli-args.ts +function parseArgs(argv = process.argv.slice(2)) { + const args = { _: [] }; + for (let i = 0; i < argv.length; i += 1) { + const arg = argv[i]; + if (!arg.startsWith("-") || arg === "-") { + args._.push(arg); + continue; + } + if (arg === "--") { + const remaining = argv.slice(i + 1); + args._.push(...remaining); + break; + } + const [rawKey, inlineValue] = arg.split("=", 2); + const normalisedKey = rawKey.replace(/^-+/, ""); + let value; + if (inlineValue !== void 0) { + value = inlineValue; + } else { + const next = argv[i + 1]; + if (next !== void 0 && !next.startsWith("-")) { + value = next; + i += 1; + } else { + value = true; + } + } + args[normalisedKey] = value; + } + return args; +} + +// coding-tools/figma-tools/js/src/_utils/url-parse.ts +var FILE_KEY_REGEX = /figma\.com\/(?:file|design)\/([A-Za-z0-9]+)\//i; +function parseFigmaUrl(input) { + if (!input) return { fileKey: null, nodeId: null }; + try { + const url = new URL(input); + const match = url.href.match(FILE_KEY_REGEX); + const fileKey = match ? match[1] : null; + const nodeParam = url.searchParams.get("node-id"); + const nodeId = nodeParam ? ensureNodeId(nodeParam) : null; + return { fileKey, nodeId }; + } catch { + return { fileKey: null, nodeId: null }; + } +} +function ensureNodeId(value) { + if (!value) return null; + const decoded = decodeURIComponent(value); + if (decoded.includes(":")) return decoded; + if (/^[0-9]+-[0-9]+$/.test(decoded)) { + const [left, right] = decoded.split("-", 2); + return `${left}:${right}`; + } + return decoded; +} + +// coding-tools/figma-tools/js/src/_utils/config.ts +var config_default = { + schemaVersion: "1.0.0", + source: "agentic-coding-templates/figma-tools", + http: { + maxAttempts: 5, + initialDelayMs: 250 + } +}; + +// coding-tools/figma-tools/js/src/_utils/envelope.ts +function buildRateLimitMeta(rateLimit = {}) { + return { + remaining: rateLimit.remaining ?? null, + resetAt: rateLimit.resetAt ?? null, + attempts: rateLimit.attempts ?? 1, + lastWaitMs: rateLimit.lastWaitMs ?? 0 + }; +} +function createEnvelope({ + tool, + input = {}, + data = {}, + warnings = [], + errors = [], + rateLimit, + schemaVersion +}) { + return { + schemaVersion: schemaVersion ?? config_default.schemaVersion, + tool, + input, + meta: { + generatedAt: (/* @__PURE__ */ new Date()).toISOString(), + source: config_default.source, + rateLimit: buildRateLimitMeta(rateLimit) + }, + data, + warnings, + errors + }; +} + +// coding-tools/figma-tools/js/src/_utils/errors.ts +var ERROR_EXIT_CODES = { + INPUT_INVALID: 1, + CONFIG_INVALID: 1, + FIGMA_AUTH: 1, + FIGMA_NOT_FOUND: 2, + FIGMA_RATE_LIMIT: 2, + NETWORK: 2, + INTERNAL: 3 +}; +function createError(code, message, detail) { + return { + code, + message, + detail: detail ?? null + }; +} +function getExitCode(errors = []) { + if (!errors.length) { + return 0; + } + return errors.reduce((max, error) => { + const exitCode = ERROR_EXIT_CODES[error.code] ?? 1; + return Math.max(max, exitCode); + }, 0); +} + +// coding-tools/figma-tools/js/src/_utils/http-client.ts +var BASE_URL = "https://api.figma.com"; +function sleep(ms) { + return new Promise((resolve) => setTimeout(resolve, ms)); +} +function parseJsonSafely(text) { + try { + return text ? JSON.parse(text) : {}; + } catch { + return { raw: text }; + } +} +function parseRateLimit(headers, attempts, lastWaitMs) { + const remainingHeader = headers.get("x-ratelimit-remaining"); + const resetHeader = headers.get("x-ratelimit-reset"); + let remaining = null; + if (remainingHeader !== null && remainingHeader !== void 0) { + const parsed = Number(remainingHeader); + remaining = Number.isNaN(parsed) ? null : parsed; + } + let resetAt = null; + if (resetHeader) { + const numericReset = Number(resetHeader); + if (!Number.isNaN(numericReset)) { + resetAt = new Date(numericReset * 1e3).toISOString(); + } else { + const date = new Date(resetHeader); + if (!Number.isNaN(date.valueOf())) { + resetAt = date.toISOString(); + } + } + } + return { + remaining, + resetAt, + attempts, + lastWaitMs + }; +} +function computeBackoffMs(attempt, initialDelayMs) { + return initialDelayMs * 2 ** (attempt - 1); +} +async function figmaRequest(options) { + const { + path, + method = "GET", + token, + headers = {}, + body, + searchParams, + maxAttempts = config_default.http?.maxAttempts ?? 5, + initialDelayMs = config_default.http?.initialDelayMs ?? 250 + } = options; + if (!token) { + return { + ok: false, + error: createError("FIGMA_AUTH", "FIGMA_ACCESS_TOKEN is missing from the environment."), + status: null, + rateLimit: null + }; + } + const url = new URL(path, BASE_URL); + if (searchParams) { + Object.entries(searchParams).forEach(([key, value]) => { + if (value === void 0 || value === null) return; + url.searchParams.append(key, String(value)); + }); + } + let attempt = 0; + let lastWaitMs = 0; + while (attempt < maxAttempts) { + attempt += 1; + const response = await fetch(url, { + method, + headers: { + "Content-Type": "application/json", + "X-Figma-Token": token, + ...headers + }, + body: body ? JSON.stringify(body) : void 0 + }); + const text = await response.text(); + const payload = parseJsonSafely(text); + const rateLimit = parseRateLimit(response.headers, attempt, lastWaitMs); + if (response.ok) { + return { ok: true, data: payload, rateLimit }; + } + const status = response.status; + if (status === 401 || status === 403) { + return { ok: false, error: createError("FIGMA_AUTH", payload?.message ?? "Figma token is unauthorized.", { status }), status, rateLimit }; + } + if (status === 404) { + return { ok: false, error: createError("FIGMA_NOT_FOUND", payload?.message ?? "Resource not found.", { status }), status, rateLimit }; + } + if (status === 429 || status >= 500) { + if (attempt >= maxAttempts) { + return { + ok: false, + error: createError(status === 429 ? "FIGMA_RATE_LIMIT" : "NETWORK", payload?.message ?? "Figma request failed after maximum retries.", { status }), + status, + rateLimit + }; + } + let waitMs = computeBackoffMs(attempt, initialDelayMs); + const resetHeader = response.headers.get("x-ratelimit-reset"); + if (resetHeader) { + const asNumber = Number(resetHeader); + if (!Number.isNaN(asNumber)) { + const resetMs = asNumber * 1e3; + const delta = resetMs - Date.now(); + if (delta > 0) waitMs = Math.max(waitMs, delta); + } + } + const jitter = Math.floor(Math.random() * 100); + lastWaitMs = waitMs + jitter; + await sleep(lastWaitMs); + continue; + } + return { ok: false, error: createError("INTERNAL", payload?.message ?? "Unexpected error from Figma API.", { status }), status, rateLimit }; + } + return { + ok: false, + error: createError("NETWORK", "Unable to reach Figma API."), + status: null, + rateLimit: { remaining: null, resetAt: null, attempts: maxAttempts, lastWaitMs } + }; +} + +// coding-tools/figma-tools/js/src/get-variable-definitions.ts +var TOOL_NAME = "get-variable-definitions"; +function log(message, verbose) { + if (verbose) process.stderr.write(`[${TOOL_NAME}] ${message} +`); +} +function toOptionalString(value) { + return typeof value === "string" && value.length > 0 ? value : null; +} +function exitWithEnvelope(envelope, errors = []) { + process.stdout.write(`${JSON.stringify(envelope, null, 2)} +`); + process.exit(getExitCode(errors)); +} +function resolveCollectionName(id, collections) { + if (!id) return null; + const entry = collections.find((c) => c.id === id); + return entry?.name ?? null; +} +function buildVariableEntry(variable, collections, sets) { + return { + id: variable.id, + name: variable.name, + key: variable.key, + resolvedType: variable.resolvedType, + collectionId: variable.collectionId ?? variable.variableCollectionId ?? null, + collectionName: resolveCollectionName(variable.collectionId ?? variable.variableCollectionId, collections), + variableSetId: variable.variableSetId ?? null, + variableSetName: resolveCollectionName(variable.variableSetId, sets), + scopes: variable.scopes ?? [], + description: variable.description ?? null, + defaultValue: variable.valuesByMode?.[variable.defaultModeId ?? ""] ?? null, + valuesByMode: variable.valuesByMode ?? {} + }; +} +function partitionVariables(list) { + const colors = []; + const spacing = []; + const typography = []; + const others = []; + for (const entry of list) { + switch (entry.resolvedType) { + case "COLOR": + colors.push(entry); + break; + case "FLOAT": + spacing.push(entry); + break; + case "STRING": + case "BOOLEAN": + typography.push(entry); + break; + default: + others.push(entry); + } + } + return { colors, spacing, typography, others }; +} +function extractStyles(payload) { + if (!payload) return []; + if (Array.isArray(payload.styles)) return payload.styles; + if (payload.meta?.styles) return Object.values(payload.meta.styles); + return []; +} +async function main() { + const args = parseArgs(); + const verbose = Boolean(args.verbose ?? args.v); + const schemaVersion = toOptionalString(args["schema-version"]) ?? void 0; + const warnings = []; + const errors = []; + const token = process.env.FIGMA_ACCESS_TOKEN; + if (!token || !token.trim()) { + errors.push(createError("FIGMA_AUTH", "FIGMA_ACCESS_TOKEN is required but was not provided.")); + const envelope2 = createEnvelope({ + tool: TOOL_NAME, + input: { fileKey: null, includeStyles: false }, + warnings, + errors, + schemaVersion, + data: {} + }); + exitWithEnvelope(envelope2, errors); + } + const urlInput = toOptionalString(args.url) ?? toOptionalString(args.u); + let fileKey = toOptionalString(args["file-key"]) ?? void 0; + if (urlInput) { + const parsed = parseFigmaUrl(urlInput); + fileKey = fileKey || parsed.fileKey || void 0; + } + const includeStyles = args["include-styles"] !== "false"; + const input = { fileKey: fileKey ?? null, includeStyles }; + if (!fileKey) { + errors.push(createError("INPUT_INVALID", "A valid Figma file key is required (--file-key or --url).")); + } + if (errors.length) { + const envelope2 = createEnvelope({ tool: TOOL_NAME, input, warnings, errors, data: {}, schemaVersion }); + exitWithEnvelope(envelope2, errors); + } + const resolvedFileKey = fileKey; + log("Fetching variables", verbose); + const variablesResponse = await figmaRequest({ + path: `/v1/files/${resolvedFileKey}/variables/local`, + token + }); + let stylesResponse; + if (includeStyles) { + log("Fetching styles", verbose); + stylesResponse = await figmaRequest({ path: `/v1/files/${resolvedFileKey}/styles`, token }); + } else { + stylesResponse = { ok: true, data: { styles: [] }, rateLimit: null }; + } + if (!variablesResponse.ok) { + errors.push(variablesResponse.error ?? createError("INTERNAL", "Failed to fetch variables.")); + const envelope2 = createEnvelope({ tool: TOOL_NAME, input, warnings, errors, rateLimit: variablesResponse.rateLimit ?? void 0, schemaVersion, data: {} }); + exitWithEnvelope(envelope2, errors); + } + if (!stylesResponse.ok) { + warnings.push(stylesResponse.error?.message ?? "Failed to fetch styles."); + } + const variablesPayload = variablesResponse.data ?? {}; + const variableCollections = variablesPayload.collections ?? []; + const variableSets = variablesPayload.variableCollections ?? []; + const variables = variablesPayload.variables ?? []; + const normalisedVariables = variables.map((v) => buildVariableEntry(v, variableCollections, variableSets)); + const partitions = partitionVariables(normalisedVariables); + const styles = stylesResponse.ok ? extractStyles(stylesResponse.data) : []; + const data = { + file: { key: resolvedFileKey }, + variables: partitions, + rawVariables: normalisedVariables, + styles + }; + const envelope = createEnvelope({ tool: TOOL_NAME, input, data, warnings, errors, rateLimit: variablesResponse.rateLimit ?? void 0, schemaVersion }); + process.stdout.write(`${JSON.stringify(envelope, null, 2)} +`); + process.exit(getExitCode(errors)); +} +main().catch((error) => { + const message = error instanceof Error ? error.message : "Unknown error"; + const envelope = createEnvelope({ tool: TOOL_NAME, input: { fileKey: null, includeStyles: false }, errors: [createError("INTERNAL", message, { stack: error instanceof Error ? error.stack : void 0 })], data: {} }); + process.stdout.write(`${JSON.stringify(envelope, null, 2)} +`); + process.exit(3); +}); +//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiLi4vc3JjL191dGlscy9jbGktYXJncy50cyIsICIuLi9zcmMvX3V0aWxzL3VybC1wYXJzZS50cyIsICIuLi9zcmMvX3V0aWxzL2NvbmZpZy50cyIsICIuLi9zcmMvX3V0aWxzL2VudmVsb3BlLnRzIiwgIi4uL3NyYy9fdXRpbHMvZXJyb3JzLnRzIiwgIi4uL3NyYy9fdXRpbHMvaHR0cC1jbGllbnQudHMiLCAiLi4vc3JjL2dldC12YXJpYWJsZS1kZWZpbml0aW9ucy50cyJdLAogICJzb3VyY2VzQ29udGVudCI6IFsiZXhwb3J0IHR5cGUgQ2xpQXJnVmFsdWUgPSBzdHJpbmcgfCBib29sZWFuO1xuXG5leHBvcnQgaW50ZXJmYWNlIENsaUFyZ3Mge1xuICBfOiBzdHJpbmdbXTtcbiAgW2tleTogc3RyaW5nXTogQ2xpQXJnVmFsdWUgfCBzdHJpbmdbXTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIHBhcnNlQXJncyhhcmd2OiBzdHJpbmdbXSA9IHByb2Nlc3MuYXJndi5zbGljZSgyKSk6IENsaUFyZ3Mge1xuICBjb25zdCBhcmdzOiBDbGlBcmdzID0geyBfOiBbXSB9O1xuXG4gIGZvciAobGV0IGkgPSAwOyBpIDwgYXJndi5sZW5ndGg7IGkgKz0gMSkge1xuICAgIGNvbnN0IGFyZyA9IGFyZ3ZbaV07XG5cbiAgICBpZiAoIWFyZy5zdGFydHNXaXRoKCctJykgfHwgYXJnID09PSAnLScpIHtcbiAgICAgIGFyZ3MuXy5wdXNoKGFyZyk7XG4gICAgICBjb250aW51ZTtcbiAgICB9XG5cbiAgICBpZiAoYXJnID09PSAnLS0nKSB7XG4gICAgICBjb25zdCByZW1haW5pbmcgPSBhcmd2LnNsaWNlKGkgKyAxKTtcbiAgICAgIGFyZ3MuXy5wdXNoKC4uLnJlbWFpbmluZyk7XG4gICAgICBicmVhaztcbiAgICB9XG5cbiAgICBjb25zdCBbcmF3S2V5LCBpbmxpbmVWYWx1ZV0gPSBhcmcuc3BsaXQoJz0nLCAyKTtcbiAgICBjb25zdCBub3JtYWxpc2VkS2V5ID0gcmF3S2V5LnJlcGxhY2UoL14tKy8sICcnKTtcblxuICAgIGxldCB2YWx1ZTogQ2xpQXJnVmFsdWU7XG4gICAgaWYgKGlubGluZVZhbHVlICE9PSB1bmRlZmluZWQpIHtcbiAgICAgIHZhbHVlID0gaW5saW5lVmFsdWU7XG4gICAgfSBlbHNlIHtcbiAgICAgIGNvbnN0IG5leHQgPSBhcmd2W2kgKyAxXTtcbiAgICAgIGlmIChuZXh0ICE9PSB1bmRlZmluZWQgJiYgIW5leHQuc3RhcnRzV2l0aCgnLScpKSB7XG4gICAgICAgIHZhbHVlID0gbmV4dDtcbiAgICAgICAgaSArPSAxO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgdmFsdWUgPSB0cnVlO1xuICAgICAgfVxuICAgIH1cblxuICAgIGFyZ3Nbbm9ybWFsaXNlZEtleV0gPSB2YWx1ZTtcbiAgfVxuXG4gIHJldHVybiBhcmdzO1xufVxuXG4iLCAiY29uc3QgRklMRV9LRVlfUkVHRVggPSAvZmlnbWFcXC5jb21cXC8oPzpmaWxlfGRlc2lnbilcXC8oW0EtWmEtejAtOV0rKVxcLy9pO1xuXG5leHBvcnQgaW50ZXJmYWNlIFBhcnNlZEZpZ21hVXJsIHtcbiAgZmlsZUtleTogc3RyaW5nIHwgbnVsbDtcbiAgbm9kZUlkOiBzdHJpbmcgfCBudWxsO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gcGFyc2VGaWdtYVVybChpbnB1dDogc3RyaW5nIHwgbnVsbCB8IHVuZGVmaW5lZCk6IFBhcnNlZEZpZ21hVXJsIHtcbiAgaWYgKCFpbnB1dCkgcmV0dXJuIHsgZmlsZUtleTogbnVsbCwgbm9kZUlkOiBudWxsIH07XG4gIHRyeSB7XG4gICAgY29uc3QgdXJsID0gbmV3IFVSTChpbnB1dCk7XG4gICAgY29uc3QgbWF0Y2ggPSB1cmwuaHJlZi5tYXRjaChGSUxFX0tFWV9SRUdFWCk7XG4gICAgY29uc3QgZmlsZUtleSA9IG1hdGNoID8gbWF0Y2hbMV0gOiBudWxsO1xuICAgIGNvbnN0IG5vZGVQYXJhbSA9IHVybC5zZWFyY2hQYXJhbXMuZ2V0KCdub2RlLWlkJyk7XG4gICAgY29uc3Qgbm9kZUlkID0gbm9kZVBhcmFtID8gZW5zdXJlTm9kZUlkKG5vZGVQYXJhbSkgOiBudWxsO1xuICAgIHJldHVybiB7IGZpbGVLZXksIG5vZGVJZCB9O1xuICB9IGNhdGNoIHtcbiAgICByZXR1cm4geyBmaWxlS2V5OiBudWxsLCBub2RlSWQ6IG51bGwgfTtcbiAgfVxufVxuXG5leHBvcnQgZnVuY3Rpb24gZW5zdXJlTm9kZUlkKHZhbHVlOiBzdHJpbmcgfCBudWxsIHwgdW5kZWZpbmVkKTogc3RyaW5nIHwgbnVsbCB7XG4gIGlmICghdmFsdWUpIHJldHVybiBudWxsO1xuICBjb25zdCBkZWNvZGVkID0gZGVjb2RlVVJJQ29tcG9uZW50KHZhbHVlKTtcbiAgaWYgKGRlY29kZWQuaW5jbHVkZXMoJzonKSkgcmV0dXJuIGRlY29kZWQ7XG4gIGlmICgvXlswLTldKy1bMC05XSskLy50ZXN0KGRlY29kZWQpKSB7XG4gICAgY29uc3QgW2xlZnQsIHJpZ2h0XSA9IGRlY29kZWQuc3BsaXQoJy0nLCAyKTtcbiAgICByZXR1cm4gYCR7bGVmdH06JHtyaWdodH1gO1xuICB9XG4gIHJldHVybiBkZWNvZGVkO1xufVxuXG4iLCAiZXhwb3J0IGRlZmF1bHQge1xuICBzY2hlbWFWZXJzaW9uOiAnMS4wLjAnLFxuICBzb3VyY2U6ICdhZ2VudGljLWNvZGluZy10ZW1wbGF0ZXMvZmlnbWEtdG9vbHMnLFxuICBodHRwOiB7XG4gICAgbWF4QXR0ZW1wdHM6IDUsXG4gICAgaW5pdGlhbERlbGF5TXM6IDI1MCxcbiAgfSxcbn0gYXMgY29uc3Q7XG5cbiIsICJpbXBvcnQgY29uZmlnIGZyb20gJy4vY29uZmlnLnRzJztcbmltcG9ydCB0eXBlIHsgVG9vbEVycm9yIH0gZnJvbSAnLi9lcnJvcnMudHMnO1xuXG5leHBvcnQgaW50ZXJmYWNlIFJhdGVMaW1pdE1ldGEge1xuICByZW1haW5pbmc6IG51bWJlciB8IG51bGw7XG4gIHJlc2V0QXQ6IHN0cmluZyB8IG51bGw7XG4gIGF0dGVtcHRzOiBudW1iZXI7XG4gIGxhc3RXYWl0TXM6IG51bWJlcjtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBUb29sRW52ZWxvcGU8XG4gIFRJbnB1dCBleHRlbmRzIFJlY29yZDxzdHJpbmcsIHVua25vd24+ID0gUmVjb3JkPHN0cmluZywgdW5rbm93bj4sXG4gIFREYXRhID0gdW5rbm93blxuPiB7XG4gIHNjaGVtYVZlcnNpb246IHN0cmluZztcbiAgdG9vbDogc3RyaW5nO1xuICBpbnB1dDogVElucHV0O1xuICBtZXRhOiB7XG4gICAgZ2VuZXJhdGVkQXQ6IHN0cmluZztcbiAgICBzb3VyY2U6IHN0cmluZztcbiAgICByYXRlTGltaXQ6IFJhdGVMaW1pdE1ldGE7XG4gIH07XG4gIGRhdGE6IFREYXRhO1xuICB3YXJuaW5nczogc3RyaW5nW107XG4gIGVycm9yczogVG9vbEVycm9yW107XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgQ3JlYXRlRW52ZWxvcGVPcHRpb25zPFxuICBUSW5wdXQgZXh0ZW5kcyBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPiA9IFJlY29yZDxzdHJpbmcsIHVua25vd24+LFxuICBURGF0YSA9IHVua25vd25cbj4ge1xuICB0b29sOiBzdHJpbmc7XG4gIGlucHV0PzogVElucHV0O1xuICBkYXRhPzogVERhdGE7XG4gIHdhcm5pbmdzPzogc3RyaW5nW107XG4gIGVycm9ycz86IFRvb2xFcnJvcltdO1xuICByYXRlTGltaXQ/OiBQYXJ0aWFsPFJhdGVMaW1pdE1ldGE+O1xuICBzY2hlbWFWZXJzaW9uPzogc3RyaW5nO1xufVxuXG5mdW5jdGlvbiBidWlsZFJhdGVMaW1pdE1ldGEocmF0ZUxpbWl0OiBQYXJ0aWFsPFJhdGVMaW1pdE1ldGE+ID0ge30pOiBSYXRlTGltaXRNZXRhIHtcbiAgcmV0dXJuIHtcbiAgICByZW1haW5pbmc6IHJhdGVMaW1pdC5yZW1haW5pbmcgPz8gbnVsbCxcbiAgICByZXNldEF0OiByYXRlTGltaXQucmVzZXRBdCA/PyBudWxsLFxuICAgIGF0dGVtcHRzOiByYXRlTGltaXQuYXR0ZW1wdHMgPz8gMSxcbiAgICBsYXN0V2FpdE1zOiByYXRlTGltaXQubGFzdFdhaXRNcyA/PyAwLFxuICB9O1xufVxuXG5leHBvcnQgZnVuY3Rpb24gY3JlYXRlRW52ZWxvcGU8XG4gIFRJbnB1dCBleHRlbmRzIFJlY29yZDxzdHJpbmcsIHVua25vd24+ID0gUmVjb3JkPHN0cmluZywgdW5rbm93bj4sXG4gIFREYXRhID0gdW5rbm93blxuPih7XG4gIHRvb2wsXG4gIGlucHV0ID0ge30gYXMgVElucHV0LFxuICBkYXRhID0ge30gYXMgVERhdGEsXG4gIHdhcm5pbmdzID0gW10sXG4gIGVycm9ycyA9IFtdLFxuICByYXRlTGltaXQsXG4gIHNjaGVtYVZlcnNpb24sXG59OiBDcmVhdGVFbnZlbG9wZU9wdGlvbnM8VElucHV0LCBURGF0YT4pOiBUb29sRW52ZWxvcGU8VElucHV0LCBURGF0YT4ge1xuICByZXR1cm4ge1xuICAgIHNjaGVtYVZlcnNpb246IHNjaGVtYVZlcnNpb24gPz8gY29uZmlnLnNjaGVtYVZlcnNpb24sXG4gICAgdG9vbCxcbiAgICBpbnB1dCxcbiAgICBtZXRhOiB7XG4gICAgICBnZW5lcmF0ZWRBdDogbmV3IERhdGUoKS50b0lTT1N0cmluZygpLFxuICAgICAgc291cmNlOiBjb25maWcuc291cmNlLFxuICAgICAgcmF0ZUxpbWl0OiBidWlsZFJhdGVMaW1pdE1ldGEocmF0ZUxpbWl0KSxcbiAgICB9LFxuICAgIGRhdGEsXG4gICAgd2FybmluZ3MsXG4gICAgZXJyb3JzLFxuICB9O1xufVxuXG4iLCAiZXhwb3J0IGNvbnN0IEVSUk9SX0VYSVRfQ09ERVMgPSB7XG4gIElOUFVUX0lOVkFMSUQ6IDEsXG4gIENPTkZJR19JTlZBTElEOiAxLFxuICBGSUdNQV9BVVRIOiAxLFxuICBGSUdNQV9OT1RfRk9VTkQ6IDIsXG4gIEZJR01BX1JBVEVfTElNSVQ6IDIsXG4gIE5FVFdPUks6IDIsXG4gIElOVEVSTkFMOiAzLFxufSBhcyBjb25zdDtcblxuZXhwb3J0IHR5cGUgRXJyb3JDb2RlID0ga2V5b2YgdHlwZW9mIEVSUk9SX0VYSVRfQ09ERVM7XG5cbmV4cG9ydCBpbnRlcmZhY2UgVG9vbEVycm9yPFREZXRhaWwgPSB1bmtub3duPiB7XG4gIGNvZGU6IEVycm9yQ29kZSB8IHN0cmluZztcbiAgbWVzc2FnZTogc3RyaW5nO1xuICBkZXRhaWw/OiBURGV0YWlsIHwgbnVsbDtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGNyZWF0ZUVycm9yPFREZXRhaWwgPSB1bmtub3duPihcbiAgY29kZTogRXJyb3JDb2RlIHwgc3RyaW5nLFxuICBtZXNzYWdlOiBzdHJpbmcsXG4gIGRldGFpbD86IFREZXRhaWwgfCBudWxsXG4pOiBUb29sRXJyb3I8VERldGFpbD4ge1xuICByZXR1cm4ge1xuICAgIGNvZGUsXG4gICAgbWVzc2FnZSxcbiAgICBkZXRhaWw6IGRldGFpbCA/PyBudWxsLFxuICB9O1xufVxuXG5leHBvcnQgZnVuY3Rpb24gZ2V0RXhpdENvZGUoZXJyb3JzOiBUb29sRXJyb3JbXSA9IFtdKTogbnVtYmVyIHtcbiAgaWYgKCFlcnJvcnMubGVuZ3RoKSB7XG4gICAgcmV0dXJuIDA7XG4gIH1cblxuICByZXR1cm4gZXJyb3JzLnJlZHVjZSgobWF4LCBlcnJvcikgPT4ge1xuICAgIGNvbnN0IGV4aXRDb2RlID0gRVJST1JfRVhJVF9DT0RFU1tlcnJvci5jb2RlIGFzIEVycm9yQ29kZV0gPz8gMTtcbiAgICByZXR1cm4gTWF0aC5tYXgobWF4LCBleGl0Q29kZSk7XG4gIH0sIDApO1xufVxuXG4iLCAiaW1wb3J0IGNvbmZpZyBmcm9tICcuL2NvbmZpZy50cyc7XG5pbXBvcnQgeyBjcmVhdGVFcnJvciB9IGZyb20gJy4vZXJyb3JzLnRzJztcbmltcG9ydCB0eXBlIHsgVG9vbEVycm9yIH0gZnJvbSAnLi9lcnJvcnMudHMnO1xuaW1wb3J0IHR5cGUgeyBSYXRlTGltaXRNZXRhIH0gZnJvbSAnLi9lbnZlbG9wZS50cyc7XG5cbmNvbnN0IEJBU0VfVVJMID0gJ2h0dHBzOi8vYXBpLmZpZ21hLmNvbSc7XG5cbnR5cGUgU2VhcmNoUGFyYW1zID0gUmVjb3JkPHN0cmluZywgc3RyaW5nIHwgbnVtYmVyIHwgYm9vbGVhbiB8IG51bGwgfCB1bmRlZmluZWQ+O1xuXG5pbnRlcmZhY2UgRmlnbWFSZXF1ZXN0T3B0aW9ucyB7XG4gIHBhdGg6IHN0cmluZztcbiAgbWV0aG9kPzogc3RyaW5nO1xuICB0b2tlbj86IHN0cmluZztcbiAgaGVhZGVycz86IFJlY29yZDxzdHJpbmcsIHN0cmluZz47XG4gIGJvZHk/OiB1bmtub3duO1xuICBzZWFyY2hQYXJhbXM/OiBTZWFyY2hQYXJhbXM7XG4gIG1heEF0dGVtcHRzPzogbnVtYmVyO1xuICBpbml0aWFsRGVsYXlNcz86IG51bWJlcjtcbn1cblxuaW50ZXJmYWNlIEZpZ21hU3VjY2VzczxURGF0YT4ge1xuICBvazogdHJ1ZTtcbiAgZGF0YTogVERhdGE7XG4gIHJhdGVMaW1pdDogUmF0ZUxpbWl0TWV0YTtcbn1cblxuaW50ZXJmYWNlIEZpZ21hRmFpbHVyZSB7XG4gIG9rOiBmYWxzZTtcbiAgZXJyb3I6IFRvb2xFcnJvcjx7IHN0YXR1cz86IG51bWJlciB9PjtcbiAgc3RhdHVzPzogbnVtYmVyIHwgbnVsbDtcbiAgcmF0ZUxpbWl0OiBSYXRlTGltaXRNZXRhIHwgbnVsbDtcbn1cblxuZXhwb3J0IHR5cGUgRmlnbWFSZXNwb25zZTxURGF0YT4gPSBGaWdtYVN1Y2Nlc3M8VERhdGE+IHwgRmlnbWFGYWlsdXJlO1xuXG5mdW5jdGlvbiBzbGVlcChtczogbnVtYmVyKTogUHJvbWlzZTx2b2lkPiB7XG4gIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSkgPT4gc2V0VGltZW91dChyZXNvbHZlLCBtcykpO1xufVxuXG5mdW5jdGlvbiBwYXJzZUpzb25TYWZlbHkodGV4dDogc3RyaW5nKTogdW5rbm93biB7XG4gIHRyeSB7XG4gICAgcmV0dXJuIHRleHQgPyBKU09OLnBhcnNlKHRleHQpIDoge307XG4gIH0gY2F0Y2gge1xuICAgIHJldHVybiB7IHJhdzogdGV4dCB9O1xuICB9XG59XG5cbmZ1bmN0aW9uIHBhcnNlUmF0ZUxpbWl0KGhlYWRlcnM6IEhlYWRlcnMsIGF0dGVtcHRzOiBudW1iZXIsIGxhc3RXYWl0TXM6IG51bWJlcik6IFJhdGVMaW1pdE1ldGEge1xuICBjb25zdCByZW1haW5pbmdIZWFkZXIgPSBoZWFkZXJzLmdldCgneC1yYXRlbGltaXQtcmVtYWluaW5nJyk7XG4gIGNvbnN0IHJlc2V0SGVhZGVyID0gaGVhZGVycy5nZXQoJ3gtcmF0ZWxpbWl0LXJlc2V0Jyk7XG5cbiAgbGV0IHJlbWFpbmluZzogbnVtYmVyIHwgbnVsbCA9IG51bGw7XG4gIGlmIChyZW1haW5pbmdIZWFkZXIgIT09IG51bGwgJiYgcmVtYWluaW5nSGVhZGVyICE9PSB1bmRlZmluZWQpIHtcbiAgICBjb25zdCBwYXJzZWQgPSBOdW1iZXIocmVtYWluaW5nSGVhZGVyKTtcbiAgICByZW1haW5pbmcgPSBOdW1iZXIuaXNOYU4ocGFyc2VkKSA/IG51bGwgOiBwYXJzZWQ7XG4gIH1cblxuICBsZXQgcmVzZXRBdDogc3RyaW5nIHwgbnVsbCA9IG51bGw7XG4gIGlmIChyZXNldEhlYWRlcikge1xuICAgIGNvbnN0IG51bWVyaWNSZXNldCA9IE51bWJlcihyZXNldEhlYWRlcik7XG4gICAgaWYgKCFOdW1iZXIuaXNOYU4obnVtZXJpY1Jlc2V0KSkge1xuICAgICAgcmVzZXRBdCA9IG5ldyBEYXRlKG51bWVyaWNSZXNldCAqIDEwMDApLnRvSVNPU3RyaW5nKCk7XG4gICAgfSBlbHNlIHtcbiAgICAgIGNvbnN0IGRhdGUgPSBuZXcgRGF0ZShyZXNldEhlYWRlcik7XG4gICAgICBpZiAoIU51bWJlci5pc05hTihkYXRlLnZhbHVlT2YoKSkpIHtcbiAgICAgICAgcmVzZXRBdCA9IGRhdGUudG9JU09TdHJpbmcoKTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICByZXR1cm4ge1xuICAgIHJlbWFpbmluZyxcbiAgICByZXNldEF0LFxuICAgIGF0dGVtcHRzLFxuICAgIGxhc3RXYWl0TXMsXG4gIH07XG59XG5cbmZ1bmN0aW9uIGNvbXB1dGVCYWNrb2ZmTXMoYXR0ZW1wdDogbnVtYmVyLCBpbml0aWFsRGVsYXlNczogbnVtYmVyKTogbnVtYmVyIHtcbiAgcmV0dXJuIGluaXRpYWxEZWxheU1zICogMiAqKiAoYXR0ZW1wdCAtIDEpO1xufVxuXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gZmlnbWFSZXF1ZXN0PFREYXRhID0gdW5rbm93bj4oXG4gIG9wdGlvbnM6IEZpZ21hUmVxdWVzdE9wdGlvbnNcbik6IFByb21pc2U8RmlnbWFSZXNwb25zZTxURGF0YT4+IHtcbiAgY29uc3Qge1xuICAgIHBhdGgsXG4gICAgbWV0aG9kID0gJ0dFVCcsXG4gICAgdG9rZW4sXG4gICAgaGVhZGVycyA9IHt9LFxuICAgIGJvZHksXG4gICAgc2VhcmNoUGFyYW1zLFxuICAgIG1heEF0dGVtcHRzID0gY29uZmlnLmh0dHA/Lm1heEF0dGVtcHRzID8/IDUsXG4gICAgaW5pdGlhbERlbGF5TXMgPSBjb25maWcuaHR0cD8uaW5pdGlhbERlbGF5TXMgPz8gMjUwLFxuICB9ID0gb3B0aW9ucztcblxuICBpZiAoIXRva2VuKSB7XG4gICAgcmV0dXJuIHtcbiAgICAgIG9rOiBmYWxzZSxcbiAgICAgIGVycm9yOiBjcmVhdGVFcnJvcignRklHTUFfQVVUSCcsICdGSUdNQV9BQ0NFU1NfVE9LRU4gaXMgbWlzc2luZyBmcm9tIHRoZSBlbnZpcm9ubWVudC4nKSxcbiAgICAgIHN0YXR1czogbnVsbCxcbiAgICAgIHJhdGVMaW1pdDogbnVsbCxcbiAgICB9O1xuICB9XG5cbiAgY29uc3QgdXJsID0gbmV3IFVSTChwYXRoLCBCQVNFX1VSTCk7XG5cbiAgaWYgKHNlYXJjaFBhcmFtcykge1xuICAgIE9iamVjdC5lbnRyaWVzKHNlYXJjaFBhcmFtcykuZm9yRWFjaCgoW2tleSwgdmFsdWVdKSA9PiB7XG4gICAgICBpZiAodmFsdWUgPT09IHVuZGVmaW5lZCB8fCB2YWx1ZSA9PT0gbnVsbCkgcmV0dXJuO1xuICAgICAgdXJsLnNlYXJjaFBhcmFtcy5hcHBlbmQoa2V5LCBTdHJpbmcodmFsdWUpKTtcbiAgICB9KTtcbiAgfVxuXG4gIGxldCBhdHRlbXB0ID0gMDtcbiAgbGV0IGxhc3RXYWl0TXMgPSAwO1xuXG4gIHdoaWxlIChhdHRlbXB0IDwgbWF4QXR0ZW1wdHMpIHtcbiAgICBhdHRlbXB0ICs9IDE7XG5cbiAgICBjb25zdCByZXNwb25zZSA9IGF3YWl0IGZldGNoKHVybCwge1xuICAgICAgbWV0aG9kLFxuICAgICAgaGVhZGVyczoge1xuICAgICAgICAnQ29udGVudC1UeXBlJzogJ2FwcGxpY2F0aW9uL2pzb24nLFxuICAgICAgICAnWC1GaWdtYS1Ub2tlbic6IHRva2VuLFxuICAgICAgICAuLi5oZWFkZXJzLFxuICAgICAgfSxcbiAgICAgIGJvZHk6IGJvZHkgPyBKU09OLnN0cmluZ2lmeShib2R5KSA6IHVuZGVmaW5lZCxcbiAgICB9KTtcblxuICAgIGNvbnN0IHRleHQgPSBhd2FpdCByZXNwb25zZS50ZXh0KCk7XG4gICAgY29uc3QgcGF5bG9hZCA9IHBhcnNlSnNvblNhZmVseSh0ZXh0KSBhcyB7IG1lc3NhZ2U/OiBzdHJpbmcgfTtcbiAgICBjb25zdCByYXRlTGltaXQgPSBwYXJzZVJhdGVMaW1pdChyZXNwb25zZS5oZWFkZXJzLCBhdHRlbXB0LCBsYXN0V2FpdE1zKTtcblxuICAgIGlmIChyZXNwb25zZS5vaykge1xuICAgICAgcmV0dXJuIHsgb2s6IHRydWUsIGRhdGE6IHBheWxvYWQgYXMgVERhdGEsIHJhdGVMaW1pdCB9O1xuICAgIH1cblxuICAgIGNvbnN0IHN0YXR1cyA9IHJlc3BvbnNlLnN0YXR1cztcblxuICAgIGlmIChzdGF0dXMgPT09IDQwMSB8fCBzdGF0dXMgPT09IDQwMykge1xuICAgICAgcmV0dXJuIHsgb2s6IGZhbHNlLCBlcnJvcjogY3JlYXRlRXJyb3IoJ0ZJR01BX0FVVEgnLCBwYXlsb2FkPy5tZXNzYWdlID8/ICdGaWdtYSB0b2tlbiBpcyB1bmF1dGhvcml6ZWQuJywgeyBzdGF0dXMgfSksIHN0YXR1cywgcmF0ZUxpbWl0IH07XG4gICAgfVxuXG4gICAgaWYgKHN0YXR1cyA9PT0gNDA0KSB7XG4gICAgICByZXR1cm4geyBvazogZmFsc2UsIGVycm9yOiBjcmVhdGVFcnJvcignRklHTUFfTk9UX0ZPVU5EJywgcGF5bG9hZD8ubWVzc2FnZSA/PyAnUmVzb3VyY2Ugbm90IGZvdW5kLicsIHsgc3RhdHVzIH0pLCBzdGF0dXMsIHJhdGVMaW1pdCB9O1xuICAgIH1cblxuICAgIGlmIChzdGF0dXMgPT09IDQyOSB8fCBzdGF0dXMgPj0gNTAwKSB7XG4gICAgICBpZiAoYXR0ZW1wdCA+PSBtYXhBdHRlbXB0cykge1xuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgIG9rOiBmYWxzZSxcbiAgICAgICAgICBlcnJvcjogY3JlYXRlRXJyb3Ioc3RhdHVzID09PSA0MjkgPyAnRklHTUFfUkFURV9MSU1JVCcgOiAnTkVUV09SSycsIHBheWxvYWQ/Lm1lc3NhZ2UgPz8gJ0ZpZ21hIHJlcXVlc3QgZmFpbGVkIGFmdGVyIG1heGltdW0gcmV0cmllcy4nLCB7IHN0YXR1cyB9KSxcbiAgICAgICAgICBzdGF0dXMsXG4gICAgICAgICAgcmF0ZUxpbWl0LFxuICAgICAgICB9O1xuICAgICAgfVxuXG4gICAgICBsZXQgd2FpdE1zID0gY29tcHV0ZUJhY2tvZmZNcyhhdHRlbXB0LCBpbml0aWFsRGVsYXlNcyk7XG4gICAgICBjb25zdCByZXNldEhlYWRlciA9IHJlc3BvbnNlLmhlYWRlcnMuZ2V0KCd4LXJhdGVsaW1pdC1yZXNldCcpO1xuICAgICAgaWYgKHJlc2V0SGVhZGVyKSB7XG4gICAgICAgIGNvbnN0IGFzTnVtYmVyID0gTnVtYmVyKHJlc2V0SGVhZGVyKTtcbiAgICAgICAgaWYgKCFOdW1iZXIuaXNOYU4oYXNOdW1iZXIpKSB7XG4gICAgICAgICAgY29uc3QgcmVzZXRNcyA9IGFzTnVtYmVyICogMTAwMDtcbiAgICAgICAgICBjb25zdCBkZWx0YSA9IHJlc2V0TXMgLSBEYXRlLm5vdygpO1xuICAgICAgICAgIGlmIChkZWx0YSA+IDApIHdhaXRNcyA9IE1hdGgubWF4KHdhaXRNcywgZGVsdGEpO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IGppdHRlciA9IE1hdGguZmxvb3IoTWF0aC5yYW5kb20oKSAqIDEwMCk7XG4gICAgICBsYXN0V2FpdE1zID0gd2FpdE1zICsgaml0dGVyO1xuICAgICAgYXdhaXQgc2xlZXAobGFzdFdhaXRNcyk7XG4gICAgICBjb250aW51ZTtcbiAgICB9XG5cbiAgICByZXR1cm4geyBvazogZmFsc2UsIGVycm9yOiBjcmVhdGVFcnJvcignSU5URVJOQUwnLCBwYXlsb2FkPy5tZXNzYWdlID8/ICdVbmV4cGVjdGVkIGVycm9yIGZyb20gRmlnbWEgQVBJLicsIHsgc3RhdHVzIH0pLCBzdGF0dXMsIHJhdGVMaW1pdCB9O1xuICB9XG5cbiAgcmV0dXJuIHtcbiAgICBvazogZmFsc2UsXG4gICAgZXJyb3I6IGNyZWF0ZUVycm9yKCdORVRXT1JLJywgJ1VuYWJsZSB0byByZWFjaCBGaWdtYSBBUEkuJyksXG4gICAgc3RhdHVzOiBudWxsLFxuICAgIHJhdGVMaW1pdDogeyByZW1haW5pbmc6IG51bGwsIHJlc2V0QXQ6IG51bGwsIGF0dGVtcHRzOiBtYXhBdHRlbXB0cywgbGFzdFdhaXRNcyB9LFxuICB9O1xufVxuXG4iLCAiIyEvdXNyL2Jpbi9lbnYgbm9kZVxuXG5pbXBvcnQgeyBwYXJzZUFyZ3MsIHR5cGUgQ2xpQXJncyB9IGZyb20gJy4vX3V0aWxzL2NsaS1hcmdzLnRzJ1xuaW1wb3J0IHsgcGFyc2VGaWdtYVVybCB9IGZyb20gJy4vX3V0aWxzL3VybC1wYXJzZS50cydcbmltcG9ydCB7IGNyZWF0ZUVudmVsb3BlLCB0eXBlIFRvb2xFbnZlbG9wZSB9IGZyb20gJy4vX3V0aWxzL2VudmVsb3BlLnRzJ1xuaW1wb3J0IHsgY3JlYXRlRXJyb3IsIGdldEV4aXRDb2RlLCB0eXBlIFRvb2xFcnJvciB9IGZyb20gJy4vX3V0aWxzL2Vycm9ycy50cydcbmltcG9ydCB7IGZpZ21hUmVxdWVzdCB9IGZyb20gJy4vX3V0aWxzL2h0dHAtY2xpZW50LnRzJ1xuXG5jb25zdCBUT09MX05BTUUgPSAnZ2V0LXZhcmlhYmxlLWRlZmluaXRpb25zJ1xudHlwZSBFbXB0eURhdGEgPSBSZWNvcmQ8c3RyaW5nLCBuZXZlcj5cblxuaW50ZXJmYWNlIFRvb2xJbnB1dCBleHRlbmRzIFJlY29yZDxzdHJpbmcsIHVua25vd24+IHtcbiAgZmlsZUtleTogc3RyaW5nIHwgbnVsbFxuICBpbmNsdWRlU3R5bGVzOiBib29sZWFuXG59XG5cbmludGVyZmFjZSBWYXJpYWJsZU1vZGUgeyBtb2RlSWQ6IHN0cmluZzsgbmFtZTogc3RyaW5nIH1cblxuaW50ZXJmYWNlIFZhcmlhYmxlUGF5bG9hZEVudHJ5IHtcbiAgaWQ6IHN0cmluZ1xuICBuYW1lOiBzdHJpbmdcbiAga2V5Pzogc3RyaW5nXG4gIHJlc29sdmVkVHlwZT86IHN0cmluZ1xuICBjb2xsZWN0aW9uSWQ/OiBzdHJpbmdcbiAgdmFyaWFibGVDb2xsZWN0aW9uSWQ/OiBzdHJpbmdcbiAgdmFyaWFibGVTZXRJZD86IHN0cmluZ1xuICB2YXJpYWJsZUNvbGxlY3Rpb24/OiBzdHJpbmdcbiAgdmFyaWFibGVTZXQ/OiBzdHJpbmdcbiAgc2NvcGVzPzogc3RyaW5nW11cbiAgZGVzY3JpcHRpb24/OiBzdHJpbmdcbiAgZGVmYXVsdE1vZGVJZD86IHN0cmluZ1xuICB2YWx1ZXNCeU1vZGU/OiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPlxuICBtb2Rlcz86IFZhcmlhYmxlTW9kZVtdXG59XG5cbmludGVyZmFjZSBWYXJpYWJsZUNvbGxlY3Rpb25NZXRhIHsgaWQ6IHN0cmluZzsgbmFtZT86IHN0cmluZyB9XG5cbmludGVyZmFjZSBWYXJpYWJsZXNSZXNwb25zZVBheWxvYWQge1xuICBjb2xsZWN0aW9ucz86IFZhcmlhYmxlQ29sbGVjdGlvbk1ldGFbXVxuICB2YXJpYWJsZUNvbGxlY3Rpb25zPzogVmFyaWFibGVDb2xsZWN0aW9uTWV0YVtdXG4gIHZhcmlhYmxlcz86IFZhcmlhYmxlUGF5bG9hZEVudHJ5W11cbn1cblxuaW50ZXJmYWNlIFN0eWxlc1Jlc3BvbnNlUGF5bG9hZCB7IG1ldGE/OiB7IHN0eWxlcz86IFJlY29yZDxzdHJpbmcsIEZpZ21hU3R5bGU+IH07IHN0eWxlcz86IEZpZ21hU3R5bGVbXSB9XG5pbnRlcmZhY2UgRmlnbWFTdHlsZSB7IGtleT86IHN0cmluZzsgbmFtZT86IHN0cmluZzsgc3R5bGVfdHlwZT86IHN0cmluZzsgZGVzY3JpcHRpb24/OiBzdHJpbmcgfVxuXG5pbnRlcmZhY2UgVmFyaWFibGVFbnRyeSB7XG4gIGlkOiBzdHJpbmdcbiAgbmFtZTogc3RyaW5nXG4gIGtleT86IHN0cmluZ1xuICByZXNvbHZlZFR5cGU/OiBzdHJpbmdcbiAgY29sbGVjdGlvbklkOiBzdHJpbmcgfCBudWxsXG4gIGNvbGxlY3Rpb25OYW1lOiBzdHJpbmcgfCBudWxsXG4gIHZhcmlhYmxlU2V0SWQ6IHN0cmluZyB8IG51bGxcbiAgdmFyaWFibGVTZXROYW1lOiBzdHJpbmcgfCBudWxsXG4gIHNjb3Blczogc3RyaW5nW11cbiAgZGVzY3JpcHRpb246IHN0cmluZyB8IG51bGxcbiAgZGVmYXVsdFZhbHVlOiB1bmtub3duXG4gIHZhbHVlc0J5TW9kZTogUmVjb3JkPHN0cmluZywgdW5rbm93bj5cbn1cblxuaW50ZXJmYWNlIFBhcnRpdGlvbmVkVmFyaWFibGVzIHtcbiAgY29sb3JzOiBWYXJpYWJsZUVudHJ5W11cbiAgc3BhY2luZzogVmFyaWFibGVFbnRyeVtdXG4gIHR5cG9ncmFwaHk6IFZhcmlhYmxlRW50cnlbXVxuICBvdGhlcnM6IFZhcmlhYmxlRW50cnlbXVxufVxuXG5pbnRlcmZhY2UgVmFyaWFibGVEYXRhIHtcbiAgZmlsZTogeyBrZXk6IHN0cmluZyB9XG4gIHZhcmlhYmxlczogUGFydGl0aW9uZWRWYXJpYWJsZXNcbiAgcmF3VmFyaWFibGVzOiBWYXJpYWJsZUVudHJ5W11cbiAgc3R5bGVzOiBGaWdtYVN0eWxlW11cbn1cblxuZnVuY3Rpb24gbG9nKG1lc3NhZ2U6IHN0cmluZywgdmVyYm9zZTogYm9vbGVhbik6IHZvaWQge1xuICBpZiAodmVyYm9zZSkgcHJvY2Vzcy5zdGRlcnIud3JpdGUoYFske1RPT0xfTkFNRX1dICR7bWVzc2FnZX1cXG5gKVxufVxuXG5mdW5jdGlvbiB0b09wdGlvbmFsU3RyaW5nKHZhbHVlOiBDbGlBcmdzW3N0cmluZ10pOiBzdHJpbmcgfCBudWxsIHtcbiAgcmV0dXJuIHR5cGVvZiB2YWx1ZSA9PT0gJ3N0cmluZycgJiYgdmFsdWUubGVuZ3RoID4gMCA/IHZhbHVlIDogbnVsbFxufVxuXG5mdW5jdGlvbiBleGl0V2l0aEVudmVsb3BlKFxuICBlbnZlbG9wZTogVG9vbEVudmVsb3BlPFRvb2xJbnB1dCwgVmFyaWFibGVEYXRhIHwgRW1wdHlEYXRhPixcbiAgZXJyb3JzOiBUb29sRXJyb3JbXSA9IFtdXG4pOiBuZXZlciB7XG4gIHByb2Nlc3Muc3Rkb3V0LndyaXRlKGAke0pTT04uc3RyaW5naWZ5KGVudmVsb3BlLCBudWxsLCAyKX1cXG5gKVxuICBwcm9jZXNzLmV4aXQoZ2V0RXhpdENvZGUoZXJyb3JzKSlcbn1cblxuZnVuY3Rpb24gcmVzb2x2ZUNvbGxlY3Rpb25OYW1lKGlkOiBzdHJpbmcgfCB1bmRlZmluZWQsIGNvbGxlY3Rpb25zOiBWYXJpYWJsZUNvbGxlY3Rpb25NZXRhW10pOiBzdHJpbmcgfCBudWxsIHtcbiAgaWYgKCFpZCkgcmV0dXJuIG51bGxcbiAgY29uc3QgZW50cnkgPSBjb2xsZWN0aW9ucy5maW5kKChjKSA9PiBjLmlkID09PSBpZClcbiAgcmV0dXJuIGVudHJ5Py5uYW1lID8/IG51bGxcbn1cblxuZnVuY3Rpb24gYnVpbGRWYXJpYWJsZUVudHJ5KFxuICB2YXJpYWJsZTogVmFyaWFibGVQYXlsb2FkRW50cnksXG4gIGNvbGxlY3Rpb25zOiBWYXJpYWJsZUNvbGxlY3Rpb25NZXRhW10sXG4gIHNldHM6IFZhcmlhYmxlQ29sbGVjdGlvbk1ldGFbXVxuKTogVmFyaWFibGVFbnRyeSB7XG4gIHJldHVybiB7XG4gICAgaWQ6IHZhcmlhYmxlLmlkLFxuICAgIG5hbWU6IHZhcmlhYmxlLm5hbWUsXG4gICAga2V5OiB2YXJpYWJsZS5rZXksXG4gICAgcmVzb2x2ZWRUeXBlOiB2YXJpYWJsZS5yZXNvbHZlZFR5cGUsXG4gICAgY29sbGVjdGlvbklkOiB2YXJpYWJsZS5jb2xsZWN0aW9uSWQgPz8gdmFyaWFibGUudmFyaWFibGVDb2xsZWN0aW9uSWQgPz8gbnVsbCxcbiAgICBjb2xsZWN0aW9uTmFtZTpcbiAgICAgIHJlc29sdmVDb2xsZWN0aW9uTmFtZSh2YXJpYWJsZS5jb2xsZWN0aW9uSWQgPz8gdmFyaWFibGUudmFyaWFibGVDb2xsZWN0aW9uSWQsIGNvbGxlY3Rpb25zKSxcbiAgICB2YXJpYWJsZVNldElkOiB2YXJpYWJsZS52YXJpYWJsZVNldElkID8/IG51bGwsXG4gICAgdmFyaWFibGVTZXROYW1lOiByZXNvbHZlQ29sbGVjdGlvbk5hbWUodmFyaWFibGUudmFyaWFibGVTZXRJZCwgc2V0cyksXG4gICAgc2NvcGVzOiB2YXJpYWJsZS5zY29wZXMgPz8gW10sXG4gICAgZGVzY3JpcHRpb246IHZhcmlhYmxlLmRlc2NyaXB0aW9uID8/IG51bGwsXG4gICAgZGVmYXVsdFZhbHVlOiB2YXJpYWJsZS52YWx1ZXNCeU1vZGU/Llt2YXJpYWJsZS5kZWZhdWx0TW9kZUlkID8/ICcnXSA/PyBudWxsLFxuICAgIHZhbHVlc0J5TW9kZTogdmFyaWFibGUudmFsdWVzQnlNb2RlID8/IHt9LFxuICB9XG59XG5cbmZ1bmN0aW9uIHBhcnRpdGlvblZhcmlhYmxlcyhsaXN0OiBWYXJpYWJsZUVudHJ5W10pOiBQYXJ0aXRpb25lZFZhcmlhYmxlcyB7XG4gIGNvbnN0IGNvbG9yczogVmFyaWFibGVFbnRyeVtdID0gW11cbiAgY29uc3Qgc3BhY2luZzogVmFyaWFibGVFbnRyeVtdID0gW11cbiAgY29uc3QgdHlwb2dyYXBoeTogVmFyaWFibGVFbnRyeVtdID0gW11cbiAgY29uc3Qgb3RoZXJzOiBWYXJpYWJsZUVudHJ5W10gPSBbXVxuICBmb3IgKGNvbnN0IGVudHJ5IG9mIGxpc3QpIHtcbiAgICBzd2l0Y2ggKGVudHJ5LnJlc29sdmVkVHlwZSkge1xuICAgICAgY2FzZSAnQ09MT1InOlxuICAgICAgICBjb2xvcnMucHVzaChlbnRyeSlcbiAgICAgICAgYnJlYWtcbiAgICAgIGNhc2UgJ0ZMT0FUJzpcbiAgICAgICAgc3BhY2luZy5wdXNoKGVudHJ5KVxuICAgICAgICBicmVha1xuICAgICAgY2FzZSAnU1RSSU5HJzpcbiAgICAgIGNhc2UgJ0JPT0xFQU4nOlxuICAgICAgICB0eXBvZ3JhcGh5LnB1c2goZW50cnkpXG4gICAgICAgIGJyZWFrXG4gICAgICBkZWZhdWx0OlxuICAgICAgICBvdGhlcnMucHVzaChlbnRyeSlcbiAgICB9XG4gIH1cbiAgcmV0dXJuIHsgY29sb3JzLCBzcGFjaW5nLCB0eXBvZ3JhcGh5LCBvdGhlcnMgfVxufVxuXG5mdW5jdGlvbiBleHRyYWN0U3R5bGVzKHBheWxvYWQ6IFN0eWxlc1Jlc3BvbnNlUGF5bG9hZCB8IG51bGwgfCB1bmRlZmluZWQpOiBGaWdtYVN0eWxlW10ge1xuICBpZiAoIXBheWxvYWQpIHJldHVybiBbXVxuICBpZiAoQXJyYXkuaXNBcnJheShwYXlsb2FkLnN0eWxlcykpIHJldHVybiBwYXlsb2FkLnN0eWxlc1xuICBpZiAocGF5bG9hZC5tZXRhPy5zdHlsZXMpIHJldHVybiBPYmplY3QudmFsdWVzKHBheWxvYWQubWV0YS5zdHlsZXMpXG4gIHJldHVybiBbXVxufVxuXG5hc3luYyBmdW5jdGlvbiBtYWluKCk6IFByb21pc2U8dm9pZD4ge1xuICBjb25zdCBhcmdzID0gcGFyc2VBcmdzKClcbiAgY29uc3QgdmVyYm9zZSA9IEJvb2xlYW4oYXJncy52ZXJib3NlID8/IGFyZ3MudilcbiAgY29uc3Qgc2NoZW1hVmVyc2lvbiA9IHRvT3B0aW9uYWxTdHJpbmcoYXJnc1snc2NoZW1hLXZlcnNpb24nXSkgPz8gdW5kZWZpbmVkXG5cbiAgY29uc3Qgd2FybmluZ3M6IHN0cmluZ1tdID0gW11cbiAgY29uc3QgZXJyb3JzOiBUb29sRXJyb3JbXSA9IFtdXG5cbiAgY29uc3QgdG9rZW4gPSBwcm9jZXNzLmVudi5GSUdNQV9BQ0NFU1NfVE9LRU5cbiAgaWYgKCF0b2tlbiB8fCAhdG9rZW4udHJpbSgpKSB7XG4gICAgZXJyb3JzLnB1c2goY3JlYXRlRXJyb3IoJ0ZJR01BX0FVVEgnLCAnRklHTUFfQUNDRVNTX1RPS0VOIGlzIHJlcXVpcmVkIGJ1dCB3YXMgbm90IHByb3ZpZGVkLicpKVxuICAgIGNvbnN0IGVudmVsb3BlID0gY3JlYXRlRW52ZWxvcGU8VG9vbElucHV0LCBFbXB0eURhdGE+KHtcbiAgICAgIHRvb2w6IFRPT0xfTkFNRSxcbiAgICAgIGlucHV0OiB7IGZpbGVLZXk6IG51bGwsIGluY2x1ZGVTdHlsZXM6IGZhbHNlIH0sXG4gICAgICB3YXJuaW5ncyxcbiAgICAgIGVycm9ycyxcbiAgICAgIHNjaGVtYVZlcnNpb24sXG4gICAgICBkYXRhOiB7fSBhcyBFbXB0eURhdGEsXG4gICAgfSlcbiAgICBleGl0V2l0aEVudmVsb3BlKGVudmVsb3BlLCBlcnJvcnMpXG4gIH1cblxuICBjb25zdCB1cmxJbnB1dCA9IHRvT3B0aW9uYWxTdHJpbmcoYXJncy51cmwpID8/IHRvT3B0aW9uYWxTdHJpbmcoYXJncy51KVxuICBsZXQgZmlsZUtleSA9IHRvT3B0aW9uYWxTdHJpbmcoYXJnc1snZmlsZS1rZXknXSkgPz8gdW5kZWZpbmVkXG4gIGlmICh1cmxJbnB1dCkge1xuICAgIGNvbnN0IHBhcnNlZCA9IHBhcnNlRmlnbWFVcmwodXJsSW5wdXQpXG4gICAgZmlsZUtleSA9IGZpbGVLZXkgfHwgcGFyc2VkLmZpbGVLZXkgfHwgdW5kZWZpbmVkXG4gIH1cblxuICBjb25zdCBpbmNsdWRlU3R5bGVzID0gYXJnc1snaW5jbHVkZS1zdHlsZXMnXSAhPT0gJ2ZhbHNlJ1xuXG4gIGNvbnN0IGlucHV0OiBUb29sSW5wdXQgPSB7IGZpbGVLZXk6IGZpbGVLZXkgPz8gbnVsbCwgaW5jbHVkZVN0eWxlcyB9XG5cbiAgaWYgKCFmaWxlS2V5KSB7XG4gICAgZXJyb3JzLnB1c2goY3JlYXRlRXJyb3IoJ0lOUFVUX0lOVkFMSUQnLCAnQSB2YWxpZCBGaWdtYSBmaWxlIGtleSBpcyByZXF1aXJlZCAoLS1maWxlLWtleSBvciAtLXVybCkuJykpXG4gIH1cbiAgaWYgKGVycm9ycy5sZW5ndGgpIHtcbiAgICBjb25zdCBlbnZlbG9wZSA9IGNyZWF0ZUVudmVsb3BlPFRvb2xJbnB1dCwgRW1wdHlEYXRhPih7IHRvb2w6IFRPT0xfTkFNRSwgaW5wdXQsIHdhcm5pbmdzLCBlcnJvcnMsIGRhdGE6IHt9IGFzIEVtcHR5RGF0YSwgc2NoZW1hVmVyc2lvbiB9KVxuICAgIGV4aXRXaXRoRW52ZWxvcGUoZW52ZWxvcGUsIGVycm9ycylcbiAgfVxuXG4gIGNvbnN0IHJlc29sdmVkRmlsZUtleSA9IGZpbGVLZXkgYXMgc3RyaW5nXG5cbiAgbG9nKCdGZXRjaGluZyB2YXJpYWJsZXMnLCB2ZXJib3NlKVxuICBjb25zdCB2YXJpYWJsZXNSZXNwb25zZSA9IGF3YWl0IGZpZ21hUmVxdWVzdDxWYXJpYWJsZXNSZXNwb25zZVBheWxvYWQ+KHtcbiAgICBwYXRoOiBgL3YxL2ZpbGVzLyR7cmVzb2x2ZWRGaWxlS2V5fS92YXJpYWJsZXMvbG9jYWxgLFxuICAgIHRva2VuLFxuICB9KVxuXG4gIGxldCBzdHlsZXNSZXNwb25zZTpcbiAgICB8IEF3YWl0ZWQ8UmV0dXJuVHlwZTx0eXBlb2YgZmlnbWFSZXF1ZXN0PFN0eWxlc1Jlc3BvbnNlUGF5bG9hZD4+PlxuICAgIHwgeyBvazogdHJ1ZTsgZGF0YTogU3R5bGVzUmVzcG9uc2VQYXlsb2FkOyByYXRlTGltaXQ6IG51bGwgfVxuXG4gIGlmIChpbmNsdWRlU3R5bGVzKSB7XG4gICAgbG9nKCdGZXRjaGluZyBzdHlsZXMnLCB2ZXJib3NlKVxuICAgIHN0eWxlc1Jlc3BvbnNlID0gYXdhaXQgZmlnbWFSZXF1ZXN0PFN0eWxlc1Jlc3BvbnNlUGF5bG9hZD4oeyBwYXRoOiBgL3YxL2ZpbGVzLyR7cmVzb2x2ZWRGaWxlS2V5fS9zdHlsZXNgLCB0b2tlbiB9KVxuICB9IGVsc2Uge1xuICAgIHN0eWxlc1Jlc3BvbnNlID0geyBvazogdHJ1ZSwgZGF0YTogeyBzdHlsZXM6IFtdIH0sIHJhdGVMaW1pdDogbnVsbCB9XG4gIH1cblxuICBpZiAoIXZhcmlhYmxlc1Jlc3BvbnNlLm9rKSB7XG4gICAgZXJyb3JzLnB1c2godmFyaWFibGVzUmVzcG9uc2UuZXJyb3IgPz8gY3JlYXRlRXJyb3IoJ0lOVEVSTkFMJywgJ0ZhaWxlZCB0byBmZXRjaCB2YXJpYWJsZXMuJykpXG4gICAgY29uc3QgZW52ZWxvcGUgPSBjcmVhdGVFbnZlbG9wZTxUb29sSW5wdXQsIEVtcHR5RGF0YT4oeyB0b29sOiBUT09MX05BTUUsIGlucHV0LCB3YXJuaW5ncywgZXJyb3JzLCByYXRlTGltaXQ6IHZhcmlhYmxlc1Jlc3BvbnNlLnJhdGVMaW1pdCA/PyB1bmRlZmluZWQsIHNjaGVtYVZlcnNpb24sIGRhdGE6IHt9IGFzIEVtcHR5RGF0YSB9KVxuICAgIGV4aXRXaXRoRW52ZWxvcGUoZW52ZWxvcGUsIGVycm9ycylcbiAgfVxuXG4gIGlmICghc3R5bGVzUmVzcG9uc2Uub2spIHtcbiAgICB3YXJuaW5ncy5wdXNoKHN0eWxlc1Jlc3BvbnNlLmVycm9yPy5tZXNzYWdlID8/ICdGYWlsZWQgdG8gZmV0Y2ggc3R5bGVzLicpXG4gIH1cblxuICBjb25zdCB2YXJpYWJsZXNQYXlsb2FkID0gdmFyaWFibGVzUmVzcG9uc2UuZGF0YSA/PyB7fVxuICBjb25zdCB2YXJpYWJsZUNvbGxlY3Rpb25zID0gdmFyaWFibGVzUGF5bG9hZC5jb2xsZWN0aW9ucyA/PyBbXVxuICBjb25zdCB2YXJpYWJsZVNldHMgPSB2YXJpYWJsZXNQYXlsb2FkLnZhcmlhYmxlQ29sbGVjdGlvbnMgPz8gW11cbiAgY29uc3QgdmFyaWFibGVzID0gdmFyaWFibGVzUGF5bG9hZC52YXJpYWJsZXMgPz8gW11cblxuICBjb25zdCBub3JtYWxpc2VkVmFyaWFibGVzID0gdmFyaWFibGVzLm1hcCgodikgPT4gYnVpbGRWYXJpYWJsZUVudHJ5KHYsIHZhcmlhYmxlQ29sbGVjdGlvbnMsIHZhcmlhYmxlU2V0cykpXG4gIGNvbnN0IHBhcnRpdGlvbnMgPSBwYXJ0aXRpb25WYXJpYWJsZXMobm9ybWFsaXNlZFZhcmlhYmxlcylcbiAgY29uc3Qgc3R5bGVzID0gc3R5bGVzUmVzcG9uc2Uub2sgPyBleHRyYWN0U3R5bGVzKHN0eWxlc1Jlc3BvbnNlLmRhdGEpIDogW11cblxuICBjb25zdCBkYXRhOiBWYXJpYWJsZURhdGEgPSB7XG4gICAgZmlsZTogeyBrZXk6IHJlc29sdmVkRmlsZUtleSB9LFxuICAgIHZhcmlhYmxlczogcGFydGl0aW9ucyxcbiAgICByYXdWYXJpYWJsZXM6IG5vcm1hbGlzZWRWYXJpYWJsZXMsXG4gICAgc3R5bGVzLFxuICB9XG5cbiAgY29uc3QgZW52ZWxvcGUgPSBjcmVhdGVFbnZlbG9wZTxUb29sSW5wdXQsIFZhcmlhYmxlRGF0YT4oeyB0b29sOiBUT09MX05BTUUsIGlucHV0LCBkYXRhLCB3YXJuaW5ncywgZXJyb3JzLCByYXRlTGltaXQ6IHZhcmlhYmxlc1Jlc3BvbnNlLnJhdGVMaW1pdCA/PyB1bmRlZmluZWQsIHNjaGVtYVZlcnNpb24gfSlcbiAgcHJvY2Vzcy5zdGRvdXQud3JpdGUoYCR7SlNPTi5zdHJpbmdpZnkoZW52ZWxvcGUsIG51bGwsIDIpfVxcbmApXG4gIHByb2Nlc3MuZXhpdChnZXRFeGl0Q29kZShlcnJvcnMpKVxufVxuXG5tYWluKCkuY2F0Y2goKGVycm9yOiB1bmtub3duKSA9PiB7XG4gIGNvbnN0IG1lc3NhZ2UgPSBlcnJvciBpbnN0YW5jZW9mIEVycm9yID8gZXJyb3IubWVzc2FnZSA6ICdVbmtub3duIGVycm9yJ1xuICBjb25zdCBlbnZlbG9wZSA9IGNyZWF0ZUVudmVsb3BlPFRvb2xJbnB1dCwgRW1wdHlEYXRhPih7IHRvb2w6IFRPT0xfTkFNRSwgaW5wdXQ6IHsgZmlsZUtleTogbnVsbCwgaW5jbHVkZVN0eWxlczogZmFsc2UgfSwgZXJyb3JzOiBbY3JlYXRlRXJyb3IoJ0lOVEVSTkFMJywgbWVzc2FnZSwgeyBzdGFjazogZXJyb3IgaW5zdGFuY2VvZiBFcnJvciA/IGVycm9yLnN0YWNrIDogdW5kZWZpbmVkIH0pXSwgZGF0YToge30gYXMgRW1wdHlEYXRhIH0pXG4gIHByb2Nlc3Muc3Rkb3V0LndyaXRlKGAke0pTT04uc3RyaW5naWZ5KGVudmVsb3BlLCBudWxsLCAyKX1cXG5gKVxuICBwcm9jZXNzLmV4aXQoMylcbn0pXG5cbiJdLAogICJtYXBwaW5ncyI6ICI7OztBQU9PLFNBQVMsVUFBVSxPQUFpQixRQUFRLEtBQUssTUFBTSxDQUFDLEdBQVk7QUFDekUsUUFBTSxPQUFnQixFQUFFLEdBQUcsQ0FBQyxFQUFFO0FBRTlCLFdBQVMsSUFBSSxHQUFHLElBQUksS0FBSyxRQUFRLEtBQUssR0FBRztBQUN2QyxVQUFNLE1BQU0sS0FBSyxDQUFDO0FBRWxCLFFBQUksQ0FBQyxJQUFJLFdBQVcsR0FBRyxLQUFLLFFBQVEsS0FBSztBQUN2QyxXQUFLLEVBQUUsS0FBSyxHQUFHO0FBQ2Y7QUFBQSxJQUNGO0FBRUEsUUFBSSxRQUFRLE1BQU07QUFDaEIsWUFBTSxZQUFZLEtBQUssTUFBTSxJQUFJLENBQUM7QUFDbEMsV0FBSyxFQUFFLEtBQUssR0FBRyxTQUFTO0FBQ3hCO0FBQUEsSUFDRjtBQUVBLFVBQU0sQ0FBQyxRQUFRLFdBQVcsSUFBSSxJQUFJLE1BQU0sS0FBSyxDQUFDO0FBQzlDLFVBQU0sZ0JBQWdCLE9BQU8sUUFBUSxPQUFPLEVBQUU7QUFFOUMsUUFBSTtBQUNKLFFBQUksZ0JBQWdCLFFBQVc7QUFDN0IsY0FBUTtBQUFBLElBQ1YsT0FBTztBQUNMLFlBQU0sT0FBTyxLQUFLLElBQUksQ0FBQztBQUN2QixVQUFJLFNBQVMsVUFBYSxDQUFDLEtBQUssV0FBVyxHQUFHLEdBQUc7QUFDL0MsZ0JBQVE7QUFDUixhQUFLO0FBQUEsTUFDUCxPQUFPO0FBQ0wsZ0JBQVE7QUFBQSxNQUNWO0FBQUEsSUFDRjtBQUVBLFNBQUssYUFBYSxJQUFJO0FBQUEsRUFDeEI7QUFFQSxTQUFPO0FBQ1Q7OztBQzVDQSxJQUFNLGlCQUFpQjtBQU9o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 diff --git a/use-figma/scripts/whoami.mjs b/use-figma/scripts/whoami.mjs new file mode 100755 index 0000000..b92613c --- /dev/null +++ b/use-figma/scripts/whoami.mjs @@ -0,0 +1,276 @@ +#!/usr/bin/env node + +// coding-tools/figma-tools/js/src/_utils/cli-args.ts +function parseArgs(argv = process.argv.slice(2)) { + const args = { _: [] }; + for (let i = 0; i < argv.length; i += 1) { + const arg = argv[i]; + if (!arg.startsWith("-") || arg === "-") { + args._.push(arg); + continue; + } + if (arg === "--") { + const remaining = argv.slice(i + 1); + args._.push(...remaining); + break; + } + const [rawKey, inlineValue] = arg.split("=", 2); + const normalisedKey = rawKey.replace(/^-+/, ""); + let value; + if (inlineValue !== void 0) { + value = inlineValue; + } else { + const next = argv[i + 1]; + if (next !== void 0 && !next.startsWith("-")) { + value = next; + i += 1; + } else { + value = true; + } + } + args[normalisedKey] = value; + } + return args; +} + +// coding-tools/figma-tools/js/src/_utils/config.ts +var config_default = { + schemaVersion: "1.0.0", + source: "agentic-coding-templates/figma-tools", + http: { + maxAttempts: 5, + initialDelayMs: 250 + } +}; + +// coding-tools/figma-tools/js/src/_utils/envelope.ts +function buildRateLimitMeta(rateLimit = {}) { + return { + remaining: rateLimit.remaining ?? null, + resetAt: rateLimit.resetAt ?? null, + attempts: rateLimit.attempts ?? 1, + lastWaitMs: rateLimit.lastWaitMs ?? 0 + }; +} +function createEnvelope({ + tool, + input = {}, + data = {}, + warnings = [], + errors = [], + rateLimit, + schemaVersion +}) { + return { + schemaVersion: schemaVersion ?? config_default.schemaVersion, + tool, + input, + meta: { + generatedAt: (/* @__PURE__ */ new Date()).toISOString(), + source: config_default.source, + rateLimit: buildRateLimitMeta(rateLimit) + }, + data, + warnings, + errors + }; +} + +// coding-tools/figma-tools/js/src/_utils/errors.ts +var ERROR_EXIT_CODES = { + INPUT_INVALID: 1, + CONFIG_INVALID: 1, + FIGMA_AUTH: 1, + FIGMA_NOT_FOUND: 2, + FIGMA_RATE_LIMIT: 2, + NETWORK: 2, + INTERNAL: 3 +}; +function createError(code, message, detail) { + return { + code, + message, + detail: detail ?? null + }; +} +function getExitCode(errors = []) { + if (!errors.length) { + return 0; + } + return errors.reduce((max, error) => { + const exitCode = ERROR_EXIT_CODES[error.code] ?? 1; + return Math.max(max, exitCode); + }, 0); +} + +// coding-tools/figma-tools/js/src/_utils/http-client.ts +var BASE_URL = "https://api.figma.com"; +function sleep(ms) { + return new Promise((resolve) => setTimeout(resolve, ms)); +} +function parseJsonSafely(text) { + try { + return text ? JSON.parse(text) : {}; + } catch { + return { raw: text }; + } +} +function parseRateLimit(headers, attempts, lastWaitMs) { + const remainingHeader = headers.get("x-ratelimit-remaining"); + const resetHeader = headers.get("x-ratelimit-reset"); + let remaining = null; + if (remainingHeader !== null && remainingHeader !== void 0) { + const parsed = Number(remainingHeader); + remaining = Number.isNaN(parsed) ? null : parsed; + } + let resetAt = null; + if (resetHeader) { + const numericReset = Number(resetHeader); + if (!Number.isNaN(numericReset)) { + resetAt = new Date(numericReset * 1e3).toISOString(); + } else { + const date = new Date(resetHeader); + if (!Number.isNaN(date.valueOf())) { + resetAt = date.toISOString(); + } + } + } + return { + remaining, + resetAt, + attempts, + lastWaitMs + }; +} +function computeBackoffMs(attempt, initialDelayMs) { + return initialDelayMs * 2 ** (attempt - 1); +} +async function figmaRequest(options) { + const { + path, + method = "GET", + token, + headers = {}, + body, + searchParams, + maxAttempts = config_default.http?.maxAttempts ?? 5, + initialDelayMs = config_default.http?.initialDelayMs ?? 250 + } = options; + if (!token) { + return { + ok: false, + error: createError("FIGMA_AUTH", "FIGMA_ACCESS_TOKEN is missing from the environment."), + status: null, + rateLimit: null + }; + } + const url = new URL(path, BASE_URL); + if (searchParams) { + Object.entries(searchParams).forEach(([key, value]) => { + if (value === void 0 || value === null) return; + url.searchParams.append(key, String(value)); + }); + } + let attempt = 0; + let lastWaitMs = 0; + while (attempt < maxAttempts) { + attempt += 1; + const response = await fetch(url, { + method, + headers: { + "Content-Type": "application/json", + "X-Figma-Token": token, + ...headers + }, + body: body ? JSON.stringify(body) : void 0 + }); + const text = await response.text(); + const payload = parseJsonSafely(text); + const rateLimit = parseRateLimit(response.headers, attempt, lastWaitMs); + if (response.ok) { + return { ok: true, data: payload, rateLimit }; + } + const status = response.status; + if (status === 401 || status === 403) { + return { ok: false, error: createError("FIGMA_AUTH", payload?.message ?? "Figma token is unauthorized.", { status }), status, rateLimit }; + } + if (status === 404) { + return { ok: false, error: createError("FIGMA_NOT_FOUND", payload?.message ?? "Resource not found.", { status }), status, rateLimit }; + } + if (status === 429 || status >= 500) { + if (attempt >= maxAttempts) { + return { + ok: false, + error: createError(status === 429 ? "FIGMA_RATE_LIMIT" : "NETWORK", payload?.message ?? "Figma request failed after maximum retries.", { status }), + status, + rateLimit + }; + } + let waitMs = computeBackoffMs(attempt, initialDelayMs); + const resetHeader = response.headers.get("x-ratelimit-reset"); + if (resetHeader) { + const asNumber = Number(resetHeader); + if (!Number.isNaN(asNumber)) { + const resetMs = asNumber * 1e3; + const delta = resetMs - Date.now(); + if (delta > 0) waitMs = Math.max(waitMs, delta); + } + } + const jitter = Math.floor(Math.random() * 100); + lastWaitMs = waitMs + jitter; + await sleep(lastWaitMs); + continue; + } + return { ok: false, error: createError("INTERNAL", payload?.message ?? "Unexpected error from Figma API.", { status }), status, rateLimit }; + } + return { + ok: false, + error: createError("NETWORK", "Unable to reach Figma API."), + status: null, + rateLimit: { remaining: null, resetAt: null, attempts: maxAttempts, lastWaitMs } + }; +} + +// coding-tools/figma-tools/js/src/whoami.ts +var TOOL_NAME = "whoami"; +function log(message, verbose) { + if (verbose) process.stderr.write(`[${TOOL_NAME}] ${message} +`); +} +async function main() { + const args = parseArgs(); + const verbose = Boolean(args.verbose ?? args.v); + log("Starting...", verbose); + const warnings = []; + const errors = []; + const token = process.env.FIGMA_ACCESS_TOKEN; + if (!token || !token.trim()) { + errors.push(createError("FIGMA_AUTH", "FIGMA_ACCESS_TOKEN must be set in environment.")); + } + let envelope = createEnvelope({ tool: TOOL_NAME, warnings, errors }); + if (errors.length > 0) { + process.stdout.write(`${JSON.stringify(envelope, null, 2)} +`); + process.exit(getExitCode(errors)); + } + const result = await figmaRequest({ path: "/v1/me", token }); + if (!result.ok) { + errors.push(result.error); + envelope = createEnvelope({ tool: TOOL_NAME, warnings, errors, rateLimit: result.rateLimit ?? void 0 }); + process.stdout.write(`${JSON.stringify(envelope, null, 2)} +`); + process.exit(getExitCode(errors)); + } + envelope = createEnvelope({ tool: TOOL_NAME, data: result.data, warnings, errors, rateLimit: result.rateLimit }); + process.stdout.write(`${JSON.stringify(envelope, null, 2)} +`); + process.exit(0); +} +main().catch((error) => { + const message = error instanceof Error ? error.message : "Unknown error"; + const envelope = createEnvelope({ tool: TOOL_NAME, input: {}, errors: [createError("INTERNAL", message)] }); + process.stdout.write(`${JSON.stringify(envelope, null, 2)} +`); + process.exit(3); +}); +//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiLi4vc3JjL191dGlscy9jbGktYXJncy50cyIsICIuLi9zcmMvX3V0aWxzL2NvbmZpZy50cyIsICIuLi9zcmMvX3V0aWxzL2VudmVsb3BlLnRzIiwgIi4uL3NyYy9fdXRpbHMvZXJyb3JzLnRzIiwgIi4uL3NyYy9fdXRpbHMvaHR0cC1jbGllbnQudHMiLCAiLi4vc3JjL3dob2FtaS50cyJdLAogICJzb3VyY2VzQ29udGVudCI6IFsiZXhwb3J0IHR5cGUgQ2xpQXJnVmFsdWUgPSBzdHJpbmcgfCBib29sZWFuO1xuXG5leHBvcnQgaW50ZXJmYWNlIENsaUFyZ3Mge1xuICBfOiBzdHJpbmdbXTtcbiAgW2tleTogc3RyaW5nXTogQ2xpQXJnVmFsdWUgfCBzdHJpbmdbXTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIHBhcnNlQXJncyhhcmd2OiBzdHJpbmdbXSA9IHByb2Nlc3MuYXJndi5zbGljZSgyKSk6IENsaUFyZ3Mge1xuICBjb25zdCBhcmdzOiBDbGlBcmdzID0geyBfOiBbXSB9O1xuXG4gIGZvciAobGV0IGkgPSAwOyBpIDwgYXJndi5sZW5ndGg7IGkgKz0gMSkge1xuICAgIGNvbnN0IGFyZyA9IGFyZ3ZbaV07XG5cbiAgICBpZiAoIWFyZy5zdGFydHNXaXRoKCctJykgfHwgYXJnID09PSAnLScpIHtcbiAgICAgIGFyZ3MuXy5wdXNoKGFyZyk7XG4gICAgICBjb250aW51ZTtcbiAgICB9XG5cbiAgICBpZiAoYXJnID09PSAnLS0nKSB7XG4gICAgICBjb25zdCByZW1haW5pbmcgPSBhcmd2LnNsaWNlKGkgKyAxKTtcbiAgICAgIGFyZ3MuXy5wdXNoKC4uLnJlbWFpbmluZyk7XG4gICAgICBicmVhaztcbiAgICB9XG5cbiAgICBjb25zdCBbcmF3S2V5LCBpbmxpbmVWYWx1ZV0gPSBhcmcuc3BsaXQoJz0nLCAyKTtcbiAgICBjb25zdCBub3JtYWxpc2VkS2V5ID0gcmF3S2V5LnJlcGxhY2UoL14tKy8sICcnKTtcblxuICAgIGxldCB2YWx1ZTogQ2xpQXJnVmFsdWU7XG4gICAgaWYgKGlubGluZVZhbHVlICE9PSB1bmRlZmluZWQpIHtcbiAgICAgIHZhbHVlID0gaW5saW5lVmFsdWU7XG4gICAgfSBlbHNlIHtcbiAgICAgIGNvbnN0IG5leHQgPSBhcmd2W2kgKyAxXTtcbiAgICAgIGlmIChuZXh0ICE9PSB1bmRlZmluZWQgJiYgIW5leHQuc3RhcnRzV2l0aCgnLScpKSB7XG4gICAgICAgIHZhbHVlID0gbmV4dDtcbiAgICAgICAgaSArPSAxO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgdmFsdWUgPSB0cnVlO1xuICAgICAgfVxuICAgIH1cblxuICAgIGFyZ3Nbbm9ybWFsaXNlZEtleV0gPSB2YWx1ZTtcbiAgfVxuXG4gIHJldHVybiBhcmdzO1xufVxuXG4iLCAiZXhwb3J0IGRlZmF1bHQge1xuICBzY2hlbWFWZXJzaW9uOiAnMS4wLjAnLFxuICBzb3VyY2U6ICdhZ2VudGljLWNvZGluZy10ZW1wbGF0ZXMvZmlnbWEtdG9vbHMnLFxuICBodHRwOiB7XG4gICAgbWF4QXR0ZW1wdHM6IDUsXG4gICAgaW5pdGlhbERlbGF5TXM6IDI1MCxcbiAgfSxcbn0gYXMgY29uc3Q7XG5cbiIsICJpbXBvcnQgY29uZmlnIGZyb20gJy4vY29uZmlnLnRzJztcbmltcG9ydCB0eXBlIHsgVG9vbEVycm9yIH0gZnJvbSAnLi9lcnJvcnMudHMnO1xuXG5leHBvcnQgaW50ZXJmYWNlIFJhdGVMaW1pdE1ldGEge1xuICByZW1haW5pbmc6IG51bWJlciB8IG51bGw7XG4gIHJlc2V0QXQ6IHN0cmluZyB8IG51bGw7XG4gIGF0dGVtcHRzOiBudW1iZXI7XG4gIGxhc3RXYWl0TXM6IG51bWJlcjtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBUb29sRW52ZWxvcGU8XG4gIFRJbnB1dCBleHRlbmRzIFJlY29yZDxzdHJpbmcsIHVua25vd24+ID0gUmVjb3JkPHN0cmluZywgdW5rbm93bj4sXG4gIFREYXRhID0gdW5rbm93blxuPiB7XG4gIHNjaGVtYVZlcnNpb246IHN0cmluZztcbiAgdG9vbDogc3RyaW5nO1xuICBpbnB1dDogVElucHV0O1xuICBtZXRhOiB7XG4gICAgZ2VuZXJhdGVkQXQ6IHN0cmluZztcbiAgICBzb3VyY2U6IHN0cmluZztcbiAgICByYXRlTGltaXQ6IFJhdGVMaW1pdE1ldGE7XG4gIH07XG4gIGRhdGE6IFREYXRhO1xuICB3YXJuaW5nczogc3RyaW5nW107XG4gIGVycm9yczogVG9vbEVycm9yW107XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgQ3JlYXRlRW52ZWxvcGVPcHRpb25zPFxuICBUSW5wdXQgZXh0ZW5kcyBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPiA9IFJlY29yZDxzdHJpbmcsIHVua25vd24+LFxuICBURGF0YSA9IHVua25vd25cbj4ge1xuICB0b29sOiBzdHJpbmc7XG4gIGlucHV0PzogVElucHV0O1xuICBkYXRhPzogVERhdGE7XG4gIHdhcm5pbmdzPzogc3RyaW5nW107XG4gIGVycm9ycz86IFRvb2xFcnJvcltdO1xuICByYXRlTGltaXQ/OiBQYXJ0aWFsPFJhdGVMaW1pdE1ldGE+O1xuICBzY2hlbWFWZXJzaW9uPzogc3RyaW5nO1xufVxuXG5mdW5jdGlvbiBidWlsZFJhdGVMaW1pdE1ldGEocmF0ZUxpbWl0OiBQYXJ0aWFsPFJhdGVMaW1pdE1ldGE+ID0ge30pOiBSYXRlTGltaXRNZXRhIHtcbiAgcmV0dXJuIHtcbiAgICByZW1haW5pbmc6IHJhdGVMaW1pdC5yZW1haW5pbmcgPz8gbnVsbCxcbiAgICByZXNldEF0OiByYXRlTGltaXQucmVzZXRBdCA/PyBudWxsLFxuICAgIGF0dGVtcHRzOiByYXRlTGltaXQuYXR0ZW1wdHMgPz8gMSxcbiAgICBsYXN0V2FpdE1zOiByYXRlTGltaXQubGFzdFdhaXRNcyA/PyAwLFxuICB9O1xufVxuXG5leHBvcnQgZnVuY3Rpb24gY3JlYXRlRW52ZWxvcGU8XG4gIFRJbnB1dCBleHRlbmRzIFJlY29yZDxzdHJpbmcsIHVua25vd24+ID0gUmVjb3JkPHN0cmluZywgdW5rbm93bj4sXG4gIFREYXRhID0gdW5rbm93blxuPih7XG4gIHRvb2wsXG4gIGlucHV0ID0ge30gYXMgVElucHV0LFxuICBkYXRhID0ge30gYXMgVERhdGEsXG4gIHdhcm5pbmdzID0gW10sXG4gIGVycm9ycyA9IFtdLFxuICByYXRlTGltaXQsXG4gIHNjaGVtYVZlcnNpb24sXG59OiBDcmVhdGVFbnZlbG9wZU9wdGlvbnM8VElucHV0LCBURGF0YT4pOiBUb29sRW52ZWxvcGU8VElucHV0LCBURGF0YT4ge1xuICByZXR1cm4ge1xuICAgIHNjaGVtYVZlcnNpb246IHNjaGVtYVZlcnNpb24gPz8gY29uZmlnLnNjaGVtYVZlcnNpb24sXG4gICAgdG9vbCxcbiAgICBpbnB1dCxcbiAgICBtZXRhOiB7XG4gICAgICBnZW5lcmF0ZWRBdDogbmV3IERhdGUoKS50b0lTT1N0cmluZygpLFxuICAgICAgc291cmNlOiBjb25maWcuc291cmNlLFxuICAgICAgcmF0ZUxpbWl0OiBidWlsZFJhdGVMaW1pdE1ldGEocmF0ZUxpbWl0KSxcbiAgICB9LFxuICAgIGRhdGEsXG4gICAgd2FybmluZ3MsXG4gICAgZXJyb3JzLFxuICB9O1xufVxuXG4iLCAiZXhwb3J0IGNvbnN0IEVSUk9SX0VYSVRfQ09ERVMgPSB7XG4gIElOUFVUX0lOVkFMSUQ6IDEsXG4gIENPTkZJR19JTlZBTElEOiAxLFxuICBGSUdNQV9BVVRIOiAxLFxuICBGSUdNQV9OT1RfRk9VTkQ6IDIsXG4gIEZJR01BX1JBVEVfTElNSVQ6IDIsXG4gIE5FVFdPUks6IDIsXG4gIElOVEVSTkFMOiAzLFxufSBhcyBjb25zdDtcblxuZXhwb3J0IHR5cGUgRXJyb3JDb2RlID0ga2V5b2YgdHlwZW9mIEVSUk9SX0VYSVRfQ09ERVM7XG5cbmV4cG9ydCBpbnRlcmZhY2UgVG9vbEVycm9yPFREZXRhaWwgPSB1bmtub3duPiB7XG4gIGNvZGU6IEVycm9yQ29kZSB8IHN0cmluZztcbiAgbWVzc2FnZTogc3RyaW5nO1xuICBkZXRhaWw/OiBURGV0YWlsIHwgbnVsbDtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGNyZWF0ZUVycm9yPFREZXRhaWwgPSB1bmtub3duPihcbiAgY29kZTogRXJyb3JDb2RlIHwgc3RyaW5nLFxuICBtZXNzYWdlOiBzdHJpbmcsXG4gIGRldGFpbD86IFREZXRhaWwgfCBudWxsXG4pOiBUb29sRXJyb3I8VERldGFpbD4ge1xuICByZXR1cm4ge1xuICAgIGNvZGUsXG4gICAgbWVzc2FnZSxcbiAgICBkZXRhaWw6IGRldGFpbCA/PyBudWxsLFxuICB9O1xufVxuXG5leHBvcnQgZnVuY3Rpb24gZ2V0RXhpdENvZGUoZXJyb3JzOiBUb29sRXJyb3JbXSA9IFtdKTogbnVtYmVyIHtcbiAgaWYgKCFlcnJvcnMubGVuZ3RoKSB7XG4gICAgcmV0dXJuIDA7XG4gIH1cblxuICByZXR1cm4gZXJyb3JzLnJlZHVjZSgobWF4LCBlcnJvcikgPT4ge1xuICAgIGNvbnN0IGV4aXRDb2RlID0gRVJST1JfRVhJVF9DT0RFU1tlcnJvci5jb2RlIGFzIEVycm9yQ29kZV0gPz8gMTtcbiAgICByZXR1cm4gTWF0aC5tYXgobWF4LCBleGl0Q29kZSk7XG4gIH0sIDApO1xufVxuXG4iLCAiaW1wb3J0IGNvbmZpZyBmcm9tICcuL2NvbmZpZy50cyc7XG5pbXBvcnQgeyBjcmVhdGVFcnJvciB9IGZyb20gJy4vZXJyb3JzLnRzJztcbmltcG9ydCB0eXBlIHsgVG9vbEVycm9yIH0gZnJvbSAnLi9lcnJvcnMudHMnO1xuaW1wb3J0IHR5cGUgeyBSYXRlTGltaXRNZXRhIH0gZnJvbSAnLi9lbnZlbG9wZS50cyc7XG5cbmNvbnN0IEJBU0VfVVJMID0gJ2h0dHBzOi8vYXBpLmZpZ21hLmNvbSc7XG5cbnR5cGUgU2VhcmNoUGFyYW1zID0gUmVjb3JkPHN0cmluZywgc3RyaW5nIHwgbnVtYmVyIHwgYm9vbGVhbiB8IG51bGwgfCB1bmRlZmluZWQ+O1xuXG5pbnRlcmZhY2UgRmlnbWFSZXF1ZXN0T3B0aW9ucyB7XG4gIHBhdGg6IHN0cmluZztcbiAgbWV0aG9kPzogc3RyaW5nO1xuICB0b2tlbj86IHN0cmluZztcbiAgaGVhZGVycz86IFJlY29yZDxzdHJpbmcsIHN0cmluZz47XG4gIGJvZHk/OiB1bmtub3duO1xuICBzZWFyY2hQYXJhbXM/OiBTZWFyY2hQYXJhbXM7XG4gIG1heEF0dGVtcHRzPzogbnVtYmVyO1xuICBpbml0aWFsRGVsYXlNcz86IG51bWJlcjtcbn1cblxuaW50ZXJmYWNlIEZpZ21hU3VjY2VzczxURGF0YT4ge1xuICBvazogdHJ1ZTtcbiAgZGF0YTogVERhdGE7XG4gIHJhdGVMaW1pdDogUmF0ZUxpbWl0TWV0YTtcbn1cblxuaW50ZXJmYWNlIEZpZ21hRmFpbHVyZSB7XG4gIG9rOiBmYWxzZTtcbiAgZXJyb3I6IFRvb2xFcnJvcjx7IHN0YXR1cz86IG51bWJlciB9PjtcbiAgc3RhdHVzPzogbnVtYmVyIHwgbnVsbDtcbiAgcmF0ZUxpbWl0OiBSYXRlTGltaXRNZXRhIHwgbnVsbDtcbn1cblxuZXhwb3J0IHR5cGUgRmlnbWFSZXNwb25zZTxURGF0YT4gPSBGaWdtYVN1Y2Nlc3M8VERhdGE+IHwgRmlnbWFGYWlsdXJlO1xuXG5mdW5jdGlvbiBzbGVlcChtczogbnVtYmVyKTogUHJvbWlzZTx2b2lkPiB7XG4gIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSkgPT4gc2V0VGltZW91dChyZXNvbHZlLCBtcykpO1xufVxuXG5mdW5jdGlvbiBwYXJzZUpzb25TYWZlbHkodGV4dDogc3RyaW5nKTogdW5rbm93biB7XG4gIHRyeSB7XG4gICAgcmV0dXJuIHRleHQgPyBKU09OLnBhcnNlKHRleHQpIDoge307XG4gIH0gY2F0Y2gge1xuICAgIHJldHVybiB7IHJhdzogdGV4dCB9O1xuICB9XG59XG5cbmZ1bmN0aW9uIHBhcnNlUmF0ZUxpbWl0KGhlYWRlcnM6IEhlYWRlcnMsIGF0dGVtcHRzOiBudW1iZXIsIGxhc3RXYWl0TXM6IG51bWJlcik6IFJhdGVMaW1pdE1ldGEge1xuICBjb25zdCByZW1haW5pbmdIZWFkZXIgPSBoZWFkZXJzLmdldCgneC1yYXRlbGltaXQtcmVtYWluaW5nJyk7XG4gIGNvbnN0IHJlc2V0SGVhZGVyID0gaGVhZGVycy5nZXQoJ3gtcmF0ZWxpbWl0LXJlc2V0Jyk7XG5cbiAgbGV0IHJlbWFpbmluZzogbnVtYmVyIHwgbnVsbCA9IG51bGw7XG4gIGlmIChyZW1haW5pbmdIZWFkZXIgIT09IG51bGwgJiYgcmVtYWluaW5nSGVhZGVyICE9PSB1bmRlZmluZWQpIHtcbiAgICBjb25zdCBwYXJzZWQgPSBOdW1iZXIocmVtYWluaW5nSGVhZGVyKTtcbiAgICByZW1haW5pbmcgPSBOdW1iZXIuaXNOYU4ocGFyc2VkKSA/IG51bGwgOiBwYXJzZWQ7XG4gIH1cblxuICBsZXQgcmVzZXRBdDogc3RyaW5nIHwgbnVsbCA9IG51bGw7XG4gIGlmIChyZXNldEhlYWRlcikge1xuICAgIGNvbnN0IG51bWVyaWNSZXNldCA9IE51bWJlcihyZXNldEhlYWRlcik7XG4gICAgaWYgKCFOdW1iZXIuaXNOYU4obnVtZXJpY1Jlc2V0KSkge1xuICAgICAgcmVzZXRBdCA9IG5ldyBEYXRlKG51bWVyaWNSZXNldCAqIDEwMDApLnRvSVNPU3RyaW5nKCk7XG4gICAgfSBlbHNlIHtcbiAgICAgIGNvbnN0IGRhdGUgPSBuZXcgRGF0ZShyZXNldEhlYWRlcik7XG4gICAgICBpZiAoIU51bWJlci5pc05hTihkYXRlLnZhbHVlT2YoKSkpIHtcbiAgICAgICAgcmVzZXRBdCA9IGRhdGUudG9JU09TdHJpbmcoKTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICByZXR1cm4ge1xuICAgIHJlbWFpbmluZyxcbiAgICByZXNldEF0LFxuICAgIGF0dGVtcHRzLFxuICAgIGxhc3RXYWl0TXMsXG4gIH07XG59XG5cbmZ1bmN0aW9uIGNvbXB1dGVCYWNrb2ZmTXMoYXR0ZW1wdDogbnVtYmVyLCBpbml0aWFsRGVsYXlNczogbnVtYmVyKTogbnVtYmVyIHtcbiAgcmV0dXJuIGluaXRpYWxEZWxheU1zICogMiAqKiAoYXR0ZW1wdCAtIDEpO1xufVxuXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gZmlnbWFSZXF1ZXN0PFREYXRhID0gdW5rbm93bj4oXG4gIG9wdGlvbnM6IEZpZ21hUmVxdWVzdE9wdGlvbnNcbik6IFByb21pc2U8RmlnbWFSZXNwb25zZTxURGF0YT4+IHtcbiAgY29uc3Qge1xuICAgIHBhdGgsXG4gICAgbWV0aG9kID0gJ0dFVCcsXG4gICAgdG9rZW4sXG4gICAgaGVhZGVycyA9IHt9LFxuICAgIGJvZHksXG4gICAgc2VhcmNoUGFyYW1zLFxuICAgIG1heEF0dGVtcHRzID0gY29uZmlnLmh0dHA/Lm1heEF0dGVtcHRzID8/IDUsXG4gICAgaW5pdGlhbERlbGF5TXMgPSBjb25maWcuaHR0cD8uaW5pdGlhbERlbGF5TXMgPz8gMjUwLFxuICB9ID0gb3B0aW9ucztcblxuICBpZiAoIXRva2VuKSB7XG4gICAgcmV0dXJuIHtcbiAgICAgIG9rOiBmYWxzZSxcbiAgICAgIGVycm9yOiBjcmVhdGVFcnJvcignRklHTUFfQVVUSCcsICdGSUdNQV9BQ0NFU1NfVE9LRU4gaXMgbWlzc2luZyBmcm9tIHRoZSBlbnZpcm9ubWVudC4nKSxcbiAgICAgIHN0YXR1czogbnVsbCxcbiAgICAgIHJhdGVMaW1pdDogbnVsbCxcbiAgICB9O1xuICB9XG5cbiAgY29uc3QgdXJsID0gbmV3IFVSTChwYXRoLCBCQVNFX1VSTCk7XG5cbiAgaWYgKHNlYXJjaFBhcmFtcykge1xuICAgIE9iamVjdC5lbnRyaWVzKHNlYXJjaFBhcmFtcykuZm9yRWFjaCgoW2tleSwgdmFsdWVdKSA9PiB7XG4gICAgICBpZiAodmFsdWUgPT09IHVuZGVmaW5lZCB8fCB2YWx1ZSA9PT0gbnVsbCkgcmV0dXJuO1xuICAgICAgdXJsLnNlYXJjaFBhcmFtcy5hcHBlbmQoa2V5LCBTdHJpbmcodmFsdWUpKTtcbiAgICB9KTtcbiAgfVxuXG4gIGxldCBhdHRlbXB0ID0gMDtcbiAgbGV0IGxhc3RXYWl0TXMgPSAwO1xuXG4gIHdoaWxlIChhdHRlbXB0IDwgbWF4QXR0ZW1wdHMpIHtcbiAgICBhdHRlbXB0ICs9IDE7XG5cbiAgICBjb25zdCByZXNwb25zZSA9IGF3YWl0IGZldGNoKHVybCwge1xuICAgICAgbWV0aG9kLFxuICAgICAgaGVhZGVyczoge1xuICAgICAgICAnQ29udGVudC1UeXBlJzogJ2FwcGxpY2F0aW9uL2pzb24nLFxuICAgICAgICAnWC1GaWdtYS1Ub2tlbic6IHRva2VuLFxuICAgICAgICAuLi5oZWFkZXJzLFxuICAgICAgfSxcbiAgICAgIGJvZHk6IGJvZHkgPyBKU09OLnN0cmluZ2lmeShib2R5KSA6IHVuZGVmaW5lZCxcbiAgICB9KTtcblxuICAgIGNvbnN0IHRleHQgPSBhd2FpdCByZXNwb25zZS50ZXh0KCk7XG4gICAgY29uc3QgcGF5bG9hZCA9IHBhcnNlSnNvblNhZmVseSh0ZXh0KSBhcyB7IG1lc3NhZ2U/OiBzdHJpbmcgfTtcbiAgICBjb25zdCByYXRlTGltaXQgPSBwYXJzZVJhdGVMaW1pdChyZXNwb25zZS5oZWFkZXJzLCBhdHRlbXB0LCBsYXN0V2FpdE1zKTtcblxuICAgIGlmIChyZXNwb25zZS5vaykge1xuICAgICAgcmV0dXJuIHsgb2s6IHRydWUsIGRhdGE6IHBheWxvYWQgYXMgVERhdGEsIHJhdGVMaW1pdCB9O1xuICAgIH1cblxuICAgIGNvbnN0IHN0YXR1cyA9IHJlc3BvbnNlLnN0YXR1cztcblxuICAgIGlmIChzdGF0dXMgPT09IDQwMSB8fCBzdGF0dXMgPT09IDQwMykge1xuICAgICAgcmV0dXJuIHsgb2s6IGZhbHNlLCBlcnJvcjogY3JlYXRlRXJyb3IoJ0ZJR01BX0FVVEgnLCBwYXlsb2FkPy5tZXNzYWdlID8/ICdGaWdtYSB0b2tlbiBpcyB1bmF1dGhvcml6ZWQuJywgeyBzdGF0dXMgfSksIHN0YXR1cywgcmF0ZUxpbWl0IH07XG4gICAgfVxuXG4gICAgaWYgKHN0YXR1cyA9PT0gNDA0KSB7XG4gICAgICByZXR1cm4geyBvazogZmFsc2UsIGVycm9yOiBjcmVhdGVFcnJvcignRklHTUFfTk9UX0ZPVU5EJywgcGF5bG9hZD8ubWVzc2FnZSA/PyAnUmVzb3VyY2Ugbm90IGZvdW5kLicsIHsgc3RhdHVzIH0pLCBzdGF0dXMsIHJhdGVMaW1pdCB9O1xuICAgIH1cblxuICAgIGlmIChzdGF0dXMgPT09IDQyOSB8fCBzdGF0dXMgPj0gNTAwKSB7XG4gICAgICBpZiAoYXR0ZW1wdCA+PSBtYXhBdHRlbXB0cykge1xuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgIG9rOiBmYWxzZSxcbiAgICAgICAgICBlcnJvcjogY3JlYXRlRXJyb3Ioc3RhdHVzID09PSA0MjkgPyAnRklHTUFfUkFURV9MSU1JVCcgOiAnTkVUV09SSycsIHBheWxvYWQ/Lm1lc3NhZ2UgPz8gJ0ZpZ21hIHJlcXVlc3QgZmFpbGVkIGFmdGVyIG1heGltdW0gcmV0cmllcy4nLCB7IHN0YXR1cyB9KSxcbiAgICAgICAgICBzdGF0dXMsXG4gICAgICAgICAgcmF0ZUxpbWl0LFxuICAgICAgICB9O1xuICAgICAgfVxuXG4gICAgICBsZXQgd2FpdE1zID0gY29tcHV0ZUJhY2tvZmZNcyhhdHRlbXB0LCBpbml0aWFsRGVsYXlNcyk7XG4gICAgICBjb25zdCByZXNldEhlYWRlciA9IHJlc3BvbnNlLmhlYWRlcnMuZ2V0KCd4LXJhdGVsaW1pdC1yZXNldCcpO1xuICAgICAgaWYgKHJlc2V0SGVhZGVyKSB7XG4gICAgICAgIGNvbnN0IGFzTnVtYmVyID0gTnVtYmVyKHJlc2V0SGVhZGVyKTtcbiAgICAgICAgaWYgKCFOdW1iZXIuaXNOYU4oYXNOdW1iZXIpKSB7XG4gICAgICAgICAgY29uc3QgcmVzZXRNcyA9IGFzTnVtYmVyICogMTAwMDtcbiAgICAgICAgICBjb25zdCBkZWx0YSA9IHJlc2V0TXMgLSBEYXRlLm5vdygpO1xuICAgICAgICAgIGlmIChkZWx0YSA+IDApIHdhaXRNcyA9IE1hdGgubWF4KHdhaXRNcywgZGVsdGEpO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IGppdHRlciA9IE1hdGguZmxvb3IoTWF0aC5yYW5kb20oKSAqIDEwMCk7XG4gICAgICBsYXN0V2FpdE1zID0gd2FpdE1zICsgaml0dGVyO1xuICAgICAgYXdhaXQgc2xlZXAobGFzdFdhaXRNcyk7XG4gICAgICBjb250aW51ZTtcbiAgICB9XG5cbiAgICByZXR1cm4geyBvazogZmFsc2UsIGVycm9yOiBjcmVhdGVFcnJvcignSU5URVJOQUwnLCBwYXlsb2FkPy5tZXNzYWdlID8/ICdVbmV4cGVjdGVkIGVycm9yIGZyb20gRmlnbWEgQVBJLicsIHsgc3RhdHVzIH0pLCBzdGF0dXMsIHJhdGVMaW1pdCB9O1xuICB9XG5cbiAgcmV0dXJuIHtcbiAgICBvazogZmFsc2UsXG4gICAgZXJyb3I6IGNyZWF0ZUVycm9yKCdORVRXT1JLJywgJ1VuYWJsZSB0byByZWFjaCBGaWdtYSBBUEkuJyksXG4gICAgc3RhdHVzOiBudWxsLFxuICAgIHJhdGVMaW1pdDogeyByZW1haW5pbmc6IG51bGwsIHJlc2V0QXQ6IG51bGwsIGF0dGVtcHRzOiBtYXhBdHRlbXB0cywgbGFzdFdhaXRNcyB9LFxuICB9O1xufVxuXG4iLCAiIyEvdXNyL2Jpbi9lbnYgbm9kZVxuaW1wb3J0IHsgcGFyc2VBcmdzLCB0eXBlIENsaUFyZ3MgfSBmcm9tICcuL191dGlscy9jbGktYXJncy50cydcbmltcG9ydCB7IGNyZWF0ZUVudmVsb3BlIH0gZnJvbSAnLi9fdXRpbHMvZW52ZWxvcGUudHMnXG5pbXBvcnQgeyBjcmVhdGVFcnJvciwgZ2V0RXhpdENvZGUsIHR5cGUgVG9vbEVycm9yIH0gZnJvbSAnLi9fdXRpbHMvZXJyb3JzLnRzJ1xuaW1wb3J0IHsgZmlnbWFSZXF1ZXN0IH0gZnJvbSAnLi9fdXRpbHMvaHR0cC1jbGllbnQudHMnXG5cbmNvbnN0IFRPT0xfTkFNRSA9ICd3aG9hbWknXG5cbmludGVyZmFjZSBUb29sSW5wdXQgZXh0ZW5kcyBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPiB7fVxuXG5pbnRlcmZhY2UgV2hvYW1pUmVzcG9uc2Uge1xuICBpZD86IHN0cmluZ1xuICBlbWFpbD86IHN0cmluZ1xuICBoYW5kbGU/OiBzdHJpbmdcbn1cblxuZnVuY3Rpb24gbG9nKG1lc3NhZ2U6IHN0cmluZywgdmVyYm9zZTogYm9vbGVhbik6IHZvaWQge1xuICBpZiAodmVyYm9zZSkgcHJvY2Vzcy5zdGRlcnIud3JpdGUoYFske1RPT0xfTkFNRX1dICR7bWVzc2FnZX1cXG5gKVxufVxuXG5mdW5jdGlvbiB0b09wdGlvbmFsU3RyaW5nKHZhbHVlOiBDbGlBcmdzW3N0cmluZ10pOiBzdHJpbmcgfCBudWxsIHtcbiAgcmV0dXJuIHR5cGVvZiB2YWx1ZSA9PT0gJ3N0cmluZycgJiYgdmFsdWUubGVuZ3RoID4gMCA/IHZhbHVlIDogbnVsbFxufVxuXG5hc3luYyBmdW5jdGlvbiBtYWluKCk6IFByb21pc2U8dm9pZD4ge1xuICBjb25zdCBhcmdzID0gcGFyc2VBcmdzKClcbiAgY29uc3QgdmVyYm9zZSA9IEJvb2xlYW4oYXJncy52ZXJib3NlID8/IGFyZ3MudilcbiAgbG9nKCdTdGFydGluZy4uLicsIHZlcmJvc2UpXG5cbiAgY29uc3Qgd2FybmluZ3M6IHN0cmluZ1tdID0gW11cbiAgY29uc3QgZXJyb3JzOiBUb29sRXJyb3JbXSA9IFtdXG5cbiAgY29uc3QgdG9rZW4gPSBwcm9jZXNzLmVudi5GSUdNQV9BQ0NFU1NfVE9LRU5cbiAgaWYgKCF0b2tlbiB8fCAhdG9rZW4udHJpbSgpKSB7XG4gICAgZXJyb3JzLnB1c2goY3JlYXRlRXJyb3IoJ0ZJR01BX0FVVEgnLCAnRklHTUFfQUNDRVNTX1RPS0VOIG11c3QgYmUgc2V0IGluIGVudmlyb25tZW50LicpKVxuICB9XG5cbiAgbGV0IGVudmVsb3BlID0gY3JlYXRlRW52ZWxvcGU8VG9vbElucHV0Pih7IHRvb2w6IFRPT0xfTkFNRSwgd2FybmluZ3MsIGVycm9ycyB9KVxuICBpZiAoZXJyb3JzLmxlbmd0aCA+IDApIHtcbiAgICBwcm9jZXNzLnN0ZG91dC53cml0ZShgJHtKU09OLnN0cmluZ2lmeShlbnZlbG9wZSwgbnVsbCwgMil9XFxuYClcbiAgICBwcm9jZXNzLmV4aXQoZ2V0RXhpdENvZGUoZXJyb3JzKSlcbiAgfVxuXG4gIGNvbnN0IHJlc3VsdCA9IGF3YWl0IGZpZ21hUmVxdWVzdDxXaG9hbWlSZXNwb25zZT4oeyBwYXRoOiAnL3YxL21lJywgdG9rZW46IHRva2VuIGFzIHN0cmluZyB9KVxuICBpZiAoIXJlc3VsdC5vaykge1xuICAgIGVycm9ycy5wdXNoKHJlc3VsdC5lcnJvcilcbiAgICBlbnZlbG9wZSA9IGNyZWF0ZUVudmVsb3BlKHsgdG9vbDogVE9PTF9OQU1FLCB3YXJuaW5ncywgZXJyb3JzLCByYXRlTGltaXQ6IHJlc3VsdC5yYXRlTGltaXQgPz8gdW5kZWZpbmVkIH0pXG4gICAgcHJvY2Vzcy5zdGRvdXQud3JpdGUoYCR7SlNPTi5zdHJpbmdpZnkoZW52ZWxvcGUsIG51bGwsIDIpfVxcbmApXG4gICAgcHJvY2Vzcy5leGl0KGdldEV4aXRDb2RlKGVycm9ycykpXG4gIH1cblxuICBlbnZlbG9wZSA9IGNyZWF0ZUVudmVsb3BlKHsgdG9vbDogVE9PTF9OQU1FLCBkYXRhOiByZXN1bHQuZGF0YSwgd2FybmluZ3MsIGVycm9ycywgcmF0ZUxpbWl0OiByZXN1bHQucmF0ZUxpbWl0IH0pXG4gIHByb2Nlc3Muc3Rkb3V0LndyaXRlKGAke0pTT04uc3RyaW5naWZ5KGVudmVsb3BlLCBudWxsLCAyKX1cXG5gKVxuICBwcm9jZXNzLmV4aXQoMClcbn1cblxubWFpbigpLmNhdGNoKChlcnJvcjogdW5rbm93bikgPT4ge1xuICBjb25zdCBtZXNzYWdlID0gZXJyb3IgaW5zdGFuY2VvZiBFcnJvciA/IGVycm9yLm1lc3NhZ2UgOiAnVW5rbm93biBlcnJvcidcbiAgY29uc3QgZW52ZWxvcGUgPSBjcmVhdGVFbnZlbG9wZSh7IHRvb2w6IFRPT0xfTkFNRSwgaW5wdXQ6IHt9LCBlcnJvcnM6IFtjcmVhdGVFcnJvcignSU5URVJOQUwnLCBtZXNzYWdlKV0gfSlcbiAgcHJvY2Vzcy5zdGRvdXQud3JpdGUoYCR7SlNPTi5zdHJpbmdpZnkoZW52ZWxvcGUsIG51bGwsIDIpfVxcbmApXG4gIHByb2Nlc3MuZXhpdCgzKVxufSlcblxuIl0sCiAgIm1hcHBpbmdzIjogIjs7O0FBT08sU0FBUyxVQUFVLE9BQWlCLFFBQVEsS0FBSyxNQUFNLENBQUMsR0FBWTtB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