Files
skills-software-development/figma/scripts/get-design-context.mjs
T

485 lines
58 KiB
JavaScript
Executable File

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