projen
Version:
CDK for software projects
433 lines • 68.1 kB
JavaScript
"use strict";
var _a, _b;
Object.defineProperty(exports, "__esModule", { value: true });
exports.UpgradeDependenciesSchedule = exports.UpgradeDependencies = void 0;
const JSII_RTTI_SYMBOL_1 = Symbol.for("jsii.rtti");
const component_1 = require("../component");
const dependencies_1 = require("../dependencies");
const github_1 = require("../github");
const constants_1 = require("../github/constants");
const workflow_actions_1 = require("../github/workflow-actions");
const workflows_model_1 = require("../github/workflows-model");
const javascript_1 = require("../javascript");
const release_1 = require("../release");
const runner_options_1 = require("../runner-options");
const util_1 = require("./util");
const CREATE_PATCH_STEP_ID = "create_patch";
const PATCH_CREATED_OUTPUT = "patch_created";
/**
* Upgrade node project dependencies.
*/
class UpgradeDependencies extends component_1.Component {
constructor(project, options = {}) {
super(project);
/**
* The workflows that execute the upgrades. One workflow per branch.
*/
this.workflows = [];
this.project = project;
this.options = options;
// Validate cooldown
if (options.cooldown !== undefined &&
(!Number.isInteger(options.cooldown) || options.cooldown < 0)) {
throw new Error("The 'cooldown' option must be a non-negative integer representing days");
}
// Yarn classic doesn't support cooldown
if (options.cooldown && (0, util_1.isYarnClassic)(project.package.packageManager)) {
throw new Error("The 'cooldown' option is not supported with yarn classic. " +
"Consider using npm, pnpm, bun, or yarn berry instead.");
}
this.depTypes = this.options.types ?? [
dependencies_1.DependencyType.BUILD,
dependencies_1.DependencyType.BUNDLED,
dependencies_1.DependencyType.DEVENV,
dependencies_1.DependencyType.PEER,
dependencies_1.DependencyType.RUNTIME,
dependencies_1.DependencyType.TEST,
dependencies_1.DependencyType.OPTIONAL,
];
this.upgradeTarget = this.options.target ?? "minor";
this.satisfyPeerDependencies = this.options.satisfyPeerDependencies ?? true;
this.includeDeprecatedVersions =
this.options.includeDeprecatedVersions ?? false;
this.pullRequestTitle = options.pullRequestTitle ?? "upgrade dependencies";
this.gitIdentity =
options.workflowOptions?.gitIdentity ?? constants_1.DEFAULT_GITHUB_ACTIONS_USER;
this.permissions = {
contents: workflows_model_1.JobPermission.READ,
...options.workflowOptions?.permissions,
};
this.postBuildSteps = [];
this.containerOptions = options.workflowOptions?.container;
this.postUpgradeTask =
project.tasks.tryFind("post-upgrade") ??
project.tasks.addTask("post-upgrade", {
description: "Runs after upgrading dependencies",
});
const taskEnv = { CI: "0" };
// Set yarn berry cooldown via environment variable, expects minutes
if (options.cooldown && (0, util_1.isYarnBerry)(project.package.packageManager)) {
taskEnv.YARN_NPM_MINIMAL_AGE_GATE = String(daysToMinutes(options.cooldown));
}
// Set npm cooldown date via environment variable (calculated at runtime), expects a date in ISO format
if (options.cooldown && (0, util_1.isNpm)(project.package.packageManager)) {
taskEnv.NPM_CONFIG_BEFORE = `$(node -p "new Date(Date.now()-${daysToMilliseconds(options.cooldown)}).toISOString()")`;
}
this.upgradeTask = project.addTask(options.taskName ?? "upgrade", {
// this task should not run in CI mode because its designed to
// update package.json and lock files.
env: taskEnv,
description: this.pullRequestTitle,
steps: { toJSON: () => this.renderTaskSteps() },
});
this.upgradeTask.lock(); // this task is a lazy value, so make it readonly
if (this.upgradeTask && project.github && (options.workflow ?? true)) {
if (options.workflowOptions?.branches) {
for (const branch of options.workflowOptions.branches) {
this.workflows.push(this.createWorkflow(this.upgradeTask, project.github, branch));
}
}
else if (release_1.Release.of(project)) {
const release = release_1.Release.of(project);
release._forEachBranch((branch) => {
this.workflows.push(this.createWorkflow(this.upgradeTask, project.github, branch));
});
}
else {
// represents the default repository branch.
// just like not specifying anything.
const defaultBranch = undefined;
this.workflows.push(this.createWorkflow(this.upgradeTask, project.github, defaultBranch));
}
}
}
/**
* Add steps to execute a successful build.
* @param steps workflow steps
*/
addPostBuildSteps(...steps) {
this.postBuildSteps.push(...steps);
}
renderTaskSteps() {
const steps = new Array();
// Package Manager upgrade should always include all deps
const includeForPackageManagerUpgrade = this.buildDependencyList(true);
if (includeForPackageManagerUpgrade.length === 0) {
return [{ exec: "echo No dependencies to upgrade." }];
}
// Removing `npm-check-updates` from our dependency tree because it depends on a package
// that uses an npm-specific feature that causes an invalid dependency tree when using Yarn 1.
// See https://github.com/projen/projen/pull/3136 for more details.
const includeForNcu = this.buildDependencyList(false);
// bump versions in package.json
if (includeForNcu.length) {
const ncuCommand = this.buildNcuCommand(includeForNcu, {
upgrade: true,
target: this.upgradeTarget,
});
steps.push({ exec: ncuCommand });
}
// run "yarn/npm install" to update the lockfile and install any deps (such as projen)
steps.push({ exec: this.project.package.installAndUpdateLockfileCommand });
// run upgrade command to upgrade transitive deps as well
steps.push({
exec: this.renderUpgradePackagesCommand(includeForPackageManagerUpgrade),
});
// run "projen" to give projen a chance to update dependencies (it will also run "yarn install")
steps.push({ exec: this.project.projenCommand });
steps.push({ spawn: this.postUpgradeTask.name });
return steps;
}
/**
* Build npm-check-updates command with common options.
*/
buildNcuCommand(includePackages, options = {}) {
function executeCommand(packageManager) {
switch (packageManager) {
case javascript_1.NodePackageManager.NPM:
case javascript_1.NodePackageManager.YARN:
case javascript_1.NodePackageManager.YARN_CLASSIC:
return "npx";
case javascript_1.NodePackageManager.PNPM:
return "pnpm dlx";
case javascript_1.NodePackageManager.YARN2:
case javascript_1.NodePackageManager.YARN_BERRY:
return "yarn dlx";
case javascript_1.NodePackageManager.BUN:
return "bunx";
}
}
const command = [
`${executeCommand(this.project.package.packageManager)} npm-check-updates@18`,
];
if (options.upgrade) {
command.push("--upgrade");
}
if (options.target) {
command.push(`--target=${options.target}`);
}
if (options.format) {
command.push(`--format=${options.format}`);
}
if (options.removeRange) {
command.push("--removeRange");
}
if (this.options.cooldown) {
command.push(`--cooldown=${this.options.cooldown}`);
}
command.push(`--${this.satisfyPeerDependencies ? "peer" : "no-peer"}`);
command.push(`--${this.includeDeprecatedVersions ? "deprecated" : "no-deprecated"}`);
command.push(`--dep=${this.renderNcuDependencyTypes(this.depTypes)}`);
command.push(`--filter=${includePackages.join(",")}`);
return command.join(" ");
}
/**
* Render projen dependencies types to a list of ncu compatible types
*/
renderNcuDependencyTypes(types) {
return Array.from(new Set(types
.map((type) => {
switch (type) {
case dependencies_1.DependencyType.PEER:
return "peer";
case dependencies_1.DependencyType.RUNTIME:
return "prod";
case dependencies_1.DependencyType.OPTIONAL:
return "optional";
case dependencies_1.DependencyType.TEST:
case dependencies_1.DependencyType.DEVENV:
case dependencies_1.DependencyType.BUILD:
return "dev";
case dependencies_1.DependencyType.BUNDLED:
default:
return false;
}
})
.filter((type) => Boolean(type)))).join(",");
}
/**
* Render a package manager specific command to upgrade all requested dependencies.
*/
renderUpgradePackagesCommand(include) {
function upgradePackages(command, cooldownFlag) {
return () => {
const parts = [command, ...include];
if (cooldownFlag) {
parts.push(cooldownFlag);
}
return parts.join(" ");
};
}
const packageManager = this.project.package.packageManager;
const cooldown = this.options.cooldown;
let lazy = undefined;
switch (packageManager) {
case javascript_1.NodePackageManager.YARN:
case javascript_1.NodePackageManager.YARN_CLASSIC:
lazy = upgradePackages("yarn upgrade");
break;
case javascript_1.NodePackageManager.YARN2:
case javascript_1.NodePackageManager.YARN_BERRY:
// Yarn Berry cooldown set via task env
lazy = upgradePackages("yarn up");
break;
case javascript_1.NodePackageManager.NPM:
// npm cooldown set via NPM_CONFIG_BEFORE env
lazy = upgradePackages("npm update");
break;
case javascript_1.NodePackageManager.PNPM:
// pnpm expects minutes
lazy = upgradePackages("pnpm update", cooldown !== undefined
? `--config.minimum-release-age=${daysToMinutes(cooldown)}`
: undefined);
break;
case javascript_1.NodePackageManager.BUN:
// bun expects seconds
lazy = upgradePackages("bun update", cooldown
? `--minimum-release-age=${daysToSeconds(cooldown)}`
: undefined);
break;
default:
throw new Error(`unexpected package manager ${packageManager}`);
}
// return a lazy function so that dependencies include ones that were
// added post project instantiation (i.e using project.addDeps)
return lazy;
}
buildDependencyList(includeDependenciesWithConstraint) {
return Array.from(new Set(this.options.include ??
this.filterDependencies(includeDependenciesWithConstraint)));
}
filterDependencies(includeConstraint) {
const dependencies = [];
const deps = this.project.deps.all
// remove those that have a constraint version (unless includeConstraint is true)
.filter((d) => includeConstraint || this.packageCanBeUpgradedInPackageJson(d.version))
// remove override dependencies
.filter((d) => d.type !== dependencies_1.DependencyType.OVERRIDE);
for (const type of this.depTypes) {
dependencies.push(...deps
.filter((d) => d.type === type)
.filter((d) => !(this.options.exclude ?? []).includes(d.name)));
}
return dependencies.map((d) => d.name);
}
/**
* Projen can alter a package's version in package.json when either the version is omitted, or set to "*".
* Otherwise, the exact version selected is placed in the package.json file and upgrading is handled through the package manager
* rather than npm-check-updates.
*
* @param version semver from DependencyCoordinates.version, may be undefined
* @returns whether the version is the default versioning behavior
*/
packageCanBeUpgradedInPackageJson(version) {
// No version means "latest"
return !version || version === "*";
}
createWorkflow(task, github, branch) {
const schedule = this.options.workflowOptions?.schedule ??
UpgradeDependenciesSchedule.DAILY;
const workflowName = `${task.name}${branch ? `-${branch.replace(/\//g, "-")}` : ""}`;
const workflow = github.addWorkflow(workflowName);
const triggers = {
workflowDispatch: {},
schedule: schedule.cron.length > 0
? schedule.cron.map((e) => ({ cron: e }))
: undefined,
};
workflow.on(triggers);
const upgrade = this.createUpgrade(task, github, branch);
const pr = this.createPr(workflow, upgrade);
const jobs = {};
jobs[upgrade.jobId] = upgrade.job;
jobs[pr.jobId] = pr.job;
workflow.addJobs(jobs);
return workflow;
}
createUpgrade(task, github, branch) {
const with_ = {
...(branch ? { ref: branch } : {}),
...(github.downloadLfs ? { lfs: true } : {}),
};
const steps = [
github_1.WorkflowSteps.checkout({ with: with_ }),
...this.project.renderWorkflowSetup({ mutable: false }),
{
name: "Upgrade dependencies",
run: this.project.runTaskCommand(task),
},
];
steps.push(...this.postBuildSteps);
steps.push(...workflow_actions_1.WorkflowActions.uploadGitPatch({
stepId: CREATE_PATCH_STEP_ID,
outputName: PATCH_CREATED_OUTPUT,
}));
return {
job: {
name: "Upgrade",
container: this.containerOptions,
permissions: this.permissions,
env: this.options.workflowOptions?.env,
...(0, runner_options_1.filteredRunsOnOptions)(this.options.workflowOptions?.runsOn, this.options.workflowOptions?.runsOnGroup),
steps: steps,
outputs: {
[PATCH_CREATED_OUTPUT]: {
stepId: CREATE_PATCH_STEP_ID,
outputName: PATCH_CREATED_OUTPUT,
},
},
},
jobId: "upgrade",
ref: branch,
};
}
createPr(workflow, upgrade) {
const credentials = this.options.workflowOptions?.projenCredentials ??
workflow.projenCredentials;
const semanticCommit = this.options.semanticCommit ?? "chore";
return {
job: github_1.WorkflowJobs.pullRequestFromPatch({
patch: {
jobId: upgrade.jobId,
outputName: PATCH_CREATED_OUTPUT,
ref: upgrade.ref,
},
workflowName: workflow.name,
credentials,
...(0, runner_options_1.filteredRunsOnOptions)(this.options.workflowOptions?.runsOn, this.options.workflowOptions?.runsOnGroup),
pullRequestTitle: `${semanticCommit}(deps): ${this.pullRequestTitle}`,
pullRequestDescription: "Upgrades project dependencies.",
gitIdentity: this.gitIdentity,
assignees: this.options.workflowOptions?.assignees,
labels: this.options.workflowOptions?.labels,
signoff: this.options.signoff,
}),
jobId: "pr",
};
}
}
exports.UpgradeDependencies = UpgradeDependencies;
_a = JSII_RTTI_SYMBOL_1;
UpgradeDependencies[_a] = { fqn: "projen.javascript.UpgradeDependencies", version: "0.98.32" };
/**
* How often to check for new versions and raise pull requests for version upgrades.
*/
class UpgradeDependenciesSchedule {
/**
* Create a schedule from a raw cron expression.
*/
static expressions(cron) {
return new UpgradeDependenciesSchedule(cron);
}
constructor(cron) {
this.cron = cron;
}
}
exports.UpgradeDependenciesSchedule = UpgradeDependenciesSchedule;
_b = JSII_RTTI_SYMBOL_1;
UpgradeDependenciesSchedule[_b] = { fqn: "projen.javascript.UpgradeDependenciesSchedule", version: "0.98.32" };
/**
* Disables automatic upgrades.
*/
UpgradeDependenciesSchedule.NEVER = new UpgradeDependenciesSchedule([]);
/**
* At 00:00.
*/
UpgradeDependenciesSchedule.DAILY = new UpgradeDependenciesSchedule(["0 0 * * *"]);
/**
* At 00:00 on every day-of-week from Monday through Friday.
*/
UpgradeDependenciesSchedule.WEEKDAY = new UpgradeDependenciesSchedule([
"0 0 * * 1-5",
]);
/**
* At 00:00 on Monday.
*/
UpgradeDependenciesSchedule.WEEKLY = new UpgradeDependenciesSchedule([
"0 0 * * 1",
]);
/**
* At 00:00 on day-of-month 1.
*/
UpgradeDependenciesSchedule.MONTHLY = new UpgradeDependenciesSchedule([
"0 0 1 * *",
]);
/**
* Convert days to minutes.
*/
function daysToMinutes(days) {
return days * 1440;
}
/**
* Convert days to seconds.
*/
function daysToSeconds(days) {
return days * 86400;
}
/**
* Convert days to milliseconds.
*/
function daysToMilliseconds(days) {
return days * 86400000;
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidXBncmFkZS1kZXBlbmRlbmNpZXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvamF2YXNjcmlwdC91cGdyYWRlLWRlcGVuZGVuY2llcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7OztBQUFBLDRDQUF5QztBQUN6QyxrREFBaUQ7QUFDakQsc0NBUW1CO0FBQ25CLG1EQUFrRTtBQUNsRSxpRUFBNkQ7QUFDN0QsK0RBS21DO0FBQ25DLDhDQUFnRTtBQUNoRSx3Q0FBcUM7QUFDckMsc0RBQThFO0FBRzlFLGlDQUEyRDtBQUUzRCxNQUFNLG9CQUFvQixHQUFHLGNBQWMsQ0FBQztBQUM1QyxNQUFNLG9CQUFvQixHQUFHLGVBQWUsQ0FBQztBQWdJN0M7O0dBRUc7QUFDSCxNQUFhLG1CQUFvQixTQUFRLHFCQUFTO0lBa0NoRCxZQUFZLE9BQW9CLEVBQUUsVUFBc0MsRUFBRTtRQUN4RSxLQUFLLENBQUMsT0FBTyxDQUFDLENBQUM7UUFsQ2pCOztXQUVHO1FBQ2EsY0FBUyxHQUFxQixFQUFFLENBQUM7UUFpQy9DLElBQUksQ0FBQyxPQUFPLEdBQUcsT0FBTyxDQUFDO1FBQ3ZCLElBQUksQ0FBQyxPQUFPLEdBQUcsT0FBTyxDQUFDO1FBRXZCLG9CQUFvQjtRQUNwQixJQUNFLE9BQU8sQ0FBQyxRQUFRLEtBQUssU0FBUztZQUM5QixDQUFDLENBQUMsTUFBTSxDQUFDLFNBQVMsQ0FBQyxPQUFPLENBQUMsUUFBUSxDQUFDLElBQUksT0FBTyxDQUFDLFFBQVEsR0FBRyxDQUFDLENBQUMsRUFDN0QsQ0FBQztZQUNELE1BQU0sSUFBSSxLQUFLLENBQ2Isd0VBQXdFLENBQ3pFLENBQUM7UUFDSixDQUFDO1FBRUQsd0NBQXdDO1FBQ3hDLElBQUksT0FBTyxDQUFDLFFBQVEsSUFBSSxJQUFBLG9CQUFhLEVBQUMsT0FBTyxDQUFDLE9BQU8sQ0FBQyxjQUFjLENBQUMsRUFBRSxDQUFDO1lBQ3RFLE1BQU0sSUFBSSxLQUFLLENBQ2IsNERBQTREO2dC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QVEsQ0FBQztBQUN6QixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgQ29tcG9uZW50IH0gZnJvbSBcIi4uL2NvbXBvbmVudFwiO1xuaW1wb3J0IHsgRGVwZW5kZW5jeVR5cGUgfSBmcm9tIFwiLi4vZGVwZW5kZW5jaWVzXCI7XG5pbXBvcnQge1xuICBHaXRodWJDcmVkZW50aWFscyxcbiAgR2l0SHViLFxuICBHaXRodWJXb3JrZmxvdyxcbiAgR2l0SWRlbnRpdHksXG4gIHdvcmtmbG93cyxcbiAgV29ya2Zsb3dKb2JzLFxuICBXb3JrZmxvd1N0ZXBzLFxufSBmcm9tIFwiLi4vZ2l0aHViXCI7XG5pbXBvcnQgeyBERUZBVUxUX0dJVEhVQl9BQ1RJT05TX1VTRVIgfSBmcm9tIFwiLi4vZ2l0aHViL2NvbnN0YW50c1wiO1xuaW1wb3J0IHsgV29ya2Zsb3dBY3Rpb25zIH0gZnJvbSBcIi4uL2dpdGh1Yi93b3JrZmxvdy1hY3Rpb25zXCI7XG5pbXBvcnQge1xuICBDb250YWluZXJPcHRpb25zLFxuICBKb2JTdGVwLFxuICBKb2JQZXJtaXNzaW9uLFxuICBKb2JQZXJtaXNzaW9ucyxcbn0gZnJvbSBcIi4uL2dpdGh1Yi93b3JrZmxvd3MtbW9kZWxcIjtcbmltcG9ydCB7IE5vZGVQYWNrYWdlTWFuYWdlciwgTm9kZVByb2plY3QgfSBmcm9tIFwiLi4vamF2YXNjcmlwdFwiO1xuaW1wb3J0IHsgUmVsZWFzZSB9IGZyb20gXCIuLi9yZWxlYXNlXCI7XG5pbXBvcnQgeyBHcm91cFJ1bm5lck9wdGlvbnMsIGZpbHRlcmVkUnVuc09uT3B0aW9ucyB9IGZyb20gXCIuLi9ydW5uZXItb3B0aW9uc1wiO1xuaW1wb3J0IHsgVGFzayB9IGZyb20gXCIuLi90YXNrXCI7XG5pbXBvcnQgeyBUYXNrU3RlcCB9IGZyb20gXCIuLi90YXNrLW1vZGVsXCI7XG5pbXBvcnQgeyBpc1lhcm5DbGFzc2ljLCBpc1lhcm5CZXJyeSwgaXNOcG0gfSBmcm9tIFwiLi91dGlsXCI7XG5cbmNvbnN0IENSRUFURV9QQVRDSF9TVEVQX0lEID0gXCJjcmVhdGVfcGF0Y2hcIjtcbmNvbnN0IFBBVENIX0NSRUFURURfT1VUUFVUID0gXCJwYXRjaF9jcmVhdGVkXCI7XG5cbi8qKlxuICogT3B0aW9ucyBmb3IgYFVwZ3JhZGVEZXBlbmRlbmNpZXNgLlxuICovXG5leHBvcnQgaW50ZXJmYWNlIFVwZ3JhZGVEZXBlbmRlbmNpZXNPcHRpb25zIHtcbiAgLyoqXG4gICAqIExpc3Qgb2YgcGFja2FnZSBuYW1lcyB0byBleGNsdWRlIGR1cmluZyB0aGUgdXBncmFkZS5cbiAgICpcbiAgICogQGRlZmF1bHQgLSBOb3RoaW5nIGlzIGV4Y2x1ZGVkLlxuICAgKi9cbiAgcmVhZG9ubHkgZXhjbHVkZT86IHN0cmluZ1tdO1xuXG4gIC8qKlxuICAgKiBMaXN0IG9mIHBhY2thZ2UgbmFtZXMgdG8gaW5jbHVkZSBkdXJpbmcgdGhlIHVwZ3JhZGUuXG4gICAqXG4gICAqIEBkZWZhdWx0IC0gRXZlcnl0aGluZyBpcyBpbmNsdWRlZC5cbiAgICovXG4gIHJlYWRvbmx5IGluY2x1ZGU/OiBzdHJpbmdbXTtcblxuICAvKipcbiAgICogRGV0ZXJtaW5lcyB0aGUgdGFyZ2V0IHZlcnNpb24gdG8gdXBncmFkZSBkZXBlbmRlbmNpZXMgdG8uXG4gICAqXG4gICAqIEBzZWUgaHR0cHM6Ly9naXRodWIuY29tL3JhaW5lb3JzaGluZS9ucG0tY2hlY2stdXBkYXRlcyN0YXJnZXRcbiAgICpcbiAgICogQGRlZmF1bHQgXCJtaW5vclwiXG4gICAqL1xuICByZWFkb25seSB0YXJnZXQ/OiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIENoZWNrIHBlZXIgZGVwZW5kZW5jaWVzIG9mIGluc3RhbGxlZCBwYWNrYWdlcyBhbmQgZmlsdGVyIHVwZGF0ZXMgdG8gY29tcGF0aWJsZSB2ZXJzaW9ucy5cbiAgICpcbiAgICogQnkgZGVmYXVsdCwgdGhlIHVwZ3JhZGUgd29ya2Zsb3cgd2lsbCBhZGhlcmUgdG8gdmVyc2lvbiBjb25zdHJhaW50cyBmcm9tIHBlZXIgZGVwZW5kZW5jaWVzLlxuICAgKiBTb21ldGltZXMgdGhpcyBpcyBub3QgZGVzaXJhYmxlIGFuZCBjYW4gYmUgZGlzYWJsZWQuXG4gICAqXG4gICAqIEBzZWUgaHR0cHM6Ly9naXRodWIuY29tL3JhaW5lb3JzaGluZS9ucG0tY2hlY2stdXBkYXRlcyNwZWVyXG4gICAqXG4gICAqIEBkZWZhdWx0IHRydWVcbiAgICovXG4gIHJlYWRvbmx5IHNhdGlzZnlQZWVyRGVwZW5kZW5jaWVzPzogYm9vbGVhbjtcblxuICAvKipcbiAgICogSW5jbHVkZSBkZXByZWNhdGVkIHBhY2thZ2VzLlxuICAgKlxuICAgKiBCeSBkZWZhdWx0LCBkZXByZWNhdGVkIHZlcnNpb25zIHdpbGwgYmUgZXhjbHVkZWQgZnJvbSB1cGdyYWRlcy5cbiAgICpcbiAgICogQHNlZSBodHRwczovL2dpdGh1Yi5jb20vcmFpbmVvcnNoaW5lL25wbS1jaGVjay11cGRhdGVzP3RhYj1yZWFkbWUtb3YtZmlsZSNvcHRpb25zXG4gICAqXG4gICAqIEBkZWZhdWx0IGZhbHNlXG4gICAqL1xuICByZWFkb25seSBpbmNsdWRlRGVwcmVjYXRlZFZlcnNpb25zPzogYm9vbGVhbjtcblxuICAvKipcbiAgICogSW5jbHVkZSBhIGdpdGh1YiB3b3JrZmxvdyBmb3IgY3JlYXRpbmcgUFIncyB0aGF0IHVwZ3JhZGVzIHRoZVxuICAgKiByZXF1aXJlZCBkZXBlbmRlbmNpZXMsIGVpdGhlciBieSBtYW51YWwgZGlzcGF0Y2gsIG9yIGJ5IGEgc2NoZWR1bGUuXG4gICAqXG4gICAqIElmIHRoaXMgaXMgYGZhbHNlYCwgb25seSBhIGxvY2FsIHByb2plbiB0YXNrIGlzIGNyZWF0ZWQsIHdoaWNoIGNhbiBiZSBleGVjdXRlZCBtYW51YWxseSB0b1xuICAgKiB1cGdyYWRlIHRoZSBkZXBlbmRlbmNpZXMuXG4gICAqXG4gICAqIEBkZWZhdWx0IC0gdHJ1ZSBmb3Igcm9vdCBwcm9qZWN0cywgZmFsc2UgZm9yIHN1YnByb2plY3RzLlxuICAgKi9cbiAgcmVhZG9ubHkgd29ya2Zsb3c/OiBib29sZWFuO1xuXG4gIC8qKlxuICAgKiBPcHRpb25zIGZvciB0aGUgZ2l0aHViIHdvcmtmbG93LiBPbmx5IGFwcGxpZXMgaWYgYHdvcmtmbG93YCBpcyB0cnVlLlxuICAgKlxuICAgKiBAZGVmYXVsdCAtIGRlZmF1bHQgb3B0aW9ucy5cbiAgICovXG4gIHJlYWRvbmx5IHdvcmtmbG93T3B0aW9ucz86IFVwZ3JhZGVEZXBlbmRlbmNpZXNXb3JrZmxvd09wdGlvbnM7XG5cbiAgLyoqXG4gICAqIFRoZSBuYW1lIG9mIHRoZSB0YXNrIHRoYXQgd2lsbCBiZSBjcmVhdGVkLlxuICAgKiBUaGlzIHdpbGwgYWxzbyBiZSB0aGUgd29ya2Zsb3cgbmFtZS5cbiAgICpcbiAgICogQGRlZmF1bHQgXCJ1cGdyYWRlXCIuXG4gICAqL1xuICByZWFkb25seSB0YXNrTmFtZT86IHN0cmluZztcblxuICAvKipcbiAgICogVGl0bGUgb2YgdGhlIHB1bGwgcmVxdWVzdCB0byB1c2UgKHNob3VsZCBiZSBhbGwgbG93ZXItY2FzZSkuXG4gICAqXG4gICAqIEBkZWZhdWx0IFwidXBncmFkZSBkZXBlbmRlbmNpZXNcIlxuICAgKi9cbiAgcmVhZG9ubHkgcHVsbFJlcXVlc3RUaXRsZT86IHN0cmluZztcblxuICAvKipcbiAgICogVGhlIHNlbWFudGljIGNvbW1pdCB0eXBlLlxuICAgKlxuICAgKiBAZGVmYXVsdCAnY2hvcmUnXG4gICAqL1xuICByZWFkb25seSBzZW1hbnRpY0NvbW1pdD86IHN0cmluZztcblxuICAvKipcbiAgICogQWRkIFNpZ25lZC1vZmYtYnkgbGluZSBieSB0aGUgY29tbWl0dGVyIGF0IHRoZSBlbmQgb2YgdGhlIGNvbW1pdCBsb2cgbWVzc2FnZS5cbiAgICpcbiAgICogQGRlZmF1bHQgdHJ1ZVxuICAgKi9cbiAgcmVhZG9ubHkgc2lnbm9mZj86IGJvb2xlYW47XG5cbiAgLyoqXG4gICAqIFNwZWNpZnkgd2hpY2ggZGVwZW5kZW5jeSB0eXBlcyB0aGUgdXBncmFkZSBzaG91bGQgb3BlcmF0ZSBvbi5cbiAgICpcbiAgICogQGRlZmF1bHQgLSBBbGwgZGVwZW5kZW5jeSB0eXBlcy5cbiAgICovXG4gIHJlYWRvbmx5IHR5cGVzPzogRGVwZW5kZW5jeVR5cGVbXTtcblxuICAvKipcbiAgICogRXhjbHVkZSBwYWNrYWdlIHZlcnNpb25zIHB1Ymxpc2hlZCB3aXRoaW4gdGhlIHNwZWNpZmllZCBudW1iZXIgb2YgZGF5cy5cbiAgICpcbiAgICogVGhpcyBtYXkgcHJvdmlkZSBzb21lIHByb3RlY3Rpb24gYWdhaW5zdCBzdXBwbHkgY2hhaW4gYXR0YWNrcywgc2ltcGx5IGJ5IGF2b2lkaW5nXG4gICAqIG5ld2x5IHB1Ymxpc2hlZCBwYWNrYWdlcyB0aGF0IG1heSBiZSBtYWxpY2lvdXMuIEl0IGdpdmVzIHRoZSBlY29zeXN0ZW0gbW9yZSB0aW1lXG4gICAqIHRvIGRldGVjdCBtYWxpY2lvdXMgcGFja2FnZXMuIEhvd2V2ZXIgaXQgY29tZXMgYXQgdGhlIGNvc3Qgb2YgdXBkYXRpbmcgb3RoZXJcbiAgICogcGFja2FnZXMgc2xvd2VyLCB3aGljaCBtaWdodCBhbHNvIGNvbnRhaW4gdnVsbmVyYWJpbGl0aWVzIG9yIGJ1Z3MgaW4gbmVlZCBvZiBhIGZpeC5cbiAgICpcbiAgICogVGhlIGNvb2xkb3duIHBlcmlvZCBhcHBsaWVzIHRvIGJvdGggbnBtLWNoZWNrLXVwZGF0ZXMgZGlzY292ZXJ5XG4gICAqIGFuZCB0aGUgcGFja2FnZSBtYW5hZ2VyIHVwZGF0ZSBjb21tYW5kLlxuICAgKlxuICAgKiBAc2VlIGh0dHBzOi8vZ2l0aHViLmNvbS9yYWluZW9yc2hpbmUvbnBtLWNoZWNrLXVwZGF0ZXMjY29vbGRvd25cbiAgICogQHNlZSBodHRwczovL2RvY3MubnBtanMuY29tL2NsaS92MTEvY29tbWFuZHMvbnBtLXVwZGF0ZSNiZWZvcmVcbiAgICogQHNlZSBodHRwczovL3BucG0uaW8vc2V0dGluZ3MjbWluaW11bXJlbGVhc2VhZ2VcbiAgICogQHNlZSBodHRwczovL2J1bi5jb20vZG9jcy9wbS9jbGkvaW5zdGFsbCNtaW5pbXVtLXJlbGVhc2UtYWdlXG4gICAqIEBzZWUgaHR0cHM6Ly95YXJucGtnLmNvbS9jb25maWd1cmF0aW9uL3lhcm5yYyNucG1NaW5pbWFsQWdlR2F0ZVxuICAgKlxuICAgKiBAZGVmYXVsdCAtIE5vIGNvb2xkb3duIHBlcmlvZC5cbiAgICovXG4gIHJlYWRvbmx5IGNvb2xkb3duPzogbnVtYmVyO1xufVxuXG4vKipcbiAqIFVwZ3JhZGUgbm9kZSBwcm9qZWN0IGRlcGVuZGVuY2llcy5cbiAqL1xuZXhwb3J0IGNsYXNzIFVwZ3JhZGVEZXBlbmRlbmNpZXMgZXh0ZW5kcyBDb21wb25lbnQge1xuICAvKipcbiAgICogVGhlIHdvcmtmbG93cyB0aGF0IGV4ZWN1dGUgdGhlIHVwZ3JhZGVzLiBPbmUgd29ya2Zsb3cgcGVyIGJyYW5jaC5cbiAgICovXG4gIHB1YmxpYyByZWFkb25seSB3b3JrZmxvd3M6IEdpdGh1YldvcmtmbG93W10gPSBbXTtcblxuICBwdWJsaWMgcmVhZG9ubHkgcHJvamVjdDogTm9kZVByb2plY3Q7XG5cbiAgcHJpdmF0ZSByZWFkb25seSBvcHRpb25zOiBVcGdyYWRlRGVwZW5kZW5jaWVzT3B0aW9ucztcbiAgcHJpdmF0ZSByZWFkb25seSBwdWxsUmVxdWVzdFRpdGxlOiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIENvbnRhaW5lciBkZWZpbml0aW9ucyBmb3IgdGhlIHVwZ3JhZGUgd29ya2Zsb3cuXG4gICAqL1xuICBwdWJsaWMgY29udGFpbmVyT3B0aW9ucz86IENvbnRhaW5lck9wdGlvbnM7XG5cbiAgLyoqXG4gICAqIFRoZSB1cGdyYWRlIHRhc2suXG4gICAqL1xuICBwdWJsaWMgcmVhZG9ubHkgdXBncmFkZVRhc2s6IFRhc2s7XG5cbiAgLyoqXG4gICAqIEEgdGFzayBydW4gYWZ0ZXIgdGhlIHVwZ3JhZGUgdGFzay5cbiAgICovXG4gIHB1YmxpYyByZWFkb25seSBwb3N0VXBncmFkZVRhc2s6IFRhc2s7XG5cbiAgcHJpdmF0ZSByZWFkb25seSBnaXRJZGVudGl0eTogR2l0SWRlbnRpdHk7XG4gIHByaXZhdGUgcmVhZG9ubHkgcG9zdEJ1aWxkU3RlcHM6IEpvYlN0ZXBbXTtcbiAgcHJpdmF0ZSByZWFkb25seSBwZXJtaXNzaW9uczogSm9iUGVybWlzc2lvbnM7XG4gIHByaXZhdGUgcmVhZG9ubHkgZGVwVHlwZXM6IERlcGVuZGVuY3lUeXBlW107XG4gIHByaXZhdGUgcmVhZG9ubHkgdXBncmFkZVRhcmdldDogc3RyaW5nO1xuICBwcml2YXRlIHJlYWRvbmx5IHNhdGlzZnlQZWVyRGVwZW5kZW5jaWVzOiBib29sZWFuO1xuICBwcml2YXRlIHJlYWRvbmx5IGluY2x1ZGVEZXByZWNhdGVkVmVyc2lvbnM6IGJvb2xlYW47XG5cbiAgY29uc3RydWN0b3IocHJvamVjdDogTm9kZVByb2plY3QsIG9wdGlvbnM6IFVwZ3JhZGVEZXBlbmRlbmNpZXNPcHRpb25zID0ge30pIHtcbiAgICBzdXBlcihwcm9qZWN0KTtcblxuICAgIHRoaXMucHJvamVjdCA9IHByb2plY3Q7XG4gICAgdGhpcy5vcHRpb25zID0gb3B0aW9ucztcblxuICAgIC8vIFZhbGlkYXRlIGNvb2xkb3duXG4gICAgaWYgKFxuICAgICAgb3B0aW9ucy5jb29sZG93biAhPT0gdW5kZWZpbmVkICYmXG4gICAgICAoIU51bWJlci5pc0ludGVnZXIob3B0aW9ucy5jb29sZG93bikgfHwgb3B0aW9ucy5jb29sZG93biA8IDApXG4gICAgKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgIFwiVGhlICdjb29sZG93bicgb3B0aW9uIG11c3QgYmUgYSBub24tbmVnYXRpdmUgaW50ZWdlciByZXByZXNlbnRpbmcgZGF5c1wiXG4gICAgICApO1xuICAgIH1cblxuICAgIC8vIFlhcm4gY2xhc3NpYyBkb2Vzbid0IHN1cHBvcnQgY29vbGRvd25cbiAgICBpZiAob3B0aW9ucy5jb29sZG93biAmJiBpc1lhcm5DbGFzc2ljKHByb2plY3QucGFja2FnZS5wYWNrYWdlTWFuYWdlcikpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgXCJUaGUgJ2Nvb2xkb3duJyBvcHRpb24gaXMgbm90IHN1cHBvcnRlZCB3aXRoIHlhcm4gY2xhc3NpYy4gXCIgK1xuICAgICAgICAgIFwiQ29uc2lkZXIgdXNpbmcgbnBtLCBwbnBtLCBidW4sIG9yIHlhcm4gYmVycnkgaW5zdGVhZC5cIlxuICAgICAgKTtcbiAgICB9XG5cbiAgICB0aGlzLmRlcFR5cGVzID0gdGhpcy5vcHRpb25zLnR5cGVzID8/IFtcbiAgICAgIERlcGVuZGVuY3lUeXBlLkJVSUxELFxuICAgICAgRGVwZW5kZW5jeVR5cGUuQlVORExFRCxcbiAgICAgIERlcGVuZGVuY3lUeXBlLkRFVkVOVixcbiAgICAgIERlcGVuZGVuY3lUeXBlLlBFRVIsXG4gICAgICBEZXBlbmRlbmN5VHlwZS5SVU5USU1FLFxuICAgICAgRGVwZW5kZW5jeVR5cGUuVEVTVCxcbiAgICAgIERlcGVuZGVuY3lUeXBlLk9QVElPTkFMLFxuICAgIF07XG4gICAgdGhpcy51cGdyYWRlVGFyZ2V0ID0gdGhpcy5vcHRpb25zLnRhcmdldCA/PyBcIm1pbm9yXCI7XG4gICAgdGhpcy5zYXRpc2Z5UGVlckRlcGVuZGVuY2llcyA9IHRoaXMub3B0aW9ucy5zYXRpc2Z5UGVlckRlcGVuZGVuY2llcyA/PyB0cnVlO1xuICAgIHRoaXMuaW5jbHVkZURlcHJlY2F0ZWRWZXJzaW9ucyA9XG4gICAgICB0aGlzLm9wdGlvbnMuaW5jbHVkZURlcHJlY2F0ZWRWZXJzaW9ucyA/PyBmYWxzZTtcbiAgICB0aGlzLnB1bGxSZXF1ZXN0VGl0bGUgPSBvcHRpb25zLnB1bGxSZXF1ZXN0VGl0bGUgPz8gXCJ1cGdyYWRlIGRlcGVuZGVuY2llc1wiO1xuICAgIHRoaXMuZ2l0SWRlbnRpdHkgPVxuICAgICAgb3B0aW9ucy53b3JrZmxvd09wdGlvbnM/LmdpdElkZW50aXR5ID8/IERFRkFVTFRfR0lUSFVCX0FDVElPTlNfVVNFUjtcbiAgICB0aGlzLnBlcm1pc3Npb25zID0ge1xuICAgICAgY29udGVudHM6IEpvYlBlcm1pc3Npb24uUkVBRCxcbiAgICAgIC4uLm9wdGlvbnMud29ya2Zsb3dPcHRpb25zPy5wZXJtaXNzaW9ucyxcbiAgICB9O1xuICAgIHRoaXMucG9zdEJ1aWxkU3RlcHMgPSBbXTtcbiAgICB0aGlzLmNvbnRhaW5lck9wdGlvbnMgPSBvcHRpb25zLndvcmtmbG93T3B0aW9ucz8uY29udGFpbmVyO1xuXG4gICAgdGhpcy5wb3N0VXBncmFkZVRhc2sgPVxuICAgICAgcHJvamVjdC50YXNrcy50cnlGaW5kKFwicG9zdC11cGdyYWRlXCIpID8/XG4gICAgICBwcm9qZWN0LnRhc2tzLmFkZFRhc2soXCJwb3N0LXVwZ3JhZGVcIiwge1xuICAgICAgICBkZXNjcmlwdGlvbjogXCJSdW5zIGFmdGVyIHVwZ3JhZGluZyBkZXBlbmRlbmNpZXNcIixcbiAgICAgIH0pO1xuXG4gICAgY29uc3QgdGFza0VudjogUmVjb3JkPHN0cmluZywgc3RyaW5nPiA9IHsgQ0k6IFwiMFwiIH07XG5cbiAgICAvLyBTZXQgeWFybiBiZXJyeSBjb29sZG93biB2aWEgZW52aXJvbm1lbnQgdmFyaWFibGUsIGV4cGVjdHMgbWludXRlc1xuICAgIGlmIChvcHRpb25zLmNvb2xkb3duICYmIGlzWWFybkJlcnJ5KHByb2plY3QucGFja2FnZS5wYWNrYWdlTWFuYWdlcikpIHtcbiAgICAgIHRhc2tFbnYuWUFSTl9OUE1fTUlOSU1BTF9BR0VfR0FURSA9IFN0cmluZyhcbiAgICAgICAgZGF5c1RvTWludXRlcyhvcHRpb25zLmNvb2xkb3duKVxuICAgICAgKTtcbiAgICB9XG5cbiAgICAvLyBTZXQgbnBtIGNvb2xkb3duIGRhdGUgdmlhIGVudmlyb25tZW50IHZhcmlhYmxlIChjYWxjdWxhdGVkIGF0IHJ1bnRpbWUpLCBleHBlY3RzIGEgZGF0ZSBpbiBJU08gZm9ybWF0XG4gICAgaWYgKG9wdGlvbnMuY29vbGRvd24gJiYgaXNOcG0ocHJvamVjdC5wYWNrYWdlLnBhY2thZ2VNYW5hZ2VyKSkge1xuICAgICAgdGFza0Vudi5OUE1fQ09ORklHX0JFRk9SRSA9IGAkKG5vZGUgLXAgXCJuZXcgRGF0ZShEYXRlLm5vdygpLSR7ZGF5c1RvTWlsbGlzZWNvbmRzKFxuICAgICAgICBvcHRpb25zLmNvb2xkb3duXG4gICAgICApfSkudG9JU09TdHJpbmcoKVwiKWA7XG4gICAgfVxuXG4gICAgdGhpcy51cGdyYWRlVGFzayA9IHByb2plY3QuYWRkVGFzayhvcHRpb25zLnRhc2tOYW1lID8/IFwidXBncmFkZVwiLCB7XG4gICAgICAvLyB0aGlzIHRhc2sgc2hvdWxkIG5vdCBydW4gaW4gQ0kgbW9kZSBiZWNhdXNlIGl0cyBkZXNpZ25lZCB0b1xuICAgICAgLy8gdXBkYXRlIHBhY2thZ2UuanNvbiBhbmQgbG9jayBmaWxlcy5cbiAgICAgIGVudjogdGFza0VudixcbiAgICAgIGRlc2NyaXB0aW9uOiB0aGlzLnB1bGxSZXF1ZXN0VGl0bGUsXG4gICAgICBzdGVwczogeyB0b0pTT046ICgpID0+IHRoaXMucmVuZGVyVGFza1N0ZXBzKCkgfSBhcyBhbnksXG4gICAgfSk7XG4gICAgdGhpcy51cGdyYWRlVGFzay5sb2NrKCk7IC8vIHRoaXMgdGFzayBpcyBhIGxhenkgdmFsdWUsIHNvIG1ha2UgaXQgcmVhZG9ubHlcblxuICAgIGlmICh0aGlzLnVwZ3JhZGVUYXNrICYmIHByb2plY3QuZ2l0aHViICYmIChvcHRpb25zLndvcmtmbG93ID8/IHRydWUpKSB7XG4gICAgICBpZiAob3B0aW9ucy53b3JrZmxvd09wdGlvbnM/LmJyYW5jaGVzKSB7XG4gICAgICAgIGZvciAoY29uc3QgYnJhbmNoIG9mIG9wdGlvbnMud29ya2Zsb3dPcHRpb25zLmJyYW5jaGVzKSB7XG4gICAgICAgICAgdGhpcy53b3JrZmxvd3MucHVzaChcbiAgICAgICAgICAgIHRoaXMuY3JlYXRlV29ya2Zsb3codGhpcy51cGdyYWRlVGFzaywgcHJvamVjdC5naXRodWIsIGJyYW5jaClcbiAgICAgICAgICApO1xuICAgICAgICB9XG4gICAgICB9IGVsc2UgaWYgKFJlbGVhc2Uub2YocHJvamVjdCkpIHtcbiAgICAgICAgY29uc3QgcmVsZWFzZSA9IFJlbGVhc2Uub2YocHJvamVjdCkhO1xuICAgICAgICByZWxlYXNlLl9mb3JFYWNoQnJhbmNoKChicmFuY2g6IHN0cmluZykgPT4ge1xuICAgICAgICAgIHRoaXMud29ya2Zsb3dzLnB1c2goXG4gICAgICAgICAgICB0aGlzLmNyZWF0ZVdvcmtmbG93KHRoaXMudXBncmFkZVRhc2ssIHByb2plY3QuZ2l0aHViISwgYnJhbmNoKVxuICAgICAgICAgICk7XG4gICAgICAgIH0pO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgLy8gcmVwcmVzZW50cyB0aGUgZGVmYXVsdCByZXBvc2l0b3J5IGJyYW5jaC5cbiAgICAgICAgLy8ganVzdCBsaWtlIG5vdCBzcGVjaWZ5aW5nIGFueXRoaW5nLlxuICAgICAgICBjb25zdCBkZWZhdWx0QnJhbmNoID0gdW5kZWZpbmVkO1xuICAgICAgICB0aGlzLndvcmtmbG93cy5wdXNoKFxuICAgICAgICAgIHRoaXMuY3JlYXRlV29ya2Zsb3codGhpcy51cGdyYWRlVGFzaywgcHJvamVjdC5naXRodWIsIGRlZmF1bHRCcmFuY2gpXG4gICAgICAgICk7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIEFkZCBzdGVwcyB0byBleGVjdXRlIGEgc3VjY2Vzc2Z1bCBidWlsZC5cbiAgICogQHBhcmFtIHN0ZXBzIHdvcmtmbG93IHN0ZXBzXG4gICAqL1xuICBwdWJsaWMgYWRkUG9zdEJ1aWxkU3RlcHMoLi4uc3RlcHM6IEpvYlN0ZXBbXSkge1xuICAgIHRoaXMucG9zdEJ1aWxkU3RlcHMucHVzaCguLi5zdGVwcyk7XG4gIH1cblxuICBwcml2YXRlIHJlbmRlclRhc2tTdGVwcygpOiBUYXNrU3RlcFtdIHtcbiAgICBjb25zdCBzdGVwcyA9IG5ldyBBcnJheTxUYXNrU3RlcD4oKTtcblxuICAgIC8vIFBhY2thZ2UgTWFuYWdlciB1cGdyYWRlIHNob3VsZCBhbHdheXMgaW5jbHVkZSBhbGwgZGVwc1xuICAgIGNvbnN0IGluY2x1ZGVGb3JQYWNrYWdlTWFuYWdlclVwZ3JhZGUgPSB0aGlzLmJ1aWxkRGVwZW5kZW5jeUxpc3QodHJ1ZSk7XG4gICAgaWYgKGluY2x1ZGVGb3JQYWNrYWdlTWFuYWdlclVwZ3JhZGUubGVuZ3RoID09PSAwKSB7XG4gICAgICByZXR1cm4gW3sgZXhlYzogXCJlY2hvIE5vIGRlcGVuZGVuY2llcyB0byB1cGdyYWRlLlwiIH1dO1xuICAgIH1cblxuICAgIC8vIFJlbW92aW5nIGBucG0tY2hlY2stdXBkYXRlc2AgZnJvbSBvdXIgZGVwZW5kZW5jeSB0cmVlIGJlY2F1c2UgaXQgZGVwZW5kcyBvbiBhIHBhY2thZ2VcbiAgICAvLyB0aGF0IHVzZXMgYW4gbnBtLXNwZWNpZmljIGZlYXR1cmUgdGhhdCBjYXVzZXMgYW4gaW52YWxpZCBkZXBlbmRlbmN5IHRyZWUgd2hlbiB1c2luZyBZYXJuIDEuXG4gICAgLy8gU2VlIGh0dHBzOi8vZ2l0aHViLmNvbS9wcm9qZW4vcHJvamVuL3B1bGwvMzEzNiBmb3IgbW9yZSBkZXRhaWxzLlxuICAgIGNvbnN0IGluY2x1ZGVGb3JOY3UgPSB0aGlzLmJ1aWxkRGVwZW5kZW5jeUxpc3QoZmFsc2UpO1xuXG4gICAgLy8gYnVtcCB2ZXJzaW9ucyBpbiBwYWNrYWdlLmpzb25cbiAgICBpZiAoaW5jbHVkZUZvck5jdS5sZW5ndGgpIHtcbiAgICAgIGNvbnN0IG5jdUNvbW1hbmQgPSB0aGlzLmJ1aWxkTmN1Q29tbWFuZChpbmNsdWRlRm9yTmN1LCB7XG4gICAgICAgIHVwZ3JhZGU6IHRydWUsXG4gICAgICAgIHRhcmdldDogdGhpcy51cGdyYWRlVGFyZ2V0LFxuICAgICAgfSk7XG4gICAgICBzdGVwcy5wdXNoKHsgZXhlYzogbmN1Q29tbWFuZCB9KTtcbiAgICB9XG5cbiAgICAvLyBydW4gXCJ5YXJuL25wbSBpbnN0YWxsXCIgdG8gdXBkYXRlIHRoZSBsb2NrZmlsZSBhbmQgaW5zdGFsbCBhbnkgZGVwcyAoc3VjaCBhcyBwcm9qZW4pXG4gICAgc3RlcHMucHVzaCh7IGV4ZWM6IHRoaXMucHJvamVjdC5wYWNrYWdlLmluc3RhbGxBbmRVcGRhdGVMb2NrZmlsZUNvbW1hbmQgfSk7XG5cbiAgICAvLyBydW4gdXBncmFkZSBjb21tYW5kIHRvIHVwZ3JhZGUgdHJhbnNpdGl2ZSBkZXBzIGFzIHdlbGxcbiAgICBzdGVwcy5wdXNoKHtcbiAgICAgIGV4ZWM6IHRoaXMucmVuZGVyVXBncmFkZVBhY2thZ2VzQ29tbWFuZChpbmNsdWRlRm9yUGFja2FnZU1hbmFnZXJVcGdyYWRlKSxcbiAgICB9KTtcblxuICAgIC8vIHJ1biBcInByb2plblwiIHRvIGdpdmUgcHJvamVuIGEgY2hhbmNlIHRvIHVwZGF0ZSBkZXBlbmRlbmNpZXMgKGl0IHdpbGwgYWxzbyBydW4gXCJ5YXJuIGluc3RhbGxcIilcbiAgICBzdGVwcy5wdXNoKHsgZXhlYzogdGhpcy5w