391 lines
51 KiB
JavaScript
Executable File
391 lines
51 KiB
JavaScript
Executable File
#!/usr/bin/env node
|
|
|
|
// coding-tools/figma-tools/js/src/get-code-connect-map.ts
|
|
import { readFile } from "node:fs/promises";
|
|
import path from "node:path";
|
|
|
|
// coding-tools/figma-tools/js/src/_utils/cli-args.ts
|
|
function parseArgs(argv = process.argv.slice(2)) {
|
|
const args = { _: [] };
|
|
for (let i = 0; i < argv.length; i += 1) {
|
|
const arg = argv[i];
|
|
if (!arg.startsWith("-") || arg === "-") {
|
|
args._.push(arg);
|
|
continue;
|
|
}
|
|
if (arg === "--") {
|
|
const remaining = argv.slice(i + 1);
|
|
args._.push(...remaining);
|
|
break;
|
|
}
|
|
const [rawKey, inlineValue] = arg.split("=", 2);
|
|
const normalisedKey = rawKey.replace(/^-+/, "");
|
|
let value;
|
|
if (inlineValue !== void 0) {
|
|
value = inlineValue;
|
|
} else {
|
|
const next = argv[i + 1];
|
|
if (next !== void 0 && !next.startsWith("-")) {
|
|
value = next;
|
|
i += 1;
|
|
} else {
|
|
value = true;
|
|
}
|
|
}
|
|
args[normalisedKey] = value;
|
|
}
|
|
return args;
|
|
}
|
|
|
|
// coding-tools/figma-tools/js/src/_utils/url-parse.ts
|
|
var FILE_KEY_REGEX = /figma\.com\/(?:file|design)\/([A-Za-z0-9]+)\//i;
|
|
function parseFigmaUrl(input) {
|
|
if (!input) return { fileKey: null, nodeId: null };
|
|
try {
|
|
const url = new URL(input);
|
|
const match = url.href.match(FILE_KEY_REGEX);
|
|
const fileKey = match ? match[1] : null;
|
|
const nodeParam = url.searchParams.get("node-id");
|
|
const nodeId = nodeParam ? ensureNodeId(nodeParam) : null;
|
|
return { fileKey, nodeId };
|
|
} catch {
|
|
return { fileKey: null, nodeId: null };
|
|
}
|
|
}
|
|
function ensureNodeId(value) {
|
|
if (!value) return null;
|
|
const decoded = decodeURIComponent(value);
|
|
if (decoded.includes(":")) return decoded;
|
|
if (/^[0-9]+-[0-9]+$/.test(decoded)) {
|
|
const [left, right] = decoded.split("-", 2);
|
|
return `${left}:${right}`;
|
|
}
|
|
return decoded;
|
|
}
|
|
|
|
// coding-tools/figma-tools/js/src/_utils/config.ts
|
|
var config_default = {
|
|
schemaVersion: "1.0.0",
|
|
source: "agentic-coding-templates/figma-tools",
|
|
http: {
|
|
maxAttempts: 5,
|
|
initialDelayMs: 250
|
|
}
|
|
};
|
|
|
|
// coding-tools/figma-tools/js/src/_utils/envelope.ts
|
|
function buildRateLimitMeta(rateLimit = {}) {
|
|
return {
|
|
remaining: rateLimit.remaining ?? null,
|
|
resetAt: rateLimit.resetAt ?? null,
|
|
attempts: rateLimit.attempts ?? 1,
|
|
lastWaitMs: rateLimit.lastWaitMs ?? 0
|
|
};
|
|
}
|
|
function createEnvelope({
|
|
tool,
|
|
input = {},
|
|
data = {},
|
|
warnings = [],
|
|
errors = [],
|
|
rateLimit,
|
|
schemaVersion
|
|
}) {
|
|
return {
|
|
schemaVersion: schemaVersion ?? config_default.schemaVersion,
|
|
tool,
|
|
input,
|
|
meta: {
|
|
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
source: config_default.source,
|
|
rateLimit: buildRateLimitMeta(rateLimit)
|
|
},
|
|
data,
|
|
warnings,
|
|
errors
|
|
};
|
|
}
|
|
|
|
// coding-tools/figma-tools/js/src/_utils/errors.ts
|
|
var ERROR_EXIT_CODES = {
|
|
INPUT_INVALID: 1,
|
|
CONFIG_INVALID: 1,
|
|
FIGMA_AUTH: 1,
|
|
FIGMA_NOT_FOUND: 2,
|
|
FIGMA_RATE_LIMIT: 2,
|
|
NETWORK: 2,
|
|
INTERNAL: 3
|
|
};
|
|
function createError(code, message, detail) {
|
|
return {
|
|
code,
|
|
message,
|
|
detail: detail ?? null
|
|
};
|
|
}
|
|
function getExitCode(errors = []) {
|
|
if (!errors.length) {
|
|
return 0;
|
|
}
|
|
return errors.reduce((max, error) => {
|
|
const exitCode = ERROR_EXIT_CODES[error.code] ?? 1;
|
|
return Math.max(max, exitCode);
|
|
}, 0);
|
|
}
|
|
|
|
// coding-tools/figma-tools/js/src/_utils/http-client.ts
|
|
var BASE_URL = "https://api.figma.com";
|
|
function sleep(ms) {
|
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
}
|
|
function parseJsonSafely(text) {
|
|
try {
|
|
return text ? JSON.parse(text) : {};
|
|
} catch {
|
|
return { raw: text };
|
|
}
|
|
}
|
|
function parseRateLimit(headers, attempts, lastWaitMs) {
|
|
const remainingHeader = headers.get("x-ratelimit-remaining");
|
|
const resetHeader = headers.get("x-ratelimit-reset");
|
|
let remaining = null;
|
|
if (remainingHeader !== null && remainingHeader !== void 0) {
|
|
const parsed = Number(remainingHeader);
|
|
remaining = Number.isNaN(parsed) ? null : parsed;
|
|
}
|
|
let resetAt = null;
|
|
if (resetHeader) {
|
|
const numericReset = Number(resetHeader);
|
|
if (!Number.isNaN(numericReset)) {
|
|
resetAt = new Date(numericReset * 1e3).toISOString();
|
|
} else {
|
|
const date = new Date(resetHeader);
|
|
if (!Number.isNaN(date.valueOf())) {
|
|
resetAt = date.toISOString();
|
|
}
|
|
}
|
|
}
|
|
return {
|
|
remaining,
|
|
resetAt,
|
|
attempts,
|
|
lastWaitMs
|
|
};
|
|
}
|
|
function computeBackoffMs(attempt, initialDelayMs) {
|
|
return initialDelayMs * 2 ** (attempt - 1);
|
|
}
|
|
async function figmaRequest(options) {
|
|
const {
|
|
path: path2,
|
|
method = "GET",
|
|
token,
|
|
headers = {},
|
|
body,
|
|
searchParams,
|
|
maxAttempts = config_default.http?.maxAttempts ?? 5,
|
|
initialDelayMs = config_default.http?.initialDelayMs ?? 250
|
|
} = options;
|
|
if (!token) {
|
|
return {
|
|
ok: false,
|
|
error: createError("FIGMA_AUTH", "FIGMA_ACCESS_TOKEN is missing from the environment."),
|
|
status: null,
|
|
rateLimit: null
|
|
};
|
|
}
|
|
const url = new URL(path2, BASE_URL);
|
|
if (searchParams) {
|
|
Object.entries(searchParams).forEach(([key, value]) => {
|
|
if (value === void 0 || value === null) return;
|
|
url.searchParams.append(key, String(value));
|
|
});
|
|
}
|
|
let attempt = 0;
|
|
let lastWaitMs = 0;
|
|
while (attempt < maxAttempts) {
|
|
attempt += 1;
|
|
const response = await fetch(url, {
|
|
method,
|
|
headers: {
|
|
"Content-Type": "application/json",
|
|
"X-Figma-Token": token,
|
|
...headers
|
|
},
|
|
body: body ? JSON.stringify(body) : void 0
|
|
});
|
|
const text = await response.text();
|
|
const payload = parseJsonSafely(text);
|
|
const rateLimit = parseRateLimit(response.headers, attempt, lastWaitMs);
|
|
if (response.ok) {
|
|
return { ok: true, data: payload, rateLimit };
|
|
}
|
|
const status = response.status;
|
|
if (status === 401 || status === 403) {
|
|
return { ok: false, error: createError("FIGMA_AUTH", payload?.message ?? "Figma token is unauthorized.", { status }), status, rateLimit };
|
|
}
|
|
if (status === 404) {
|
|
return { ok: false, error: createError("FIGMA_NOT_FOUND", payload?.message ?? "Resource not found.", { status }), status, rateLimit };
|
|
}
|
|
if (status === 429 || status >= 500) {
|
|
if (attempt >= maxAttempts) {
|
|
return {
|
|
ok: false,
|
|
error: createError(status === 429 ? "FIGMA_RATE_LIMIT" : "NETWORK", payload?.message ?? "Figma request failed after maximum retries.", { status }),
|
|
status,
|
|
rateLimit
|
|
};
|
|
}
|
|
let waitMs = computeBackoffMs(attempt, initialDelayMs);
|
|
const resetHeader = response.headers.get("x-ratelimit-reset");
|
|
if (resetHeader) {
|
|
const asNumber = Number(resetHeader);
|
|
if (!Number.isNaN(asNumber)) {
|
|
const resetMs = asNumber * 1e3;
|
|
const delta = resetMs - Date.now();
|
|
if (delta > 0) waitMs = Math.max(waitMs, delta);
|
|
}
|
|
}
|
|
const jitter = Math.floor(Math.random() * 100);
|
|
lastWaitMs = waitMs + jitter;
|
|
await sleep(lastWaitMs);
|
|
continue;
|
|
}
|
|
return { ok: false, error: createError("INTERNAL", payload?.message ?? "Unexpected error from Figma API.", { status }), status, rateLimit };
|
|
}
|
|
return {
|
|
ok: false,
|
|
error: createError("NETWORK", "Unable to reach Figma API."),
|
|
status: null,
|
|
rateLimit: { remaining: null, resetAt: null, attempts: maxAttempts, lastWaitMs }
|
|
};
|
|
}
|
|
|
|
// coding-tools/figma-tools/js/src/get-code-connect-map.ts
|
|
var TOOL_NAME = "get-code-connect-map";
|
|
function log(message, verbose) {
|
|
if (verbose) process.stderr.write(`[${TOOL_NAME}] ${message}
|
|
`);
|
|
}
|
|
function toOptionalString(value) {
|
|
return typeof value === "string" && value.length > 0 ? value : null;
|
|
}
|
|
function exitWithEnvelope(envelope, errors = []) {
|
|
process.stdout.write(`${JSON.stringify(envelope, null, 2)}
|
|
`);
|
|
process.exit(getExitCode(errors));
|
|
}
|
|
async function readRepoConfig() {
|
|
try {
|
|
const configPath = path.resolve("config/code-connect-map.json");
|
|
const content = await readFile(configPath, "utf8");
|
|
const parsed = JSON.parse(content);
|
|
if (parsed && Array.isArray(parsed.components)) return parsed;
|
|
return { version: "0.1", components: [] };
|
|
} catch {
|
|
return { version: "0.1", components: [] };
|
|
}
|
|
}
|
|
async function main() {
|
|
const args = parseArgs();
|
|
const verbose = Boolean(args.verbose ?? args.v);
|
|
const schemaVersion = toOptionalString(args["schema-version"]) ?? void 0;
|
|
const warnings = [];
|
|
const errors = [];
|
|
let repoConfig = { version: "0.1", components: [] };
|
|
try {
|
|
repoConfig = await readRepoConfig();
|
|
} catch (error) {
|
|
warnings.push(error instanceof Error ? error.message : String(error));
|
|
}
|
|
const token = process.env.FIGMA_ACCESS_TOKEN;
|
|
if (!token || !token.trim()) {
|
|
errors.push(createError("FIGMA_AUTH", "FIGMA_ACCESS_TOKEN is required but was not provided."));
|
|
const envelope2 = createEnvelope({ tool: TOOL_NAME, input: { fileKey: null, nodeId: null }, warnings, errors, schemaVersion, data: {} });
|
|
exitWithEnvelope(envelope2, errors);
|
|
}
|
|
const urlInput = toOptionalString(args.url) ?? toOptionalString(args.u);
|
|
let fileKey = toOptionalString(args["file-key"]) ?? void 0;
|
|
const nodeIdInput = ensureNodeId(toOptionalString(args["node-id"]));
|
|
if (urlInput) {
|
|
const parsed = parseFigmaUrl(urlInput);
|
|
fileKey = fileKey || parsed.fileKey || void 0;
|
|
}
|
|
const input = { fileKey: fileKey ?? null, nodeId: nodeIdInput ?? null };
|
|
if (!fileKey) errors.push(createError("INPUT_INVALID", "A valid Figma file key is required (--file-key or --url)."));
|
|
if (errors.length) {
|
|
const envelope2 = createEnvelope({ tool: TOOL_NAME, input, warnings, errors, data: {}, schemaVersion });
|
|
exitWithEnvelope(envelope2, errors);
|
|
}
|
|
const resolvedFileKey = fileKey;
|
|
log("Fetching dev resources", verbose);
|
|
const devResourcesResponse = await figmaRequest({ path: `/v1/files/${resolvedFileKey}/devresources`, token });
|
|
log("Fetching components", verbose);
|
|
const componentsResponse = await figmaRequest({ path: `/v1/files/${resolvedFileKey}/components`, token });
|
|
if (!devResourcesResponse.ok) {
|
|
errors.push(devResourcesResponse.error ?? createError("INTERNAL", "Failed to fetch dev resources."));
|
|
const envelope2 = createEnvelope({ tool: TOOL_NAME, input, warnings, errors, rateLimit: devResourcesResponse.rateLimit ?? void 0, schemaVersion, data: {} });
|
|
exitWithEnvelope(envelope2, errors);
|
|
}
|
|
if (!componentsResponse.ok) warnings.push(componentsResponse.error?.message ?? "Failed to fetch components.");
|
|
const devResources = devResourcesResponse.data?.dev_resources ?? [];
|
|
const componentsMap = componentsResponse.ok ? componentsResponse.data?.components ?? {} : {};
|
|
const repoMappings = repoConfig.components ?? [];
|
|
const normalisedResources = devResources.map((resource) => ({
|
|
id: resource.id,
|
|
name: resource.name,
|
|
description: resource.description ?? null,
|
|
url: resource.url ?? null,
|
|
nodeId: resource.node_id ?? null,
|
|
componentId: resource.component_id ?? null,
|
|
fileKey: resource.file_key ?? resolvedFileKey,
|
|
status: resource.status ?? null,
|
|
createdAt: resource.created_at ?? null,
|
|
updatedAt: resource.updated_at ?? null
|
|
}));
|
|
const normalisedComponents = Object.entries(componentsMap).map(([componentId, component]) => ({
|
|
id: componentId,
|
|
key: component.key,
|
|
name: component.name,
|
|
description: component.description ?? null,
|
|
fileKey: component.file_key ?? resolvedFileKey,
|
|
nodeId: component.node_id ?? null
|
|
}));
|
|
const findRepoMapping = (name) => {
|
|
if (!name) return null;
|
|
return repoMappings.find((m) => m.name === name || m.component === name) ?? null;
|
|
};
|
|
const mappings = normalisedResources.map((resource) => {
|
|
const component = resource.componentId ? normalisedComponents.find((entry) => entry.id === resource.componentId) : null;
|
|
const repoMapping = findRepoMapping(component?.name ?? resource.name);
|
|
if (!repoMapping) {
|
|
warnings.push(`Node ${resource.nodeId ?? component?.nodeId ?? "unknown"} (${resource.name ?? component?.name ?? "unnamed"}) has no mapping in config/code-connect-map.json.`);
|
|
}
|
|
return {
|
|
nodeId: resource.nodeId ?? component?.nodeId ?? null,
|
|
componentId: resource.componentId ?? component?.id ?? null,
|
|
componentKey: component?.key ?? null,
|
|
componentName: component?.name ?? resource.name ?? null,
|
|
repoComponent: repoMapping?.component ?? null,
|
|
repoPath: repoMapping?.path ?? null,
|
|
props: repoMapping?.props ?? null,
|
|
description: component?.description ?? resource.description ?? null,
|
|
status: resource.status ?? null,
|
|
sourceUrl: resource.url ?? null
|
|
};
|
|
});
|
|
const data = { file: { key: resolvedFileKey }, mappings, components: normalisedComponents, devResources: normalisedResources };
|
|
const envelope = createEnvelope({ tool: TOOL_NAME, input, data, warnings, errors, rateLimit: devResourcesResponse.rateLimit ?? void 0, schemaVersion });
|
|
process.stdout.write(`${JSON.stringify(envelope, null, 2)}
|
|
`);
|
|
process.exit(getExitCode(errors));
|
|
}
|
|
main().catch((error) => {
|
|
const message = error instanceof Error ? error.message : "Unknown error";
|
|
const envelope = createEnvelope({ tool: TOOL_NAME, input: { fileKey: null, nodeId: null }, errors: [createError("INTERNAL", message, { stack: error instanceof Error ? error.stack : void 0 })], data: {} });
|
|
process.stdout.write(`${JSON.stringify(envelope, null, 2)}
|
|
`);
|
|
process.exit(3);
|
|
});
|
|
//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiLi4vc3JjL2dldC1jb2RlLWNvbm5lY3QtbWFwLnRzIiwgIi4uL3NyYy9fdXRpbHMvY2xpLWFyZ3MudHMiLCAiLi4vc3JjL191dGlscy91cmwtcGFyc2UudHMiLCAiLi4vc3JjL191dGlscy9jb25maWcudHMiLCAiLi4vc3JjL191dGlscy9lbnZlbG9wZS50cyIsICIuLi9zcmMvX3V0aWxzL2Vycm9ycy50cyIsICIuLi9zcmMvX3V0aWxzL2h0dHAtY2xpZW50LnRzIl0sCiAgInNvdXJjZXNDb250ZW50IjogWyIjIS91c3IvYmluL2VudiBub2RlXG5cbmltcG9ydCB7IHJlYWRGaWxlIH0gZnJvbSAnbm9kZTpmcy9wcm9taXNlcydcbmltcG9ydCBwYXRoIGZyb20gJ25vZGU6cGF0aCdcbmltcG9ydCB7IHBhcnNlQXJncywgdHlwZSBDbGlBcmdzIH0gZnJvbSAnLi9fdXRpbHMvY2xpLWFyZ3MudHMnXG5pbXBvcnQgeyBwYXJzZUZpZ21hVXJsLCBlbnN1cmVOb2RlSWQgfSBmcm9tICcuL191dGlscy91cmwtcGFyc2UudHMnXG5pbXBvcnQgeyBjcmVhdGVFbnZlbG9wZSwgdHlwZSBUb29sRW52ZWxvcGUgfSBmcm9tICcuL191dGlscy9lbnZlbG9wZS50cydcbmltcG9ydCB7IGNyZWF0ZUVycm9yLCBnZXRFeGl0Q29kZSwgdHlwZSBUb29sRXJyb3IgfSBmcm9tICcuL191dGlscy9lcnJvcnMudHMnXG5pbXBvcnQgeyBmaWdtYVJlcXVlc3QgfSBmcm9tICcuL191dGlscy9odHRwLWNsaWVudC50cydcblxuY29uc3QgVE9PTF9OQU1FID0gJ2dldC1jb2RlLWNvbm5lY3QtbWFwJ1xudHlwZSBFbXB0eURhdGEgPSBSZWNvcmQ8c3RyaW5nLCBuZXZlcj5cblxuaW50ZXJmYWNlIFRvb2xJbnB1dCBleHRlbmRzIFJlY29yZDxzdHJpbmcsIHVua25vd24+IHsgZmlsZUtleTogc3RyaW5nIHwgbnVsbDsgbm9kZUlkOiBzdHJpbmcgfCBudWxsIH1cblxuaW50ZXJmYWNlIFJlcG9Db21wb25lbnRNYXBwaW5nIHsgbmFtZT86IHN0cmluZzsgY29tcG9uZW50Pzogc3RyaW5nOyBwYXRoPzogc3RyaW5nOyBwcm9wcz86IFJlY29yZDxzdHJpbmcsIHVua25vd24+IH1cbmludGVyZmFjZSBSZXBvQ29uZmlnIHsgdmVyc2lvbj86IHN0cmluZzsgY29tcG9uZW50cz86IFJlcG9Db21wb25lbnRNYXBwaW5nW10gfVxuXG5pbnRlcmZhY2UgRGV2UmVzb3VyY2VQYXlsb2FkIHsgZGV2X3Jlc291cmNlcz86IERldlJlc291cmNlW10gfVxuaW50ZXJmYWNlIERldlJlc291cmNlIHsgaWQ6IHN0cmluZzsgbmFtZT86IHN0cmluZzsgZGVzY3JpcHRpb24/OiBzdHJpbmc7IHVybD86IHN0cmluZzsgbm9kZV9pZD86IHN0cmluZzsgY29tcG9uZW50X2lkPzogc3RyaW5nOyBmaWxlX2tleT86IHN0cmluZzsgc3RhdHVzPzogc3RyaW5nOyBjcmVhdGVkX2F0Pzogc3RyaW5nOyB1cGRhdGVkX2F0Pzogc3RyaW5nIH1cbmludGVyZmFjZSBOb3JtYWxpc2VkRGV2UmVzb3VyY2UgeyBpZDogc3RyaW5nOyBuYW1lPzogc3RyaW5nOyBkZXNjcmlwdGlvbjogc3RyaW5nIHwgbnVsbDsgdXJsOiBzdHJpbmcgfCBudWxsOyBub2RlSWQ6IHN0cmluZyB8IG51bGw7IGNvbXBvbmVudElkOiBzdHJpbmcgfCBudWxsOyBmaWxlS2V5OiBzdHJpbmc7IHN0YXR1czogc3RyaW5nIHwgbnVsbDsgY3JlYXRlZEF0OiBzdHJpbmcgfCBudWxsOyB1cGRhdGVkQXQ6IHN0cmluZyB8IG51bGwgfVxuXG5pbnRlcmZhY2UgQ29tcG9uZW50TWV0YSB7IGtleT86IHN0cmluZzsgbmFtZT86IHN0cmluZzsgZGVzY3JpcHRpb24/OiBzdHJpbmc7IGZpbGVfa2V5Pzogc3RyaW5nOyBub2RlX2lkPzogc3RyaW5nIH1cbmludGVyZmFjZSBDb21wb25lbnRzUGF5bG9hZCB7IGNvbXBvbmVudHM/OiBSZWNvcmQ8c3RyaW5nLCBDb21wb25lbnRNZXRhPiB9XG5pbnRlcmZhY2UgTm9ybWFsaXNlZENvbXBvbmVudCB7IGlkOiBzdHJpbmc7IGtleT86IHN0cmluZzsgbmFtZT86IHN0cmluZzsgZGVzY3JpcHRpb246IHN0cmluZyB8IG51bGw7IGZpbGVLZXk6IHN0cmluZzsgbm9kZUlkOiBzdHJpbmcgfCBudWxsIH1cblxuaW50ZXJmYWNlIE1hcHBpbmcgeyBub2RlSWQ6IHN0cmluZyB8IG51bGw7IGNvbXBvbmVudElkOiBzdHJpbmcgfCBudWxsOyBjb21wb25lbnRLZXk6IHN0cmluZyB8IG51bGw7IGNvbXBvbmVudE5hbWU6IHN0cmluZyB8IG51bGw7IHJlcG9Db21wb25lbnQ6IHN0cmluZyB8IG51bGw7IHJlcG9QYXRoOiBzdHJpbmcgfCBudWxsOyBwcm9wczogUmVjb3JkPHN0cmluZywgdW5rbm93bj4gfCBudWxsOyBkZXNjcmlwdGlvbjogc3RyaW5nIHwgbnVsbDsgc3RhdHVzOiBzdHJpbmcgfCBudWxsOyBzb3VyY2VVcmw6IHN0cmluZyB8IG51bGwgfVxuXG5pbnRlcmZhY2UgQ29kZUNvbm5lY3REYXRhIHsgZmlsZTogeyBrZXk6IHN0cmluZyB9OyBtYXBwaW5nczogTWFwcGluZ1tdOyBjb21wb25lbnRzOiBOb3JtYWxpc2VkQ29tcG9uZW50W107IGRldlJlc291cmNlczogTm9ybWFsaXNlZERldlJlc291cmNlW10gfVxuXG5mdW5jdGlvbiBsb2cobWVzc2FnZTogc3RyaW5nLCB2ZXJib3NlOiBib29sZWFuKTogdm9pZCB7IGlmICh2ZXJib3NlKSBwcm9jZXNzLnN0ZGVyci53cml0ZShgWyR7VE9PTF9OQU1FfV0gJHttZXNzYWdlfVxcbmApIH1cbmZ1bmN0aW9uIHRvT3B0aW9uYWxTdHJpbmcodmFsdWU6IENsaUFyZ3Nbc3RyaW5nXSk6IHN0cmluZyB8IG51bGwgeyByZXR1cm4gdHlwZW9mIHZhbHVlID09PSAnc3RyaW5nJyAmJiB2YWx1ZS5sZW5ndGggPiAwID8gdmFsdWUgOiBudWxsIH1cbmZ1bmN0aW9uIGV4aXRXaXRoRW52ZWxvcGUoZW52ZWxvcGU6IFRvb2xFbnZlbG9wZTxUb29sSW5wdXQsIENvZGVDb25uZWN0RGF0YSB8IEVtcHR5RGF0YT4sIGVycm9yczogVG9vbEVycm9yW10gPSBbXSk6IG5ldmVyIHsgcHJvY2Vzcy5zdGRvdXQud3JpdGUoYCR7SlNPTi5zdHJpbmdpZnkoZW52ZWxvcGUsIG51bGwsIDIpfVxcbmApOyBwcm9jZXNzLmV4aXQoZ2V0RXhpdENvZGUoZXJyb3JzKSkgfVxuXG5hc3luYyBmdW5jdGlvbiByZWFkUmVwb0NvbmZpZygpOiBQcm9taXNlPFJlcG9Db25maWc+IHtcbiAgdHJ5IHtcbiAgICBjb25zdCBjb25maWdQYXRoID0gcGF0aC5yZXNvbHZlKCdjb25maWcvY29kZS1jb25uZWN0LW1hcC5qc29uJylcbiAgICBjb25zdCBjb250ZW50ID0gYXdhaXQgcmVhZEZpbGUoY29uZmlnUGF0aCwgJ3V0ZjgnKVxuICAgIGNvbnN0IHBhcnNlZCA9IEpTT04ucGFyc2UoY29udGVudClcbiAgICBpZiAocGFyc2VkICYmIEFycmF5LmlzQXJyYXkocGFyc2VkLmNvbXBvbmVudHMpKSByZXR1cm4gcGFyc2VkXG4gICAgcmV0dXJuIHsgdmVyc2lvbjogJzAuMScsIGNvbXBvbmVudHM6IFtdIH1cbiAgfSBjYXRjaCB7XG4gICAgcmV0dXJuIHsgdmVyc2lvbjogJzAuMScsIGNvbXBvbmVudHM6IFtdIH1cbiAgfVxufVxuXG5hc3luYyBmdW5jdGlvbiBtYWluKCk6IFByb21pc2U8dm9pZD4ge1xuICBjb25zdCBhcmdzID0gcGFyc2VBcmdzKClcbiAgY29uc3QgdmVyYm9zZSA9IEJvb2xlYW4oYXJncy52ZXJib3NlID8/IGFyZ3MudilcbiAgY29uc3Qgc2NoZW1hVmVyc2lvbiA9IHRvT3B0aW9uYWxTdHJpbmcoYXJnc1snc2NoZW1hLXZlcnNpb24nXSkgPz8gdW5kZWZpbmVkXG5cbiAgY29uc3Qgd2FybmluZ3M6IHN0cmluZ1tdID0gW11cbiAgY29uc3QgZXJyb3JzOiBUb29sRXJyb3JbXSA9IFtdXG5cbiAgbGV0IHJlcG9Db25maWc6IFJlcG9Db25maWcgPSB7IHZlcnNpb246ICcwLjEnLCBjb21wb25lbnRzOiBbXSB9XG4gIHRyeSB7IHJlcG9Db25maWcgPSBhd2FpdCByZWFkUmVwb0NvbmZpZygpIH0gY2F0Y2ggKGVycm9yKSB7IHdhcm5pbmdzLnB1c2goZXJyb3IgaW5zdGFuY2VvZiBFcnJvciA/IGVycm9yLm1lc3NhZ2UgOiBTdHJpbmcoZXJyb3IpKSB9XG5cbiAgY29uc3QgdG9rZW4gPSBwcm9jZXNzLmVudi5GSUdNQV9BQ0NFU1NfVE9LRU5cbiAgaWYgKCF0b2tlbiB8fCAhdG9rZW4udHJpbSgpKSB7XG4gICAgZXJyb3JzLnB1c2goY3JlYXRlRXJyb3IoJ0ZJR01BX0FVVEgnLCAnRklHTUFfQUNDRVNTX1RPS0VOIGlzIHJlcXVpcmVkIGJ1dCB3YXMgbm90IHByb3ZpZGVkLicpKVxuICAgIGNvbnN0IGVudmVsb3BlID0gY3JlYXRlRW52ZWxvcGU8VG9vbElucHV0LCBFbXB0eURhdGE+KHsgdG9vbDogVE9PTF9OQU1FLCBpbnB1dDogeyBmaWxlS2V5OiBudWxsLCBub2RlSWQ6IG51bGwgfSwgd2FybmluZ3MsIGVycm9ycywgc2NoZW1hVmVyc2lvbiwgZGF0YToge30gYXMgRW1wdHlEYXRhIH0pXG4gICAgZXhpdFdpdGhFbnZlbG9wZShlbnZlbG9wZSwgZXJyb3JzKVxuICB9XG5cbiAgY29uc3QgdXJsSW5wdXQgPSB0b09wdGlvbmFsU3RyaW5nKGFyZ3MudXJsKSA/PyB0b09wdGlvbmFsU3RyaW5nKGFyZ3MudSlcbiAgbGV0IGZpbGVLZXkgPSB0b09wdGlvbmFsU3RyaW5nKGFyZ3NbJ2ZpbGUta2V5J10pID8/IHVuZGVmaW5lZFxuICBjb25zdCBub2RlSWRJbnB1dCA9IGVuc3VyZU5vZGVJZCh0b09wdGlvbmFsU3RyaW5nKGFyZ3NbJ25vZGUtaWQnXSkpXG4gIGlmICh1cmxJbnB1dCkgeyBjb25zdCBwYXJzZWQgPSBwYXJzZUZpZ21hVXJsKHVybElucHV0KTsgZmlsZUtleSA9IGZpbGVLZXkgfHwgcGFyc2VkLmZpbGVLZXkgfHwgdW5kZWZpbmVkIH1cblxuICBjb25zdCBpbnB1dDogVG9vbElucHV0ID0geyBmaWxlS2V5OiBmaWxlS2V5ID8/IG51bGwsIG5vZGVJZDogbm9kZUlkSW5wdXQgPz8gbnVsbCB9XG4gIGlmICghZmlsZUtleSkgZXJyb3JzLnB1c2goY3JlYXRlRXJyb3IoJ0lOUFVUX0lOVkFMSUQnLCAnQSB2YWxpZCBGaWdtYSBmaWxlIGtleSBpcyByZXF1aXJlZCAoLS1maWxlLWtleSBvciAtLXVybCkuJykpXG4gIGlmIChlcnJvcnMubGVuZ3RoKSB7IGNvbnN0IGVudmVsb3BlID0gY3JlYXRlRW52ZWxvcGU8VG9vbElucHV0LCBFbXB0eURhdGE+KHsgdG9vbDogVE9PTF9OQU1FLCBpbnB1dCwgd2FybmluZ3MsIGVycm9ycywgZGF0YToge30gYXMgRW1wdHlEYXRhLCBzY2hlbWFWZXJzaW9uIH0pOyBleGl0V2l0aEVudmVsb3BlKGVudmVsb3BlLCBlcnJvcnMpIH1cblxuICBjb25zdCByZXNvbHZlZEZpbGVLZXkgPSBmaWxlS2V5IGFzIHN0cmluZ1xuXG4gIGxvZygnRmV0Y2hpbmcgZGV2IHJlc291cmNlcycsIHZlcmJvc2UpXG4gIGNvbnN0IGRldlJlc291cmNlc1Jlc3BvbnNlID0gYXdhaXQgZmlnbWFSZXF1ZXN0PERldlJlc291cmNlUGF5bG9hZD4oeyBwYXRoOiBgL3YxL2ZpbGVzLyR7cmVzb2x2ZWRGaWxlS2V5fS9kZXZyZXNvdXJjZXNgLCB0b2tlbiB9KVxuICBsb2coJ0ZldGNoaW5nIGNvbXBvbmVudHMnLCB2ZXJib3NlKVxuICBjb25zdCBjb21wb25lbnRzUmVzcG9uc2UgPSBhd2FpdCBmaWdtYVJlcXVlc3Q8Q29tcG9uZW50c1BheWxvYWQ+KHsgcGF0aDogYC92MS9maWxlcy8ke3Jlc29sdmVkRmlsZUtleX0vY29tcG9uZW50c2AsIHRva2VuIH0pXG5cbiAgaWYgKCFkZXZSZXNvdXJjZXNSZXNwb25zZS5vaykge1xuICAgIGVycm9ycy5wdXNoKGRldlJlc291cmNlc1Jlc3BvbnNlLmVycm9yID8/IGNyZWF0ZUVycm9yKCdJTlRFUk5BTCcsICdGYWlsZWQgdG8gZmV0Y2ggZGV2IHJlc291cmNlcy4nKSlcbiAgICBjb25zdCBlbnZlbG9wZSA9IGNyZWF0ZUVudmVsb3BlPFRvb2xJbnB1dCwgRW1wdHlEYXRhPih7IHRvb2w6IFRPT0xfTkFNRSwgaW5wdXQsIHdhcm5pbmdzLCBlcnJvcnMsIHJhdGVMaW1pdDogZGV2UmVzb3VyY2VzUmVzcG9uc2UucmF0ZUxpbWl0ID8/IHVuZGVmaW5lZCwgc2NoZW1hVmVyc2lvbiwgZGF0YToge30gYXMgRW1wdHlEYXRhIH0pXG4gICAgZXhpdFdpdGhFbnZlbG9wZShlbnZlbG9wZSwgZXJyb3JzKVxuICB9XG4gIGlmICghY29tcG9uZW50c1Jlc3BvbnNlLm9rKSB3YXJuaW5ncy5wdXNoKGNvbXBvbmVudHNSZXNwb25zZS5lcnJvcj8ubWVzc2FnZSA/PyAnRmFpbGVkIHRvIGZldGNoIGNvbXBvbmVudHMuJylcblxuICBjb25zdCBkZXZSZXNvdXJjZXMgPSBkZXZSZXNvdXJjZXNSZXNwb25zZS5kYXRhPy5kZXZfcmVzb3VyY2VzID8/IFtdXG4gIGNvbnN0IGNvbXBvbmVudHNNYXA6IFJlY29yZDxzdHJpbmcsIENvbXBvbmVudE1ldGE+ID0gY29tcG9uZW50c1Jlc3BvbnNlLm9rID8gY29tcG9uZW50c1Jlc3BvbnNlLmRhdGE/LmNvbXBvbmVudHMgPz8ge30gOiB7fVxuICBjb25zdCByZXBvTWFwcGluZ3MgPSByZXBvQ29uZmlnLmNvbXBvbmVudHMgPz8gW11cblxuICBjb25zdCBub3JtYWxpc2VkUmVzb3VyY2VzOiBOb3JtYWxpc2VkRGV2UmVzb3VyY2VbXSA9IGRldlJlc291cmNlcy5tYXAoKHJlc291cmNlOiBEZXZSZXNvdXJjZSkgPT4gKHtcbiAgICBpZDogcmVzb3VyY2UuaWQsXG4gICAgbmFtZTogcmVzb3VyY2UubmFtZSxcbiAgICBkZXNjcmlwdGlvbjogcmVzb3VyY2UuZGVzY3JpcHRpb24gPz8gbnVsbCxcbiAgICB1cmw6IHJlc291cmNlLnVybCA/PyBudWxsLFxuICAgIG5vZGVJZDogcmVzb3VyY2Uubm9kZV9pZCA/PyBudWxsLFxuICAgIGNvbXBvbmVudElkOiByZXNvdXJjZS5jb21wb25lbnRfaWQgPz8gbnVsbCxcbiAgICBmaWxlS2V5OiByZXNvdXJjZS5maWxlX2tleSA/PyByZXNvbHZlZEZpbGVLZXksXG4gICAgc3RhdHVzOiByZXNvdXJjZS5zdGF0dXMgPz8gbnVsbCxcbiAgICBjcmVhdGVkQXQ6IHJlc291cmNlLmNyZWF0ZWRfYXQgPz8gbnVsbCxcbiAgICB1cGRhdGVkQXQ6IHJlc291cmNlLnVwZGF0ZWRfYXQgPz8gbnVsbCxcbiAgfSkpXG5cbiAgY29uc3Qgbm9ybWFsaXNlZENvbXBvbmVudHM6IE5vcm1hbGlzZWRDb21wb25lbnRbXSA9IE9iamVjdC5lbnRyaWVzKGNvbXBvbmVudHNNYXApLm1hcCgoW2NvbXBvbmVudElkLCBjb21wb25lbnRdKSA9PiAoe1xuICAgIGlkOiBjb21wb25lbnRJZCxcbiAgICBrZXk6IGNvbXBvbmVudC5rZXksXG4gICAgbmFtZTogY29tcG9uZW50Lm5hbWUsXG4gICAgZGVzY3JpcHRpb246IGNvbXBvbmVudC5kZXNjcmlwdGlvbiA/PyBudWxsLFxuICAgIGZpbGVLZXk6IGNvbXBvbmVudC5maWxlX2tleSA/PyByZXNvbHZlZEZpbGVLZXksXG4gICAgbm9kZUlkOiBjb21wb25lbnQubm9kZV9pZCA/PyBudWxsLFxuICB9KSlcblxuICBjb25zdCBmaW5kUmVwb01hcHBpbmcgPSAobmFtZT86IHN0cmluZyB8IG51bGwpID0+IHtcbiAgICBpZiAoIW5hbWUpIHJldHVybiBudWxsXG4gICAgcmV0dXJuIHJlcG9NYXBwaW5ncy5maW5kKChtKSA9PiBtLm5hbWUgPT09IG5hbWUgfHwgbS5jb21wb25lbnQgPT09IG5hbWUpID8/IG51bGxcbiAgfVxuXG4gIGNvbnN0IG1hcHBpbmdzOiBNYXBwaW5nW10gPSBub3JtYWxpc2VkUmVzb3VyY2VzLm1hcCgocmVzb3VyY2UpID0+IHtcbiAgICBjb25zdCBjb21wb25lbnQgPSByZXNvdXJjZS5jb21wb25lbnRJZCA/IG5vcm1hbGlzZWRDb21wb25lbnRzLmZpbmQoKGVudHJ5KSA9PiBlbnRyeS5pZCA9PT0gcmVzb3VyY2UuY29tcG9uZW50SWQpIDogbnVsbFxuICAgIGNvbnN0IHJlcG9NYXBwaW5nID0gZmluZFJlcG9NYXBwaW5nKGNvbXBvbmVudD8ubmFtZSA/PyByZXNvdXJjZS5uYW1lKVxuICAgIGlmICghcmVwb01hcHBpbmcpIHtcbiAgICAgIHdhcm5pbmdzLnB1c2goYE5vZGUgJHtyZXNvdXJjZS5ub2RlSWQgPz8gY29tcG9uZW50Py5ub2RlSWQgPz8gJ3Vua25vd24nfSAoJHtyZXNvdXJjZS5uYW1lID8/IGNvbXBvbmVudD8ubmFtZSA/PyAndW5uYW1lZCd9KSBoYXMgbm8gbWFwcGluZyBpbiBjb25maWcvY29kZS1jb25uZWN0LW1hcC5qc29uLmApXG4gICAgfVxuICAgIHJldHVybiB7XG4gICAgICBub2RlSWQ6IHJlc291cmNlLm5vZGVJZCA/PyBjb21wb25lbnQ/Lm5vZGVJZCA/PyBudWxsLFxuICAgICAgY29tcG9uZW50SWQ6IHJlc291cmNlLmNvbXBvbmVudElkID8/IGNvbXBvbmVudD8uaWQgPz8gbnVsbCxcbiAgICAgIGNvbXBvbmVudEtleTogY29tcG9uZW50Py5rZXkgPz8gbnVsbCxcbiAgICAgIGNvbXBvbmVudE5hbWU6IGNvbXBvbmVudD8ubmFtZSA/PyByZXNvdXJjZS5uYW1lID8/IG51bGwsXG4gICAgICByZXBvQ29tcG9uZW50OiByZXBvTWFwcGluZz8uY29tcG9uZW50ID8/IG51bGwsXG4gICAgICByZXBvUGF0aDogcmVwb01hcHBpbmc/LnBhdGggPz8gbnVsbCxcbiAgICAgIHByb3BzOiByZXBvTWFwcGluZz8ucHJvcHMgPz8gbnVsbCxcbiAgICAgIGRlc2NyaXB0aW9uOiBjb21wb25lbnQ/LmRlc2NyaXB0aW9uID8/IHJlc291cmNlLmRlc2NyaXB0aW9uID8/IG51bGwsXG4gICAgICBzdGF0dXM6IHJlc291cmNlLnN0YXR1cyA/PyBudWxsLFxuICAgICAgc291cmNlVXJsOiByZXNvdXJjZS51cmwgPz8gbnVsbCxcbiAgICB9XG4gIH0pXG5cbiAgY29uc3QgZGF0YTogQ29kZUNvbm5lY3REYXRhID0geyBmaWxlOiB7IGtleTogcmVzb2x2ZWRGaWxlS2V5IH0sIG1hcHBpbmdzLCBjb21wb25lbnRzOiBub3JtYWxpc2VkQ29tcG9uZW50cywgZGV2UmVzb3VyY2VzOiBub3JtYWxpc2VkUmVzb3VyY2VzIH1cblxuICBjb25zdCBlbnZlbG9wZSA9IGNyZWF0ZUVudmVsb3BlPFRvb2xJbnB1dCwgQ29kZUNvbm5lY3REYXRhPih7IHRvb2w6IFRPT0xfTkFNRSwgaW5wdXQsIGRhdGEsIHdhcm5pbmdzLCBlcnJvcnMsIHJhdGVMaW1pdDogZGV2UmVzb3VyY2VzUmVzcG9uc2UucmF0ZUxpbWl0ID8/IHVuZGVmaW5lZCwgc2NoZW1hVmVyc2lvbiB9KVxuICBwcm9jZXNzLnN0ZG91dC53cml0ZShgJHtKU09OLnN0cmluZ2lmeShlbnZlbG9wZSwgbnVsbCwgMil9XFxuYClcbiAgcHJvY2Vzcy5leGl0KGdldEV4aXRDb2RlKGVycm9ycykpXG59XG5cbm1haW4oKS5jYXRjaCgoZXJyb3I6IHVua25vd24pID0+IHtcbiAgY29uc3QgbWVzc2FnZSA9IGVycm9yIGluc3RhbmNlb2YgRXJyb3IgPyBlcnJvci5tZXNzYWdlIDogJ1Vua25vd24gZXJyb3InXG4gIGNvbnN0IGVudmVsb3BlID0gY3JlYXRlRW52ZWxvcGU8VG9vbElucHV0LCBFbXB0eURhdGE+KHsgdG9vbDogVE9PTF9OQU1FLCBpbnB1dDogeyBmaWxlS2V5OiBudWxsLCBub2RlSWQ6IG51bGwgfSwgZXJyb3JzOiBbY3JlYXRlRXJyb3IoJ0lOVEVSTkFMJywgbWVzc2FnZSwgeyBzdGFjazogZXJyb3IgaW5zdGFuY2VvZiBFcnJvciA/IGVycm9yLnN0YWNrIDogdW5kZWZpbmVkIH0pXSwgZGF0YToge30gYXMgRW1wdHlEYXRhIH0pXG4gIHByb2Nlc3Muc3Rkb3V0LndyaXRlKGAke0pTT04uc3RyaW5naWZ5KGVudmVsb3BlLCBudWxsLCAyKX1cXG5gKVxuICBwcm9jZXNzLmV4aXQoMylcbn0pXG5cbiIsICJleHBvcnQgdHlwZSBDbGlBcmdWYWx1ZSA9IHN0cmluZyB8IGJvb2xlYW47XG5cbmV4cG9ydCBpbnRlcmZhY2UgQ2xpQXJncyB7XG4gIF86IHN0cmluZ1tdO1xuICBba2V5OiBzdHJpbmddOiBDbGlBcmdWYWx1ZSB8IHN0cmluZ1tdO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gcGFyc2VBcmdzKGFyZ3Y6IHN0cmluZ1tdID0gcHJvY2Vzcy5hcmd2LnNsaWNlKDIpKTogQ2xpQXJncyB7XG4gIGNvbnN0IGFyZ3M6IENsaUFyZ3MgPSB7IF86IFtdIH07XG5cbiAgZm9yIChsZXQgaSA9IDA7IGkgPCBhcmd2Lmxlbmd0aDsgaSArPSAxKSB7XG4gICAgY29uc3QgYXJnID0gYXJndltpXTtcblxuICAgIGlmICghYXJnLnN0YXJ0c1dpdGgoJy0nKSB8fCBhcmcgPT09ICctJykge1xuICAgICAgYXJncy5fLnB1c2goYXJnKTtcbiAgICAgIGNvbnRpbnVlO1xuICAgIH1cblxuICAgIGlmIChhcmcgPT09ICctLScpIHtcbiAgICAgIGNvbnN0IHJlbWFpbmluZyA9IGFyZ3Yuc2xpY2UoaSArIDEpO1xuICAgICAgYXJncy5fLnB1c2goLi4ucmVtYWluaW5nKTtcbiAgICAgIGJyZWFrO1xuICAgIH1cblxuICAgIGNvbnN0IFtyYXdLZXksIGlubGluZVZhbHVlXSA9IGFyZy5zcGxpdCgnPScsIDIpO1xuICAgIGNvbnN0IG5vcm1hbGlzZWRLZXkgPSByYXdLZXkucmVwbGFjZSgvXi0rLywgJycpO1xuXG4gICAgbGV0IHZhbHVlOiBDbGlBcmdWYWx1ZTtcbiAgICBpZiAoaW5saW5lVmFsdWUgIT09IHVuZGVmaW5lZCkge1xuICAgICAgdmFsdWUgPSBpbmxpbmVWYWx1ZTtcbiAgICB9IGVsc2Uge1xuICAgICAgY29uc3QgbmV4dCA9IGFyZ3ZbaSArIDFdO1xuICAgICAgaWYgKG5leHQgIT09IHVuZGVmaW5lZCAmJiAhbmV4dC5zdGFydHNXaXRoKCctJykpIHtcbiAgICAgICAgdmFsdWUgPSBuZXh0O1xuICAgICAgICBpICs9IDE7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICB2YWx1ZSA9IHRydWU7XG4gICAgICB9XG4gICAgfVxuXG4gICAgYXJnc1tub3JtYWxpc2VkS2V5XSA9IHZhbHVlO1xuICB9XG5cbiAgcmV0dXJuIGFyZ3M7XG59XG5cbiIsICJjb25zdCBGSUxFX0tFWV9SRUdFWCA9IC9maWdtYVxcLmNvbVxcLyg/OmZpbGV8ZGVzaWduKVxcLyhbQS1aYS16MC05XSspXFwvL2k7XG5cbmV4cG9ydCBpbnRlcmZhY2UgUGFyc2VkRmlnbWFVcmwge1xuICBmaWxlS2V5OiBzdHJpbmcgfCBudWxsO1xuICBub2RlSWQ6IHN0cmluZyB8IG51bGw7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBwYXJzZUZpZ21hVXJsKGlucHV0OiBzdHJpbmcgfCBudWxsIHwgdW5kZWZpbmVkKTogUGFyc2VkRmlnbWFVcmwge1xuICBpZiAoIWlucHV0KSByZXR1cm4geyBmaWxlS2V5OiBudWxsLCBub2RlSWQ6IG51bGwgfTtcbiAgdHJ5IHtcbiAgICBjb25zdCB1cmwgPSBuZXcgVVJMKGlucHV0KTtcbiAgICBjb25zdCBtYXRjaCA9IHVybC5ocmVmLm1hdGNoKEZJTEVfS0VZX1JFR0VYKTtcbiAgICBjb25zdCBmaWxlS2V5ID0gbWF0Y2ggPyBtYXRjaFsxXSA6IG51bGw7XG4gICAgY29uc3Qgbm9kZVBhcmFtID0gdXJsLnNlYXJjaFBhcmFtcy5nZXQoJ25vZGUtaWQnKTtcbiAgICBjb25zdCBub2RlSWQgPSBub2RlUGFyYW0gPyBlbnN1cmVOb2RlSWQobm9kZVBhcmFtKSA6IG51bGw7XG4gICAgcmV0dXJuIHsgZmlsZUtleSwgbm9kZUlkIH07XG4gIH0gY2F0Y2gge1xuICAgIHJldHVybiB7IGZpbGVLZXk6IG51bGwsIG5vZGVJZDogbnVsbCB9O1xuICB9XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBlbnN1cmVOb2RlSWQodmFsdWU6IHN0cmluZyB8IG51bGwgfCB1bmRlZmluZWQpOiBzdHJpbmcgfCBudWxsIHtcbiAgaWYgKCF2YWx1ZSkgcmV0dXJuIG51bGw7XG4gIGNvbnN0IGRlY29kZWQgPSBkZWNvZGVVUklDb21wb25lbnQodmFsdWUpO1xuICBpZiAoZGVjb2RlZC5pbmNsdWRlcygnOicpKSByZXR1cm4gZGVjb2RlZDtcbiAgaWYgKC9eWzAtOV0rLVswLTldKyQvLnRlc3QoZGVjb2RlZCkpIHtcbiAgICBjb25zdCBbbGVmdCwgcmlnaHRdID0gZGVjb2RlZC5zcGxpdCgnLScsIDIpO1xuICAgIHJldHVybiBgJHtsZWZ0fToke3JpZ2h0fWA7XG4gIH1cbiAgcmV0dXJuIGRlY29kZWQ7XG59XG5cbiIsICJleHBvcnQgZGVmYXVsdCB7XG4gIHNjaGVtYVZlcnNpb246ICcxLjAuMCcsXG4gIHNvdXJjZTogJ2FnZW50aWMtY29kaW5nLXRlbXBsYXRlcy9maWdtYS10b29scycsXG4gIGh0dHA6IHtcbiAgICBtYXhBdHRlbXB0czogNSxcbiAgICBpbml0aWFsRGVsYXlNczogMjUwLFxuICB9LFxufSBhcyBjb25zdDtcblxuIiwgImltcG9ydCBjb25maWcgZnJvbSAnLi9jb25maWcudHMnO1xuaW1wb3J0IHR5cGUgeyBUb29sRXJyb3IgfSBmcm9tICcuL2Vycm9ycy50cyc7XG5cbmV4cG9ydCBpbnRlcmZhY2UgUmF0ZUxpbWl0TWV0YSB7XG4gIHJlbWFpbmluZzogbnVtYmVyIHwgbnVsbDtcbiAgcmVzZXRBdDogc3RyaW5nIHwgbnVsbDtcbiAgYXR0ZW1wdHM6IG51bWJlcjtcbiAgbGFzdFdhaXRNczogbnVtYmVyO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIFRvb2xFbnZlbG9wZTxcbiAgVElucHV0IGV4dGVuZHMgUmVjb3JkPHN0cmluZywgdW5rbm93bj4gPSBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPixcbiAgVERhdGEgPSB1bmtub3duXG4+IHtcbiAgc2NoZW1hVmVyc2lvbjogc3RyaW5nO1xuICB0b29sOiBzdHJpbmc7XG4gIGlucHV0OiBUSW5wdXQ7XG4gIG1ldGE6IHtcbiAgICBnZW5lcmF0ZWRBdDogc3RyaW5nO1xuICAgIHNvdXJjZTogc3RyaW5nO1xuICAgIHJhdGVMaW1pdDogUmF0ZUxpbWl0TWV0YTtcbiAgfTtcbiAgZGF0YTogVERhdGE7XG4gIHdhcm5pbmdzOiBzdHJpbmdbXTtcbiAgZXJyb3JzOiBUb29sRXJyb3JbXTtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBDcmVhdGVFbnZlbG9wZU9wdGlvbnM8XG4gIFRJbnB1dCBleHRlbmRzIFJlY29yZDxzdHJpbmcsIHVua25vd24+ID0gUmVjb3JkPHN0cmluZywgdW5rbm93bj4sXG4gIFREYXRhID0gdW5rbm93blxuPiB7XG4gIHRvb2w6IHN0cmluZztcbiAgaW5wdXQ/OiBUSW5wdXQ7XG4gIGRhdGE/OiBURGF0YTtcbiAgd2FybmluZ3M/OiBzdHJpbmdbXTtcbiAgZXJyb3JzPzogVG9vbEVycm9yW107XG4gIHJhdGVMaW1pdD86IFBhcnRpYWw8UmF0ZUxpbWl0TWV0YT47XG4gIHNjaGVtYVZlcnNpb24/OiBzdHJpbmc7XG59XG5cbmZ1bmN0aW9uIGJ1aWxkUmF0ZUxpbWl0TWV0YShyYXRlTGltaXQ6IFBhcnRpYWw8UmF0ZUxpbWl0TWV0YT4gPSB7fSk6IFJhdGVMaW1pdE1ldGEge1xuICByZXR1cm4ge1xuICAgIHJlbWFpbmluZzogcmF0ZUxpbWl0LnJlbWFpbmluZyA/PyBudWxsLFxuICAgIHJlc2V0QXQ6IHJhdGVMaW1pdC5yZXNldEF0ID8/IG51bGwsXG4gICAgYXR0ZW1wdHM6IHJhdGVMaW1pdC5hdHRlbXB0cyA/PyAxLFxuICAgIGxhc3RXYWl0TXM6IHJhdGVMaW1pdC5sYXN0V2FpdE1zID8/IDAsXG4gIH07XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBjcmVhdGVFbnZlbG9wZTxcbiAgVElucHV0IGV4dGVuZHMgUmVjb3JkPHN0cmluZywgdW5rbm93bj4gPSBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPixcbiAgVERhdGEgPSB1bmtub3duXG4+KHtcbiAgdG9vbCxcbiAgaW5wdXQgPSB7fSBhcyBUSW5wdXQsXG4gIGRhdGEgPSB7fSBhcyBURGF0YSxcbiAgd2FybmluZ3MgPSBbXSxcbiAgZXJyb3JzID0gW10sXG4gIHJhdGVMaW1pdCxcbiAgc2NoZW1hVmVyc2lvbixcbn06IENyZWF0ZUVudmVsb3BlT3B0aW9uczxUSW5wdXQsIFREYXRhPik6IFRvb2xFbnZlbG9wZTxUSW5wdXQsIFREYXRhPiB7XG4gIHJldHVybiB7XG4gICAgc2NoZW1hVmVyc2lvbjogc2NoZW1hVmVyc2lvbiA/PyBjb25maWcuc2NoZW1hVmVyc2lvbixcbiAgICB0b29sLFxuICAgIGlucHV0LFxuICAgIG1ldGE6IHtcbiAgICAgIGdlbmVyYXRlZEF0OiBuZXcgRGF0ZSgpLnRvSVNPU3RyaW5nKCksXG4gICAgICBzb3VyY2U6IGNvbmZpZy5zb3VyY2UsXG4gICAgICByYXRlTGltaXQ6IGJ1aWxkUmF0ZUxpbWl0TWV0YShyYXRlTGltaXQpLFxuICAgIH0sXG4gICAgZGF0YSxcbiAgICB3YXJuaW5ncyxcbiAgICBlcnJvcnMsXG4gIH07XG59XG5cbiIsICJleHBvcnQgY29uc3QgRVJST1JfRVhJVF9DT0RFUyA9IHtcbiAgSU5QVVRfSU5WQUxJRDogMSxcbiAgQ09ORklHX0lOVkFMSUQ6IDEsXG4gIEZJR01BX0FVVEg6IDEsXG4gIEZJR01BX05PVF9GT1VORDogMixcbiAgRklHTUFfUkFURV9MSU1JVDogMixcbiAgTkVUV09SSzogMixcbiAgSU5URVJOQUw6IDMsXG59IGFzIGNvbnN0O1xuXG5leHBvcnQgdHlwZSBFcnJvckNvZGUgPSBrZXlvZiB0eXBlb2YgRVJST1JfRVhJVF9DT0RFUztcblxuZXhwb3J0IGludGVyZmFjZSBUb29sRXJyb3I8VERldGFpbCA9IHVua25vd24+IHtcbiAgY29kZTogRXJyb3JDb2RlIHwgc3RyaW5nO1xuICBtZXNzYWdlOiBzdHJpbmc7XG4gIGRldGFpbD86IFREZXRhaWwgfCBudWxsO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gY3JlYXRlRXJyb3I8VERldGFpbCA9IHVua25vd24+KFxuICBjb2RlOiBFcnJvckNvZGUgfCBzdHJpbmcsXG4gIG1lc3NhZ2U6IHN0cmluZyxcbiAgZGV0YWlsPzogVERldGFpbCB8IG51bGxcbik6IFRvb2xFcnJvcjxURGV0YWlsPiB7XG4gIHJldHVybiB7XG4gICAgY29kZSxcbiAgICBtZXNzYWdlLFxuICAgIGRldGFpbDogZGV0YWlsID8/IG51bGwsXG4gIH07XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBnZXRFeGl0Q29kZShlcnJvcnM6IFRvb2xFcnJvcltdID0gW10pOiBudW1iZXIge1xuICBpZiAoIWVycm9ycy5sZW5ndGgpIHtcbiAgICByZXR1cm4gMDtcbiAgfVxuXG4gIHJldHVybiBlcnJvcnMucmVkdWNlKChtYXgsIGVycm9yKSA9PiB7XG4gICAgY29uc3QgZXhpdENvZGUgPSBFUlJPUl9FWElUX0NPREVTW2Vycm9yLmNvZGUgYXMgRXJyb3JDb2RlXSA/PyAxO1xuICAgIHJldHVybiBNYXRoLm1heChtYXgsIGV4aXRDb2RlKTtcbiAgfSwgMCk7XG59XG5cbiIsICJpbXBvcnQgY29uZmlnIGZyb20gJy4vY29uZmlnLnRzJztcbmltcG9ydCB7IGNyZWF0ZUVycm9yIH0gZnJvbSAnLi9lcnJvcnMudHMnO1xuaW1wb3J0IHR5cGUgeyBUb29sRXJyb3IgfSBmcm9tICcuL2Vycm9ycy50cyc7XG5pbXBvcnQgdHlwZSB7IFJhdGVMaW1pdE1ldGEgfSBmcm9tICcuL2VudmVsb3BlLnRzJztcblxuY29uc3QgQkFTRV9VUkwgPSAnaHR0cHM6Ly9hcGkuZmlnbWEuY29tJztcblxudHlwZSBTZWFyY2hQYXJhbXMgPSBSZWNvcmQ8c3RyaW5nLCBzdHJpbmcgfCBudW1iZXIgfCBib29sZWFuIHwgbnVsbCB8IHVuZGVmaW5lZD47XG5cbmludGVyZmFjZSBGaWdtYVJlcXVlc3RPcHRpb25zIHtcbiAgcGF0aDogc3RyaW5nO1xuICBtZXRob2Q/OiBzdHJpbmc7XG4gIHRva2VuPzogc3RyaW5nO1xuICBoZWFkZXJzPzogUmVjb3JkPHN0cmluZywgc3RyaW5nPjtcbiAgYm9keT86IHVua25vd247XG4gIHNlYXJjaFBhcmFtcz86IFNlYXJjaFBhcmFtcztcbiAgbWF4QXR0ZW1wdHM/OiBudW1iZXI7XG4gIGluaXRpYWxEZWxheU1zPzogbnVtYmVyO1xufVxuXG5pbnRlcmZhY2UgRmlnbWFTdWNjZXNzPFREYXRhPiB7XG4gIG9rOiB0cnVlO1xuICBkYXRhOiBURGF0YTtcbiAgcmF0ZUxpbWl0OiBSYXRlTGltaXRNZXRhO1xufVxuXG5pbnRlcmZhY2UgRmlnbWFGYWlsdXJlIHtcbiAgb2s6IGZhbHNlO1xuICBlcnJvcjogVG9vbEVycm9yPHsgc3RhdHVzPzogbnVtYmVyIH0+O1xuICBzdGF0dXM/OiBudW1iZXIgfCBudWxsO1xuICByYXRlTGltaXQ6IFJhdGVMaW1pdE1ldGEgfCBudWxsO1xufVxuXG5leHBvcnQgdHlwZSBGaWdtYVJlc3BvbnNlPFREYXRhPiA9IEZpZ21hU3VjY2VzczxURGF0YT4gfCBGaWdtYUZhaWx1cmU7XG5cbmZ1bmN0aW9uIHNsZWVwKG1zOiBudW1iZXIpOiBQcm9taXNlPHZvaWQ+IHtcbiAgcmV0dXJuIG5ldyBQcm9taXNlKChyZXNvbHZlKSA9PiBzZXRUaW1lb3V0KHJlc29sdmUsIG1zKSk7XG59XG5cbmZ1bmN0aW9uIHBhcnNlSnNvblNhZmVseSh0ZXh0OiBzdHJpbmcpOiB1bmtub3duIHtcbiAgdHJ5IHtcbiAgICByZXR1cm4gdGV4dCA/IEpTT04ucGFyc2UodGV4dCkgOiB7fTtcbiAgfSBjYXRjaCB7XG4gICAgcmV0dXJuIHsgcmF3OiB0ZXh0IH07XG4gIH1cbn1cblxuZnVuY3Rpb24gcGFyc2VSYXRlTGltaXQoaGVhZGVyczogSGVhZGVycywgYXR0ZW1wdHM6IG51bWJlciwgbGFzdFdhaXRNczogbnVtYmVyKTogUmF0ZUxpbWl0TWV0YSB7XG4gIGNvbnN0IHJlbWFpbmluZ0hlYWRlciA9IGhlYWRlcnMuZ2V0KCd4LXJhdGVsaW1pdC1yZW1haW5pbmcnKTtcbiAgY29uc3QgcmVzZXRIZWFkZXIgPSBoZWFkZXJzLmdldCgneC1yYXRlbGltaXQtcmVzZXQnKTtcblxuICBsZXQgcmVtYWluaW5nOiBudW1iZXIgfCBudWxsID0gbnVsbDtcbiAgaWYgKHJlbWFpbmluZ0hlYWRlciAhPT0gbnVsbCAmJiByZW1haW5pbmdIZWFkZXIgIT09IHVuZGVmaW5lZCkge1xuICAgIGNvbnN0IHBhcnNlZCA9IE51bWJlcihyZW1haW5pbmdIZWFkZXIpO1xuICAgIHJlbWFpbmluZyA9IE51bWJlci5pc05hTihwYXJzZWQpID8gbnVsbCA6IHBhcnNlZDtcbiAgfVxuXG4gIGxldCByZXNldEF0OiBzdHJpbmcgfCBudWxsID0gbnVsbDtcbiAgaWYgKHJlc2V0SGVhZGVyKSB7XG4gICAgY29uc3QgbnVtZXJpY1Jlc2V0ID0gTnVtYmVyKHJlc2V0SGVhZGVyKTtcbiAgICBpZiAoIU51bWJlci5pc05hTihudW1lcmljUmVzZXQpKSB7XG4gICAgICByZXNldEF0ID0gbmV3IERhdGUobnVtZXJpY1Jlc2V0ICogMTAwMCkudG9JU09TdHJpbmcoKTtcbiAgICB9IGVsc2Uge1xuICAgICAgY29uc3QgZGF0ZSA9IG5ldyBEYXRlKHJlc2V0SGVhZGVyKTtcbiAgICAgIGlmICghTnVtYmVyLmlzTmFOKGRhdGUudmFsdWVPZigpKSkge1xuICAgICAgICByZXNldEF0ID0gZGF0ZS50b0lTT1N0cmluZygpO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIHJldHVybiB7XG4gICAgcmVtYWluaW5nLFxuICAgIHJlc2V0QXQsXG4gICAgYXR0ZW1wdHMsXG4gICAgbGFzdFdhaXRNcyxcbiAgfTtcbn1cblxuZnVuY3Rpb24gY29tcHV0ZUJhY2tvZmZNcyhhdHRlbXB0OiBudW1iZXIsIGluaXRpYWxEZWxheU1zOiBudW1iZXIpOiBudW1iZXIge1xuICByZXR1cm4gaW5pdGlhbERlbGF5TXMgKiAyICoqIChhdHRlbXB0IC0gMSk7XG59XG5cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBmaWdtYVJlcXVlc3Q8VERhdGEgPSB1bmtub3duPihcbiAgb3B0aW9uczogRmlnbWFSZXF1ZXN0T3B0aW9uc1xuKTogUHJvbWlzZTxGaWdtYVJlc3BvbnNlPFREYXRhPj4ge1xuICBjb25zdCB7XG4gICAgcGF0aCxcbiAgICBtZXRob2QgPSAnR0VUJyxcbiAgICB0b2tlbixcbiAgICBoZWFkZXJzID0ge30sXG4gICAgYm9keSxcbiAgICBzZWFyY2hQYXJhbXMsXG4gICAgbWF4QXR0ZW1wdHMgPSBjb25maWcuaHR0cD8ubWF4QXR0ZW1wdHMgPz8gNSxcbiAgICBpbml0aWFsRGVsYXlNcyA9IGNvbmZpZy5odHRwPy5pbml0aWFsRGVsYXlNcyA/PyAyNTAsXG4gIH0gPSBvcHRpb25zO1xuXG4gIGlmICghdG9rZW4pIHtcbiAgICByZXR1cm4ge1xuICAgICAgb2s6IGZhbHNlLFxuICAgICAgZXJyb3I6IGNyZWF0ZUVycm9yKCdGSUdNQV9BVVRIJywgJ0ZJR01BX0FDQ0VTU19UT0tFTiBpcyBtaXNzaW5nIGZyb20gdGhlIGVudmlyb25tZW50LicpLFxuICAgICAgc3RhdHVzOiBudWxsLFxuICAgICAgcmF0ZUxpbWl0OiBudWxsLFxuICAgIH07XG4gIH1cblxuICBjb25zdCB1cmwgPSBuZXcgVVJMKHBhdGgsIEJBU0VfVVJMKTtcblxuICBpZiAoc2VhcmNoUGFyYW1zKSB7XG4gICAgT2JqZWN0LmVudHJpZXMoc2VhcmNoUGFyYW1zKS5mb3JFYWNoKChba2V5LCB2YWx1ZV0pID0+IHtcbiAgICAgIGlmICh2YWx1ZSA9PT0gdW5kZWZpbmVkIHx8IHZhbHVlID09PSBudWxsKSByZXR1cm47XG4gICAgICB1cmwuc2VhcmNoUGFyYW1zLmFwcGVuZChrZXksIFN0cmluZyh2YWx1ZSkpO1xuICAgIH0pO1xuICB9XG5cbiAgbGV0IGF0dGVtcHQgPSAwO1xuICBsZXQgbGFzdFdhaXRNcyA9IDA7XG5cbiAgd2hpbGUgKGF0dGVtcHQgPCBtYXhBdHRlbXB0cykge1xuICAgIGF0dGVtcHQgKz0gMTtcblxuICAgIGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgZmV0Y2godXJsLCB7XG4gICAgICBtZXRob2QsXG4gICAgICBoZWFkZXJzOiB7XG4gICAgICAgICdDb250ZW50LVR5cGUnOiAnYXBwbGljYXRpb24vanNvbicsXG4gICAgICAgICdYLUZpZ21hLVRva2VuJzogdG9rZW4sXG4gICAgICAgIC4uLmhlYWRlcnMsXG4gICAgICB9LFxuICAgICAgYm9keTogYm9keSA/IEpTT04uc3RyaW5naWZ5KGJvZHkpIDogdW5kZWZpbmVkLFxuICAgIH0pO1xuXG4gICAgY29uc3QgdGV4dCA9IGF3YWl0IHJlc3BvbnNlLnRleHQoKTtcbiAgICBjb25zdCBwYXlsb2FkID0gcGFyc2VKc29uU2FmZWx5KHRleHQpIGFzIHsgbWVzc2FnZT86IHN0cmluZyB9O1xuICAgIGNvbnN0IHJhdGVMaW1pdCA9IHBhcnNlUmF0ZUxpbWl0KHJlc3BvbnNlLmhlYWRlcnMsIGF0dGVtcHQsIGxhc3RXYWl0TXMpO1xuXG4gICAgaWYgKHJlc3BvbnNlLm9rKSB7XG4gICAgICByZXR1cm4geyBvazogdHJ1ZSwgZGF0YTogcGF5bG9hZCBhcyBURGF0YSwgcmF0ZUxpbWl0IH07XG4gICAgfVxuXG4gICAgY29uc3Qgc3RhdHVzID0gcmVzcG9uc2Uuc3RhdHVzO1xuXG4gICAgaWYgKHN0YXR1cyA9PT0gNDAxIHx8IHN0YXR1cyA9PT0gNDAzKSB7XG4gICAgICByZXR1cm4geyBvazogZmFsc2UsIGVycm9yOiBjcmVhdGVFcnJvcignRklHTUFfQVVUSCcsIHBheWxvYWQ/Lm1lc3NhZ2UgPz8gJ0ZpZ21hIHRva2VuIGlzIHVuYXV0aG9yaXplZC4nLCB7IHN0YXR1cyB9KSwgc3RhdHVzLCByYXRlTGltaXQgfTtcbiAgICB9XG5cbiAgICBpZiAoc3RhdHVzID09PSA0MDQpIHtcbiAgICAgIHJldHVybiB7IG9rOiBmYWxzZSwgZXJyb3I6IGNyZWF0ZUVycm9yKCdGSUdNQV9OT1RfRk9VTkQnLCBwYXlsb2FkPy5tZXNzYWdlID8/ICdSZXNvdXJjZSBub3QgZm91bmQuJywgeyBzdGF0dXMgfSksIHN0YXR1cywgcmF0ZUxpbWl0IH07XG4gICAgfVxuXG4gICAgaWYgKHN0YXR1cyA9PT0gNDI5IHx8IHN0YXR1cyA+PSA1MDApIHtcbiAgICAgIGlmIChhdHRlbXB0ID49IG1heEF0dGVtcHRzKSB7XG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgb2s6IGZhbHNlLFxuICAgICAgICAgIGVycm9yOiBjcmVhdGVFcnJvcihzdGF0dXMgPT09IDQyOSA/ICdGSUdNQV9SQVRFX0xJTUlUJyA6ICdORVRXT1JLJywgcGF5bG9hZD8ubWVzc2FnZSA/PyAnRmlnbWEgcmVxdWVzdCBmYWlsZWQgYWZ0ZXIgbWF4aW11bSByZXRyaWVzLicsIHsgc3RhdHVzIH0pLFxuICAgICAgICAgIHN0YXR1cyxcbiAgICAgICAgICByYXRlTGltaXQsXG4gICAgICAgIH07XG4gICAgICB9XG5cbiAgICAgIGxldCB3YWl0TXMgPSBjb21wdXRlQmFja29mZk1zKGF0dGVtcHQsIGluaXRpYWxEZWxheU1zKTtcbiAgICAgIGNvbnN0IHJlc2V0SGVhZGVyID0gcmVzcG9uc2UuaGVhZGVycy5nZXQoJ3gtcmF0ZWxpbWl0LXJlc2V0Jyk7XG4gICAgICBpZiAocmVzZXRIZWFkZXIpIHtcbiAgICAgICAgY29uc3QgYXNOdW1iZXIgPSBOdW1iZXIocmVzZXRIZWFkZXIpO1xuICAgICAgICBpZiAoIU51bWJlci5pc05hTihhc051bWJlcikpIHtcbiAgICAgICAgICBjb25zdCByZXNldE1zID0gYXNOdW1iZXIgKiAxMDAwO1xuICAgICAgICAgIGNvbnN0IGRlbHRhID0gcmVzZXRNcyAtIERhdGUubm93KCk7XG4gICAgICAgICAgaWYgKGRlbHRhID4gMCkgd2FpdE1zID0gTWF0aC5tYXgod2FpdE1zLCBkZWx0YSk7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgY29uc3Qgaml0dGVyID0gTWF0aC5mbG9vcihNYXRoLnJhbmRvbSgpICogMTAwKTtcbiAgICAgIGxhc3RXYWl0TXMgPSB3YWl0TXMgKyBqaXR0ZXI7XG4gICAgICBhd2FpdCBzbGVlcChsYXN0V2FpdE1zKTtcbiAgICAgIGNvbnRpbnVlO1xuICAgIH1cblxuICAgIHJldHVybiB7IG9rOiBmYWxzZSwgZXJyb3I6IGNyZWF0ZUVycm9yKCdJTlRFUk5BTCcsIHBheWxvYWQ/Lm1lc3NhZ2UgPz8gJ1VuZXhwZWN0ZWQgZXJyb3IgZnJvbSBGaWdtYSBBUEkuJywgeyBzdGF0dXMgfSksIHN0YXR1cywgcmF0ZUxpbWl0IH07XG4gIH1cblxuICByZXR1cm4ge1xuICAgIG9rOiBmYWxzZSxcbiAgICBlcnJvcjogY3JlYXRlRXJyb3IoJ05FVFdPUksnLCAnVW5hYmxlIHRvIHJlYWNoIEZpZ21hIEFQSS4nKSxcbiAgICBzdGF0dXM6IG51bGwsXG4gICAgcmF0ZUxpbWl0OiB7IHJlbWFpbmluZzogbnVsbCwgcmVzZXRBdDogbnVsbCwgYXR0ZW1wdHM6IG1heEF0dGVtcHRzLCBsYXN0V2FpdE1zIH0sXG4gIH07XG59XG5cbiJdLAogICJtYXBwaW5ncyI6ICI7OztBQUVBLFNBQVMsZ0JBQWdCO0FBQ3pCLE9BQU8sVUFBVTs7O0FDSVYsU0FBUyxVQUFVLE9BQWlCLFFBQVEsS0FBSyxNQUFNLENBQUMsR0FBWTtBQUN6RSxRQUFNLE9BQWdCLEVBQUUsR0FBRyxDQUFDLEVBQUU7QUFFOUIsV0FBUyxJQUFJLEdBQUcsSUFBSSxLQUFLLFFBQVEsS0FBSyxHQUFHO0FBQ3ZDLFVBQU0sTUFBTSxLQUFLLENBQUM7QUFFbEIsUUFBSSxDQUFDLElBQUksV0FBVyxHQUFHLEtBQUssUUFBUSxLQUFLO0FBQ3ZDLFdBQUssRUFBRSxLQUFLLEdBQUc7QUFDZjtBQUFBLElBQ0Y7QUFFQSxRQUFJLFFBQVEsTUFBTTtBQUNoQixZQUFNLFlBQVksS0FBSyxNQUFNLElBQUksQ0FBQztBQUNsQyxXQUFLLEVBQUUsS0FBSyxHQUFHLFNBQVM7QUFDeEI7QUFBQSxJQUNGO0FBRUEsVUFBTSxDQUFDLFFBQVEsV0FBVyxJQUFJLElBQUksTUFBTSxLQUFLLENBQUM7QUFDOUMsVUFBTSxnQkFBZ0IsT0FBTyxRQUFRLE9BQU8sRUFBRTtBQUU5QyxRQUFJO0FBQ0osUUFBSSxnQkFBZ0IsUUFBVztBQUM3QixjQUFRO0FBQUEsSUFDVixPQUFPO0FBQ0wsWUFBTSxPQUFPLEtBQUss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
|