idioma-cli
Version:
CLI for Idioma - Internationalization engine with smart defaults
319 lines (313 loc) • 40.5 kB
JavaScript
import {
getTranslationStatus,
startBackgroundTranslation,
stopBackgroundTranslation
} from "../shared/chunk-3acbb6gb.js";
// src/cli/index.ts
import { Command } from "commander";
import { readFileSync } from "fs";
import { dirname, join } from "path";
import { fileURLToPath } from "url";
// src/cli/commands.ts
import fs from "node:fs/promises";
import path from "node:path";
import { glob } from "glob";
import {
loadConfig,
loadLock,
processFiles,
replaceLocaleInPattern,
saveConfig,
saveLock
} from "idioma-sdk";
async function initCommand() {
const configPath = path.resolve("idioma.json");
try {
await fs.access(configPath);
console.log("Configuration file already exists.");
} catch {
const defaultConfig = {
provider: "anthropic",
locale: {
source: "en",
targets: []
},
files: {
include: ["**/*.mdx"]
}
};
await saveConfig(defaultConfig);
console.log("✓ Created idioma.json");
console.log(`
Next steps:`);
console.log("1. Add target locales: idioma add <locale>");
console.log("2. Configure your file patterns in idioma.json");
console.log("3. Run translation: idioma translate");
}
}
async function translateCommand(options) {
try {
const config = await loadConfig();
if (options.provider || options.model) {
config.translation = {
...config.translation || {},
...options.provider ? { provider: options.provider } : {},
...options.model ? { model: options.model } : {}
};
if (options.provider) {
config.provider = options.provider;
}
if (options.model) {
config.model = options.model;
}
}
const effectiveProvider = config.translation?.provider || config.provider || "anthropic";
const effectiveModel = config.translation?.model || config.model;
console.log(`[idioma] Using provider: ${effectiveProvider}${effectiveModel ? ` (model: ${effectiveModel})` : ""}`);
const lock = await loadLock();
const result = await processFiles(config, lock, { showCosts: options.costs });
await saveLock(result.lock);
console.log("Translation complete. Lockfile updated.");
} catch (error) {
if (error instanceof Error) {
console.error("Error:", error.message);
} else {
console.error("An unknown error occurred");
}
process.exit(1);
}
}
async function localeAddCommand(locales) {
try {
const config = await loadConfig();
const localeList = locales.split(",").map((l) => l.trim());
const added = [];
for (const locale of localeList) {
if (!config.locale.targets.includes(locale)) {
config.locale.targets.push(locale);
added.push(locale);
}
}
if (added.length > 0) {
await saveConfig(config);
console.log(`✓ Added locales: ${added.join(", ")}`);
} else {
console.log("All specified locales already exist.");
}
} catch (error) {
if (error instanceof Error) {
console.error("Error:", error.message);
} else {
console.error("An unknown error occurred");
}
process.exit(1);
}
}
async function localeRemoveCommand(locales) {
try {
const config = await loadConfig();
const localeList = locales.split(",").map((l) => l.trim());
const removed = [];
for (const locale of localeList) {
const index = config.locale.targets.indexOf(locale);
if (index !== -1) {
config.locale.targets.splice(index, 1);
removed.push(locale);
}
}
if (removed.length > 0) {
await saveConfig(config);
console.log(`✓ Removed locales: ${removed.join(", ")}`);
} else {
console.log("None of the specified locales were found.");
}
} catch (error) {
if (error instanceof Error) {
console.error("Error:", error.message);
} else {
console.error("An unknown error occurred");
}
process.exit(1);
}
}
async function localeListCommand() {
try {
const config = await loadConfig();
console.log("Source locale:", config.locale.source);
console.log("Target locales:", config.locale.targets.length ? config.locale.targets.join(", ") : "None");
} catch (error) {
if (error instanceof Error) {
console.error("Error:", error.message);
} else {
console.error("An unknown error occurred");
}
process.exit(1);
}
}
async function resetCommand() {
try {
const config = await loadConfig();
const lock = await loadLock();
if (config.locale.targets.length === 0) {
console.log("No target locales configured.");
return;
}
const deletedFiles = [];
for (const pattern of config.files) {
for (const targetLocale of config.locale.targets) {
const targetPattern = replaceLocaleInPattern(pattern, config.locale.source, targetLocale);
const files = await glob(targetPattern);
for (const file of files) {
try {
await fs.unlink(file);
deletedFiles.push(file);
} catch (_error) {}
}
if (files.length > 0) {
try {
const dirsToCheck = new Set;
for (const file of files) {
let dir = path.dirname(file);
while (dir.includes(`/${targetLocale}/`) || dir.endsWith(`/${targetLocale}`)) {
dirsToCheck.add(dir);
dir = path.dirname(dir);
}
}
const sortedDirs = Array.from(dirsToCheck).sort((a, b) => b.split("/").length - a.split("/").length);
for (const dir of sortedDirs) {
try {
await fs.rmdir(dir);
} catch {}
}
} catch {}
}
}
}
lock.files = {};
await saveLock(lock);
if (deletedFiles.length > 0) {
console.log(`✓ Reset complete. Removed ${deletedFiles.length} generated translation files:`);
deletedFiles.forEach((file) => console.log(` - ${file}`));
console.log(`
Translation status cleared. Run "idioma translate" to regenerate translations.`);
} else {
console.log("No translation files found. Lock file has been reset.");
}
} catch (error) {
if (error instanceof Error) {
console.error("Error:", error.message);
} else {
console.error("An unknown error occurred");
}
process.exit(1);
}
}
function displayStatus(status) {
const percentage = status.totalFiles > 0 ? Math.round(status.processedFiles / status.totalFiles * 100) : 0;
console.log(`
\uD83D\uDCCA Translation Status`);
console.log("─".repeat(40));
console.log(`Status: ${status.status === "running" ? "\uD83D\uDD04" : status.status === "completed" ? "✅" : "❌"} ${status.status}`);
console.log(`Progress: ${status.processedFiles}/${status.totalFiles} files (${percentage}%)`);
if (status.currentFile) {
console.log(`Current file: ${status.currentFile}`);
}
console.log(`Started: ${new Date(status.startTime).toLocaleString()}`);
if (status.endTime) {
console.log(`Ended: ${new Date(status.endTime).toLocaleString()}`);
const duration = new Date(status.endTime).getTime() - new Date(status.startTime).getTime();
const minutes = Math.floor(duration / 60000);
const seconds = Math.floor(duration % 60000 / 1000);
console.log(`Duration: ${minutes}m ${seconds}s`);
}
if (status.errors.length > 0) {
console.log(`
⚠️ Errors (${status.errors.length}):`);
status.errors.slice(-5).forEach((error) => {
console.log(` - ${error}`);
});
}
if (status.pid && status.status === "running") {
console.log(`
Process ID: ${status.pid}`);
console.log("To stop: idioma stop");
}
}
async function statusCommand(options = {}) {
if (options.tail) {
console.log("\uD83D\uDCE1 Real-time translation status (Press Ctrl+C to exit)");
console.log("═".repeat(50));
let lastStatus = null;
const updateDisplay = async () => {
const status = await getTranslationStatus();
if (!status) {
console.log(`
❌ No background translation is currently running.`);
process.exit(0);
}
const statusStr = JSON.stringify(status);
if (statusStr !== lastStatus) {
process.stdout.write("\x1B[2J\x1B[0f");
console.log("\uD83D\uDCE1 Real-time translation status (Press Ctrl+C to exit)");
console.log("═".repeat(50));
displayStatus(status);
if (status.status !== "running") {
console.log(`
\uD83C\uDFAF Translation finished!`);
process.exit(0);
}
lastStatus = statusStr;
}
};
await updateDisplay();
const interval = setInterval(updateDisplay, 2000);
process.on("SIGINT", () => {
clearInterval(interval);
console.log(`
\uD83D\uDC4B Exiting real-time status...`);
process.exit(0);
});
} else {
const status = await getTranslationStatus();
if (!status) {
console.log("No background translation is currently running.");
return;
}
displayStatus(status);
}
}
async function stopCommand() {
await stopBackgroundTranslation();
}
// src/cli/index.ts
var __filename2 = fileURLToPath(import.meta.url);
var __dirname2 = dirname(__filename2);
var packageJsonPath = join(__dirname2, "../../package.json");
var packageJson = JSON.parse(readFileSync(packageJsonPath, "utf8"));
var program = new Command;
program.name("idioma").description("Internationalization engine").version(packageJson.version);
program.command("init").description("Initialize Idioma configuration").action(initCommand);
program.command("translate").description("Translate files based on configuration").option("--costs", "Show translation costs based on token usage").option("--provider <provider>", "Override translation provider for this run").option("--model <model>", "Override translation model for this run").option("--background", "Run translation in the background").action(async (options) => {
if (options.background) {
const args = [];
if (options.costs)
args.push("--costs");
if (options.provider)
args.push("--provider", options.provider);
if (options.model)
args.push("--model", options.model);
await startBackgroundTranslation(args);
} else {
await translateCommand(options);
}
});
program.command("add <locales>").description("Add target locale(s) - supports comma-separated values (e.g., pt,fr)").action(localeAddCommand);
program.command("remove <locales>").description("Remove target locale(s) - supports comma-separated values (e.g., pt,fr)").action(localeRemoveCommand);
program.command("list").description("List all configured locales").action(localeListCommand);
program.command("reset").description("Reset translation status and remove generated translation files").action(resetCommand);
program.command("status").description("Check the status of a background translation").option("--tail", "Show real-time status updates").action(statusCommand);
program.command("stop").description("Stop a running background translation").action(stopCommand);
program.parse();
//# debugId=E649EAFE1D55390564756E2164756E21
//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiLi4vc3JjL2NsaS9pbmRleC50cyIsICIuLi9zcmMvY2xpL2NvbW1hbmRzLnRzIl0sCiAgInNvdXJjZXNDb250ZW50IjogWwogICAgIiMhL3Vzci9iaW4vZW52IG5vZGVcbmltcG9ydCB7IENvbW1hbmQgfSBmcm9tICdjb21tYW5kZXInO1xuaW1wb3J0IHsgcmVhZEZpbGVTeW5jIH0gZnJvbSAnZnMnO1xuaW1wb3J0IHsgZGlybmFtZSwgam9pbiB9IGZyb20gJ3BhdGgnO1xuaW1wb3J0IHsgZmlsZVVSTFRvUGF0aCB9IGZyb20gJ3VybCc7XG5pbXBvcnQgeyBzdGFydEJhY2tncm91bmRUcmFuc2xhdGlvbiB9IGZyb20gJy4vYmFja2dyb3VuZCc7XG5pbXBvcnQge1xuICBpbml0Q29tbWFuZCxcbiAgbG9jYWxlQWRkQ29tbWFuZCxcbiAgbG9jYWxlTGlzdENvbW1hbmQsXG4gIGxvY2FsZVJlbW92ZUNvbW1hbmQsXG4gIHJlc2V0Q29tbWFuZCxcbiAgc3RhdHVzQ29tbWFuZCxcbiAgc3RvcENvbW1hbmQsXG4gIHRyYW5zbGF0ZUNvbW1hbmQsXG59IGZyb20gJy4vY29tbWFuZHMnO1xuXG5jb25zdCBfX2ZpbGVuYW1lID0gZmlsZVVSTFRvUGF0aChpbXBvcnQubWV0YS51cmwpO1xuY29uc3QgX19kaXJuYW1lID0gZGlybmFtZShfX2ZpbGVuYW1lKTtcbmNvbnN0IHBhY2thZ2VKc29uUGF0aCA9IGpvaW4oX19kaXJuYW1lLCAnLi4vLi4vcGFja2FnZS5qc29uJyk7XG5jb25zdCBwYWNrYWdlSnNvbiA9IEpTT04ucGFyc2UocmVhZEZpbGVTeW5jKHBhY2thZ2VKc29uUGF0aCwgJ3V0ZjgnKSk7XG5cbmNvbnN0IHByb2dyYW0gPSBuZXcgQ29tbWFuZCgpO1xuXG5wcm9ncmFtLm5hbWUoJ2lkaW9tYScpLmRlc2NyaXB0aW9uKCdJbnRlcm5hdGlvbmFsaXphdGlvbiBlbmdpbmUnKS52ZXJzaW9uKHBhY2thZ2VKc29uLnZlcnNpb24pO1xuXG4vLyBJbml0IGNvbW1hbmRcbnByb2dyYW0uY29tbWFuZCgnaW5pdCcpLmRlc2NyaXB0aW9uKCdJbml0aWFsaXplIElkaW9tYSBjb25maWd1cmF0aW9uJykuYWN0aW9uKGluaXRDb21tYW5kKTtcblxuLy8gVHJhbnNsYXRlIGNvbW1hbmRcbnByb2dyYW1cbiAgLmNvbW1hbmQoJ3RyYW5zbGF0ZScpXG4gIC5kZXNjcmlwdGlvbignVHJhbnNsYXRlIGZpbGVzIGJhc2VkIG9uIGNvbmZpZ3VyYXRpb24nKVxuICAub3B0aW9uKCctLWNvc3RzJywgJ1Nob3cgdHJhbnNsYXRpb24gY29zdHMgYmFzZWQgb24gdG9rZW4gdXNhZ2UnKVxuICAub3B0aW9uKCctLXByb3ZpZGVyIDxwcm92aWRlcj4nLCAnT3ZlcnJpZGUgdHJhbnNsYXRpb24gcHJvdmlkZXIgZm9yIHRoaXMgcnVuJylcbiAgLm9wdGlvbignLS1tb2RlbCA8bW9kZWw+JywgJ092ZXJyaWRlIHRyYW5zbGF0aW9uIG1vZGVsIGZvciB0aGlzIHJ1bicpXG4gIC5vcHRpb24oJy0tYmFja2dyb3VuZCcsICdSdW4gdHJhbnNsYXRpb24gaW4gdGhlIGJhY2tncm91bmQnKVxuICAuYWN0aW9uKGFzeW5jIChvcHRpb25zKSA9PiB7XG4gICAgaWYgKG9wdGlvbnMuYmFja2dyb3VuZCkge1xuICAgICAgY29uc3QgYXJncyA9IFtdO1xuICAgICAgaWYgKG9wdGlvbnMuY29zdHMpIGFyZ3MucHVzaCgnLS1jb3N0cycpO1xuICAgICAgaWYgKG9wdGlvbnMucHJvdmlkZXIpIGFyZ3MucHVzaCgnLS1wcm92aWRlcicsIG9wdGlvbnMucHJvdmlkZXIpO1xuICAgICAgaWYgKG9wdGlvbnMubW9kZWwpIGFyZ3MucHVzaCgnLS1tb2RlbCcsIG9wdGlvbnMubW9kZWwpO1xuICAgICAgYXdhaXQgc3RhcnRCYWNrZ3JvdW5kVHJhbnNsYXRpb24oYXJncyk7XG4gICAgfSBlbHNlIHtcbiAgICAgIGF3YWl0IHRyYW5zbGF0ZUNvbW1hbmQob3B0aW9ucyk7XG4gICAgfVxuICB9KTtcblxuLy8gRGlyZWN0IGxvY2FsZSBjb21tYW5kc1xucHJvZ3JhbVxuICAuY29tbWFuZCgnYWRkIDxsb2NhbGVzPicpXG4gIC5kZXNjcmlwdGlvbignQWRkIHRhcmdldCBsb2NhbGUocykgLSBzdXBwb3J0cyBjb21tYS1zZXBhcmF0ZWQgdmFsdWVzIChlLmcuLCBwdCxmciknKVxuICAuYWN0aW9uKGxvY2FsZUFkZENvbW1hbmQpO1xuXG5wcm9ncmFtXG4gIC5jb21tYW5kKCdyZW1vdmUgPGxvY2FsZXM+JylcbiAgLmRlc2NyaXB0aW9uKCdSZW1vdmUgdGFyZ2V0IGxvY2FsZShzKSAtIHN1cHBvcnRzIGNvbW1hLXNlcGFyYXRlZCB2YWx1ZXMgKGUuZy4sIHB0LGZyKScpXG4gIC5hY3Rpb24obG9jYWxlUmVtb3ZlQ29tbWFuZCk7XG5cbnByb2dyYW0uY29tbWFuZCgnbGlzdCcpLmRlc2NyaXB0aW9uKCdMaXN0IGFsbCBjb25maWd1cmVkIGxvY2FsZXMnKS5hY3Rpb24obG9jYWxlTGlzdENvbW1hbmQpO1xuXG4vLyBSZXNldCBjb21tYW5kXG5wcm9ncmFtXG4gIC5jb21tYW5kKCdyZXNldCcpXG4gIC5kZXNjcmlwdGlvbignUmVzZXQgdHJhbnNsYXRpb24gc3RhdHVzIGFuZCByZW1vdmUgZ2VuZXJhdGVkIHRyYW5zbGF0aW9uIGZpbGVzJylcbiAgLmFjdGlvbihyZXNldENvbW1hbmQpO1xuXG4vLyBTdGF0dXMgY29tbWFuZCAtIGNoZWNrIGJhY2tncm91bmQgdHJhbnNsYXRpb24gc3RhdHVzXG5wcm9ncmFtXG4gIC5jb21tYW5kKCdzdGF0dXMnKVxuICAuZGVzY3JpcHRpb24oJ0NoZWNrIHRoZSBzdGF0dXMgb2YgYSBiYWNrZ3JvdW5kIHRyYW5zbGF0aW9uJylcbiAgLm9wdGlvbignLS10YWlsJywgJ1Nob3cgcmVhbC10aW1lIHN0YXR1cyB1cGRhdGVzJylcbiAgLmFjdGlvbihzdGF0dXNDb21tYW5kKTtcblxuLy8gU3RvcCBjb21tYW5kIC0gc3RvcCBiYWNrZ3JvdW5kIHRyYW5zbGF0aW9uXG5wcm9ncmFtLmNvbW1hbmQoJ3N0b3AnKS5kZXNjcmlwdGlvbignU3RvcCBhIHJ1bm5pbmcgYmFja2dyb3VuZCB0cmFuc2xhdGlvbicpLmFjdGlvbihzdG9wQ29tbWFuZCk7XG5cbi8vIFBhcnNlIGNvbW1hbmQgbGluZSBhcmd1bWVudHNcbnByb2dyYW0ucGFyc2UoKTtcbiIsCiAgICAiaW1wb3J0IGZzIGZyb20gJ25vZGU6ZnMvcHJvbWlzZXMnO1xuaW1wb3J0IHBhdGggZnJvbSAnbm9kZTpwYXRoJztcbmltcG9ydCB7IGdsb2IgfSBmcm9tICdnbG9iJztcbmltcG9ydCB7XG4gIHR5cGUgQ29uZmlnLFxuICBsb2FkQ29uZmlnLFxuICBsb2FkTG9jayxcbiAgcHJvY2Vzc0ZpbGVzLFxuICByZXBsYWNlTG9jYWxlSW5QYXR0ZXJuLFxuICBzYXZlQ29uZmlnLFxuICBzYXZlTG9jayxcbn0gZnJvbSAnaWRpb21hLXNkayc7XG5pbXBvcnQgeyBnZXRUcmFuc2xhdGlvblN0YXR1cywgc3RvcEJhY2tncm91bmRUcmFuc2xhdGlvbiB9IGZyb20gJy4vYmFja2dyb3VuZCc7XG5cbi8vIEluaXQgY29tbWFuZCAtIGNyZWF0ZSBjb25maWcgZmlsZVxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGluaXRDb21tYW5kKCk6IFByb21pc2U8dm9pZD4ge1xuICBjb25zdCBjb25maWdQYXRoID0gcGF0aC5yZXNvbHZlKCdpZGlvbWEuanNvbicpO1xuXG4gIHRyeSB7XG4gICAgYXdhaXQgZnMuYWNjZXNzKGNvbmZpZ1BhdGgpO1xuICAgIGNvbnNvbGUubG9nKCdDb25maWd1cmF0aW9uIGZpbGUgYWxyZWFkeSBleGlzdHMuJyk7XG4gIH0gY2F0Y2gge1xuICAgIGNvbnN0IGRlZmF1bHRDb25maWc6IENvbmZpZyA9IHtcbiAgICAgIHByb3ZpZGVyOiAnYW50aHJvcGljJyxcbiAgICAgIGxvY2FsZToge1xuICAgICAgICBzb3VyY2U6ICdlbicsXG4gICAgICAgIHRhcmdldHM6IFtdLFxuICAgICAgfSxcbiAgICAgIGZpbGVzOiB7XG4gICAgICAgIGluY2x1ZGU6IFsnKiovKi5tZHgnXSxcbiAgICAgIH0sXG4gICAgfTtcblxuICAgIGF3YWl0IHNhdmVDb25maWcoZGVmYXVsdENvbmZpZyk7XG4gICAgY29uc29sZS5sb2coJ+KckyBDcmVhdGVkIGlkaW9tYS5qc29uJyk7XG4gICAgY29uc29sZS5sb2coJ1xcbk5leHQgc3RlcHM6Jyk7XG4gICAgY29uc29sZS5sb2coJzEuIEFkZCB0YXJnZXQgbG9jYWxlczogaWRpb21hIGFkZCA8bG9jYWxlPicpO1xuICAgIGNvbnNvbGUubG9nKCcyLiBDb25maWd1cmUgeW91ciBmaWxlIHBhdHRlcm5zIGluIGlkaW9tYS5qc29uJyk7XG4gICAgY29uc29sZS5sb2coJzMuIFJ1biB0cmFuc2xhdGlvbjogaWRpb21hIHRyYW5zbGF0ZScpO1xuICB9XG59XG5cbi8vIFRyYW5zbGF0ZSBjb21tYW5kIC0gcHJvY2VzcyBhbGwgZmlsZXNcbmV4cG9ydCBhc3luYyBmdW5jdGlvbiB0cmFuc2xhdGVDb21tYW5kKG9wdGlvbnM6IHtcbiAgY29zdHM/OiBib29sZWFuO1xuICBwcm92aWRlcj86IHN0cmluZztcbiAgbW9kZWw/OiBzdHJpbmc7XG59KTogUHJvbWlzZTx2b2lkPiB7XG4gIHRyeSB7XG4gICAgLy8gTG9hZCBjb25maWd1cmF0aW9uXG4gICAgY29uc3QgY29uZmlnID0gYXdhaXQgbG9hZENvbmZpZygpO1xuICAgIGlmIChvcHRpb25zLnByb3ZpZGVyIHx8IG9wdGlvbnMubW9kZWwpIHtcbiAgICAgIGNvbmZpZy50cmFuc2xhdGlvbiA9IHtcbiAgICAgICAgLi4uKGNvbmZpZy50cmFuc2xhdGlvbiB8fCB7fSksXG4gICAgICAgIC4uLihvcHRpb25zLnByb3ZpZGVyID8geyBwcm92aWRlcjogb3B0aW9ucy5wcm92aWRlciB9IDoge30pLFxuICAgICAgICAuLi4ob3B0aW9ucy5tb2RlbCA/IHsgbW9kZWw6IG9wdGlvbnMubW9kZWwgfSA6IHt9KSxcbiAgICAgIH07XG4gICAgICBpZiAob3B0aW9ucy5wcm92aWRlcikge1xuICAgICAgICBjb25maWcucHJvdmlkZXIgPSBvcHRpb25zLnByb3ZpZGVyO1xuICAgICAgfVxuICAgICAgaWYgKG9wdGlvbnMubW9kZWwpIHtcbiAgICAgICAgY29uZmlnLm1vZGVsID0gb3B0aW9ucy5tb2RlbDtcbiAgICAgIH1cbiAgICB9XG4gICAgY29uc3QgZWZmZWN0aXZlUHJvdmlkZXIgPSBjb25maWcudHJhbnNsYXRpb24/LnByb3ZpZGVyIHx8IGNvbmZpZy5wcm92aWRlciB8fCAnYW50aHJvcGljJztcbiAgICBjb25zdCBlZmZlY3RpdmVNb2RlbCA9IGNvbmZpZy50cmFuc2xhdGlvbj8ubW9kZWwgfHwgY29uZmlnLm1vZGVsO1xuICAgIGNvbnNvbGUubG9nKFxuICAgICAgYFtpZGlvbWFdIFVzaW5nIHByb3ZpZGVyOiAke2VmZmVjdGl2ZVByb3ZpZGVyfSR7XG4gICAgICAgIGVmZmVjdGl2ZU1vZGVsID8gYCAobW9kZWw6ICR7ZWZmZWN0aXZlTW9kZWx9KWAgOiAnJ1xuICAgICAgfWBcbiAgICApO1xuICAgIGNvbnN0IGxvY2sgPSBhd2FpdCBsb2FkTG9jaygpO1xuXG4gICAgLy8gUHJvY2VzcyBhbGwgZmlsZXNcbiAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBwcm9jZXNzRmlsZXMoY29uZmlnLCBsb2NrLCB7IHNob3dDb3N0czogb3B0aW9ucy5jb3N0cyB9KTtcblxuICAgIC8vIFNhdmUgdXBkYXRlZCBsb2NrIGZpbGVcbiAgICBhd2FpdCBzYXZlTG9jayhyZXN1bHQubG9jayk7XG4gICAgY29uc29sZS5sb2coJ1RyYW5zbGF0aW9uIGNvbXBsZXRlLiBMb2NrZmlsZSB1cGRhdGVkLicpO1xuICB9IGNhdGNoIChlcnJvcikge1xuICAgIGlmIChlcnJvciBpbnN0YW5jZW9mIEVycm9yKSB7XG4gICAgICBjb25zb2xlLmVycm9yKCdFcnJvcjonLCBlcnJvci5tZXNzYWdlKTtcbiAgICB9IGVsc2Uge1xuICAgICAgY29uc29sZS5lcnJvcignQW4gdW5rbm93biBlcnJvciBvY2N1cnJlZCcpO1xuICAgIH1cbiAgICBwcm9jZXNzLmV4aXQoMSk7XG4gIH1cbn1cblxuLy8gTG9jYWxlIGFkZCBjb21tYW5kIC0gc3VwcG9ydHMgY29tbWEtc2VwYXJhdGVkIGxvY2FsZXNcbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBsb2NhbGVBZGRDb21tYW5kKGxvY2FsZXM6IHN0cmluZyk6IFByb21pc2U8dm9pZD4ge1xuICB0cnkge1xuICAgIGNvbnN0IGNvbmZpZyA9IGF3YWl0IGxvYWRDb25maWcoKTtcbiAgICBjb25zdCBsb2NhbGVMaXN0ID0gbG9jYWxlcy5zcGxpdCgnLCcpLm1hcCgobCkgPT4gbC50cmltKCkpO1xuICAgIGNvbnN0IGFkZGVkOiBzdHJpbmdbXSA9IFtdO1xuXG4gICAgZm9yIChjb25zdCBsb2NhbGUgb2YgbG9jYWxlTGlzdCkge1xuICAgICAgaWYgKCFjb25maWcubG9jYWxlLnRhcmdldHMuaW5jbHVkZXMobG9jYWxlKSkge1xuICAgICAgICBjb25maWcubG9jYWxlLnRhcmdldHMucHVzaChsb2NhbGUpO1xuICAgICAgICBhZGRlZC5wdXNoKGxvY2FsZSk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgaWYgKGFkZGVkLmxlbmd0aCA+IDApIHtcbiAgICAgIGF3YWl0IHNhdmVDb25maWcoY29uZmlnKTtcbiAgICAgIGNvbnNvbGUubG9nKGDinJMgQWRkZWQgbG9jYWxlczogJHthZGRlZC5qb2luKCcsICcpfWApO1xuICAgIH0gZWxzZSB7XG4gICAgICBjb25zb2xlLmxvZygnQWxsIHNwZWNpZmllZCBsb2NhbGVzIGFscmVhZHkgZXhpc3QuJyk7XG4gICAgfVxuICB9IGNhdGNoIChlcnJvcikge1xuICAgIGlmIChlcnJvciBpbnN0YW5jZW9mIEVycm9yKSB7XG4gICAgICBjb25zb2xlLmVycm9yKCdFcnJvcjonLCBlcnJvci5tZXNzYWdlKTtcbiAgICB9IGVsc2Uge1xuICAgICAgY29uc29sZS5lcnJvcignQW4gdW5rbm93biBlcnJvciBvY2N1cnJlZCcpO1xuICAgIH1cbiAgICBwcm9jZXNzLmV4aXQoMSk7XG4gIH1cbn1cblxuLy8gTG9jYWxlIHJlbW92ZSBjb21tYW5kIC0gc3VwcG9ydHMgY29tbWEtc2VwYXJhdGVkIGxvY2FsZXNcbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBsb2NhbGVSZW1vdmVDb21tYW5kKGxvY2FsZXM6IHN0cmluZyk6IFByb21pc2U8dm9pZD4ge1xuICB0cnkge1xuICAgIGNvbnN0IGNvbmZpZyA9IGF3YWl0IGxvYWRDb25maWcoKTtcbiAgICBjb25zdCBsb2NhbGVMaXN0ID0gbG9jYWxlcy5zcGxpdCgnLCcpLm1hcCgobCkgPT4gbC50cmltKCkpO1xuICAgIGNvbnN0IHJlbW92ZWQ6IHN0cmluZ1tdID0gW107XG5cbiAgICBmb3IgKGNvbnN0IGxvY2FsZSBvZiBsb2NhbGVMaXN0KSB7XG4gICAgICBjb25zdCBpbmRleCA9IGNvbmZpZy5sb2NhbGUudGFyZ2V0cy5pbmRleE9mKGxvY2FsZSk7XG4gICAgICBpZiAoaW5kZXggIT09IC0xKSB7XG4gICAgICAgIGNvbmZpZy5sb2NhbGUudGFyZ2V0cy5zcGxpY2UoaW5kZXgsIDEpO1xuICAgICAgICByZW1vdmVkLnB1c2gobG9jYWxlKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICBpZiAocmVtb3ZlZC5sZW5ndGggPiAwKSB7XG4gICAgICBhd2FpdCBzYXZlQ29uZmlnKGNvbmZpZyk7XG4gICAgICBjb25zb2xlLmxvZyhg4pyTIFJlbW92ZWQgbG9jYWxlczogJHtyZW1vdmVkLmpvaW4oJywgJyl9YCk7XG4gICAgfSBlbHNlIHtcbiAgICAgIGNvbnNvbGUubG9nKCdOb25lIG9mIHRoZSBzcGVjaWZpZWQgbG9jYWxlcyB3ZXJlIGZvdW5kLicpO1xuICAgIH1cbiAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICBpZiAoZXJyb3IgaW5zdGFuY2VvZiBFcnJvcikge1xuICAgICAgY29uc29sZS5lcnJvcignRXJyb3I6JywgZXJyb3IubWVzc2FnZSk7XG4gICAgfSBlbHNlIHtcbiAgICAgIGNvbnNvbGUuZXJyb3IoJ0FuIHVua25vd24gZXJyb3Igb2NjdXJyZWQnKTtcbiAgICB9XG4gICAgcHJvY2Vzcy5leGl0KDEpO1xuICB9XG59XG5cbi8vIExvY2FsZSBsaXN0IGNvbW1hbmRcbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBsb2NhbGVMaXN0Q29tbWFuZCgpOiBQcm9taXNlPHZvaWQ+IHtcbiAgdHJ5IHtcbiAgICBjb25zdCBjb25maWcgPSBhd2FpdCBsb2FkQ29uZmlnKCk7XG5cbiAgICBjb25zb2xlLmxvZygnU291cmNlIGxvY2FsZTonLCBjb25maWcubG9jYWxlLnNvdXJjZSk7XG4gICAgY29uc29sZS5sb2coXG4gICAgICAnVGFyZ2V0IGxvY2FsZXM6JyxcbiAgICAgIGNvbmZpZy5sb2NhbGUudGFyZ2V0cy5sZW5ndGggPyBjb25maWcubG9jYWxlLnRhcmdldHMuam9pbignLCAnKSA6ICdOb25lJ1xuICAgICk7XG4gIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgaWYgKGVycm9yIGluc3RhbmNlb2YgRXJyb3IpIHtcbiAgICAgIGNvbnNvbGUuZXJyb3IoJ0Vycm9yOicsIGVycm9yLm1lc3NhZ2UpO1xuICAgIH0gZWxzZSB7XG4gICAgICBjb25zb2xlLmVycm9yKCdBbiB1bmtub3duIGVycm9yIG9jY3VycmVkJyk7XG4gICAgfVxuICAgIHByb2Nlc3MuZXhpdCgxKTtcbiAgfVxufVxuXG4vLyBSZXNldCBjb21tYW5kIC0gcmVzZXQgdHJhbnNsYXRpb24gc3RhdHVzIGFuZCByZW1vdmUgZ2VuZXJhdGVkIGZpbGVzXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gcmVzZXRDb21tYW5kKCk6IFByb21pc2U8dm9pZD4ge1xuICB0cnkge1xuICAgIGNvbnN0IGNvbmZpZyA9IGF3YWl0IGxvYWRDb25maWcoKTtcbiAgICBjb25zdCBsb2NrID0gYXdhaXQgbG9hZExvY2soKTtcblxuICAgIGlmIChjb25maWcubG9jYWxlLnRhcmdldHMubGVuZ3RoID09PSAwKSB7XG4gICAgICBjb25zb2xlLmxvZygnTm8gdGFyZ2V0IGxvY2FsZXMgY29uZmlndXJlZC4nKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBjb25zdCBkZWxldGVkRmlsZXM6IHN0cmluZ1tdID0gW107XG5cbiAgICAvLyBQcm9jZXNzIGVhY2ggZmlsZSBwYXR0ZXJuXG4gICAgZm9yIChjb25zdCBwYXR0ZXJuIG9mIGNvbmZpZy5maWxlcykge1xuICAgICAgZm9yIChjb25zdCB0YXJnZXRMb2NhbGUgb2YgY29uZmlnLmxvY2FsZS50YXJnZXRzKSB7XG4gICAgICAgIC8vIFJlcGxhY2UgW2xvY2FsZV0gcGxhY2Vob2xkZXIgd2l0aCB0YXJnZXQgbG9jYWxlXG4gICAgICAgIGNvbnN0IHRhcmdldFBhdHRlcm4gPSByZXBsYWNlTG9jYWxlSW5QYXR0ZXJuKHBhdHRlcm4sIGNvbmZpZy5sb2NhbGUuc291cmNlLCB0YXJnZXRMb2NhbGUpO1xuXG4gICAgICAgIC8vIEZpbmQgYWxsIGZpbGVzIG1hdGNoaW5nIHRoZSB0YXJnZXQgcGF0dGVyblxuICAgICAgICBjb25zdCBmaWxlcyA9IGF3YWl0IGdsb2IodGFyZ2V0UGF0dGVybik7XG5cbiAgICAgICAgZm9yIChjb25zdCBmaWxlIG9mIGZpbGVzKSB7XG4gICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIGF3YWl0IGZzLnVubGluayhmaWxlKTtcbiAgICAgICAgICAgIGRlbGV0ZWRGaWxlcy5wdXNoKGZpbGUpO1xuICAgICAgICAgIH0gY2F0Y2ggKF9lcnJvcikge1xuICAgICAgICAgICAgLy8gRmlsZSBtaWdodCBub3QgZXhpc3QsIGNvbnRpbnVlXG4gICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgLy8gVHJ5IHRvIHJlbW92ZSBlbXB0eSBkaXJlY3RvcmllcyBhZnRlciBkZWxldGluZyBmaWxlc1xuICAgICAgICBpZiAoZmlsZXMubGVuZ3RoID4gMCkge1xuICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICAvLyBHZXQgdW5pcXVlIGRpcmVjdG9yaWVzIGZyb20gZGVsZXRlZCBmaWxlc1xuICAgICAgICAgICAgY29uc3QgZGlyc1RvQ2hlY2sgPSBuZXcgU2V0PHN0cmluZz4oKTtcbiAgICAgICAgICAgIGZvciAoY29uc3QgZmlsZSBvZiBmaWxlcykge1xuICAgICAgICAgICAgICBsZXQgZGlyID0gcGF0aC5kaXJuYW1lKGZpbGUpO1xuICAgICAgICAgICAgICAvLyBBZGQgYWxsIHBhcmVudCBkaXJlY3RvcmllcyB1cCB0byB0aGUgbG9jYWxlIGRpcmVjdG9yeVxuICAgICAgICAgICAgICB3aGlsZSAoZGlyLmluY2x1ZGVzKGAvJHt0YXJnZXRMb2NhbGV9L2ApIHx8IGRpci5lbmRzV2l0aChgLyR7dGFyZ2V0TG9jYWxlfWApKSB7XG4gICAgICAgICAgICAgICAgZGlyc1RvQ2hlY2suYWRkKGRpcik7XG4gICAgICAgICAgICAgICAgZGlyID0gcGF0aC5kaXJuYW1lKGRpcik7XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgLy8gU29ydCBkaXJlY3RvcmllcyBieSBkZXB0aCAoZGVlcGVzdCBmaXJzdCkgdG8gcmVtb3ZlIGZyb20gYm90dG9tIHVwXG4gICAgICAgICAgICBjb25zdCBzb3J0ZWREaXJzID0gQXJyYXkuZnJvbShkaXJzVG9DaGVjaykuc29ydChcbiAgICAgICAgICAgICAgKGEsIGIpID0+IGIuc3BsaXQoJy8nKS5sZW5ndGggLSBhLnNwbGl0KCcvJykubGVuZ3RoXG4gICAgICAgICAgICApO1xuXG4gICAgICAgICAgICBmb3IgKGNvbnN0IGRpciBvZiBzb3J0ZWREaXJzKSB7XG4gICAgICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICAgICAgYXdhaXQgZnMucm1kaXIoZGlyKTtcbiAgICAgICAgICAgICAgfSBjYXRjaCB7XG4gICAgICAgICAgICAgICAgLy8gRGlyZWN0b3J5IG5vdCBlbXB0eSBvciBkb2Vzbid0IGV4aXN0LCBjb250aW51ZVxuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSBjYXRjaCB7XG4gICAgICAgICAgICAvLyBFcnJvciByZW1vdmluZyBkaXJlY3RvcmllcywgY29udGludWVcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBSZXNldCBsb2NrIGZpbGUgdG8gaW5pdGlhbCBzdGF0ZVxuICAgIGxvY2suZmlsZXMgPSB7fTtcblxuICAgIGF3YWl0IHNhdmVMb2NrKGxvY2spO1xuXG4gICAgaWYgKGRlbGV0ZWRGaWxlcy5sZW5ndGggPiAwKSB7XG4gICAgICBjb25zb2xlLmxvZyhg4pyTIFJlc2V0IGNvbXBsZXRlLiBSZW1vdmVkICR7ZGVsZXRlZEZpbGVzLmxlbmd0aH0gZ2VuZXJhdGVkIHRyYW5zbGF0aW9uIGZpbGVzOmApO1xuICAgICAgZGVsZXRlZEZpbGVzLmZvckVhY2goKGZpbGUpID0+IGNvbnNvbGUubG9nKGAgIC0gJHtmaWxlfWApKTtcbiAgICAgIGNvbnNvbGUubG9nKFxuICAgICAgICAnXFxuVHJhbnNsYXRpb24gc3RhdHVzIGNsZWFyZWQuIFJ1biBcImlkaW9tYSB0cmFuc2xhdGVcIiB0byByZWdlbmVyYXRlIHRyYW5zbGF0aW9ucy4nXG4gICAgICApO1xuICAgIH0gZWxzZSB7XG4gICAgICBjb25zb2xlLmxvZygnTm8gdHJhbnNsYXRpb24gZmlsZXMgZm91bmQuIExvY2sgZmlsZSBoYXMgYmVlbiByZXNldC4nKTtcbiAgICB9XG4gIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgaWYgKGVycm9yIGluc3RhbmNlb2YgRXJyb3IpIHtcbiAgICAgIGNvbnNvbGUuZXJyb3IoJ0Vycm9yOicsIGVycm9yLm1lc3NhZ2UpO1xuICAgIH0gZWxzZSB7XG4gICAgICBjb25zb2xlLmVycm9yKCdBbiB1bmtub3duIGVycm9yIG9jY3VycmVkJyk7XG4gICAgfVxuICAgIHByb2Nlc3MuZXhpdCgxKTtcbiAgfVxufVxuXG4vLyBEaXNwbGF5IHRyYW5zbGF0aW9uIHN0YXR1cyAoc2hhcmVkIGhlbHBlcilcbmZ1bmN0aW9uIGRpc3BsYXlTdGF0dXMoc3RhdHVzOiBhbnkpOiB2b2lkIHtcbiAgY29uc3QgcGVyY2VudGFnZSA9XG4gICAgc3RhdHVzLnRvdGFsRmlsZXMgPiAwID8gTWF0aC5yb3VuZCgoc3RhdHVzLnByb2Nlc3NlZEZpbGVzIC8gc3RhdHVzLnRvdGFsRmlsZXMpICogMTAwKSA6IDA7XG5cbiAgY29uc29sZS5sb2coJ1xcbvCfk4ogVHJhbnNsYXRpb24gU3RhdHVzJyk7XG4gIGNvbnNvbGUubG9nKCfilIAnLnJlcGVhdCg0MCkpO1xuICBjb25zb2xlLmxvZyhcbiAgICBgU3RhdHVzOiAke3N0YXR1cy5zdGF0dXMgPT09ICdydW5uaW5nJyA/ICfwn5SEJyA6IHN0YXR1cy5zdGF0dXMgPT09ICdjb21wbGV0ZWQnID8gJ+KchScgOiAn4p2MJ30gJHtzdGF0dXMuc3RhdHVzfWBcbiAgKTtcbiAgY29uc29sZS5sb2coYFByb2dyZXNzOiAke3N0YXR1cy5wcm9jZXNzZWRGaWxlc30vJHtzdGF0dXMudG90YWxGaWxlc30gZmlsZXMgKCR7cGVyY2VudGFnZX0lKWApO1xuXG4gIGlmIChzdGF0dXMuY3VycmVudEZpbGUpIHtcbiAgICBjb25zb2xlLmxvZyhgQ3VycmVudCBmaWxlOiAke3N0YXR1cy5jdXJyZW50RmlsZX1gKTtcbiAgfVxuXG4gIGNvbnNvbGUubG9nKGBTdGFydGVkOiAke25ldyBEYXRlKHN0YXR1cy5zdGFydFRpbWUpLnRvTG9jYWxlU3RyaW5nKCl9YCk7XG5cbiAgaWYgKHN0YXR1cy5lbmRUaW1lKSB7XG4gICAgY29uc29sZS5sb2coYEVuZGVkOiAke25ldyBEYXRlKHN0YXR1cy5lbmRUaW1lKS50b0xvY2FsZVN0cmluZygpfWApO1xuICAgIGNvbnN0IGR1cmF0aW9uID0gbmV3IERhdGUoc3RhdHVzLmVuZFRpbWUpLmdldFRpbWUoKSAtIG5ldyBEYXRlKHN0YXR1cy5zdGFydFRpbWUpLmdldFRpbWUoKTtcbiAgICBjb25zdCBtaW51dGVzID0gTWF0aC5mbG9vcihkdXJhdGlvbiAvIDYwMDAwKTtcbiAgICBjb25zdCBzZWNvbmRzID0gTWF0aC5mbG9vcigoZHVyYXRpb24gJSA2MDAwMCkgLyAxMDAwKTtcbiAgICBjb25zb2xlLmxvZyhgRHVyYXRpb246ICR7bWludXRlc31tICR7c2Vjb25kc31zYCk7XG4gIH1cblxuICBpZiAoc3RhdHVzLmVycm9ycy5sZW5ndGggPiAwKSB7XG4gICAgY29uc29sZS5sb2coYFxcbuKaoO+4jyAgRXJyb3JzICgke3N0YXR1cy5lcnJvcnMubGVuZ3RofSk6YCk7XG4gICAgc3RhdHVzLmVycm9ycy5zbGljZSgtNSkuZm9yRWFjaCgoZXJyb3IpID0+IHtcbiAgICAgIGNvbnNvbGUubG9nKGAgIC0gJHtlcnJvcn1gKTtcbiAgICB9KTtcbiAgfVxuXG4gIGlmIChzdGF0dXMucGlkICYmIHN0YXR1cy5zdGF0dXMgPT09ICdydW5uaW5nJykge1xuICAgIGNvbnNvbGUubG9nKGBcXG5Qcm9jZXNzIElEOiAke3N0YXR1cy5waWR9YCk7XG4gICAgY29uc29sZS5sb2coJ1RvIHN0b3A6IGlkaW9tYSBzdG9wJyk7XG4gIH1cbn1cblxuLy8gU3RhdHVzIGNvbW1hbmQgLSBjaGVjayBiYWNrZ3JvdW5kIHRyYW5zbGF0aW9uIHN0YXR1c1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHN0YXR1c0NvbW1hbmQob3B0aW9uczogeyB0YWlsPzogYm9vbGVhbiB9ID0ge30pOiBQcm9taXNlPHZvaWQ+IHtcbiAgaWYgKG9wdGlvbnMudGFpbCkge1xuICAgIC8vIFJlYWwtdGltZSBzdGF0dXMgdXBkYXRlc1xuICAgIGNvbnNvbGUubG9nKCfwn5OhIFJlYWwtdGltZSB0cmFuc2xhdGlvbiBzdGF0dXMgKFByZXNzIEN0cmwrQyB0byBleGl0KScpO1xuICAgIGNvbnNvbGUubG9nKCfilZAnLnJlcGVhdCg1MCkpO1xuXG4gICAgbGV0IGxhc3RTdGF0dXM6IGFueSA9IG51bGw7XG5cbiAgICBjb25zdCB1cGRhdGVEaXNwbGF5ID0gYXN5bmMgKCkgPT4ge1xuICAgICAgY29uc3Qgc3RhdHVzID0gYXdhaXQgZ2V0VHJhbnNsYXRpb25TdGF0dXMoKTtcblxuICAgICAgaWYgKCFzdGF0dXMpIHtcbiAgICAgICAgY29uc29sZS5sb2coJ1xcbuKdjCBObyBiYWNrZ3JvdW5kIHRyYW5zbGF0aW9uIGlzIGN1cnJlbnRseSBydW5uaW5nLicpO1xuICAgICAgICBwcm9jZXNzLmV4aXQoMCk7XG4gICAgICB9XG5cbiAgICAgIC8vIE9ubHkgdXBkYXRlIGRpc3BsYXkgaWYgc3RhdHVzIGNoYW5nZWRcbiAgICAgIGNvbnN0IHN0YXR1c1N0ciA9IEpTT04uc3RyaW5naWZ5KHN0YXR1cyk7XG4gICAgICBpZiAoc3RhdHVzU3RyICE9PSBsYXN0U3RhdHVzKSB7XG4gICAgICAgIC8vIENsZWFyIHNjcmVlbiBhbmQgc2hvdyB1cGRhdGVkIHN0YXR1c1xuICAgICAgICBwcm9jZXNzLnN0ZG91dC53cml0ZSgnXFx4MUJbMkpcXHgxQlswZicpO1xuICAgICAgICBjb25zb2xlLmxvZygn8J+ToSBSZWFsLXRpbWUgdHJhbnNsYXRpb24gc3RhdHVzIChQcmVzcyBDdHJsK0MgdG8gZXhpdCknKTtcbiAgICAgICAgY29uc29sZS5sb2coJ+KVkCcucmVwZWF0KDUwKSk7XG4gICAgICAgIGRpc3BsYXlTdGF0dXMoc3RhdHVzKTtcblxuICAgICAgICAvLyBFeGl0IGlmIHRyYW5zbGF0aW9uIGNvbXBsZXRlZCBvciBmYWlsZWRcbiAgICAgICAgaWYgKHN0YXR1cy5zdGF0dXMgIT09ICdydW5uaW5nJykge1xuICAgICAgICAgIGNvbnNvbGUubG9nKCdcXG7wn46vIFRyYW5zbGF0aW9uIGZpbmlzaGVkIScpO1xuICAgICAgICAgIHByb2Nlc3MuZXhpdCgwKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGxhc3RTdGF0dXMgPSBzdGF0dXNTdHI7XG4gICAgICB9XG4gICAgfTtcblxuICAgIC8vIEluaXRpYWwgZGlzcGxheVxuICAgIGF3YWl0IHVwZGF0ZURpc3BsYXkoKTtcblxuICAgIC8vIFVwZGF0ZSBldmVyeSAyIHNlY29uZHNcbiAgICBjb25zdCBpbnRlcnZhbCA9IHNldEludGVydmFsKHVwZGF0ZURpc3BsYXksIDIwMDApO1xuXG4gICAgLy8gSGFuZGxlIEN0cmwrQyBncmFjZWZ1bGx5XG4gICAgcHJvY2Vzcy5vbignU0lHSU5UJywgKCkgPT4ge1xuICAgICAgY2xlYXJJbnRlcnZhbChpbnRlcnZhbCk7XG4gICAgICBjb25zb2xlLmxvZygnXFxuXFxu8J+RiyBFeGl0aW5nIHJlYWwtdGltZSBzdGF0dXMuLi4nKTtcbiAgICAgIHByb2Nlc3MuZXhpdCgwKTtcbiAgICB9KTtcbiAgfSBlbHNlIHtcbiAgICAvLyBTaW5nbGUgc3RhdHVzIGNoZWNrXG4gICAgY29uc3Qgc3RhdHVzID0gYXdhaXQgZ2V0VHJhbnNsYXRpb25TdGF0dXMoKTtcblxuICAgIGlmICghc3RhdHVzKSB7XG4gICAgICBjb25zb2xlLmxvZygnTm8gYmFja2dyb3VuZCB0cmFuc2xhdGlvbiBpcyBjdXJyZW50bHkgcnVubmluZy4nKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBkaXNwbGF5U3RhdHVzKHN0YXR1cyk7XG4gIH1cbn1cblxuLy8gU3RvcCBjb21tYW5kIC0gc3RvcCBiYWNrZ3JvdW5kIHRyYW5zbGF0aW9uXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gc3RvcENvbW1hbmQoKTogUHJvbWlzZTx2b2lkPiB7XG4gIGF3YWl0IHN0b3BCYWNrZ3JvdW5kVHJhbnNsYXRpb24oKTtcbn1cbiIKICBdLAogICJtYXBwaW5ncyI6ICI7Ozs7Ozs7O0FBQ0E7QUFDQTtBQUNBO0FBQ0E7OztBQ0pBO0FBQ0E7QUFDQTtBQUNBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFZQSxlQUFzQixXQUFXLEdBQWtCO0FBQUEsRUFDakQsTUFBTSxhQUFhLEtBQUssUUFBUSxhQUFhO0FBQUEsRUFFN0MsSUFBSTtBQUFBLElBQ0YsTUFBTSxHQUFHLE9BQU8sVUFBVTtBQUFBLElBQzFCLFFBQVEsSUFBSSxvQ0FBb0M7QUFBQSxJQUNoRCxNQUFNO0FBQUEsSUFDTixNQUFNLGdCQUF3QjtBQUFBLE1BQzVCLFVBQVU7QUFBQSxNQUNWLFFBQVE7QUFBQSxRQUNOLFFBQVE7QUFBQSxR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RjtBQUFBLElBRUEsY0FBYyxNQUFNO0FBQUE7QUFBQTtBQUt4QixlQUFzQixXQUFXLEdBQWtCO0FBQUEsRUFDakQsTUFBTSwwQkFBMEI7QUFBQTs7O0FEdlZsQyxJQUFNLGNBQWEsY0FBYyxZQUFZLEdBQUc7QUFDaEQsSUFBTSxhQUFZLFFBQVEsV0FBVTtBQUNwQyxJQUFNLGtCQUFrQixLQUFLLFlBQVcsb0JBQW9CO0FBQzVELElBQU0sY0FBYyxLQUFLLE1BQU0sYUFBYSxpQkFBaUIsTUFBTSxDQUFDO0FBRXBFLElBQU0sVUFBVSxJQUFJO0FBRXBCLFFBQVEsS0FBSyxRQUFRLEVBQUUsWUFBWSw2QkFBNkIsRUFBRSxRQUFRLFlBQVksT0FBTztBQUc3RixRQUFRLFFBQVEsTUFBTSxFQUFFLFlBQVksaUNBQWlDLEVBQUUsT0FBTyxXQUFXO0FBR3pGLFFBQ0csUUFBUSxXQUFXLEVBQ25CLFlBQVksd0NBQXdDLEVBQ3BELE9BQU8sV0FBVyw2Q0FBNkMsRUFDL0QsT0FBTyx5QkFBeUIsNENBQTRDLEVBQzVFLE9BQU8sbUJBQW1CLHlDQUF5QyxFQUNuRSxPQUFPLGdCQUFnQixtQ0FBbUMsRUFDMUQsT0FBTyxPQUFPLFlBQVk7QUFBQSxFQUN6QixJQUFJLFFBQVEsWUFBWTtBQUFBLElBQ3RCLE1BQU0sT0FBTyxDQUFDO0FBQUEsSUFDZCxJQUFJLFFBQVE7QUFBQSxNQUFPLEtBQUssS0FBSyxTQUFTO0FBQUEsSUFDdEMsSUFBSSxRQUFRO0FBQUEsTUFBVSxLQUFLLEtBQUssY0FBYyxRQUFRLFFBQVE7QUFBQSxJQUM5RCxJQUFJLFFBQVE7QUFBQSxNQUFPLEtBQUssS0FBSyxXQUFXLFFBQVEsS0FBSztBQUFBLElBQ3JELE1BQU0sMkJBQTJCLElBQUk7QUFBQSxFQUN2QyxFQUFPO0FBQUEsSUFDTCxNQUFNLGlCQUFpQixPQUFPO0FBQUE7QUFBQSxDQUVqQztBQUdILFFBQ0csUUFBUSxlQUFlLEVBQ3ZCLFlBQVksc0VBQXNFLEVBQ2xGLE9BQU8sZ0JBQWdCO0FBRTFCLFFBQ0csUUFBUSxrQkFBa0IsRUFDMUIsWUFBWSx5RUFBeUUsRUFDckYsT0FBTyxtQkFBbUI7QUFFN0IsUUFBUSxRQUFRLE1BQU0sRUFBRSxZQUFZLDZCQUE2QixFQUFFLE9BQU8saUJBQWlCO0FBRzNGLFFBQ0csUUFBUSxPQUFPLEVBQ2YsWUFBWSxpRUFBaUUsRUFDN0UsT0FBTyxZQUFZO0FBR3RCLFFBQ0csUUFBUSxRQUFRLEVBQ2hCLFlBQVksOENBQThDLEVBQzFELE9BQU8sVUFBVSwrQkFBK0IsRUFDaEQsT0FBTyxhQUFhO0FBR3ZCLFFBQVEsUUFBUSxNQUFNLEVBQUUsWUFBWSx1Q0FBdUMsRUFBRSxPQUFPLFdBQVc7QUFHL0YsUUFBUSxNQUFNOyIsCiAgImRlYnVnSWQiOiAiRTY0OUVBRkUxRDU1MzkwNTY0NzU2RTIxNjQ3NTZFMjEiLAogICJuYW1lcyI6IFtdCn0=