Files

277 lines
31 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/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/whoami.ts
var TOOL_NAME = "whoami";
function log(message, verbose) {
if (verbose) process.stderr.write(`[${TOOL_NAME}] ${message}
`);
}
async function main() {
const args = parseArgs();
const verbose = Boolean(args.verbose ?? args.v);
log("Starting...", verbose);
const warnings = [];
const errors = [];
const token = process.env.FIGMA_ACCESS_TOKEN;
if (!token || !token.trim()) {
errors.push(createError("FIGMA_AUTH", "FIGMA_ACCESS_TOKEN must be set in environment."));
}
let envelope = createEnvelope({ tool: TOOL_NAME, warnings, errors });
if (errors.length > 0) {
process.stdout.write(`${JSON.stringify(envelope, null, 2)}
`);
process.exit(getExitCode(errors));
}
const result = await figmaRequest({ path: "/v1/me", token });
if (!result.ok) {
errors.push(result.error);
envelope = createEnvelope({ tool: TOOL_NAME, warnings, errors, rateLimit: result.rateLimit ?? void 0 });
process.stdout.write(`${JSON.stringify(envelope, null, 2)}
`);
process.exit(getExitCode(errors));
}
envelope = createEnvelope({ tool: TOOL_NAME, data: result.data, warnings, errors, rateLimit: result.rateLimit });
process.stdout.write(`${JSON.stringify(envelope, null, 2)}
`);
process.exit(0);
}
main().catch((error) => {
const message = error instanceof Error ? error.message : "Unknown error";
const envelope = createEnvelope({ tool: TOOL_NAME, input: {}, errors: [createError("INTERNAL", message)] });
process.stdout.write(`${JSON.stringify(envelope, null, 2)}
`);
process.exit(3);
});
//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiLi4vc3JjL191dGlscy9jbGktYXJncy50cyIsICIuLi9zcmMvX3V0aWxzL2NvbmZpZy50cyIsICIuLi9zcmMvX3V0aWxzL2VudmVsb3BlLnRzIiwgIi4uL3NyYy9fdXRpbHMvZXJyb3JzLnRzIiwgIi4uL3NyYy9fdXRpbHMvaHR0cC1jbGllbnQudHMiLCAiLi4vc3JjL3dob2FtaS50cyJdLAogICJzb3VyY2VzQ29udGVudCI6IFsiZXhwb3J0IHR5cGUgQ2xpQXJnVmFsdWUgPSBzdHJpbmcgfCBib29sZWFuO1xuXG5leHBvcnQgaW50ZXJmYWNlIENsaUFyZ3Mge1xuICBfOiBzdHJpbmdbXTtcbiAgW2tleTogc3RyaW5nXTogQ2xpQXJnVmFsdWUgfCBzdHJpbmdbXTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIHBhcnNlQXJncyhhcmd2OiBzdHJpbmdbXSA9IHByb2Nlc3MuYXJndi5zbGljZSgyKSk6IENsaUFyZ3Mge1xuICBjb25zdCBhcmdzOiBDbGlBcmdzID0geyBfOiBbXSB9O1xuXG4gIGZvciAobGV0IGkgPSAwOyBpIDwgYXJndi5sZW5ndGg7IGkgKz0gMSkge1xuICAgIGNvbnN0IGFyZyA9IGFyZ3ZbaV07XG5cbiAgICBpZiAoIWFyZy5zdGFydHNXaXRoKCctJykgfHwgYXJnID09PSAnLScpIHtcbiAgICAgIGFyZ3MuXy5wdXNoKGFyZyk7XG4gICAgICBjb250aW51ZTtcbiAgICB9XG5cbiAgICBpZiAoYXJnID09PSAnLS0nKSB7XG4gICAgICBjb25zdCByZW1haW5pbmcgPSBhcmd2LnNsaWNlKGkgKyAxKTtcbiAgICAgIGFyZ3MuXy5wdXNoKC4uLnJlbWFpbmluZyk7XG4gICAgICBicmVhaztcbiAgICB9XG5cbiAgICBjb25zdCBbcmF3S2V5LCBpbmxpbmVWYWx1ZV0gPSBhcmcuc3BsaXQoJz0nLCAyKTtcbiAgICBjb25zdCBub3JtYWxpc2VkS2V5ID0gcmF3S2V5LnJlcGxhY2UoL14tKy8sICcnKTtcblxuICAgIGxldCB2YWx1ZTogQ2xpQXJnVmFsdWU7XG4gICAgaWYgKGlubGluZVZhbHVlICE9PSB1bmRlZmluZWQpIHtcbiAgICAgIHZhbHVlID0gaW5saW5lVmFsdWU7XG4gICAgfSBlbHNlIHtcbiAgICAgIGNvbnN0IG5leHQgPSBhcmd2W2kgKyAxXTtcbiAgICAgIGlmIChuZXh0ICE9PSB1bmRlZmluZWQgJiYgIW5leHQuc3RhcnRzV2l0aCgnLScpKSB7XG4gICAgICAgIHZhbHVlID0gbmV4dDtcbiAgICAgICAgaSArPSAxO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgdmFsdWUgPSB0cnVlO1xuICAgICAgfVxuICAgIH1cblxuICAgIGFyZ3Nbbm9ybWFsaXNlZEtleV0gPSB2YWx1ZTtcbiAgfVxuXG4gIHJldHVybiBhcmdzO1xufVxuXG4iLCAiZXhwb3J0IGRlZmF1bHQge1xuICBzY2hlbWFWZXJzaW9uOiAnMS4wLjAnLFxuICBzb3VyY2U6ICdhZ2VudGljLWNvZGluZy10ZW1wbGF0ZXMvZmlnbWEtdG9vbHMnLFxuICBodHRwOiB7XG4gICAgbWF4QXR0ZW1wdHM6IDUsXG4gICAgaW5pdGlhbERlbGF5TXM6IDI1MCxcbiAgfSxcbn0gYXMgY29uc3Q7XG5cbiIsICJpbXBvcnQgY29uZmlnIGZyb20gJy4vY29uZmlnLnRzJztcbmltcG9ydCB0eXBlIHsgVG9vbEVycm9yIH0gZnJvbSAnLi9lcnJvcnMudHMnO1xuXG5leHBvcnQgaW50ZXJmYWNlIFJhdGVMaW1pdE1ldGEge1xuICByZW1haW5pbmc6IG51bWJlciB8IG51bGw7XG4gIHJlc2V0QXQ6IHN0cmluZyB8IG51bGw7XG4gIGF0dGVtcHRzOiBudW1iZXI7XG4gIGxhc3RXYWl0TXM6IG51bWJlcjtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBUb29sRW52ZWxvcGU8XG4gIFRJbnB1dCBleHRlbmRzIFJlY29yZDxzdHJpbmcsIHVua25vd24+ID0gUmVjb3JkPHN0cmluZywgdW5rbm93bj4sXG4gIFREYXRhID0gdW5rbm93blxuPiB7XG4gIHNjaGVtYVZlcnNpb246IHN0cmluZztcbiAgdG9vbDogc3RyaW5nO1xuICBpbnB1dDogVElucHV0O1xuICBtZXRhOiB7XG4gICAgZ2VuZXJhdGVkQXQ6IHN0cmluZztcbiAgICBzb3VyY2U6IHN0cmluZztcbiAgICByYXRlTGltaXQ6IFJhdGVMaW1pdE1ldGE7XG4gIH07XG4gIGRhdGE6IFREYXRhO1xuICB3YXJuaW5nczogc3RyaW5nW107XG4gIGVycm9yczogVG9vbEVycm9yW107XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgQ3JlYXRlRW52ZWxvcGVPcHRpb25zPFxuICBUSW5wdXQgZXh0ZW5kcyBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPiA9IFJlY29yZDxzdHJpbmcsIHVua25vd24+LFxuICBURGF0YSA9IHVua25vd25cbj4ge1xuICB0b29sOiBzdHJpbmc7XG4gIGlucHV0PzogVElucHV0O1xuICBkYXRhPzogVERhdGE7XG4gIHdhcm5pbmdzPzogc3RyaW5nW107XG4gIGVycm9ycz86IFRvb2xFcnJvcltdO1xuICByYXRlTGltaXQ/OiBQYXJ0aWFsPFJhdGVMaW1pdE1ldGE+O1xuICBzY2hlbWFWZXJzaW9uPzogc3RyaW5nO1xufVxuXG5mdW5jdGlvbiBidWlsZFJhdGVMaW1pdE1ldGEocmF0ZUxpbWl0OiBQYXJ0aWFsPFJhdGVMaW1pdE1ldGE+ID0ge30pOiBSYXRlTGltaXRNZXRhIHtcbiAgcmV0dXJuIHtcbiAgICByZW1haW5pbmc6IHJhdGVMaW1pdC5yZW1haW5pbmcgPz8gbnVsbCxcbiAgICByZXNldEF0OiByYXRlTGltaXQucmVzZXRBdCA/PyBudWxsLFxuICAgIGF0dGVtcHRzOiByYXRlTGltaXQuYXR0ZW1wdHMgPz8gMSxcbiAgICBsYXN0V2FpdE1zOiByYXRlTGltaXQubGFzdFdhaXRNcyA/PyAwLFxuICB9O1xufVxuXG5leHBvcnQgZnVuY3Rpb24gY3JlYXRlRW52ZWxvcGU8XG4gIFRJbnB1dCBleHRlbmRzIFJlY29yZDxzdHJpbmcsIHVua25vd24+ID0gUmVjb3JkPHN0cmluZywgdW5rbm93bj4sXG4gIFREYXRhID0gdW5rbm93blxuPih7XG4gIHRvb2wsXG4gIGlucHV0ID0ge30gYXMgVElucHV0LFxuICBkYXRhID0ge30gYXMgVERhdGEsXG4gIHdhcm5pbmdzID0gW10sXG4gIGVycm9ycyA9IFtdLFxuICByYXRlTGltaXQsXG4gIHNjaGVtYVZlcnNpb24sXG59OiBDcmVhdGVFbnZlbG9wZU9wdGlvbnM8VElucHV0LCBURGF0YT4pOiBUb29sRW52ZWxvcGU8VElucHV0LCBURGF0YT4ge1xuICByZXR1cm4ge1xuICAgIHNjaGVtYVZlcnNpb246IHNjaGVtYVZlcnNpb24gPz8gY29uZmlnLnNjaGVtYVZlcnNpb24sXG4gICAgdG9vbCxcbiAgICBpbnB1dCxcbiAgICBtZXRhOiB7XG4gICAgICBnZW5lcmF0ZWRBdDogbmV3IERhdGUoKS50b0lTT1N0cmluZygpLFxuICAgICAgc291cmNlOiBjb25maWcuc291cmNlLFxuICAgICAgcmF0ZUxpbWl0OiBidWlsZFJhdGVMaW1pdE1ldGEocmF0ZUxpbWl0KSxcbiAgICB9LFxuICAgIGRhdGEsXG4gICAgd2FybmluZ3MsXG4gICAgZXJyb3JzLFxuICB9O1xufVxuXG4iLCAiZXhwb3J0IGNvbnN0IEVSUk9SX0VYSVRfQ09ERVMgPSB7XG4gIElOUFVUX0lOVkFMSUQ6IDEsXG4gIENPTkZJR19JTlZBTElEOiAxLFxuICBGSUdNQV9BVVRIOiAxLFxuICBGSUdNQV9OT1RfRk9VTkQ6IDIsXG4gIEZJR01BX1JBVEVfTElNSVQ6IDIsXG4gIE5FVFdPUks6IDIsXG4gIElOVEVSTkFMOiAzLFxufSBhcyBjb25zdDtcblxuZXhwb3J0IHR5cGUgRXJyb3JDb2RlID0ga2V5b2YgdHlwZW9mIEVSUk9SX0VYSVRfQ09ERVM7XG5cbmV4cG9ydCBpbnRlcmZhY2UgVG9vbEVycm9yPFREZXRhaWwgPSB1bmtub3duPiB7XG4gIGNvZGU6IEVycm9yQ29kZSB8IHN0cmluZztcbiAgbWVzc2FnZTogc3RyaW5nO1xuICBkZXRhaWw/OiBURGV0YWlsIHwgbnVsbDtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGNyZWF0ZUVycm9yPFREZXRhaWwgPSB1bmtub3duPihcbiAgY29kZTogRXJyb3JDb2RlIHwgc3RyaW5nLFxuICBtZXNzYWdlOiBzdHJpbmcsXG4gIGRldGFpbD86IFREZXRhaWwgfCBudWxsXG4pOiBUb29sRXJyb3I8VERldGFpbD4ge1xuICByZXR1cm4ge1xuICAgIGNvZGUsXG4gICAgbWVzc2FnZSxcbiAgICBkZXRhaWw6IGRldGFpbCA/PyBudWxsLFxuICB9O1xufVxuXG5leHBvcnQgZnVuY3Rpb24gZ2V0RXhpdENvZGUoZXJyb3JzOiBUb29sRXJyb3JbXSA9IFtdKTogbnVtYmVyIHtcbiAgaWYgKCFlcnJvcnMubGVuZ3RoKSB7XG4gICAgcmV0dXJuIDA7XG4gIH1cblxuICByZXR1cm4gZXJyb3JzLnJlZHVjZSgobWF4LCBlcnJvcikgPT4ge1xuICAgIGNvbnN0IGV4aXRDb2RlID0gRVJST1JfRVhJVF9DT0RFU1tlcnJvci5jb2RlIGFzIEVycm9yQ29kZV0gPz8gMTtcbiAgICByZXR1cm4gTWF0aC5tYXgobWF4LCBleGl0Q29kZSk7XG4gIH0sIDApO1xufVxuXG4iLCAiaW1wb3J0IGNvbmZpZyBmcm9tICcuL2NvbmZpZy50cyc7XG5pbXBvcnQgeyBjcmVhdGVFcnJvciB9IGZyb20gJy4vZXJyb3JzLnRzJztcbmltcG9ydCB0eXBlIHsgVG9vbEVycm9yIH0gZnJvbSAnLi9lcnJvcnMudHMnO1xuaW1wb3J0IHR5cGUgeyBSYXRlTGltaXRNZXRhIH0gZnJvbSAnLi9lbnZlbG9wZS50cyc7XG5cbmNvbnN0IEJBU0VfVVJMID0gJ2h0dHBzOi8vYXBpLmZpZ21hLmNvbSc7XG5cbnR5cGUgU2VhcmNoUGFyYW1zID0gUmVjb3JkPHN0cmluZywgc3RyaW5nIHwgbnVtYmVyIHwgYm9vbGVhbiB8IG51bGwgfCB1bmRlZmluZWQ+O1xuXG5pbnRlcmZhY2UgRmlnbWFSZXF1ZXN0T3B0aW9ucyB7XG4gIHBhdGg6IHN0cmluZztcbiAgbWV0aG9kPzogc3RyaW5nO1xuICB0b2tlbj86IHN0cmluZztcbiAgaGVhZGVycz86IFJlY29yZDxzdHJpbmcsIHN0cmluZz47XG4gIGJvZHk/OiB1bmtub3duO1xuICBzZWFyY2hQYXJhbXM/OiBTZWFyY2hQYXJhbXM7XG4gIG1heEF0dGVtcHRzPzogbnVtYmVyO1xuICBpbml0aWFsRGVsYXlNcz86IG51bWJlcjtcbn1cblxuaW50ZXJmYWNlIEZpZ21hU3VjY2VzczxURGF0YT4ge1xuICBvazogdHJ1ZTtcbiAgZGF0YTogVERhdGE7XG4gIHJhdGVMaW1pdDogUmF0ZUxpbWl0TWV0YTtcbn1cblxuaW50ZXJmYWNlIEZpZ21hRmFpbHVyZSB7XG4gIG9rOiBmYWxzZTtcbiAgZXJyb3I6IFRvb2xFcnJvcjx7IHN0YXR1cz86IG51bWJlciB9PjtcbiAgc3RhdHVzPzogbnVtYmVyIHwgbnVsbDtcbiAgcmF0ZUxpbWl0OiBSYXRlTGltaXRNZXRhIHwgbnVsbDtcbn1cblxuZXhwb3J0IHR5cGUgRmlnbWFSZXNwb25zZTxURGF0YT4gPSBGaWdtYVN1Y2Nlc3M8VERhdGE+IHwgRmlnbWFGYWlsdXJlO1xuXG5mdW5jdGlvbiBzbGVlcChtczogbnVtYmVyKTogUHJvbWlzZTx2b2lkPiB7XG4gIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSkgPT4gc2V0VGltZW91dChyZXNvbHZlLCBtcykpO1xufVxuXG5mdW5jdGlvbiBwYXJzZUpzb25TYWZlbHkodGV4dDogc3RyaW5nKTogdW5rbm93biB7XG4gIHRyeSB7XG4gICAgcmV0dXJuIHRleHQgPyBKU09OLnBhcnNlKHRleHQpIDoge307XG4gIH0gY2F0Y2gge1xuICAgIHJldHVybiB7IHJhdzogdGV4dCB9O1xuICB9XG59XG5cbmZ1bmN0aW9uIHBhcnNlUmF0ZUxpbWl0KGhlYWRlcnM6IEhlYWRlcnMsIGF0dGVtcHRzOiBudW1iZXIsIGxhc3RXYWl0TXM6IG51bWJlcik6IFJhdGVMaW1pdE1ldGEge1xuICBjb25zdCByZW1haW5pbmdIZWFkZXIgPSBoZWFkZXJzLmdldCgneC1yYXRlbGltaXQtcmVtYWluaW5nJyk7XG4gIGNvbnN0IHJlc2V0SGVhZGVyID0gaGVhZGVycy5nZXQoJ3gtcmF0ZWxpbWl0LXJlc2V0Jyk7XG5cbiAgbGV0IHJlbWFpbmluZzogbnVtYmVyIHwgbnVsbCA9IG51bGw7XG4gIGlmIChyZW1haW5pbmdIZWFkZXIgIT09IG51bGwgJiYgcmVtYWluaW5nSGVhZGVyICE9PSB1bmRlZmluZWQpIHtcbiAgICBjb25zdCBwYXJzZWQgPSBOdW1iZXIocmVtYWluaW5nSGVhZGVyKTtcbiAgICByZW1haW5pbmcgPSBOdW1iZXIuaXNOYU4ocGFyc2VkKSA/IG51bGwgOiBwYXJzZWQ7XG4gIH1cblxuICBsZXQgcmVzZXRBdDogc3RyaW5nIHwgbnVsbCA9IG51bGw7XG4gIGlmIChyZXNldEhlYWRlcikge1xuICAgIGNvbnN0IG51bWVyaWNSZXNldCA9IE51bWJlcihyZXNldEhlYWRlcik7XG4gICAgaWYgKCFOdW1iZXIuaXNOYU4obnVtZXJpY1Jlc2V0KSkge1xuICAgICAgcmVzZXRBdCA9IG5ldyBEYXRlKG51bWVyaWNSZXNldCAqIDEwMDApLnRvSVNPU3RyaW5nKCk7XG4gICAgfSBlbHNlIHtcbiAgICAgIGNvbnN0IGRhdGUgPSBuZXcgRGF0ZShyZXNldEhlYWRlcik7XG4gICAgICBpZiAoIU51bWJlci5pc05hTihkYXRlLnZhbHVlT2YoKSkpIHtcbiAgICAgICAgcmVzZXRBdCA9IGRhdGUudG9JU09TdHJpbmcoKTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICByZXR1cm4ge1xuICAgIHJlbWFpbmluZyxcbiAgICByZXNldEF0LFxuICAgIGF0dGVtcHRzLFxuICAgIGxhc3RXYWl0TXMsXG4gIH07XG59XG5cbmZ1bmN0aW9uIGNvbXB1dGVCYWNrb2ZmTXMoYXR0ZW1wdDogbnVtYmVyLCBpbml0aWFsRGVsYXlNczogbnVtYmVyKTogbnVtYmVyIHtcbiAgcmV0dXJuIGluaXRpYWxEZWxheU1zICogMiAqKiAoYXR0ZW1wdCAtIDEpO1xufVxuXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gZmlnbWFSZXF1ZXN0PFREYXRhID0gdW5rbm93bj4oXG4gIG9wdGlvbnM6IEZpZ21hUmVxdWVzdE9wdGlvbnNcbik6IFByb21pc2U8RmlnbWFSZXNwb25zZTxURGF0YT4+IHtcbiAgY29uc3Qge1xuICAgIHBhdGgsXG4gICAgbWV0aG9kID0gJ0dFVCcsXG4gICAgdG9rZW4sXG4gICAgaGVhZGVycyA9IHt9LFxuICAgIGJvZHksXG4gICAgc2VhcmNoUGFyYW1zLFxuICAgIG1heEF0dGVtcHRzID0gY29uZmlnLmh0dHA/Lm1heEF0dGVtcHRzID8/IDUsXG4gICAgaW5pdGlhbERlbGF5TXMgPSBjb25maWcuaHR0cD8uaW5pdGlhbERlbGF5TXMgPz8gMjUwLFxuICB9ID0gb3B0aW9ucztcblxuICBpZiAoIXRva2VuKSB7XG4gICAgcmV0dXJuIHtcbiAgICAgIG9rOiBmYWxzZSxcbiAgICAgIGVycm9yOiBjcmVhdGVFcnJvcignRklHTUFfQVVUSCcsICdGSUdNQV9BQ0NFU1NfVE9LRU4gaXMgbWlzc2luZyBmcm9tIHRoZSBlbnZpcm9ubWVudC4nKSxcbiAgICAgIHN0YXR1czogbnVsbCxcbiAgICAgIHJhdGVMaW1pdDogbnVsbCxcbiAgICB9O1xuICB9XG5cbiAgY29uc3QgdXJsID0gbmV3IFVSTChwYXRoLCBCQVNFX1VSTCk7XG5cbiAgaWYgKHNlYXJjaFBhcmFtcykge1xuICAgIE9iamVjdC5lbnRyaWVzKHNlYXJjaFBhcmFtcykuZm9yRWFjaCgoW2tleSwgdmFsdWVdKSA9PiB7XG4gICAgICBpZiAodmFsdWUgPT09IHVuZGVmaW5lZCB8fCB2YWx1ZSA9PT0gbnVsbCkgcmV0dXJuO1xuICAgICAgdXJsLnNlYXJjaFBhcmFtcy5hcHBlbmQoa2V5LCBTdHJpbmcodmFsdWUpKTtcbiAgICB9KTtcbiAgfVxuXG4gIGxldCBhdHRlbXB0ID0gMDtcbiAgbGV0IGxhc3RXYWl0TXMgPSAwO1xuXG4gIHdoaWxlIChhdHRlbXB0IDwgbWF4QXR0ZW1wdHMpIHtcbiAgICBhdHRlbXB0ICs9IDE7XG5cbiAgICBjb25zdCByZXNwb25zZSA9IGF3YWl0IGZldGNoKHVybCwge1xuICAgICAgbWV0aG9kLFxuICAgICAgaGVhZGVyczoge1xuICAgICAgICAnQ29udGVudC1UeXBlJzogJ2FwcGxpY2F0aW9uL2pzb24nLFxuICAgICAgICAnWC1GaWdtYS1Ub2tlbic6IHRva2VuLFxuICAgICAgICAuLi5oZWFkZXJzLFxuICAgICAgfSxcbiAgICAgIGJvZHk6IGJvZHkgPyBKU09OLnN0cmluZ2lmeShib2R5KSA6IHVuZGVmaW5lZCxcbiAgICB9KTtcblxuICAgIGNvbnN0IHRleHQgPSBhd2FpdCByZXNwb25zZS50ZXh0KCk7XG4gICAgY29uc3QgcGF5bG9hZCA9IHBhcnNlSnNvblNhZmVseSh0ZXh0KSBhcyB7IG1lc3NhZ2U/OiBzdHJpbmcgfTtcbiAgICBjb25zdCByYXRlTGltaXQgPSBwYXJzZVJhdGVMaW1pdChyZXNwb25zZS5oZWFkZXJzLCBhdHRlbXB0LCBsYXN0V2FpdE1zKTtcblxuICAgIGlmIChyZXNwb25zZS5vaykge1xuICAgICAgcmV0dXJuIHsgb2s6IHRydWUsIGRhdGE6IHBheWxvYWQgYXMgVERhdGEsIHJhdGVMaW1pdCB9O1xuICAgIH1cblxuICAgIGNvbnN0IHN0YXR1cyA9IHJlc3BvbnNlLnN0YXR1cztcblxuICAgIGlmIChzdGF0dXMgPT09IDQwMSB8fCBzdGF0dXMgPT09IDQwMykge1xuICAgICAgcmV0dXJuIHsgb2s6IGZhbHNlLCBlcnJvcjogY3JlYXRlRXJyb3IoJ0ZJR01BX0FVVEgnLCBwYXlsb2FkPy5tZXNzYWdlID8/ICdGaWdtYSB0b2tlbiBpcyB1bmF1dGhvcml6ZWQuJywgeyBzdGF0dXMgfSksIHN0YXR1cywgcmF0ZUxpbWl0IH07XG4gICAgfVxuXG4gICAgaWYgKHN0YXR1cyA9PT0gNDA0KSB7XG4gICAgICByZXR1cm4geyBvazogZmFsc2UsIGVycm9yOiBjcmVhdGVFcnJvcignRklHTUFfTk9UX0ZPVU5EJywgcGF5bG9hZD8ubWVzc2FnZSA/PyAnUmVzb3VyY2Ugbm90IGZvdW5kLicsIHsgc3RhdHVzIH0pLCBzdGF0dXMsIHJhdGVMaW1pdCB9O1xuICAgIH1cblxuICAgIGlmIChzdGF0dXMgPT09IDQyOSB8fCBzdGF0dXMgPj0gNTAwKSB7XG4gICAgICBpZiAoYXR0ZW1wdCA+PSBtYXhBdHRlbXB0cykge1xuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgIG9rOiBmYWxzZSxcbiAgICAgICAgICBlcnJvcjogY3JlYXRlRXJyb3Ioc3RhdHVzID09PSA0MjkgPyAnRklHTUFfUkFURV9MSU1JVCcgOiAnTkVUV09SSycsIHBheWxvYWQ/Lm1lc3NhZ2UgPz8gJ0ZpZ21hIHJlcXVlc3QgZmFpbGVkIGFmdGVyIG1heGltdW0gcmV0cmllcy4nLCB7IHN0YXR1cyB9KSxcbiAgICAgICAgICBzdGF0dXMsXG4gICAgICAgICAgcmF0ZUxpbWl0LFxuICAgICAgICB9O1xuICAgICAgfVxuXG4gICAgICBsZXQgd2FpdE1zID0gY29tcHV0ZUJhY2tvZmZNcyhhdHRlbXB0LCBpbml0aWFsRGVsYXlNcyk7XG4gICAgICBjb25zdCByZXNldEhlYWRlciA9IHJlc3BvbnNlLmhlYWRlcnMuZ2V0KCd4LXJhdGVsaW1pdC1yZXNldCcpO1xuICAgICAgaWYgKHJlc2V0SGVhZGVyKSB7XG4gICAgICAgIGNvbnN0IGFzTnVtYmVyID0gTnVtYmVyKHJlc2V0SGVhZGVyKTtcbiAgICAgICAgaWYgKCFOdW1iZXIuaXNOYU4oYXNOdW1iZXIpKSB7XG4gICAgICAgICAgY29uc3QgcmVzZXRNcyA9IGFzTnVtYmVyICogMTAwMDtcbiAgICAgICAgICBjb25zdCBkZWx0YSA9IHJlc2V0TXMgLSBEYXRlLm5vdygpO1xuICAgICAgICAgIGlmIChkZWx0YSA+IDApIHdhaXRNcyA9IE1hdGgubWF4KHdhaXRNcywgZGVsdGEpO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IGppdHRlciA9IE1hdGguZmxvb3IoTWF0aC5yYW5kb20oKSAqIDEwMCk7XG4gICAgICBsYXN0V2FpdE1zID0gd2FpdE1zICsgaml0dGVyO1xuICAgICAgYXdhaXQgc2xlZXAobGFzdFdhaXRNcyk7XG4gICAgICBjb250aW51ZTtcbiAgICB9XG5cbiAgICByZXR1cm4geyBvazogZmFsc2UsIGVycm9yOiBjcmVhdGVFcnJvcignSU5URVJOQUwnLCBwYXlsb2FkPy5tZXNzYWdlID8/ICdVbmV4cGVjdGVkIGVycm9yIGZyb20gRmlnbWEgQVBJLicsIHsgc3RhdHVzIH0pLCBzdGF0dXMsIHJhdGVMaW1pdCB9O1xuICB9XG5cbiAgcmV0dXJuIHtcbiAgICBvazogZmFsc2UsXG4gICAgZXJyb3I6IGNyZWF0ZUVycm9yKCdORVRXT1JLJywgJ1VuYWJsZSB0byByZWFjaCBGaWdtYSBBUEkuJyksXG4gICAgc3RhdHVzOiBudWxsLFxuICAgIHJhdGVMaW1pdDogeyByZW1haW5pbmc6IG51bGwsIHJlc2V0QXQ6IG51bGwsIGF0dGVtcHRzOiBtYXhBdHRlbXB0cywgbGFzdFdhaXRNcyB9LFxuICB9O1xufVxuXG4iLCAiIyEvdXNyL2Jpbi9lbnYgbm9kZVxuaW1wb3J0IHsgcGFyc2VBcmdzLCB0eXBlIENsaUFyZ3MgfSBmcm9tICcuL191dGlscy9jbGktYXJncy50cydcbmltcG9ydCB7IGNyZWF0ZUVudmVsb3BlIH0gZnJvbSAnLi9fdXRpbHMvZW52ZWxvcGUudHMnXG5pbXBvcnQgeyBjcmVhdGVFcnJvciwgZ2V0RXhpdENvZGUsIHR5cGUgVG9vbEVycm9yIH0gZnJvbSAnLi9fdXRpbHMvZXJyb3JzLnRzJ1xuaW1wb3J0IHsgZmlnbWFSZXF1ZXN0IH0gZnJvbSAnLi9fdXRpbHMvaHR0cC1jbGllbnQudHMnXG5cbmNvbnN0IFRPT0xfTkFNRSA9ICd3aG9hbWknXG5cbmludGVyZmFjZSBUb29sSW5wdXQgZXh0ZW5kcyBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPiB7fVxuXG5pbnRlcmZhY2UgV2hvYW1pUmVzcG9uc2Uge1xuICBpZD86IHN0cmluZ1xuICBlbWFpbD86IHN0cmluZ1xuICBoYW5kbGU/OiBzdHJpbmdcbn1cblxuZnVuY3Rpb24gbG9nKG1lc3NhZ2U6IHN0cmluZywgdmVyYm9zZTogYm9vbGVhbik6IHZvaWQge1xuICBpZiAodmVyYm9zZSkgcHJvY2Vzcy5zdGRlcnIud3JpdGUoYFske1RPT0xfTkFNRX1dICR7bWVzc2FnZX1cXG5gKVxufVxuXG5mdW5jdGlvbiB0b09wdGlvbmFsU3RyaW5nKHZhbHVlOiBDbGlBcmdzW3N0cmluZ10pOiBzdHJpbmcgfCBudWxsIHtcbiAgcmV0dXJuIHR5cGVvZiB2YWx1ZSA9PT0gJ3N0cmluZycgJiYgdmFsdWUubGVuZ3RoID4gMCA/IHZhbHVlIDogbnVsbFxufVxuXG5hc3luYyBmdW5jdGlvbiBtYWluKCk6IFByb21pc2U8dm9pZD4ge1xuICBjb25zdCBhcmdzID0gcGFyc2VBcmdzKClcbiAgY29uc3QgdmVyYm9zZSA9IEJvb2xlYW4oYXJncy52ZXJib3NlID8/IGFyZ3MudilcbiAgbG9nKCdTdGFydGluZy4uLicsIHZlcmJvc2UpXG5cbiAgY29uc3Qgd2FybmluZ3M6IHN0cmluZ1tdID0gW11cbiAgY29uc3QgZXJyb3JzOiBUb29sRXJyb3JbXSA9IFtdXG5cbiAgY29uc3QgdG9rZW4gPSBwcm9jZXNzLmVudi5GSUdNQV9BQ0NFU1NfVE9LRU5cbiAgaWYgKCF0b2tlbiB8fCAhdG9rZW4udHJpbSgpKSB7XG4gICAgZXJyb3JzLnB1c2goY3JlYXRlRXJyb3IoJ0ZJR01BX0FVVEgnLCAnRklHTUFfQUNDRVNTX1RPS0VOIG11c3QgYmUgc2V0IGluIGVudmlyb25tZW50LicpKVxuICB9XG5cbiAgbGV0IGVudmVsb3BlID0gY3JlYXRlRW52ZWxvcGU8VG9vbElucHV0Pih7IHRvb2w6IFRPT0xfTkFNRSwgd2FybmluZ3MsIGVycm9ycyB9KVxuICBpZiAoZXJyb3JzLmxlbmd0aCA+IDApIHtcbiAgICBwcm9jZXNzLnN0ZG91dC53cml0ZShgJHtKU09OLnN0cmluZ2lmeShlbnZlbG9wZSwgbnVsbCwgMil9XFxuYClcbiAgICBwcm9jZXNzLmV4aXQoZ2V0RXhpdENvZGUoZXJyb3JzKSlcbiAgfVxuXG4gIGNvbnN0IHJlc3VsdCA9IGF3YWl0IGZpZ21hUmVxdWVzdDxXaG9hbWlSZXNwb25zZT4oeyBwYXRoOiAnL3YxL21lJywgdG9rZW46IHRva2VuIGFzIHN0cmluZyB9KVxuICBpZiAoIXJlc3VsdC5vaykge1xuICAgIGVycm9ycy5wdXNoKHJlc3VsdC5lcnJvcilcbiAgICBlbnZlbG9wZSA9IGNyZWF0ZUVudmVsb3BlKHsgdG9vbDogVE9PTF9OQU1FLCB3YXJuaW5ncywgZXJyb3JzLCByYXRlTGltaXQ6IHJlc3VsdC5yYXRlTGltaXQgPz8gdW5kZWZpbmVkIH0pXG4gICAgcHJvY2Vzcy5zdGRvdXQud3JpdGUoYCR7SlNPTi5zdHJpbmdpZnkoZW52ZWxvcGUsIG51bGwsIDIpfVxcbmApXG4gICAgcHJvY2Vzcy5leGl0KGdldEV4aXRDb2RlKGVycm9ycykpXG4gIH1cblxuICBlbnZlbG9wZSA9IGNyZWF0ZUVudmVsb3BlKHsgdG9vbDogVE9PTF9OQU1FLCBkYXRhOiByZXN1bHQuZGF0YSwgd2FybmluZ3MsIGVycm9ycywgcmF0ZUxpbWl0OiByZXN1bHQucmF0ZUxpbWl0IH0pXG4gIHByb2Nlc3Muc3Rkb3V0LndyaXRlKGAke0pTT04uc3RyaW5naWZ5KGVudmVsb3BlLCBudWxsLCAyKX1cXG5gKVxuICBwcm9jZXNzLmV4aXQoMClcbn1cblxubWFpbigpLmNhdGNoKChlcnJvcjogdW5rbm93bikgPT4ge1xuICBjb25zdCBtZXNzYWdlID0gZXJyb3IgaW5zdGFuY2VvZiBFcnJvciA/IGVycm9yLm1lc3NhZ2UgOiAnVW5rbm93biBlcnJvcidcbiAgY29uc3QgZW52ZWxvcGUgPSBjcmVhdGVFbnZlbG9wZSh7IHRvb2w6IFRPT0xfTkFNRSwgaW5wdXQ6IHt9LCBlcnJvcnM6IFtjcmVhdGVFcnJvcignSU5URVJOQUwnLCBtZXNzYWdlKV0gfSlcbiAgcHJvY2Vzcy5zdGRvdXQud3JpdGUoYCR7SlNPTi5zdHJpbmdpZnkoZW52ZWxvcGUsIG51bGwsIDIpfVxcbmApXG4gIHByb2Nlc3MuZXhpdCgzKVxufSlcblxuIl0sCiAgIm1hcHBpbmdzIjogIjs7O0FBT08sU0FBUyxVQUFVLE9BQWlCLFFBQVEsS0FBSyxNQUFNLENBQUMsR0FBWTtB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