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

388 lines
50 KiB
JavaScript
Executable File

#!/usr/bin/env node
// coding-tools/figma-tools/js/src/get-screenshot.ts
import { mkdir, writeFile } from "node:fs/promises";
import path from "node:path";
// coding-tools/figma-tools/js/src/_utils/cli-args.ts
function parseArgs(argv = process.argv.slice(2)) {
const args = { _: [] };
for (let i = 0; i < argv.length; i += 1) {
const arg = argv[i];
if (!arg.startsWith("-") || arg === "-") {
args._.push(arg);
continue;
}
if (arg === "--") {
const remaining = argv.slice(i + 1);
args._.push(...remaining);
break;
}
const [rawKey, inlineValue] = arg.split("=", 2);
const normalisedKey = rawKey.replace(/^-+/, "");
let value;
if (inlineValue !== void 0) {
value = inlineValue;
} else {
const next = argv[i + 1];
if (next !== void 0 && !next.startsWith("-")) {
value = next;
i += 1;
} else {
value = true;
}
}
args[normalisedKey] = value;
}
return args;
}
// coding-tools/figma-tools/js/src/_utils/url-parse.ts
var FILE_KEY_REGEX = /figma\.com\/(?:file|design)\/([A-Za-z0-9]+)\//i;
function parseFigmaUrl(input) {
if (!input) return { fileKey: null, nodeId: null };
try {
const url = new URL(input);
const match = url.href.match(FILE_KEY_REGEX);
const fileKey = match ? match[1] : null;
const nodeParam = url.searchParams.get("node-id");
const nodeId = nodeParam ? ensureNodeId(nodeParam) : null;
return { fileKey, nodeId };
} catch {
return { fileKey: null, nodeId: null };
}
}
function ensureNodeId(value) {
if (!value) return null;
const decoded = decodeURIComponent(value);
if (decoded.includes(":")) return decoded;
if (/^[0-9]+-[0-9]+$/.test(decoded)) {
const [left, right] = decoded.split("-", 2);
return `${left}:${right}`;
}
return decoded;
}
// coding-tools/figma-tools/js/src/_utils/config.ts
var config_default = {
schemaVersion: "1.0.0",
source: "agentic-coding-templates/figma-tools",
http: {
maxAttempts: 5,
initialDelayMs: 250
}
};
// coding-tools/figma-tools/js/src/_utils/envelope.ts
function buildRateLimitMeta(rateLimit = {}) {
return {
remaining: rateLimit.remaining ?? null,
resetAt: rateLimit.resetAt ?? null,
attempts: rateLimit.attempts ?? 1,
lastWaitMs: rateLimit.lastWaitMs ?? 0
};
}
function createEnvelope({
tool,
input = {},
data = {},
warnings = [],
errors = [],
rateLimit,
schemaVersion
}) {
return {
schemaVersion: schemaVersion ?? config_default.schemaVersion,
tool,
input,
meta: {
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
source: config_default.source,
rateLimit: buildRateLimitMeta(rateLimit)
},
data,
warnings,
errors
};
}
// coding-tools/figma-tools/js/src/_utils/errors.ts
var ERROR_EXIT_CODES = {
INPUT_INVALID: 1,
CONFIG_INVALID: 1,
FIGMA_AUTH: 1,
FIGMA_NOT_FOUND: 2,
FIGMA_RATE_LIMIT: 2,
NETWORK: 2,
INTERNAL: 3
};
function createError(code, message, detail) {
return {
code,
message,
detail: detail ?? null
};
}
function getExitCode(errors = []) {
if (!errors.length) {
return 0;
}
return errors.reduce((max, error) => {
const exitCode = ERROR_EXIT_CODES[error.code] ?? 1;
return Math.max(max, exitCode);
}, 0);
}
// coding-tools/figma-tools/js/src/_utils/http-client.ts
var BASE_URL = "https://api.figma.com";
function sleep(ms) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
function parseJsonSafely(text) {
try {
return text ? JSON.parse(text) : {};
} catch {
return { raw: text };
}
}
function parseRateLimit(headers, attempts, lastWaitMs) {
const remainingHeader = headers.get("x-ratelimit-remaining");
const resetHeader = headers.get("x-ratelimit-reset");
let remaining = null;
if (remainingHeader !== null && remainingHeader !== void 0) {
const parsed = Number(remainingHeader);
remaining = Number.isNaN(parsed) ? null : parsed;
}
let resetAt = null;
if (resetHeader) {
const numericReset = Number(resetHeader);
if (!Number.isNaN(numericReset)) {
resetAt = new Date(numericReset * 1e3).toISOString();
} else {
const date = new Date(resetHeader);
if (!Number.isNaN(date.valueOf())) {
resetAt = date.toISOString();
}
}
}
return {
remaining,
resetAt,
attempts,
lastWaitMs
};
}
function computeBackoffMs(attempt, initialDelayMs) {
return initialDelayMs * 2 ** (attempt - 1);
}
async function figmaRequest(options) {
const {
path: path2,
method = "GET",
token,
headers = {},
body,
searchParams,
maxAttempts = config_default.http?.maxAttempts ?? 5,
initialDelayMs = config_default.http?.initialDelayMs ?? 250
} = options;
if (!token) {
return {
ok: false,
error: createError("FIGMA_AUTH", "FIGMA_ACCESS_TOKEN is missing from the environment."),
status: null,
rateLimit: null
};
}
const url = new URL(path2, BASE_URL);
if (searchParams) {
Object.entries(searchParams).forEach(([key, value]) => {
if (value === void 0 || value === null) return;
url.searchParams.append(key, String(value));
});
}
let attempt = 0;
let lastWaitMs = 0;
while (attempt < maxAttempts) {
attempt += 1;
const response = await fetch(url, {
method,
headers: {
"Content-Type": "application/json",
"X-Figma-Token": token,
...headers
},
body: body ? JSON.stringify(body) : void 0
});
const text = await response.text();
const payload = parseJsonSafely(text);
const rateLimit = parseRateLimit(response.headers, attempt, lastWaitMs);
if (response.ok) {
return { ok: true, data: payload, rateLimit };
}
const status = response.status;
if (status === 401 || status === 403) {
return { ok: false, error: createError("FIGMA_AUTH", payload?.message ?? "Figma token is unauthorized.", { status }), status, rateLimit };
}
if (status === 404) {
return { ok: false, error: createError("FIGMA_NOT_FOUND", payload?.message ?? "Resource not found.", { status }), status, rateLimit };
}
if (status === 429 || status >= 500) {
if (attempt >= maxAttempts) {
return {
ok: false,
error: createError(status === 429 ? "FIGMA_RATE_LIMIT" : "NETWORK", payload?.message ?? "Figma request failed after maximum retries.", { status }),
status,
rateLimit
};
}
let waitMs = computeBackoffMs(attempt, initialDelayMs);
const resetHeader = response.headers.get("x-ratelimit-reset");
if (resetHeader) {
const asNumber = Number(resetHeader);
if (!Number.isNaN(asNumber)) {
const resetMs = asNumber * 1e3;
const delta = resetMs - Date.now();
if (delta > 0) waitMs = Math.max(waitMs, delta);
}
}
const jitter = Math.floor(Math.random() * 100);
lastWaitMs = waitMs + jitter;
await sleep(lastWaitMs);
continue;
}
return { ok: false, error: createError("INTERNAL", payload?.message ?? "Unexpected error from Figma API.", { status }), status, rateLimit };
}
return {
ok: false,
error: createError("NETWORK", "Unable to reach Figma API."),
status: null,
rateLimit: { remaining: null, resetAt: null, attempts: maxAttempts, lastWaitMs }
};
}
// coding-tools/figma-tools/js/src/get-screenshot.ts
var TOOL_NAME = "get-screenshot";
var SUPPORTED_FORMATS = ["png", "jpg", "jpeg", "svg"];
var SCREENSHOT_DIR = ".tmp/figma-tools/screenshots";
function log(message, verbose) {
if (verbose) process.stderr.write(`[${TOOL_NAME}] ${message}
`);
}
function toOptionalString(value) {
return typeof value === "string" && value.length > 0 ? value : null;
}
function exitWithEnvelope(envelope, errors = []) {
process.stdout.write(`${JSON.stringify(envelope, null, 2)}
`);
process.exit(getExitCode(errors));
}
async function ensureDirExists(dirPath) {
await mkdir(dirPath, { recursive: true });
}
async function main() {
const args = parseArgs();
const verbose = Boolean(args.verbose ?? args.v);
const schemaVersion = toOptionalString(args["schema-version"]) ?? void 0;
const warnings = [];
const errors = [];
const token = process.env.FIGMA_ACCESS_TOKEN;
if (!token || !token.trim()) {
errors.push(createError("FIGMA_AUTH", "FIGMA_ACCESS_TOKEN is required but was not provided."));
const envelope2 = createEnvelope({ tool: TOOL_NAME, input: { fileKey: null, nodeId: null, format: "jpg", scale: 1, bounds: "selection", background: "canvas" }, warnings, errors, schemaVersion, data: {} });
exitWithEnvelope(envelope2, errors);
}
const urlInput = toOptionalString(args.url) ?? toOptionalString(args.u);
let fileKey = toOptionalString(args["file-key"]) ?? void 0;
let nodeId = ensureNodeId(toOptionalString(args["node-id"]));
if (urlInput) {
const parsed = parseFigmaUrl(urlInput);
fileKey = fileKey || parsed.fileKey || void 0;
nodeId = nodeId || parsed.nodeId;
}
if (!fileKey) errors.push(createError("INPUT_INVALID", "A valid Figma file key is required (--file-key or --url)."));
if (!nodeId) errors.push(createError("INPUT_INVALID", "A valid Figma node id is required (--node-id or --url with node-id)."));
let format = String(args.format ?? "jpg").toLowerCase();
if (!SUPPORTED_FORMATS.includes(format)) {
warnings.push(`Unsupported format "${format}". Falling back to jpg.`);
format = "jpg";
}
if (format === "jpeg") format = "jpg";
const scaleInput = Number(args.scale ?? 1);
const scale = Number.isFinite(scaleInput) ? Math.min(Math.max(scaleInput, 0.01), 1) : 1;
const boundsInput = String(args.bounds ?? "selection").toLowerCase();
const bounds = ["selection", "frame", "node"].includes(boundsInput) ? boundsInput : "selection";
const useAbsoluteBounds = bounds === "frame";
const backgroundInput = String(args.background ?? "canvas").toLowerCase();
let backgroundParam;
if (backgroundInput === "transparent") backgroundParam = "00000000";
else if (/^[0-9a-f]{6,8}$/i.test(backgroundInput)) {
const value = backgroundInput.toUpperCase();
backgroundParam = value.length >= 6 ? value.slice(0, 8).padEnd(8, "F") : void 0;
} else if (backgroundInput.startsWith("#")) backgroundParam = backgroundInput.replace("#", "").slice(0, 8).padEnd(8, "F");
const input = { fileKey: fileKey ?? null, nodeId: nodeId ?? null, format, scale, bounds, background: backgroundInput };
if (errors.length) {
const envelope2 = createEnvelope({ tool: TOOL_NAME, input, warnings, errors, data: {}, schemaVersion });
exitWithEnvelope(envelope2, errors);
}
const resolvedFileKey = fileKey;
const resolvedNodeId = nodeId;
log(`Requesting image for ${resolvedNodeId} (${format}, scale ${scale})`, verbose);
const imageResponse = await figmaRequest({
path: `/v1/images/${resolvedFileKey}`,
token,
searchParams: { ids: resolvedNodeId, format, scale, use_absolute_bounds: useAbsoluteBounds ? "true" : void 0, background: backgroundParam }
});
if (!imageResponse.ok) {
errors.push(imageResponse.error ?? createError("INTERNAL", "Failed to request image export."));
const envelope2 = createEnvelope({ tool: TOOL_NAME, input, warnings, errors, rateLimit: imageResponse.rateLimit ?? void 0, data: {}, schemaVersion });
exitWithEnvelope(envelope2, errors);
}
const imageUrl = imageResponse.data?.images?.[resolvedNodeId];
if (!imageUrl) {
errors.push(createError("FIGMA_NOT_FOUND", "Figma did not return an image URL for the requested node."));
const envelope2 = createEnvelope({ tool: TOOL_NAME, input, warnings, errors, rateLimit: imageResponse.rateLimit ?? void 0, data: {}, schemaVersion });
exitWithEnvelope(envelope2, errors);
}
log("Downloading image", verbose);
let buffer = null;
let contentType = null;
try {
const res = await fetch(imageUrl);
if (!res.ok) errors.push(createError("NETWORK", `Unable to download image (status ${res.status}).`));
else {
contentType = res.headers.get("content-type");
buffer = format === "svg" ? Buffer.from(await res.text()) : Buffer.from(await res.arrayBuffer());
}
} catch (error) {
const message = error instanceof Error ? error.message : "Unknown download error";
errors.push(createError("NETWORK", `Unable to download image: ${message}`));
}
if (!buffer || errors.length) {
const envelope2 = createEnvelope({ tool: TOOL_NAME, input, warnings, errors, rateLimit: imageResponse.rateLimit ?? void 0, data: {}, schemaVersion });
exitWithEnvelope(envelope2, errors);
}
const sanitizedNodeId = resolvedNodeId.replace(/[^a-zA-Z0-9-_]/g, "_");
const baseDir = path.resolve(SCREENSHOT_DIR, resolvedFileKey);
await ensureDirExists(baseDir);
const extension = format === "jpg" ? "jpg" : format;
const filePath = path.join(baseDir, `${sanitizedNodeId}.${extension}`);
await writeFile(filePath, buffer);
const data = {
file: { key: resolvedFileKey, nodeId: resolvedNodeId },
screenshot: { path: filePath, url: imageUrl, format: extension, scale, bounds, background: backgroundInput, contentType }
};
const envelope = createEnvelope({ tool: TOOL_NAME, input, data, warnings, errors, rateLimit: imageResponse.rateLimit ?? void 0, schemaVersion });
process.stdout.write(`${JSON.stringify(envelope, null, 2)}
`);
process.exit(getExitCode(errors));
}
main().catch((error) => {
const message = error instanceof Error ? error.message : "Unknown error";
const envelope = createEnvelope({ tool: TOOL_NAME, input: { fileKey: null, nodeId: null, format: "jpg", scale: 1, bounds: "selection", background: "canvas" }, errors: [createError("INTERNAL", message, { stack: error instanceof Error ? error.stack : void 0 })], data: {} });
process.stdout.write(`${JSON.stringify(envelope, null, 2)}
`);
process.exit(3);
});
//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiLi4vc3JjL2dldC1zY3JlZW5zaG90LnRzIiwgIi4uL3NyYy9fdXRpbHMvY2xpLWFyZ3MudHMiLCAiLi4vc3JjL191dGlscy91cmwtcGFyc2UudHMiLCAiLi4vc3JjL191dGlscy9jb25maWcudHMiLCAiLi4vc3JjL191dGlscy9lbnZlbG9wZS50cyIsICIuLi9zcmMvX3V0aWxzL2Vycm9ycy50cyIsICIuLi9zcmMvX3V0aWxzL2h0dHAtY2xpZW50LnRzIl0sCiAgInNvdXJjZXNDb250ZW50IjogWyIjIS91c3IvYmluL2VudiBub2RlXG5cbmltcG9ydCB7IG1rZGlyLCB3cml0ZUZpbGUgfSBmcm9tICdub2RlOmZzL3Byb21pc2VzJ1xuaW1wb3J0IHBhdGggZnJvbSAnbm9kZTpwYXRoJ1xuaW1wb3J0IHsgcGFyc2VBcmdzLCB0eXBlIENsaUFyZ3MgfSBmcm9tICcuL191dGlscy9jbGktYXJncy50cydcbmltcG9ydCB7IHBhcnNlRmlnbWFVcmwsIGVuc3VyZU5vZGVJZCB9IGZyb20gJy4vX3V0aWxzL3VybC1wYXJzZS50cydcbmltcG9ydCB7IGNyZWF0ZUVudmVsb3BlLCB0eXBlIFRvb2xFbnZlbG9wZSB9IGZyb20gJy4vX3V0aWxzL2VudmVsb3BlLnRzJ1xuaW1wb3J0IHsgY3JlYXRlRXJyb3IsIGdldEV4aXRDb2RlLCB0eXBlIFRvb2xFcnJvciB9IGZyb20gJy4vX3V0aWxzL2Vycm9ycy50cydcbmltcG9ydCB7IGZpZ21hUmVxdWVzdCB9IGZyb20gJy4vX3V0aWxzL2h0dHAtY2xpZW50LnRzJ1xuXG5jb25zdCBUT09MX05BTUUgPSAnZ2V0LXNjcmVlbnNob3QnXG5jb25zdCBTVVBQT1JURURfRk9STUFUUyA9IFsncG5nJywgJ2pwZycsICdqcGVnJywgJ3N2ZyddXG5jb25zdCBTQ1JFRU5TSE9UX0RJUiA9ICcudG1wL2ZpZ21hLXRvb2xzL3NjcmVlbnNob3RzJ1xudHlwZSBFbXB0eURhdGEgPSBSZWNvcmQ8c3RyaW5nLCBuZXZlcj5cblxuaW50ZXJmYWNlIFRvb2xJbnB1dCBleHRlbmRzIFJlY29yZDxzdHJpbmcsIHVua25vd24+IHtcbiAgZmlsZUtleTogc3RyaW5nIHwgbnVsbFxuICBub2RlSWQ6IHN0cmluZyB8IG51bGxcbiAgZm9ybWF0OiBzdHJpbmdcbiAgc2NhbGU6IG51bWJlclxuICBib3VuZHM6IHN0cmluZ1xuICBiYWNrZ3JvdW5kOiBzdHJpbmdcbn1cblxuaW50ZXJmYWNlIEltYWdlRXhwb3J0UmVzcG9uc2UgeyBpbWFnZXM/OiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+IH1cblxuaW50ZXJmYWNlIFNjcmVlbnNob3REYXRhIHtcbiAgZmlsZTogeyBrZXk6IHN0cmluZzsgbm9kZUlkOiBzdHJpbmcgfVxuICBzY3JlZW5zaG90OiB7XG4gICAgcGF0aDogc3RyaW5nXG4gICAgdXJsOiBzdHJpbmdcbiAgICBmb3JtYXQ6IHN0cmluZ1xuICAgIHNjYWxlOiBudW1iZXJcbiAgICBib3VuZHM6IHN0cmluZ1xuICAgIGJhY2tncm91bmQ6IHN0cmluZ1xuICAgIGNvbnRlbnRUeXBlOiBzdHJpbmcgfCBudWxsXG4gIH1cbn1cblxuZnVuY3Rpb24gbG9nKG1lc3NhZ2U6IHN0cmluZywgdmVyYm9zZTogYm9vbGVhbik6IHZvaWQge1xuICBpZiAodmVyYm9zZSkgcHJvY2Vzcy5zdGRlcnIud3JpdGUoYFske1RPT0xfTkFNRX1dICR7bWVzc2FnZX1cXG5gKVxufVxuXG5mdW5jdGlvbiB0b09wdGlvbmFsU3RyaW5nKHZhbHVlOiBDbGlBcmdzW3N0cmluZ10pOiBzdHJpbmcgfCBudWxsIHtcbiAgcmV0dXJuIHR5cGVvZiB2YWx1ZSA9PT0gJ3N0cmluZycgJiYgdmFsdWUubGVuZ3RoID4gMCA/IHZhbHVlIDogbnVsbFxufVxuXG5mdW5jdGlvbiBleGl0V2l0aEVudmVsb3BlKFxuICBlbnZlbG9wZTogVG9vbEVudmVsb3BlPFRvb2xJbnB1dCwgU2NyZWVuc2hvdERhdGEgfCBFbXB0eURhdGE+LFxuICBlcnJvcnM6IFRvb2xFcnJvcltdID0gW11cbik6IG5ldmVyIHtcbiAgcHJvY2Vzcy5zdGRvdXQud3JpdGUoYCR7SlNPTi5zdHJpbmdpZnkoZW52ZWxvcGUsIG51bGwsIDIpfVxcbmApXG4gIHByb2Nlc3MuZXhpdChnZXRFeGl0Q29kZShlcnJvcnMpKVxufVxuXG5hc3luYyBmdW5jdGlvbiBlbnN1cmVEaXJFeGlzdHMoZGlyUGF0aDogc3RyaW5nKTogUHJvbWlzZTx2b2lkPiB7IGF3YWl0IG1rZGlyKGRpclBhdGgsIHsgcmVjdXJzaXZlOiB0cnVlIH0pIH1cblxuYXN5bmMgZnVuY3Rpb24gbWFpbigpOiBQcm9taXNlPHZvaWQ+IHtcbiAgY29uc3QgYXJncyA9IHBhcnNlQXJncygpXG4gIGNvbnN0IHZlcmJvc2UgPSBCb29sZWFuKGFyZ3MudmVyYm9zZSA/PyBhcmdzLnYpXG4gIGNvbnN0IHNjaGVtYVZlcnNpb24gPSB0b09wdGlvbmFsU3RyaW5nKGFyZ3NbJ3NjaGVtYS12ZXJzaW9uJ10pID8/IHVuZGVmaW5lZFxuXG4gIGNvbnN0IHdhcm5pbmdzOiBzdHJpbmdbXSA9IFtdXG4gIGNvbnN0IGVycm9yczogVG9vbEVycm9yW10gPSBbXVxuXG4gIGNvbnN0IHRva2VuID0gcHJvY2Vzcy5lbnYuRklHTUFfQUNDRVNTX1RPS0VOXG4gIGlmICghdG9rZW4gfHwgIXRva2VuLnRyaW0oKSkge1xuICAgIGVycm9ycy5wdXNoKGNyZWF0ZUVycm9yKCdGSUdNQV9BVVRIJywgJ0ZJR01BX0FDQ0VTU19UT0tFTiBpcyByZXF1aXJlZCBidXQgd2FzIG5vdCBwcm92aWRlZC4nKSlcbiAgICBjb25zdCBlbnZlbG9wZSA9IGNyZWF0ZUVudmVsb3BlPFRvb2xJbnB1dCwgRW1wdHlEYXRhPih7IHRvb2w6IFRPT0xfTkFNRSwgaW5wdXQ6IHsgZmlsZUtleTogbnVsbCwgbm9kZUlkOiBudWxsLCBmb3JtYXQ6ICdqcGcnLCBzY2FsZTogMSwgYm91bmRzOiAnc2VsZWN0aW9uJywgYmFja2dyb3VuZDogJ2NhbnZhcycgfSwgd2FybmluZ3MsIGVycm9ycywgc2NoZW1hVmVyc2lvbiwgZGF0YToge30gYXMgRW1wdHlEYXRhIH0pXG4gICAgZXhpdFdpdGhFbnZlbG9wZShlbnZlbG9wZSwgZXJyb3JzKVxuICB9XG5cbiAgY29uc3QgdXJsSW5wdXQgPSB0b09wdGlvbmFsU3RyaW5nKGFyZ3MudXJsKSA/PyB0b09wdGlvbmFsU3RyaW5nKGFyZ3MudSlcbiAgbGV0IGZpbGVLZXkgPSB0b09wdGlvbmFsU3RyaW5nKGFyZ3NbJ2ZpbGUta2V5J10pID8/IHVuZGVmaW5lZFxuICBsZXQgbm9kZUlkID0gZW5zdXJlTm9kZUlkKHRvT3B0aW9uYWxTdHJpbmcoYXJnc1snbm9kZS1pZCddKSlcbiAgaWYgKHVybElucHV0KSB7XG4gICAgY29uc3QgcGFyc2VkID0gcGFyc2VGaWdtYVVybCh1cmxJbnB1dClcbiAgICBmaWxlS2V5ID0gZmlsZUtleSB8fCBwYXJzZWQuZmlsZUtleSB8fCB1bmRlZmluZWRcbiAgICBub2RlSWQgPSBub2RlSWQgfHwgcGFyc2VkLm5vZGVJZFxuICB9XG5cbiAgaWYgKCFmaWxlS2V5KSBlcnJvcnMucHVzaChjcmVhdGVFcnJvcignSU5QVVRfSU5WQUxJRCcsICdBIHZhbGlkIEZpZ21hIGZpbGUga2V5IGlzIHJlcXVpcmVkICgtLWZpbGUta2V5IG9yIC0tdXJsKS4nKSlcbiAgaWYgKCFub2RlSWQpIGVycm9ycy5wdXNoKGNyZWF0ZUVycm9yKCdJTlBVVF9JTlZBTElEJywgJ0EgdmFsaWQgRmlnbWEgbm9kZSBpZCBpcyByZXF1aXJlZCAoLS1ub2RlLWlkIG9yIC0tdXJsIHdpdGggbm9kZS1pZCkuJykpXG5cbiAgbGV0IGZvcm1hdCA9IFN0cmluZyhhcmdzLmZvcm1hdCA/PyAnanBnJykudG9Mb3dlckNhc2UoKVxuICBpZiAoIVNVUFBPUlRFRF9GT1JNQVRTLmluY2x1ZGVzKGZvcm1hdCkpIHsgd2FybmluZ3MucHVzaChgVW5zdXBwb3J0ZWQgZm9ybWF0IFwiJHtmb3JtYXR9XCIuIEZhbGxpbmcgYmFjayB0byBqcGcuYCk7IGZvcm1hdCA9ICdqcGcnIH1cbiAgaWYgKGZvcm1hdCA9PT0gJ2pwZWcnKSBmb3JtYXQgPSAnanBnJ1xuXG4gIGNvbnN0IHNjYWxlSW5wdXQgPSBOdW1iZXIoYXJncy5zY2FsZSA/PyAxKVxuICBjb25zdCBzY2FsZSA9IE51bWJlci5pc0Zpbml0ZShzY2FsZUlucHV0KSA/IE1hdGgubWluKE1hdGgubWF4KHNjYWxlSW5wdXQsIDAuMDEpLCAxKSA6IDFcblxuICBjb25zdCBib3VuZHNJbnB1dCA9IFN0cmluZyhhcmdzLmJvdW5kcyA/PyAnc2VsZWN0aW9uJykudG9Mb3dlckNhc2UoKVxuICBjb25zdCBib3VuZHMgPSBbJ3NlbGVjdGlvbicsICdmcmFtZScsICdub2RlJ10uaW5jbHVkZXMoYm91bmRzSW5wdXQpID8gYm91bmRzSW5wdXQgOiAnc2VsZWN0aW9uJ1xuICBjb25zdCB1c2VBYnNvbHV0ZUJvdW5kcyA9IGJvdW5kcyA9PT0gJ2ZyYW1lJ1xuXG4gIGNvbnN0IGJhY2tncm91bmRJbnB1dCA9IFN0cmluZyhhcmdzLmJhY2tncm91bmQgPz8gJ2NhbnZhcycpLnRvTG93ZXJDYXNlKClcbiAgbGV0IGJhY2tncm91bmRQYXJhbTogc3RyaW5nIHwgdW5kZWZpbmVkXG4gIGlmIChiYWNrZ3JvdW5kSW5wdXQgPT09ICd0cmFuc3BhcmVudCcpIGJhY2tncm91bmRQYXJhbSA9ICcwMDAwMDAwMCdcbiAgZWxzZSBpZiAoL15bMC05YS1mXXs2LDh9JC9pLnRlc3QoYmFja2dyb3VuZElucHV0KSkgeyBjb25zdCB2YWx1ZSA9IGJhY2tncm91bmRJbnB1dC50b1VwcGVyQ2FzZSgpOyBiYWNrZ3JvdW5kUGFyYW0gPSB2YWx1ZS5sZW5ndGggPj0gNiA/IHZhbHVlLnNsaWNlKDAsIDgpLnBhZEVuZCg4LCAnRicpIDogdW5kZWZpbmVkIH1cbiAgZWxzZSBpZiAoYmFja2dyb3VuZElucHV0LnN0YXJ0c1dpdGgoJyMnKSkgYmFja2dyb3VuZFBhcmFtID0gYmFja2dyb3VuZElucHV0LnJlcGxhY2UoJyMnLCAnJykuc2xpY2UoMCwgOCkucGFkRW5kKDgsICdGJylcblxuICBjb25zdCBpbnB1dDogVG9vbElucHV0ID0geyBmaWxlS2V5OiBmaWxlS2V5ID8/IG51bGwsIG5vZGVJZDogbm9kZUlkID8/IG51bGwsIGZvcm1hdCwgc2NhbGUsIGJvdW5kcywgYmFja2dyb3VuZDogYmFja2dyb3VuZElucHV0IH1cbiAgaWYgKGVycm9ycy5sZW5ndGgpIHsgY29uc3QgZW52ZWxvcGUgPSBjcmVhdGVFbnZlbG9wZTxUb29sSW5wdXQsIEVtcHR5RGF0YT4oeyB0b29sOiBUT09MX05BTUUsIGlucHV0LCB3YXJuaW5ncywgZXJyb3JzLCBkYXRhOiB7fSBhcyBFbXB0eURhdGEsIHNjaGVtYVZlcnNpb24gfSk7IGV4aXRXaXRoRW52ZWxvcGUoZW52ZWxvcGUsIGVycm9ycykgfVxuXG4gIGNvbnN0IHJlc29sdmVkRmlsZUtleSA9IGZpbGVLZXkgYXMgc3RyaW5nXG4gIGNvbnN0IHJlc29sdmVkTm9kZUlkID0gbm9kZUlkIGFzIHN0cmluZ1xuXG4gIGxvZyhgUmVxdWVzdGluZyBpbWFnZSBmb3IgJHtyZXNvbHZlZE5vZGVJZH0gKCR7Zm9ybWF0fSwgc2NhbGUgJHtzY2FsZX0pYCwgdmVyYm9zZSlcbiAgY29uc3QgaW1hZ2VSZXNwb25zZSA9IGF3YWl0IGZpZ21hUmVxdWVzdDxJbWFnZUV4cG9ydFJlc3BvbnNlPih7XG4gICAgcGF0aDogYC92MS9pbWFnZXMvJHtyZXNvbHZlZEZpbGVLZXl9YCxcbiAgICB0b2tlbixcbiAgICBzZWFyY2hQYXJhbXM6IHsgaWRzOiByZXNvbHZlZE5vZGVJZCwgZm9ybWF0LCBzY2FsZSwgdXNlX2Fic29sdXRlX2JvdW5kczogdXNlQWJzb2x1dGVCb3VuZHMgPyAndHJ1ZScgOiB1bmRlZmluZWQsIGJhY2tncm91bmQ6IGJhY2tncm91bmRQYXJhbSB9LFxuICB9KVxuXG4gIGlmICghaW1hZ2VSZXNwb25zZS5vaykge1xuICAgIGVycm9ycy5wdXNoKGltYWdlUmVzcG9uc2UuZXJyb3IgPz8gY3JlYXRlRXJyb3IoJ0lOVEVSTkFMJywgJ0ZhaWxlZCB0byByZXF1ZXN0IGltYWdlIGV4cG9ydC4nKSlcbiAgICBjb25zdCBlbnZlbG9wZSA9IGNyZWF0ZUVudmVsb3BlPFRvb2xJbnB1dCwgRW1wdHlEYXRhPih7IHRvb2w6IFRPT0xfTkFNRSwgaW5wdXQsIHdhcm5pbmdzLCBlcnJvcnMsIHJhdGVMaW1pdDogaW1hZ2VSZXNwb25zZS5yYXRlTGltaXQgPz8gdW5kZWZpbmVkLCBkYXRhOiB7fSBhcyBFbXB0eURhdGEsIHNjaGVtYVZlcnNpb24gfSlcbiAgICBleGl0V2l0aEVudmVsb3BlKGVudmVsb3BlLCBlcnJvcnMpXG4gIH1cblxuICBjb25zdCBpbWFnZVVybCA9IGltYWdlUmVzcG9uc2UuZGF0YT8uaW1hZ2VzPy5bcmVzb2x2ZWROb2RlSWRdXG4gIGlmICghaW1hZ2VVcmwpIHtcbiAgICBlcnJvcnMucHVzaChjcmVhdGVFcnJvcignRklHTUFfTk9UX0ZPVU5EJywgJ0ZpZ21hIGRpZCBub3QgcmV0dXJuIGFuIGltYWdlIFVSTCBmb3IgdGhlIHJlcXVlc3RlZCBub2RlLicpKVxuICAgIGNvbnN0IGVudmVsb3BlID0gY3JlYXRlRW52ZWxvcGU8VG9vbElucHV0LCBFbXB0eURhdGE+KHsgdG9vbDogVE9PTF9OQU1FLCBpbnB1dCwgd2FybmluZ3MsIGVycm9ycywgcmF0ZUxpbWl0OiBpbWFnZVJlc3BvbnNlLnJhdGVMaW1pdCA/PyB1bmRlZmluZWQsIGRhdGE6IHt9IGFzIEVtcHR5RGF0YSwgc2NoZW1hVmVyc2lvbiB9KVxuICAgIGV4aXRXaXRoRW52ZWxvcGUoZW52ZWxvcGUsIGVycm9ycylcbiAgfVxuXG4gIGxvZygnRG93bmxvYWRpbmcgaW1hZ2UnLCB2ZXJib3NlKVxuICBsZXQgYnVmZmVyOiBCdWZmZXIgfCBudWxsID0gbnVsbFxuICBsZXQgY29udGVudFR5cGU6IHN0cmluZyB8IG51bGwgPSBudWxsXG4gIHRyeSB7XG4gICAgY29uc3QgcmVzID0gYXdhaXQgZmV0Y2goaW1hZ2VVcmwpXG4gICAgaWYgKCFyZXMub2spIGVycm9ycy5wdXNoKGNyZWF0ZUVycm9yKCdORVRXT1JLJywgYFVuYWJsZSB0byBkb3dubG9hZCBpbWFnZSAoc3RhdHVzICR7cmVzLnN0YXR1c30pLmApKVxuICAgIGVsc2UgeyBjb250ZW50VHlwZSA9IHJlcy5oZWFkZXJzLmdldCgnY29udGVudC10eXBlJyk7IGJ1ZmZlciA9IChmb3JtYXQgPT09ICdzdmcnKSA/IEJ1ZmZlci5mcm9tKGF3YWl0IHJlcy50ZXh0KCkpIDogQnVmZmVyLmZyb20oYXdhaXQgcmVzLmFycmF5QnVmZmVyKCkpIH1cbiAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICBjb25zdCBtZXNzYWdlID0gZXJyb3IgaW5zdGFuY2VvZiBFcnJvciA/IGVycm9yLm1lc3NhZ2UgOiAnVW5rbm93biBkb3dubG9hZCBlcnJvcidcbiAgICBlcnJvcnMucHVzaChjcmVhdGVFcnJvcignTkVUV09SSycsIGBVbmFibGUgdG8gZG93bmxvYWQgaW1hZ2U6ICR7bWVzc2FnZX1gKSlcbiAgfVxuXG4gIGlmICghYnVmZmVyIHx8IGVycm9ycy5sZW5ndGgpIHtcbiAgICBjb25zdCBlbnZlbG9wZSA9IGNyZWF0ZUVudmVsb3BlPFRvb2xJbnB1dCwgRW1wdHlEYXRhPih7IHRvb2w6IFRPT0xfTkFNRSwgaW5wdXQsIHdhcm5pbmdzLCBlcnJvcnMsIHJhdGVMaW1pdDogaW1hZ2VSZXNwb25zZS5yYXRlTGltaXQgPz8gdW5kZWZpbmVkLCBkYXRhOiB7fSBhcyBFbXB0eURhdGEsIHNjaGVtYVZlcnNpb24gfSlcbiAgICBleGl0V2l0aEVudmVsb3BlKGVudmVsb3BlLCBlcnJvcnMpXG4gIH1cblxuICBjb25zdCBzYW5pdGl6ZWROb2RlSWQgPSByZXNvbHZlZE5vZGVJZC5yZXBsYWNlKC9bXmEtekEtWjAtOS1fXS9nLCAnXycpXG4gIGNvbnN0IGJhc2VEaXIgPSBwYXRoLnJlc29sdmUoU0NSRUVOU0hPVF9ESVIsIHJlc29sdmVkRmlsZUtleSlcbiAgYXdhaXQgZW5zdXJlRGlyRXhpc3RzKGJhc2VEaXIpXG4gIGNvbnN0IGV4dGVuc2lvbiA9IGZvcm1hdCA9PT0gJ2pwZycgPyAnanBnJyA6IGZvcm1hdFxuICBjb25zdCBmaWxlUGF0aCA9IHBhdGguam9pbihiYXNlRGlyLCBgJHtzYW5pdGl6ZWROb2RlSWR9LiR7ZXh0ZW5zaW9ufWApXG4gIGF3YWl0IHdyaXRlRmlsZShmaWxlUGF0aCwgYnVmZmVyKVxuXG4gIGNvbnN0IGRhdGE6IFNjcmVlbnNob3REYXRhID0ge1xuICAgIGZpbGU6IHsga2V5OiByZXNvbHZlZEZpbGVLZXksIG5vZGVJZDogcmVzb2x2ZWROb2RlSWQgfSxcbiAgICBzY3JlZW5zaG90OiB7IHBhdGg6IGZpbGVQYXRoLCB1cmw6IGltYWdlVXJsLCBmb3JtYXQ6IGV4dGVuc2lvbiwgc2NhbGUsIGJvdW5kcywgYmFja2dyb3VuZDogYmFja2dyb3VuZElucHV0LCBjb250ZW50VHlwZSB9LFxuICB9XG5cbiAgY29uc3QgZW52ZWxvcGUgPSBjcmVhdGVFbnZlbG9wZTxUb29sSW5wdXQsIFNjcmVlbnNob3REYXRhPih7IHRvb2w6IFRPT0xfTkFNRSwgaW5wdXQsIGRhdGEsIHdhcm5pbmdzLCBlcnJvcnMsIHJhdGVMaW1pdDogaW1hZ2VSZXNwb25zZS5yYXRlTGltaXQgPz8gdW5kZWZpbmVkLCBzY2hlbWFWZXJzaW9uIH0pXG4gIHByb2Nlc3Muc3Rkb3V0LndyaXRlKGAke0pTT04uc3RyaW5naWZ5KGVudmVsb3BlLCBudWxsLCAyKX1cXG5gKVxuICBwcm9jZXNzLmV4aXQoZ2V0RXhpdENvZGUoZXJyb3JzKSlcbn1cblxubWFpbigpLmNhdGNoKChlcnJvcjogdW5rbm93bikgPT4ge1xuICBjb25zdCBtZXNzYWdlID0gZXJyb3IgaW5zdGFuY2VvZiBFcnJvciA/IGVycm9yLm1lc3NhZ2UgOiAnVW5rbm93biBlcnJvcidcbiAgY29uc3QgZW52ZWxvcGUgPSBjcmVhdGVFbnZlbG9wZTxUb29sSW5wdXQsIEVtcHR5RGF0YT4oeyB0b29sOiBUT09MX05BTUUsIGlucHV0OiB7IGZpbGVLZXk6IG51bGwsIG5vZGVJZDogbnVsbCwgZm9ybWF0OiAnanBnJywgc2NhbGU6IDEsIGJvdW5kczogJ3NlbGVjdGlvbicsIGJhY2tncm91bmQ6ICdjYW52YXMnIH0sIGVycm9yczogW2NyZWF0ZUVycm9yKCdJTlRFUk5BTCcsIG1lc3NhZ2UsIHsgc3RhY2s6IGVycm9yIGluc3RhbmNlb2YgRXJyb3IgPyBlcnJvci5zdGFjayA6IHVuZGVmaW5lZCB9KV0sIGRhdGE6IHt9IGFzIEVtcHR5RGF0YSB9KVxuICBwcm9jZXNzLnN0ZG91dC53cml0ZShgJHtKU09OLnN0cmluZ2lmeShlbnZlbG9wZSwgbnVsbCwgMil9XFxuYClcbiAgcHJvY2Vzcy5leGl0KDMpXG59KVxuIiwgImV4cG9ydCB0eXBlIENsaUFyZ1ZhbHVlID0gc3RyaW5nIHwgYm9vbGVhbjtcblxuZXhwb3J0IGludGVyZmFjZSBDbGlBcmdzIHtcbiAgXzogc3RyaW5nW107XG4gIFtrZXk6IHN0cmluZ106IENsaUFyZ1ZhbHVlIHwgc3RyaW5nW107XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBwYXJzZUFyZ3MoYXJndjogc3RyaW5nW10gPSBwcm9jZXNzLmFyZ3Yuc2xpY2UoMikpOiBDbGlBcmdzIHtcbiAgY29uc3QgYXJnczogQ2xpQXJncyA9IHsgXzogW10gfTtcblxuICBmb3IgKGxldCBpID0gMDsgaSA8IGFyZ3YubGVuZ3RoOyBpICs9IDEpIHtcbiAgICBjb25zdCBhcmcgPSBhcmd2W2ldO1xuXG4gICAgaWYgKCFhcmcuc3RhcnRzV2l0aCgnLScpIHx8IGFyZyA9PT0gJy0nKSB7XG4gICAgICBhcmdzLl8ucHVzaChhcmcpO1xuICAgICAgY29udGludWU7XG4gICAgfVxuXG4gICAgaWYgKGFyZyA9PT0gJy0tJykge1xuICAgICAgY29uc3QgcmVtYWluaW5nID0gYXJndi5zbGljZShpICsgMSk7XG4gICAgICBhcmdzLl8ucHVzaCguLi5yZW1haW5pbmcpO1xuICAgICAgYnJlYWs7XG4gICAgfVxuXG4gICAgY29uc3QgW3Jhd0tleSwgaW5saW5lVmFsdWVdID0gYXJnLnNwbGl0KCc9JywgMik7XG4gICAgY29uc3Qgbm9ybWFsaXNlZEtleSA9IHJhd0tleS5yZXBsYWNlKC9eLSsvLCAnJyk7XG5cbiAgICBsZXQgdmFsdWU6IENsaUFyZ1ZhbHVlO1xuICAgIGlmIChpbmxpbmVWYWx1ZSAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICB2YWx1ZSA9IGlubGluZVZhbHVlO1xuICAgIH0gZWxzZSB7XG4gICAgICBjb25zdCBuZXh0ID0gYXJndltpICsgMV07XG4gICAgICBpZiAobmV4dCAhPT0gdW5kZWZpbmVkICYmICFuZXh0LnN0YXJ0c1dpdGgoJy0nKSkge1xuICAgICAgICB2YWx1ZSA9IG5leHQ7XG4gICAgICAgIGkgKz0gMTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHZhbHVlID0gdHJ1ZTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICBhcmdzW25vcm1hbGlzZWRLZXldID0gdmFsdWU7XG4gIH1cblxuICByZXR1cm4gYXJncztcbn1cblxuIiwgImNvbnN0IEZJTEVfS0VZX1JFR0VYID0gL2ZpZ21hXFwuY29tXFwvKD86ZmlsZXxkZXNpZ24pXFwvKFtBLVphLXowLTldKylcXC8vaTtcblxuZXhwb3J0IGludGVyZmFjZSBQYXJzZWRGaWdtYVVybCB7XG4gIGZpbGVLZXk6IHN0cmluZyB8IG51bGw7XG4gIG5vZGVJZDogc3RyaW5nIHwgbnVsbDtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIHBhcnNlRmlnbWFVcmwoaW5wdXQ6IHN0cmluZyB8IG51bGwgfCB1bmRlZmluZWQpOiBQYXJzZWRGaWdtYVVybCB7XG4gIGlmICghaW5wdXQpIHJldHVybiB7IGZpbGVLZXk6IG51bGwsIG5vZGVJZDogbnVsbCB9O1xuICB0cnkge1xuICAgIGNvbnN0IHVybCA9IG5ldyBVUkwoaW5wdXQpO1xuICAgIGNvbnN0IG1hdGNoID0gdXJsLmhyZWYubWF0Y2goRklMRV9LRVlfUkVHRVgpO1xuICAgIGNvbnN0IGZpbGVLZXkgPSBtYXRjaCA/IG1hdGNoWzFdIDogbnVsbDtcbiAgICBjb25zdCBub2RlUGFyYW0gPSB1cmwuc2VhcmNoUGFyYW1zLmdldCgnbm9kZS1pZCcpO1xuICAgIGNvbnN0IG5vZGVJZCA9IG5vZGVQYXJhbSA/IGVuc3VyZU5vZGVJZChub2RlUGFyYW0pIDogbnVsbDtcbiAgICByZXR1cm4geyBmaWxlS2V5LCBub2RlSWQgfTtcbiAgfSBjYXRjaCB7XG4gICAgcmV0dXJuIHsgZmlsZUtleTogbnVsbCwgbm9kZUlkOiBudWxsIH07XG4gIH1cbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGVuc3VyZU5vZGVJZCh2YWx1ZTogc3RyaW5nIHwgbnVsbCB8IHVuZGVmaW5lZCk6IHN0cmluZyB8IG51bGwge1xuICBpZiAoIXZhbHVlKSByZXR1cm4gbnVsbDtcbiAgY29uc3QgZGVjb2RlZCA9IGRlY29kZVVSSUNvbXBvbmVudCh2YWx1ZSk7XG4gIGlmIChkZWNvZGVkLmluY2x1ZGVzKCc6JykpIHJldHVybiBkZWNvZGVkO1xuICBpZiAoL15bMC05XSstWzAtOV0rJC8udGVzdChkZWNvZGVkKSkge1xuICAgIGNvbnN0IFtsZWZ0LCByaWdodF0gPSBkZWNvZGVkLnNwbGl0KCctJywgMik7XG4gICAgcmV0dXJuIGAke2xlZnR9OiR7cmlnaHR9YDtcbiAgfVxuICByZXR1cm4gZGVjb2RlZDtcbn1cblxuIiwgImV4cG9ydCBkZWZhdWx0IHtcbiAgc2NoZW1hVmVyc2lvbjogJzEuMC4wJyxcbiAgc291cmNlOiAnYWdlbnRpYy1jb2RpbmctdGVtcGxhdGVzL2ZpZ21hLXRvb2xzJyxcbiAgaHR0cDoge1xuICAgIG1heEF0dGVtcHRzOiA1LFxuICAgIGluaXRpYWxEZWxheU1zOiAyNTAsXG4gIH0sXG59IGFzIGNvbnN0O1xuXG4iLCAiaW1wb3J0IGNvbmZpZyBmcm9tICcuL2NvbmZpZy50cyc7XG5pbXBvcnQgdHlwZSB7IFRvb2xFcnJvciB9IGZyb20gJy4vZXJyb3JzLnRzJztcblxuZXhwb3J0IGludGVyZmFjZSBSYXRlTGltaXRNZXRhIHtcbiAgcmVtYWluaW5nOiBudW1iZXIgfCBudWxsO1xuICByZXNldEF0OiBzdHJpbmcgfCBudWxsO1xuICBhdHRlbXB0czogbnVtYmVyO1xuICBsYXN0V2FpdE1zOiBudW1iZXI7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgVG9vbEVudmVsb3BlPFxuICBUSW5wdXQgZXh0ZW5kcyBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPiA9IFJlY29yZDxzdHJpbmcsIHVua25vd24+LFxuICBURGF0YSA9IHVua25vd25cbj4ge1xuICBzY2hlbWFWZXJzaW9uOiBzdHJpbmc7XG4gIHRvb2w6IHN0cmluZztcbiAgaW5wdXQ6IFRJbnB1dDtcbiAgbWV0YToge1xuICAgIGdlbmVyYXRlZEF0OiBzdHJpbmc7XG4gICAgc291cmNlOiBzdHJpbmc7XG4gICAgcmF0ZUxpbWl0OiBSYXRlTGltaXRNZXRhO1xuICB9O1xuICBkYXRhOiBURGF0YTtcbiAgd2FybmluZ3M6IHN0cmluZ1tdO1xuICBlcnJvcnM6IFRvb2xFcnJvcltdO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIENyZWF0ZUVudmVsb3BlT3B0aW9uczxcbiAgVElucHV0IGV4dGVuZHMgUmVjb3JkPHN0cmluZywgdW5rbm93bj4gPSBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPixcbiAgVERhdGEgPSB1bmtub3duXG4+IHtcbiAgdG9vbDogc3RyaW5nO1xuICBpbnB1dD86IFRJbnB1dDtcbiAgZGF0YT86IFREYXRhO1xuICB3YXJuaW5ncz86IHN0cmluZ1tdO1xuICBlcnJvcnM/OiBUb29sRXJyb3JbXTtcbiAgcmF0ZUxpbWl0PzogUGFydGlhbDxSYXRlTGltaXRNZXRhPjtcbiAgc2NoZW1hVmVyc2lvbj86IHN0cmluZztcbn1cblxuZnVuY3Rpb24gYnVpbGRSYXRlTGltaXRNZXRhKHJhdGVMaW1pdDogUGFydGlhbDxSYXRlTGltaXRNZXRhPiA9IHt9KTogUmF0ZUxpbWl0TWV0YSB7XG4gIHJldHVybiB7XG4gICAgcmVtYWluaW5nOiByYXRlTGltaXQucmVtYWluaW5nID8/IG51bGwsXG4gICAgcmVzZXRBdDogcmF0ZUxpbWl0LnJlc2V0QXQgPz8gbnVsbCxcbiAgICBhdHRlbXB0czogcmF0ZUxpbWl0LmF0dGVtcHRzID8/IDEsXG4gICAgbGFzdFdhaXRNczogcmF0ZUxpbWl0Lmxhc3RXYWl0TXMgPz8gMCxcbiAgfTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGNyZWF0ZUVudmVsb3BlPFxuICBUSW5wdXQgZXh0ZW5kcyBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPiA9IFJlY29yZDxzdHJpbmcsIHVua25vd24+LFxuICBURGF0YSA9IHVua25vd25cbj4oe1xuICB0b29sLFxuICBpbnB1dCA9IHt9IGFzIFRJbnB1dCxcbiAgZGF0YSA9IHt9IGFzIFREYXRhLFxuICB3YXJuaW5ncyA9IFtdLFxuICBlcnJvcnMgPSBbXSxcbiAgcmF0ZUxpbWl0LFxuICBzY2hlbWFWZXJzaW9uLFxufTogQ3JlYXRlRW52ZWxvcGVPcHRpb25zPFRJbnB1dCwgVERhdGE+KTogVG9vbEVudmVsb3BlPFRJbnB1dCwgVERhdGE+IHtcbiAgcmV0dXJuIHtcbiAgICBzY2hlbWFWZXJzaW9uOiBzY2hlbWFWZXJzaW9uID8/IGNvbmZpZy5zY2hlbWFWZXJzaW9uLFxuICAgIHRvb2wsXG4gICAgaW5wdXQsXG4gICAgbWV0YToge1xuICAgICAgZ2VuZXJhdGVkQXQ6IG5ldyBEYXRlKCkudG9JU09TdHJpbmcoKSxcbiAgICAgIHNvdXJjZTogY29uZmlnLnNvdXJjZSxcbiAgICAgIHJhdGVMaW1pdDogYnVpbGRSYXRlTGltaXRNZXRhKHJhdGVMaW1pdCksXG4gICAgfSxcbiAgICBkYXRhLFxuICAgIHdhcm5pbmdzLFxuICAgIGVycm9ycyxcbiAgfTtcbn1cblxuIiwgImV4cG9ydCBjb25zdCBFUlJPUl9FWElUX0NPREVTID0ge1xuICBJTlBVVF9JTlZBTElEOiAxLFxuICBDT05GSUdfSU5WQUxJRDogMSxcbiAgRklHTUFfQVVUSDogMSxcbiAgRklHTUFfTk9UX0ZPVU5EOiAyLFxuICBGSUdNQV9SQVRFX0xJTUlUOiAyLFxuICBORVRXT1JLOiAyLFxuICBJTlRFUk5BTDogMyxcbn0gYXMgY29uc3Q7XG5cbmV4cG9ydCB0eXBlIEVycm9yQ29kZSA9IGtleW9mIHR5cGVvZiBFUlJPUl9FWElUX0NPREVTO1xuXG5leHBvcnQgaW50ZXJmYWNlIFRvb2xFcnJvcjxURGV0YWlsID0gdW5rbm93bj4ge1xuICBjb2RlOiBFcnJvckNvZGUgfCBzdHJpbmc7XG4gIG1lc3NhZ2U6IHN0cmluZztcbiAgZGV0YWlsPzogVERldGFpbCB8IG51bGw7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBjcmVhdGVFcnJvcjxURGV0YWlsID0gdW5rbm93bj4oXG4gIGNvZGU6IEVycm9yQ29kZSB8IHN0cmluZyxcbiAgbWVzc2FnZTogc3RyaW5nLFxuICBkZXRhaWw/OiBURGV0YWlsIHwgbnVsbFxuKTogVG9vbEVycm9yPFREZXRhaWw+IHtcbiAgcmV0dXJuIHtcbiAgICBjb2RlLFxuICAgIG1lc3NhZ2UsXG4gICAgZGV0YWlsOiBkZXRhaWwgPz8gbnVsbCxcbiAgfTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGdldEV4aXRDb2RlKGVycm9yczogVG9vbEVycm9yW10gPSBbXSk6IG51bWJlciB7XG4gIGlmICghZXJyb3JzLmxlbmd0aCkge1xuICAgIHJldHVybiAwO1xuICB9XG5cbiAgcmV0dXJuIGVycm9ycy5yZWR1Y2UoKG1heCwgZXJyb3IpID0+IHtcbiAgICBjb25zdCBleGl0Q29kZSA9IEVSUk9SX0VYSVRfQ09ERVNbZXJyb3IuY29kZSBhcyBFcnJvckNvZGVdID8/IDE7XG4gICAgcmV0dXJuIE1hdGgubWF4KG1heCwgZXhpdENvZGUpO1xuICB9LCAwKTtcbn1cblxuIiwgImltcG9ydCBjb25maWcgZnJvbSAnLi9jb25maWcudHMnO1xuaW1wb3J0IHsgY3JlYXRlRXJyb3IgfSBmcm9tICcuL2Vycm9ycy50cyc7XG5pbXBvcnQgdHlwZSB7IFRvb2xFcnJvciB9IGZyb20gJy4vZXJyb3JzLnRzJztcbmltcG9ydCB0eXBlIHsgUmF0ZUxpbWl0TWV0YSB9IGZyb20gJy4vZW52ZWxvcGUudHMnO1xuXG5jb25zdCBCQVNFX1VSTCA9ICdodHRwczovL2FwaS5maWdtYS5jb20nO1xuXG50eXBlIFNlYXJjaFBhcmFtcyA9IFJlY29yZDxzdHJpbmcsIHN0cmluZyB8IG51bWJlciB8IGJvb2xlYW4gfCBudWxsIHwgdW5kZWZpbmVkPjtcblxuaW50ZXJmYWNlIEZpZ21hUmVxdWVzdE9wdGlvbnMge1xuICBwYXRoOiBzdHJpbmc7XG4gIG1ldGhvZD86IHN0cmluZztcbiAgdG9rZW4/OiBzdHJpbmc7XG4gIGhlYWRlcnM/OiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+O1xuICBib2R5PzogdW5rbm93bjtcbiAgc2VhcmNoUGFyYW1zPzogU2VhcmNoUGFyYW1zO1xuICBtYXhBdHRlbXB0cz86IG51bWJlcjtcbiAgaW5pdGlhbERlbGF5TXM/OiBudW1iZXI7XG59XG5cbmludGVyZmFjZSBGaWdtYVN1Y2Nlc3M8VERhdGE+IHtcbiAgb2s6IHRydWU7XG4gIGRhdGE6IFREYXRhO1xuICByYXRlTGltaXQ6IFJhdGVMaW1pdE1ldGE7XG59XG5cbmludGVyZmFjZSBGaWdtYUZhaWx1cmUge1xuICBvazogZmFsc2U7XG4gIGVycm9yOiBUb29sRXJyb3I8eyBzdGF0dXM/OiBudW1iZXIgfT47XG4gIHN0YXR1cz86IG51bWJlciB8IG51bGw7XG4gIHJhdGVMaW1pdDogUmF0ZUxpbWl0TWV0YSB8IG51bGw7XG59XG5cbmV4cG9ydCB0eXBlIEZpZ21hUmVzcG9uc2U8VERhdGE+ID0gRmlnbWFTdWNjZXNzPFREYXRhPiB8IEZpZ21hRmFpbHVyZTtcblxuZnVuY3Rpb24gc2xlZXAobXM6IG51bWJlcik6IFByb21pc2U8dm9pZD4ge1xuICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUpID0+IHNldFRpbWVvdXQocmVzb2x2ZSwgbXMpKTtcbn1cblxuZnVuY3Rpb24gcGFyc2VKc29uU2FmZWx5KHRleHQ6IHN0cmluZyk6IHVua25vd24ge1xuICB0cnkge1xuICAgIHJldHVybiB0ZXh0ID8gSlNPTi5wYXJzZSh0ZXh0KSA6IHt9O1xuICB9IGNhdGNoIHtcbiAgICByZXR1cm4geyByYXc6IHRleHQgfTtcbiAgfVxufVxuXG5mdW5jdGlvbiBwYXJzZVJhdGVMaW1pdChoZWFkZXJzOiBIZWFkZXJzLCBhdHRlbXB0czogbnVtYmVyLCBsYXN0V2FpdE1zOiBudW1iZXIpOiBSYXRlTGltaXRNZXRhIHtcbiAgY29uc3QgcmVtYWluaW5nSGVhZGVyID0gaGVhZGVycy5nZXQoJ3gtcmF0ZWxpbWl0LXJlbWFpbmluZycpO1xuICBjb25zdCByZXNldEhlYWRlciA9IGhlYWRlcnMuZ2V0KCd4LXJhdGVsaW1pdC1yZXNldCcpO1xuXG4gIGxldCByZW1haW5pbmc6IG51bWJlciB8IG51bGwgPSBudWxsO1xuICBpZiAocmVtYWluaW5nSGVhZGVyICE9PSBudWxsICYmIHJlbWFpbmluZ0hlYWRlciAhPT0gdW5kZWZpbmVkKSB7XG4gICAgY29uc3QgcGFyc2VkID0gTnVtYmVyKHJlbWFpbmluZ0hlYWRlcik7XG4gICAgcmVtYWluaW5nID0gTnVtYmVyLmlzTmFOKHBhcnNlZCkgPyBudWxsIDogcGFyc2VkO1xuICB9XG5cbiAgbGV0IHJlc2V0QXQ6IHN0cmluZyB8IG51bGwgPSBudWxsO1xuICBpZiAocmVzZXRIZWFkZXIpIHtcbiAgICBjb25zdCBudW1lcmljUmVzZXQgPSBOdW1iZXIocmVzZXRIZWFkZXIpO1xuICAgIGlmICghTnVtYmVyLmlzTmFOKG51bWVyaWNSZXNldCkpIHtcbiAgICAgIHJlc2V0QXQgPSBuZXcgRGF0ZShudW1lcmljUmVzZXQgKiAxMDAwKS50b0lTT1N0cmluZygpO1xuICAgIH0gZWxzZSB7XG4gICAgICBjb25zdCBkYXRlID0gbmV3IERhdGUocmVzZXRIZWFkZXIpO1xuICAgICAgaWYgKCFOdW1iZXIuaXNOYU4oZGF0ZS52YWx1ZU9mKCkpKSB7XG4gICAgICAgIHJlc2V0QXQgPSBkYXRlLnRvSVNPU3RyaW5nKCk7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgcmV0dXJuIHtcbiAgICByZW1haW5pbmcsXG4gICAgcmVzZXRBdCxcbiAgICBhdHRlbXB0cyxcbiAgICBsYXN0V2FpdE1zLFxuICB9O1xufVxuXG5mdW5jdGlvbiBjb21wdXRlQmFja29mZk1zKGF0dGVtcHQ6IG51bWJlciwgaW5pdGlhbERlbGF5TXM6IG51bWJlcik6IG51bWJlciB7XG4gIHJldHVybiBpbml0aWFsRGVsYXlNcyAqIDIgKiogKGF0dGVtcHQgLSAxKTtcbn1cblxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGZpZ21hUmVxdWVzdDxURGF0YSA9IHVua25vd24+KFxuICBvcHRpb25zOiBGaWdtYVJlcXVlc3RPcHRpb25zXG4pOiBQcm9taXNlPEZpZ21hUmVzcG9uc2U8VERhdGE+PiB7XG4gIGNvbnN0IHtcbiAgICBwYXRoLFxuICAgIG1ldGhvZCA9ICdHRVQnLFxuICAgIHRva2VuLFxuICAgIGhlYWRlcnMgPSB7fSxcbiAgICBib2R5LFxuICAgIHNlYXJjaFBhcmFtcyxcbiAgICBtYXhBdHRlbXB0cyA9IGNvbmZpZy5odHRwPy5tYXhBdHRlbXB0cyA/PyA1LFxuICAgIGluaXRpYWxEZWxheU1zID0gY29uZmlnLmh0dHA/LmluaXRpYWxEZWxheU1zID8/IDI1MCxcbiAgfSA9IG9wdGlvbnM7XG5cbiAgaWYgKCF0b2tlbikge1xuICAgIHJldHVybiB7XG4gICAgICBvazogZmFsc2UsXG4gICAgICBlcnJvcjogY3JlYXRlRXJyb3IoJ0ZJR01BX0FVVEgnLCAnRklHTUFfQUNDRVNTX1RPS0VOIGlzIG1pc3NpbmcgZnJvbSB0aGUgZW52aXJvbm1lbnQuJyksXG4gICAgICBzdGF0dXM6IG51bGwsXG4gICAgICByYXRlTGltaXQ6IG51bGwsXG4gICAgfTtcbiAgfVxuXG4gIGNvbnN0IHVybCA9IG5ldyBVUkwocGF0aCwgQkFTRV9VUkwpO1xuXG4gIGlmIChzZWFyY2hQYXJhbXMpIHtcbiAgICBPYmplY3QuZW50cmllcyhzZWFyY2hQYXJhbXMpLmZvckVhY2goKFtrZXksIHZhbHVlXSkgPT4ge1xuICAgICAgaWYgKHZhbHVlID09PSB1bmRlZmluZWQgfHwgdmFsdWUgPT09IG51bGwpIHJldHVybjtcbiAgICAgIHVybC5zZWFyY2hQYXJhbXMuYXBwZW5kKGtleSwgU3RyaW5nKHZhbHVlKSk7XG4gICAgfSk7XG4gIH1cblxuICBsZXQgYXR0ZW1wdCA9IDA7XG4gIGxldCBsYXN0V2FpdE1zID0gMDtcblxuICB3aGlsZSAoYXR0ZW1wdCA8IG1heEF0dGVtcHRzKSB7XG4gICAgYXR0ZW1wdCArPSAxO1xuXG4gICAgY29uc3QgcmVzcG9uc2UgPSBhd2FpdCBmZXRjaCh1cmwsIHtcbiAgICAgIG1ldGhvZCxcbiAgICAgIGhlYWRlcnM6IHtcbiAgICAgICAgJ0NvbnRlbnQtVHlwZSc6ICdhcHBsaWNhdGlvbi9qc29uJyxcbiAgICAgICAgJ1gtRmlnbWEtVG9rZW4nOiB0b2tlbixcbiAgICAgICAgLi4uaGVhZGVycyxcbiAgICAgIH0sXG4gICAgICBib2R5OiBib2R5ID8gSlNPTi5zdHJpbmdpZnkoYm9keSkgOiB1bmRlZmluZWQsXG4gICAgfSk7XG5cbiAgICBjb25zdCB0ZXh0ID0gYXdhaXQgcmVzcG9uc2UudGV4dCgpO1xuICAgIGNvbnN0IHBheWxvYWQgPSBwYXJzZUpzb25TYWZlbHkodGV4dCkgYXMgeyBtZXNzYWdlPzogc3RyaW5nIH07XG4gICAgY29uc3QgcmF0ZUxpbWl0ID0gcGFyc2VSYXRlTGltaXQocmVzcG9uc2UuaGVhZGVycywgYXR0ZW1wdCwgbGFzdFdhaXRNcyk7XG5cbiAgICBpZiAocmVzcG9uc2Uub2spIHtcbiAgICAgIHJldHVybiB7IG9rOiB0cnVlLCBkYXRhOiBwYXlsb2FkIGFzIFREYXRhLCByYXRlTGltaXQgfTtcbiAgICB9XG5cbiAgICBjb25zdCBzdGF0dXMgPSByZXNwb25zZS5zdGF0dXM7XG5cbiAgICBpZiAoc3RhdHVzID09PSA0MDEgfHwgc3RhdHVzID09PSA0MDMpIHtcbiAgICAgIHJldHVybiB7IG9rOiBmYWxzZSwgZXJyb3I6IGNyZWF0ZUVycm9yKCdGSUdNQV9BVVRIJywgcGF5bG9hZD8ubWVzc2FnZSA/PyAnRmlnbWEgdG9rZW4gaXMgdW5hdXRob3JpemVkLicsIHsgc3RhdHVzIH0pLCBzdGF0dXMsIHJhdGVMaW1pdCB9O1xuICAgIH1cblxuICAgIGlmIChzdGF0dXMgPT09IDQwNCkge1xuICAgICAgcmV0dXJuIHsgb2s6IGZhbHNlLCBlcnJvcjogY3JlYXRlRXJyb3IoJ0ZJR01BX05PVF9GT1VORCcsIHBheWxvYWQ/Lm1lc3NhZ2UgPz8gJ1Jlc291cmNlIG5vdCBmb3VuZC4nLCB7IHN0YXR1cyB9KSwgc3RhdHVzLCByYXRlTGltaXQgfTtcbiAgICB9XG5cbiAgICBpZiAoc3RhdHVzID09PSA0MjkgfHwgc3RhdHVzID49IDUwMCkge1xuICAgICAgaWYgKGF0dGVtcHQgPj0gbWF4QXR0ZW1wdHMpIHtcbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICBvazogZmFsc2UsXG4gICAgICAgICAgZXJyb3I6IGNyZWF0ZUVycm9yKHN0YXR1cyA9PT0gNDI5ID8gJ0ZJR01BX1JBVEVfTElNSVQnIDogJ05FVFdPUksnLCBwYXlsb2FkPy5tZXNzYWdlID8/ICdGaWdtYSByZXF1ZXN0IGZhaWxlZCBhZnRlciBtYXhpbXVtIHJldHJpZXMuJywgeyBzdGF0dXMgfSksXG4gICAgICAgICAgc3RhdHVzLFxuICAgICAgICAgIHJhdGVMaW1pdCxcbiAgICAgICAgfTtcbiAgICAgIH1cblxuICAgICAgbGV0IHdhaXRNcyA9IGNvbXB1dGVCYWNrb2ZmTXMoYXR0ZW1wdCwgaW5pdGlhbERlbGF5TXMpO1xuICAgICAgY29uc3QgcmVzZXRIZWFkZXIgPSByZXNwb25zZS5oZWFkZXJzLmdldCgneC1yYXRlbGltaXQtcmVzZXQnKTtcbiAgICAgIGlmIChyZXNldEhlYWRlcikge1xuICAgICAgICBjb25zdCBhc051bWJlciA9IE51bWJlcihyZXNldEhlYWRlcik7XG4gICAgICAgIGlmICghTnVtYmVyLmlzTmFOKGFzTnVtYmVyKSkge1xuICAgICAgICAgIGNvbnN0IHJlc2V0TXMgPSBhc051bWJlciAqIDEwMDA7XG4gICAgICAgICAgY29uc3QgZGVsdGEgPSByZXNldE1zIC0gRGF0ZS5ub3coKTtcbiAgICAgICAgICBpZiAoZGVsdGEgPiAwKSB3YWl0TXMgPSBNYXRoLm1heCh3YWl0TXMsIGRlbHRhKTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICBjb25zdCBqaXR0ZXIgPSBNYXRoLmZsb29yKE1hdGgucmFuZG9tKCkgKiAxMDApO1xuICAgICAgbGFzdFdhaXRNcyA9IHdhaXRNcyArIGppdHRlcjtcbiAgICAgIGF3YWl0IHNsZWVwKGxhc3RXYWl0TXMpO1xuICAgICAgY29udGludWU7XG4gICAgfVxuXG4gICAgcmV0dXJuIHsgb2s6IGZhbHNlLCBlcnJvcjogY3JlYXRlRXJyb3IoJ0lOVEVSTkFMJywgcGF5bG9hZD8ubWVzc2FnZSA/PyAnVW5leHBlY3RlZCBlcnJvciBmcm9tIEZpZ21hIEFQSS4nLCB7IHN0YXR1cyB9KSwgc3RhdHVzLCByYXRlTGltaXQgfTtcbiAgfVxuXG4gIHJldHVybiB7XG4gICAgb2s6IGZhbHNlLFxuICAgIGVycm9yOiBjcmVhdGVFcnJvcignTkVUV09SSycsICdVbmFibGUgdG8gcmVhY2ggRmlnbWEgQVBJLicpLFxuICAgIHN0YXR1czogbnVsbCxcbiAgICByYXRlTGltaXQ6IHsgcmVtYWluaW5nOiBudWxsLCByZXNldEF0OiBudWxsLCBhdHRlbXB0czogbWF4QXR0ZW1wdHMsIGxhc3RXYWl0TXMgfSxcbiAgfTtcbn1cblxuIl0sCiAgIm1hcHBpbmdzIjogIjs7O0FBRUEsU0FBUyxPQUFPLGlCQUFpQjtBQUNqQyxPQUFPLFVBQVU7OztBQ0lWLFNBQVMsVUFBVSxPQUFpQixRQUFRLEtBQUssTUFBTSxDQUFDLEdBQVk7QUFDekUsUUFBTSxPQUFnQixFQUFFLEdBQUcsQ0FBQyxFQUFFO0FBRTlCLFdBQVMsSUFBSSxHQUFHLElBQUksS0FBSyxRQUFRLEtBQUssR0FBRztBQUN2QyxVQUFNLE1BQU0sS0FBSyxDQUFDO0FBRWxCLFFBQUksQ0FBQyxJQUFJLFdBQVcsR0FBRyxLQUFLLFFBQVEsS0FBSztBQUN2QyxXQUFLLEVBQUUsS0FBSyxHQUFHO0FBQ2Y7QUFBQSxJQUNGO0FBRUEsUUFBSSxRQUFRLE1BQU07QUFDaEIsWUFBTSxZQUFZLEtBQUssTUFBTSxJQUFJLENBQUM7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SyxNQUFNLElBQUksS0FBSyxDQUFDLElBQUksT0FBTyxLQUFLLE1BQU0sSUFBSSxZQUFZLENBQUM7QUFBQSxJQUFFO0FBQUEsRUFDM0osU0FBUyxPQUFPO0FBQ2QsVUFBTSxVQUFVLGlCQUFpQixRQUFRLE1BQU0sVUFBVTtBQUN6RCxXQUFPLEtBQUssWUFBWSxXQUFXLDZCQUE2QixPQUFPLEVBQUUsQ0FBQztBQUFBLEVBQzVFO0FBRUEsTUFBSSxDQUFDLFVBQVUsT0FBTyxRQUFRO0FBQzVCLFVBQU1BLFlBQVcsZUFBcUMsRUFBRSxNQUFNLFdBQVcsT0FBTyxVQUFVLFFBQVEsV0FBVyxjQUFjLGFBQWEsUUFBVyxNQUFNLENBQUMsR0FBZ0IsY0FBYyxDQUFDO0FBQ3pMLHFCQUFpQkEsV0FBVSxNQUFNO0FBQUEsRUFDbkM7QUFFQSxRQUFNLGtCQUFrQixlQUFlLFFBQVEsbUJBQW1CLEdBQUc7QUFDckUsUUFBTSxVQUFVLEtBQUssUUFBUSxnQkFBZ0IsZUFBZTtBQUM1RCxRQUFNLGdCQUFnQixPQUFPO0FBQzdCLFFBQU0sWUFBWSxXQUFXLFFBQVEsUUFBUTtBQUM3QyxRQUFNLFdBQVcsS0FBSyxLQUFLLFNBQVMsR0FBRyxlQUFlLElBQUksU0FBUyxFQUFFO0FBQ3JFLFFBQU0sVUFBVSxVQUFVLE1BQU07QUFFaEMsUUFBTSxPQUF1QjtBQUFBLElBQzNCLE1BQU0sRUFBRSxLQUFLLGlCQUFpQixRQUFRLGVBQWU7QUFBQSxJQUNyRCxZQUFZLEVBQUUsTUFBTSxVQUFVLEtBQUssVUFBVSxRQUFRLFdBQVcsT0FBTyxRQUFRLFlBQVksaUJBQWlCLFlBQVk7QUFBQSxFQUMxSDtBQUVBLFFBQU0sV0FBVyxlQUEwQyxFQUFFLE1BQU0sV0FBVyxPQUFPLE1BQU0sVUFBVSxRQUFRLFdBQVcsY0FBYyxhQUFhLFFBQVcsY0FBYyxDQUFDO0FBQzdLLFVBQVEsT0FBTyxNQUFNLEdBQUcsS0FBSyxVQUFVLFVBQVUsTUFBTSxDQUFDLENBQUM7QUFBQSxDQUFJO0FBQzdELFVBQVEsS0FBSyxZQUFZLE1BQU0sQ0FBQztBQUNsQztBQUVBLEtBQUssRUFBRSxNQUFNLENBQUMsVUFBbUI7QUFDL0IsUUFBTSxVQUFVLGlCQUFpQixRQUFRLE1BQU0sVUFBVTtBQUN6RCxRQUFNLFdBQVcsZUFBcUMsRUFBRSxNQUFNLFdBQVcsT0FBTyxFQUFFLFNBQVMsTUFBTSxRQUFRLE1BQU0sUUFBUSxPQUFPLE9BQU8sR0FBRyxRQUFRLGFBQWEsWUFBWSxTQUFTLEdBQUcsUUFBUSxDQUFDLFlBQVksWUFBWSxTQUFTLEVBQUUsT0FBTyxpQkFBaUIsUUFBUSxNQUFNLFFBQVEsT0FBVSxDQUFDLENBQUMsR0FBRyxNQUFNLENBQUMsRUFBZSxDQUFDO0FBQ3JULFVBQVEsT0FBTyxNQUFNLEdBQUcsS0FBSyxVQUFVLFVBQVUsTUFBTSxDQUFDLENBQUM7QUFBQSxDQUFJO0FBQzdELFVBQVEsS0FBSyxDQUFDO0FBQ2hCLENBQUM7IiwKICAibmFtZXMiOiBbInBhdGgiLCAiZW52ZWxvcGUiXQp9Cg==