gitlab-ci-local
Version:
Tired of pushing to test your .gitlab-ci.yml?
384 lines • 58.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 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 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 = 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;
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`;
});
// Convert all null.match functions to false
evalStr = evalStr.replace(/null.matchRE2JS\(.+?\)\s*!=\s*null/g, "false");
evalStr = evalStr.replace(/null.matchRE2JS\(.+?\)\s*==\s*null/g, "false");
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) {
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 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 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 {
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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidXRpbHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJ1dGlscy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLGFBQWEsQ0FBQztBQUNyQixPQUFPLEVBQUMsS0FBSyxFQUFDLE1BQU0sT0FBTyxDQUFDO0FBQzVCLE9BQU8sS0FBSyxNQUFNLE9BQU8sQ0FBQztBQUMxQixPQUFPLEVBQUMsR0FBRyxFQUFVLE1BQU0sVUFBVSxDQUFDO0FBQ3RDLE9BQU8sRUFBRSxNQUFNLFVBQVUsQ0FBQztBQUMxQixPQUFPLFFBQVEsTUFBTSxVQUFVLENBQUM7QUFDaEMsT0FBTyxTQUFTLE1BQU0sV0FBVyxDQUFDO0FBQ2xDLE9BQU8sS0FBSyxNQUFNLE9BQU8sQ0FBQztBQUMxQixPQUFPLE1BQU0sTUFBTSxRQUFRLENBQUM7QUFFNUIsT0FBTyxFQUFDLE9BQU8sRUFBWSxNQUFNLGVBQWUsQ0FBQztBQUNqRCxPQUFPLE1BQU0sTUFBTSxRQUFRLENBQUM7QUFDNUIsT0FBTyxVQUFVLE1BQU0sWUFBWSxDQUFDO0FBQ3BDLE9BQU8sS0FBSyxNQUFNLE9BQU8sQ0FBQztBQUMxQixPQUFPLElBQUksTUFBTSxNQUFNLENBQUM7QUFleEIsTUFBTSxPQUFPLEtBQUs7SUFDZCxNQUFNLENBQUMsU0FBUyxDQUFFLE9BQWlCLEVBQUUsR0FBRyxHQUFHLE9BQU8sQ0FBQyxHQUFHLEVBQUU7UUFDcEQsT0FBTyxLQUFLLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsRUFBRSxFQUFDLEtBQUssRUFBRSxNQUFNLEVBQUUsR0FBRyxFQUFDLENBQUMsQ0FBQztJQUMvRCxDQUFDO0lBRUQsTUFBTSxDQUFDLElBQUksQ0FBRSxXQUFtQixFQUFFLEdBQUcsR0FBRyxPQUFPLENBQUMsR0FBRyxFQUFFO1FBQ2pELE9BQU8sS0FBSyxDQUFDLFdBQVcsRUFBRSxFQUFDLEtBQUssRUFBRSxNQUFNLEVBQUUsR0FBRyxFQUFDLENBQUMsQ0FBQztJQUNwRCxDQUFDO0lB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QUN4RyxPQUFPLENBQUMsTUFBTSxLQUFLLEdBQUcsQ0FBQyxDQUFDO2dCQUM1QixDQUFDO2dCQUFDLE1BQU0sQ0FBQztvQkFDTCxPQUFPLEtBQUssQ0FBQztnQkFDakIsQ0FBQztZQUNMLENBQUM7WUFDRCxPQUFPLENBQUMsQ0FBQyxDQUFDO2dCQUNOLEtBQUssQ0FBQyw4QkFBOEIsQ0FBQyxRQUFRLENBQUMsQ0FBQztZQUNuRCxDQUFDO1FBQ0wsQ0FBQztJQUNMLENBQUM7SUFFRCxNQUFNLENBQUMsOEJBQThCLENBQUUsS0FBWTtRQUMvQyxxRUFBcUU7UUFDckUsTUFBTSxJQUFJLEtBQUssQ0FBQyxrQkFBa0IsS0FBSyxFQUFFLENBQUMsQ0FBQztJQUMvQyxDQUFDO0NBQ0oiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgXCIuL2dsb2JhbC5qc1wiO1xuaW1wb3J0IHtSRTJKU30gZnJvbSBcInJlMmpzXCI7XG5pbXBvcnQgY2hhbGsgZnJvbSBcImNoYWxrXCI7XG5pbXBvcnQge0pvYiwgSm9iUnVsZX0gZnJvbSBcIi4vam9iLmpzXCI7XG5pbXBvcnQgZnMgZnJvbSBcImZzLWV4dHJhXCI7XG5pbXBvcnQgY2hlY2tzdW0gZnJvbSBcImNoZWNrc3VtXCI7XG5pbXBvcnQgYmFzZTY0dXJsIGZyb20gXCJiYXNlNjR1cmxcIjtcbmltcG9ydCBleGVjYSBmcm9tIFwiZXhlY2FcIjtcbmltcG9ydCBhc3NlcnQgZnJvbSBcImFzc2VydFwiO1xuaW1wb3J0IHtDSUNEVmFyaWFibGV9IGZyb20gXCIuL3ZhcmlhYmxlcy1mcm9tLWZpbGVzLmpzXCI7XG5pbXBvcnQge0dpdERhdGEsIEdpdFNjaGVtYX0gZnJvbSBcIi4vZ2l0LWRhdGEuanNcIjtcbmltcG9ydCBnbG9iYnkgZnJvbSBcImdsb2JieVwiO1xuaW1wb3J0IG1pY3JvbWF0Y2ggZnJvbSBcIm1pY3JvbWF0Y2hcIjtcbmltcG9ydCBheGlvcyBmcm9tIFwiYXhpb3NcIjtcbmltcG9ydCBwYXRoIGZyb20gXCJwYXRoXCI7XG5pbXBvcnQge0FyZ3Z9IGZyb20gXCIuL2FyZ3YuanNcIjtcblxudHlwZSBSdWxlUmVzdWx0T3B0ID0ge1xuICAgIGFyZ3Y6IEFyZ3Y7XG4gICAgY3dkOiBzdHJpbmc7XG4gICAgcnVsZXM6IEpvYlJ1bGVbXTtcbiAgICB2YXJpYWJsZXM6IHtba2V5OiBzdHJpbmddOiBzdHJpbmd9O1xufTtcblxudHlwZSBFeHBhbmRXaXRoID0ge1xuICAgIHVuZXNjYXBlOiBzdHJpbmc7XG4gICAgdmFyaWFibGU6IChuYW1lOiBzdHJpbmcpID0+IHN0cmluZztcbn07XG5cbmV4cG9ydCBjbGFzcyBVdGlscyB7XG4gICAgc3RhdGljIGJhc2hNdWx0aSAoc2NyaXB0czogc3RyaW5nW10sIGN3ZCA9IHByb2Nlc3MuY3dkKCkpOiBQcm9taXNlPHtzdGRvdXQ6IHN0cmluZzsgc3RkZXJyOiBzdHJpbmc7IGV4aXRDb2RlOiBudW1iZXJ9PiB7XG4gICAgICAgIHJldHVybiBleGVjYShzY3JpcHRzLmpvaW4oXCIgJiYgXFxcXFwiKSwge3NoZWxsOiBcImJhc2hcIiwgY3dkfSk7XG4gICAgfVxuXG4gICAgc3RhdGljIGJhc2ggKHNoZWxsU2NyaXB0OiBzdHJpbmcsIGN3ZCA9IHByb2Nlc3MuY3dkKCkpOiBQcm9taXNlPHtzdGRvdXQ6IHN0cmluZzsgc3RkZXJyOiBzdHJpbmc7IGV4aXRDb2RlOiBudW1iZXJ9PiB7XG4gICAgICAgIHJldHVybiBleGVjYShzaGVsbFNjcmlwdCwge3NoZWxsOiBcImJhc2hcIiwgY3dkfSk7XG4gICAgfVxuXG4gICAgc3RhdGljIHNwYXduIChjbWRBcmdzOiBzdHJpbmdbXSwgY3dkID0gcHJvY2Vzcy5jd2QoKSk6IFByb21pc2U8e3N0ZG91dDogc3RyaW5nOyBzdGRlcnI6IHN0cmluZ30+IHtcbiAgICAgICAgcmV0dXJuIGV4ZWNhKGNtZEFyZ3NbMF0sIGNtZEFyZ3Muc2xpY2UoMSksIHtjd2R9KTtcbiAgICB9XG5cbiAgICBzdGF0aWMgc3luY1NwYXduIChjbWRBcmdzOiBzdHJpbmdbXSwgY3dkID0gcHJvY2Vzcy5jd2QoKSk6IHtzdGRvdXQ6IHN0cmluZzsgc3RkZXJyOiBzdHJpbmd9IHtcbiAgICAgICAgcmV0dXJuIGV4ZWNhLnN5bmMoY21kQXJnc1swXSwgY21kQXJncy5zbGljZSgxKSwge2N3ZH0pO1xuICAgIH1cblxuICAgIHN0YXRpYyBmc1VybCAodXJsOiBzdHJpbmcpOiBzdHJpbmcge1xuICAgICAgICByZXR1cm4gdXJsLnJlcGxhY2UoL15odHRwczpcXC9cXC8vZywgXCJcIikucmVwbGFjZSgvXmh0dHA6XFwvXFwvL2csIFwiXCIpO1xuICAgIH1cblxuICAgIHN0YXRpYyBzYWZlRG9ja2VyU3RyaW5nIChqb2JOYW1lOiBzdHJpbmcpIHtcbiAgICAgICAgcmV0dXJuIGpvYk5hbWUucmVwbGFjZSgvW15cXHctXSsvZywgKG1hdGNoKSA9PiB7XG4gICAgICAgICAgICByZXR1cm4gYmFzZTY0dXJsLmVuY29kZShtYXRjaCk7XG4gICAgICAgIH0pO1xuICAgIH1cblxuICAgIHN0YXRpYyBzYWZlQmFzaFN0cmluZyAoczogc3RyaW5nKSB7XG4gICAgICAgIHJldHVybiBgJyR7cy5yZXBsYWNlKC8nL2csIFwiJ1xcXCInXFxcIidcIil9J2A7IC8vIHJlcGxhY2VzIGAnYCB3aXRoIGAnXCInXCInYFxuICAgIH1cblxuICAgIHN0YXRpYyBmb3JFYWNoUmVhbEpvYiAoZ2l0bGFiRGF0YTogYW55LCBjYWxsYmFjazogKGpvYk5hbWU6IHN0cmluZywgam9iRGF0YTogYW55KSA9PiB2b2lkKSB7XG4gICAgICAgIGZvciAoY29uc3QgW2pvYk5hbWUsIGpvYkRhdGFdIG9mIE9iamVjdC5lbnRyaWVzPGFueT4oZ2l0bGFiRGF0YSkpIHtcbiAgICAgICAgICAgIGlmIChKb2IuaWxsZWdhbEpvYk5hbWVzLmhhcyhqb2JOYW1lKSB8fCBqb2JOYW1lWzBdLnN0YXJ0c1dpdGgoXCIuXCIpKSB7XG4gICAgICAgICAgICAgICAgY29udGludWU7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBjYWxsYmFjayhqb2JOYW1lLCBqb2JEYXRhKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHN0YXRpYyBnZXRKb2JOYW1lc0Zyb21QcmV2aW91c1N0YWdlcyAoam9iczogUmVhZG9ubHlBcnJheTxKb2I+LCBzdGFnZXM6IHJlYWRvbmx5IHN0cmluZ1tdLCBjdXJyZW50Sm9iOiBKb2IpIHtcbiAgICAgICAgY29uc3Qgam9iTmFtZXM6IHN0cmluZ1tdID0gW107XG4gICAgICAgIGNvbnN0IGN1cnJlbnRTdGFnZUluZGV4ID0gc3RhZ2VzLmluZGV4T2YoY3VycmVudEpvYi5zdGFnZSk7XG4gICAgICAgIGpvYnMuZm9yRWFjaChqb2IgPT4ge1xuICAgICAgICAgICAgY29uc3Qgc3RhZ2VJbmRleCA9IHN0YWdlcy5pbmRleE9mKGpvYi5zdGFnZSk7XG4gICAgICAgICAgICBpZiAoc3RhZ2VJbmRleCA8IGN1cnJlbnRTdGFnZUluZGV4KSB7XG4gICAgICAgICAgICAgICAgam9iTmFtZXMucHVzaChqb2IubmFtZSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgICAgICByZXR1cm4gam9iTmFtZXM7XG4gICAgfVxuXG4gICAgc3RhdGljIGFzeW5jIGdldENvdmVyYWdlUGVyY2VudCAoY3dkOiBzdHJpbmcsIHN0YXRlRGlyOiBzdHJpbmcsIGNvdmVyYWdlUmVnZXg6IHN0cmluZywgam9iTmFtZTogc3RyaW5nKSB7XG4gICAgICAgIGNvbnN0IGNvbnRlbnQgPSBhd2FpdCBmcy5yZWFkRmlsZShgJHtjd2R9LyR7c3RhdGVEaXJ9L291dHB1dC8ke2pvYk5hbWV9LmxvZ2AsIFwidXRmOFwiKTtcblxuICAgICAgICBjb25zdCByZWdleCA9IG5ldyBSZWdFeHAoY292ZXJhZ2VSZWdleC5yZXBsYWNlKC9eXFwvLywgXCJcIikucmVwbGFjZSgvXFwvJC8sIFwiXCIpLCBcImdtXCIpO1xuICAgICAgICBjb25zdCBtYXRjaGVzID0gQXJyYXkuZnJvbShjb250ZW50Lm1hdGNoQWxsKHJlZ2V4KSk7XG4gICAgICAgIGlmIChtYXRjaGVzLmxlbmd0aCA9PT0gMCkgcmV0dXJuIFwiMFwiO1xuXG4gICAgICAgIGNvbnN0IGxhc3RNYXRjaCA9IG1hdGNoZXNbbWF0Y2hlcy5sZW5ndGggLSAxXTtcbiAgICAgICAgY29uc3QgZGlnaXRzID0gL1xcZCsoPzpcXC5cXGQrKT8vLmV4ZWMobGFzdE1hdGNoWzFdID8/IGxhc3RNYXRjaFswXSk7XG4gICAgICAgIGlmICghZGlnaXRzKSByZXR1cm4gXCIwXCI7XG4gICAgICAgIHJldHVybiBkaWdpdHNbMF0gPz8gXCIwXCI7XG4gICAgfVxuXG4gICAgc3RhdGljIHByaW50Sm9iTmFtZXMgKHN0cmVhbTogKHR4dDogc3RyaW5nKSA9PiB2b2lkLCBqb2I6IHtuYW1lOiBzdHJpbmd9LCBpOiBudW1iZXIsIGFycjoge25hbWU6IHN0cmluZ31bXSkge1xuICAgICAgICBpZiAoaSA9PT0gYXJyLmxlbmd0aCAtIDEpIHtcbiAgICAgICAgICAgIHN0cmVhbShjaGFsa2B7Ymx1ZUJyaWdodCAke2pvYi5uYW1lfX1gKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHN0cmVhbShjaGFsa2B7Ymx1ZUJyaWdodCAke2pvYi5uYW1lfX0sIGApO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBzdGF0aWMgZXhwYW5kVGV4dFdpdGggKHRleHQ6IGFueSwgZXhwYW5kV2l0aDogRXhwYW5kV2l0aCkge1xuICAgICAgICBpZiAodHlwZW9mIHRleHQgIT09IFwic3RyaW5nXCIpIHtcbiAgICAgICAgICAgIHJldHVybiB0ZXh0O1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIHRleHQucmVwbGFjZShcbiAgICAgICAgICAgIC8oXFwkXFwkKXxcXCRcXHsoW2EtekEtWl9dXFx3Kil9fFxcJChbYS16QS1aX11cXHcqKS9nLCAvLyBodHRwczovL3JlZ2V4ci5jb20vN3M0a2FcbiAgICAgICAgICAgIChfbWF0Y2gsIGVzY2FwZSwgdmFyMSwgdmFyMikgPT4ge1xuICAgICAgICAgICAgICAgIGlmICh0eXBlb2YgZXNjYXBlICE9PSBcInVuZGVmaW5lZFwiKSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBleHBhbmRXaXRoLnVuZXNjYXBlO1xuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IG5hbWUgPSB2YXIxIHx8IHZhcjI7XG4gICAgICAgICAgICAgICAgICAgIGFzc2VydChuYW1lLCBcInVuZXhwZWN0ZWQgdW5zZXQgY2FwdHVyZSBncm91cFwiKTtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGAke2V4cGFuZFdpdGgudmFyaWFibGUobmFtZSl9YDtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9LFxuICAgICAgICApO1xuICAgIH1cblxuICAgIHN0YXRpYyBleHBhbmRUZXh0ICh0ZXh0OiBhbnksIGVudnM6IHtba2V5OiBzdHJpbmddOiBzdHJpbmd9KSB7XG4gICAgICAgIHJldHVybiB0aGlzLmV4cGFuZFRleHRXaXRoKHRleHQsIHtcbiAgICAgICAgICAgIHVuZXNjYXBlOiBcIiRcIixcbiAgICAgICAgICAgIHZhcmlhYmxlOiAobmFtZSkgPT4gZW52c1tuYW1lXSA/PyBcIlwiLFxuICAgICAgICB9KTtcbiAgICB9XG5cbiAgICBzdGF0aWMgZXhwYW5kVmFyaWFibGVzICh2YXJpYWJsZXM6IHtba2V5OiBzdHJpbmddOiBzdHJpbmd9KSB7XG4gICAgICAgIGNvbnN0IF92YXJpYWJsZXMgPSB7Li4udmFyaWFibGVzfTsgLy8gY29weSBieSB2YWx1ZSB0byBwcmV2ZW50IG11dGF0aW5nIHRoZSBvcmlnaW5hbCBpbnB1dFxuICAgICAgICBsZXQgZXhwYW5kZWRBbnlWYXJpYWJsZXMsIGkgPSAwO1xuICAgICAgICBkbyB7XG4gICAgICAgICAgICBhc3NlcnQoaSA8IDEwMCwgXCJSZWN1cnNpdmUgdmFyaWFibGUgZXhwYW5zaW9uIHJlYWNoZWQgMTAwIGl0ZXJhdGlvbnNcIik7XG4gICAgICAgICAgICBleHBhbmRlZEFueVZhcmlhYmxlcyA9IGZhbHNlO1xuICAgICAgICAgICAgZm9yIChjb25zdCBbaywgdl0gb2YgT2JqZWN0LmVudHJpZXMoX3ZhcmlhYmxlcykpIHtcbiAgICAgICAgICAgICAgICBjb25zdCBlbnZzV2l0aG91dFNlbGYgPSB7Li4uX3ZhcmlhYmxlc307XG4gICAgICAgICAgICAgICAgZGVsZXRlIGVudnNXaXRob3V0U2VsZltrXTtcbiAgICAgICAgICAgICAgICAvLyBJZiB0aGUgJCQncyBhcmUgY29udmVydGVkIHRvIHNpbmdsZSAkJ3Mgbm93LCB0aGVuIHRoZSBuZXh0XG4gICAgICAgICAgICAgICAgLy8gaXRlcmF0aW9uLCB0aGV5IG1pZ2h0IGJlIGludGVycHJldGVkIGFzIF92YXJpYWJsZXMsIGV2ZW5cbiAgICAgICAgICAgICAgICAvLyB0aG91Z2ggdGhleSB3ZXJlICpleHBsaWNpdGx5KiBlc2NhcGVkLiBUbyB3b3JrIGFyb3VuZCB0aGlzLFxuICAgICAgICAgICAgICAgIC8vIGxlYXZlIHRoZSAnJCQncyBhcyB0aGUgc2FtZSB2YWx1ZSwgdGhlbiBvbmx5IHVuZXNjYXBlIHRoZW0gYXRcbiAgICAgICAgICAgICAgICAvLyB0aGUgdmVyeSBlbmQuXG4gICAgICAgICAgICAgICAgX3ZhcmlhYmxlc1trXSA9IFV0aWxzLmV4cGFuZFRleHRXaXRoKHYsIHtcbiAgICAgICAgICAgICAgICAgICAgdW5lc2NhcGU6IFwiJCRcIixcbiAgICAgICAgICAgICAgICAgICAgdmFyaWFibGU6IChuYW1lKSA9PiBlbnZzV2l0aG91dFNlbGZbbmFtZV0gPz8gXCJcIixcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICBleHBhbmRlZEFueVZhcmlhYmxlcyB8fD0gX3ZhcmlhYmxlc1trXSAhPT0gdjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGkrKztcbiAgICAgICAgfSB3aGlsZSAoZXhwYW5kZWRBbnlWYXJpYWJsZXMpO1xuXG4gICAgICAgIHJldHVybiBfdmFyaWFibGVzO1xuICAgIH1cblxuICAgIHN0YXRpYyB1bnNjYXBlJCRWYXJpYWJsZXMgKHZhcmlhYmxlczoge1trZXk6IHN0cmluZ106IHN0cmluZ30pIHtcbiAgICAgICAgZm9yIChjb25zdCBbaywgdl0gb2YgT2JqZWN0LmVudHJpZXModmFyaWFibGVzKSkge1xuICAgICAgICAgICAgdmFyaWFibGVzW2tdID0gVXRpbHMuZXhwYW5kVGV4dCh2LCB7fSk7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gdmFyaWFibGVzO1xuICAgIH1cblxuICAgIHN0YXRpYyBmaW5kRW52TWF0Y2hlZFZhcmlhYmxlcyAodmFyaWFibGVzOiB7W25hbWU6IHN0cmluZ106IENJQ0RWYXJpYWJsZX0sIGZpbGVWYXJpYWJsZXNEaXI/OiBzdHJpbmcsIGVudmlyb25tZW50Pzoge25hbWU6IHN0cmluZ30pIHtcbiAgICAgICAgY29uc3QgZW52TWF0Y2hlZFZhcmlhYmxlczoge1trZXk6IHN0cmluZ106IHN0cmluZ30gPSB7fTtcbiAgICAgICAgZm9yIChjb25zdCBbaywgdl0gb2YgT2JqZWN0LmVudHJpZXModmFyaWFibGVzKSkge1xuICAgICAgICAgICAgZm9yIChjb25zdCBlbnRyeSBvZiB2LmVudmlyb25tZW50cykge1xuICAgICAgICAgICAgICAgIGlmIChlbnZpcm9ubWVudD8ubmFtZS5tYXRjaChlbnRyeS5yZWdleHApIHx8IGVudHJ5LnJlZ2V4cC5zb3VyY2UgPT09IFwiLipcIikge1xuICAgICAgICAgICAgICAgICAgICBpZiAoZmlsZVZhcmlhYmxlc0RpciAhPSBudWxsICYmIHYudHlwZSA9PT0gXCJmaWxlXCIgJiYgIWVudHJ5LmZpbGVTb3VyY2UpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGVudk1hdGNoZWRWYXJpYWJsZXNba10gPSBgJHtmaWxlVmFyaWFibGVzRGlyfS8ke2t9YDtcbiAgICAgICAgICAgICAgICAgICAgICAgIGZzLm1rZGlycFN5bmMoYCR7ZmlsZVZhcmlhYmxlc0Rpcn1gKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGZzLndyaXRlRmlsZVN5bmMoYCR7ZmlsZVZhcmlhYmxlc0Rpcn0vJHtrfWAsIGVudHJ5LmNvbnRlbnQpO1xuICAgICAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKGZpbGVWYXJpYWJsZXNEaXIgIT0gbnVsbCAmJiB2LnR5cGUgPT09IFwiZmlsZVwiICYmIGVudHJ5LmZpbGVTb3VyY2UpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGVudk1hdGNoZWRWYXJpYWJsZXNba10gPSBgJHtmaWxlVmFyaWFibGVzRGlyfS8ke2t9YDtcbiAgICAgICAgICAgICAgICAgICAgICAgIGZzLm1rZGlycFN5bmMoYCR7ZmlsZVZhcmlhYmxlc0Rpcn1gKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGZzLmNvcHlGaWxlU3luYyhlbnRyeS5maWxlU291cmNlLCBgJHtmaWxlVmFyaWFibGVzRGlyfS8ke2t9YCk7XG4gICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBlbnZNYXRjaGVkVmFyaWFibGVzW2tdID0gZW50cnkuY29udGVudDtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIGVudk1hdGNoZWRWYXJpYWJsZXM7XG4gICAgfVxuXG4gICAgc3RhdGljIGdldFJ1bGVzUmVzdWx0IChvcHQ6IFJ1bGVSZXN1bHRPcHQsIGdpdERhdGE6IEdpdERhdGEsIGpvYldoZW46IHN0cmluZyA9IFwib25fc3VjY2Vzc1wiLCBqb2JBbGxvd0ZhaWx1cmU6IGJvb2xlYW4gfCB7ZXhpdF9jb2RlczogbnVtYmVyIHwgbnVtYmVyW119ID0gZmFsc2UpOiB7d2hlbjogc3RyaW5nOyBhbGxvd0ZhaWx1cmU6IGJvb2xlYW4gfCB7ZXhpdF9jb2RlczogbnVtYmVyIHwgbnVtYmVyW119OyB2YXJpYWJsZXM/OiB7W25hbWU6IHN0cmluZ106IHN0cmluZ319IHtcbiAgICAgICAgbGV0IHdoZW4gPSBcIm5ldmVyXCI7XG4gICAgICAgIGNvbnN0IHtldmFsdWF0ZVJ1bGVDaGFuZ2VzfSA9IG9wdC5hcmd2O1xuXG4gICAgICAgIC8vIG9wdGlvbmFsIG1hbnVhbCBqb2JzIGFsbG93RmFpbHVyZSBkZWZhdWx0cyB0byB0cnVlIGh0dHBzOi8vZG9jcy5naXRsYWIuY29tL2VlL2NpL2pvYnMvam9iX2NvbnRyb2wuaHRtbCN0eXBlcy1vZi1tYW51YWwtam9ic1xuICAgICAgICBsZXQgYWxsb3dGYWlsdXJlID0gam9iV2hlbiA9PT0gXCJtYW51YWxcIiA/IHRydWUgOiBqb2JBbGxvd0ZhaWx1cmU7XG4gICAgICAgIGxldCBydWxlVmFyaWFibGU6IHtbbmFtZTogc3RyaW5nXTogc3RyaW5nfSB8IHVuZGVmaW5lZDtcblxuICAgICAgICBmb3IgKGNvbnN0IHJ1bGUgb2Ygb3B0LnJ1bGVzKSB7XG4gICAgICAgICAgICBpZiAoIVV0aWxzLmV2YWx1YXRlUnVsZUlmKHJ1bGUuaWYsIG9wdC52YXJpYWJsZXMpKSBjb250aW51ZTtcbiAgICAgICAgICAgIGlmICghVXRpbHMuZXZhbHVhdGVSdWxlRXhpc3Qob3B0LmN3ZCwgcnVsZS5leGlzdHMpKSBjb250aW51ZTtcbiAgICAgICAgICAgIGlmIChldmFsdWF0ZVJ1bGVDaGFuZ2VzICYmICFVdGlscy5ldmFsdWF0ZVJ1bGVDaGFuZ2VzKGdpdERhdGEuYnJhbmNoZXMuZGVmYXVsdCwgcnVsZS5jaGFuZ2VzKSkgY29udGludWU7XG5cbiAgICAgICAgICAgIHdoZW4gPSBydWxlLndoZW4gPyBydWxlLndoZW4gOiBqb2JXaGVuO1xuICAgICAgICAgICAgYWxsb3dGYWlsdXJlID0gcnVsZS5hbGxvd19mYWlsdXJlID8/IGFsbG93RmFpbHVyZTtcbiAgICAgICAgICAgIHJ1bGVWYXJpYWJsZSA9IHJ1bGUudmFyaWFibGVzO1xuXG4gICAgICAgICAgICBicmVhazsgLy8gRWFybHkgcmV0dXJuLCB3aWxsIG5vdCBldmFsdWF0ZSB0aGUgcmVtYWluaW5nIHJ1bGVzXG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4ge3doZW4sIGFsbG93RmFpbHVyZSwgdmFyaWFibGVzOiBydWxlVmFyaWFibGV9O1xuICAgIH1cblxuICAgIHN0YXRpYyBldmFsdWF0ZVJ1bGVJZiAocnVsZUlmOiBzdHJpbmcgfCB1bmRlZmluZWQsIGVudnM6IHtba2V5OiBzdHJpbmddOiBzdHJpbmd9KTogYm9vbGVhbiB7XG4gICAgICAgIGlmIChydWxlSWYgPT09IHVuZGVmaW5lZCkgcmV0dXJuIHRydWU7XG4gICAgICAgIGxldCBldmFsU3RyID0gcnVsZUlmO1xuXG4gICAgICAgIGNvbnN0IGZsYWdzVG9CaW5hcnkgPSAoZmxhZ3M6IHN0cmluZyk6IG51bWJlciA9PiB7XG4gICAgICAgICAgICBsZXQgYmluYXJ5ID0gMDtcbiAgICAgICAgICAgIGlmIChmbGFncy5pbmNsdWRlcyhcImlcIikpIHtcbiAgICAgICAgICAgICAgICBiaW5hcnkgfD0gUkUySlMuQ0FTRV9JTlNFTlNJVElWRTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmIChmbGFncy5pbmNsdWRlcyhcInNcIikpIHtcbiAgICAgICAgICAgICAgICBiaW5hcnkgfD0gUkUySlMuRE9UQUxMO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKGZsYWdzLmluY2x1ZGVzKFwibVwiKSkge1xuICAgICAgICAgICAgICAgIGJpbmFyeSB8PSBSRTJKUy5NVUxUSUxJTkU7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gYmluYXJ5O1xuICAgICAgICB9O1xuXG4gICAgICAgIC8vIEV4cGFuZCBhbGwgdmFyaWFibGVzXG4gICAgICAgIGV2YWxTdHIgPSB0aGlzLmV4cGFuZFRleHRXaXRoKGV2YWxTdHIsIHtcbiAgICAgICAgICAgIHVuZXNjYXBlOiBKU09OLnN0cmluZ2lmeShcIiRcIiksXG4gICAgICAgICAgICB2YXJpYWJsZTogKG5hbWUpID0+IEpTT04uc3RyaW5naWZ5KGVudnNbbmFtZV0gPz8gbnVsbCkucmVwbGFjZUFsbChcIlxcXFxcXFxcXCIsIFwiXFxcXFwiKSxcbiAgICAgICAgfSk7XG4gICAgICAgIGNvbnN0IGV4cGFuZGVkRXZhbFN0ciA9IGV2YWxTdHI7XG5cbiAgICAgICAgLy8gU2NlbmFyaW8gd2hlbiBSSFMgaXMgYSA8cmVnZXg+XG4gICAgICAgIC8vIGh0dHBzOi8vcmVnZXhyLmNvbS84NXNqb1xuICAgICAgICBjb25zdCBwYXR0ZXJuMSA9IC9cXHMqKD88b3BlcmF0b3I+KD86PX4pfCg/OiF+KSlcXHMqXFwvKD88cmhzPi4qPylcXC8oPzxmbGFncz5baWdtc3V5XSopKFxcc3wkfFxcKSkvZztcbiAgICAgICAgZXZhbFN0ciA9IGV2YWxTdHIucmVwbGFjZShwYXR0ZXJuMSwgKF8sIG9wZXJhdG9yLCByaHMsIGZsYWdzLCByZW1haW5pbmdUb2tlbnMpID0+IHtcbiAgICAgICAgICAgIGxldCBfb3BlcmF0b3I7XG4gICAgICAgICAgICBzd2l0Y2ggKG9wZXJhdG9yKSB7XG4gICAgICAgICAgICAgICAgY2FzZSBcIj1+XCI6XG4gICAgICAgICAgICAgICAgICAgIF9vcGVyYXRvciA9IFwiIT1cIjtcbiAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgY2FzZSBcIiF+XCI6XG4gICAgICAgICAgICAgICAgICAgIF9vcGVyYXRvciA9IFwiPT1cIjtcbiAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgZGVmYXVsdDpcbiAgICAgICAgICAgICAgICAgICAgdGhyb3cgb3BlcmF0b3I7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBjb25zdCBfcmhzID0gSlNPTi5zdHJpbmdpZnkocmhzKTsgLy8gSlNPTi5zdHJpbmdpZnkgZm9yIGVzY2FwaW5nIGBcImBcbiAgICAgICAgICAgIGNvbnN0IGNvbnRhaW5zTm9uRXNjYXBlZFNsYXNoID0gLyg/PCFcXFxcKVxcLy8udGVzdChfcmhzKTtcbiAgICAgICAgICAgIGNvbnN0IGFzc2VydE1zZyA9IFtcbiAgICAgICAgICAgICAgICBcIkVycm9yIGF0dGVtcHRpbmcgdG8gZXZhbHVhdGUgdGhlIGZvbGxvd2luZyBydWxlczpcIixcbiAgICAgICAgICAgICAgICBcIiAgcnVsZXM6XCIsXG4gICAgICAgICAgICAgICAgYCAgICAtIGlmOiAnJHtleHBhbmRlZEV2YWxTdHJ9J2AsXG4gICAgICAgICAgICAgICAgXCJhcyByaHMgY29udGFpbnMgdW5lc2NhcGVkIHF1b3RlXCIsXG4gICAgICAgICAgICBdO1xuICAgICAgICAgICAgYXNzZXJ0KCFjb250YWluc05vbkVzY2FwZWRTbGFzaCwgYXNzZXJ0TXNnLmpvaW4oXCJcXG5cIikpO1xuICAgICAgICAgICAgY29uc3QgZmxhZ3NCaW5hcnkgPSBmbGFnc1RvQmluYXJ5KGZsYWdzKTtcbiAgICAgICAgICAgIHJldHVybiBgLm1hdGNoUkUySlMoUkUySlMuY29tcGlsZSgke19yaHN9LCAke2ZsYWdzQmluYXJ5fSkpICR7X29wZXJhdG9yfSBudWxsJHtyZW1haW5pbmdUb2tlbnN9YDtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgLy8gU2NlbmFyaW8gd2hlbiBSSFMgaXMgc3Vycm91bmRlZCBieSBzaW5nbGUvZG91YmxlLXF1b3Rlc1xuICAgICAgICAvLyBodHRwczovL3JlZ2V4ci5jb20vODV0MGdcbiAgICAgICAgY29uc3QgcGF0dGVybjIgPSAvXFxzKig/PG9wZXJhdG9yPj1+fCF+KVxccyooW1wiJ10pKD88cmhzPig/OlxcXFwufFteXFxcXF0pKj8pXFwyL2c7XG4gICAgICAgIGV2YWxTdHIgPSBldmFsU3RyLnJlcGxhY2UocGF0dGVybjIsIChfLCBvcGVyYXRvciwgX18sIHJocykgPT4ge1xuICAgICAgICAgICAgbGV0IF9vcGVyYXRvcjtcbiAgICAgICAgICAgIHN3aXRjaCAob3BlcmF0b3IpIHtcbiAgICAgICAgICAgICAgICBjYXNlIFwiPX5cIjpcbiAgICAgICAgICAgICAgICAgICAgX29wZXJhdG9yID0gXCIhPVwiO1xuICAgICAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgICBjYXNlIFwiIX5cIjpcbiAgICAgICAgICAgICAgICAgICAgX29wZXJhdG9yID0gXCI9PVwiO1xuICAgICAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgICBkZWZhdWx0OlxuICAgICAgICAgICAgICAgICAgICB0aHJvdyBvcGVyYXRvcjtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgY29uc3QgYXNzZXJ0TXNnID0gW1xuICAgICAgICAgICAgICAgIFwiUkhTICgke3Joc30pIG11c3QgYmUgYSByZWdleCBwYXR0ZXJuLiBEbyBub3QgcmVseSBvbiB0aGlzIGJlaGF2aW9yIVwiLFxuICAgICAgICAgICAgICAgIFwiUmVmZXIgdG8gaHR0cHM6Ly9kb2NzLmdpdGxhYi5jb20vZWUvY2kvam9icy9qb2JfcnVsZXMuaHRtbCN1bmV4cGVjdGVkLWJlaGF2aW9yLWZyb20tcmVn