gitlab-ci-local
Version:
Tired of pushing to test your .gitlab-ci.yml?
407 lines • 61.8 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 = 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 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 axiosConfig = Utils.getAxiosProxyConfig();
const { status } = await axios.get(`${protocol}://${domain}:${port}/${projectPath}/-/raw/${ref}/${file}`, axiosConfig);
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}`);
}
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 {};
}
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidXRpbHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJ1dGlscy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLGFBQWEsQ0FBQztBQUNyQixPQUFPLEVBQUMsS0FBSyxFQUFDLE1BQU0sT0FBTyxDQUFDO0FBQzVCLE9BQU8sS0FBSyxNQUFNLE9BQU8sQ0FBQztBQUMxQixPQUFPLEVBQUMsR0FBRyxFQUFVLE1BQU0sVUFBVSxDQUFDO0FBQ3RDLE9BQU8sRUFBRSxNQUFNLFVBQVUsQ0FBQztBQUMxQixPQUFPLFFBQVEsTUFBTSxVQUFVLENBQUM7QUFDaEMsT0FBTyxTQUFTLE1BQU0sV0FBVyxDQUFDO0FBQ2xDLE9BQU8sS0FBSyxNQUFNLE9BQU8sQ0FBQztBQUMxQixPQUFPLE1BQU0sTUFBTSxRQUFRLENBQUM7QUFFNUIsT0FBTyxFQUFDLE9BQU8sRUFBWSxNQUFNLGVBQWUsQ0FBQztBQUNqRCxPQUFPLE1BQU0sTUFBTSxRQUFRLENBQUM7QUFDNUIsT0FBTyxVQUFVLE1BQU0sWUFBWSxDQUFDO0FBQ3BDLE9BQU8sS0FBMkIsTUFBTSxPQUFPLENBQUM7QUFDaEQsT0FBTyxJQUFJLE1BQU0sTUFBTSxDQUFDO0FBZXhCLE1BQU0sT0FBTyxLQUFLO0lBQ2QsTUFBTSxDQUFDLFNBQVMsQ0FBRSxPQUFpQixFQUFFLEdBQUcsR0FBRyxPQUFPLENBQUMsR0FBRyxFQUFFO1FBQ3BELE9BQU8sS0FBSyxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLEVBQUUsRUFBQyxLQUFLLEVBQUUsTUFBTSxFQUFFLEdBQUcsRUFBQyxDQUFDLENBQUM7SUFDL0QsQ0FBQztJQUVELE1BQU0sQ0FBQyxJQUFJLENBQUUsV0FBbUIsRUFBRSxHQUFHLEdBQUcsT0FBTyxDQUFDLEdBQUcsRUFBRTtRQUNqRCxPQUFPLEtBQUssQ0FBQyxXQUFXLEVBQUUsRUFBQyxLQUFLLEVBQUUsTUFBTSxFQUFFLEdBQUcsRUFBQyxDQUFDLENBQUM7SUFDcEQsQ0FBQztJQUVELE1BQU0sQ0FBQyxLQUFLLENBQUUsT0FBaUIsRUFBRSxHQUFHLEdBQUcsT0FBTyxDQUFDLEdBQUcsRUFBRTtRQUNoRCxPQUFPLEtBQUssQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLEVBQUUsT0FBTyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFDLEdBQUcsRUFBQyxDQUFDLENBQUM7SUFDdEQsQ0FBQztJQUVELE1BQU0sQ0FBQyxTQUFTLENBQUUsT0FBaUIsRUFBRSxHQUFHLEdBQUcsT0FBTyxDQUFDLEdBQUcsRUFBRTtRQUNwRCxPQUFPLEtBQUssQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxFQUFFLE9BQU8sQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBQyxHQUFHLEVBQUMsQ0FBQyxDQUFDO0lBQzNELENBQUM7SUFFRCxNQUFNLENBQUMsS0FBSyxDQUFFLEdBQVc7UUFDckIsT0FBTyxHQUFHLENBQUMsT0FBTyxDQUFDLGNBQWMsRUFBRSxFQUFFLENBQUMsQ0FBQyxPQUFPLENBQUMsYUFBYSxFQUFFLEVBQUUsQ0FBQyxDQUFDO0lBQ3RFLENBQUM7SUFFRCxNQUFNLENBQUMsZ0JBQWdCLENBQUUsT0FBZTtRQUNwQyxPQUFPLE9BQU8sQ0FBQyxPQUFPLENBQUMsVUFBVSxFQUFFLENBQUMsS0FBSyxFQUFFLEVBQUU7WUFDekMsT0FBTyxTQUFTLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxDQUFDO1FBQ25DLENBQUMsQ0FBQyxDQUFDO0lBQ1AsQ0FBQztJQUVELE1BQU0sQ0FBQyxjQUFjLENBQUUsQ0FBUztRQUM1QixPQUFPLElBQUksQ0FBQyxDQUFDLE9BQU8sQ0FBQyxJQUFJLEVBQUUsU0FBUyxDQUFDLEdBQUcsQ0FBQyxDQUFDLDRCQUE0QjtJQUMxRSxDQUFDO0lBRUQsTUFBTSxDQUFDLGNBQWMsQ0FBRSxVQUFlLEVBQUUsUUFBaUQ7UUFDckYsS0FBSyxNQUFNLENBQUMsT0FBTyxFQUFFLE9BQU8sQ0FBQyxJQUFJLE1BQU0sQ0FBQyxPQUFPLENBQU0sVUFBVSxDQUFDLEVBQUUsQ0FBQztZQUMvRCxJQUFJLEdBQUcsQ0FBQyxlQUFlLENBQUMsR0FBRyxDQUFDLE9BQU8sQ0FBQyxJQUFJLE9BQU8sQ0FBQyxDQUFDLENBQUMsQ0FBQyxVQUFVLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQztnQkFDakUsU0FBUztZQUNiLENBQUM7WUFDRCxRQUFRLENBQUMsT0FBTyxFQUFFLE9BQU8sQ0FBQyxDQUFDO1FBQy9CLENBQUM7SUFDTCxDQUFDO0lBRUQsTUFBTSxDQUFDLDZCQUE2QixDQUFFLElBQXdCLEVBQUUsTUFBeUIsRUFBRSxVQUFlO1FBQ3RHLE1BQU0sUUFBUSxHQUFhLEVBQUUsQ0FBQztRQUM5QixNQUFNLGlCQUFpQixHQUFHLE1BQU0sQ0FBQyxPQUFPLENBQUMsVUFBVSxDQUFDLEtBQUssQ0FBQyxDQUFDO1FBQzNELElBQUksQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLEVBQUU7WUFDZixNQUFNLFVBQVUsR0FBRyxNQUFNLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUMsQ0FBQztZQUM3QyxJQUFJLFVBQVUsR0FBRyxpQkFBaUIsRUFBRSxDQUFDO2dCQUNqQyxRQUFRLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsQ0FBQztZQUM1QixDQUFDO1FBQ0wsQ0FBQyxDQUFDLENBQUM7UUFDSCxPQUFPLFFBQVEsQ0FBQztJQUNwQixDQUFDO0lBRUQsTUFBTSxDQUFDLEtBQUssQ0FBQyxrQkFBa0IsQ0FBRSxHQUFXLEVBQUUsUUFBZ0IsRUFBRSxhQUFxQixFQUFFLE9BQWU7UUFDbEcsTUFBTSxPQUFPLEdBQUcsTUFBTSxFQUFFLENBQUMsUUFBUSxDQUFDLEdBQUcsR0FBRyxJQUFJLFFBQVEsV0FBVyxPQUFPLE1BQU0sRUFBRSxNQUFNLENBQUMsQ0FBQztRQUV0RixNQUFNLEtBQUssR0FBRyxLQUFLLENBQUMsT0FBTyxDQUN2QixhQUFhO2FBQ1IsT0FBTyxDQUFDLEtBQUssRUFBRSxFQUFFLENBQUM7YUFDbEIsT0FBTyxDQUFDLEtBQUssRUFBRSxFQUFFLENBQUMsRUFDdkIsS0FBSyxDQUFDLFNBQVMsQ0FDbEIsQ0FBQztRQUNGLE1BQU0sT0FBTyxHQUFHLEtBQUssQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLGFBQWEsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDO1FBQ3pELElBQUksT0FBTyxDQUFDLE1BQU0sS0FBSyxDQUFDO1lBQUUsT0FBTyxHQUFHLENBQUM7UUFFckMsTUFBTSxTQUFTLEdBQUcsT0FBTyxDQUFDLE9BQU8sQ0FBQyxNQUFNLEdBQUcsQ0FBQyxDQUFDLENBQUM7UUFDOUMsTUFBTSxNQUFNLEdBQUcsZUFBZSxDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDLElBQUksU0FBUyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFDbEUsSUFBSSxDQUFDLE1BQU07WUFBRSxPQUFPLEdBQUcsQ0FBQztRQUN4QixPQUFPLE1BQU0sQ0FBQyxDQUFDLENBQUMsSUFBSSxHQUFHLENBQUM7SUFDNUIsQ0FBQztJQUVELE1BQU0sQ0FBQyxhQUFhLENBQUUsTUFBNkIsRUFBRSxHQUFtQixFQUFFLENBQVMsRUFBRSxHQUFxQjtRQUN0RyxJQUFJLENBQUMsS0FBSyxHQUFHLENBQUMsTUFBTSxHQUFHLENBQUMsRUFBRSxDQUFDO1lBQ3ZCLE1BQU0sQ0FBQyxLQUFLLENBQUEsZUFBZSxHQUFHLENBQUMsSUFBSSxHQUFHLENBQUMsQ0FBQztRQUM1QyxDQUFDO2FBQU0sQ0FBQztZQUNKLE1BQU0sQ0FBQyxLQUFLLENBQUEsZUFBZSxHQUFHLENBQUMsSUFBSSxLQUFLLENBQUMsQ0FBQztRQUM5QyxDQUFDO0lBQ0wsQ0FBQztJQUVPLE1BQU0sQ0FBQyxjQUFjLENBQUUsSUFBUyxFQUFFLFVBQXNCO1FBQzVELElBQUksT0FBTyxJQUFJLEtBQUssUUFBUSxFQUFFLENBQUM7WUFDM0IsT0FBTyxJQUFJLENBQUM7UUFDaEIsQ0FBQztRQUVELE9BQU8sSUFBSSxDQUFDLE9BQU8sQ0FDZiw4Q0FBOEMsRUFBRSwyQkFBMkI7UUFDM0UsQ0FBQyxNQUFNLEVBQUUsTUFBTSxFQUFFLElBQUksRUFBRSxJQUFJLEVBQUUsRUFBRTtZQUMzQixJQUFJLE9BQU8sTUFBTSxLQUFLLFdBQVcsRUFBRSxDQUFDO2dCQUNoQyxPQUFPLFVBQVUsQ0FBQyxRQUFRLENBQUM7WUFDL0IsQ0FBQztpQkFBTSxDQUFDO2dCQUNKLE1BQU0sSUFBSSxHQUFHLElBQUksSUFBSSxJQUFJLENBQUM7Z0JBQzFCLE1BQU0sQ0FBQyxJQUFJLEVBQUUsZ0NBQWdDLENBQUMsQ0FBQztnQkFDL0MsT0FBTyxHQUFHLFVBQVUsQ0FBQyxRQUFRLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQztZQUMxQyxDQUFDO1FBQ0wsQ0FBQyxDQUNKLENBQUM7SUFDTixDQUFDO0lBRUQsTUFBTSxDQUFDLFVBQVUsQ0FBRSxJQUFTLEVBQUUsSUFBNkI7UUFDdkQsT0FBTyxJQUFJLENBQUMsY0FBYyxDQUFDLElBQUksRUFBRTtZQUM3QixRQUFRLEVBQUUsR0FBRztZQUNiLFFBQVEsRUFBRSxDQUFDLElBQUksRUFBRSxFQUFFLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxJQUFJLEVBQUU7U0FDdkMsQ0FBQyxDQUFDO0lBQ1AsQ0FBQztJQUVELE1BQU0sQ0FBQyxlQUFlLENBQUUsU0FBa0M7UUFDdEQsTUFBTSxVQUFVLEdBQUcsRUFBQyxHQUFHLFNBQVMsRUFBQyxDQUFDLENBQUMsdURBQXVEO1FBQzFGLElBQUksb0JBQW9CLEVBQUUsQ0FBQyxHQUFHLENBQUMsQ0FBQztRQUNoQyxHQUFHLENBQUM7WUFDQSxNQUFNLENBQUMsQ0FBQyxHQUFHLEdBQUcsRUFBRSxxREFBcUQsQ0FBQyxDQUFDO1lBQ3ZFLG9CQUFvQixHQUFHLEtBQUssQ0FBQztZQUM3QixLQUFLLE1BQU0sQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLElBQUksTUFBTSxDQUFDLE9BQU8sQ0FBQyxVQUFVLENBQUMsRUFBRSxDQUFDO2dCQUM5QyxNQUFNLGVBQWUsR0FBRyxFQUFDLEdBQUcsVUFBVSxFQUFDLENBQUM7Z0JBQ3hDLE9BQU8sZUFBZSxDQUFDLENBQUMsQ0FBQyxDQUFDO2dCQUMxQiw2REFBNkQ7Z0JBQzdELDJEQUEyRDtnQkFDM0QsOERBQThEO2dCQUM5RCxnRUFBZ0U7Z0JBQ2hFLGdCQUFnQjtnQkFDaEIsVUFBVSxDQUFDLENBQUMsQ0FBQyxHQUFHLEtBQUssQ0FBQyxjQUFjLENBQUMsQ0FBQyxFQUFFO29CQUNwQyxRQUFRLEVBQUUsSUFBSTtvQkFDZCxRQUFRLEVBQUUsQ0FBQyxJQUFJLEVBQUUsRUFBRSxDQUFDLGVBQWUsQ0FBQyxJQUFJLENBQUMsSUFBSSxFQUFFO2lCQUNsRCxDQUFDLENBQUM7Z0JBQ0gsb0JBQW9CLEtBQUssVUFBVSxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsQ0FBQztZQUNqRCxDQUFDO1lBQ0QsQ0FBQyxFQUFFLENBQUM7UUFDUixDQUFDLFFBQVEsb0JBQW9CLEVBQUU7UUFFL0IsT0FBTyxVQUFVLENBQUM7SUFDdEIsQ0FBQztJQUVELE1BQU0sQ0FBQyxrQkFBa0IsQ0FBRSxTQUFrQztRQUN6RCxLQUFLLE1BQU0sQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLElBQUksTUFBTSxDQUFDLE9BQU8sQ0FBQyxTQUFTLENBQUMsRUFBRSxDQUFDO1lBQzdDLFNBQVMsQ0FBQyxDQUFDLENBQUMsR0FBRyxLQUFLLENBQUMsVUFBVSxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQztRQUMzQyxDQUFDO1FBRUQsT0FBTyxTQUFTLENBQUM7SUFDckIsQ0FBQztJQUVELE1BQU0sQ0FBQyx1QkFBdUIsQ0FBRSxTQUF5QyxFQUFFLGdCQUF5QixFQUFFLFdBQTRCO1FBQzlILE1BQU0sbUJBQW1CLEdBQTRCLEVBQUUsQ0FBQztRQUN4RCxLQUFLLE1BQU0sQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLElBQUksTUFBTSxDQUFDLE9BQU8sQ0FBQyxTQUFTLENBQUMsRUFBRSxDQUFDO1lBQzdDLEtBQUssTUFBTSxLQUFLLElBQUksQ0FBQyxDQUFDLFlBQVksRUFBRSxDQUFDO2dCQUNqQyxJQUFJLFdBQVcsRUFBRSxJQUFJLENBQUMsS0FBSyxDQUFDLEtBQUssQ0FBQyxNQUFNLENBQUMsSUFBSSxLQUFLLENBQUMsTUFBTSxDQUFDLE1BQU0sS0FBSyxJQUFJLEVBQUUsQ0FBQztvQkFDeEUsSUFBSSxnQkFBZ0IsSUFBSSxJQUFJLElBQUksQ0FBQyxDQUFDLElBQUksS0FBSyxNQUFNLElBQUksQ0FBQyxLQUFLLENBQUMsVUFBVSxFQUFFLENBQUM7d0JBQ3JFLG1CQUFtQixDQUFDLENBQUMsQ0FBQyxHQUFHLEdBQUcsZ0JBQWdCLElBQUksQ0FBQyxFQUFFLENBQUM7d0JBQ3BELEVBQUUsQ0FBQyxVQUFVLENBQUMsR0FBRyxnQkFBZ0IsRUFBRSxDQUFDLENBQUM7d0JBQ3JDLEVBQUUsQ0FBQyxhQUFhLENBQUMsR0FBRyxnQkFBZ0IsSUFBSSxDQUFDLEVBQUUsRUFBRSxLQUFLLENBQUMsT0FBTyxDQUFDLENBQUM7b0JBQ2hFLENBQUM7eUJBQU0sSUFBSSxnQkFBZ0IsSUFBSSxJQUFJLElBQUksQ0FBQyxDQUFDLElBQUksS0FBSyxNQUFNLElBQUksS0FBSyxDQUFDLFVBQVUsRUFBRSxDQUFDO3dCQUMzRSxtQkFBbUIsQ0FBQyxDQUFDLENBQUMsR0FBRyxHQUFHLGdCQUFnQixJQUFJLENBQUMsRUFBRSxDQUFDO3dCQUNwRCxFQUFFLENBQUMsVUFBVSxDQUFDLEdBQUcsZ0JBQWdCLEVBQUUsQ0FBQyxDQUFDO3dCQUNyQyxFQUFFLENBQUMsWUFBWSxDQUFDLEtBQUssQ0FBQyxVQUFVLEVBQUUsR0FBRyxnQkFBZ0IsSUFBSSxDQUFDLEVBQUUsQ0FBQyxDQUFDO29CQUNsRSxDQUFDO3lCQUFNLENBQUM7d0JBQ0osbUJBQW1CLENBQUMsQ0FBQyxDQUFDLEdBQUcsS0FBSyxDQUFDLE9BQU8sQ0FBQztvQkFDM0MsQ0FBQztvQkFDRCxNQUFNO2dCQUNWLENBQUM7WUFDTCxDQUFDO1FBQ0wsQ0FBQztRQUNELE9BQU8sbUJBQW1CLENBQUM7SUFDL0IsQ0FBQztJQUVELE1BQU0sQ0FBQyxjQUFjLENBQUUsR0FBa0IsRUFBRSxPQUFnQixFQUFFLFVBQWtCLFlBQVksRUFBRSxrQkFBNkQsS0FBSztRQUMzSixJQUFJLElBQUksR0FBRyxPQUFPLENBQUM7UUFDbkIsTUFBTSxFQUFDLG1CQUFtQixFQUFDLEdBQUcsR0FBRyxDQUFDLElBQUksQ0FBQztRQUV2Qyw4SEFBOEg7UUFDOUgsSUFBSSxZQUFZLEdBQUcsT0FBTyxLQUFLLFFBQVEsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxlQUFlLENBQUM7UUFDakUsSUFBSSxZQUFrRCxDQUFDO1FBRXZELEtBQUssTUFBTSxJQUFJLElBQUksR0FBRyxDQUFDLEtBQUssRUFBRSxDQUFDO1lBQzNCLElBQUksQ0FBQyxLQUFLLENBQUMsY0FBYyxDQUFDLElBQUksQ0FBQyxFQUFFLEVBQUUsR0FBRyxDQUFDLFNBQVMsQ0FBQztnQkFBRSxTQUFTO1lBQzVELElBQUksQ0FBQyxLQUFLLENBQUMsaUJBQWlCLENBQUMsR0FBRyxDQUFDLEdBQUcsRUFBRSxJQUFJLENBQUMsTUFBTSxDQUFDO2dCQUFFLFNBQVM7WUFDN0QsSUFBSSxtQkFBbUIsSUFBSSxDQUFDLEtBQUssQ0FBQyxtQkFBbUIsQ0FBQyxPQUFPLENBQUMsUUFBUSxDQUFDLE9BQU8sRUFBRSxJQUFJLENBQUMsT0FBTyxFQUFFLEdBQUcsQ0FBQyxHQUFHLENBQUM7Z0JBQUUsU0FBUztZQUVqSCxJQUFJLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsT0FBTyxDQUFDO1lBQ3ZDLFlBQVksR0FBRyxJQUFJLENBQUMsYUFBYSxJQUFJLFlBQVksQ0FBQztZQUNsRCxZQUFZLEdBQUcsSUFBSSxDQUFDLFNBQVMsQ0FBQztZQUU5QixNQUFNLENBQUMsc0RBQXNEO1FBQ2pFLENBQUM7UUFFRCxPQUFPLEVBQUMsSUFBSSxFQUFFLFlBQVksRUFBRSxTQUFTLEVBQUUsWUFBWSxFQUFDLENBQUM7SUFDekQsQ0FBQztJQUVELE1BQU0sQ0FBQyxjQUFjLENBQUUsTUFBMEIsRUFBRSxJQUE2QjtRQUM1RSxJQUFJLE1BQU0sS0FBSyxTQUFTO1lBQUUsT0FBTyxJQUFJLENBQUM7UUFDdEMsSUFBSSxPQUFPLEdBQUcsTUFBTSxDQUFDO1FBRXJCLE1BQU0sYUFBYSxHQUFHLENBQUMsS0FBYSxFQUFVLEVBQUU7WUFDNUMsSUFBSSxNQUFNLEdBQUcsQ0FBQyxDQUFDO1lBQ2YsSUFBSSxLQUFLLENBQUMsUUFBUSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUM7Z0JBQ3RCLE1BQU0sSUFBSSxLQUFLLENBQUMsZ0JBQWdCLENBQUM7WUFDckMsQ0FBQztZQUNELElBQUksS0FBSyxDQUFDLFFBQVEsQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDO2dCQUN0QixNQUFNLElBQUksS0FBSyxDQUFDLE1BQU0sQ0FBQztZQUMzQixDQUFDO1lBQ0QsSUFBSSxLQUFLLENBQUMsUUFBUSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUM7Z0JBQ3RCLE1BQU0sSUFBSSxLQUFLLENBQUMsU0FBUyxDQUFDO1lBQzlCLENBQUM7WUFDRCxPQUFPLE1BQU0sQ0FBQztRQUNsQixDQUFDLENBQUM7UUFFRix1QkFBdUI7UUFDdkIsT0FBTyxHQUFHLElBQUksQ0FBQyxjQUFjLENBQUMsT0FBTyxFQUFFO1lBQ25DLFFBQVEsRUFBRSxJQUFJLENBQUMsU0FBUyxDQUFDLEdBQUcsQ0FBQztZQUM3QixRQUFRLEVBQUUsQ0FBQyxJQUFJLEVBQUUsRUFBRSxDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxJQUFJLElBQUksQ0FBQyxDQUFDLFVBQVUsQ0FBQyxNQUFNLEVBQUUsSUFBSSxDQUFDO1NBQ2xGLENBQUMsQ0FBQztRQUNILE1BQU0sZUFBZSxHQUFHLE9BQU8sQ0FBQztRQUVoQyxpQ0FBaUM7UUFDakMsMkJBQTJCO1FBQzNCLE1BQU0sUUFBUSxHQUFHLDhFQUE4RSxDQUFDO1FBQ2hHLE9BQU8sR0FBRyxPQUFPLENBQUMsT0FBTyxDQUFDLFFBQVEsRUFBRSxDQUFDLENBQUMsRUFBRSxRQUFRLEVBQUUsR0FBRyxFQUFFLEtBQUssRUFBRSxlQUFlLEVBQUUsRUFBRTtZQUM3RSxJQUFJLFNBQVMsQ0FBQztZQUNkLFFBQVEsUUFBUSxFQUFFLENBQUM7Z0JBQ2YsS0FBSyxJQUFJO29CQUNMLFNBQVMsR0FBRyxJQUFJLENBQUM7b0JBQ2pCLE1BQU07Z0JBQ1YsS0FBSyxJQUFJO29CQUNMLFNBQVMsR0FBRyxJQUFJLENBQUM7b0JBQ2pCLE1BQU07Z0JBQ1Y7b0JBQ0ksTUFBTSxRQUFRLENBQUM7WUFDdkIsQ0FBQztZQUNELE1BQU0sSUFBSSxHQUFHLElBQUksQ0FBQyxTQUFTLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxrQ0FBa0M7WUFDcEUsTUFBTSx1QkFBdUIsR0FBRyxXQUFXLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDO1lBQ3ZELE1BQU0sU0FBUyxHQUFHO2dCQUNkLG1EQUFtRDtnQkFDbkQsVUFBVTtnQkFDVixjQUFjLGVBQWUsR0FBRztnQkFDaEMsaUNBQWlDO2FBQ3BDLENBQUM7WUFDRixNQUFNLENBQUMsQ0FBQyx1QkFBdUIsRUFBRSxTQUFTLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUM7WUFDdkQsTUFBTSxXQUFXLEdBQUcsYUFBYSxDQUFDLEtBQUssQ0FBQyxDQUFDO1lBQ3pDLE9BQU8sNkJBQTZCLElBQUksS0FBSyxXQUFXLE1BQU0sU0FBUyxRQUFRLGVBQWUsRUFBRSxDQUFDO1FBQ3JHLENBQUMsQ0FBQyxDQUFDO1FBRUgsMERBQTBEO1FBQzFELDJCQUEyQjtRQUMzQixNQUFNLFFBQVEsR0FBRywwREFBMEQsQ0FBQztRQUM1RSxPQUFPLEdBQUcsT0FBTyxDQUFDLE9BQU8sQ0FBQyxRQUFRLEVBQUUsQ0FBQyxDQUFDLEVBQUUsUUFBUSxFQUFFLEVBQUUsRUFBRSxHQUFHLEVBQUUsRUFBRTtZQUN6RCxJQUFJLFNBQVMsQ0FBQztZQUNkLFFBQVEsUUFBUSxFQUFFLENBQUM7Z0JBQ2YsS0FBSyxJQUFJO29CQUNMLFNBQVMsR0FBRyxJQUFJLENBQUM7b0JBQ2pCLE1BQU07Z0JBQ1YsS0FBSyxJQUFJO29CQUNMLFNBQVMsR0FBRyxJQUFJLENBQUM7b0JBQ2pCLE1BQU07Z0JBQ1Y7b0JBQ0ksTUFBTSxRQUFRLENBQUM7WUFDdkIsQ0FBQztZQUVELE1BQU0sU0FBUyxHQUFHO2dCQUNkLHFFQUFxRTtnQkFDckUsd0lBQXdJO2FBQzNJLENBQUM7WUFDRixNQUFNLENBQUMsQ0FBQyxlQUFlLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLEVBQUUsU0FBUyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDO1lBRTFELE1BQU0sS0FBSyxHQUFHLHVDQUF1QyxDQUFDO1lBQ3RELE1BQU0sSUFBSSxHQUFHLEdBQUcsQ0FBQyxPQUFPLENBQUMsS0FBSyxFQUFFLENBQUMsQ0FBUyxFQUFFLE9BQWUsRUFBRSxLQUFhLEVBQUUsRUFBRTtnQkFDMUUsTUFBTSxXQUFXLEdBQUcsYUFBYSxDQUFDLEtBQUssQ0FBQyxDQUFDO2dCQUN6QyxPQUFPLGtCQUFrQixPQUFPLE1BQU0sV0FBVyxHQUFHLENBQUM7WUFDekQsQ0FBQyxDQUFDLENBQUM7WUFDSCxPQUFPLGVBQWUsSUFBSSxLQUFLLFNBQVMsT0FBTyxDQUFDO1FBQ3BELENBQUMsQ0FBQyxDQUFDO1FBRUgsT0FBTyxHQUFHLE9BQU8sQ0FBQyxPQUFPLENBQUMscUNBQXFDLEVBQUUsT0FBTyxDQUFDLENBQUM7UUFDMUUsT0FBTyxHQUFHLE9BQU8sQ0FBQyxPQUFPLENBQUMscUNBQXFDLEVBQUUsTUFBTSxDQUFDLENBQUM7UUFFekUsT0FBTyxHQUFHLE9BQU8sQ0FBQyxJQUFJLEVBQUUsQ0FBQztRQUV6QixJQUFJLEdBQUcsQ0FBQztRQUNSLElBQUksQ0FBQztZQUNBLE1BQWMsQ0FBQyxLQUFLLEdBQUcsS0FBSyxDQUFDLENBQUMsb0NBQW9DO1lBQ25FLEdBQUcsR0FBRyxDQUFDLENBQUMsRUFBRSxJQUFJLENBQUMsQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLHVEQUF1RDtZQUNqRixPQUFRLE1BQWMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxVQUFVO1FBQzVDLENBQUM7UUFBQyxNQUFNLENBQUM7WUFDTCxNQUFNLFNBQVMsR0FBRztnQkFDZCxtREFBbUQ7Z0JBQ25ELFVBQVU7Z0JBQ1YsY0FBYyxlQUFlLEdBQUc7Z0JBQ2hDLElBQUk7Z0JBQ0osZUFBZTtnQkFDZixHQUFHLE9BQU8sRUFBRTtnQkFDWixLQUFLO2FBQ1IsQ0FBQztZQUNGLE1BQU0sQ0FBQyxLQUFLLEVBQUUsU0FBUyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDO1FBQ3hDLENBQUM7UUFDRCxPQUFPLE9BQU8sQ0FBQyxHQUFHLENBQUMsQ0FBQztJQUN4QixDQUFDO0lBRUQsTUFBTSxDQUFDLGlCQUFpQixDQUFFLEdBQVcsRUFBRSxVQUFvRDtRQUN2RixJQUFJLFVBQVUsS0FBSyxTQUFTO1lBQUUsT0FBTyxJQUFJLENBQUM7UUFFMUMsK0NBQStDO1FBQy9DLElBQUksQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLFVBQVUsQ0FBQztZQUFFLFVBQVUsR0FBRyxVQUFVLENBQUMsS0FBSyxDQUFDO1FBRTlELEtBQUssTUFBTSxPQUFPLElBQUksVUFBVSxFQUFFLENBQUM7WUFDL0IsSUFBSSxPQUFPLElBQUksRUFBRSxFQUFFLENBQUM7Z0JBQ2hCLFNBQVM7WUFDYixDQUFDO1lBQ0QsSUFBSSxNQUFNLENBQUMsSUFBSSxDQUFDLE9BQU8sRUFBRSxFQUFDLEdBQUcsRUFBRSxJQUFJLEVBQUUsR0FBRyxFQUFDLENBQUMsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxFQUFFLENBQUM7Z0JBQ3BELE9BQU8sSUFBSSxDQUFDO1lBQ2hCLENBQUM7UUFDTCxDQUFDO1FBQ0QsT0FBTyxLQUFLLENBQUM7SUFDakIsQ0FBQztJQUVELE1BQU0sQ0FBQyxtQkFBbUIsQ0FBRSxhQUFxQixFQUFFLFdBQXFELEVBQUUsR0FBVztRQUNqSCxJQUFJLFdBQVcsS0FBSyxTQUFTO1lBQUUsT0FBTyxJQUFJLENBQUM7UUFFM0MsaURBQWlEO1FBQ2pELElBQUksQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLFdBQVcsQ0FBQztZQUFFLFdBQVcsR0FBRyxXQUFXLENBQUMsS0FBSyxDQUFDO1FBRWpFLHlEQUF5RDtRQUN6RCw4SEFBOEg7UUFDOUgsZ0ZBQWdGO1FBQ2hGLE9BQU8sVUFBVSxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsWUFBWSxDQUFDLFVBQVUsYUFBYSxFQUFFLEVBQUUsR0FBRyxDQUFDLEVBQUUsV0FBVyxFQUFFO1lBQ3RGLFFBQVEsRUFBRSxJQUFJO1lBQ2QsU0FBUyxFQUFFLElBQUk7WUFDZixLQUFLLEVBQUUsS0FBSztZQUNaLEdBQUcsRUFBRSxJQUFJO1NBQ1osQ0FBQyxDQUFDO0lBQ1AsQ0FBQztJQUVELE1BQU0sQ0FBQyxTQUFTLENBQUUsR0FBVyxFQUFFLEdBQVcsRUFBRSxNQUFjLE9BQU8sQ0FBQyxHQUFHLEVBQUU7UUFDbkUsSUFBSSxNQUFNLEdBQUcsRUFBRSxDQUFDO1FBQ2hCLElBQUksSUFBSSxDQUFDLFVBQVUsQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDO1lBQ3ZCLE1BQU0sR0FBRyxHQUFHLENBQUM7UUFDakIsQ0FBQzthQUFNLENBQUM7WUFDSixNQUFNLEdBQUcsSUFBSSxDQUFDLE9BQU8sQ0FBQyxHQUFHLEVBQUUsR0FBRyxDQUFDLENBQUM7UUFDcEMsQ0FBQztRQUVELElBQUksTUFBTSxHQUFHLEVBQUUsQ0FBQztRQUNoQixJQUFJLElBQUksQ0FBQyxVQUFVLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQztZQUN2QixNQUFNLEdBQUcsR0FBRyxDQUFDO1FBQ2pCLENBQUM7YUFBTSxDQUFDO1lBQ0osTUFBTSxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUMsR0FBRyxFQUFFLEdBQUcsQ0FBQyxDQUFDO1FBQ3BDLENBQUM7UUFFRCxNQUFNLFFBQVEsR0FBRyxJQUFJLENBQUMsUUFBUSxDQUFDLE1BQU0sRUFBRSxNQUFNLENBQUMsQ0FBQztRQUMvQyxPQUFPLENBQUMsUUFBUSxDQUFDLFVBQVUsQ0FBQyxJQUFJLENBQUMsQ0FBQztJQUN0QyxDQUFDO0lBRUQsTUFBTSxDQUFDLEtBQUssQ0FBQyxpQkFBaUIsQ0FBRSxHQUFXLEVBQUUsUUFBZ0IsRUFBRSxNQUFjO1FBQ3pFLE1BQU0sSUFBSSxHQUFHLE9BQU8sQ0FBQyxNQUFNLEVBQUUsQ0FBQztRQUM5QixNQUFNLEVBQUUsQ0FBQyxNQUFNLENBQUMsR0FBRyxHQUFHLElBQUksUUFBUSxXQUFXLE1BQU0sRUFBRSxDQUFDLENBQUM7UUFDdkQsTUFBTSxLQUFLLENBQUMsSUFBSSxDQUFDLHFIQUFxSCxRQUFRLFFBQVEsUUFBUSxXQUFXLE1BQU0sR0FBRyxFQUFFLEdBQUcsQ0FBQyxDQUFDO1FBQ3pMLE9BQU8sRUFBQyxXQUFXLEVBQUUsT0FBTyxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsRUFBQyxDQUFDO0lBQy9DLENBQUM7SUFFRCxNQUFNLENBQUMsS0FBSyxDQUFDLGFBQWEsQ0FBRSxHQUFXLEVBQUUsS0FBZTtRQUNwRCxNQUFNLFFBQVEsR0FBc0IsRUFBRSxDQUFDO1FBRXZDLEtBQUssQ0FBQyxPQUFPLENBQUMsQ0FBQyxJQUFJLEVBQUUsRUFBRTtZQUNuQixRQUFRLENBQUMsSUFBSSxDQUFDLElBQUksT0FBTyxDQUFDLENBQUMsT0FBTyxFQUFFLE1BQU0sRUFBRSxFQUFFO2dCQUMxQyxJQUFJLENBQUUsRUFBRSxDQUFDLGNBQWMsQ0FBQyxJQUFJLENBQUM7b0JBQUUsT0FBTyxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsR0FBRyxFQUFFLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQyxpR0FBaUc7Z0JBQ25LLFFBQVEsQ0FBQyxJQUFJLENBQUMsSUFBSSxFQUFFLENBQUMsR0FBRyxFQUFFLElBQUksRUFBRSxFQUFFO29CQUM5QixJQUFJLEdBQUcsRUFBRSxDQUFDO3dCQUNOLE9BQU8sTUFBTSxDQUFDLEdBQUcsQ0FBQyxDQUFDO29CQUN2QixDQUFDO29CQUNELE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FBQztnQkFDbEIsQ0FBQyxDQUFDLENBQUM7WUFDUCxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQ1IsQ0FBQyxDQUFDLENBQUM7UUFFSCxNQUFNLE1BQU0sR0FBRyxNQUFNLE9BQU8sQ0FBQyxHQUFHLENBQUMsUUFBUSxDQUFDLENBQUM7UUFDM0MsT0FBTyxRQUFRLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDO0lBQ3JDLENBQUM7SUFFRCxNQUFNLENBQUMsUUFBUSxDQUFFLENBQU07UUFDbkIsT0FBTyxNQUFNLENBQUMsY0FBYyxDQUFDLENBQUMsQ0FBQyxLQUFLLE1BQU0sQ0FBQyxTQUFTLENBQUM7SUFDekQsQ0FBQztJQUVELE1BQU0sQ0FBQyxLQUFLLENBQUMsZUFBZSxDQUFFLEdBQVcsRUFBRSxJQUFZLEVBQUUsR0FBVyxFQUFFLE1BQWMsRUFBRSxXQUFtQixFQUFFLFFBQW1CLEVBQUUsSUFBWTtRQUN4SSxRQUFRLFFBQVEsRUFBRSxDQUFDO1lBQ2YsS0FBSyxLQUFLLENBQUM7WUFDWCxLQUFLLEtBQUs7Z0JBQ04sSUFBSSxDQUFDO29CQUNELE1BQU0sS0FBSyxDQUFDLEtBQUssQ0FBQyxrQ0FBa0MsTUFBTSxJQUFJLElBQUksSUFBSSxXQUFXLFFBQVEsR0FBRyxJQUFJLElBQUksRUFBRSxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsRUFBRSxHQUFHLENBQUMsQ0FBQztvQkFDeEgsT0FBTyxJQUFJLENBQUM7Z0JBQ2hCLENBQUM7Z0JBQUMsT0FBTyxDQUFNLEVBQUUsQ0FBQztvQkFDZCxJQUFJLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxRQUFRLENBQUMsNEJBQTRCLElBQUksMkJBQTJCLENBQUM7d0JBQUUsTUFBTSxJQUFJLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQztvQkFDeEcsT0FBTyxLQUFLLENBQUM7Z0JBQ2pCLENBQUM7WUFFTCxLQUFLLE1BQU0sQ0FBQztZQUNaLEtBQUssT0FBTyxDQUFDLENBQUMsQ0FBQztnQkFDWCxJQUFJLENBQUM7b0JBQ0QsTUFBTSxXQUFXLEdBQXVCLEtBQUssQ0FBQyxtQkFBbUIsRUFBRSxDQUFDO29CQUNwRSxNQUFNLEVBQUMsTUFBTSxFQUFDLEdBQUcsTUFBTSxLQUFLLENBQUMsR0FBRyxDQUM1QixHQUFHLFFBQVEsTUFBTSxNQUFNLElBQUksSUFBSSxJQUFJLFdBQVcsVUFBVSxHQUFHLElBQUksSUFBSSxFQUFFLEVBQ3JFLFdBQVcsQ0FDZCxDQUFDO29CQUNGLE9BQU8sQ0FBQyxNQUFNLEtBQUssR0FBRyxDQUFDLENBQUM7Z0JBQzVCLENBQUM7Z0JBQUMsTUFBTSxDQUFDO29CQUNMLE9BQU8sS0FBSyxDQUFDO2dCQUNqQixDQUFDO1lBQ0wsQ0FBQztZQUNELE9BQU8sQ0FBQyxDQUFDLENBQUM7Z0JBQ04sS0FBSyxDQUFDLDhCQUE4QixDQUFDLFFBQVEsQ0FBQyxDQUFDO1lBQ25ELENBQUM7UUFDTCxDQUFDO0lBQ0wsQ0FBQztJQUVELE1BQU0sQ0FBQyw4QkFBOEIsQ0FBRSxLQUFZO1FBQy9DLHFFQUFxRTtRQUNyRSxNQUFNLElBQUksS0FBSyxDQUFDLGtCQUFrQixLQUFLLEVBQUUsQ0FBQyxDQUFDO0lBQy9DLENBQUM7SUFFRCxNQUFNLENBQUMsS0FBSyxDQUFDLGVBQWUsQ0FBRSxHQUFXO1FBQ3JDLE1BQU0sVUFBVSxHQUFHLE1BQU0sS0FBSyxDQUFDLElBQUksQ0FBQyw0QkFBNEIsRUFBRSxHQUFHLENBQUMsQ0FBQztRQUN2RSxJQUFJLFVBQVUsQ0FBQyxRQUFRLElBQUksQ0FBQyxFQUFFLENBQUM7WUFDM0IsTUFBTSxJQUFJLEtBQUssQ0FBQyxtQ0FBbUMsR0FBRyxLQUFLLFVBQVUsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxDQUFDO1FBQ3BGLENBQUM7UUFDRCxPQUFPLFVBQVUsQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxDQUFDO0lBQ3pDLENBQUM7SUFFRCxNQUFNLENBQUMsbUJBQW1CO1FBQ3RCLE1BQU0sUUFBUSxHQUFHLE9BQU8sQ0FBQyxHQUFHLENBQUMsV0FBVyxJQUFJLE9BQU8sQ0FBQyxHQUFHLENBQUMsVUFBVSxDQUFDO1FBQ25FLElBQUksUUFBUSxFQUFFLENBQUM7WUFDWCxNQUFNLFFBQVEsR0FBRyxJQUFJLEdBQUcsQ0FBQyxRQUFRLENBQUMsQ0FBQztZQUNuQyxPQUFPO2dCQUNILEtBQUssRUFBRTtvQkFDSCxJQUFJLEVBQUUsUUFBUSxDQUFDLFFBQVE7b0JBQ3ZCLElBQUksRUFBRSxRQUFRLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxRQUFRLENBQUMsUUFBUSxDQUFDLElBQUksRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBSTtvQkFDeEQsUUFBUSxFQUFFLFFBQVEsQ0FBQyxRQUFRLENBQUMsT0FBTyxDQUFDLEdBQUcsRUFBRSxFQUFFLENBQUM7aUJBQy9DO2FBQ0osQ0FBQztRQUNOLENBQUM7UUFDRCxPQUFPLEVBQUUsQ0FBQztJQUNkLENBQUM7Q0FDSiIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBcIi4vZ2xvYmFsLmpzXCI7XG5pbXBvcnQge1JFMkpTfSBmcm9tIFwicmUyanNcIjtcbmltcG9ydCBjaGFsayBmcm9tIFwiY2hhbGtcIjtcbmltcG9ydCB7Sm9iLCBKb2JSdWxlfSBmcm9tIFwiLi9qb2IuanNcIjtcbmltcG9ydCBmcyBmcm9tIFwiZnMtZXh0cmFcIjtcbmltcG9ydCBjaGVja3N1bSBmcm9tIFwiY2hlY2tzdW1cIjtcbmltcG9ydCBiYXNlNjR1cmwgZnJvbSBcImJhc2U2NHVybFwiO1xuaW1wb3J0IGV4ZWNhIGZyb20gXCJleGVjYVwiO1xuaW1wb3J0IGFzc2VydCBmcm9tIFwiYXNzZXJ0XCI7XG5pbXBvcnQge0NJQ0RWYXJpYWJsZX0gZnJvbSBcIi4vdmFyaWFibGVzLWZyb20tZmlsZXMuanNcIjtcbmltcG9ydCB7R2l0RGF0YSwgR2l0U2NoZW1hfSBmcm9tIFwiLi9naXQtZGF0YS5qc1wiO1xuaW1wb3J0IGdsb2JieSBmcm9tIFwiZ2xvYmJ5XCI7XG5pbXBvcnQgbWljcm9tYXRjaCBmcm9tIFwibWljcm9tYXRjaFwiO1xuaW1wb3J0IGF4aW9zLCB7QXhpb3NSZXF1ZXN0Q29uZmlnfSBmcm9tIFwiYXhpb3NcIjtcbmltcG9ydCBwYXRoIGZyb20gXCJwYXRoXCI7XG5pbXBvcnQge0FyZ3Z9IGZyb20gXCIuL2FyZ3YuanNcIjtcblxudHlwZSBSdWxlUmVzdWx0T3B0ID0ge1xuICAgIGFyZ3Y6IEFyZ3Y7XG4gICAgY3dkOiBzdHJpbmc7XG4gICAgcnVsZXM6IEpvYlJ1bGVbXTtcbiAgICB2YXJpYWJsZXM6IHtba2V5OiBzdHJpbmddOiBzdHJpbmd9O1xufTtcblxudHlwZSBFeHBhbmRXaXRoID0ge1xuICAgIHVuZXNjYXBlOiBzdHJpbmc7XG4gICAgdmFyaWFibGU6IChuYW1lOiBzdHJpbmcpID0+IHN0cmluZztcbn07XG5cbmV4cG9ydCBjbGFzcyBVdGlscyB7XG4gICAgc3RhdGljIGJhc2hNdWx0aSAoc2NyaXB0czogc3RyaW5nW10sIGN3ZCA9IHByb2Nlc3MuY3dkKCkpOiBQcm9taXNlPHtzdGRvdXQ6IHN0cmluZzsgc3RkZXJyOiBzdHJpbmc7IGV4aXRDb2RlOiBudW1iZXJ9PiB7XG4gICAgICAgIHJldHVybiBleGVjYShzY3JpcHRzLmpvaW4oXCIgJiYgXFxcXFwiKSwge3NoZWxsOiBcImJhc2hcIiwgY3dkfSk7XG4gICAgfVxuXG4gICAgc3RhdGljIGJhc2ggKHNoZWxsU2NyaXB0OiBzdHJpbmcsIGN3ZCA9IHByb2Nlc3MuY3dkKCkpOiBQcm9taXNlPHtzdGRvdXQ6IHN0cmluZzsgc3RkZXJyOiBzdHJpbmc7IGV4aXRDb2RlOiBudW1iZXJ9PiB7XG4gICAgICAgIHJldHVybiBleGVjYShzaGVsbFNjcmlwdCwge3NoZWxsOiBcImJhc2hcIiwgY3dkfSk7XG4gICAgfVxuXG4gICAgc3RhdGljIHNwYXduIChjbWRBcmdzOiBzdHJpbmdbXSwgY3dkID0gcHJvY2Vzcy5jd2QoKSk6IFByb21pc2U8e3N0ZG91dDogc3RyaW5nOyBzdGRlcnI6IHN0cmluZ30+IHtcbiAgICAgICAgcmV0dXJuIGV4ZWNhKGNtZEFyZ3NbMF0sIGNtZEFyZ3Muc2xpY2UoMSksIHtjd2R9KTtcbiAgICB9XG5cbiAgICBzdGF0aWMgc3luY1NwYXduIChjbWRBcmdzOiBzdHJpbmdbXSwgY3dkID0gcHJvY2Vzcy5jd2QoKSk6IHtzdGRvdXQ6IHN0cmluZzsgc3RkZXJyOiBzdHJpbmd9IHtcbiAgICAgICAgcmV0dXJuIGV4ZWNhLnN5bmMoY21kQXJnc1swXSwgY21kQXJncy5zbGljZSgxKSwge2N3ZH0pO1xuICAgIH1cblxuICAgIHN0YXRpYyBmc1VybCAodXJsOiBzdHJpbmcpOiBzdHJpbmcge1xuICAgICAgICByZXR1cm4gdXJsLnJlcGxhY2UoL15odHRwczpcXC9cXC8vZywgXCJcIikucmVwbGFjZSgvXmh0dHA6XFwvXFwvL2csIFwiXCIpO1xuICAgIH1cblxuICAgIHN0YXRpYyBzYWZlRG9ja2VyU3RyaW5nIChqb2JOYW1lOiBzdHJpbmcpIHtcbiAgICAgICAgcmV0dXJuIGpvYk5hbWUucmVwbGFjZSgvW15cXHctXSsvZywgKG1hdGNoKSA9PiB7XG4gICAgICAgICAgICByZXR1cm4gYmFzZTY0dXJsLmVuY29kZShtYXRjaCk7XG4gICAgICAgIH0pO1xuICAgIH1cblxuICAgIHN0YXRpYyBzYWZlQmFzaFN0cmluZyAoczogc3RyaW5nKSB7XG4gICAgICAgIHJldHVybiBgJyR7cy5yZXBsYWNlKC8nL2csIFwiJ1xcXCInXFxcIidcIil9J2A7IC8vIHJlcGxhY2VzIGAnYCB3aXRoIGAnXCInXCInYFxuICAgIH1cblxuICAgIHN0YXRpYyBmb3JFYWNoUmVhbEpvYiAoZ2l0bGFiRGF0YTogYW55LCBjYWxsYmFjazogKGpvYk5hbWU6IHN0cmluZywgam9iRGF0YTogYW55KSA9PiB2b2lkKSB7XG4gICAgICAgIGZvciAoY29uc3QgW2pvYk5hbWUsIGpvYkRhdGFdIG9mIE9iamVjdC5lbnRyaWVzPGFueT4oZ2l0bGFiRGF0YSkpIHtcbiAgICAgICAgICAgIGlmIChKb2IuaWxsZWdhbEpvYk5hbWVzLmhhcyhqb2JOYW1lKSB8fCBqb2JOYW1lWzBdLnN0YXJ0c1dpdGgoXCIuXCIpKSB7XG4gICAgICAgICAgICAgICAgY29udGludWU7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBjYWxsYmFjayhqb2JOYW1lLCBqb2JEYXRhKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHN0YXRpYyBnZXRKb2JOYW1lc0Zyb21QcmV2aW91c1N0YWdlcyAoam9iczogUmVhZG9ubHlBcnJheTxKb2I+LCBzdGFnZXM6IHJlYWRvbmx5IHN0cmluZ1tdLCBjdXJyZW50Sm9iOiBKb2IpIHtcbiAgICAgICAgY29uc3Qgam9iTmFtZXM6IHN0cmluZ1tdID0gW107XG4gICAgICAgIGNvbnN0IGN1cnJlbnRTdGFnZUluZGV4ID0gc3RhZ2VzLmluZGV4T2YoY3VycmVudEpvYi5zdGFnZSk7XG4gICAgICAgIGpvYnMuZm9yRWFjaChqb2IgPT4ge1xuICAgICAgICAgICAgY29uc3Qgc3RhZ2VJbmRleCA9IHN0YWdlcy5pbmRleE9mKGpvYi5zdGFnZSk7XG4gICAgICAgICAgICBpZiAoc3RhZ2VJbmRleCA8IGN1cnJlbnRTdGFnZUluZGV4KSB7XG4gICAgICAgICAgICAgICAgam9iTmFtZXMucHVzaChqb2IubmFtZSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgICAgICByZXR1cm4gam9iTmFtZXM7XG4gICAgfVxuXG4gICAgc3RhdGljIGFzeW5jIGdldENvdmVyYWdlUGVyY2VudCAoY3dkOiBzdHJpbmcsIHN0YXRlRGlyOiBzdHJpbmcsIGNvdmVyYWdlUmVnZXg6IHN0cmluZywgam9iTmFtZTogc3RyaW5nKSB7XG4gICAgICAgIGNvbnN0IGNvbnRlbnQgPSBhd2FpdCBmcy5yZWFkRmlsZShgJHtjd2R9LyR7c3RhdGVEaXJ9L291dHB1dC8ke2pvYk5hbWV9LmxvZ2AsIFwidXRmOFwiKTtcblxuICAgICAgICBjb25zdCByZWdleCA9IFJFMkpTLmNvbXBpbGUoXG4gICAgICAgICAgICBjb3ZlcmFnZVJlZ2V4XG4gICAgICAgICAgICAgICAgLnJlcGxhY2UoL15cXC8vLCBcIlwiKVxuICAgICAgICAgICAgICAgIC5yZXBsYWNlKC9cXC8kLywgXCJcIiksXG4gICAgICAgICAgICBSRTJKUy5NVUxUSUxJTkUsXG4gICAgICAgICk7XG4gICAgICAgIGNvbnN0IG1hdGNoZXMgPSBBcnJheS5mcm9tKGNvbnRlbnQubWF0Y2hBbGxSRTJKUyhyZWdleCkpO1xuICAgICAgICBpZiAobWF0Y2hlcy5sZW5ndGggPT09IDApIHJldHVybiBcIjBcIjtcblxuICAgICAgICBjb25zdCBsYXN0TWF0Y2ggPSBtYXRjaGVzW21hdGNoZXMubGVuZ3RoIC0gMV07XG4gICAgICAgIGNvbnN0IGRpZ2l0cyA9IC9cXGQrKD86XFwuXFxkKyk/Ly5leGVjKGxhc3RNYXRjaFsxXSA/PyBsYXN0TWF0Y2hbMF0pO1xuICAgICAgICBpZiAoIWRpZ2l0cykgcmV0dXJuIFwiMFwiO1xuICAgICAgICByZXR1cm4gZGlnaXRzWzBdID8/IFwiMFwiO1xuICAgIH1cblxuICAgIHN0YXRpYyBwcmludEpvYk5hbWVzIChzdHJlYW06ICh0eHQ6IHN0cmluZykgPT4gdm9pZCwgam9iOiB7bmFtZTogc3RyaW5nfSwgaTogbnVtYmVyLCBhcnI6IHtuYW1lOiBzdHJpbmd9W10pIHtcbiAgICAgICAgaWYgKGkgPT09IGFyci5sZW5ndGggLSAxKSB7XG4gICAgICAgICAgICBzdHJlYW0oY2hhbGtge2JsdWVCcmlnaHQgJHtqb2IubmFtZX19YCk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBzdHJlYW0oY2hhbGtge2JsdWVCcmlnaHQgJHtqb2IubmFtZX19LCBgKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHByaXZhdGUgc3RhdGljIGV4cGFuZFRleHRXaXRoICh0ZXh0OiBhbnksIGV4cGFuZFdpdGg6IEV4cGFuZFdpdGgpIHtcbiAgICAgICAgaWYgKHR5cGVvZiB0ZXh0ICE9PSBcInN0cmluZ1wiKSB7XG4gICAgICAgICAgICByZXR1cm4gdGV4dDtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiB0ZXh0LnJlcGxhY2UoXG4gICAgICAgICAgICAvKFxcJFxcJCl8XFwkXFx7KFthLXpBLVpfXVxcdyopfXxcXCQoW2EtekEtWl9dXFx3KikvZywgLy8gaHR0cHM6Ly9yZWdleHIuY29tLzdzNGthXG4gICAgICAgICAgICAoX21hdGNoLCBlc2NhcGUsIHZhcjEsIHZhcjIpID0+IHtcbiAgICAgICAgICAgICAgICBpZiAodHlwZW9mIGVzY2FwZSAhPT0gXCJ1bmRlZmluZWRcIikge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gZXhwYW5kV2l0aC51bmVzY2FwZTtcbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICBjb25zdCBuYW1lID0gdmFyMSB8fCB2YXIyO1xuICAgICAgICAgICAgICAgICAgICBhc3NlcnQobmFtZSwgXCJ1bmV4cGVjdGVkIHVuc2V0IGNhcHR1cmUgZ3JvdXBcIik7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBgJHtleHBhbmRXaXRoLnZhcmlhYmxlKG5hbWUpfWA7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSxcbiAgICAgICAgKTtcbiAgICB9XG5cbiAgICBzdGF0aWMgZXhwYW5kVGV4dCAodGV4dDogYW55LCBlbnZzOiB7W2tleTogc3RyaW5nXTogc3RyaW5nfSkge1xuICAgICAgICByZXR1cm4gdGhpcy5leHBhbmRUZXh0V2l0aCh0ZXh0LCB7XG4gICAgICAgICAgICB1bmVzY2FwZTogXCIkXCIsXG4gICAgICAgICAgICB2YXJpYWJsZTogKG5hbWUpID0+IGVudnNbbmFtZV0gPz8gXCJcIixcbiAgICAgICAgfSk7XG4gICAgfVxuXG4gICAgc3RhdGljIGV4cGFuZFZhcmlhYmxlcyAodmFyaWFibGVzOiB7W2tleTogc3RyaW5nXTogc3RyaW5nfSkge1xuICAgICAgICBjb25zdCBfdmFyaWFibGVzID0gey4uLnZhcmlhYmxlc307IC8vIGNvcHkgYnkgdmFsdWUgdG8gcHJldmVudCBtdXRhdGluZyB0aGUgb3JpZ2luYWwgaW5wdXRcbiAgICAgICAgbGV0IGV4cGFuZGVkQW55VmFyaWFibGVzLCBpID0gMDtcbiAgICAgICAgZG8ge1xuICAgICAgICAgICAgYXNzZXJ0KGkgPCAxMDAsIFwiUmVjdXJzaXZlIHZhcmlhYmxlIGV4cGFuc2lvbiByZWFjaGVkIDEwMCBpdGVyYXRpb25zXCIpO1xuICAgICAgICAgICAgZXhwYW5kZWRBbnlWYXJpYWJsZXMgPSBmYWxzZTtcbiAgICAgICAgICAgIGZvciAoY29uc3QgW2ssIHZdIG9mIE9iamVjdC5lbnRyaWVzKF92YXJpYWJsZXMpKSB7XG4gICAgICAgICAgICAgICAgY29uc3QgZW52c1dpdGhvdXRTZWxmID0gey4uLl92YXJpYWJsZXN9O1xuICAgICAgICAgICAgICAgIGRlbGV0ZSBlbnZzV2l0aG91dFNlbGZba107XG4gICAgICAgICAgICAgICAgLy8gSWYgdGhlICQkJ3MgYXJlIGNvbnZlcnRlZCB0byBzaW5nbGUgJCdzIG5vdywgdGhlbiB0aGUgbmV4dFxuICAgICAgICAgICAgICAgIC8vIGl0ZXJhdGlvbiwgdGhleSBtaWdodCBiZSBpbnRlcnByZXRlZCBhcyBfdmFyaWFibGVzLCBldmVuXG4gICAgICAgICAgICAgICAgLy8gdGhvdWdoIHRoZXkgd2VyZSAqZXhwbGljaXRseSogZXNjYXBlZC4gVG8gd29yayBhcm91bmQgdGhpcyxcbiAgICAgICAgICAgICAgICAvLyBsZWF2ZSB0aGUgJyQkJ3MgYXMgdGhlIHNhbWUgdmFsdWUsIHRoZW4gb25seSB1bmVzY2FwZSB0aGVtIGF0XG4gICAgICAgICAgICAgICAgLy8gdGhlIHZlcnkgZW5kLlxuICAgICAgICAgICAgICAgIF92YXJpYWJsZXNba10gPSBVdGlscy5leHBhbmRUZXh0V2l0aCh2LCB7XG4gICAgICAgICAgICAgICAgICAgIHVuZXNjYXBlOiBcIiQkXCIsXG4gICAgICAgICAgICAgICAgICAgIHZhcmlhYmxlOiAobmFtZSkgPT4gZW52c1dpdGhvdXRTZWxmW25hbWVdID8/IFwiXCIsXG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgZXhwYW5kZWRBbnlWYXJpYWJsZXMgfHw9IF92YXJpYWJsZXNba10gIT09IHY7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpKys7XG4gICAgICAgIH0gd2hpbGUgKGV4cGFuZGVkQW55VmFyaWFibGVzKTtcblxuICAgICAgICByZXR1cm4gX3ZhcmlhYmxlcztcbiAgICB9XG5cbiAgICBzdGF0aWMgdW5zY2FwZSQkVmFyaWFibGVzICh2YXJpYWJsZXM6IHtba2V5OiBzdHJpbmddOiBzdHJpbmd9KSB7XG4gICAgICAgIGZvciAoY29uc3QgW2ssIHZdIG9mIE9iamVjdC5lbnRyaWVzKHZhcmlhYmxlcykpIHtcbiAgICAgICAgICAgIHZhcmlhYmxlc1trXSA9IFV0aWxzLmV4cGFuZFRleHQodiwge30pO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIHZhcmlhYmxlcztcbiAgICB9XG5cbiAgICBzdGF0aWMgZmluZEVudk1hdGNoZWRWYXJpYWJsZXMgKHZhcmlhYmxlczoge1tuYW1lOiBzdHJpbmddOiBDSUNEVmFyaWFibGV9LCBmaWxlVmFyaWFibGVzRGlyPzogc3RyaW5nLCBlbnZpcm9ubWVudD86IHtuYW1lOiBzdHJpbmd9KSB7XG4gICAgICAgIGNvbnN0IGVudk1hdGNoZWRWYXJpYWJsZXM6IHtba2V5OiBzdHJpbmddOiBzdHJpbmd9ID0ge307XG4gICAgICAgIGZvciAoY29uc3QgW2ssIHZdIG9mIE9iamVjdC5lbnRyaWVzKHZhcmlhYmxlcykpIHtcbiAgICAgICAgICAgIGZvciAoY29uc3QgZW50cnkgb2Ygdi5lbnZpcm9ubWVudHMpIHtcbiAgICAgICAgICAgICAgICBpZiAoZW52aXJvbm1lbnQ/Lm5hbWUubWF0Y2goZW50cnkucmVnZXhwKSB8fCBlbnRyeS5yZWdleHAuc291cmNlID09PSBcIi4qXCIpIHtcbiAgICAgICAgICAgICAgICAgICAgaWYgKGZpbGVWYXJpYWJsZXNEaXIgIT0gbnVsbCAmJiB2LnR5cGUgPT09IFwiZmlsZVwiICYmICFlbnRyeS5maWxlU291cmNlKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBlbnZNYXRjaGVkVmFyaWFibGVzW2tdID0gYCR7ZmlsZVZhcmlhYmxlc0Rpcn0vJHtrfWA7XG4gICAgICAgICAgICAgICAgICAgICAgICBmcy5ta2RpcnBTeW5jKGAke2ZpbGVWYXJpYWJsZXNEaXJ9YCk7XG4gICAgICAgICAgICAgICAgICAgICAgICBmcy53cml0ZUZpbGVTeW5jKGAke2ZpbGVWYXJpYWJsZXNEaXJ9LyR7a31gLCBlbnRyeS5jb250ZW50KTtcbiAgICAgICAgICAgICAgICAgICAgfSBlbHNlIGlmIChmaWxlVmFyaWFibGVzRGlyICE9IG51bGwgJiYgdi50eXBlID09PSBcImZpbGVcIiAmJiBlbnRyeS5maWxlU291cmNlKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBlbnZNYXRjaGVkVmFyaWFibGVzW2tdID0gYCR7ZmlsZVZhcmlhYmxlc0Rpcn0vJHtrfWA7XG4gICAgICAgICAgICAgICAgICAgICAgICBmcy5ta2RpcnBTeW5jKGAke2ZpbGVWYXJpYWJsZXNEaXJ9YCk7XG4gICAgICAgICAgICAgICAgICAgICAgICBmcy5jb3B5RmlsZVN5bmMoZW50cnkuZmlsZVNvdXJjZSwgYCR7ZmlsZVZhcmlhYmxlc0Rpcn0vJHtrfWApO1xuICAgICAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgICAgZW52TWF0Y2hlZFZhcmlhYmxlc1trXSA9IGVudHJ5LmNvbnRlbnQ7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIHJldHVybiBlbnZNYXRjaGVkVmFyaWFibGVzO1xuICAgIH1cblxuICAgIHN0YXRpYyBnZXRSdWxlc1Jlc3VsdCAob3B0OiBSdWxlUmVzdWx0T3B0LCBnaXREYXRhOiBHaXREYXRhLCBqb2JXaGVuOiBzdHJpbmcgPSBcIm9uX3N1Y2Nlc3NcIiwgam9iQWxsb3dGYWlsdXJlOiBib29sZWFuIHwge2V4aXRfY29kZXM6IG51bWJlciB8IG51bWJlcltdfSA9IGZhbHNlKToge3doZW46IHN0cmluZzsgYWxsb3dGYWlsdXJlOiBib29sZWFuIHwge2V4aXRfY29kZXM6IG51bWJlciB8IG51bWJlcltdfTsgdmFyaWFibGVzPzoge1tuYW1lOiBzdHJpbmddOiBzdHJpbmd9fSB7XG4gICAgICAgIGxldCB3aGVuID0gXCJuZXZlclwiO1xuICAgICAgICBjb25zdCB7ZXZhbHVhdGVSdWxlQ2hhbmdlc30gPSBvcHQuYXJndjtcblxuICAgICAgICAvLyBvcHRpb25hbCBtYW51YWwgam9icyBhbGxvd0ZhaWx1cmUgZGVmYXVsdHMgdG8gdHJ1ZSBodHRwczovL2RvY3MuZ2l0bGFiLmNvbS9lZS9jaS9qb2JzL2pvYl9jb250cm9sLmh0bWwjdHlwZXMtb2YtbWFudWFsLWpvYnNcbiAgICAgICAgbGV0IGFsbG93RmFpbHVyZSA9IGpvYldoZW4gPT09IFwibWFudWFsXCIgPyB0cnVlIDogam9iQWxsb3dGYWlsdXJlO1xuICAgICAgICBsZXQgcnVsZVZhcmlhYmxlOiB7W25hbWU6IHN0cmluZ106IHN0cmluZ30gfCB1bmRlZmluZWQ7XG5cbiAgICAgICAgZm9yIChjb25zdCBydWxlIG9mIG9wdC5ydWxlcykge1xuICAgICAgICAgICAgaWYgKCFVdGlscy5ldmFsdWF0ZVJ1bGVJZihydWxlLmlmLCBvcHQudmFyaWFibGVzKSkgY29udGludWU7XG4gICAgICAgICAgICBpZiAoIVV0aWxzLmV2YWx1YXRlUnVsZUV4aXN0KG9wdC5jd2QsIHJ1bGUuZXhpc3RzKSkgY29udGludWU7XG4gICAgICAgICAgICBpZiAoZXZhbHVhdGVSdWxlQ2hhbmdlcyAmJiAhVXRpbHMuZXZhbHVhdGVSdWxlQ2hhbmdlcyhnaXREYXRhLmJyYW5jaGVzLmRlZmF1bHQsIHJ1bGUuY2hhbmdlcywgb3B0LmN3ZCkpIGNvbnRpbnVlO1xuXG4gICAgICAgICAgICB3aGVuID0gcnVsZS53aGVuID8gcnVsZS53aGVuIDogam9iV2hlbjtcbiAgICAgICAgICAgIGFsbG93RmFpbHVyZSA9IHJ1bGUuYWxsb3dfZmFpbHVyZSA/PyBhbGxvd0ZhaWx1cmU7XG4gICAgICAgICAgICBydWxlVmFyaWFibGUgPSBydWxlLnZhcmlhYmxlcztcblxuICAgICAgICAgICAgYnJlYWs7IC8vIEVhcmx5IHJldHVybiwgd2lsbCBub3QgZXZhbHVhdGUgdGhlIHJlbWFpbmluZyBydWxlc1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIHt3aGVuLCBhbGxvd0ZhaWx1cmUsIHZhcmlhYmxlczogcnVsZVZhcmlhYmxlfTtcbiAgICB9XG5cbiAgICBzdGF0aWMgZXZhbHVhdGVSdWxlSWYgKHJ1bGVJZjogc3RyaW5nIHwgdW5kZWZpbmVkLCBlbnZzOiB7W2tleTogc3RyaW5nXTogc3RyaW5nfSk6IGJvb2xlYW4ge1xuICAgICAgICBpZiAocnVsZUlmID09PSB1bmRlZmluZWQpIHJldHVybiB0cnVlO1xuICAgICAgICBsZXQgZXZhbFN0ciA9IHJ1bGVJZjtcblxuICAgICAgICBjb25zdCBmbGFnc1RvQmluYXJ5ID0gKGZsYWdzOiBzdHJpbmcpOiBudW1iZXIgPT4ge1xuICAgICAgICAgICAgbGV0IGJpbmFyeSA9IDA7XG4gICAgICAgICAgICBpZiAoZmxhZ3MuaW5jbHVkZXMoXCJpXCIpKSB7XG4gICAgICAgICAgICAgICAgYmluYXJ5IHw9IFJFMkpTLkNBU0VfSU5TRU5TSVRJVkU7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAoZmxhZ3MuaW5jbHVkZXMoXCJzXCIpKSB7XG4gICAgICAgICAgICAgICAgYmluYXJ5IHw9IFJFMkpTLkRPVEFMTDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmIChmbGFncy5pbmNsdWRlcyhcIm1cIikpIHtcbiAgICAgICAgICAgICAgICBiaW5hcnkgfD0gUkUySlMuTVVMVElMSU5FO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuIGJpbmFyeTtcbiAgICAgICAgfTtcblxuICAgICAgICAvLyBFeHBhbmQgYWxsIHZhcmlhYmxlc1xuICAgICAgICBldmFsU3RyID0gdGhpcy5leHBhbmRUZXh0V2l0aChldmFsU3RyLCB7XG4gICAgICAgICAgICB1bmVzY2FwZTogSlNPTi5zdHJpbmdpZnkoXCIkXCIpLFxuICAgICAgICAgICAgdmFyaWFibGU6IChuYW1lKSA9PiBKU09OLnN0cmluZ2lmeShlbnZzW25hbWVdID8/IG51bGwpLnJlcGxhY2VBbGwoXCJcXFxcXFxcXFwiLCBcIlxcXFxcIiksXG4gICAgICAgIH0pO1xuICAgICAgICBjb25zdCBleHBhbmRlZEV2YWxTdHIgPSBldmFsU3RyO1xuXG4gICAgICAgIC8vIFNjZW5hcmlvIHdoZW4gUkhTIGlzIGEgPHJlZ2V4PlxuICAgICAgICAvLyBodHRwczovL3JlZ2V4ci5jb20vODVzam9cbiAgICAgICAgY29uc3QgcGF0dGVybjEgPSAvXFxzKig/PG9wZXJhdG9yPig/Oj1+KXwoPzohfikpXFxzKlxcLyg/PHJocz4uKj8pXFwvKD88ZmxhZ3M+W2lnbXN1eV0qKShcXHN8JHxcXCkpL2c7XG4gICAgICAgIGV2YWxTdHIgPSBldmFsU3RyLnJlcGxhY2UocGF0dGVybjEsIChfLCBvcGVyYXRvciwgcmhzLCBmbGFncywgcmVtYWluaW5nVG9rZW5zKSA9PiB7XG4gICAgICAgICAgICBsZXQgX29wZXJhdG9yO1xuICAgICAgICAgICAgc3dpdGNoIChvcGVyYXRvcikge1xuICAgICAgICAgICAgICAgIGNhc2UgXCI9flwiOlxuICAgICAgICAgICAgICAgICAgICBfb3BlcmF0b3IgPSBcIiE9XCI7XG4gICAgICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgIC