Files

391 lines
51 KiB
JavaScript
Executable File

#!/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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