gitlab-ci-local
Version:
Tired of pushing to test your .gitlab-ci.yml?
340 lines • 63.2 kB
JavaScript
import { Utils } from "./utils.js";
import fs from "fs-extra";
import assert, { AssertionError } from "assert";
import chalk from "chalk";
import { Parser } from "./parser.js";
import axios from "axios";
import globby from "globby";
import path from "path";
import semver from "semver";
import { RE2JS } from "re2js";
export class ParserIncludes {
static count = 0;
static resetCount() {
this.count = 0;
}
static normalizeTriggerInclude(gitlabData, opts) {
const { writeStreams } = opts;
for (const [jobName, jobData] of Object.entries(gitlabData ?? {})) {
if (typeof jobData.trigger?.include === "string") {
jobData.trigger.include = [{
local: jobData.trigger.include,
}];
}
else if (jobData.trigger?.project) {
writeStreams.memoStdout(chalk `{bgYellowBright WARN } The job: \`{blueBright ${jobName}}\` will be no-op. Multi-project pipeline is not supported by gitlab-ci-local\n`);
}
}
}
static async init(gitlabData, opts) {
const { argv } = opts;
this.count++;
assert(this.count <= opts.maximumIncludes + 1, // 1st init call is not counted
chalk `This GitLab CI configuration is invalid: Maximum of {blueBright ${opts.maximumIncludes}} nested includes are allowed!. This limit can be increased with the --maximum-includes cli flags.`);
let includeDatas = [];
const promises = [];
const { stateDir, cwd, fetchIncludes, gitData, expandVariables } = opts;
const include = this.expandInclude(gitlabData?.include, opts.variables);
this.normalizeTriggerInclude(gitlabData, opts);
// Find files to fetch from remote and place in .gitlab-ci-local/includes
for (const value of include) {
if (value["rules"]) {
const include_rules = value["rules"];
const rulesResult = Utils.getRulesResult({ argv, cwd, rules: include_rules, variables: opts.variables }, gitData);
if (rulesResult.when === "never") {
continue;
}
}
if (value["file"]) {
for (const fileValue of Array.isArray(value["file"]) ? value["file"] : [value["file"]]) {
promises.push(this.downloadIncludeProjectFile(cwd, stateDir, value["project"], value["ref"] || "HEAD", fileValue, gitData, fetchIncludes));
}
}
else if (value["template"]) {
const { project, ref, file, domain } = this.covertTemplateToProjectFile(value["template"]);
const url = `https://${domain}/${project}/-/raw/${ref}/${file}`;
promises.push(this.downloadIncludeRemote(cwd, stateDir, url, fetchIncludes));
}
else if (value["remote"]) {
promises.push(this.downloadIncludeRemote(cwd, stateDir, value["remote"], fetchIncludes));
}
}
await Promise.all(promises);
for (const value of include) {
if (value["rules"]) {
const include_rules = value["rules"];
const rulesResult = Utils.getRulesResult({ argv, cwd, rules: include_rules, variables: opts.variables }, gitData);
if (rulesResult.when === "never") {
continue;
}
}
if (value["local"]) {
validateIncludeLocal(value["local"]);
const files = resolveIncludeLocal(value["local"], cwd);
if (files.length == 0) {
throw new AssertionError({ message: `Local include file cannot be found ${value["local"]}` });
}
for (const localFile of files) {
const content = await Parser.loadYaml(localFile, { inputs: value.inputs ?? {} }, expandVariables);
includeDatas = includeDatas.concat(await this.init(content, opts));
}
}
else if (value["project"]) {
for (const fileValue of Array.isArray(value["file"]) ? value["file"] : [value["file"]]) {
const fileDoc = await Parser.loadYaml(`${cwd}/${stateDir}/includes/${gitData.remote.host}/${value["project"]}/${value["ref"] || "HEAD"}/${fileValue}`, { inputs: value.inputs || {} }, expandVariables);
// Expand local includes inside a "project"-like include
fileDoc["include"] = this.expandInclude(fileDoc["include"], opts.variables);
fileDoc["include"].forEach((inner, i) => {
if (!inner["local"])
return;
if (inner["rules"]) {
const rulesResult = Utils.getRulesResult({ argv, cwd: opts.cwd, variables: opts.variables, rules: inner["rules"] }, gitData);
if (rulesResult.when === "never") {
return;
}
}
fileDoc["include"][i] = {
project: value["project"],
file: inner["local"].replace(/^\//, ""),
ref: value["ref"],
inputs: inner.inputs || {},
};
});
includeDatas = includeDatas.concat(await this.init(fileDoc, opts));
}
}
else if (value["component"]) {
const { domain, port, projectPath, componentName, ref, isLocalComponent } = this.parseIncludeComponent(value["component"], gitData);
// converts component to project. gitlab allows two different file path ways to include a component
let files = [`${componentName}.yml`, `${componentName}/template.yml`, null];
// If a file is present locally, keep only that one in the files array to avoid downloading the other one that never exists
if (!argv.fetchIncludes) {
for (const f of files) {
const localFileName = `${cwd}/${stateDir}/includes/${gitData.remote.host}/${projectPath}/${ref}/${f}`;
if (fs.existsSync(localFileName)) {
files = [f];
break;
}
}
}
for (const f of files) {
assert(f !== null, `This GitLab CI configuration is invalid: component: \`${value["component"]}\`. One of the files [${files}] must exist in \`${domain}` +
(port ? `:${port}` : "") + `/${projectPath}\``);
if (isLocalComponent) {
const localComponentInclude = `${cwd}/${f}`;
if (!(await fs.pathExists(localComponentInclude))) {
continue;
}
const content = await Parser.loadYaml(localComponentInclude, { inputs: value.inputs || {} }, expandVariables);
includeDatas = includeDatas.concat(await this.init(content, opts));
break;
}
else {
const localFileName = `${cwd}/${stateDir}/includes/${gitData.remote.host}/${projectPath}/${ref}/${f}`;
// Check remotely only if the file does not exist locally
if (!fs.existsSync(localFileName) && !(await Utils.remoteFileExist(cwd, f, ref, domain, projectPath, gitData.remote.schema, gitData.remote.port))) {
continue;
}
const fileDoc = {
include: {
project: projectPath,
file: f,
ref: ref,
inputs: value.inputs || {},
},
};
includeDatas = includeDatas.concat(await this.init(fileDoc, opts));
break;
}
}
}
else if (value["template"]) {
const { project, ref, file, domain } = this.covertTemplateToProjectFile(value["template"]);
const fsUrl = Utils.fsUrl(`https://${domain}/${project}/-/raw/${ref}/${file}`);
const fileDoc = await Parser.loadYaml(`${cwd}/${stateDir}/includes/${fsUrl}`, { inputs: value.inputs || {} }, expandVariables);
includeDatas = includeDatas.concat(await this.init(fileDoc, opts));
}
else if (value["remote"]) {
const fsUrl = Utils.fsUrl(value["remote"]);
const fileDoc = await Parser.loadYaml(`${cwd}/${stateDir}/includes/${fsUrl}`, { inputs: value.inputs || {} }, expandVariables);
includeDatas = includeDatas.concat(await this.init(fileDoc, opts));
}
else {
throw new AssertionError({ message: `Didn't understand include ${JSON.stringify(value)}` });
}
}
includeDatas.push(gitlabData);
return includeDatas;
}
static expandInclude(i, variables) {
let include = i || [];
if (include && include.length == null) {
include = [i];
}
if (typeof include === "string") {
include = [include];
}
for (const [index, entry] of Object.entries(include)) {
if (typeof entry === "string" && (entry.startsWith("https:") || entry.startsWith("http:"))) {
include[index] = { "remote": entry };
}
else if (typeof entry === "string") {
include[index] = { "local": entry };
}
else {
include[index] = entry;
}
}
for (const entry of include) {
for (const [key, value] of Object.entries(entry)) {
if (Array.isArray(value)) {
entry[key] = value.map((v) => Utils.expandText(v, variables));
}
else {
entry[key] = Utils.expandText(value, variables);
}
}
}
return include;
}
static covertTemplateToProjectFile(template) {
return {
domain: "gitlab.com",
project: "gitlab-org/gitlab",
ref: "HEAD",
file: `lib/gitlab/ci/templates/${template}`,
};
}
static parseIncludeComponent(component, gitData) {
assert(!component.includes("://"), `This GitLab CI configuration is invalid: component: \`${component}\` should not contain protocol`);
const pattern = /(?<domain>[^/:\s]+)(:(?<port>\d+))?\/(?<projectPath>.+)\/(?<componentName>[^@]+)@(?<ref>.+)/; // https://regexr.com/7v7hm
const gitRemoteMatch = pattern.exec(component);
if (gitRemoteMatch?.groups == null)
throw new Error(`This is a bug, please create a github issue if this is something you're expecting to work. input: ${component}`);
const { domain, projectPath, port } = gitRemoteMatch.groups;
let ref = gitRemoteMatch.groups["ref"];
const isLocalComponent = projectPath === `${gitData.remote.group}/${gitData.remote.project}` && ref === gitData.commit.SHA;
if (!isLocalComponent) {
const semanticVersionRangesPattern = /^\d+(\.\d+)?$/;
if (ref == "~latest" || semanticVersionRangesPattern.test(ref)) {
// https://docs.gitlab.com/ci/components/#semantic-version-ranges
let stdout;
try {
stdout = Utils.syncSpawn(["git", "ls-remote", "--tags", `git@${domain}:${projectPath}`]).stdout;
}
catch {
stdout = Utils.syncSpawn(["git", "ls-remote", "--tags", `https://${domain}:${port ?? 443}/${projectPath}.git`]).stdout;
}
assert(stdout);
const tags = stdout
.split("\n")
.map((line) => {
return line
.split("\t")[1]
.split("/")[2];
});
const _ref = resolveSemanticVersionRange(ref, tags);
assert(_ref, `This GitLab CI configuration is invalid: component: \`${component}\` - The ref (${ref}) is invalid`);
ref = _ref;
}
}
return {
domain: domain,
port: port,
projectPath: projectPath,
componentName: `templates/${gitRemoteMatch.groups["componentName"]}`,
ref: ref,
isLocalComponent: isLocalComponent,
};
}
static async downloadIncludeRemote(cwd, stateDir, url, fetchIncludes) {
const fsUrl = Utils.fsUrl(url);
try {
const target = `${cwd}/${stateDir}/includes/${fsUrl}`;
if (await fs.pathExists(target) && !fetchIncludes)
return;
const res = await axios.get(url, { headers: { "User-Agent": "gitlab-ci-local" } });
await fs.outputFile(target, res.data);
}
catch (e) {
throw new AssertionError({ message: `Remote include could not be fetched ${url}\n${e}` });
}
}
static async downloadIncludeProjectFile(cwd, stateDir, project, ref, file, gitData, fetchIncludes) {
const remote = gitData.remote;
const normalizedFile = file.replace(/^\/+/, "");
try {
const target = `${stateDir}/includes/${remote.host}/${project}/${ref}`;
if (await fs.pathExists(`${cwd}/${target}/${normalizedFile}`) && !fetchIncludes)
return;
if (remote.schema.startsWith("http")) {
const ext = "tmp-" + Math.random();
await fs.mkdirp(path.dirname(`${cwd}/${target}/${normalizedFile}`));
const gitCloneBranch = (ref === "HEAD") ? "" : `--branch ${ref}`;
await Utils.bashMulti([
`cd ${cwd}/${stateDir}`,
`git clone ${gitCloneBranch} -n --depth=1 --filter=tree:0 ${remote.schema}://${remote.host}:${remote.port}/${project}.git ${cwd}/${target}.${ext}`,
`cd ${cwd}/${target}.${ext}`,
`git sparse-checkout set --no-cone ${normalizedFile}`,
"git checkout",
`cd ${cwd}/${stateDir}`,
`cp ${cwd}/${target}.${ext}/${normalizedFile} ${cwd}/${target}/${normalizedFile}`,
], cwd);
}
else {
await fs.mkdirp(`${cwd}/${target}`);
await Utils.bash(`set -eou pipefail; git archive --remote=ssh://git@${remote.host}:${remote.port}/${project}.git ${ref} ${normalizedFile} | tar -f - -xC ${target}/`, cwd);
}
}
catch (e) {
throw new AssertionError({ message: `Project include could not be fetched { project: ${project}, ref: ${ref}, file: ${normalizedFile} }\n${e}` });
}
}
static memoLocalRepoFiles = (() => {
const cache = new Map();
return (path) => {
let result = cache.get(path);
if (typeof result !== "undefined")
return result;
result = globby.sync(path, { dot: true, gitignore: true });
cache.set(path, result);
return result;
};
})();
}
export function validateIncludeLocal(filePath) {
assert(!filePath.startsWith("./"), `\`${filePath}\` for include:local is invalid. Gitlab does not support relative path (ie. cannot start with \`./\`).`);
assert(!filePath.includes(".."), `\`${filePath}\` for include:local is invalid. Gitlab does not support directory traversal.`);
}
export function resolveSemanticVersionRange(range, gitTags) {
/** sorted list of tags thats compliant to semantic version where index 0 is the latest */
const sanitizedSemverTags = semver.rsort(gitTags.filter(s => semver.valid(s)));
const found = sanitizedSemverTags.find(t => {
if (range == "~latest") {
const semverParsed = semver.parse(t);
assert(semverParsed);
return (semverParsed.prerelease.length == 0 && semverParsed.build.length == 0);
}
else {
return semver.satisfies(t, range);
}
});
return found;
}
export function resolveIncludeLocal(pattern, cwd) {
const repoFiles = ParserIncludes.memoLocalRepoFiles(cwd);
if (!pattern.startsWith("/"))
pattern = `/${pattern}`; // Ensure pattern starts with `/`
pattern = `${cwd}${pattern}`;
// escape all special regex metacharacters
pattern = pattern.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
// `**` matches anything
const anything = ".*?";
pattern = pattern.replace(/\\\*\\\*/g, anything);
// `*` matches anything except for `/`
const anything_but_not_slash = "([^/])*?";
pattern = pattern.replace(/\\\*/g, anything_but_not_slash);
const re2js = RE2JS.compile(`^${pattern}`);
return repoFiles.filter((f) => re2js.matches(f));
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGFyc2VyLWluY2x1ZGVzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsicGFyc2VyLWluY2x1ZGVzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUNBLE9BQU8sRUFBQyxLQUFLLEVBQUMsTUFBTSxZQUFZLENBQUM7QUFDakMsT0FBTyxFQUFFLE1BQU0sVUFBVSxDQUFDO0FBRzFCLE9BQU8sTUFBTSxFQUFFLEVBQUMsY0FBYyxFQUFDLE1BQU0sUUFBUSxDQUFDO0FBQzlDLE9BQU8sS0FBSyxNQUFNLE9BQU8sQ0FBQztBQUMxQixPQUFPLEVBQUMsTUFBTSxFQUFDLE1BQU0sYUFBYSxDQUFDO0FBQ25DLE9BQU8sS0FBSyxNQUFNLE9BQU8sQ0FBQztBQUMxQixPQUFPLE1BQU0sTUFBTSxRQUFRLENBQUM7QUFDNUIsT0FBTyxJQUFJLE1BQU0sTUFBTSxDQUFDO0FBQ3hCLE9BQU8sTUFBTSxNQUFNLFFBQVEsQ0FBQztBQUM1QixPQUFPLEVBQUMsS0FBSyxFQUFDLE1BQU0sT0FBTyxDQUFDO0FBYzVCLE1BQU0sT0FBTyxjQUFjO0lBQ2YsTUFBTSxDQUFDLEtBQUssR0FBVyxDQUFDLENBQUM7SUFFakMsTUFBTSxDQUFDLFVBQVU7UUFDYixJQUFJLENBQUMsS0FBSyxHQUFHLENBQUMsQ0FBQztJQUNuQixDQUFDO0lBRU8sTUFBTSxDQUFDLHVCQUF1QixDQUFFLFVBQWUsRUFBRSxJQUErQjtRQUNwRixNQUFNLEVBQUMsWUFBWSxFQUFDLEdBQUcsSUFBSSxDQUFDO1FBQzVCLEtBQUssTUFBTSxDQUFDLE9BQU8sRUFBRSxPQUFPLENBQUMsSUFBSSxNQUFNLENBQUMsT0FBTyxDQUFNLFVBQVUsSUFBSSxFQUFFLENBQUMsRUFBRSxDQUFDO1lBQ3JFLElBQUksT0FBTyxPQUFPLENBQUMsT0FBTyxFQUFFLE9BQU8sS0FBSyxRQUFRLEVBQUUsQ0FBQztnQkFDL0MsT0FBTyxDQUFDLE9BQU8sQ0FBQyxPQUFPLEdBQUcsQ0FBQzt3QkFDdkIsS0FBSyxFQUFFLE9BQU8sQ0FBQyxPQUFPLENBQUMsT0FBTztxQkFDakMsQ0FBRSxDQUFDO1lBQ1IsQ0FBQztpQkFBTSxJQUFJLE9BQU8sQ0FBQyxPQUFPLEVBQUUsT0FBTyxFQUFFLENBQUM7Z0JBQ2xDLFlBQVksQ0FBQyxVQUFVLENBQUMsS0FBSyxDQUFBLGtEQUFrRCxPQUFPLGlGQUFpRixDQUFDLENBQUM7WUFDN0ssQ0FBQztRQUNMLENBQUM7SUFDTCxDQUFDO0lBRUQsTUFBTSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUUsVUFBZSxFQUFFLElBQStCO1FBQy9ELE1BQU0sRUFBQyxJQUFJLEVBQUMsR0FBRyxJQUFJLENBQUM7UUFDcEIsSUFBSSxDQUFDLEtBQUssRUFBRSxDQUFDO1FBQ2IsTUFBTSxDQUNGLElBQUksQ0FBQyxLQUFLLElBQUksSUFBSSxDQUFDLGVBQWUsR0FBRyxDQUFDLEVBQUUsK0JBQStCO1FBQ3ZFLEtBQUssQ0FBQSxtRUFBbUUsSUFBSSxDQUFDLGVBQWUsb0dBQW9HLENBQ25NLENBQUM7UUFDRixJQUFJLFlBQVksR0FBVSxFQUFFLENBQUM7UUFDN0IsTUFBTSxRQUFRLEdBQUcsRUFBRSxDQUFDO1FBQ3BCLE1BQU0sRUFBQyxRQUFRLEVBQUUsR0FBRyxFQUFFLGFBQWEsRUFBRSxPQUFPLEVBQUUsZUFBZSxFQUFDLEdBQUcsSUFBSSxDQUFDO1FBRXRFLE1BQU0sT0FBTyxHQUFHLElBQUksQ0FBQyxhQUFhLENBQUMsVUFBVSxFQUFFLE9BQU8sRUFBRSxJQUFJLENBQUMsU0FBUyxDQUFDLENBQUM7UUFFeEUsSUFBSSxDQUFDLHVCQUF1QixDQUFDLFVBQVUsRUFBRSxJQUFJLENBQUMsQ0FBQztRQUMvQyx5RUFBeUU7UUFDekUsS0FBSyxNQUFNLEtBQUssSUFBSSxPQUFPLEVBQUUsQ0FBQztZQUMxQixJQUFJLEtBQUssQ0FBQyxPQUFPLENBQUMsRUFBRSxDQUFDO2dCQUNqQixNQUFNLGFBQWEsR0FBRyxLQUFLLENBQUMsT0FBTyxDQUFDLENBQUM7Z0JBQ3JDLE1BQU0sV0FBVyxHQUFHLEtBQUssQ0FBQyxjQUFjLENBQUMsRUFBQyxJQUFJLEVBQUUsR0FBRyxFQUFFLEtBQUssRUFBRSxhQUFhLEVBQUUsU0FBUyxFQUFFLElBQUksQ0FBQyxTQUFTLEVBQUMsRUFBRSxPQUFPLENBQUMsQ0FBQztnQkFDaEgsSUFBSSxXQUFXLENBQUMsSUFBSSxLQUFLLE9BQU8sRUFBRSxDQUFDO29CQUMvQixTQUFTO2dCQUNiLENBQUM7WUFDTCxDQUFDO1lBQ0QsSUFBSSxLQUFLLENBQUMsTUFBTSxDQUFDLEVBQUUsQ0FBQztnQkFDaEIsS0FBSyxNQUFNLFNBQVMsSUFBSSxLQUFLLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLE1BQU0sQ0FBQyxDQUFDLEVBQUUsQ0FBQztvQkFDckYsUUFBUSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsMEJBQTBCLENBQUMsR0FBRyxFQUFFLFFBQVEsRUFBRSxLQUFLLENBQUMsU0FBUyxDQUFDLEVBQUUsS0FBSyxDQUFDLEtBQUssQ0FBQyxJQUFJLE1BQU0sRUFBRSxTQUFTLEVBQUUsT0FBTyxFQUFFLGFBQWEsQ0FBQyxDQUFDLENBQUM7Z0JBQy9JLENBQUM7WUFDTCxDQUFDO2lCQUFNLElBQUksS0FBSyxDQUFDLFVBQVUsQ0FBQyxFQUFFLENBQUM7Z0JBQzNCLE1BQU0sRUFBQyxPQUFPLEVBQUUsR0FBRyxFQUFFLElBQUksRUFBRSxNQUFNLEVBQUMsR0FBRyxJQUFJLENBQUMsMkJBQTJCLENBQUMsS0FBSyxDQUFDLFVBQVUsQ0FBQyxDQUFDLENBQUM7Z0JBQ3pGLE1BQU0sR0FBRyxHQUFHLFdBQVcsTUFBTSxJQUFJLE9BQU8sVUFBVSxHQUFHLElBQUksSUFBSSxFQUFFLENBQUM7Z0JBQ2hFLFFBQVEsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLHFCQUFxQixDQUFDLEdBQUcsRUFBRSxRQUFRLEVBQUUsR0FBRyxFQUFFLGFBQWEsQ0FBQyxDQUFDLENBQUM7WUFDakYsQ0FBQztpQkFBTSxJQUFJLEtBQUssQ0FBQyxRQUFRLENBQUMsRUFBRSxDQUFDO2dCQUN6QixRQUFRLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxxQkFBcUIsQ0FBQyxHQUFHLEVBQUUsUUFBUSxFQUFFLEtBQUssQ0FBQyxRQUFRLENBQUMsRUFBRSxhQUFhLENBQUMsQ0FBQyxDQUFDO1lBQzdGLENBQUM7UUFFTCxDQUFDO1FBRUQsTUFBTSxPQUFPLENBQUMsR0FBRyxDQUFDLFFBQVEsQ0FBQyxDQUFDO1FBRTVCLEtBQUssTUFBTSxLQUFLLElBQUksT0FBTyxFQUFFLENBQUM7WUFDMUIsSUFBSSxLQUFLLENBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQztnQkFDakIsTUFBTSxhQUFhLEdBQUcsS0FBSyxDQUFDLE9BQU8sQ0FBQyxDQUFDO2dCQUNyQyxNQUFNLFdBQVcsR0FBRyxLQUFLLENBQUMsY0FBYyxDQUFDLEVBQUMsSUFBSSxFQUFFLEdBQUcsRUFBRSxLQUFLLEVBQUUsYUFBYSxFQUFFLFNBQVMsRUFBRSxJQUFJLENBQUMsU0FBUyxFQUFDLEVBQUUsT0FBTyxDQUFDLENBQUM7Z0JBQ2hILElBQUksV0FBVyxDQUFDLElBQUksS0FBSyxPQUFPLEVBQUUsQ0FBQztvQkFDL0IsU0FBUztnQkFDYixDQUFDO1lBQ0wsQ0FBQztZQUNELElBQUksS0FBSyxDQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUM7Z0JBQ2pCLG9CQUFvQixDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDO2dCQUNyQyxNQUFNLEtBQUssR0FBRyxtQkFBbUIsQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLEVBQUUsR0FBRyxDQUFDLENBQUM7Z0JBQ3ZELElBQUksS0FBSyxDQUFDLE1BQU0sSUFBSSxDQUFDLEVBQUUsQ0FBQztvQkFDcEIsTUFBTSxJQUFJLGNBQWMsQ0FBQyxFQUFDLE9BQU8sRUFBRSxzQ0FBc0MsS0FBSyxDQUFDLE9BQU8sQ0FBQyxFQUFFLEVBQUMsQ0FBQyxDQUFDO2dCQUNoRyxDQUFDO2dCQUNELEtBQUssTUFBTSxTQUFTLElBQUksS0FBSyxFQUFFLENBQUM7b0JBQzVCLE1BQU0sT0FBTyxHQUFHLE1BQU0sTUFBTSxDQUFDLFFBQVEsQ0FBQyxTQUFTLEVBQUUsRUFBQyxNQUFNLEVBQUUsS0FBSyxDQUFDLE1BQU0sSUFBSSxFQUFFLEVBQUMsRUFBRSxlQUFlLENBQUMsQ0FBQztvQkFDaEcsWUFBWSxHQUFHLFlBQVksQ0FBQyxNQUFNLENBQUMsTUFBTSxJQUFJLENBQUMsSUFBSSxDQUFDLE9BQU8sRUFBRSxJQUFJLENBQUMsQ0FBQyxDQUFDO2dCQUN2RSxDQUFDO1lBQ0wsQ0FBQztpQkFBTSxJQUFJLEtBQUssQ0FBQyxTQUFTLENBQUMsRUFBRSxDQUFDO2dCQUMxQixLQUFLLE1BQU0sU0FBUyxJQUFJLEtBQUssQ0FBQyxPQUFPLENBQUMsS0FBSyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsTUFBTSxDQUFDLENBQUMsRUFBRSxDQUFDO29CQUNyRixNQUFNLE9BQU8sR0FBRyxNQUFNLE1BQU0sQ0FBQyxRQUFRLENBQ2pDLEdBQUcsR0FBRyxJQUFJLFFBQVEsYUFBYSxPQUFPLENBQUMsTUFBTSxDQUFDLElBQUksSUFBSSxLQUFLLENBQUMsU0FBUyxDQUFDLElBQUksS0FBSyxDQUFDLEtBQUssQ0FBQyxJQUFJLE1BQU0sSUFBSSxTQUFTLEVBQUUsRUFDN0csRUFBQyxNQUFNLEVBQUUsS0FBSyxDQUFDLE1BQU0sSUFBSSxFQUFFLEVBQUMsRUFDNUIsZUFBZSxDQUFDLENBQUM7b0JBQ3ZCLHdEQUF3RDtvQkFDeEQsT0FBTyxDQUFDLFNBQVMsQ0FBQyxHQUFHLElBQUksQ0FBQyxhQUFhLENBQUMsT0FBTyxDQUFDLFNBQVMsQ0FBQyxFQUFFLElBQUksQ0FBQyxTQUFTLENBQUMsQ0FBQztvQkFDNUUsT0FBTyxDQUFDLFNBQVMsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxDQUFDLEtBQVUsRUFBRSxDQUFTLEVBQUUsRUFBRTt3QkFDakQsSUFBSSxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUM7NEJBQUUsT0FBTzt3QkFDNUIsSUFBSSxLQUFLLENBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQzs0QkFDakIsTUFBTSxXQUFXLEdBQUcsS0FBSyxDQUFDLGNBQWMsQ0FBQyxFQUFDLElBQUksRUFBRSxHQUFHLEVBQUUsSUFBSSxDQUFDLEdBQUcsRUFBRSxTQUFTLEVBQUUsSUFBSSxDQUFDLFNBQVMsRUFBRSxLQUFLLEVBQUUsS0FBSyxDQUFDLE9BQU8sQ0FBQyxFQUFDLEVBQUUsT0FBTyxDQUFDLENBQUM7NEJBQzNILElBQUksV0FBVyxDQUFDLElBQUksS0FBSyxPQUFPLEVBQUUsQ0FBQztnQ0FDL0IsT0FBTzs0QkFDWCxDQUFDO3dCQUNMLENBQUM7d0JBQ0QsT0FBTyxDQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFHOzRCQUNwQixPQUFPLEVBQUUsS0FBSyxDQUFDLFNBQVMsQ0FBQzs0QkFDekIsSUFBSSxFQUFFLEtBQUssQ0FBQyxPQUFPLENBQUMsQ0FBQyxPQUFPLENBQUMsS0FBSyxFQUFFLEVBQUUsQ0FBQzs0QkFDdkMsR0FBRyxFQUFFLEtBQUssQ0FBQyxLQUFLLENBQUM7NEJBQ2pCLE1BQU0sRUFBRSxLQUFLLENBQUMsTUFBTSxJQUFJLEVBQUU7eUJBQzdCLENBQUM7b0JBQ04sQ0FBQyxDQUFDLENBQUM7b0JBRUgsWUFBWSxHQUFHLFlBQVksQ0FBQyxNQUFNLENBQUMsTUFBTSxJQUFJLENBQUMsSUFBSSxDQUFDLE9BQU8sRUFBRSxJQUFJLENBQUMsQ0FBQyxDQUFDO2dCQUN2RSxDQUFDO1lBQ0wsQ0FBQztpQkFBTSxJQUFJLEtBQUssQ0FBQyxXQUFXLENBQUMsRUFBRSxDQUFDO2dCQUM1QixNQUFNLEVBQUMsTUFBTSxFQUFFLElBQUksRUFBRSxXQUFXLEVBQUUsYUFBYSxFQUFFLEdBQUcsRUFBRSxnQkFBZ0IsRUFBQyxHQUFHLElBQUksQ0FBQyxxQkFBcUIsQ0FBQyxLQUFLLENBQUMsV0FBVyxDQUFDLEVBQUUsT0FBTyxDQUFDLENBQUM7Z0JBQ2xJLG1HQUFtRztnQkFDbkcsSUFBSSxLQUFLLEdBQUcsQ0FBQyxHQUFHLGFBQWEsTUFBTSxFQUFFLEdBQUcsYUFBYSxlQUFlLEVBQUUsSUFBSSxDQUFDLENBQUM7Z0JBRTVFLDJIQUEySDtnQkFDM0gsSUFBSSxDQUFDLElBQUksQ0FBQyxhQUFhLEVBQUUsQ0FBQztvQkFDdEIsS0FBSyxNQUFNLENBQUMsSUFBSSxLQUFLLEVBQUUsQ0FBQzt3QkFDcEIsTUFBTSxhQUFhLEdBQUcsR0FBRyxHQUFHLElBQUksUUFBUSxhQUFhLE9BQU8sQ0FBQyxNQUFNLENBQUMsSUFBSSxJQUFJLFdBQVcsSUFBSSxHQUFHLElBQUksQ0FBQyxFQUFFLENBQUM7d0JBQ3RHLElBQUksRUFBRSxDQUFDLFVBQVUsQ0FBQyxhQUFhLENBQUMsRUFBRSxDQUFDOzRCQUMvQixLQUFLLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQzs0QkFDWixNQUFNO3dCQUNWLENBQUM7b0JBQ0wsQ0FBQztnQkFDTCxDQUFDO2dCQUVELEtBQUssTUFBTSxDQUFDLElBQUksS0FBSyxFQUFFLENBQUM7b0JBQ3BCLE1BQU0sQ0FBQyxDQUFDLEtBQUssSUFBSSxFQUFFLHlEQUF5RCxLQUFLLENBQUMsV0FBVyxDQUFDLHlCQUF5QixLQUFLLHFCQUFxQixNQUFNLEVBQUU7d0JBQ3JJLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxJQUFJLElBQUksRUFBRSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsR0FBRyxJQUFJLFdBQVcsSUFBSSxDQUFDLENBQUM7b0JBRXBFLElBQUksZ0JBQWdCLEVBQUUsQ0FBQzt3QkFDbkIsTUFBTSxxQkFBcUIsR0FBRyxHQUFHLEdBQUcsSUFBSSxDQUFDLEVBQUUsQ0FBQzt3QkFDNUMsSUFBSSxDQUFDLENBQUMsTUFBTSxFQUFFLENBQUMsVUFBVSxDQUFDLHFCQUFxQixDQUFDLENBQUMsRUFBRSxDQUFDOzRCQUNoRCxTQUFTO3dCQUNiLENBQUM7d0JBRUQsTUFBTSxPQUFPLEdBQUcsTUFBTSxNQUFNLENBQUMsUUFBUSxDQUFDLHFCQUFxQixFQUFFLEVBQUMsTUFBTSxFQUFFLEtBQUssQ0FBQyxNQUFNLElBQUksRUFBRSxFQUFDLEVBQUUsZUFBZSxDQUFDLENBQUM7d0JBQzVHLFlBQVksR0FBRyxZQUFZLENBQUMsTUFBTSxDQUFDLE1BQU0sSUFBSSxDQUFDLElBQUksQ0FBQyxPQUFPLEVBQUUsSUFBSSxDQUFDLENBQUMsQ0FBQzt3QkFDbkUsTUFBTTtvQkFDVixDQUFDO3lCQUFNLENBQUM7d0JBQ0osTUFBTSxhQUFhLEdBQUcsR0FBRyxHQUFHLElBQUksUUFBUSxhQUFhLE9BQU8sQ0FBQyxNQUFNLENBQUMsSUFBSSxJQUFJLFdBQVcsSUFBSSxHQUFHLElBQUksQ0FBQyxFQUFFLENBQUM7d0JBQ3RHLHlEQUF5RDt3QkFDekQsSUFBSSxDQUFDLEVBQUUsQ0FBQyxVQUFVLENBQUMsYUFBYSxDQUFDLElBQUksQ0FBQyxDQUFDLE1BQU0sS0FBSyxDQUFDLGVBQWUsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxFQUFFLEdBQUcsRUFBRSxNQUFNLEVBQUUsV0FBVyxFQUFFLE9BQU8sQ0FBQyxNQUFNLENBQUMsTUFBTSxFQUFFLE9BQU8sQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLENBQUMsRUFBRSxDQUFDOzRCQUNoSixTQUFTO3dCQUNiLENBQUM7d0JBRUQsTUFBTSxPQUFPLEdBQUc7NEJBQ1osT0FBTyxFQUFFO2dDQUNMLE9BQU8sRUFBRSxXQUFXO2dDQUNwQixJQUFJLEVBQUUsQ0FBQztnQ0FDUCxHQUFHLEVBQUUsR0FBRztnQ0FDUixNQUFNLEVBQUUsS0FBSyxDQUFDLE1BQU0sSUFBSSxFQUFFOzZCQUM3Qjt5QkFDSixDQUFDO3dCQUNGLFlBQVksR0FBRyxZQUFZLENBQUMsTUFBTSxDQUFDLE1BQU0sSUFBSSxDQUFDLElBQUksQ0FBQyxPQUFPLEVBQUUsSUFBSSxDQUFDLENBQUMsQ0FBQzt3QkFDbkUsTUFBTTtvQkFDVixDQUFDO2dCQUNMLENBQUM7WUFDTCxDQUFDO2lCQUFNLElBQUksS0FBSyxDQUFDLFVBQVUsQ0FBQyxFQUFFLENBQUM7Z0JBQzNCLE1BQU0sRUFBQyxPQUFPLEVBQUUsR0FBRyxFQUFFLElBQUksRUFBRSxNQUFNLEVBQUMsR0FBRyxJQUFJLENBQUMsMkJBQTJCLENBQUMsS0FBSyxDQUFDLFVBQVUsQ0FBQyxDQUFDLENBQUM7Z0JBQ3pGLE1BQU0sS0FBSyxHQUFHLEtBQUssQ0FBQyxLQUFLLENBQUMsV0FBVyxNQUFNLElBQUksT0FBTyxVQUFVLEdBQUcsSUFBSSxJQUFJLEVBQUUsQ0FBQyxDQUFDO2dCQUMvRSxNQUFNLE9BQU8sR0FBRyxNQUFNLE1BQU0sQ0FBQyxRQUFRLENBQ2pDLEdBQUcsR0FBRyxJQUFJLFFBQVEsYUFBYSxLQUFLLEVBQUUsRUFBRSxFQUFDLE1BQU0sRUFBRSxLQUFLLENBQUMsTUFBTSxJQUFJLEVBQUUsRUFBQyxFQUFFLGVBQWUsQ0FDeEYsQ0FBQztnQkFDRixZQUFZLEdBQUcsWUFBWSxDQUFDLE1BQU0sQ0FBQyxNQUFNLElBQUksQ0FBQyxJQUFJLENBQUMsT0FBTyxFQUFFLElBQUksQ0FBQyxDQUFDLENBQUM7WUFDdkUsQ0FBQztpQkFBTSxJQUFJLEtBQUssQ0FBQyxRQUFRLENBQUMsRUFBRSxDQUFDO2dCQUN6QixNQUFNLEtBQUssR0FBRyxLQUFLLENBQUMsS0FBSyxDQUFDLEtBQUssQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDO2dCQUMzQyxNQUFNLE9BQU8sR0FBRyxNQUFNLE1BQU0sQ0FBQyxRQUFRLENBQ2pDLEdBQUcsR0FBRyxJQUFJLFFBQVEsYUFBYSxLQUFLLEVBQUUsRUFBRSxFQUFDLE1BQU0sRUFBRSxLQUFLLENBQUMsTUFBTSxJQUFJLEVBQUUsRUFBQyxFQUFFLGVBQWUsQ0FDeEYsQ0FBQztnQkFDRixZQUFZLEdBQUcsWUFBWSxDQUFDLE1BQU0sQ0FBQyxNQUFNLElBQUksQ0FBQyxJQUFJLENBQUMsT0FBTyxFQUFFLElBQUksQ0FBQyxDQUFDLENBQUM7WUFDdkUsQ0FBQztpQkFBTSxDQUFDO2dCQUNKLE1BQU0sSUFBSSxjQUFjLENBQUMsRUFBQyxPQUFPLEVBQUUsNkJBQTZCLElBQUksQ0FBQyxTQUFTLENBQUMsS0FBSyxDQUFDLEVBQUUsRUFBQyxDQUFDLENBQUM7WUFDOUYsQ0FBQztRQUNMLENBQUM7UUFFRCxZQUFZLENBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxDQUFDO1FBQzlCLE9BQU8sWUFBWSxDQUFDO0lBQ3hCLENBQUM7SUFFRCxNQUFNLENBQUMsYUFBYSxDQUFFLENBQU0sRUFBRSxTQUFrQztRQUM1RCxJQUFJLE9BQU8sR0FBRyxDQUFDLElBQUksRUFBRSxDQUFDO1FBQ3RCLElBQUksT0FBTyxJQUFJLE9BQU8sQ0FBQyxNQUFNLElBQUksSUFBSSxFQUFFLENBQUM7WUFDcEMsT0FBTyxHQUFHLENBQUUsQ0FBQyxDQUFFLENBQUM7UUFDcEIsQ0FBQztRQUNELElBQUksT0FBTyxPQUFPLEtBQUssUUFBUSxFQUFFLENBQUM7WUFDOUIsT0FBTyxHQUFHLENBQUMsT0FBTyxDQUFDLENBQUM7UUFDeEIsQ0FBQztRQUVELEtBQUssTUFBTSxDQUFDLEtBQUssRUFBRSxLQUFLLENBQUMsSUFBSSxNQUFNLENBQUMsT0FBTyxDQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUM7WUFDbkQsSUFBSSxPQUFPLEtBQUssS0FBSyxRQUFRLElBQUksQ0FBQyxLQUFLLENBQUMsVUFBVSxDQUFDLFFBQVEsQ0FBQyxJQUFJLEtBQUssQ0FBQyxVQUFVLENBQUMsT0FBTyxDQUFDLENBQUMsRUFBRSxDQUFDO2dCQUN6RixPQUFPLENBQUMsS0FBSyxDQUFDLEdBQUcsRUFBQyxRQUFRLEVBQUUsS0FBSyxFQUFDLENBQUM7WUFDdkMsQ0FBQztpQkFBTSxJQUFJLE9BQU8sS0FBSyxLQUFLLFFBQVEsRUFBRSxDQUFDO2dCQUNuQyxPQUFPLENBQUMsS0FBSyxDQUFDLEdBQUcsRUFBQyxPQUFPLEVBQUUsS0FBSyxFQUFDLENBQUM7WUFDdEMsQ0FBQztpQkFBTSxDQUFDO2dCQUNKLE9BQU8sQ0FBQyxLQUFLLENBQUMsR0FBRyxLQUFLLENBQUM7WUFDM0IsQ0FBQztRQUVMLENBQUM7UUFFRCxLQUFLLE1BQU0sS0FBSyxJQUFJLE9BQU8sRUFBRSxDQUFDO1lBQzFCLEtBQUssTUFBTSxDQUFDLEdBQUcsRUFBRSxLQUFLLENBQUMsSUFBSSxNQUFNLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUM7Z0JBQy9DLElBQUksS0FBSyxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDO29CQUN2QixLQUFLLENBQUMsR0FBRyxDQUFDLEdBQUcsS0FBSyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsS0FBSyxDQUFDLFVBQVUsQ0FBQyxDQUFDLEVBQUUsU0FBUyxDQUFDLENBQUMsQ0FBQztnQkFDbEUsQ0FBQztxQkFBTSxDQUFDO29CQUNKLEtBQUssQ0FBQyxHQUFHLENBQUMsR0FBRyxLQUFLLENBQUMsVUFBVSxDQUFDLEtBQUssRUFBRSxTQUFTLENBQUMsQ0FBQztnQkFDcEQsQ0FBQztZQUNMLENBQUM7UUFDTCxDQUFDO1FBRUQsT0FBTyxPQUFPLENBQUM7SUFDbkIsQ0FBQztJQUVELE1BQU0sQ0FBQywyQkFBMkIsQ0FBRSxRQUFnQjtRQUNoRCxPQUFPO1lBQ0gsTUFBTSxFQUFFLFlBQVk7WUFDcEIsT0FBTyxFQUFFLG1CQUFtQjtZQUM1QixHQUFHLEVBQUUsTUFBTTtZQUNYLElBQUksRUFBRSwyQkFBMkIsUUFBUSxFQUFFO1NBQzlDLENBQUM7SUFDTixDQUFDO0lBRUQsTUFBTSxDQUFDLHFCQUFxQixDQUFFLFNBQWlCLEVBQUUsT0FBZ0I7UUFDN0QsTUFBTSxDQUFDLENBQUMsU0FBUyxDQUFDLFFBQVEsQ0FBQyxLQUFLLENBQUMsRUFBRSx5REFBeUQsU0FBUyxnQ0FBZ0MsQ0FBQyxDQUFDO1FBQ3ZJLE1BQU0sT0FBTyxHQUFHLDZGQUE2RixDQUFDLENBQUMsMkJBQTJCO1FBQzFJLE1BQU0sY0FBYyxHQUFHLE9BQU8sQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLENBQUM7UUFFL0MsSUFBSSxjQUFjLEVBQUUsTUFBTSxJQUFJLElBQUk7WUFBRSxNQUFNLElBQUksS0FBSyxDQUFDLHFHQUFxRyxTQUFTLEVBQUUsQ0FBQyxDQUFDO1FBRXRLLE1BQU0sRUFBQyxNQUFNLEVBQUUsV0FBVyxFQUFFLElBQUksRUFBQyxHQUFHLGNBQWMsQ0FBQyxNQUFNLENBQUM7UUFDMUQsSUFBSSxHQUFHLEdBQUcsY0FBYyxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsQ0FBQztRQUN2QyxNQUFNLGdCQUFnQixHQUFHLFdBQVcsS0FBSyxHQUFHLE9BQU8sQ0FBQyxNQUFNLENBQUMsS0FBSyxJQUFJLE9BQU8sQ0FBQyxNQUFNLENBQUMsT0FBTyxFQUFFLElBQUksR0FBRyxLQUFLLE9BQU8sQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDO1FBRTNILElBQUksQ0FBQyxnQkFBZ0IsRUFBRSxDQUFDO1lBQ3BCLE1BQU0sNEJBQTRCLEdBQUcsZUFBZSxDQUFDO1lBQ3JELElBQUksR0FBRyxJQUFJLFNBQVMsSUFBSSw0QkFBNEIsQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQztnQkFDN0QsaUVBQWlFO2dCQUNqRSxJQUFJLE1BQU0sQ0FBQztnQkFDWCxJQUFJLENBQUM7b0JBQ0QsTUFBTSxHQUFHLEtBQUssQ0FBQyxTQUFTLENBQUMsQ0FBQyxLQUFLLEVBQUUsV0FBVyxFQUFFLFFBQVEsRUFBRSxPQUFPLE1BQU0sSUFBSSxXQUFXLEVBQUUsQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDO2dCQUNwRyxDQUFDO2dCQUFDLE1BQU0sQ0FBQztvQkFDTCxNQUFNLEdBQUcsS0FBSyxDQUFDLFNBQVMsQ0FBQyxDQUFDLEtBQUssRUFBRSxXQUFXLEVBQUUsUUFBUSxFQUFFLFdBQVcsTUFBTSxJQUFJLElBQUksSUFBSSxHQUFHLElBQUksV0FBVyxNQUFNLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQztnQkFDM0gsQ0FBQztnQkFDRCxNQUFNLENBQUMsTUFBTSxDQUFDLENBQUM7Z0JBQ2YsTUFBTSxJQUFJLEdBQUcsTUFBTTtxQkFDZCxLQUFLLENBQUMsSUFBSSxDQUFDO3FCQUNYLEdBQUcsQ0FBQyxDQUFDLElBQUksRUFBRSxFQUFFO29CQUNWLE9BQU8sSUFBSTt5QkFDTixLQUFLLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDO3lCQUNkLEtBQUssQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztnQkFDdkIsQ0FBQyxDQUFDLENBQUM7Z0JBQ1AsTUFBTSxJQUFJLEdBQUcsMkJBQTJCLENBQUMsR0FBRyxFQUFFLElBQUksQ0FBQyxDQUFDO2dCQUNwRCxNQUFNLENBQUMsSUFBSSxFQUFFLHlEQUF5RCxTQUFTLGlCQUFpQixHQUFHLGNBQWMsQ0FBQyxDQUFDO2dCQUNuSCxHQUFHLEdBQUcsSUFBSSxDQUFDO1lBQ2YsQ0FBQztRQUNMLENBQUM7UUFDRCxPQUFPO1lBQ0gsTUFBTSxFQUFFLE1BQU07WUFDZCxJQUFJLEVBQUUsSUFBSTtZQUNWLFdBQVcsRUFBRSxXQUFXO1lBQ3hCLGFBQWEsRUFBRSxhQUFhLGNBQWMsQ0FBQyxNQUFNLENBQUMsZUFBZSxDQUFDLEVBQUU7WUFDcEUsR0FBRyxFQUFFLEdBQUc7WUFDUixnQkFBZ0IsRUFBRSxnQkFBZ0I7U0FDckMsQ0FBQztJQUNOLENBQUM7SUFFRCxNQUFNLENBQUMsS0FBSyxDQUFDLHFCQUFxQixDQUFFLEdBQVcsRUFBRSxRQUFnQixFQUFFLEdBQVcsRUFBRSxhQUFzQjtRQUNsRyxNQUFNLEtBQUssR0FBRyxLQUFLLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxDQUFDO1FBQy9CLElBQUksQ0FBQztZQUNELE1BQU0sTUFBTSxHQUFHLEdBQUcsR0FBRyxJQUFJLFFBQVEsYUFBYSxLQUFLLEVBQUUsQ0FBQztZQUN0RCxJQUFJLE1BQU0sRUFBRSxDQUFDLFVBQVUsQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLGFBQWE7Z0JBQUUsT0FBTztZQUMxRCxNQUFNLEdBQUcsR0FBRyxNQUFNLEtBQUssQ0FBQyxHQUFHLENBQUMsR0FBRyxFQUFFLEVBQUMsT0FBTyxFQUFFLEVBQUMsWUFBWSxFQUFFLGlCQUFpQixFQUFDLEVBQUMsQ0FBQyxDQUFDO1lBQy9FLE1BQU0sRUFBRSxDQUFDLFVBQVUsQ0FBQyxNQUFNLEVBQUUsR0FBRyxDQUFDLElBQUksQ0FBQyxDQUFDO1FBQzFDLENBQUM7UUFBQyxPQUFPLENBQUMsRUFBRSxDQUFDO1lBQ1QsTUFBTSxJQUFJLGNBQWMsQ0FBQyxFQUFDLE9BQU8sRUFBRSx1Q0FBdUMsR0FBRyxLQUFLLENBQUMsRUFBRSxFQUFDLENBQUMsQ0FBQztRQUM1RixDQUFDO0lBQ0wsQ0FBQztJQUVELE1BQU0sQ0FBQyxLQUFLLENBQUMsMEJBQTBCLENBQUUsR0FBVyxFQUFFLFFBQWdCLEVBQUUsT0FBZSxFQUFFLEdBQVcsRUFBRSxJQUFZLEVBQUUsT0FBZ0IsRUFBRSxhQUFzQjtRQUN4SixNQUFNLE1BQU0sR0FBRyxPQUFPLENBQUMsTUFBTSxDQUFDO1FBQzlCLE1BQU0sY0FBYyxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUMsTUFBTSxFQUFFLEVBQUUsQ0FBQyxDQUFDO1FBQ2hELElBQUksQ0FBQztZQUNELE1BQU0sTUFBTSxHQUFHLEdBQUcsUUFBUSxhQUFhLE1BQU0sQ0FBQyxJQUFJLElBQUksT0FBTyxJQUFJLEdBQUcsRUFBRSxDQUFDO1lBQ3ZFLElBQUksTUFBTSxFQUFFLENBQUMsVUFBVSxDQUFDLEdBQUcsR0FBRyxJQUFJLE1BQU0sSUFBSSxjQUFjLEVBQUUsQ0FBQyxJQUFJLENBQUMsYUFBYTtnQkFBRSxPQUFPO1lBRXhGLElBQUksTUFBTSxDQUFDLE1BQU0sQ0FBQyxVQUFVLENBQUMsTUFBTSxDQUFDLEVBQUUsQ0FBQztnQkFDbkMsTUFBTSxHQUFHLEdBQUcsTUFBTSxHQUFHLElBQUksQ0FBQyxNQUFNLEVBQUUsQ0FBQztnQkFDbkMsTUFBTSxFQUFFLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsR0FBRyxHQUFHLElBQUksTUFBTSxJQUFJLGNBQWMsRUFBRSxDQUFDLENBQUMsQ0FBQztnQkFFcEUsTUFBTSxjQUFjLEdBQUcsQ0FBQyxHQUFHLEtBQUssTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsWUFBWSxHQUFHLEVBQUUsQ0FBQztnQkFDakUsTUFBTSxLQUFLLENBQUMsU0FBUyxDQUFDO29CQUNsQixNQUFNLEdBQUcsSUFBSSxRQUFRLEVBQUU7b0JBQ3ZCLGFBQWEsY0FBYyxpQ0FBaUMsTUFBTSxDQUFDLE1BQU0sTUFBTSxNQUFNLENBQUMsSUFBSSxJQUFJLE1BQU0sQ0FBQyxJQUFJLElBQUksT0FBTyxRQUFRLEdBQUcsSUFBSSxNQUFNLElBQUksR0FBRyxFQUFFO29CQUNsSixNQUFNLEdBQUcsSUFBSSxNQUFNLElBQUksR0FBRyxFQUFFO29CQUM1QixxQ0FBcUMsY0FBYyxFQUFFO29CQUNyRCxjQUFjO29CQUNkLE1BQU0sR0FBRyxJQUFJLFFBQVEsRUFBRTtvQkFDdkIsTUFBTSxHQUFHLElBQUksTUFBTSxJQUFJLEdBQUcsSUFBSSxjQUFjLElBQUksR0FBRyxJQUFJLE1BQU0sSUFBSSxjQUFjLEVBQUU7aUJBQ3BGLEVBQUUsR0FBRyxDQUFDLENBQUM7WUFDWixDQUFDO2lCQUFNLENBQUM7Z0JBQ0osTUFBTSxFQUFFLENBQUMsTUFBTSxDQUFDLEdBQUcsR0FBRyxJQUFJLE1BQU0sRUFBRSxDQUFDLENBQUM7Z0JBQ3BDLE1BQU0sS0FBSyxDQUFDLElBQUksQ0FBQyxxREFBcUQsTUFBTSxDQUFDLElBQUksSUFBSSxNQUFNLENBQUMsSUFBSSxJQUFJLE9BQU8sUUFBUSxHQUFHLElBQUksY0FBYyxtQkFBbUIsTUFBTSxHQUFHLEVBQUUsR0FBRyxDQUFDLENBQUM7WUFDL0ssQ0FBQztRQUNMLENBQUM7UUFBQyxPQUFPLENBQUMsRUFBRSxDQUFDO1lBQ1QsTUFBTSxJQUFJLGNBQWMsQ0FBQyxFQUFDLE9BQU8sRUFBRSxtREFBbUQsT0FBTyxVQUFVLEdBQUcsV0FBVyxjQUFjLE9BQU8sQ0FBQyxFQUFFLEVBQUMsQ0FBQyxDQUFDO1FBQ3BKLENBQUM7SUFDTCxDQUFDO0lBRUQsTUFBTSxDQUFVLGtCQUFrQixHQUFHLENBQUMsR0FBRyxFQUFFO1FBQ3ZDLE1BQU0sS0FBSyxHQUFHLElBQUksR0FBRyxFQUFvQixDQUFDO1FBQzFDLE9BQU8sQ0FBQyxJQUFZLEVBQUUsRUFBRTtZQUNwQixJQUFJLE1BQU0sR0FBRyxLQUFLLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxDQUFDO1lBQzdCLElBQUksT0FBTyxNQUFNLEtBQUssV0FBVztnQkFBRSxPQUFPLE1BQU0sQ0FBQztZQUVqRCxNQUFNLEdBQUcsTUFBTSxDQUFDLElBQUksQ0FBQyxJQUFJLEVBQUUsRUFBQyxHQUFHLEVBQUUsSUFBSSxFQUFFLFNBQVMsRUFBRSxJQUFJLEVBQUMsQ0FBQyxDQUFDO1lBQ3pELEtBQUssQ0FBQyxHQUFHLENBQUMsSUFBSSxFQUFFLE1BQU0sQ0FBQyxDQUFDO1lBQ3hCLE9BQU8sTUFBTSxDQUFDO1FBQ2xCLENBQUMsQ0FBQztJQUNOLENBQUMsQ0FBQyxFQUFFLENBQUM7O0FBR1QsTUFBTSxVQUFVLG9CQUFvQixDQUFFLFFBQWdCO0lBQ2xELE1BQU0sQ0FBQyxDQUFDLFFBQVEsQ0FBQyxVQUFVLENBQUMsSUFBSSxDQUFDLEVBQUUsS0FBSyxRQUFRLHdHQUF3RyxDQUFDLENBQUM7SUFDMUosTUFBTSxDQUFDLENBQUMsUUFBUSxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUMsRUFBRSxLQUFLLFFBQVEsK0VBQStFLENBQUMsQ0FBQztBQUNuSSxDQUFDO0FBRUQsTUFBTSxVQUFVLDJCQUEyQixDQUFFLEtBQWEsRUFBRSxPQUFpQjtJQUN6RSwwRkFBMEY7SUFDMUYsTUFBTSxtQkFBbUIsR0FBRyxNQUFNLENBQUMsS0FBSyxDQUNwQyxPQUFPLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUN2QyxDQUFDO0lBRUYsTUFBTSxLQUFLLEdBQUcsbUJBQW1CLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxFQUFFO1FBQ3ZDLElBQUksS0FBSyxJQUFJLFNBQVMsRUFBRSxDQUFDO1lBQ3JCLE1BQU0sWUFBWSxHQUFHLE1BQU0sQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUM7WUFDckMsTUFBTSxDQUFDLFlBQVksQ0FBQyxDQUFDO1lBQ3JCLE9BQU8sQ0FBQyxZQUFZLENBQUMsVUFBVSxDQUFDLE1BQU0sSUFBSSxDQUFDLElBQUksWUFBWSxDQUFDLEtBQUssQ0FBQyxNQUFNLElBQUksQ0FBQyxDQUFDLENBQUM7UUFDbkYsQ0FBQzthQUFNLENBQUM7WUFDSixPQUFPLE1BQU0sQ0FBQyxTQUFTLENBQUMsQ0FBQyxFQUFFLEtBQUssQ0FBQyxDQUFDO1FBQ3RDLENBQUM7SUFDTCxDQUFDLENBQUMsQ0FBQztJQUNILE9BQU8sS0FBSyxDQUFDO0FBQ2pCLENBQUM7QUFFRCxNQUFNLFVBQVUsbUJBQW1CLENBQUUsT0FBZSxFQUFFLEdBQVc7SUFDN0QsTUFBTSxTQUFTLEdBQUcsY0FBYyxDQUFDLGtCQUFrQixDQUFDLEdBQUcsQ0FBQyxDQUFDO0lBRXpELElBQUksQ0FBQyxPQUFPLENBQUMsVUFBVSxDQUFDLEdBQUcsQ0FBQztRQUFFLE9BQU8sR0FBRyxJQUFJLE9BQU8sRUFBRSxDQUFDLENBQUMsaUNBQWlDO0lBQ3hGLE9BQU8sR0FBRyxHQUFHLEdBQUcsR0FBRyxPQUFPLEVBQUUsQ0FBQztJQUU3QiwwQ0FBMEM7SUFDMUMsT0FBTyxHQUFHLE9BQU8sQ0FBQyxPQUFPLENBQUMscUJBQXFCLEVBQUUsTUFBTSxDQUFDLENBQUM7SUFFekQsd0JBQXdCO0lBQ3hCLE1BQU0sUUFBUSxHQUFHLEtBQUssQ0FBQztJQUN2QixPQUFPLEdBQUcsT0FBTyxDQUFDLE9BQU8sQ0FBQyxXQUFXLEVBQUUsUUFBUSxDQUFDLENBQUM7SUFFakQsc0NBQXNDO0lBQ3RDLE1BQU0sc0JBQXNCLEdBQUcsVUFBVSxDQUFDO0lBQzFDLE9BQU8sR0FBRyxPQUFPLENBQUMsT0FBTyxDQUFDLE9BQU8sRUFBRSxzQkFBc0IsQ0FBQyxDQUFDO0lBRTNELE1BQU0sS0FBSyxHQUFHLEtBQUssQ0FBQyxPQUFPLENBQUMsSUFBSSxPQUFPLEVBQUUsQ0FBQyxDQUFDO0lBQzNDLE9BQU8sU0FBUyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQU0sRUFBRSxFQUFFLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO0FBQzFELENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge0FyZ3Z9IGZyb20gXCIuL2FyZ3YuanNcIjtcbmltcG9ydCB7VXRpbHN9IGZyb20gXCIuL3V0aWxzLmpzXCI7XG5pbXBvcnQgZnMgZnJvbSBcImZzLWV4dHJhXCI7XG5pbXBvcnQge1dyaXRlU3RyZWFtc30gZnJvbSBcIi4vd3JpdGUtc3RyZWFtcy5qc1wiO1xuaW1wb3J0IHtHaXREYXRhfSBmcm9tIFwiLi9naXQtZGF0YS5qc1wiO1xuaW1wb3J0IGFzc2VydCwge0Fzc2VydGlvbkVycm9yfSBmcm9tIFwiYXNzZXJ0XCI7XG5pbXBvcnQgY2hhbGsgZnJvbSBcImNoYWxrXCI7XG5pbXBvcnQge1BhcnNlcn0gZnJvbSBcIi4vcGFyc2VyLmpzXCI7XG5pbXBvcnQgYXhpb3MgZnJvbSBcImF4aW9zXCI7XG5pbXBvcnQgZ2xvYmJ5IGZyb20gXCJnbG9iYnlcIjtcbmltcG9ydCBwYXRoIGZyb20gXCJwYXRoXCI7XG5pbXBvcnQgc2VtdmVyIGZyb20gXCJzZW12ZXJcIjtcbmltcG9ydCB7UkUySlN9IGZyb20gXCJyZTJqc1wiO1xuXG50eXBlIFBhcnNlckluY2x1ZGVzSW5pdE9wdGlvbnMgPSB7XG4gICAgYXJndjogQXJndjtcbiAgICBjd2Q6IHN0cmluZztcbiAgICBzdGF0ZURpcjogc3RyaW5nO1xuICAgIHdyaXRlU3RyZWFtczogV3JpdGVTdHJlYW1zO1xuICAgIGdpdERhdGE6IEdpdERhdGE7XG4gICAgZmV0Y2hJbmNsdWRlczogYm9vbGVhbjtcbiAgICB2YXJpYWJsZXM6IHtba2V5OiBzdHJpbmddOiBzdHJpbmd9O1xuICAgIGV4cGFuZFZhcmlhYmxlczogYm9vbGVhbjtcbiAgICBtYXhpbXVtSW5jbHVkZXM6IG51bWJlcjtcbn07XG5cbmV4cG9ydCBjbGFzcyBQYXJzZXJJbmNsdWRlcyB7XG4gICAgcHJpdmF0ZSBzdGF0aWMgY291bnQ6IG51bWJlciA9IDA7XG5cbiAgICBzdGF0aWMgcmVzZXRDb3VudCAoKTogdm9pZCB7XG4gICAgICAgIHRoaXMuY291bnQgPSAwO1xuICAgIH1cblxuICAgIHByaXZhdGUgc3RhdGljIG5vcm1hbGl6ZVRyaWdnZXJJbmNsdWRlIChnaXRsYWJEYXRhOiBhbnksIG9wdHM6IFBhcnNlckluY2x1ZGVzSW5pdE9wdGlvbnMpIHtcbiAgICAgICAgY29uc3Qge3dyaXRlU3RyZWFtc30gPSBvcHRzO1xuICAgICAgICBmb3IgKGNvbnN0IFtqb2JOYW1lLCBqb2JEYXRhXSBvZiBPYmplY3QuZW50cmllczxhbnk+KGdpdGxhYkRhdGEgPz8ge30pKSB7XG4gICAgICAgICAgICBpZiAodHlwZW9mIGpvYkRhdGEudHJpZ2dlcj8uaW5jbHVkZSA9PT0gXCJzdHJpbmdcIikge1xuICAgICAgICAgICAgICAgIGpvYkRhdGEudHJpZ2dlci5pbmNsdWRlID0gW3tcbiAgICAgICAgICAgICAgICAgICAgbG9jYWw6IGpvYkRhdGEudHJpZ2dlci5pbmNsdWRlLFxuICAgICAgICAgICAgICAgIH0gXTtcbiAgICAgICAgICAgIH0gZWxzZSBpZiAoam9iRGF0YS50cmlnZ2VyPy5wcm9qZWN0KSB7XG4gICAgICAgICAgICAgICAgd3JpdGVTdHJlYW1zLm1lbW9TdGRvdXQoY2hhbGtge2JnWWVsbG93QnJpZ2h0ICBXQVJOIH0gVGhlIGpvYjogXFxge2JsdWVCcmlnaHQgJHtqb2JOYW1lfX1cXGAgd2lsbCBiZSBuby1vcC4gTXVsdGktcHJvamVjdCBwaXBlbGluZSBpcyBub3Qgc3VwcG9ydGVkIGJ5IGdpdGxhYi1jaS1sb2NhbFxcbmApO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfVxuXG4gICAgc3RhdGljIGFzeW5jIGluaXQgKGdpdGxhYkRhdGE6IGFueSwgb3B0czogUGFyc2VySW5jbHVkZXNJbml0T3B0aW9ucyk6IFByb21pc2U8YW55W10+IHtcbiAgICAgICAgY29uc3Qge2FyZ3Z9ID0gb3B0cztcbiAgICAgICAgdGhpcy5jb3VudCsrO1xuICAgICAgICBhc3NlcnQoXG4gICAgICAgICAgICB0aGlzLmNvdW50IDw9IG9wdHMubWF4aW11bUluY2x1ZGVzICsgMSwgLy8gMXN0IGluaXQgY2FsbCBpcyBub3QgY291bnRlZFxuICAgICAgICAgICAgY2hhbGtgVGhpcyBHaXRMYWIgQ0kgY29uZmlndXJhdGlvbiBpcyBpbnZhbGlkOiBNYXhpbXVtIG9mIHtibHVlQnJpZ2h0ICR7b3B0cy5tYXhpbXVtSW5jbHVkZXN9fSBuZXN0ZWQgaW5jbHVkZXMgYXJlIGFsbG93ZWQhLiBUaGlzIGxpbWl0IGNhbiBiZSBpbmNyZWFzZWQgd2l0aCB0aGUgLS1tYXhpbXVtLWluY2x1ZGVzIGNsaSBmbGFncy5gLFxuICAgICAgICApO1xuICAgICAgICBsZXQgaW5jbHVkZURhdGFzOiBhbnlbXSA9IFtdO1xuICAgICAgICBjb25zdCBwcm9taXNlcyA9IFtdO1xuICAgICAgICBjb25zdCB7c3RhdGVEaXIsIGN3ZCwgZmV0Y2hJbmNsdWRlcywgZ2l0RGF0YSwgZXhwYW5kVmFyaWFibGVzfSA9IG9wdHM7XG5cbiAgICAgICAgY29uc3QgaW5jbHVkZSA9IHRoaXMuZXhwYW5kSW5jbHVkZShnaXRsYWJEYXRhPy5pbmNsdWRlLCBvcHRzLnZhcmlhYmxlcyk7XG5cbiAgICAgICAgdGhpcy5ub3JtYWxpemVUcmlnZ2VySW5jbHVkZShnaXRsYWJEYXRhLCBvcHRzKTtcbiAgICAgICAgLy8gRmluZCBmaWxlcyB0byBmZXRjaCBmcm9tIHJlbW90ZSBhbmQgcGxhY2UgaW4gLmdpdGxhYi1jaS1sb2NhbC9pbmNsdWRlc1xuICAgICAgICBmb3IgKGNvbnN0IHZhbHVlIG9mIGluY2x1ZGUpIHtcbiAgICAgICAgICAgIGlmICh2YWx1ZVtcInJ1bGVzXCJdKSB7XG4gICAgICAgICAgICAgICAgY29uc3QgaW5jbHVkZV9ydWxlcyA9IHZhbHVlW1wicnVsZXNcIl07XG4gICAgICAgICAgICAgICAgY29uc3QgcnVsZXNSZXN1bHQgPSBVdGlscy5nZXRSdWxlc1Jlc3VsdCh7YXJndiwgY3dkLCBydWxlczogaW5jbHVkZV9ydWxlcywgdmFyaWFibGVzOiBvcHRzLnZhcmlhYmxlc30sIGdpdERhdGEpO1xuICAgICAgICAgICAgICAgIGlmIChydWxlc1Jlc3VsdC53aGVuID09PSBcIm5ldmVyXCIpIHtcbiAgICAgICAgICAgICAgICAgICAgY29udGludWU7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKHZhbHVlW1wiZmlsZVwiXSkge1xuICAgICAgICAgICAgICAgIGZvciAoY29uc3QgZmlsZVZhbHVlIG9mIEFycmF5LmlzQXJyYXkodmFsdWVbXCJmaWxlXCJdKSA/IHZhbHVlW1wiZmlsZVwiXSA6IFt2YWx1ZVtcImZpbGVcIl1dKSB7XG4gICAgICAgICAgICAgICAgICAgIHByb21pc2VzLnB1c2godGhpcy5kb3dubG9hZEluY2x1ZGVQcm9qZWN0RmlsZShjd2QsIHN0YXRlRGlyLCB2YWx1ZVtcInByb2plY3RcIl0sIHZhbHVlW1wicmVmXCJdIHx8IFwiSEVBRFwiLCBmaWxlVmFsdWUsIGdpdERhdGEsIGZldGNoSW5jbHVkZXMpKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9IGVsc2UgaWYgKHZhbHVlW1widGVtcGxhdGVcIl0pIHtcbiAgICAgICAgICAgICAgICBjb25zdCB7cHJvamVjdCwgcmVmLCBmaWxlLCBkb21haW59ID0gdGhpcy5jb3ZlcnRUZW1wbGF0ZVRvUHJvamVjdEZpbGUodmFsdWVbXCJ0ZW1wbGF0ZVwiXSk7XG4gICAgICAgICAgICAgICAgY29uc3QgdXJsID0gYGh0dHBzOi8vJHtkb21haW59LyR7cHJvamVjdH0vLS9yYXcvJHtyZWZ9LyR7ZmlsZX1gO1xuICAgICAgICAgICAgICAgIHByb21pc2VzLnB1c2godGhpcy5kb3dubG9hZEluY2x1ZGVSZW1vdGUoY3dkLCBzdGF0ZURpciwgdXJsLCBmZXRjaEluY2x1ZGVzKSk7XG4gICAgICAgICAgICB9IGVsc2UgaWYgKHZhbHVlW1wicmVtb3RlXCJdKSB7XG4gICAgICAgICAgICAgICAgcHJvbWlzZXMucHVzaCh0aGlzLmRvd25sb2FkSW5jbHVkZVJlbW90ZShjd2QsIHN0YXRlRGlyLCB2YWx1ZVtcInJlbW90ZVwiXSwgZmV0Y2hJbmNsdWRlcykpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgIH1cblxuICAgICAgICBhd2FpdCBQcm9taXNlLmFsbChwcm9taXNlcyk7XG5cbiAgICAgICAgZm9yIChjb25zdCB2YWx1ZSBvZiBpbmNsdWRlKSB7XG4gICAgICAgICAgICBpZiAodmFsdWVbXCJydWxlc1wiXSkge1xuICAgICAgICAgICAgICAgIGNvbnN0IGluY2x1ZGVfcnVsZXMgPSB2YWx1ZVtcInJ1bGVzXCJdO1xuICAgICAgICAgICAgICAgIGNvbnN0IHJ1bGVzUmVzdWx0ID0gVXRpbHMuZ2V0UnVsZXNSZXN1bHQoe2FyZ3YsIGN3ZCwgcnVsZXM6IGluY2x1ZGVfcnVsZXMsIHZhcmlhYmxlczogb3B0cy52YXJpYWJsZXN9LCBnaXREYXRhKTtcbiAgICAgICAgICAgICAgICBpZiAocnVsZXNSZXN1bHQud2hlbiA9PT0gXCJuZXZlclwiKSB7XG4gICAgICAgICAgICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmICh2YWx1ZVtcImxvY2FsXCJdKSB7XG4gICAgICAgICAgICAgICAgdmFsaWRhdGVJbmNsdWRlTG9jYWwodmFsdWVbXCJsb2NhbFwiXSk7XG4gICAgICAgICAgICAgICAgY29uc3QgZmlsZXMgPSByZXNvbHZlSW5jbHVkZUxvY2FsKHZhbHVlW1wibG9jYWxcIl0sIGN3ZCk7XG4gICAgICAgICAgICAgICAgaWYgKGZpbGVzLmxlbmd0aCA9PSAwKSB7XG4gICAgICAgICAgICAgICAgICAgIHRocm93IG5ldyBBc3NlcnRpb25FcnJvcih7bWVzc2FnZTogYExvY2FsIGluY2x1ZGUgZmlsZSBjYW5ub3QgYmUgZm91bmQgJHt2YWx1ZVtcImxvY2FsXCJdfWB9KTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgZm9yIChjb25zdCBsb2NhbEZpbGUgb2YgZmlsZXMpIHtcbiAgICAgICAgICAgICAgICAgICAgY29uc3QgY29udGVudCA9IGF3YWl0IFBhcnNlci5sb2FkWWFtbChsb2NhbEZpbGUsIHtpbnB1dHM6IHZhbHVlLmlucHV0cyA/PyB7fX0sIGV4cGFuZFZhcmlhYmxlcyk7XG4gICAgICAgICAgICAgICAgICAgIGluY2x1ZGVEYXRhcyA9IGluY2x1ZGVEYXRhcy5jb25jYXQoYXdhaXQgdGhpcy5pbml0KGNvbnRlbnQsIG9wdHMpKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9IGVsc2UgaWYgKHZhbHVlW1wicHJvamVjdFwiXSkge1xuICAgICAgICAgICAgICAgIGZvciAoY29uc3QgZmlsZVZhbHVlIG9mIEFycmF5LmlzQXJyYXkodmFsdWVbXCJmaWxlXCJdKSA/IHZhbHVlW1wiZmlsZVwiXSA6IFt2YWx1ZVtcImZpbGVcIl1dKSB7XG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IGZpbGVEb2MgPSBhd2FpdCBQYXJzZXIubG9hZFlhbWwoXG4gICAgICAgICAgICAgICAgICAgICAgICBgJHtjd2R9LyR7c3RhdGVEaXJ9L2luY2x1ZGVzLyR7Z2l0RGF0YS5yZW1vdGUuaG9zdH0vJHt2YWx1ZVtcInByb2plY3RcIl19LyR7dmFsdWVbXCJyZWZcIl0gfHwgXCJIRUFEXCJ9LyR7ZmlsZVZhbHVlfWBcbiAgICAgICAgICAgICAgICAgICAgICAgICwge2lucHV0czogdmFsdWUuaW5wdXRzIHx8IHt9fVxuICAgICAgICAgICAgICAgICAgICAgICAgLCBleHBhbmRWYXJpYWJsZXMpO1xuICAgICAgICAgICAgICAgICAgICAvLyBFeHBhbmQgbG9jYWwgaW5jbHVkZXMgaW5zaWRlIGEgXCJwcm9qZWN0XCItbGlrZSBpbmNsdWRlXG4gICAgICAgICAgICAgICAgICAgIGZpbGVEb2NbXCJpbmNsdWRlXCJdID0gdGhpcy5leHBhbmRJbmNsdWRlKGZpbGVEb2NbXCJpbmNsdWRlXCJdLCBvcHRzLnZhcmlhYmxlcyk7XG4gICAgICAgICAgICAgICAgICAgIGZpbGVEb2NbXCJpbmNsdWRlXCJdLmZvckVhY2goKGlubmVyOiBhbnksIGk6IG51bWJlcikgPT4ge1xuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKCFpbm5lcltcImxvY2FsXCJdKSByZXR1cm47XG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAoaW5uZXJbXCJydWxlc1wiXSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IHJ1bGVzUmVzdWx0ID0gVXRpbHMuZ2V0UnVsZXNSZXN1bHQoe2FyZ3YsIGN3ZDogb3B0cy5jd2QsIHZhcmlhYmxlczogb3B0cy52YXJpYWJsZXMsIHJ1bGVzOiBpbm5lcltcInJ1bGVzXCJdfSwgZ2l0RGF0YSk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHJ1bGVzUmVzdWx0LndoZW4gPT09IFwibmV2ZXJcIikge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgZmlsZURvY1tcImluY2x1ZGVcIl1baV0gPSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJvamVjdDogdmFsdWVbXCJwcm9qZWN0XCJdLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbGU6IGlubmVyW1wibG9jYWxcIl0ucmVwbGFjZSgvXlxcLy8sIFwiXCIpLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlZjogdmFsdWVbXCJyZWZcIl0sXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaW5wdXRzOiBpbm5lci5pbnB1dHMgfHwge30sXG4gICAgICAgICAgICAgICAgICAgICAgICB9O1xuICAgICAgICAgICAgICAgICAgICB9KTtcblxuICAgICAgICAgICAgICAgICAgICBpbmNsdWRlRGF0YXMgPSBpbmNsdWRlRGF0YXMuY29uY2F0KGF3YWl0IHRoaXMuaW5pdChmaWxlRG9jLCBvcHRzKSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSBlbHNlIGlmICh2YWx1ZVtcImNvbXBvbmVudFwiXSkge1xuICAgICAgICAgICAgICAgIGNvbnN0IHtkb21haW4sIHBvcnQsIHByb2plY3RQYXRoLCBjb21wb25lbnROYW1lLCByZWYsIGlzTG9jYWxDb21wb25lbnR9ID0gdGhpcy5wYXJzZUluY2x1ZGVDb21wb25lbnQodmFsdWVbXCJjb21wb25lbnRcIl0sIGdpdERhdGEpO1xuICAgICAgICAgICAgICAgIC8vIGNvbnZlcnRzIGNvbXBvbmVudCB0byBwcm9qZWN0LiBnaXRsYWIgYWxsb3dzIHR3byBkaWZmZXJlbnQgZmlsZSBwYXRoIHdheXMgdG8gaW5jbHVkZSBhIGNvbXBvbmVudFxuICAgICAgICAgICAgICAgIGxldCBmaWxlcyA9IFtgJHtjb21wb25lbnROYW1lfS55bWxgLCBgJHtjb21wb25lbnROYW1lfS90ZW1wbGF0ZS55bWxgLCBudWxsXTtcblxuICAgICAgICAgICAgICAgIC8vIElmIGEgZmlsZSBpcyBwcmVzZW50IGxvY2FsbHksIGtlZXAgb25seSB0aGF0IG9uZSBpbiB0aGUgZmlsZXMgYXJyYXkgdG8gYXZvaWQgZG93bmxvYWRpbmcgdGhlIG90aGVyIG9uZSB0aGF0IG5ldmVyIGV4aXN0c1xuICAgICAgICAgICAgICAgIGlmICghYXJndi5mZXRjaEluY2x1ZGVzKSB7XG4gICAgICAgICAgICAgICAgICAgIGZvciAoY29uc3QgZiBvZiBmaWxlcykge1xuICAgICAgICAgICAgICAgICAgICAgICAgY29uc3QgbG9jYWxGaWxlTmFtZSA9IGAke2N3ZH0vJHtzdGF0ZURpcn0vaW5jbHVkZXMvJHtnaXREYXRhLnJlbW90ZS5ob3N0fS8ke3Byb2plY3RQYXRofS8ke3JlZn0vJHtmfWA7XG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAoZnMuZXhpc3RzU3luYyhsb2NhbEZpbGVOYW1lKSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbGVzID0gW2ZdO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgZm9yIChjb25zdCBmIG9mIGZpbGVzKSB7XG4gICAgICAgICAgICAgICAgICAgIGFzc2VydChmICE9PSBudWxsLCBgVGhpcyBHaXRMYWIgQ0kgY29uZmlndXJhdGlvbiBpcyBpbnZhbGlkOiBjb21wb25lbnQ6IFxcYCR7dmFsdWVbXCJjb21wb25lbnRcIl19XFxgLiBPbmUgb2YgdGhlIGZpbGVzIFske2ZpbGVzfV0gbXVzdCBleGlzdCBpbiBcXGAke2RvbWFpbn1gICtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAocG9ydCA/IGA6JHtwb3J0fWAgOiBcIlwiKSArIGAvJHtwcm9qZWN0UGF0aH1cXGBgKTtcblxuICAgICAgICAgICAgICAgICAgICBpZiAoaXNMb2NhbENvbXBvbmVudCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgY29uc3QgbG9jYWxDb21wb25lbnRJbmNsdWRlID0gYCR7Y3dkfS8ke2Z9YDtcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmICghKGF3YWl0IGZzLnBhdGhFeGlzdHMobG9jYWxDb21wb25lbnRJbmNsdWRlKSkpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgICAgICAgICAgY29uc3QgY29udGVudCA9IGF3YWl0IFBhcnNlci5sb2FkWWFtbChsb2NhbENvbXBvbmVudEluY2x1ZGUsIHtpbnB1dHM6IHZhbHVlLmlucHV0cyB8fCB7fX0sIGV4cGFuZFZhcmlhYmxlcyk7XG4gICAgICAgICAgICAgICAgICAgICAgICBpbmNsdWRlRGF0YXMgPSBpbmNsdWRlRGF0YXMuY29uY2F0KGF3YWl0IHRoaXMuaW5pdChjb250ZW50LCBvcHRzKSk7XG4gICAgICAgICAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IGxvY2FsRmlsZU5hbWUgPSBgJHtjd2R9LyR7c3RhdGVEaXJ9L2luY2x1ZGVzLyR7Z2l0RGF0YS5yZW1vdGUuaG9zdH0vJHtwcm9qZWN0UGF0aH0vJHtyZWZ9LyR7Zn1gO1xuICAgICAgICAgICAgICAgICAgICAgICAgLy8gQ2hlY2sgcmVtb3RlbHkgb25seSBpZiB0aGUgZmlsZSBkb2VzIG5vdCBleGlzdCBsb2NhbGx5XG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAoIWZzLmV4aXN0c1N5bmMobG9jYWxGaWxlTmFtZSkgJiYgIShhd2FpdCBVdGlscy5yZW1vdGVGaWxlRXhpc3QoY3dkLCBmLCByZWYsIGRvbWFpbiwgcHJvamVjdFBhdGgsIGdpdERhdGEucmVtb3RlLnNjaGVtYSwgZ2l0RGF0YS5yZW1vdGUucG9ydCkpKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY29udGludWU7XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IGZpbGVEb2MgPSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaW5jbHVkZToge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwcm9qZWN0OiBwcm9qZWN0UGF0aCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsZTogZixcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVmOiByZWYsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlucHV0czogdmFsdWUuaW5wdXRzIHx8IHt9LFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgICAgICAgICB9O1xuICAgICAgICAgICAgICAgICAgICAgICAgaW5jbHVkZURhdGFzID0gaW5jbHVkZURhdGFzLmNvbmNhdChhd2