Files
skills-software-development/figma/scripts/get-variable-definitions.mjs
T

405 lines
49 KiB
JavaScript
Executable File

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