gitlab-ci-local
Version:
Tired of pushing to test your .gitlab-ci.yml?
391 lines • 59.2 kB
JavaScript
import "./global.js";
import { RE2JS } from "re2js";
import chalk from "chalk";
import { Job } from "./job.js";
import fs from "fs-extra";
import checksum from "checksum";
import base64url from "base64url";
import execa from "execa";
import assert from "assert";
import { GitData } from "./git-data.js";
import globby from "globby";
import micromatch from "micromatch";
import path from "path";
export class Utils {
static bashMulti(scripts, cwd = process.cwd()) {
return execa(scripts.join(" && \\"), { shell: "bash", cwd });
}
static bash(shellScript, cwd = process.cwd()) {
return execa(shellScript, { shell: "bash", cwd });
}
static spawn(cmdArgs, cwd = process.cwd()) {
return execa(cmdArgs[0], cmdArgs.slice(1), { cwd });
}
static syncSpawn(cmdArgs, cwd = process.cwd()) {
return execa.sync(cmdArgs[0], cmdArgs.slice(1), { cwd });
}
static fsUrl(url) {
return url.replace(/^https:\/\//g, "").replace(/^http:\/\//g, "");
}
static safeDockerString(jobName) {
return jobName.replace(/[^\w-]+/g, (match) => {
return base64url.encode(match);
});
}
static safeBashString(s) {
return `'${s.replace(/'/g, "'\"'\"'")}'`; // replaces `'` with `'"'"'`
}
static forEachRealJob(gitlabData, callback) {
for (const [jobName, jobData] of Object.entries(gitlabData)) {
if (Job.illegalJobNames.has(jobName) || jobName[0].startsWith(".")) {
continue;
}
callback(jobName, jobData);
}
}
static getJobNamesFromPreviousStages(jobs, stages, currentJob) {
const jobNames = [];
const currentStageIndex = stages.indexOf(currentJob.stage);
jobs.forEach(job => {
const stageIndex = stages.indexOf(job.stage);
if (stageIndex < currentStageIndex) {
jobNames.push(job.name);
}
});
return jobNames;
}
static async getCoveragePercent(cwd, stateDir, coverageRegex, jobName) {
const content = await fs.readFile(`${cwd}/${stateDir}/output/${jobName}.log`, "utf8");
const regex = RE2JS.compile(coverageRegex
.replace(/^\//, "")
.replace(/\/$/, ""), RE2JS.MULTILINE);
const matches = Array.from(content.matchAllRE2JS(regex));
if (matches.length === 0)
return "0";
const lastMatch = matches[matches.length - 1];
const digits = /\d+(?:\.\d+)?/.exec(lastMatch[1] ?? lastMatch[0]);
if (!digits)
return "0";
return digits[0] ?? "0";
}
static printJobNames(stream, job, i, arr) {
if (i === arr.length - 1) {
stream(chalk `{blueBright ${job.name}}`);
}
else {
stream(chalk `{blueBright ${job.name}}, `);
}
}
static expandTextWith(text, expandWith) {
if (typeof text !== "string") {
return text;
}
return text.replace(/(\$\$)|\$\{([a-zA-Z_]\w*)}|\$([a-zA-Z_]\w*)/g, // https://regexr.com/7s4ka
(_match, escape, var1, var2) => {
if (typeof escape !== "undefined") {
return expandWith.unescape;
}
else {
const name = var1 || var2;
assert(name, "unexpected unset capture group");
return `${expandWith.variable(name)}`;
}
});
}
static expandText(text, envs) {
return this.expandTextWith(text, {
unescape: "$",
variable: (name) => envs[name] ?? "",
});
}
static expandVariables(variables) {
const _variables = { ...variables }; // copy by value to prevent mutating the original input
let expandedAnyVariables, i = 0;
do {
assert(i < 100, "Recursive variable expansion reached 100 iterations");
expandedAnyVariables = false;
for (const [k, v] of Object.entries(_variables)) {
const envsWithoutSelf = { ..._variables };
delete envsWithoutSelf[k];
// If the $$'s are converted to single $'s now, then the next
// iteration, they might be interpreted as _variables, even
// though they were *explicitly* escaped. To work around this,
// leave the '$$'s as the same value, then only unescape them at
// the very end.
_variables[k] = Utils.expandTextWith(v, {
unescape: "$$",
variable: (name) => envsWithoutSelf[name] ?? "",
});
expandedAnyVariables ||= _variables[k] !== v;
}
i++;
} while (expandedAnyVariables);
return _variables;
}
static unscape$$Variables(variables) {
for (const [k, v] of Object.entries(variables)) {
variables[k] = Utils.expandText(v, {});
}
return variables;
}
static findEnvMatchedVariables(variables, fileVariablesDir, environment) {
const envMatchedVariables = {};
for (const [k, v] of Object.entries(variables)) {
for (const entry of v.environments) {
if (environment?.name.match(entry.regexp) || entry.regexp.source === ".*") {
if (fileVariablesDir != null && v.type === "file" && !entry.fileSource) {
envMatchedVariables[k] = `${fileVariablesDir}/${k}`;
fs.mkdirpSync(`${fileVariablesDir}`);
fs.writeFileSync(`${fileVariablesDir}/${k}`, entry.content);
}
else if (fileVariablesDir != null && v.type === "file" && entry.fileSource) {
envMatchedVariables[k] = `${fileVariablesDir}/${k}`;
fs.mkdirpSync(`${fileVariablesDir}`);
fs.copyFileSync(entry.fileSource, `${fileVariablesDir}/${k}`);
}
else {
envMatchedVariables[k] = entry.content;
}
break;
}
}
}
return envMatchedVariables;
}
static getRulesResult(opt, gitData, jobWhen = "on_success", jobAllowFailure = false) {
let when = "never";
const { evaluateRuleChanges } = opt.argv;
// optional manual jobs allowFailure defaults to true https://docs.gitlab.com/ee/ci/jobs/job_control.html#types-of-manual-jobs
let allowFailure = jobWhen === "manual" ? true : jobAllowFailure;
let ruleVariable;
for (const rule of opt.rules) {
if (!Utils.evaluateRuleIf(rule.if, opt.variables))
continue;
if (!Utils.evaluateRuleExist(opt.cwd, rule.exists))
continue;
if (evaluateRuleChanges && !Utils.evaluateRuleChanges(gitData.branches.default, rule.changes, opt.cwd))
continue;
when = rule.when ? rule.when : jobWhen;
allowFailure = rule.allow_failure ?? allowFailure;
ruleVariable = rule.variables;
break; // Early return, will not evaluate the remaining rules
}
return { when, allowFailure, variables: ruleVariable };
}
static evaluateRuleIf(ruleIf, envs) {
if (ruleIf === undefined)
return true;
let evalStr = ruleIf;
const flagsToBinary = (flags) => {
let binary = 0;
if (flags.includes("i")) {
binary |= RE2JS.CASE_INSENSITIVE;
}
if (flags.includes("s")) {
binary |= RE2JS.DOTALL;
}
if (flags.includes("m")) {
binary |= RE2JS.MULTILINE;
}
return binary;
};
// Expand all variables
evalStr = this.expandTextWith(evalStr, {
unescape: JSON.stringify("$"),
variable: (name) => JSON.stringify(envs[name] ?? null).replaceAll("\\\\", "\\"),
});
const expandedEvalStr = evalStr;
// Scenario when RHS is a <regex>
// https://regexr.com/85sjo
const pattern1 = /\s*(?<operator>(?:=~)|(?:!~))\s*\/(?<rhs>.*?)\/(?<flags>[igmsuy]*)(\s|$|\))/g;
evalStr = evalStr.replace(pattern1, (_, operator, rhs, flags, remainingTokens) => {
let _operator;
switch (operator) {
case "=~":
_operator = "!=";
break;
case "!~":
_operator = "==";
break;
default:
throw operator;
}
const _rhs = JSON.stringify(rhs); // JSON.stringify for escaping `"`
const containsNonEscapedSlash = /(?<!\\)\//.test(_rhs);
const assertMsg = [
"Error attempting to evaluate the following rules:",
" rules:",
` - if: '${expandedEvalStr}'`,
"as rhs contains unescaped quote",
];
assert(!containsNonEscapedSlash, assertMsg.join("\n"));
const flagsBinary = flagsToBinary(flags);
return `.matchRE2JS(RE2JS.compile(${_rhs}, ${flagsBinary})) ${_operator} null${remainingTokens}`;
});
// Scenario when RHS is surrounded by single/double-quotes
// https://regexr.com/85t0g
const pattern2 = /\s*(?<operator>=~|!~)\s*(["'])(?<rhs>(?:\\.|[^\\])*?)\2/g;
evalStr = evalStr.replace(pattern2, (_, operator, __, rhs) => {
let _operator;
switch (operator) {
case "=~":
_operator = "!=";
break;
case "!~":
_operator = "==";
break;
default:
throw operator;
}
const assertMsg = [
"RHS (${rhs}) must be a regex pattern. Do not rely on this behavior!",
"Refer to https://docs.gitlab.com/ee/ci/jobs/job_rules.html#unexpected-behavior-from-regular-expression-matching-with- for more info...",
];
assert((/\/(.*)\/(\w*)/.test(rhs)), assertMsg.join("\n"));
const regex = /\/(?<pattern>.*)\/(?<flags>[igmsuy]*)/;
const _rhs = rhs.replace(regex, (_, pattern, flags) => {
const flagsBinary = flagsToBinary(flags);
return `RE2JS.compile("${pattern}", ${flagsBinary})`;
});
return `.matchRE2JS(${_rhs}) ${_operator} null`;
});
evalStr = evalStr.replace(/null.matchRE2JS\(.+?\)\s*!=\s*null/g, "false");
evalStr = evalStr.replace(/null.matchRE2JS\(.+?\)\s*==\s*null/g, "true");
evalStr = evalStr.trim();
let res;
try {
global.RE2JS = RE2JS; // Assign RE2JS to the global object
res = (0, eval)(evalStr); // https://esbuild.github.io/content-types/#direct-eval
delete global.RE2JS; // Cleanup
}
catch {
const assertMsg = [
"Error attempting to evaluate the following rules:",
" rules:",
` - if: '${expandedEvalStr}'`,
"as",
"```javascript",
`${evalStr}`,
"```",
];
assert(false, assertMsg.join("\n"));
}
return Boolean(res);
}
static evaluateRuleExist(cwd, ruleExists) {
if (ruleExists === undefined)
return true;
// Normalize rules:exists:paths to rules:exists
if (!Array.isArray(ruleExists))
ruleExists = ruleExists.paths;
for (const pattern of ruleExists) {
if (pattern == "") {
continue;
}
if (globby.sync(pattern, { dot: true, cwd }).length > 0) {
return true;
}
}
return false;
}
static evaluateRuleChanges(defaultBranch, ruleChanges, cwd) {
if (ruleChanges === undefined)
return true;
// Normalize rules:changes:paths to rules:changes
if (!Array.isArray(ruleChanges))
ruleChanges = ruleChanges.paths;
// NOTE: https://docs.gitlab.com/ee/ci/yaml/#ruleschanges
// Glob patterns are interpreted with Ruby's [File.fnmatch](https://docs.ruby-lang.org/en/master/File.html#method-c-fnmatch)
// with the flags File::FNM_PATHNAME | File::FNM_DOTMATCH | File::FNM_EXTGLOB.
return micromatch.some(GitData.changedFiles(`origin/${defaultBranch}`, cwd), ruleChanges, {
nonegate: true,
noextglob: true,
posix: false,
dot: true,
});
}
static isSubpath(lhs, rhs, cwd = process.cwd()) {
let absLhs = "";
if (path.isAbsolute(lhs)) {
absLhs = lhs;
}
else {
absLhs = path.resolve(cwd, lhs);
}
let absRhs = "";
if (path.isAbsolute(rhs)) {
absRhs = rhs;
}
else {
absRhs = path.resolve(cwd, rhs);
}
const relative = path.relative(absRhs, absLhs);
return !relative.startsWith("..");
}
static async rsyncTrackedFiles(cwd, stateDir, target) {
const time = process.hrtime();
await fs.mkdirp(`${cwd}/${stateDir}/builds/${target}`);
await Utils.bash(`rsync -a --delete-excluded --delete --exclude-from=<(git ls-files -o --directory | awk '{print "/"$0}') --exclude ${stateDir}/ ./ ${stateDir}/builds/${target}/`, cwd);
return { hrdeltatime: process.hrtime(time) };
}
static async checksumFiles(cwd, files) {
const promises = [];
files.forEach((file) => {
promises.push(new Promise((resolve, reject) => {
if (!fs.pathExistsSync(file))
resolve(path.relative(cwd, file)); // must use relative path here, so that checksum can be deterministic when running the unit tests
checksum.file(file, (err, hash) => {
if (err) {
return reject(err);
}
resolve(hash);
});
}));
});
const result = await Promise.all(promises);
return checksum(result.join(""));
}
static isObject(v) {
return Object.getPrototypeOf(v) === Object.prototype;
}
static switchStatementExhaustiveCheck(param) {
// https://dev.to/babak/exhaustive-type-checking-with-typescript-4l3f
throw new Error(`Unhandled case ${param}`);
}
static async getTrackedFiles(cwd) {
const lsFilesRes = await Utils.bash("git ls-files --deduplicate", cwd);
if (lsFilesRes.exitCode != 0) {
throw new Error(`Failed to list tracked files in ${cwd}: ${lsFilesRes.stderr}`);
}
return lsFilesRes.stdout.split("\n");
}
static getAxiosProxyConfig() {
const proxyEnv = process.env.HTTPS_PROXY || process.env.HTTP_PROXY;
if (proxyEnv) {
const proxyUrl = new URL(proxyEnv);
return {
proxy: {
host: proxyUrl.hostname,
port: proxyUrl.port ? parseInt(proxyUrl.port, 10) : 8080,
protocol: proxyUrl.protocol.replace(":", ""),
},
};
}
return {};
}
static normalizeVariables(variable) {
if (variable === null) {
return ""; // variable's values are nullable
}
else if (Utils.isObject(variable)) {
if (variable["expand"] === false) {
return String(variable["value"]).replaceAll("$", () => "$$");
}
return String(variable["value"]);
}
else {
return String(variable);
}
}
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidXRpbHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJ1dGlscy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLGFBQWEsQ0FBQztBQUNyQixPQUFPLEVBQUMsS0FBSyxFQUFDLE1BQU0sT0FBTyxDQUFDO0FBQzVCLE9BQU8sS0FBSyxNQUFNLE9BQU8sQ0FBQztBQUMxQixPQUFPLEVBQUMsR0FBRyxFQUFVLE1BQU0sVUFBVSxDQUFDO0FBQ3RDLE9BQU8sRUFBRSxNQUFNLFVBQVUsQ0FBQztBQUMxQixPQUFPLFFBQVEsTUFBTSxVQUFVLENBQUM7QUFDaEMsT0FBTyxTQUFTLE1BQU0sV0FBVyxDQUFDO0FBQ2xDLE9BQU8sS0FBSyxNQUFNLE9BQU8sQ0FBQztBQUMxQixPQUFPLE1BQU0sTUFBTSxRQUFRLENBQUM7QUFFNUIsT0FBTyxFQUFDLE9BQU8sRUFBQyxNQUFNLGVBQWUsQ0FBQztBQUN0QyxPQUFPLE1BQU0sTUFBTSxRQUFRLENBQUM7QUFDNUIsT0FBTyxVQUFVLE1BQU0sWUFBWSxDQUFDO0FBRXBDLE9BQU8sSUFBSSxNQUFNLE1BQU0sQ0FBQztBQWV4QixNQUFNLE9BQU8sS0FBSztJQUNkLE1BQU0sQ0FBQyxTQUFTLENBQUUsT0FBaUIsRUFBRSxHQUFHLEdBQUcsT0FBTyxDQUFDLEdBQUcsRUFBRTtRQUNwRCxPQUFPLEtBQUssQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxFQUFFLEVBQUMsS0FBSyxFQUFFLE1BQU0sRUFBRSxHQUFHLEVBQUMsQ0FBQyxDQUFDO0lBQy9ELENBQUM7SUFFRCxNQUFNLENBQUMsSUFBSSxDQUFFLFdBQW1CLEVBQUUsR0FBRyxHQUFHLE9BQU8sQ0FBQyxHQUFHLEVBQUU7UUFDakQsT0FBTyxLQUFLLENBQUMsV0FBVyxFQUFFLEVBQUMsS0FBSyxFQUFFLE1BQU0sRUFBRSxHQUFHLEVBQUMsQ0FBQyxDQUFDO0lBQ3BELENBQUM7SUFFRCxNQUFNLENBQUMsS0FBSyxDQUFFLE9BQWlCLEVB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UUFBUSxDQUFDLFFBQVEsQ0FBQyxJQUFJLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUk7b0JBQ3hELFFBQVEsRUFBRSxRQUFRLENBQUMsUUFBUSxDQUFDLE9BQU8sQ0FBQyxHQUFHLEVBQUUsRUFBRSxDQUFDO2lCQUMvQzthQUNKLENBQUM7UUFDTixDQUFDO1FBQ0QsT0FBTyxFQUFFLENBQUM7SUFDZCxDQUFDO0lBRUQsTUFBTSxDQUFDLGtCQUFrQixDQUFFLFFBQWE7UUFDcEMsSUFBSSxRQUFRLEtBQUssSUFBSSxFQUFFLENBQUM7WUFDcEIsT0FBTyxFQUFFLENBQUMsQ0FBQyxpQ0FBaUM7UUFDaEQsQ0FBQzthQUFNLElBQUksS0FBSyxDQUFDLFFBQVEsQ0FBQyxRQUFRLENBQUMsRUFBRSxDQUFDO1lBQ2xDLElBQUksUUFBUSxDQUFDLFFBQVEsQ0FBQyxLQUFLLEtBQUssRUFBRSxDQUFDO2dCQUMvQixPQUFPLE1BQU0sQ0FBQyxRQUFRLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxVQUFVLENBQUMsR0FBRyxFQUFFLEdBQUcsRUFBRSxDQUFDLElBQUksQ0FBQyxDQUFDO1lBQ2pFLENBQUM7WUFDRCxPQUFPLE1BQU0sQ0FBQyxRQUFRLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQztRQUNyQyxDQUFDO2FBQU0sQ0FBQztZQUNKLE9BQU8sTUFBTSxDQUFDLFFBQVEsQ0FBQyxDQUFDO1FBQzVCLENBQUM7SUFDTCxDQUFDO0NBQ0oiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgXCIuL2dsb2JhbC5qc1wiO1xuaW1wb3J0IHtSRTJKU30gZnJvbSBcInJlMmpzXCI7XG5pbXBvcnQgY2hhbGsgZnJvbSBcImNoYWxrXCI7XG5pbXBvcnQge0pvYiwgSm9iUnVsZX0gZnJvbSBcIi4vam9iLmpzXCI7XG5pbXBvcnQgZnMgZnJvbSBcImZzLWV4dHJhXCI7XG5pbXBvcnQgY2hlY2tzdW0gZnJvbSBcImNoZWNrc3VtXCI7XG5pbXBvcnQgYmFzZTY0dXJsIGZyb20gXCJiYXNlNjR1cmxcIjtcbmltcG9ydCBleGVjYSBmcm9tIFwiZXhlY2FcIjtcbmltcG9ydCBhc3NlcnQgZnJvbSBcImFzc2VydFwiO1xuaW1wb3J0IHtDSUNEVmFyaWFibGV9IGZyb20gXCIuL3ZhcmlhYmxlcy1mcm9tLWZpbGVzLmpzXCI7XG5pbXBvcnQge0dpdERhdGF9IGZyb20gXCIuL2dpdC1kYXRhLmpzXCI7XG5pbXBvcnQgZ2xvYmJ5IGZyb20gXCJnbG9iYnlcIjtcbmltcG9ydCBtaWNyb21hdGNoIGZyb20gXCJtaWNyb21hdGNoXCI7XG5pbXBvcnQge0F4aW9zUmVxdWVzdENvbmZpZ30gZnJvbSBcImF4aW9zXCI7XG5pbXBvcnQgcGF0aCBmcm9tIFwicGF0aFwiO1xuaW1wb3J0IHtBcmd2fSBmcm9tIFwiLi9hcmd2LmpzXCI7XG5cbnR5cGUgUnVsZVJlc3VsdE9wdCA9IHtcbiAgICBhcmd2OiBBcmd2O1xuICAgIGN3ZDogc3RyaW5nO1xuICAgIHJ1bGVzOiBKb2JSdWxlW107XG4gICAgdmFyaWFibGVzOiB7W2tleTogc3RyaW5nXTogc3RyaW5nfTtcbn07XG5cbnR5cGUgRXhwYW5kV2l0aCA9IHtcbiAgICB1bmVzY2FwZTogc3RyaW5nO1xuICAgIHZhcmlhYmxlOiAobmFtZTogc3RyaW5nKSA9PiBzdHJpbmc7XG59O1xuXG5leHBvcnQgY2xhc3MgVXRpbHMge1xuICAgIHN0YXRpYyBiYXNoTXVsdGkgKHNjcmlwdHM6IHN0cmluZ1tdLCBjd2QgPSBwcm9jZXNzLmN3ZCgpKTogUHJvbWlzZTx7c3Rkb3V0OiBzdHJpbmc7IHN0ZGVycjogc3RyaW5nOyBleGl0Q29kZTogbnVtYmVyfT4ge1xuICAgICAgICByZXR1cm4gZXhlY2Eoc2NyaXB0cy5qb2luKFwiICYmIFxcXFxcIiksIHtzaGVsbDogXCJiYXNoXCIsIGN3ZH0pO1xuICAgIH1cblxuICAgIHN0YXRpYyBiYXNoIChzaGVsbFNjcmlwdDogc3RyaW5nLCBjd2QgPSBwcm9jZXNzLmN3ZCgpKTogUHJvbWlzZTx7c3Rkb3V0OiBzdHJpbmc7IHN0ZGVycjogc3RyaW5nOyBleGl0Q29kZTogbnVtYmVyfT4ge1xuICAgICAgICByZXR1cm4gZXhlY2Eoc2hlbGxTY3JpcHQsIHtzaGVsbDogXCJiYXNoXCIsIGN3ZH0pO1xuICAgIH1cblxuICAgIHN0YXRpYyBzcGF3biAoY21kQXJnczogc3RyaW5nW10sIGN3ZCA9IHByb2Nlc3MuY3dkKCkpOiBQcm9taXNlPHtzdGRvdXQ6IHN0cmluZzsgc3RkZXJyOiBzdHJpbmd9PiB7XG4gICAgICAgIHJldHVybiBleGVjYShjbWRBcmdzWzBdLCBjbWRBcmdzLnNsaWNlKDEpLCB7Y3dkfSk7XG4gICAgfVxuXG4gICAgc3RhdGljIHN5bmNTcGF3biAoY21kQXJnczogc3RyaW5nW10sIGN3ZCA9IHByb2Nlc3MuY3dkKCkpOiB7c3Rkb3V0OiBzdHJpbmc7IHN0ZGVycjogc3RyaW5nfSB7XG4gICAgICAgIHJldHVybiBleGVjYS5zeW5jKGNtZEFyZ3NbMF0sIGNtZEFyZ3Muc2xpY2UoMSksIHtjd2R9KTtcbiAgICB9XG5cbiAgICBzdGF0aWMgZnNVcmwgKHVybDogc3RyaW5nKTogc3RyaW5nIHtcbiAgICAgICAgcmV0dXJuIHVybC5yZXBsYWNlKC9eaHR0cHM6XFwvXFwvL2csIFwiXCIpLnJlcGxhY2UoL15odHRwOlxcL1xcLy9nLCBcIlwiKTtcbiAgICB9XG5cbiAgICBzdGF0aWMgc2FmZURvY2tlclN0cmluZyAoam9iTmFtZTogc3RyaW5nKSB7XG4gICAgICAgIHJldHVybiBqb2JOYW1lLnJlcGxhY2UoL1teXFx3LV0rL2csIChtYXRjaCkgPT4ge1xuICAgICAgICAgICAgcmV0dXJuIGJhc2U2NHVybC5lbmNvZGUobWF0Y2gpO1xuICAgICAgICB9KTtcbiAgICB9XG5cbiAgICBzdGF0aWMgc2FmZUJhc2hTdHJpbmcgKHM6IHN0cmluZykge1xuICAgICAgICByZXR1cm4gYCcke3MucmVwbGFjZSgvJy9nLCBcIidcXFwiJ1xcXCInXCIpfSdgOyAvLyByZXBsYWNlcyBgJ2Agd2l0aCBgJ1wiJ1wiJ2BcbiAgICB9XG5cbiAgICBzdGF0aWMgZm9yRWFjaFJlYWxKb2IgKGdpdGxhYkRhdGE6IGFueSwgY2FsbGJhY2s6IChqb2JOYW1lOiBzdHJpbmcsIGpvYkRhdGE6IGFueSkgPT4gdm9pZCkge1xuICAgICAgICBmb3IgKGNvbnN0IFtqb2JOYW1lLCBqb2JEYXRhXSBvZiBPYmplY3QuZW50cmllczxhbnk+KGdpdGxhYkRhdGEpKSB7XG4gICAgICAgICAgICBpZiAoSm9iLmlsbGVnYWxKb2JOYW1lcy5oYXMoam9iTmFtZSkgfHwgam9iTmFtZVswXS5zdGFydHNXaXRoKFwiLlwiKSkge1xuICAgICAgICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgY2FsbGJhY2soam9iTmFtZSwgam9iRGF0YSk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBzdGF0aWMgZ2V0Sm9iTmFtZXNGcm9tUHJldmlvdXNTdGFnZXMgKGpvYnM6IFJlYWRvbmx5QXJyYXk8Sm9iPiwgc3RhZ2VzOiByZWFkb25seSBzdHJpbmdbXSwgY3VycmVudEpvYjogSm9iKSB7XG4gICAgICAgIGNvbnN0IGpvYk5hbWVzOiBzdHJpbmdbXSA9IFtdO1xuICAgICAgICBjb25zdCBjdXJyZW50U3RhZ2VJbmRleCA9IHN0YWdlcy5pbmRleE9mKGN1cnJlbnRKb2Iuc3RhZ2UpO1xuICAgICAgICBqb2JzLmZvckVhY2goam9iID0+IHtcbiAgICAgICAgICAgIGNvbnN0IHN0YWdlSW5kZXggPSBzdGFnZXMuaW5kZXhPZihqb2Iuc3RhZ2UpO1xuICAgICAgICAgICAgaWYgKHN0YWdlSW5kZXggPCBjdXJyZW50U3RhZ2VJbmRleCkge1xuICAgICAgICAgICAgICAgIGpvYk5hbWVzLnB1c2goam9iLm5hbWUpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICAgICAgcmV0dXJuIGpvYk5hbWVzO1xuICAgIH1cblxuICAgIHN0YXRpYyBhc3luYyBnZXRDb3ZlcmFnZVBlcmNlbnQgKGN3ZDogc3RyaW5nLCBzdGF0ZURpcjogc3RyaW5nLCBjb3ZlcmFnZVJlZ2V4OiBzdHJpbmcsIGpvYk5hbWU6IHN0cmluZykge1xuICAgICAgICBjb25zdCBjb250ZW50ID0gYXdhaXQgZnMucmVhZEZpbGUoYCR7Y3dkfS8ke3N0YXRlRGlyfS9vdXRwdXQvJHtqb2JOYW1lfS5sb2dgLCBcInV0ZjhcIik7XG5cbiAgICAgICAgY29uc3QgcmVnZXggPSBSRTJKUy5jb21waWxlKFxuICAgICAgICAgICAgY292ZXJhZ2VSZWdleFxuICAgICAgICAgICAgICAgIC5yZXBsYWNlKC9eXFwvLywgXCJcIilcbiAgICAgICAgICAgICAgICAucmVwbGFjZSgvXFwvJC8sIFwiXCIpLFxuICAgICAgICAgICAgUkUySlMuTVVMVElMSU5FLFxuICAgICAgICApO1xuICAgICAgICBjb25zdCBtYXRjaGVzID0gQXJyYXkuZnJvbShjb250ZW50Lm1hdGNoQWxsUkUySlMocmVnZXgpKTtcbiAgICAgICAgaWYgKG1hdGNoZXMubGVuZ3RoID09PSAwKSByZXR1cm4gXCIwXCI7XG5cbiAgICAgICAgY29uc3QgbGFzdE1hdGNoID0gbWF0Y2hlc1ttYXRjaGVzLmxlbmd0aCAtIDFdO1xuICAgICAgICBjb25zdCBkaWdpdHMgPSAvXFxkKyg/OlxcLlxcZCspPy8uZXhlYyhsYXN0TWF0Y2hbMV0gPz8gbGFzdE1hdGNoWzBdKTtcbiAgICAgICAgaWYgKCFkaWdpdHMpIHJldHVybiBcIjBcIjtcbiAgICAgICAgcmV0dXJuIGRpZ2l0c1swXSA/PyBcIjBcIjtcbiAgICB9XG5cbiAgICBzdGF0aWMgcHJpbnRKb2JOYW1lcyAoc3RyZWFtOiAodHh0OiBzdHJpbmcpID0+IHZvaWQsIGpvYjoge25hbWU6IHN0cmluZ30sIGk6IG51bWJlciwgYXJyOiB7bmFtZTogc3RyaW5nfVtdKSB7XG4gICAgICAgIGlmIChpID09PSBhcnIubGVuZ3RoIC0gMSkge1xuICAgICAgICAgICAgc3RyZWFtKGNoYWxrYHtibHVlQnJpZ2h0ICR7am9iLm5hbWV9fWApO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgc3RyZWFtKGNoYWxrYHtibHVlQnJpZ2h0ICR7am9iLm5hbWV9fSwgYCk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBwcml2YXRlIHN0YXRpYyBleHBhbmRUZXh0V2l0aCAodGV4dDogYW55LCBleHBhbmRXaXRoOiBFeHBhbmRXaXRoKSB7XG4gICAgICAgIGlmICh0eXBlb2YgdGV4dCAhPT0gXCJzdHJpbmdcIikge1xuICAgICAgICAgICAgcmV0dXJuIHRleHQ7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gdGV4dC5yZXBsYWNlKFxuICAgICAgICAgICAgLyhcXCRcXCQpfFxcJFxceyhbYS16QS1aX11cXHcqKX18XFwkKFthLXpBLVpfXVxcdyopL2csIC8vIGh0dHBzOi8vcmVnZXhyLmNvbS83czRrYVxuICAgICAgICAgICAgKF9tYXRjaCwgZXNjYXBlLCB2YXIxLCB2YXIyKSA9PiB7XG4gICAgICAgICAgICAgICAgaWYgKHR5cGVvZiBlc2NhcGUgIT09IFwidW5kZWZpbmVkXCIpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGV4cGFuZFdpdGgudW5lc2NhcGU7XG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgY29uc3QgbmFtZSA9IHZhcjEgfHwgdmFyMjtcbiAgICAgICAgICAgICAgICAgICAgYXNzZXJ0KG5hbWUsIFwidW5leHBlY3RlZCB1bnNldCBjYXB0dXJlIGdyb3VwXCIpO1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gYCR7ZXhwYW5kV2l0aC52YXJpYWJsZShuYW1lKX1gO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0sXG4gICAgICAgICk7XG4gICAgfVxuXG4gICAgc3RhdGljIGV4cGFuZFRleHQgKHRleHQ6IGFueSwgZW52czoge1trZXk6IHN0cmluZ106IHN0cmluZ30pIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuZXhwYW5kVGV4dFdpdGgodGV4dCwge1xuICAgICAgICAgICAgdW5lc2NhcGU6IFwiJFwiLFxuICAgICAgICAgICAgdmFyaWFibGU6IChuYW1lKSA9PiBlbnZzW25hbWVdID8/IFwiXCIsXG4gICAgICAgIH0pO1xuICAgIH1cblxuICAgIHN0YXRpYyBleHBhbmRWYXJpYWJsZXMgKHZhcmlhYmxlczoge1trZXk6IHN0cmluZ106IHN0cmluZ30pIHtcbiAgICAgICAgY29uc3QgX3ZhcmlhYmxlcyA9IHsuLi52YXJpYWJsZXN9OyAvLyBjb3B5IGJ5IHZhbHVlIHRvIHByZXZlbnQgbXV0YXRpbmcgdGhlIG9yaWdpbmFsIGlucHV0XG4gICAgICAgIGxldCBleHBhbmRlZEFueVZhcmlhYmxlcywgaSA9IDA7XG4gICAgICAgIGRvIHtcbiAgICAgICAgICAgIGFzc2VydChpIDwgMTAwLCBcIlJlY3Vyc2l2ZSB2YXJpYWJsZSBleHBhbnNpb24gcmVhY2hlZCAxMDAgaXRlcmF0aW9uc1wiKTtcbiAgICAgICAgICAgIGV4cGFuZGVkQW55VmFyaWFibGVzID0gZmFsc2U7XG4gICAgICAgICAgICBmb3IgKGNvbnN0IFtrLCB2XSBvZiBPYmplY3QuZW50cmllcyhfdmFyaWFibGVzKSkge1xuICAgICAgICAgICAgICAgIGNvbnN0IGVudnNXaXRob3V0U2VsZiA9IHsuLi5fdmFyaWFibGVzfTtcbiAgICAgICAgICAgICAgICBkZWxldGUgZW52c1dpdGhvdXRTZWxmW2tdO1xuICAgICAgICAgICAgICAgIC8vIElmIHRoZSAkJCdzIGFyZSBjb252ZXJ0ZWQgdG8gc2luZ2xlICQncyBub3csIHRoZW4gdGhlIG5leHRcbiAgICAgICAgICAgICAgICAvLyBpdGVyYXRpb24sIHRoZXkgbWlnaHQgYmUgaW50ZXJwcmV0ZWQgYXMgX3ZhcmlhYmxlcywgZXZlblxuICAgICAgICAgICAgICAgIC8vIHRob3VnaCB0aGV5IHdlcmUgKmV4cGxpY2l0bHkqIGVzY2FwZWQuIFRvIHdvcmsgYXJvdW5kIHRoaXMsXG4gICAgICAgICAgICAgICAgLy8gbGVhdmUgdGhlICckJCdzIGFzIHRoZSBzYW1lIHZhbHVlLCB0aGVuIG9ubHkgdW5lc2NhcGUgdGhlbSBhdFxuICAgICAgICAgICAgICAgIC8vIHRoZSB2ZXJ5IGVuZC5cbiAgICAgICAgICAgICAgICBfdmFyaWFibGVzW2tdID0gVXRpbHMuZXhwYW5kVGV4dFdpdGgodiwge1xuICAgICAgICAgICAgICAgICAgICB1bmVzY2FwZTogXCIkJFwiLFxuICAgICAgICAgICAgICAgICAgICB2YXJpYWJsZTogKG5hbWUpID0+IGVudnNXaXRob3V0U2VsZltuYW1lXSA/PyBcIlwiLFxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIGV4cGFuZGVkQW55VmFyaWFibGVzIHx8PSBfdmFyaWFibGVzW2tdICE9PSB2O1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaSsrO1xuICAgICAgICB9IHdoaWxlIChleHBhbmRlZEFueVZhcmlhYmxlcyk7XG5cbiAgICAgICAgcmV0dXJuIF92YXJpYWJsZXM7XG4gICAgfVxuXG4gICAgc3RhdGljIHVuc2NhcGUkJFZhcmlhYmxlcyAodmFyaWFibGVzOiB7W2tleTogc3RyaW5nXTogc3RyaW5nfSkge1xuICAgICAgICBmb3IgKGNvbnN0IFtrLCB2XSBvZiBPYmplY3QuZW50cmllcyh2YXJpYWJsZXMpKSB7XG4gICAgICAgICAgICB2YXJpYWJsZXNba10gPSBVdGlscy5leHBhbmRUZXh0KHYsIHt9KTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiB2YXJpYWJsZXM7XG4gICAgfVxuXG4gICAgc3RhdGljIGZpbmRFbnZNYXRjaGVkVmFyaWFibGVzICh2YXJpYWJsZXM6IHtbbmFtZTogc3RyaW5nXTogQ0lDRFZhcmlhYmxlfSwgZmlsZVZhcmlhYmxlc0Rpcj86IHN0cmluZywgZW52aXJvbm1lbnQ/OiB7bmFtZTogc3RyaW5nfSkge1xuICAgICAgICBjb25zdCBlbnZNYXRjaGVkVmFyaWFibGVzOiB7W2tleTogc3RyaW5nXTogc3RyaW5nfSA9IHt9O1xuICAgICAgICBmb3IgKGNvbnN0IFtrLCB2XSBvZiBPYmplY3QuZW50cmllcyh2YXJpYWJsZXMpKSB7XG4gICAgICAgICAgICBmb3IgKGNvbnN0IGVudHJ5IG9mIHYuZW52aXJvbm1lbnRzKSB7XG4gICAgICAgICAgICAgICAgaWYgKGVudmlyb25tZW50Py5uYW1lLm1hdGNoKGVudHJ5LnJlZ2V4cCkgfHwgZW50cnkucmVnZXhwLnNvdXJjZSA9PT0gXCIuKlwiKSB7XG4gICAgICAgICAgICAgICAgICAgIGlmIChmaWxlVmFyaWFibGVzRGlyICE9IG51bGwgJiYgdi50eXBlID09PSBcImZpbGVcIiAmJiAhZW50cnkuZmlsZVNvdXJjZSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgZW52TWF0Y2hlZFZhcmlhYmxlc1trXSA9IGAke2ZpbGVWYXJpYWJsZXNEaXJ9LyR7a31gO1xuICAgICAgICAgICAgICAgICAgICAgICAgZnMubWtkaXJwU3luYyhgJHtmaWxlVmFyaWFibGVzRGlyfWApO1xuICAgICAgICAgICAgICAgICAgICAgICAgZnMud3JpdGVGaWxlU3luYyhgJHtmaWxlVmFyaWFibGVzRGlyfS8ke2t9YCwgZW50cnkuY29udGVudCk7XG4gICAgICAgICAgICAgICAgICAgIH0gZWxzZSBpZiAoZmlsZVZhcmlhYmxlc0RpciAhPSBudWxsICYmIHYudHlwZSA9PT0gXCJmaWxlXCIgJiYgZW50cnkuZmlsZVNvdXJjZSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgZW52TWF0Y2hlZFZhcmlhYmxlc1trXSA9IGAke2ZpbGVWYXJpYWJsZXNEaXJ9LyR7a31gO1xuICAgICAgICAgICAgICAgICAgICAgICAgZnMubWtkaXJwU3luYyhgJHtmaWxlVmFyaWFibGVzRGlyfWApO1xuICAgICAgICAgICAgICAgICAgICAgICAgZnMuY29weUZpbGVTeW5jKGVudHJ5LmZpbGVTb3VyY2UsIGAke2ZpbGVWYXJpYWJsZXNEaXJ9LyR7a31gKTtcbiAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGVudk1hdGNoZWRWYXJpYWJsZXNba10gPSBlbnRyeS5jb250ZW50O1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gZW52TWF0Y2hlZFZhcmlhYmxlcztcbiAgICB9XG5cbiAgICBzdGF0aWMgZ2V0UnVsZXNSZXN1bHQgKG9wdDogUnVsZVJlc3VsdE9wdCwgZ2l0RGF0YTogR2l0RGF0YSwgam9iV2hlbjogc3RyaW5nID0gXCJvbl9zdWNjZXNzXCIsIGpvYkFsbG93RmFpbHVyZTogYm9vbGVhbiB8IHtleGl0X2NvZGVzOiBudW1iZXIgfCBudW1iZXJbXX0gPSBmYWxzZSk6IHt3aGVuOiBzdHJpbmc7IGFsbG93RmFpbHVyZTogYm9vbGVhbiB8IHtleGl0X2NvZGVzOiBudW1iZXIgfCBudW1iZXJbXX07IHZhcmlhYmxlcz86IHtbbmFtZTogc3RyaW5nXTogc3RyaW5nfX0ge1xuICAgICAgICBsZXQgd2hlbiA9IFwibmV2ZXJcIjtcbiAgICAgICAgY29uc3Qge2V2YWx1YXRlUnVsZUNoYW5nZXN9ID0gb3B0LmFyZ3Y7XG5cbiAgICAgICAgLy8gb3B0aW9uYWwgbWFudWFsIGpvYnMgYWxsb3dGYWlsdXJlIGRlZmF1bHRzIHRvIHRydWUgaHR0cHM6Ly9kb2NzLmdpdGxhYi5jb20vZWUvY2kvam9icy9qb2JfY29udHJvbC5odG1sI3R5cGVzLW9mLW1hbnVhbC1qb2JzXG4gICAgICAgIGxldCBhbGxvd0ZhaWx1cmUgPSBqb2JXaGVuID09PSBcIm1hbnVhbFwiID8gdHJ1ZSA6IGpvYkFsbG93RmFpbHVyZTtcbiAgICAgICAgbGV0IHJ1bGVWYXJpYWJsZToge1tuYW1lOiBzdHJpbmddOiBzdHJpbmd9IHwgdW5kZWZpbmVkO1xuXG4gICAgICAgIGZvciAoY29uc3QgcnVsZSBvZiBvcHQucnVsZXMpIHtcbiAgICAgICAgICAgIGlmICghVXRpbHMuZXZhbHVhdGVSdWxlSWYocnVsZS5pZiwgb3B0LnZhcmlhYmxlcykpIGNvbnRpbnVlO1xuICAgICAgICAgICAgaWYgKCFVdGlscy5ldmFsdWF0ZVJ1bGVFeGlzdChvcHQuY3dkLCBydWxlLmV4aXN0cykpIGNvbnRpbnVlO1xuICAgICAgICAgICAgaWYgKGV2YWx1YXRlUnVsZUNoYW5nZXMgJiYgIVV0aWxzLmV2YWx1YXRlUnVsZUNoYW5nZXMoZ2l0RGF0YS5icmFuY2hlcy5kZWZhdWx0LCBydWxlLmNoYW5nZXMsIG9wdC5jd2QpKSBjb250aW51ZTtcblxuICAgICAgICAgICAgd2hlbiA9IHJ1bGUud2hlbiA/IHJ1bGUud2hlbiA6IGpvYldoZW47XG4gICAgICAgICAgICBhbGxvd0ZhaWx1cmUgPSBydWxlLmFsbG93X2ZhaWx1cmUgPz8gYWxsb3dGYWlsdXJlO1xuICAgICAgICAgICAgcnVsZVZhcmlhYmxlID0gcnVsZS52YXJpYWJsZXM7XG5cbiAgICAgICAgICAgIGJyZWFrOyAvLyBFYXJseSByZXR1cm4sIHdpbGwgbm90IGV2YWx1YXRlIHRoZSByZW1haW5pbmcgcnVsZXNcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiB7d2hlbiwgYWxsb3dGYWlsdXJlLCB2YXJpYWJsZXM6IHJ1bGVWYXJpYWJsZX07XG4gICAgfVxuXG4gICAgc3RhdGljIGV2YWx1YXRlUnVsZUlmIChydWxlSWY6IHN0cmluZyB8IHVuZGVmaW5lZCwgZW52czoge1trZXk6IHN0cmluZ106IHN0cmluZ30pOiBib29sZWFuIHtcbiAgICAgICAgaWYgKHJ1bGVJZiA9PT0gdW5kZWZpbmVkKSByZXR1cm4gdHJ1ZTtcbiAgICAgICAgbGV0IGV2YWxTdHIgPSBydWxlSWY7XG5cbiAgICAgICAgY29uc3QgZmxhZ3NUb0JpbmFyeSA9IChmbGFnczogc3RyaW5nKTogbnVtYmVyID0+IHtcbiAgICAgICAgICAgIGxldCBiaW5hcnkgPSAwO1xuICAgICAgICAgICAgaWYgKGZsYWdzLmluY2x1ZGVzKFwiaVwiKSkge1xuICAgICAgICAgICAgICAgIGJpbmFyeSB8PSBSRTJKUy5DQVNFX0lOU0VOU0lUSVZFO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKGZsYWdzLmluY2x1ZGVzKFwic1wiKSkge1xuICAgICAgICAgICAgICAgIGJpbmFyeSB8PSBSRTJKUy5ET1RBTEw7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAoZmxhZ3MuaW5jbHVkZXMoXCJtXCIpKSB7XG4gICAgICAgICAgICAgICAgYmluYXJ5IHw9IFJFMkpTLk1VTFRJTElORTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiBiaW5hcnk7XG4gICAgICAgIH07XG5cbiAgICAgICAgLy8gRXhwYW5kIGFsbCB2YXJpYWJsZXNcbiAgICAgICAgZXZhbFN0ciA9IHRoaXMuZXhwYW5kVGV4dFdpdGgoZXZhbFN0ciwge1xuICAgICAgICAgICAgdW5lc2NhcGU6IEpTT04uc3RyaW5naWZ5KFwiJFwiKSxcbiAgICAgICAgICAgIHZhcmlhYmxlOiAobmFtZSkgPT4gSlNPTi5zdHJpbmdpZnkoZW52c1tuYW1lXSA/PyBudWxsKS5yZXBsYWNlQWxsKFwiXFxcXFxcXFxcIiwgXCJcXFxcXCIpLFxuICAgICAgICB9KTtcbiAgICAgICAgY29uc3QgZXhwYW5kZWRFdmFsU3RyID0gZXZhbFN0cjtcblxuICAgICAgICAvLyBTY2VuYXJpbyB3aGVuIFJIUyBpcyBhIDxyZWdleD5cbiAgICAgICAgLy8gaHR0cHM6Ly9yZWdleHIuY29tLzg1c2pvXG4gICAgICAgIGNvbnN0IHBhdHRlcm4xID0gL1xccyooPzxvcGVyYXRvcj4oPzo9fil8KD86IX4pKVxccypcXC8oPzxyaHM+Lio/KVxcLyg/PGZsYWdzPltpZ21zdXldKikoXFxzfCR8XFwpKS9nO1xuICAgICAgICBldmFsU3RyID0gZXZhbFN0ci5yZXBsYWNlKHBhdHRlcm4xLCAoXywgb3BlcmF0b3IsIHJocywgZmxhZ3MsIHJlbWFpbmluZ1Rva2VucykgPT4ge1xuICAgICAgICAgICAgbGV0IF9vcGVyYXRvcjtcbiAgICAgICAgICAgIHN3aXRjaCAob3BlcmF0b3IpIHtcbiAgICAgICAgICAgICAgICBjYXNlIFwiPX5cIjpcbiAgICAgICAgICAgICAgICAgICAgX29wZXJhdG9yID0gXCIhPVwiO1xuICAgICAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgICBjYXNlIFwiIX5cIjpcbiAgICAgICAgICAgICAgICAgICAgX29wZXJhdG9yID0gXCI9PVwiO1xuICAgICAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgICBkZWZhdWx0OlxuICAgICAgICAgICAgICAgICAgICB0aHJvdyBvcGVyYXRvcjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGNvbnN0IF9yaHMgPSBKU09OLnN0cmluZ2lmeShyaHMpOyAvLyBKU09OLnN0cmluZ2lmeSBmb3IgZXNjYXBpbmcgYFwiYFxuICAgICAgICAgICAgY29uc3QgY29udGFpbnNOb25Fc2NhcGVkU2xhc2ggPSAvKD88IVxcXFwpXFwvLy50ZXN0KF9yaHMpO1xuICAgICAgICAgICAgY29uc3QgYXNzZXJ0TXNnID0gW1xuICAgICAgICAgICAgICAgIFwiRXJyb3IgYXR0ZW1wdGluZyB0byBldmFsdWF0ZSB0aGUgZm9sbG93aW5nIHJ1bGVzOlwiLFxuICAgICAgICAgICAgICAgIFwiICBydWxlczpcIixcbiAgICAgICAgICAgICAgICBgICAgIC0gaWY6ICcke2V4cGFuZGVkRXZhbFN0cn0nYCxcbiAgICAgICAgICAgICAgICBcImFzIHJocyBjb250YWlucyB1bmVzY2FwZWQgcXVvdGVcIixcbiAgICAgICAgICAgIF07XG4gICAgICAgICAgICBhc3NlcnQoIWNvbnRhaW5zTm9uRXNjYXBlZFNsYXNoLCBhc3NlcnRNc2cuam9pbihcIlxcblwiKSk7XG4gICAgICAgICAgICBjb25zdCBmbGFnc0JpbmFyeSA9IGZsYWdzVG9CaW5hcnkoZmxhZ3MpO1xuICAgICAgICAgICAgcmV0dXJuIGAubWF0Y2hSRTJKUyhSRTJKUy5jb21waWxlKCR7X3Joc30sICR7ZmxhZ3NCaW5hcnl9KSkgJHtfb3BlcmF0b3J9IG51bGwke3JlbWFpbmluZ1Rva2Vuc31gO1xuICAgICAgICB9KTtcblxuICAgICAgICAvLyBTY2VuYXJpbyB3aGVuIFJIUyBpcyBzdXJyb3VuZGVkIGJ5IHNpbmdsZS9kb3VibGUtcXVvdGVzXG4gICAgICAgIC8vIGh0dHBzOi8vcmVnZXhyLmNvbS84NXQwZ1xuICAgICAgICBjb25zdCBwYXR0ZXJuMiA9IC9cXHMqKD88b3BlcmF0b3I+PX58IX4pXFxzKihbXCInXSkoPzxyaHM+KD86XFxcXC58W15cXFxcXSkqPylcXDIvZztcbiAgICAgICAgZXZhbFN0ciA9IGV2YWxTdHIucmVwbGFjZShwYXR0ZXJuMiwgKF8sIG9wZXJhdG9yLCBfXywgcmhzKSA9PiB7XG4gICAgICAgICAgICBsZXQgX29wZXJhdG9yO1x