gitlab-ci-local
Version:
Tired of pushing to test your .gitlab-ci.yml?
344 lines • 53.2 kB
JavaScript
import RE2 from "re2";
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 axios from "axios";
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 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 = new RegExp(coverageRegex.replace(/^\//, "").replace(/\/$/, ""), "gm");
const matches = Array.from(content.matchAll(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))
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;
// 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"));
return `.match(new RE2(${_rhs}, "${flags}")) ${_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) => {
return `new RE2("${pattern}", "${flags}")`;
});
return `.match(${_rhs}) ${_operator} null`;
});
// Convert all null.match functions to false
evalStr = evalStr.replace(/null.match\(.+?\)\s*!=\s*null/g, "false");
evalStr = evalStr.replace(/null.match\(.+?\)\s*==\s*null/g, "false");
evalStr = evalStr.trim();
let res;
try {
global.RE2 = RE2; // Assign RE2 to the global object
res = (0, eval)(evalStr); // https://esbuild.github.io/content-types/#direct-eval
delete global.RE2; // Cleanup
}
catch (err) {
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;
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) {
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}`), ruleChanges, {
nonegate: true,
noextglob: true,
posix: false,
dot: true,
});
}
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 async remoteFileExist(cwd, file, ref, domain, projectPath, protocol, port) {
switch (protocol) {
case "ssh":
case "git":
try {
await Utils.spawn(`git archive --remote=ssh://git@${domain}:${port}/${projectPath}.git ${ref} ${file}`.split(" "), cwd);
return true;
}
catch (e) {
if (!e.stderr.includes(`remote: fatal: pathspec '${file}' did not match any files`))
throw new Error(e);
return false;
}
case "http":
case "https": {
try {
const { status } = await axios.get(`${protocol}://${domain}:${port}/${projectPath}/-/raw/${ref}/${file}`);
return (status === 200);
}
catch (e) {
return false;
}
}
default: {
Utils.switchStatementExhaustiveCheck(protocol);
}
}
}
static switchStatementExhaustiveCheck(param) {
// https://dev.to/babak/exhaustive-type-checking-with-typescript-4l3f
throw new Error(`Unhandled case ${param}`);
}
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidXRpbHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJ1dGlscy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEdBQUcsTUFBTSxLQUFLLENBQUM7QUFDdEIsT0FBTyxLQUFLLE1BQU0sT0FBTyxDQUFDO0FBQzFCLE9BQU8sRUFBQyxHQUFHLEVBQVUsTUFBTSxVQUFVLENBQUM7QUFDdEMsT0FBTyxFQUFFLE1BQU0sVUFBVSxDQUFDO0FBQzFCLE9BQU8sUUFBUSxNQUFNLFVBQVUsQ0FBQztBQUNoQyxPQUFPLFNBQVMsTUFBTSxXQUFXLENBQUM7QUFDbEMsT0FBTyxLQUFLLE1BQU0sT0FBTyxDQUFDO0FBQzFCLE9BQU8sTUFBTSxNQUFNLFFBQVEsQ0FBQztBQUU1QixPQUFPLEVBQUMsT0FBTyxFQUFZLE1BQU0sZUFBZSxDQUFDO0FBQ2pELE9BQU8sTUFBTSxNQUFNLFFBQVEsQ0FBQztBQUM1QixPQUFPLFVBQVUsTUFBTSxZQUFZLENBQUM7QUFDcEMsT0FBTyxLQUFLLE1BQU0sT0FBTyxDQUFDO0FBQzFCLE9BQU8sSUFBSSxNQUFNLE1BQU0sQ0FBQztBQWV4QixNQUFNLE9BQU8sS0FBSztJQUNkLE1BQU0sQ0FBQyxTQUFTLENBQUUsT0FBaUIsRUFBRSxHQUFHLEdBQUcsT0FBTyxDQUFDLEdBQUcsRUFBRTtRQUNwRCxPQUFPLEtBQUssQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxFQUFFLEVBQUMsS0FBSyxFQUFFLE1BQU0sRUFBRSxHQUFHLEVBQUMsQ0FBQyxDQUFDO0lBQy9ELENBQUM7SUFFRCxNQUFNLENBQUMsSUFBSSxDQUFFLFdBQW1CLEVBQUUsR0FBRyxHQUFHLE9BQU8sQ0FBQyxHQUFHLEVBQUU7UUFDakQsT0FBTyxLQUFLLENBQUMsV0FBVyxFQUFFLEVBQUMsS0FBSyxFQUFFLE1BQU0sRUFBRSxHQUFHLEVBQUMsQ0FBQyxDQUFDO0lBQ3BELENBQUM7SUFFRCxNQUFNLENBQUMsS0FBSyxDQUFFLE9BQWlCLEVB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QVEsR0FBRyxJQUFJLElBQUksRUFBRSxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsRUFBRSxHQUFHLENBQUMsQ0FBQztvQkFDeEgsT0FBTyxJQUFJLENBQUM7Z0JBQ2hCLENBQUM7Z0JBQUMsT0FBTyxDQUFNLEVBQUUsQ0FBQztvQkFDZCxJQUFJLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxRQUFRLENBQUMsNEJBQTRCLElBQUksMkJBQTJCLENBQUM7d0JBQUUsTUFBTSxJQUFJLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQztvQkFDeEcsT0FBTyxLQUFLLENBQUM7Z0JBQ2pCLENBQUM7WUFFTCxLQUFLLE1BQU0sQ0FBQztZQUNaLEtBQUssT0FBTyxDQUFDLENBQUMsQ0FBQztnQkFDWCxJQUFJLENBQUM7b0JBQ0QsTUFBTSxFQUFDLE1BQU0sRUFBQyxHQUFHLE1BQU0sS0FBSyxDQUFDLEdBQUcsQ0FBQyxHQUFHLFFBQVEsTUFBTSxNQUFNLElBQUksSUFBSSxJQUFJLFdBQVcsVUFBVSxHQUFHLElBQUksSUFBSSxFQUFFLENBQUMsQ0FBQztvQkFDeEcsT0FBTyxDQUFDLE1BQU0sS0FBSyxHQUFHLENBQUMsQ0FBQztnQkFDNUIsQ0FBQztnQkFBQyxPQUFPLENBQUMsRUFBRSxDQUFDO29CQUNULE9BQU8sS0FBSyxDQUFDO2dCQUNqQixDQUFDO1lBQ0wsQ0FBQztZQUNELE9BQU8sQ0FBQyxDQUFDLENBQUM7Z0JBQ04sS0FBSyxDQUFDLDhCQUE4QixDQUFDLFFBQVEsQ0FBQyxDQUFDO1lBQ25ELENBQUM7UUFDTCxDQUFDO0lBQ0wsQ0FBQztJQUVELE1BQU0sQ0FBQyw4QkFBOEIsQ0FBRSxLQUFZO1FBQy9DLHFFQUFxRTtRQUNyRSxNQUFNLElBQUksS0FBSyxDQUFDLGtCQUFrQixLQUFLLEVBQUUsQ0FBQyxDQUFDO0lBQy9DLENBQUM7Q0FDSiIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBSRTIgZnJvbSBcInJlMlwiO1xuaW1wb3J0IGNoYWxrIGZyb20gXCJjaGFsa1wiO1xuaW1wb3J0IHtKb2IsIEpvYlJ1bGV9IGZyb20gXCIuL2pvYi5qc1wiO1xuaW1wb3J0IGZzIGZyb20gXCJmcy1leHRyYVwiO1xuaW1wb3J0IGNoZWNrc3VtIGZyb20gXCJjaGVja3N1bVwiO1xuaW1wb3J0IGJhc2U2NHVybCBmcm9tIFwiYmFzZTY0dXJsXCI7XG5pbXBvcnQgZXhlY2EgZnJvbSBcImV4ZWNhXCI7XG5pbXBvcnQgYXNzZXJ0IGZyb20gXCJhc3NlcnRcIjtcbmltcG9ydCB7Q0lDRFZhcmlhYmxlfSBmcm9tIFwiLi92YXJpYWJsZXMtZnJvbS1maWxlcy5qc1wiO1xuaW1wb3J0IHtHaXREYXRhLCBHaXRTY2hlbWF9IGZyb20gXCIuL2dpdC1kYXRhLmpzXCI7XG5pbXBvcnQgZ2xvYmJ5IGZyb20gXCJnbG9iYnlcIjtcbmltcG9ydCBtaWNyb21hdGNoIGZyb20gXCJtaWNyb21hdGNoXCI7XG5pbXBvcnQgYXhpb3MgZnJvbSBcImF4aW9zXCI7XG5pbXBvcnQgcGF0aCBmcm9tIFwicGF0aFwiO1xuaW1wb3J0IHtBcmd2fSBmcm9tIFwiLi9hcmd2LmpzXCI7XG5cbnR5cGUgUnVsZVJlc3VsdE9wdCA9IHtcbiAgICBhcmd2OiBBcmd2O1xuICAgIGN3ZDogc3RyaW5nO1xuICAgIHJ1bGVzOiBKb2JSdWxlW107XG4gICAgdmFyaWFibGVzOiB7W2tleTogc3RyaW5nXTogc3RyaW5nfTtcbn07XG5cbnR5cGUgRXhwYW5kV2l0aCA9IHtcbiAgICB1bmVzY2FwZTogc3RyaW5nO1xuICAgIHZhcmlhYmxlOiAobmFtZTogc3RyaW5nKSA9PiBzdHJpbmc7XG59O1xuXG5leHBvcnQgY2xhc3MgVXRpbHMge1xuICAgIHN0YXRpYyBiYXNoTXVsdGkgKHNjcmlwdHM6IHN0cmluZ1tdLCBjd2QgPSBwcm9jZXNzLmN3ZCgpKTogUHJvbWlzZTx7c3Rkb3V0OiBzdHJpbmc7IHN0ZGVycjogc3RyaW5nOyBleGl0Q29kZTogbnVtYmVyfT4ge1xuICAgICAgICByZXR1cm4gZXhlY2Eoc2NyaXB0cy5qb2luKFwiICYmIFxcXFxcIiksIHtzaGVsbDogXCJiYXNoXCIsIGN3ZH0pO1xuICAgIH1cblxuICAgIHN0YXRpYyBiYXNoIChzaGVsbFNjcmlwdDogc3RyaW5nLCBjd2QgPSBwcm9jZXNzLmN3ZCgpKTogUHJvbWlzZTx7c3Rkb3V0OiBzdHJpbmc7IHN0ZGVycjogc3RyaW5nOyBleGl0Q29kZTogbnVtYmVyfT4ge1xuICAgICAgICByZXR1cm4gZXhlY2Eoc2hlbGxTY3JpcHQsIHtzaGVsbDogXCJiYXNoXCIsIGN3ZH0pO1xuICAgIH1cblxuICAgIHN0YXRpYyBzcGF3biAoY21kQXJnczogc3RyaW5nW10sIGN3ZCA9IHByb2Nlc3MuY3dkKCkpOiBQcm9taXNlPHtzdGRvdXQ6IHN0cmluZzsgc3RkZXJyOiBzdHJpbmd9PiB7XG4gICAgICAgIHJldHVybiBleGVjYShjbWRBcmdzWzBdLCBjbWRBcmdzLnNsaWNlKDEpLCB7Y3dkfSk7XG4gICAgfVxuXG4gICAgc3RhdGljIHN5bmNTcGF3biAoY21kQXJnczogc3RyaW5nW10sIGN3ZCA9IHByb2Nlc3MuY3dkKCkpOiB7c3Rkb3V0OiBzdHJpbmc7IHN0ZGVycjogc3RyaW5nfSB7XG4gICAgICAgIHJldHVybiBleGVjYS5zeW5jKGNtZEFyZ3NbMF0sIGNtZEFyZ3Muc2xpY2UoMSksIHtjd2R9KTtcbiAgICB9XG5cbiAgICBzdGF0aWMgZnNVcmwgKHVybDogc3RyaW5nKTogc3RyaW5nIHtcbiAgICAgICAgcmV0dXJuIHVybC5yZXBsYWNlKC9eaHR0cHM6XFwvXFwvL2csIFwiXCIpLnJlcGxhY2UoL15odHRwOlxcL1xcLy9nLCBcIlwiKTtcbiAgICB9XG5cbiAgICBzdGF0aWMgc2FmZURvY2tlclN0cmluZyAoam9iTmFtZTogc3RyaW5nKSB7XG4gICAgICAgIHJldHVybiBqb2JOYW1lLnJlcGxhY2UoL1teXFx3LV0rL2csIChtYXRjaCkgPT4ge1xuICAgICAgICAgICAgcmV0dXJuIGJhc2U2NHVybC5lbmNvZGUobWF0Y2gpO1xuICAgICAgICB9KTtcbiAgICB9XG5cbiAgICBzdGF0aWMgZm9yRWFjaFJlYWxKb2IgKGdpdGxhYkRhdGE6IGFueSwgY2FsbGJhY2s6IChqb2JOYW1lOiBzdHJpbmcsIGpvYkRhdGE6IGFueSkgPT4gdm9pZCkge1xuICAgICAgICBmb3IgKGNvbnN0IFtqb2JOYW1lLCBqb2JEYXRhXSBvZiBPYmplY3QuZW50cmllczxhbnk+KGdpdGxhYkRhdGEpKSB7XG4gICAgICAgICAgICBpZiAoSm9iLmlsbGVnYWxKb2JOYW1lcy5oYXMoam9iTmFtZSkgfHwgam9iTmFtZVswXS5zdGFydHNXaXRoKFwiLlwiKSkge1xuICAgICAgICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgY2FsbGJhY2soam9iTmFtZSwgam9iRGF0YSk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBzdGF0aWMgZ2V0Sm9iTmFtZXNGcm9tUHJldmlvdXNTdGFnZXMgKGpvYnM6IFJlYWRvbmx5QXJyYXk8Sm9iPiwgc3RhZ2VzOiByZWFkb25seSBzdHJpbmdbXSwgY3VycmVudEpvYjogSm9iKSB7XG4gICAgICAgIGNvbnN0IGpvYk5hbWVzOiBzdHJpbmdbXSA9IFtdO1xuICAgICAgICBjb25zdCBjdXJyZW50U3RhZ2VJbmRleCA9IHN0YWdlcy5pbmRleE9mKGN1cnJlbnRKb2Iuc3RhZ2UpO1xuICAgICAgICBqb2JzLmZvckVhY2goam9iID0+IHtcbiAgICAgICAgICAgIGNvbnN0IHN0YWdlSW5kZXggPSBzdGFnZXMuaW5kZXhPZihqb2Iuc3RhZ2UpO1xuICAgICAgICAgICAgaWYgKHN0YWdlSW5kZXggPCBjdXJyZW50U3RhZ2VJbmRleCkge1xuICAgICAgICAgICAgICAgIGpvYk5hbWVzLnB1c2goam9iLm5hbWUpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICAgICAgcmV0dXJuIGpvYk5hbWVzO1xuICAgIH1cblxuICAgIHN0YXRpYyBhc3luYyBnZXRDb3ZlcmFnZVBlcmNlbnQgKGN3ZDogc3RyaW5nLCBzdGF0ZURpcjogc3RyaW5nLCBjb3ZlcmFnZVJlZ2V4OiBzdHJpbmcsIGpvYk5hbWU6IHN0cmluZykge1xuICAgICAgICBjb25zdCBjb250ZW50ID0gYXdhaXQgZnMucmVhZEZpbGUoYCR7Y3dkfS8ke3N0YXRlRGlyfS9vdXRwdXQvJHtqb2JOYW1lfS5sb2dgLCBcInV0ZjhcIik7XG5cbiAgICAgICAgY29uc3QgcmVnZXggPSBuZXcgUmVnRXhwKGNvdmVyYWdlUmVnZXgucmVwbGFjZSgvXlxcLy8sIFwiXCIpLnJlcGxhY2UoL1xcLyQvLCBcIlwiKSwgXCJnbVwiKTtcbiAgICAgICAgY29uc3QgbWF0Y2hlcyA9IEFycmF5LmZyb20oY29udGVudC5tYXRjaEFsbChyZWdleCkpO1xuICAgICAgICBpZiAobWF0Y2hlcy5sZW5ndGggPT09IDApIHJldHVybiBcIjBcIjtcblxuICAgICAgICBjb25zdCBsYXN0TWF0Y2ggPSBtYXRjaGVzW21hdGNoZXMubGVuZ3RoIC0gMV07XG4gICAgICAgIGNvbnN0IGRpZ2l0cyA9IC9cXGQrKD86XFwuXFxkKyk/Ly5leGVjKGxhc3RNYXRjaFsxXSA/PyBsYXN0TWF0Y2hbMF0pO1xuICAgICAgICBpZiAoIWRpZ2l0cykgcmV0dXJuIFwiMFwiO1xuICAgICAgICByZXR1cm4gZGlnaXRzWzBdID8/IFwiMFwiO1xuICAgIH1cblxuICAgIHN0YXRpYyBwcmludEpvYk5hbWVzIChzdHJlYW06ICh0eHQ6IHN0cmluZykgPT4gdm9pZCwgam9iOiB7bmFtZTogc3RyaW5nfSwgaTogbnVtYmVyLCBhcnI6IHtuYW1lOiBzdHJpbmd9W10pIHtcbiAgICAgICAgaWYgKGkgPT09IGFyci5sZW5ndGggLSAxKSB7XG4gICAgICAgICAgICBzdHJlYW0oY2hhbGtge2JsdWVCcmlnaHQgJHtqb2IubmFtZX19YCk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBzdHJlYW0oY2hhbGtge2JsdWVCcmlnaHQgJHtqb2IubmFtZX19LCBgKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHByaXZhdGUgc3RhdGljIGV4cGFuZFRleHRXaXRoICh0ZXh0OiBhbnksIGV4cGFuZFdpdGg6IEV4cGFuZFdpdGgpIHtcbiAgICAgICAgaWYgKHR5cGVvZiB0ZXh0ICE9PSBcInN0cmluZ1wiKSB7XG4gICAgICAgICAgICByZXR1cm4gdGV4dDtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiB0ZXh0LnJlcGxhY2UoXG4gICAgICAgICAgICAvKFxcJFxcJCl8XFwkXFx7KFthLXpBLVpfXVxcdyopfXxcXCQoW2EtekEtWl9dXFx3KikvZywgLy8gaHR0cHM6Ly9yZWdleHIuY29tLzdzNGthXG4gICAgICAgICAgICAoX21hdGNoLCBlc2NhcGUsIHZhcjEsIHZhcjIpID0+IHtcbiAgICAgICAgICAgICAgICBpZiAodHlwZW9mIGVzY2FwZSAhPT0gXCJ1bmRlZmluZWRcIikge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gZXhwYW5kV2l0aC51bmVzY2FwZTtcbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICBjb25zdCBuYW1lID0gdmFyMSB8fCB2YXIyO1xuICAgICAgICAgICAgICAgICAgICBhc3NlcnQobmFtZSwgXCJ1bmV4cGVjdGVkIHVuc2V0IGNhcHR1cmUgZ3JvdXBcIik7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBgJHtleHBhbmRXaXRoLnZhcmlhYmxlKG5hbWUpfWA7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICApO1xuICAgIH1cblxuICAgIHN0YXRpYyBleHBhbmRUZXh0ICh0ZXh0OiBhbnksIGVudnM6IHtba2V5OiBzdHJpbmddOiBzdHJpbmd9KSB7XG4gICAgICAgIHJldHVybiB0aGlzLmV4cGFuZFRleHRXaXRoKHRleHQsIHtcbiAgICAgICAgICAgIHVuZXNjYXBlOiBcIiRcIixcbiAgICAgICAgICAgIHZhcmlhYmxlOiAobmFtZSkgPT4gZW52c1tuYW1lXSA/PyBcIlwiLFxuICAgICAgICB9KTtcbiAgICB9XG5cbiAgICBzdGF0aWMgZXhwYW5kVmFyaWFibGVzICh2YXJpYWJsZXM6IHtba2V5OiBzdHJpbmddOiBzdHJpbmd9KSB7XG4gICAgICAgIGNvbnN0IF92YXJpYWJsZXMgPSB7Li4udmFyaWFibGVzfTsgLy8gY29weSBieSB2YWx1ZSB0byBwcmV2ZW50IG11dGF0aW5nIHRoZSBvcmlnaW5hbCBpbnB1dFxuICAgICAgICBsZXQgZXhwYW5kZWRBbnlWYXJpYWJsZXMsIGkgPSAwO1xuICAgICAgICBkbyB7XG4gICAgICAgICAgICBhc3NlcnQoaSA8IDEwMCwgXCJSZWN1cnNpdmUgdmFyaWFibGUgZXhwYW5zaW9uIHJlYWNoZWQgMTAwIGl0ZXJhdGlvbnNcIik7XG4gICAgICAgICAgICBleHBhbmRlZEFueVZhcmlhYmxlcyA9IGZhbHNlO1xuICAgICAgICAgICAgZm9yIChjb25zdCBbaywgdl0gb2YgT2JqZWN0LmVudHJpZXMoX3ZhcmlhYmxlcykpIHtcbiAgICAgICAgICAgICAgICBjb25zdCBlbnZzV2l0aG91dFNlbGYgPSB7Li4uX3ZhcmlhYmxlc307XG4gICAgICAgICAgICAgICAgZGVsZXRlIGVudnNXaXRob3V0U2VsZltrXTtcbiAgICAgICAgICAgICAgICAvLyBJZiB0aGUgJCQncyBhcmUgY29udmVydGVkIHRvIHNpbmdsZSAkJ3Mgbm93LCB0aGVuIHRoZSBuZXh0XG4gICAgICAgICAgICAgICAgLy8gaXRlcmF0aW9uLCB0aGV5IG1pZ2h0IGJlIGludGVycHJldGVkIGFzIF92YXJpYWJsZXMsIGV2ZW5cbiAgICAgICAgICAgICAgICAvLyB0aG91Z2ggdGhleSB3ZXJlICpleHBsaWNpdGx5KiBlc2NhcGVkLiBUbyB3b3JrIGFyb3VuZCB0aGlzLFxuICAgICAgICAgICAgICAgIC8vIGxlYXZlIHRoZSAnJCQncyBhcyB0aGUgc2FtZSB2YWx1ZSwgdGhlbiBvbmx5IHVuZXNjYXBlIHRoZW0gYXRcbiAgICAgICAgICAgICAgICAvLyB0aGUgdmVyeSBlbmQuXG4gICAgICAgICAgICAgICAgX3ZhcmlhYmxlc1trXSA9IFV0aWxzLmV4cGFuZFRleHRXaXRoKHYsIHtcbiAgICAgICAgICAgICAgICAgICAgdW5lc2NhcGU6IFwiJCRcIixcbiAgICAgICAgICAgICAgICAgICAgdmFyaWFibGU6IChuYW1lKSA9PiBlbnZzV2l0aG91dFNlbGZbbmFtZV0gPz8gXCJcIixcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICBleHBhbmRlZEFueVZhcmlhYmxlcyB8fD0gX3ZhcmlhYmxlc1trXSAhPT0gdjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGkrKztcbiAgICAgICAgfSB3aGlsZSAoZXhwYW5kZWRBbnlWYXJpYWJsZXMpO1xuXG4gICAgICAgIHJldHVybiBfdmFyaWFibGVzO1xuICAgIH1cblxuICAgIHN0YXRpYyB1bnNjYXBlJCRWYXJpYWJsZXMgKHZhcmlhYmxlczoge1trZXk6IHN0cmluZ106IHN0cmluZ30pIHtcbiAgICAgICAgZm9yIChjb25zdCBbaywgdl0gb2YgT2JqZWN0LmVudHJpZXModmFyaWFibGVzKSkge1xuICAgICAgICAgICAgdmFyaWFibGVzW2tdID0gVXRpbHMuZXhwYW5kVGV4dCh2LCB7fSk7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gdmFyaWFibGVzO1xuICAgIH1cblxuICAgIHN0YXRpYyBmaW5kRW52TWF0Y2hlZFZhcmlhYmxlcyAodmFyaWFibGVzOiB7W25hbWU6IHN0cmluZ106IENJQ0RWYXJpYWJsZX0sIGZpbGVWYXJpYWJsZXNEaXI/OiBzdHJpbmcsIGVudmlyb25tZW50Pzoge25hbWU6IHN0cmluZ30pIHtcbiAgICAgICAgY29uc3QgZW52TWF0Y2hlZFZhcmlhYmxlczoge1trZXk6IHN0cmluZ106IHN0cmluZ30gPSB7fTtcbiAgICAgICAgZm9yIChjb25zdCBbaywgdl0gb2YgT2JqZWN0LmVudHJpZXModmFyaWFibGVzKSkge1xuICAgICAgICAgICAgZm9yIChjb25zdCBlbnRyeSBvZiB2LmVudmlyb25tZW50cykge1xuICAgICAgICAgICAgICAgIGlmIChlbnZpcm9ubWVudD8ubmFtZS5tYXRjaChlbnRyeS5yZWdleHApIHx8IGVudHJ5LnJlZ2V4cC5zb3VyY2UgPT09IFwiLipcIikge1xuICAgICAgICAgICAgICAgICAgICBpZiAoZmlsZVZhcmlhYmxlc0RpciAhPSBudWxsICYmIHYudHlwZSA9PT0gXCJmaWxlXCIgJiYgIWVudHJ5LmZpbGVTb3VyY2UpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGVudk1hdGNoZWRWYXJpYWJsZXNba10gPSBgJHtmaWxlVmFyaWFibGVzRGlyfS8ke2t9YDtcbiAgICAgICAgICAgICAgICAgICAgICAgIGZzLm1rZGlycFN5bmMoYCR7ZmlsZVZhcmlhYmxlc0Rpcn1gKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGZzLndyaXRlRmlsZVN5bmMoYCR7ZmlsZVZhcmlhYmxlc0Rpcn0vJHtrfWAsIGVudHJ5LmNvbnRlbnQpO1xuICAgICAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKGZpbGVWYXJpYWJsZXNEaXIgIT0gbnVsbCAmJiB2LnR5cGUgPT09IFwiZmlsZVwiICYmIGVudHJ5LmZpbGVTb3VyY2UpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGVudk1hdGNoZWRWYXJpYWJsZXNba10gPSBgJHtmaWxlVmFyaWFibGVzRGlyfS8ke2t9YDtcbiAgICAgICAgICAgICAgICAgICAgICAgIGZzLm1rZGlycFN5bmMoYCR7ZmlsZVZhcmlhYmxlc0Rpcn1gKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGZzLmNvcHlGaWxlU3luYyhlbnRyeS5maWxlU291cmNlLCBgJHtmaWxlVmFyaWFibGVzRGlyfS8ke2t9YCk7XG4gICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBlbnZNYXRjaGVkVmFyaWFibGVzW2tdID0gZW50cnkuY29udGVudDtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIGVudk1hdGNoZWRWYXJpYWJsZXM7XG4gICAgfVxuXG4gICAgc3RhdGljIGdldFJ1bGVzUmVzdWx0IChvcHQ6IFJ1bGVSZXN1bHRPcHQsIGdpdERhdGE6IEdpdERhdGEsIGpvYldoZW46IHN0cmluZyA9IFwib25fc3VjY2Vzc1wiLCBqb2JBbGxvd0ZhaWx1cmU6IGJvb2xlYW4gfCB7ZXhpdF9jb2RlczogbnVtYmVyIHwgbnVtYmVyW119ID0gZmFsc2UpOiB7d2hlbjogc3RyaW5nOyBhbGxvd0ZhaWx1cmU6IGJvb2xlYW4gfCB7ZXhpdF9jb2RlczogbnVtYmVyIHwgbnVtYmVyW119OyB2YXJpYWJsZXM/OiB7W25hbWU6IHN0cmluZ106IHN0cmluZ319IHtcbiAgICAgICAgbGV0IHdoZW4gPSBcIm5ldmVyXCI7XG4gICAgICAgIGNvbnN0IHtldmFsdWF0ZVJ1bGVDaGFuZ2VzfSA9IG9wdC5hcmd2O1xuXG4gICAgICAgIC8vIG9wdGlvbmFsIG1hbnVhbCBqb2JzIGFsbG93RmFpbHVyZSBkZWZhdWx0cyB0byB0cnVlIGh0dHBzOi8vZG9jcy5naXRsYWIuY29tL2VlL2NpL2pvYnMvam9iX2NvbnRyb2wuaHRtbCN0eXBlcy1vZi1tYW51YWwtam9ic1xuICAgICAgICBsZXQgYWxsb3dGYWlsdXJlID0gam9iV2hlbiA9PT0gXCJtYW51YWxcIiA/IHRydWUgOiBqb2JBbGxvd0ZhaWx1cmU7XG4gICAgICAgIGxldCBydWxlVmFyaWFibGU6IHtbbmFtZTogc3RyaW5nXTogc3RyaW5nfSB8IHVuZGVmaW5lZDtcblxuICAgICAgICBmb3IgKGNvbnN0IHJ1bGUgb2Ygb3B0LnJ1bGVzKSB7XG4gICAgICAgICAgICBpZiAoIVV0aWxzLmV2YWx1YXRlUnVsZUlmKHJ1bGUuaWYsIG9wdC52YXJpYWJsZXMpKSBjb250aW51ZTtcbiAgICAgICAgICAgIGlmICghVXRpbHMuZXZhbHVhdGVSdWxlRXhpc3Qob3B0LmN3ZCwgcnVsZS5leGlzdHMpKSBjb250aW51ZTtcbiAgICAgICAgICAgIGlmIChldmFsdWF0ZVJ1bGVDaGFuZ2VzICYmICFVdGlscy5ldmFsdWF0ZVJ1bGVDaGFuZ2VzKGdpdERhdGEuYnJhbmNoZXMuZGVmYXVsdCwgcnVsZS5jaGFuZ2VzKSkgY29udGludWU7XG5cbiAgICAgICAgICAgIHdoZW4gPSBydWxlLndoZW4gPyBydWxlLndoZW4gOiBqb2JXaGVuO1xuICAgICAgICAgICAgYWxsb3dGYWlsdXJlID0gcnVsZS5hbGxvd19mYWlsdXJlID8/IGFsbG93RmFpbHVyZTtcbiAgICAgICAgICAgIHJ1bGVWYXJpYWJsZSA9IHJ1bGUudmFyaWFibGVzO1xuXG4gICAgICAgICAgICBicmVhazsgLy8gRWFybHkgcmV0dXJuLCB3aWxsIG5vdCBldmFsdWF0ZSB0aGUgcmVtYWluaW5nIHJ1bGVzXG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4ge3doZW4sIGFsbG93RmFpbHVyZSwgdmFyaWFibGVzOiBydWxlVmFyaWFibGV9O1xuICAgIH1cblxuICAgIHN0YXRpYyBldmFsdWF0ZVJ1bGVJZiAocnVsZUlmOiBzdHJpbmcgfCB1bmRlZmluZWQsIGVudnM6IHtba2V5OiBzdHJpbmddOiBzdHJpbmd9KTogYm9vbGVhbiB7XG4gICAgICAgIGlmIChydWxlSWYgPT09IHVuZGVmaW5lZCkgcmV0dXJuIHRydWU7XG4gICAgICAgIGxldCBldmFsU3RyID0gcnVsZUlmO1xuXG4gICAgICAgIC8vIEV4cGFuZCBhbGwgdmFyaWFibGVzXG4gICAgICAgIGV2YWxTdHIgPSB0aGlzLmV4cGFuZFRleHRXaXRoKGV2YWxTdHIsIHtcbiAgICAgICAgICAgIHVuZXNjYXBlOiBKU09OLnN0cmluZ2lmeShcIiRcIiksXG4gICAgICAgICAgICB2YXJpYWJsZTogKG5hbWUpID0+IEpTT04uc3RyaW5naWZ5KGVudnNbbmFtZV0gPz8gbnVsbCkucmVwbGFjZUFsbChcIlxcXFxcXFxcXCIsIFwiXFxcXFwiKSxcbiAgICAgICAgfSk7XG4gICAgICAgIGNvbnN0IGV4cGFuZGVkRXZhbFN0ciA9IGV2YWxTdHI7XG5cbiAgICAgICAgLy8gU2NlbmFyaW8gd2hlbiBSSFMgaXMgYSA8cmVnZXg+XG4gICAgICAgIC8vIGh0dHBzOi8vcmVnZXhyLmNvbS84NXNqb1xuICAgICAgICBjb25zdCBwYXR0ZXJuMSA9IC9cXHMqKD88b3BlcmF0b3I+KD86PX4pfCg/OiF+KSlcXHMqXFwvKD88cmhzPi4qPylcXC8oPzxmbGFncz5baWdtc3V5XSopKFxcc3wkfFxcKSkvZztcbiAgICAgICAgZXZhbFN0ciA9IGV2YWxTdHIucmVwbGFjZShwYXR0ZXJuMSwgKF8sIG9wZXJhdG9yLCByaHMsIGZsYWdzLCByZW1haW5pbmdUb2tlbnMpID0+IHtcbiAgICAgICAgICAgIGxldCBfb3BlcmF0b3I7XG4gICAgICAgICAgICBzd2l0Y2ggKG9wZXJhdG9yKSB7XG4gICAgICAgICAgICAgICAgY2FzZSBcIj1+XCI6XG4gICAgICAgICAgICAgICAgICAgIF9vcGVyYXRvciA9IFwiIT1cIjtcbiAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgY2FzZSBcIiF+XCI6XG4gICAgICAgICAgICAgICAgICAgIF9vcGVyYXRvciA9IFwiPT1cIjtcbiAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgZGVmYXVsdDpcbiAgICAgICAgICAgICAgICAgICAgdGhyb3cgb3BlcmF0b3I7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBjb25zdCBfcmhzID0gSlNPTi5zdHJpbmdpZnkocmhzKTsgLy8gSlNPTi5zdHJpbmdpZnkgZm9yIGVzY2FwaW5nIGBcImBcbiAgICAgICAgICAgIGNvbnN0IGNvbnRhaW5zTm9uRXNjYXBlZFNsYXNoID0gLyg/PCFcXFxcKVxcLy8udGVzdChfcmhzKTtcbiAgICAgICAgICAgIGNvbnN0IGFzc2VydE1zZyA9IFtcbiAgICAgICAgICAgICAgICBcIkVycm9yIGF0dGVtcHRpbmcgdG8gZXZhbHVhdGUgdGhlIGZvbGxvd2luZyBydWxlczpcIixcbiAgICAgICAgICAgICAgICBcIiAgcnVsZXM6XCIsXG4gICAgICAgICAgICAgICAgYCAgICAtIGlmOiAnJHtleHBhbmRlZEV2YWxTdHJ9J2AsXG4gICAgICAgICAgICAgICAgXCJhcyByaHMgY29udGFpbnMgdW5lc2NhcGVkIHF1b3RlXCIsXG4gICAgICAgICAgICBdO1xuICAgICAgICAgICAgYXNzZXJ0KCFjb250YWluc05vbkVzY2FwZWRTbGFzaCwgYXNzZXJ0TXNnLmpvaW4oXCJcXG5cIikpO1xuICAgICAgICAgICAgcmV0dXJuIGAubWF0Y2gobmV3IFJFMigke19yaHN9LCBcIiR7ZmxhZ3N9XCIpKSAke19vcGVyYXRvcn0gbnVsbCR7cmVtYWluaW5nVG9rZW5zfWA7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIC8vIFNjZW5hcmlvIHdoZW4gUkhTIGlzIHN1cnJvdW5kZWQgYnkgc2luZ2xlL2RvdWJsZS1xdW90ZXNcbiAgICAgICAgLy8gaHR0cHM6Ly9yZWdleHIuY29tLzg1dDBnXG4gICAgICAgIGNvbnN0IHBhdHRlcm4yID0gL1xccyooPzxvcGVyYXRvcj49fnwhfilcXHMqKFtcIiddKSg/PHJocz4oPzpcXFxcLnxbXlxcXFxdKSo/KVxcMi9nO1xuICAgICAgICBldmFsU3RyID0gZXZhbFN0ci5yZXBsYWNlKHBhdHRlcm4yLCAoXywgb3BlcmF0b3IsIF9fLCByaHMpID0+IHtcbiAgICAgICAgICAgIGxldCBfb3BlcmF0b3I7XG4gICAgICAgICAgICBzd2l0Y2ggKG9wZXJhdG9yKSB7XG4gICAgICAgICAgICAgICAgY2FzZSBcIj1+XCI6XG4gICAgICAgICAgICAgICAgICAgIF9vcGVyYXRvciA9IFwiIT1cIjtcbiAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgY2FzZSBcIiF+XCI6XG4gICAgICAgICAgICAgICAgICAgIF9vcGVyYXRvciA9IFwiPT1cIjtcbiAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgZGVmYXVsdDpcbiAgICAgICAgICAgICAgICAgICAgdGhyb3cgb3BlcmF0b3I7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGNvbnN0IGFzc2VydE1zZyA9IFtcbiAgICAgICAgICAgICAgICBcIlJIUyAoJHtyaHN9KSBtdXN0IGJlIGEgcmVnZXggcGF0dGVybi4gRG8gbm90IHJlbHkgb24gdGhpcyBiZWhhdmlvciFcIixcbiAgICAgICAgICAgICAgICBcIlJlZmVyIHRvIGh0dHBzOi8vZG9jcy5naXRsYWIuY29tL2VlL2NpL2pvYnMvam9iX3J1bGVzLmh0bWwjdW5leHBlY3RlZC1iZWhhdmlvci1mcm9tLXJlZ3VsYXItZXhwcmVzc2lvbi1tYXRjaGluZy13aXRoLSBmb3IgbW9yZSBpbmZvLi4uXCIsXG4gICAgICAgICAgICBdO1xuICAgICAgICAgICAgYXNzZXJ0KCgvXFwvKC4qKVxcLyhcXHcqKS8udGVzdChyaHMpKSwgYXNzZXJ0TXNnLmpvaW4oXCJcXG5cIikpO1xuXG4gICAgICAgICAgICBjb25zdCByZWdleCA9IC9cXC8oPzxwYXR0ZXJuPi4qKVxcLyg/PGZsYWdzPltpZ21zdXldKikvO1xuICAgICAgICAgICAgY29uc3QgX3JocyA9IHJocy5yZXBsYWNlKHJlZ2V4LCAoXzogc3RyaW5nLCBwYXR0ZXJuOiBzdHJpbmcsIGZsYWdzOiBzdHJpbmcpID0+IHtcbiAgICAgICAgICAgICAgICByZXR1cm4gYG5ldyBSRTIoXCIke3BhdHRlcm59XCIsIFwiJHtmbGFnc31cIilgO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICByZXR1cm4gYC5tYXRjaCgke19yaHN9KSAke19vcGVyYXRvcn0gbnVsbGA7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIC8vIENvbnZlcnQgYWxsIG51bGwubWF0Y2ggZnVuY3Rpb25zIHRvIGZhbHNlXG4gICAgICAgIGV2YWxTdHIgPSBldmFsU3RyLnJlcGxhY2UoL251bGwubWF0Y2hcXCguKz9cXClcXHMqIT1cXHMqbnVsbC9nLCBcImZhbHNlXCIpO1xuICAgICAgICBldmFsU3RyID0gZXZhbFN0ci5yZXBsYWNlKC9udWxsLm1hdGNoXFwoLis/XFwpXFxzKj09XFxzKm51bGwvZywgXCJmYWxzZVwiKTtcblxuICAgICAgICBldmFsU3RyID0gZXZhbFN0ci50cmltKCk7XG5cbiAgICAgICAgbGV0IHJlcztcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIChnbG9iYWwgYXMgYW55KS5SRTIgPSBSRTI7IC8vIEFzc2lnbiBSRTIgdG8gdGhlIGdsb2JhbCBvYmplY3RcbiAgICAgICAgICAgIHJlcyA9ICgwLCBldmFsKShldmFsU3RyKTsgLy8gaHR0cHM6Ly9lc2J1aWxkLmdpdGh1Yi5pby9jb250ZW50LXR5cGVzLyNkaXJlY3QtZXZhbFxuICAgICAgICAgICAgZGVsZXRlIChnbG9iYWwgYXMgYW55KS5SRTI7IC8vIENsZWFudXBcbiAgICAgICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICAgICAgICBjb25zdCBhc3NlcnRNc2cgPSBbXG4gICAgICAgICAgICAgICAgXCJFcnJvciBhdHRlbXB0aW5nIHRvIGV2YWx1YXRlIHRoZSBmb2xsb3dpbmcgcnVsZXM6XCIsXG4gICAgICAgICAgICAgICAgXCIgIHJ1bGVzOlwiLFxuICAgICAgICAgICAgICAgIGAgICAgLSBpZjogJyR7ZXhwYW5kZWRFdmFsU3RyfSdgLFxuICAgICAgICAgICAgICAgIFwiYXNcIixcbiAgICAgICAgICAgICAgICBcImBgYGphdmFzY3JpcHRcIixcbiAgICAgICAgICAgICAgICBgJHtldmFsU3RyfWAsXG4gICAgICAgICAgICAgICAgXCJgYGBcIixcbiAgICAgICAgICAgIF07XG4gICAgICAgICAgICBhc3NlcnQoZmFsc2UsIGFzc2VydE1zZy5qb2luKFwiXFxuXCIpKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gQm9vbGVhbihyZXMpO1xuICAgIH1cblxuICAgIHN0YXRpYyBldmFsdWF0ZVJ1bGVFeGlzdCAoY3dkOiBzdHJpbmcsIHJ1bGVFeGlzdHM6IHN0cmluZ1tdIHwgdW5kZWZpbmVkKTogYm9vbGVhbiB7XG4gICAgICAgIGlmIChydWxlRXhpc3RzID09PSB1bmRlZmluZWQpIHJldHVybiB0cnVlO1xuICAgICAgICBmb3IgKGNvbnN0IHBhdHRlcm4gb2YgcnVsZUV4aXN0cykge1xuICAgICAgICAgICAgaWYgKHBhdHRlcm4gPT0gXCJcIikge1xuICAgICAgICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKGdsb2JieS5zeW5jKHBhdHRlcm4sIHtkb3Q6IHRydWUsIGN3ZH0pLmxlbmd0aCA+IDApIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuXG4gICAgc3RhdGljIGV2YWx1YXRlUnVsZUNoYW5nZXMgKGRlZmF1bHRCcmFuY2g6IHN0cmluZywgcnVsZUNoYW5nZXM6IHN0cmluZ1tdIHwge3BhdGhzOiBzdHJpbmdbXX0gfCB1bmRlZmluZWQpOiBib29sZWFuIHtcbiAgICAgICAgaWYgKHJ1bGVDaGFuZ2VzID09PSB1bmRlZmluZWQpIHJldHVybiB0cnVlO1xuXG4gICAgICAgIC8vIE5vcm1hbGl6ZSBydWxlczpjaGFuZ2VzOnBhdGhzIHRvIHJ1bGVzOmNoYW5nZXNcbiAgICAgICAgaWYgKCFBcnJheS5pc0FycmF5KHJ1bGVDaGFuZ2VzKSkgcnVsZUNoYW5nZXMgPSBydWxlQ2hhbmdlcy5wYXRocztcblxuICAgICAgICAvLyBOT1RFOiBodHRwczovL2RvY3MuZ2l0bGFiLmNvbS9lZS9jaS95YW1sLyNydWxlc2NoYW5nZXNcbiAgICAgICAgLy8gICBHbG9iIHBhdHRlcm5zIGFyZSBpbnRlcnByZXRlZCB3aXRoIFJ1YnkncyBbRmlsZS5mbm1hdGNoXShodHRwczovL2RvY3MucnVieS1sYW5nLm9yZy9lbi9tYXN0ZXIvRmlsZS5odG1sI21ldGhvZC1jLWZubWF0Y2gpXG4gICAgICAgIC8vICAgd2l0aCB0aGUgZmxhZ3MgRmlsZTo6Rk5NX1BBVEhOQU1FIHwgRmlsZTo6Rk5NX0RPVE1BVENIIHwgRmlsZTo6Rk5NX0VYVEdMT0IuXG4gICAgICAgIHJldHVybiBtaWNyb21hdGNoLnNvbWUoR2l0RGF0YS5jaGFuZ2VkRmlsZXMoYG9yaWdpbi8ke2RlZmF1bHRCcmFuY2h9YCksIHJ1bGVDaGFuZ2VzLCB7XG4gICAgICAgICAgICBub25lZ2F0ZTogdHJ1ZSxcbiAgICAgICAgICAgIG5vZXh0Z2xvYjogdHJ1ZSxcbiAgICAgICAgICAgIHBvc2l4OiBmYWxzZSxcbiAgICAgICAgICAgIGRvdDogdHJ1ZSxcbiAgICAgICAgfSk7XG4gICAgfVxuXG4gICAgc3RhdGljIGFzeW5jIHJzeW5jVHJhY2tlZEZpbGVzIChjd2Q6IHN0cmluZywgc3RhdGVEaXI6IHN0cmluZywgdGFyZ2V0OiBzdHJpbmcpOiBQcm9taXNlPHtocmRlbHRhdGltZTogW251bWJlciwgbnVtYmVyXX0+IHtcbiAgICAgICAgY29uc3QgdGltZSA9IHByb2Nlc3MuaHJ0aW1lKCk7XG4gICAgICAgIGF3YWl0IGZzLm1rZGlycChgJHtjd2R9LyR7c3RhdGVEaXJ9L2J1aWxkcy8ke3RhcmdldH1gKTtcbiAgICAgICAgYXdhaXQgVXRpbHMuYmFzaChgcnN5bmMgLWEgLS1kZWxldGUtZXhjbHVkZWQgLS1kZWxldGUgLS1leGNsd