projen
Version:
CDK for software projects
266 lines • 41.5 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.ReleasableCommits = exports.Version = exports.CHANGES_SINCE_LAST_RELEASE = void 0;
const JSII_RTTI_SYMBOL_1 = Symbol.for("jsii.rtti");
const path_1 = require("path");
const component_1 = require("./component");
const dependencies_1 = require("./dependencies");
const node_package_1 = require("./javascript/node-package");
/**
* This command determines if there were any changes since the last release in a
* cross-platform compatible way. It is used as a condition for both the `bump`
* and the `release` tasks: it exits 0 (proceed) when the most recent commit is
* not a release commit, and non-zero (skip) when the most recent commit is a
* `chore(release):` commit.
*
* Explanation:
* - `git log --oneline -1` the most recent commit, one line
* - `| grep -v "chore(release):"` pass the line through only if it is NOT a release commit
* - `> /dev/null` discard grep's output; only its exit code matters
*
* grep exits 0 when it prints at least one non-matching line (a normal commit,
* so proceed) and 1 when every line matches (a release commit, so skip).
*
* IMPORTANT: do NOT reintroduce `grep -q` here (i.e. do not "optimize" this back
* to `grep -qv`). `grep -q` exits as soon as it has an answer and closes the read
* end of the pipe. When this condition runs through projen's built-in (dax)
* shell, that early close races with `git log` still writing to the pipe, and dax
* surfaces the failed write as a spurious non-zero exit ("stdin pipe broken.
* Invalid state: WritableStream is closed"). The task runtime cannot distinguish
* that from a legitimate skip (dax reports it as a plain non-zero code under
* `.noThrow()`, not as an error), so the bump/release task is silently skipped: a
* release is missed, or a dependent publishes a broken `^0.0.0` version range.
* Plain `grep -v ... > /dev/null` reads to EOF instead of short-circuiting, so it
* never closes the pipe while the writer is active and the race cannot occur. The
* exit semantics are identical to the previous `grep -qv`.
*/
exports.CHANGES_SINCE_LAST_RELEASE = 'git log --oneline -1 | grep -v "chore(release):" > /dev/null';
/**
* The default package to be used for commit-and-tag-version
*/
const COMMIT_AND_TAG_VERSION_DEFAULT = "commit-and-tag-version@^12";
class Version extends component_1.Component {
static [JSII_RTTI_SYMBOL_1] = { fqn: "projen.Version", version: "0.103.12" };
bumpTask;
unbumpTask;
/**
* The task that prints the releasable commits since the latest tag. Spawned
* by `bump`; its shell can be overridden via `task.shell`.
*/
releasableCommitsTask;
/**
* The task that runs the user's `nextVersionCommand`, if configured. Spawned
* by `bump`; its shell can be overridden via `task.shell`.
*/
nextVersionTask;
/**
* The name of the changelog file (under `artifactsDirectory`).
*/
changelogFileName;
/**
* The name of the file that contains the version (under `artifactsDirectory`).
*/
versionFileName;
/**
* The name of the file that contains the release tag (under `artifactsDirectory`).
*/
releaseTagFileName;
/**
* The package used to bump package versions, as a dependency string.
* This is a `commit-and-tag-version` compatible package.
*/
bumpPackage;
nextVersionCommand;
constructor(scope, options) {
super(scope);
this.changelogFileName = "changelog.md";
this.versionFileName = "version.txt";
this.releaseTagFileName = "releasetag.txt";
this.bumpPackage = options.bumpPackage ?? COMMIT_AND_TAG_VERSION_DEFAULT;
this.nextVersionCommand = options.nextVersionCommand;
// This component is language independent.
// However, when in the Node.js ecosystem, we can improve the experience by adding a dev dependency on the bump package.
const node = node_package_1.NodePackage.of(this.project);
if (node) {
const { name: bumpName, version: bumpVersion } = dependencies_1.Dependencies.parseDependency(this.bumpPackage);
node.project.deps.requestDependency({
name: bumpName,
version: bumpVersion,
type: dependencies_1.DependencyType.BUILD,
});
}
const versionInputFile = options.versionInputFile;
const changelogFile = path_1.posix.join(options.artifactsDirectory, this.changelogFileName);
const bumpFile = path_1.posix.join(options.artifactsDirectory, this.versionFileName);
const releaseTagFile = path_1.posix.join(options.artifactsDirectory, this.releaseTagFileName);
const commonEnv = {
OUTFILE: versionInputFile,
CHANGELOG: changelogFile,
BUMPFILE: bumpFile,
RELEASETAG: releaseTagFile,
RELEASE_TAG_PREFIX: options.tagPrefix ?? "",
// doesn't work if custom configuration is long
VERSIONRCOPTIONS: JSON.stringify(options.versionrcOptions),
BUMP_PACKAGE: this.bumpPackage,
};
// The command that lists releasable commits, run as its own spawnable task
// so its shell can be configured independently (see `TaskShell`).
// `$LATEST_TAG` is provided by `bump` when spawning it.
this.releasableCommitsTask = this.project.addTask("bump:releasable-commits", {
description: "Print the releasable commits since the latest release",
exec: (options.releasableCommits ?? ReleasableCommits.everyCommit())
.cmd,
});
// The optional command that decides the next version, also its own task.
if (this.nextVersionCommand) {
this.nextVersionTask = this.project.addTask("bump:next-version", {
description: "Determine the next version to release",
exec: this.nextVersionCommand,
});
}
// Orchestrates the release bump as a pipeline of builtins and spawned
// tasks, handing results forward via step `outputEnv` captures.
this.bumpTask = this.project.addTask("bump", {
description: "Bumps version based on latest git tag and generates a changelog entry",
condition: exports.CHANGES_SINCE_LAST_RELEASE,
env: { ...commonEnv },
});
this.bumpTask.addSteps({ builtin: "release/resolve-latest-tag", outputEnv: "LATEST_TAG" },
// On a first release the resolved tag is synthetic and does not exist, so
// there is nothing to diff against - skip listing commits in that case.
{
spawn: "bump:releasable-commits",
outputEnv: "RELEASABLE_COMMITS",
condition: 'git rev-parse --verify --quiet "refs/tags/$LATEST_TAG"',
}, { builtin: "release/suggest-version-bump", outputEnv: "SUGGESTED_BUMP" });
if (this.nextVersionTask) {
// `bump:next-version` receives `$VERSION` (the current version); read it
// from the version file into `VERSION` so it propagates to the spawn.
this.bumpTask.addSteps({
exec: `node -e "process.stdout.write(JSON.parse(require('fs').readFileSync(process.env.OUTFILE,'utf8')).version)"`,
outputEnv: "VERSION",
}, { spawn: "bump:next-version", outputEnv: "BUMP_TYPE" });
}
this.bumpTask.addSteps({ builtin: "release/apply-version-bump" });
// Resets the version in the version file back to 0.0.0 after a bump.
this.unbumpTask = this.project.addTask("unbump", {
description: "Restores version to 0.0.0",
env: { ...commonEnv },
});
this.unbumpTask.builtin("release/reset-version");
this.project.addGitIgnore(`/${changelogFile}`);
this.project.addGitIgnore(`/${bumpFile}`);
this.project.addPackageIgnore(`/${changelogFile}`);
this.project.addPackageIgnore(`/${bumpFile}`);
}
/**
* Return the environment variables to modify the bump command for release branches.
*
* These options are used to modify the behavior of the version bumping script
* for additional branches, by setting environment variables.
*
* No settings are inherited from the base `Version` object (but any parameters that
* control versions do conflict with the use of a `nextVersionCommand`).
*/
envForBranch(branchOptions) {
if (this.nextVersionCommand && branchOptions.minMajorVersion) {
throw new Error("minMajorVersion and nextVersionCommand cannot be used together.");
}
const env = {};
if (branchOptions.majorVersion !== undefined) {
env.MAJOR = branchOptions.majorVersion.toString();
}
if (branchOptions.minMajorVersion !== undefined) {
if (branchOptions.majorVersion !== undefined) {
throw new Error(`minMajorVersion and majorVersion cannot be used together.`);
}
env.MIN_MAJOR = branchOptions.minMajorVersion.toString();
}
if (branchOptions.prerelease) {
env.PRERELEASE = branchOptions.prerelease;
}
if (branchOptions.tagPrefix) {
env.RELEASE_TAG_PREFIX = branchOptions.tagPrefix;
}
return env;
}
}
exports.Version = Version;
/**
* Find commits that should be considered releasable to decide if a release is required.
*
* This setting only controls whether a release is triggered, yes or no. The
* paths used here are independent of the code that controls what commits are inspected
* to determine the version number.
*/
class ReleasableCommits {
cmd;
static [JSII_RTTI_SYMBOL_1] = { fqn: "projen.ReleasableCommits", version: "0.103.12" };
/**
* Release every commit
*
* This will only not release if the most recent commit is tagged with the latest matching tag.
*
* @param path Consider only commits that are enough to explain how the files that match the specified paths came to be.
* This path is relative to the current working dir of the `bump` task, i.e. to only consider commits of a subproject use `"."`.
*/
static everyCommit(path) {
const cmd = `git log --oneline $LATEST_TAG..HEAD`;
return new ReleasableCommits(withPath(cmd, path));
}
/**
* Limit commits by their conventional commit type
*
* This will only release commit that match one of the provided types.
* Commits are required to follow the conventional commit spec and will be ignored otherwise.
*
* @param types List of conventional commit types that should be released
* @param path Consider only commits that are enough to explain how the files that match the specified paths came to be.
* This path is relative to the current working dir of the `bump` task, i.e. to only consider commits of a subproject use `"."`.
*/
static ofType(types, path) {
const allowedTypes = types.join("|");
// @see: https://github.com/conventional-commits/parser/blob/eeefb961ebf5b9dfea0fea8b06f8ad34a1e439b9/lib/parser.js
// -E requires this to be POSIX Extended Regular Expression, which comes with certain limitations
// see https://en.wikibooks.org/wiki/Regular_Expressions/POSIX-Extended_Regular_Expressions for details
const cmd = `git log --no-merges --oneline $LATEST_TAG..HEAD -E --grep '^(${allowedTypes}){1}(\\([^()[:space:]]+\\))?(!)?:[[:blank:]]+.+'`;
return new ReleasableCommits(withPath(cmd, path));
}
/**
* Release only features and fixes
*
* Shorthand for `ReleasableCommits.onlyOfType(['feat', 'fix'])`.
*
* @param path Consider only commits that are enough to explain how the files that match the specified paths came to be.
* This path is relative to the current working dir of the `bump` task, i.e. to only consider commits of a subproject use `"."`.
*/
static featuresAndFixes(path) {
return ReleasableCommits.ofType(["feat", "fix"], path);
}
/**
* Use an arbitrary shell command to find releasable commits since the latest tag.
*
* A new release will be initiated, if the number of returned commits is greater than zero.
* Must return a newline separate list of commits that should considered releasable.
* `$LATEST_TAG` is available as an environment variable (set to the actual latest tag for the given prefix).
*
* @example "git log --oneline $LATEST_TAG..HEAD -- ."
*/
static exec(cmd) {
return new ReleasableCommits(cmd);
}
constructor(cmd) {
this.cmd = cmd;
}
}
exports.ReleasableCommits = ReleasableCommits;
/**
* Append a path argument to a git command if one is provided
*/
function withPath(cmd, path) {
if (path !== undefined) {
return `${cmd} -- ${path}`;
}
return cmd;
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidmVyc2lvbi5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy92ZXJzaW9uLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7QUFBQSwrQkFBNkI7QUFFN0IsMkNBQXdDO0FBQ3hDLGlEQUE4RDtBQUM5RCw0REFBd0Q7QUFHeEQ7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQTJCRztBQUNVLFFBQUEsMEJBQTBCLEdBQ3JDLDhEQUE4RCxDQUFDO0FBRWpFOztHQUVHO0FBQ0gsTUFBTSw4QkFBOEIsR0FBRyw0QkFBNEIsQ0FBQztBQXNFcEUsTUFBYSxPQUFRLFNBQVEscUJBQVM7O0lBQ3BCLFFBQVEsQ0FBTztJQUNmLFVBQVUsQ0FBTztJQUVqQzs7O09BR0c7SUFDYSxxQkFBcUIsQ0FBTztJQUU1Qzs7O09BR0c7SUFDYSxlQUFlLENBQVE7SUFFdkM7O09BRUc7SUFDYSxpQkFBaUIsQ0FBUztJQUUxQzs7T0FFRztJQUNhLGVBQWUsQ0FBUztJQUV4Qzs7T0FFRztJQUNhLGtCQUFrQixDQUFTO0lBRTNDOzs7T0FHRztJQUNhLFdBQVcsQ0FBUztJQUVuQixrQkFBa0IsQ0FBVTtJQUU3QyxZQUFZLEtBQWlCLEVBQUUsT0FBdUI7UUFDcEQsS0FBSyxDQUFDLEtBQUssQ0FBQyxDQUFDO1FBRWIsSUFBSSxDQUFDLGlCQUFpQixHQUFHLGNBQWMsQ0FBQztRQUN4QyxJQUFJLENBQUMsZUFBZSxHQUFHLGFBQWEsQ0FBQztRQUNyQyxJQUFJLENBQUMsa0JBQWtCLEdBQUcsZ0JBQWdCLENBQUM7UUFDM0MsSUFBSSxDQUFDLFdBQVcsR0FBRyxPQUFPLENBQUMsV0FBVyxJQUFJLDhCQUE4QixDQUFDO1FBQ3pFLElBQUksQ0FBQyxrQkFBa0IsR0FBRyxPQUFPLENBQUMsa0JBQWtCLENBQUM7UUFFckQsMENBQTBDO1FBQzFDLHdIQUF3SDtRQUN4SCxNQUFNLElBQUksR0FBRywwQkFBVyxDQUFDLEVBQUUsQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLENBQUM7UUFDMUMsSUFBSSxJQUFJLEVBQUUsQ0FBQztZQUNULE1BQU0sRUFBRSxJQUFJLEVBQUUsUUFBUSxFQUFFLE9BQU8sRUFBRSxXQUFXLEVBQUUsR0FDNUMsMkJBQVksQ0FBQyxlQUFlLENBQUMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxDQUFDO1lBQ2pELElBQUksQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLGlCQUFpQixDQUFDO2dCQUNsQyxJQUFJLEVBQUUsUUFBUTtnQkFDZCxPQUFPLEVBQUUsV0FBVztnQkFDcEIsSUFBSSxFQUFFLDZCQUFjLENBQUMsS0FBSzthQUMzQixDQUFDLENBQUM7UUFDTCxDQUFDO1FBRUQsTUFBTSxnQkFBZ0IsR0FBRyxPQUFPLENBQUMsZ0JBQWdCLENBQUM7UUFFbEQsTUFBTSxhQUFhLEdBQUcsWUFBSyxDQUFDLElBQUksQ0FDOUIsT0FBTyxDQUFDLGtCQUFrQixFQUMxQixJQUFJLENBQUMsaUJBQWlCLENBQ3ZCLENBQUM7UUFDRixNQUFNLFFBQVEsR0FBRyxZQUFLLENBQUMsSUFBSSxDQUN6QixPQUFPLENBQUMsa0JBQWtCLEVBQzFCLElBQUksQ0FBQyxlQUFlLENBQ3JCLENBQUM7UUFDRixNQUFNLGNBQWMsR0FBRyxZQUFLLENBQUMsSUFBSSxDQUMvQixPQUFPLENBQUMsa0JBQWtCLEVBQzFCLElBQUksQ0FBQyxrQkFBa0IsQ0FDeEIsQ0FBQztRQUVGLE1BQU0sU0FBUyxHQUEyQjtZQUN4QyxPQUFPLEVBQUUsZ0JBQWdCO1lBQ3pCLFNBQVMsRUFBRSxhQUFhO1lBQ3hCLFFBQVEsRUFBRSxRQUFRO1lBQ2xCLFVBQVUsRUFBRSxjQUFjO1lBQzFCLGtCQUFrQixFQUFFLE9BQU8sQ0FBQyxTQUFTLElBQUksRUFBRTtZQUMzQywrQ0FBK0M7WUFDL0MsZ0JBQWdCLEVBQUUsSUFBSSxDQUFDLFNBQVMsQ0FBQyxPQUFPLENBQUMsZ0JBQWdCLENBQUM7WUFDMUQsWUFBWSxFQUFFLElBQUksQ0FBQyxXQUFXO1NBQy9CLENBQUM7UUFFRiwyRUFBMkU7UUFDM0Usa0VBQWtFO1FBQ2xFLHdEQUF3RDtRQUN4RCxJQUFJLENBQUMscUJBQXFCLEdBQUcsSUFBSSxDQUFDLE9BQU8sQ0FBQyxPQUFPLENBQy9DLHlCQUF5QixFQUN6QjtZQUNFLFdBQVcsRUFBRSx1REFBdUQ7WUFDcEUsSUFBSSxFQUFFLENBQUMsT0FBTyxDQUFDLGlCQUFpQixJQUFJLGlCQUFpQixDQUFDLFdBQVcsRUFBRSxDQUFDO2lCQUNqRSxHQUFHO1NBQ1AsQ0FDRixDQUFDO1FBRUYseUVBQXlFO1FBQ3pFLElBQUksSUFBSSxDQUFDLGtCQUFrQixFQUFFLENBQUM7WUFDNUIsSUFBSSxDQUFDLGVBQWUsR0FBRyxJQUFJLENBQUMsT0FBTyxDQUFDLE9BQU8sQ0FBQyxtQkFBbUIsRUFBRTtnQkFDL0QsV0FBVyxFQUFFLHVDQUF1QztnQkFDcEQsSUFBSSxFQUFFLElBQUksQ0FBQyxrQkFBa0I7YUFDOUIsQ0FBQyxDQUFDO1FBQ0wsQ0FBQztRQUVELHNFQUFzRTtRQUN0RSxnRUFBZ0U7UUFDaEUsSUFBSSxDQUFDLFFBQVEsR0FBRyxJQUFJLENBQUMsT0FBTyxDQUFDLE9BQU8sQ0FBQyxNQUFNLEVBQUU7WUFDM0MsV0FBVyxFQUNULHVFQUF1RTtZQUN6RSxTQUFTLEVBQUUsa0NBQTBCO1lBQ3JDLEdBQUcsRUFBRSxFQUFFLEdBQUcsU0FBUyxFQUFFO1NBQ3RCLENBQUMsQ0FBQztRQUVILElBQUksQ0FBQyxRQUFRLENBQUMsUUFBUSxDQUNwQixFQUFFLE9BQU8sRUFBRSw0QkFBNEIsRUFBRSxTQUFTLEVBQUUsWUFBWSxFQUFFO1FBQ2xFLDBFQUEwRTtRQUMxRSx3RUFBd0U7UUFDeEU7WUFDRSxLQUFLLEVBQUUseUJBQXlCO1lBQ2hDLFNBQVMsRUFBRSxvQkFBb0I7WUFDL0IsU0FBUyxFQUFFLHdEQUF3RDtTQUNwRSxFQUNELEVBQUUsT0FBTyxFQUFFLDhCQUE4QixFQUFFLFNBQVMsRUFBRSxnQkFBZ0IsRUFBRSxDQUN6RSxDQUFDO1FBQ0YsSUFBSSxJQUFJLENBQUMsZUFBZSxFQUFFLENBQUM7WUFDekIseUVBQXlFO1lBQ3pFLHNFQUFzRTtZQUN0RSxJQUFJLENBQUMsUUFBUSxDQUFDLFFBQVEsQ0FDcEI7Z0JBQ0UsSUFBSSxFQUFFLDRHQUE0RztnQkFDbEgsU0FBUyxFQUFFLFNBQVM7YUFDckIsRUFDRCxFQUFFLEtBQUssRUFBRSxtQkFBbUIsRUFBRSxTQUFTLEVBQUUsV0FBVyxFQUFFLENBQ3ZELENBQUM7UUFDSixDQUFDO1FBQ0QsSUFBSSxDQUFDLFFBQVEsQ0FBQyxRQUFRLENBQUMsRUFBRSxPQUFPLEVBQUUsNEJBQTRCLEVBQUUsQ0FBQyxDQUFDO1FBRWxFLHFFQUFxRTtRQUNyRSxJQUFJLENBQUMsVUFBVSxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUMsT0FBTyxDQUFDLFFBQVEsRUFBRTtZQUMvQyxXQUFXLEVBQUUsMkJBQTJCO1lBQ3hDLEdBQUcsRUFBRSxFQUFFLEdBQUcsU0FBUyxFQUFFO1NBQ3RCLENBQUMsQ0FBQztRQUVILElBQUksQ0FBQyxVQUFVLENBQUMsT0FBTyxDQUFDLHVCQUF1QixDQUFDLENBQUM7UUFFakQsSUFBSSxDQUFDLE9BQU8sQ0FBQyxZQUFZLENBQUMsSUFBSSxhQUFhLEVBQUUsQ0FBQyxDQUFDO1FBQy9DLElBQUksQ0FBQyxPQUFPLENBQUMsWUFBWSxDQUFDLElBQUksUUFBUSxFQUFFLENBQUMsQ0FBQztRQUMxQyxJQUFJLENBQUMsT0FBTyxDQUFDLGdCQUFnQixDQUFDLElBQUksYUFBYSxFQUFFLENBQUMsQ0FBQztRQUNuRCxJQUFJLENBQUMsT0FBTyxDQUFDLGdCQUFnQixDQUFDLElBQUksUUFBUSxFQUFFLENBQUMsQ0FBQztJQUNoRCxDQUFDO0lBRUQ7Ozs7Ozs7O09BUUc7SUFDSSxZQUFZLENBQ2pCLGFBQW1DO1FBRW5DLElBQUksSUFBSSxDQUFDLGtCQUFrQixJQUFJLGFBQWEsQ0FBQyxlQUFlLEVBQUUsQ0FBQztZQUM3RCxNQUFNLElBQUksS0FBSyxDQUNiLGlFQUFpRSxDQUNsRSxDQUFDO1FBQ0osQ0FBQztRQUVELE1BQU0sR0FBRyxHQUEyQixFQUFFLENBQUM7UUFDdkMsSUFBSSxhQUFhLENBQUMsWUFBWSxLQUFLLFNBQVMsRUFBRSxDQUFDO1lBQzdDLEdBQUcsQ0FBQyxLQUFLLEdBQUcsYUFBYSxDQUFDLFlBQVksQ0FBQyxRQUFRLEVBQUUsQ0FBQztRQUNwRCxDQUFDO1FBRUQsSUFBSSxhQUFhLENBQUMsZUFBZSxLQUFLLFNBQVMsRUFBRSxDQUFDO1lBQ2hELElBQUksYUFBYSxDQUFDLFlBQVksS0FBSyxTQUFTLEVBQUUsQ0FBQztnQkFDN0MsTUFBTSxJQUFJLEtBQUssQ0FDYiwyREFBMkQsQ0FDNUQsQ0FBQztZQUNKLENBQUM7WUFFRCxHQUFHLENBQUMsU0FBUyxHQUFHLGFBQWEsQ0FBQyxlQUFlLENBQUMsUUFBUSxFQUFFLENBQUM7UUFDM0QsQ0FBQztRQUVELElBQUksYUFBYSxDQUFDLFVBQVUsRUFBRSxDQUFDO1lBQzdCLEdBQUcsQ0FBQyxVQUFVLEdBQUcsYUFBYSxDQUFDLFVBQVUsQ0FBQztRQUM1QyxDQUFDO1FBRUQsSUFBSSxhQUFhLENBQUMsU0FBUyxFQUFFLENBQUM7WUFDNUIsR0FBRyxDQUFDLGtCQUFrQixHQUFHLGFBQWEsQ0FBQyxTQUFTLENBQUM7UUFDbkQsQ0FBQztRQUVELE9BQU8sR0FBRyxDQUFDO0lBQ2IsQ0FBQzs7QUFwTUgsMEJBcU1DO0FBMkNEOzs7Ozs7R0FNRztBQUNILE1BQWEsaUJBQWlCO0lBNEREOztJQTNEM0I7Ozs7Ozs7T0FPRztJQUNILE1BQU0sQ0FBQyxXQUFXLENBQUMsSUFBYTtRQUM5QixNQUFNLEdBQUcsR0FBRyxxQ0FBcUMsQ0FBQztRQUNsRCxPQUFPLElBQUksaUJBQWlCLENBQUMsUUFBUSxDQUFDLEdBQUcsRUFBRSxJQUFJLENBQUMsQ0FBQyxDQUFDO0lBQ3BELENBQUM7SUFFRDs7Ozs7Ozs7O09BU0c7SUFDSCxNQUFNLENBQUMsTUFBTSxDQUFDLEtBQWUsRUFBRSxJQUFhO1FBQzFDLE1BQU0sWUFBWSxHQUFHLEtBQUssQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUM7UUFFckMsbUhBQW1IO1FBQ25ILGlHQUFpRztRQUNqRyx1R0FBdUc7UUFDdkcsTUFBTSxHQUFHLEdBQUcsZ0VBQWdFLFlBQVksa0RBQWtELENBQUM7UUFFM0ksT0FBTyxJQUFJLGlCQUFpQixDQUFDLFFBQVEsQ0FBQyxHQUFHLEVBQUUsSUFBSSxDQUFDLENBQUMsQ0FBQztJQUNwRCxDQUFDO0lBRUQ7Ozs7Ozs7T0FPRztJQUNILE1BQU0sQ0FBQyxnQkFBZ0IsQ0FBQyxJQUFhO1FBQ25DLE9BQU8saUJBQWlCLENBQUMsTUFBTSxDQUFDLENBQUMsTUFBTSxFQUFFLEtBQUssQ0FBQyxFQUFFLElBQUksQ0FBQyxDQUFDO0lBQ3pELENBQUM7SUFFRDs7Ozs7Ozs7T0FRRztJQUNILE1BQU0sQ0FBQyxJQUFJLENBQUMsR0FBVztRQUNyQixPQUFPLElBQUksaUJBQWlCLENBQUMsR0FBRyxDQUFDLENBQUM7SUFDcEMsQ0FBQztJQUVELFlBQTJCLEdBQVc7UUFBWCxRQUFHLEdBQUgsR0FBRyxDQUFRO0lBQUcsQ0FBQzs7QUE1RDVDLDhDQTZEQztBQUVEOztHQUVHO0FBQ0gsU0FBUyxRQUFRLENBQUMsR0FBVyxFQUFFLElBQWE7SUFDMUMsSUFBSSxJQUFJLEtBQUssU0FBUyxFQUFFLENBQUM7UUFDdkIsT0FBTyxHQUFHLEdBQUcsT0FBTyxJQUFJLEVBQUUsQ0FBQztJQUM3QixDQUFDO0lBRUQsT0FBTyxHQUFHLENBQUM7QUFDYixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgcG9zaXggfSBmcm9tIFwicGF0aFwiO1xuaW1wb3J0IHR5cGUgeyBJQ29uc3RydWN0IH0gZnJvbSBcImNvbnN0cnVjdHNcIjtcbmltcG9ydCB7IENvbXBvbmVudCB9IGZyb20gXCIuL2NvbXBvbmVudFwiO1xuaW1wb3J0IHsgRGVwZW5kZW5jaWVzLCBEZXBlbmRlbmN5VHlwZSB9IGZyb20gXCIuL2RlcGVuZGVuY2llc1wiO1xuaW1wb3J0IHsgTm9kZVBhY2thZ2UgfSBmcm9tIFwiLi9qYXZhc2NyaXB0L25vZGUtcGFja2FnZVwiO1xuaW1wb3J0IHR5cGUgeyBUYXNrIH0gZnJvbSBcIi4vdGFza1wiO1xuXG4vKipcbiAqIFRoaXMgY29tbWFuZCBkZXRlcm1pbmVzIGlmIHRoZXJlIHdlcmUgYW55IGNoYW5nZXMgc2luY2UgdGhlIGxhc3QgcmVsZWFzZSBpbiBhXG4gKiBjcm9zcy1wbGF0Zm9ybSBjb21wYXRpYmxlIHdheS4gSXQgaXMgdXNlZCBhcyBhIGNvbmRpdGlvbiBmb3IgYm90aCB0aGUgYGJ1bXBgXG4gKiBhbmQgdGhlIGByZWxlYXNlYCB0YXNrczogaXQgZXhpdHMgMCAocHJvY2VlZCkgd2hlbiB0aGUgbW9zdCByZWNlbnQgY29tbWl0IGlzXG4gKiBub3QgYSByZWxlYXNlIGNvbW1pdCwgYW5kIG5vbi16ZXJvIChza2lwKSB3aGVuIHRoZSBtb3N0IHJlY2VudCBjb21taXQgaXMgYVxuICogYGNob3JlKHJlbGVhc2UpOmAgY29tbWl0LlxuICpcbiAqIEV4cGxhbmF0aW9uOlxuICogIC0gYGdpdCBsb2cgLS1vbmVsaW5lIC0xYCAgICAgICAgICB0aGUgbW9zdCByZWNlbnQgY29tbWl0LCBvbmUgbGluZVxuICogIC0gYHwgZ3JlcCAtdiBcImNob3JlKHJlbGVhc2UpOlwiYCAgIHBhc3MgdGhlIGxpbmUgdGhyb3VnaCBvbmx5IGlmIGl0IGlzIE5PVCBhIHJlbGVhc2UgY29tbWl0XG4gKiAgLSBgPiAvZGV2L251bGxgICAgICAgICAgICAgICAgICAgIGRpc2NhcmQgZ3JlcCdzIG91dHB1dDsgb25seSBpdHMgZXhpdCBjb2RlIG1hdHRlcnNcbiAqXG4gKiBncmVwIGV4aXRzIDAgd2hlbiBpdCBwcmludHMgYXQgbGVhc3Qgb25lIG5vbi1tYXRjaGluZyBsaW5lIChhIG5vcm1hbCBjb21taXQsXG4gKiBzbyBwcm9jZWVkKSBhbmQgMSB3aGVuIGV2ZXJ5IGxpbmUgbWF0Y2hlcyAoYSByZWxlYXNlIGNvbW1pdCwgc28gc2tpcCkuXG4gKlxuICogSU1QT1JUQU5UOiBkbyBOT1QgcmVpbnRyb2R1Y2UgYGdyZXAgLXFgIGhlcmUgKGkuZS4gZG8gbm90IFwib3B0aW1pemVcIiB0aGlzIGJhY2tcbiAqIHRvIGBncmVwIC1xdmApLiBgZ3JlcCAtcWAgZXhpdHMgYXMgc29vbiBhcyBpdCBoYXMgYW4gYW5zd2VyIGFuZCBjbG9zZXMgdGhlIHJlYWRcbiAqIGVuZCBvZiB0aGUgcGlwZS4gV2hlbiB0aGlzIGNvbmRpdGlvbiBydW5zIHRocm91Z2ggcHJvamVuJ3MgYnVpbHQtaW4gKGRheClcbiAqIHNoZWxsLCB0aGF0IGVhcmx5IGNsb3NlIHJhY2VzIHdpdGggYGdpdCBsb2dgIHN0aWxsIHdyaXRpbmcgdG8gdGhlIHBpcGUsIGFuZCBkYXhcbiAqIHN1cmZhY2VzIHRoZSBmYWlsZWQgd3JpdGUgYXMgYSBzcHVyaW91cyBub24temVybyBleGl0IChcInN0ZGluIHBpcGUgYnJva2VuLlxuICogSW52YWxpZCBzdGF0ZTogV3JpdGFibGVTdHJlYW0gaXMgY2xvc2VkXCIpLiBUaGUgdGFzayBydW50aW1lIGNhbm5vdCBkaXN0aW5ndWlzaFxuICogdGhhdCBmcm9tIGEgbGVnaXRpbWF0ZSBza2lwIChkYXggcmVwb3J0cyBpdCBhcyBhIHBsYWluIG5vbi16ZXJvIGNvZGUgdW5kZXJcbiAqIGAubm9UaHJvdygpYCwgbm90IGFzIGFuIGVycm9yKSwgc28gdGhlIGJ1bXAvcmVsZWFzZSB0YXNrIGlzIHNpbGVudGx5IHNraXBwZWQ6IGFcbiAqIHJlbGVhc2UgaXMgbWlzc2VkLCBvciBhIGRlcGVuZGVudCBwdWJsaXNoZXMgYSBicm9rZW4gYF4wLjAuMGAgdmVyc2lvbiByYW5nZS5cbiAqIFBsYWluIGBncmVwIC12IC4uLiA+IC9kZXYvbnVsbGAgcmVhZHMgdG8gRU9GIGluc3RlYWQgb2Ygc2hvcnQtY2lyY3VpdGluZywgc28gaXRcbiAqIG5ldmVyIGNsb3NlcyB0aGUgcGlwZSB3aGlsZSB0aGUgd3JpdGVyIGlzIGFjdGl2ZSBhbmQgdGhlIHJhY2UgY2Fubm90IG9jY3VyLiBUaGVcbiAqIGV4aXQgc2VtYW50aWNzIGFyZSBpZGVudGljYWwgdG8gdGhlIHByZXZpb3VzIGBncmVwIC1xdmAuXG4gKi9cbmV4cG9ydCBjb25zdCBDSEFOR0VTX1NJTkNFX0xBU1RfUkVMRUFTRSA9XG4gICdnaXQgbG9nIC0tb25lbGluZSAtMSB8IGdyZXAgLXYgXCJjaG9yZShyZWxlYXNlKTpcIiA+IC9kZXYvbnVsbCc7XG5cbi8qKlxuICogVGhlIGRlZmF1bHQgcGFja2FnZSB0byBiZSB1c2VkIGZvciBjb21taXQtYW5kLXRhZy12ZXJzaW9uXG4gKi9cbmNvbnN0IENPTU1JVF9BTkRfVEFHX1ZFUlNJT05fREVGQVVMVCA9IFwiY29tbWl0LWFuZC10YWctdmVyc2lvbkBeMTJcIjtcblxuLyoqXG4gKiBPcHRpb25zIGZvciBgVmVyc2lvbmAuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgVmVyc2lvbk9wdGlvbnMge1xuICAvKipcbiAgICogQSBuYW1lIG9mIGEgLmpzb24gZmlsZSB0byBzZXQgdGhlIGB2ZXJzaW9uYCBmaWVsZCBpbiBhZnRlciBhIGJ1bXAuXG4gICAqXG4gICAqIEBleGFtcGxlIFwicGFja2FnZS5qc29uXCJcbiAgICovXG4gIHJlYWRvbmx5IHZlcnNpb25JbnB1dEZpbGU6IHN0cmluZztcblxuICAvKipcbiAgICogVGhlIG5hbWUgb2YgdGhlIGRpcmVjdG9yeSBpbnRvIHdoaWNoIGBjaGFuZ2Vsb2cubWRgIGFuZCBgdmVyc2lvbi50eHRgIGZpbGVzXG4gICAqIGFyZSBlbWl0dGVkLlxuICAgKi9cbiAgcmVhZG9ubHkgYXJ0aWZhY3RzRGlyZWN0b3J5OiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIEN1c3RvbSBjb25maWd1cmF0aW9uIGZvciB2ZXJzaW9ucmMgZmlsZSB1c2VkIGJ5IHN0YW5kYXJkLXJlbGVhc2VcbiAgICovXG4gIHJlYWRvbmx5IHZlcnNpb25yY09wdGlvbnM/OiBSZWNvcmQ8c3RyaW5nLCBhbnk+O1xuXG4gIC8qKlxuICAgKiBUaGUgdGFnIHByZWZpeCBjb3JyZXNwb25kaW5nIHRvIHRoaXMgdmVyc2lvbi5cbiAgICovXG4gIHJlYWRvbmx5IHRhZ1ByZWZpeD86IHN0cmluZztcblxuICAvKipcbiAgICogRmluZCBjb21taXRzIHRoYXQgc2hvdWxkIGJlIGNvbnNpZGVyZWQgcmVsZWFzYWJsZVxuICAgKiBVc2VkIHRvIGRlY2lkZSBpZiBhIHJlbGVhc2UgaXMgcmVxdWlyZWQuXG4gICAqXG4gICAqIEBkZWZhdWx0IFJlbGVhc2FibGVDb21taXRzLmV2ZXJ5Q29tbWl0KClcbiAgICovXG4gIHJlYWRvbmx5IHJlbGVhc2FibGVDb21taXRzPzogUmVsZWFzYWJsZUNvbW1pdHM7XG5cbiAgLyoqXG4gICAqIFRoZSBgY29tbWl0LWFuZC10YWctdmVyc2lvbmAgY29tcGF0aWJsZSBwYWNrYWdlIHVzZWQgdG8gYnVtcCB0aGUgcGFja2FnZSB2ZXJzaW9uLCBhcyBhIGRlcGVuZGVuY3kgc3RyaW5nLlxuICAgKlxuICAgKiBUaGlzIGNhbiBiZSBhbnkgY29tcGF0aWJsZSBwYWNrYWdlIHZlcnNpb24sIGluY2x1ZGluZyB0aGUgZGVwcmVjYXRlZCBgc3RhbmRhcmQtdmVyc2lvbkA5YC5cbiAgICpcbiAgICogQGRlZmF1bHQgXCJjb21taXQtYW5kLXRhZy12ZXJzaW9uQDEyXCJcbiAgICovXG4gIHJlYWRvbmx5IGJ1bXBQYWNrYWdlPzogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBBIHNoZWxsIGNvbW1hbmQgdG8gY29udHJvbCB0aGUgbmV4dCB2ZXJzaW9uIHRvIHJlbGVhc2UuXG4gICAqXG4gICAqIElmIHByZXNlbnQsIHRoaXMgc2hlbGwgY29tbWFuZCB3aWxsIGJlIHJ1biBiZWZvcmUgdGhlIGJ1bXAgaXMgZXhlY3V0ZWQsIGFuZFxuICAgKiBpdCBkZXRlcm1pbmVzIHdoYXQgdmVyc2lvbiB0byByZWxlYXNlLiBJdCB3aWxsIGJlIGV4ZWN1dGVkIGluIHRoZSBmb2xsb3dpbmdcbiAgICogZW52aXJvbm1lbnQ6XG4gICAqXG4gICAqIC0gV29ya2luZyBkaXJlY3Rvcnk6IHRoZSBwcm9qZWN0IGRpcmVjdG9yeS5cbiAgICogLSBgJFZFUlNJT05gOiB0aGUgY3VycmVudCB2ZXJzaW9uLiBMb29rcyBsaWtlIGAxLjIuM2AuXG4gICAqIC0gYCRMQVRFU1RfVEFHYDogdGhlIG1vc3QgcmVjZW50IHRhZy4gTG9va3MgbGlrZSBgcHJlZml4LXYxLjIuM2AsIG9yIG1heSBiZSB1bnNldC5cbiAgICogLSBgJFNVR0dFU1RFRF9CVU1QYDogdGhlIHN1Z2dlc3RlZCBidW1wIGFjdGlvbiBiYXNlZCBvbiBjb21taXRzLiBPbmUgb2YgYG1ham9yfG1pbm9yfHBhdGNofG5vbmVgLlxuICAgKlxuICAgKiBUaGUgY29tbWFuZCBzaG91bGQgcHJpbnQgb25lIG9mIHRoZSBmb2xsb3dpbmcgdG8gYHN0ZG91dGA6XG4gICAqXG4gICAqIC0gTm90aGluZzogdGhlIG5leHQgdmVyc2lvbiBudW1iZXIgd2lsbCBiZSBkZXRlcm1pbmVkIGJhc2VkIG9uIGNvbW1pdCBoaXN0b3J5LlxuICAgKiAtIGB4LnkuemA6IHRoZSBuZXh0IHZlcnNpb24gbnVtYmVyIHdpbGwgYmUgYHgueS56YC5cbiAgICogLSBgbWFqb3J8bWlub3J8cGF0Y2hgOiB0aGUgbmV4dCB2ZXJzaW9uIG51bWJlciB3aWxsIGJlIHRoZSBjdXJyZW50IHZlcnNpb24gbnVtYmVyXG4gICAqICAgd2l0aCB0aGUgaW5kaWNhdGVkIGNvbXBvbmVudCBidW1wZWQuXG4gICAqXG4gICAqIEBkZWZhdWx0IC0gVGhlIG5leHQgdmVyc2lvbiB3aWxsIGJlIGRldGVybWluZWQgYmFzZWQgb24gdGhlIGNvbW1pdCBoaXN0b3J5IGFuZCBwcm9qZWN0IHNldHRpbmdzLlxuICAgKi9cbiAgcmVhZG9ubHkgbmV4dFZlcnNpb25Db21tYW5kPzogc3RyaW5nO1xufVxuXG5leHBvcnQgY2xhc3MgVmVyc2lvbiBleHRlbmRzIENvbXBvbmVudCB7XG4gIHB1YmxpYyByZWFkb25seSBidW1wVGFzazogVGFzaztcbiAgcHVibGljIHJlYWRvbmx5IHVuYnVtcFRhc2s6IFRhc2s7XG5cbiAgLyoqXG4gICAqIFRoZSB0YXNrIHRoYXQgcHJpbnRzIHRoZSByZWxlYXNhYmxlIGNvbW1pdHMgc2luY2UgdGhlIGxhdGVzdCB0YWcuIFNwYXduZWRcbiAgICogYnkgYGJ1bXBgOyBpdHMgc2hlbGwgY2FuIGJlIG92ZXJyaWRkZW4gdmlhIGB0YXNrLnNoZWxsYC5cbiAgICovXG4gIHB1YmxpYyByZWFkb25seSByZWxlYXNhYmxlQ29tbWl0c1Rhc2s6IFRhc2s7XG5cbiAgLyoqXG4gICAqIFRoZSB0YXNrIHRoYXQgcnVucyB0aGUgdXNlcidzIGBuZXh0VmVyc2lvbkNvbW1hbmRgLCBpZiBjb25maWd1cmVkLiBTcGF3bmVkXG4gICAqIGJ5IGBidW1wYDsgaXRzIHNoZWxsIGNhbiBiZSBvdmVycmlkZGVuIHZpYSBgdGFzay5zaGVsbGAuXG4gICAqL1xuICBwdWJsaWMgcmVhZG9ubHkgbmV4dFZlcnNpb25UYXNrPzogVGFzaztcblxuICAvKipcbiAgICogVGhlIG5hbWUgb2YgdGhlIGNoYW5nZWxvZyBmaWxlICh1bmRlciBgYXJ0aWZhY3RzRGlyZWN0b3J5YCkuXG4gICAqL1xuICBwdWJsaWMgcmVhZG9ubHkgY2hhbmdlbG9nRmlsZU5hbWU6IHN0cmluZztcblxuICAvKipcbiAgICogVGhlIG5hbWUgb2YgdGhlIGZpbGUgdGhhdCBjb250YWlucyB0aGUgdmVyc2lvbiAodW5kZXIgYGFydGlmYWN0c0RpcmVjdG9yeWApLlxuICAgKi9cbiAgcHVibGljIHJlYWRvbmx5IHZlcnNpb25GaWxlTmFtZTogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBUaGUgbmFtZSBvZiB0aGUgZmlsZSB0aGF0IGNvbnRhaW5zIHRoZSByZWxlYXNlIHRhZyAodW5kZXIgYGFydGlmYWN0c0RpcmVjdG9yeWApLlxuICAgKi9cbiAgcHVibGljIHJlYWRvbmx5IHJlbGVhc2VUYWdGaWxlTmFtZTogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBUaGUgcGFja2FnZSB1c2VkIHRvIGJ1bXAgcGFja2FnZSB2ZXJzaW9ucywgYXMgYSBkZXBlbmRlbmN5IHN0cmluZy5cbiAgICogVGhpcyBpcyBhIGBjb21taXQtYW5kLXRhZy12ZXJzaW9uYCBjb21wYXRpYmxlIHBhY2thZ2UuXG4gICAqL1xuICBwdWJsaWMgcmVhZG9ubHkgYnVtcFBhY2thZ2U6IHN0cmluZztcblxuICBwcml2YXRlIHJlYWRvbmx5IG5leHRWZXJzaW9uQ29tbWFuZD86IHN0cmluZztcblxuICBjb25zdHJ1Y3RvcihzY29wZTogSUNvbnN0cnVjdCwgb3B0aW9uczogVmVyc2lvbk9wdGlvbnMpIHtcbiAgICBzdXBlcihzY29wZSk7XG5cbiAgICB0aGlzLmNoYW5nZWxvZ0ZpbGVOYW1lID0gXCJjaGFuZ2Vsb2cubWRcIjtcbiAgICB0aGlzLnZlcnNpb25GaWxlTmFtZSA9IFwidmVyc2lvbi50eHRcIjtcbiAgICB0aGlzLnJlbGVhc2VUYWdGaWxlTmFtZSA9IFwicmVsZWFzZXRhZy50eHRcIjtcbiAgICB0aGlzLmJ1bXBQYWNrYWdlID0gb3B0aW9ucy5idW1wUGFja2FnZSA/PyBDT01NSVRfQU5EX1RBR19WRVJTSU9OX0RFRkFVTFQ7XG4gICAgdGhpcy5uZXh0VmVyc2lvbkNvbW1hbmQgPSBvcHRpb25zLm5leHRWZXJzaW9uQ29tbWFuZDtcblxuICAgIC8vIFRoaXMgY29tcG9uZW50IGlzIGxhbmd1YWdlIGluZGVwZW5kZW50LlxuICAgIC8vIEhvd2V2ZXIsIHdoZW4gaW4gdGhlIE5vZGUuanMgZWNvc3lzdGVtLCB3ZSBjYW4gaW1wcm92ZSB0aGUgZXhwZXJpZW5jZSBieSBhZGRpbmcgYSBkZXYgZGVwZW5kZW5jeSBvbiB0aGUgYnVtcCBwYWNrYWdlLlxuICAgIGNvbnN0IG5vZGUgPSBOb2RlUGFja2FnZS5vZih0aGlzLnByb2plY3QpO1xuICAgIGlmIChub2RlKSB7XG4gICAgICBjb25zdCB7IG5hbWU6IGJ1bXBOYW1lLCB2ZXJzaW9uOiBidW1wVmVyc2lvbiB9ID1cbiAgICAgICAgRGVwZW5kZW5jaWVzLnBhcnNlRGVwZW5kZW5jeSh0aGlzLmJ1bXBQYWNrYWdlKTtcbiAgICAgIG5vZGUucHJvamVjdC5kZXBzLnJlcXVlc3REZXBlbmRlbmN5KHtcbiAgICAgICAgbmFtZTogYnVtcE5hbWUsXG4gICAgICAgIHZlcnNpb246IGJ1bXBWZXJzaW9uLFxuICAgICAgICB0eXBlOiBEZXBlbmRlbmN5VHlwZS5CVUlMRCxcbiAgICAgIH0pO1xuICAgIH1cblxuICAgIGNvbnN0IHZlcnNpb25JbnB1dEZpbGUgPSBvcHRpb25zLnZlcnNpb25JbnB1dEZpbGU7XG5cbiAgICBjb25zdCBjaGFuZ2Vsb2dGaWxlID0gcG9zaXguam9pbihcbiAgICAgIG9wdGlvbnMuYXJ0aWZhY3RzRGlyZWN0b3J5LFxuICAgICAgdGhpcy5jaGFuZ2Vsb2dGaWxlTmFtZSxcbiAgICApO1xuICAgIGNvbnN0IGJ1bXBGaWxlID0gcG9zaXguam9pbihcbiAgICAgIG9wdGlvbnMuYXJ0aWZhY3RzRGlyZWN0b3J5LFxuICAgICAgdGhpcy52ZXJzaW9uRmlsZU5hbWUsXG4gICAgKTtcbiAgICBjb25zdCByZWxlYXNlVGFnRmlsZSA9IHBvc2l4LmpvaW4oXG4gICAgICBvcHRpb25zLmFydGlmYWN0c0RpcmVjdG9yeSxcbiAgICAgIHRoaXMucmVsZWFzZVRhZ0ZpbGVOYW1lLFxuICAgICk7XG5cbiAgICBjb25zdCBjb21tb25FbnY6IFJlY29yZDxzdHJpbmcsIHN0cmluZz4gPSB7XG4gICAgICBPVVRGSUxFOiB2ZXJzaW9uSW5wdXRGaWxlLFxuICAgICAgQ0hBTkdFTE9HOiBjaGFuZ2Vsb2dGaWxlLFxuICAgICAgQlVNUEZJTEU6IGJ1bXBGaWxlLFxuICAgICAgUkVMRUFTRVRBRzogcmVsZWFzZVRhZ0ZpbGUsXG4gICAgICBSRUxFQVNFX1RBR19QUkVGSVg6IG9wdGlvbnMudGFnUHJlZml4ID8/IFwiXCIsXG4gICAgICAvLyBkb2Vzbid0IHdvcmsgaWYgY3VzdG9tIGNvbmZpZ3VyYXRpb24gaXMgbG9uZ1xuICAgICAgVkVSU0lPTlJDT1BUSU9OUzogSlNPTi5zdHJpbmdpZnkob3B0aW9ucy52ZXJzaW9ucmNPcHRpb25zKSxcbiAgICAgIEJVTVBfUEFDS0FHRTogdGhpcy5idW1wUGFja2FnZSxcbiAgICB9O1xuXG4gICAgLy8gVGhlIGNvbW1hbmQgdGhhdCBsaXN0cyByZWxlYXNhYmxlIGNvbW1pdHMsIHJ1biBhcyBpdHMgb3duIHNwYXduYWJsZSB0YXNrXG4gICAgLy8gc28gaXRzIHNoZWxsIGNhbiBiZSBjb25maWd1cmVkIGluZGVwZW5kZW50bHkgKHNlZSBgVGFza1NoZWxsYCkuXG4gICAgLy8gYCRMQVRFU1RfVEFHYCBpcyBwcm92aWRlZCBieSBgYnVtcGAgd2hlbiBzcGF3bmluZyBpdC5cbiAgICB0aGlzLnJlbGVhc2FibGVDb21taXRzVGFzayA9IHRoaXMucHJvamVjdC5hZGRUYXNrKFxuICAgICAgXCJidW1wOnJlbGVhc2FibGUtY29tbWl0c1wiLFxuICAgICAge1xuICAgICAgICBkZXNjcmlwdGlvbjogXCJQcmludCB0aGUgcmVsZWFzYWJsZSBjb21taXRzIHNpbmNlIHRoZSBsYXRlc3QgcmVsZWFzZVwiLFxuICAgICAgICBleGVjOiAob3B0aW9ucy5yZWxlYXNhYmxlQ29tbWl0cyA/PyBSZWxlYXNhYmxlQ29tbWl0cy5ldmVyeUNvbW1pdCgpKVxuICAgICAgICAgIC5jbWQsXG4gICAgICB9LFxuICAgICk7XG5cbiAgICAvLyBUaGUgb3B0aW9uYWwgY29tbWFuZCB0aGF0IGRlY2lkZXMgdGhlIG5leHQgdmVyc2lvbiwgYWxzbyBpdHMgb3duIHRhc2suXG4gICAgaWYgKHRoaXMubmV4dFZlcnNpb25Db21tYW5kKSB7XG4gICAgICB0aGlzLm5leHRWZXJzaW9uVGFzayA9IHRoaXMucHJvamVjdC5hZGRUYXNrKFwiYnVtcDpuZXh0LXZlcnNpb25cIiwge1xuICAgICAgICBkZXNjcmlwdGlvbjogXCJEZXRlcm1pbmUgdGhlIG5leHQgdmVyc2lvbiB0byByZWxlYXNlXCIsXG4gICAgICAgIGV4ZWM6IHRoaXMubmV4dFZlcnNpb25Db21tYW5kLFxuICAgICAgfSk7XG4gICAgfVxuXG4gICAgLy8gT3JjaGVzdHJhdGVzIHRoZSByZWxlYXNlIGJ1bXAgYXMgYSBwaXBlbGluZSBvZiBidWlsdGlucyBhbmQgc3Bhd25lZFxuICAgIC8vIHRhc2tzLCBoYW5kaW5nIHJlc3VsdHMgZm9yd2FyZCB2aWEgc3RlcCBgb3V0cHV0RW52YCBjYXB0dXJlcy5cbiAgICB0aGlzLmJ1bXBUYXNrID0gdGhpcy5wcm9qZWN0LmFkZFRhc2soXCJidW1wXCIsIHtcbiAgICAgIGRlc2NyaXB0aW9uOlxuICAgICAgICBcIkJ1bXBzIHZlcnNpb24gYmFzZWQgb24gbGF0ZXN0IGdpdCB0YWcgYW5kIGdlbmVyYXRlcyBhIGNoYW5nZWxvZyBlbnRyeVwiLFxuICAgICAgY29uZGl0aW9uOiBDSEFOR0VTX1NJTkNFX0xBU1RfUkVMRUFTRSxcbiAgICAgIGVudjogeyAuLi5jb21tb25FbnYgfSxcbiAgICB9KTtcblxuICAgIHRoaXMuYnVtcFRhc2suYWRkU3RlcHMoXG4gICAgICB7IGJ1aWx0aW46IFwicmVsZWFzZS9yZXNvbHZlLWxhdGVzdC10YWdcIiwgb3V0cHV0RW52OiBcIkxBVEVTVF9UQUdcIiB9LFxuICAgICAgLy8gT24gYSBmaXJzdCByZWxlYXNlIHRoZSByZXNvbHZlZCB0YWcgaXMgc3ludGhldGljIGFuZCBkb2VzIG5vdCBleGlzdCwgc29cbiAgICAgIC8vIHRoZXJlIGlzIG5vdGhpbmcgdG8gZGlmZiBhZ2FpbnN0IC0gc2tpcCBsaXN0aW5nIGNvbW1pdHMgaW4gdGhhdCBjYXNlLlxuICAgICAge1xuICAgICAgICBzcGF3bjogXCJidW1wOnJlbGVhc2FibGUtY29tbWl0c1wiLFxuICAgICAgICBvdXRwdXRFbnY6IFwiUkVMRUFTQUJMRV9DT01NSVRTXCIsXG4gICAgICAgIGNvbmRpdGlvbjogJ2dpdCByZXYtcGFyc2UgLS12ZXJpZnkgLS1xdWlldCBcInJlZnMvdGFncy8kTEFURVNUX1RBR1wiJyxcbiAgICAgIH0sXG4gICAgICB7IGJ1aWx0aW46IFwicmVsZWFzZS9zdWdnZXN0LXZlcnNpb24tYnVtcFwiLCBvdXRwdXRFbnY6IFwiU1VHR0VTVEVEX0JVTVBcIiB9LFxuICAgICk7XG4gICAgaWYgKHRoaXMubmV4dFZlcnNpb25UYXNrKSB7XG4gICAgICAvLyBgYnVtcDpuZXh0LXZlcnNpb25gIHJlY2VpdmVzIGAkVkVSU0lPTmAgKHRoZSBjdXJyZW50IHZlcnNpb24pOyByZWFkIGl0XG4gICAgICAvLyBmcm9tIHRoZSB2ZXJzaW9uIGZpbGUgaW50byBgVkVSU0lPTmAgc28gaXQgcHJvcGFnYXRlcyB0byB0aGUgc3Bhd24uXG4gICAgICB0aGlzLmJ1bXBUYXNrLmFkZFN0ZXBzKFxuICAgICAgICB7XG4gICAgICAgICAgZXhlYzogYG5vZGUgLWUgXCJwcm9jZXNzLnN0ZG91dC53cml0ZShKU09OLnBhcnNlKHJlcXVpcmUoJ2ZzJykucmVhZEZpbGVTeW5jKHByb2Nlc3MuZW52Lk9VVEZJTEUsJ3V0ZjgnKSkudmVyc2lvbilcImAsXG4gICAgICAgICAgb3V0cHV0RW52OiBcIlZFUlNJT05cIixcbiAgICAgICAgfSxcbiAgICAgICAgeyBzcGF3bjogXCJidW1wOm5leHQtdmVyc2lvblwiLCBvdXRwdXRFbnY6IFwiQlVNUF9UWVBFXCIgfSxcbiAgICAgICk7XG4gICAgfVxuICAgIHRoaXMuYnVtcFRhc2suYWRkU3RlcHMoeyBidWlsdGluOiBcInJlbGVhc2UvYXBwbHktdmVyc2lvbi1idW1wXCIgfSk7XG5cbiAgICAvLyBSZXNldHMgdGhlIHZlcnNpb24gaW4gdGhlIHZlcnNpb24gZmlsZSBiYWNrIHRvIDAuMC4wIGFmdGVyIGEgYnVtcC5cbiAgICB0aGlzLnVuYnVtcFRhc2sgPSB0aGlzLnByb2plY3QuYWRkVGFzayhcInVuYnVtcFwiLCB7XG4gICAgICBkZXNjcmlwdGlvbjogXCJSZXN0b3JlcyB2ZXJzaW9uIHRvIDAuMC4wXCIsXG4gICAgICBlbnY6IHsgLi4uY29tbW9uRW52IH0sXG4gICAgfSk7XG5cbiAgICB0aGlzLnVuYnVtcFRhc2suYnVpbHRpbihcInJlbGVhc2UvcmVzZXQtdmVyc2lvblwiKTtcblxuICAgIHRoaXMucHJvamVjdC5hZGRHaXRJZ25vcmUoYC8ke2NoYW5nZWxvZ0ZpbGV9YCk7XG4gICAgdGhpcy5wcm9qZWN0LmFkZEdpdElnbm9yZShgLyR7YnVtcEZpbGV9YCk7XG4gICAgdGhpcy5wcm9qZWN0LmFkZFBhY2thZ2VJZ25vcmUoYC8ke2NoYW5nZWxvZ0ZpbGV9YCk7XG4gICAgdGhpcy5wcm9qZWN0LmFkZFBhY2thZ2VJZ25vcmUoYC8ke2J1bXBGaWxlfWApO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybiB0aGUgZW52aXJvbm1lbnQgdmFyaWFibGVzIHRvIG1vZGlmeSB0aGUgYnVtcCBjb21tYW5kIGZvciByZWxlYXNlIGJyYW5jaGVzLlxuICAgKlxuICAgKiBUaGVzZSBvcHRpb25zIGFyZSB1c2VkIHRvIG1vZGlmeSB0aGUgYmVoYXZpb3Igb2YgdGhlIHZlcnNpb24gYnVtcGluZyBzY3JpcHRcbiAgICogZm9yIGFkZGl0aW9uYWwgYnJhbmNoZXMsIGJ5IHNldHRpbmcgZW52aXJvbm1lbnQgdmFyaWFibGVzLlxuICAgKlxuICAgKiBObyBzZXR0aW5ncyBhcmUgaW5oZXJpdGVkIGZyb20gdGhlIGJhc2UgYFZlcnNpb25gIG9iamVjdCAoYnV0IGFueSBwYXJhbWV0ZXJzIHRoYXRcbiAgICogY29udHJvbCB2ZXJzaW9ucyBkbyBjb25mbGljdCB3aXRoIHRoZSB1c2Ugb2YgYSBgbmV4dFZlcnNpb25Db21tYW5kYCkuXG4gICAqL1xuICBwdWJsaWMgZW52Rm9yQnJhbmNoKFxuICAgIGJyYW5jaE9wdGlvbnM6IFZlcnNpb25CcmFuY2hPcHRpb25zLFxuICApOiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+IHtcbiAgICBpZiAodGhpcy5uZXh0VmVyc2lvbkNvbW1hbmQgJiYgYnJhbmNoT3B0aW9ucy5taW5NYWpvclZlcnNpb24pIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgXCJtaW5NYWpvclZlcnNpb24gYW5kIG5leHRWZXJzaW9uQ29tbWFuZCBjYW5ub3QgYmUgdXNlZCB0b2dldGhlci5cIixcbiAgICAgICk7XG4gICAgfVxuXG4gICAgY29uc3QgZW52OiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+ID0ge307XG4gICAgaWYgKGJyYW5jaE9wdGlvbnMubWFqb3JWZXJzaW9uICE9PSB1bmRlZmluZWQpIHtcbiAgICAgIGVudi5NQUpPUiA9IGJyYW5jaE9wdGlvbnMubWFqb3JWZXJzaW9uLnRvU3RyaW5nKCk7XG4gICAgfVxuXG4gICAgaWYgKGJyYW5jaE9wdGlvbnMubWluTWFqb3JWZXJzaW9uICE9PSB1bmRlZmluZWQpIHtcbiAgICAgIGlmIChicmFuY2hPcHRpb25zLm1ham9yVmVyc2lvbiAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgICBgbWluTWFqb3JWZXJzaW9uIGFuZCBtYWpvclZlcnNpb24gY2Fubm90IGJlIHVzZWQgdG9nZXRoZXIuYCxcbiAgICAgICAgKTtcbiAgICAgIH1cblxuICAgICAgZW52Lk1JTl9NQUpPUiA9IGJyYW5jaE9wdGlvbnMubWluTWFqb3JWZXJzaW9uLnRvU3RyaW5nKCk7XG4gICAgfVxuXG4gICAgaWYgKGJyYW5jaE9wdGlvbnMucHJlcmVsZWFzZSkge1xuICAgICAgZW52LlBSRVJFTEVBU0UgPSBicmFuY2hPcHRpb25zLnByZXJlbGVhc2U7XG4gICAgfVxuXG4gICAgaWYgKGJyYW5jaE9wdGlvbnMudGFnUHJlZml4KSB7XG4gICAgICBlbnYuUkVMRUFTRV9UQUdfUFJFRklYID0gYnJhbmNoT3B0aW9ucy50YWdQcmVmaXg7XG4gICAgfVxuXG4gICAgcmV0dXJuIGVudjtcbiAgfVxufVxuXG4vKipcbiAqIE9wdGlvbnMgdG8gcGFzcyB0byBgbW9kaWZ5QnJhbmNoRW52aXJvbm1lbnRgXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgVmVyc2lvbkJyYW5jaE9wdGlvbnMge1xuICAvKipcbiAgICogVGhlIG1ham9yIHZlcnNpb25zIHJlbGVhc2VkIGZyb20gdGhpcyBicmFuY2guXG4gICAqL1xuICByZWFkb25seSBtYWpvclZlcnNpb24/OiBudW1iZXI7XG5cbiAgLyoqXG4gICAqIFRoZSBtaW5pbXVtIG1ham9yIHZlcnNpb24gdG8gcmVsZWFzZS5cbiAgICovXG4gIHJlYWRvbmx5IG1pbk1ham9yVmVyc2lvbj86IG51bWJlcjtcblxuICAvKipcbiAgICogVGhlIG1pbm9yIHZlcnNpb25zIHJlbGVhc2VkIGZyb20gdGhpcyBicmFuY2guXG4gICAqL1xuICByZWFkb25seSBtaW5vclZlcnNpb24/OiBudW1iZXI7XG5cbiAgLyoqXG4gICAqIEJ1bXAgdGhlIHZlcnNpb24gYXMgYSBwcmUtcmVsZWFzZSB0YWcuXG4gICAqXG4gICAqIEBkZWZhdWx0IC0gbm9ybWFsIHJlbGVhc2VzXG4gICAqL1xuICByZWFkb25seSBwcmVyZWxlYXNlPzogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBBdXRvbWF0aWNhbGx5IGFkZCB0aGUgZ2l2ZW4gcHJlZml4IHRvIHJlbGVhc2UgdGFncy5cbiAgICogVXNlZnVsIGlmIHlvdSBhcmUgcmVsZWFzaW5nIG9uIG11bHRpcGxlIGJyYW5jaGVzIHdpdGggb3ZlcmxhcHBpbmdcbiAgICogdmVyc2lvbiBudW1iZXJzLlxuICAgKlxuICAgKiBOb3RlOiB0aGlzIHByZWZpeCBpcyB1c2VkIHRvIGRldGVjdCB0aGUgbGF0ZXN0IHRhZ2dlZCB2ZXJzaW9uXG4gICAqIHdoZW4gYnVtcGluZywgc28gaWYgeW91IGNoYW5nZSB0aGlzIG9uIGEgcHJvamVjdCB3aXRoIGFuIGV4aXN0aW5nIHZlcnNpb25cbiAgICogaGlzdG9yeSwgeW91IG1heSBuZWVkIHRvIG1hbnVhbGx5IHRhZyB5b3VyIGxhdGVzdCByZWxlYXNlXG4gICAqIHdpdGggdGhlIG5ldyBwcmVmaXguXG4gICAqXG4gICAqIEBkZWZhdWx0IC0gbm8gcHJlZml4XG4gICAqL1xuICByZWFkb25seSB0YWdQcmVmaXg/OiBzdHJpbmc7XG59XG5cbi8qKlxuICogRmluZCBjb21taXRzIHRoYXQgc2hvdWxkIGJlIGNvbnNpZGVyZWQgcmVsZWFzYWJsZSB0byBkZWNpZGUgaWYgYSByZWxlYXNlIGlzIHJlcXVpcmVkLlxuICpcbiAqIFRoaXMgc2V0dGluZyBvbmx5IGNvbnRyb2xzIHdoZXRoZXIgYSByZWxlYXNlIGlzIHRyaWdnZXJlZCwgeWVzIG9yIG5vLiBUaGVcbiAqIHBhdGhzIHVzZWQgaGVyZSBhcmUgaW5kZXBlbmRlbnQgb2YgdGhlIGNvZGUgdGhhdCBjb250cm9scyB3aGF0IGNvbW1pdHMgYXJlIGluc3BlY3RlZFxuICogdG8gZGV0ZXJtaW5lIHRoZSB2ZXJzaW9uIG51bWJlci5cbiAqL1xuZXhwb3J0IGNsYXNzIFJlbGVhc2FibGVDb21taXRzIHtcbiAgLyoqXG4gICAqIFJlbGVhc2UgZXZlcnkgY29tbWl0XG4gICAqXG4gICAqIFRoaXMgd2lsbCBvbmx5IG5vdCByZWxlYXNlIGlmIHRoZSBtb3N0IHJlY2VudCBjb21taXQgaXMgdGFnZ2VkIHdpdGggdGhlIGxhdGVzdCBtYXRjaGluZyB0YWcuXG4gICAqXG4gICAqIEBwYXJhbSBwYXRoIENvbnNpZGVyIG9ubHkgY29tbWl0cyB0aGF0IGFyZSBlbm91Z2ggdG8gZXhwbGFpbiBob3cgdGhlIGZpbGVzIHRoYXQgbWF0Y2ggdGhlIHNwZWNpZmllZCBwYXRocyBjYW1lIHRvIGJlLlxuICAgKiBUaGlzIHBhdGggaXMgcmVsYXRpdmUgdG8gdGhlIGN1cnJlbnQgd29ya2luZyBkaXIgb2YgdGhlIGBidW1wYCB0YXNrLCBpLmUuIHRvIG9ubHkgY29uc2lkZXIgY29tbWl0cyBvZiBhIHN1YnByb2plY3QgdXNlIGBcIi5cImAuXG4gICAqL1xuICBzdGF0aWMgZXZlcnlDb21taXQocGF0aD86IHN0cmluZykge1xuICAgIGNvbnN0IGNtZCA9IGBnaXQgbG9nIC0tb25lbGluZSAkTEFURVNUX1RBRy4uSEVBRGA7XG4gICAgcmV0dXJuIG5ldyBSZWxlYXNhYmxlQ29tbWl0cyh3aXRoUGF0aChjbWQsIHBhdGgpKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBMaW1pdCBjb21taXRzIGJ5IHRoZWlyIGNvbnZlbnRpb25hbCBjb21taXQgdHlwZVxuICAgKlxuICAgKiBUaGlzIHdpbGwgb25seSByZWxlYXNlIGNvbW1pdCB0aGF0IG1hdGNoIG9uZSBvZiB0aGUgcHJvdmlkZWQgdHlwZXMuXG4gICAqIENvbW1pdHMgYXJlIHJlcXVpcmVkIHRvIGZvbGxvdyB0aGUgY29udmVudGlvbmFsIGNvbW1pdCBzcGVjIGFuZCB3aWxsIGJlIGlnbm9yZWQgb3RoZXJ3aXNlLlxuICAgKlxuICAgKiBAcGFyYW0gdHlwZXMgTGlzdCBvZiBjb252ZW50aW9uYWwgY29tbWl0IHR5cGVzIHRoYXQgc2hvdWxkIGJlIHJlbGVhc2VkXG4gICAqIEBwYXJhbSBwYXRoIENvbnNpZGVyIG9ubHkgY29tbWl0cyB0aGF0IGFyZSBlbm91Z2ggdG8gZXhwbGFpbiBob3cgdGhlIGZpbGVzIHRoYXQgbWF0Y2ggdGhlIHNwZWNpZmllZCBwYXRocyBjYW1lIHRvIGJlLlxuICAgKiBUaGlzIHBhdGggaXMgcmVsYXRpdmUgdG8gdGhlIGN1cnJlbnQgd29ya2luZyBkaXIgb2YgdGhlIGBidW1wYCB0YXNrLCBpLmUuIHRvIG9ubHkgY29uc2lkZXIgY29tbWl0cyBvZiBhIHN1YnByb2plY3QgdXNlIGBcIi5cImAuXG4gICAqL1xuICBzdGF0aWMgb2ZUeXBlKHR5cGVzOiBzdHJpbmdbXSwgcGF0aD86IHN0cmluZykge1xuICAgIGNvbnN0IGFsbG93ZWRUeXBlcyA9IHR5cGVzLmpvaW4oXCJ8XCIpO1xuXG4gICAgLy8gQHNlZTogaHR0cHM6Ly9naXRodWIuY29tL2NvbnZlbnRpb25hbC1jb21taXRzL3BhcnNlci9ibG9iL2VlZWZiOTYxZWJmNWI5ZGZlYTBmZWE4YjA2ZjhhZDM0YTFlNDM5YjkvbGliL3BhcnNlci5qc1xuICAgIC8vIC1FIHJlcXVpcmVzIHRoaXMgdG8gYmUgUE9TSVggRXh0ZW5kZWQgUmVndWxhciBFeHByZXNzaW9uLCB3aGljaCBjb21lcyB3aXRoIGNlcnRhaW4gbGltaXRhdGlvbnNcbiAgICAvLyBzZWUgaHR0cHM6Ly9lbi53aWtpYm9va3Mub3JnL3dpa2kvUmVndWxhcl9FeHByZXNzaW9ucy9QT1NJWC1FeHRlbmRlZF9SZWd1bGFyX0V4cHJlc3Npb25zIGZvciBkZXRhaWxzXG4gICAgY29uc3QgY21kID0gYGdpdCBsb2cgLS1uby1tZXJnZXMgLS1vbmVsaW5lICRMQVRFU1RfVEFHLi5IRUFEIC1FIC0tZ3JlcCAnXigke2FsbG93ZWRUeXBlc30pezF9KFxcXFwoW14oKVs6c3BhY2U6XV0rXFxcXCkpPyghKT86W1s6Ymxhbms6XV0rLisnYDtcblxuICAgIHJldHVybiBuZXcgUmVsZWFzYWJsZUNvbW1pdHMod2l0aFBhdGgoY21kLCBwYXRoKSk7XG4gIH1cblxuICAvKipcbiAgICogUmVsZWFzZSBvbmx5IGZlYXR1cmVzIGFuZCBmaXhlc1xuICAgKlxuICAgKiBTaG9ydGhhbmQgZm9yIGBSZWxlYXNhYmxlQ29tbWl0cy5vbmx5T2ZUeXBlKFsnZmVhdCcsICdmaXgnXSlgLlxuICAgKlxuICAgKiBAcGFyYW0gcGF0aCBDb25zaWRlciBvbmx5IGNvbW1pdHMgdGhhdCBhcmUgZW5vdWdoIHRvIGV4cGxhaW4gaG93IHRoZSBmaWxlcyB0aGF0IG1hdGNoIHRoZSBzcGVjaWZpZWQgcGF0aHMgY2FtZSB0byBiZS5cbiAgICogVGhpcyBwYXRoIGlzIHJlbGF0aXZlIHRvIHRoZSBjdXJyZW50IHdvcmtpbmcgZGlyIG9mIHRoZSBgYnVtcGAgdGFzaywgaS5lLiB0byBvbmx5IGNvbnNpZGVyIGNvbW1pdHMgb2YgYSBzdWJwcm9qZWN0IHVzZSBgXCIuXCJgLlxuICAgKi9cbiAgc3RhdGljIGZlYXR1cmVzQW5kRml4ZXMocGF0aD86IHN0cmluZykge1xuICAgIHJldHVybiBSZWxlYXNhYmxlQ29tbWl0cy5vZlR5cGUoW1wiZmVhdFwiLCBcImZpeFwiXSwgcGF0aCk7XG4gIH1cblxuICAvKipcbiAgICogVXNlIGFuIGFyYml0cmFyeSBzaGVsbCBjb21tYW5kIHRvIGZpbmQgcmVsZWFzYWJsZSBjb21taXRzIHNpbmNlIHRoZSBsYXRlc3QgdGFnLlxuICAgKlxuICAgKiBBIG5ldyByZWxlYXNlIHdpbGwgYmUgaW5pdGlhdGVkLCBpZiB0aGUgbnVtYmVyIG9mIHJldHVybmVkIGNvbW1pdHMgaXMgZ3JlYXRlciB0aGFuIHplcm8uXG4gICAqIE11c3QgcmV0dXJuIGEgbmV3bGluZSBzZXBhcmF0ZSBsaXN0IG9mIGNvbW1pdHMgdGhhdCBzaG91bGQgY29uc2lkZXJlZCByZWxlYXNhYmxlLlxuICAgKiBgJExBVEVTVF9UQUdgIGlzIGF2YWlsYWJsZSBhcyBhbiBlbnZpcm9ubWVudCB2YXJpYWJsZSAoc2V0IHRvIHRoZSBhY3R1YWwgbGF0ZXN0IHRhZyBmb3IgdGhlIGdpdmVuIHByZWZpeCkuXG4gICAqXG4gICAqIEBleGFtcGxlIFwiZ2l0IGxvZyAtLW9uZWxpbmUgJExBVEVTVF9UQUcuLkhFQUQgLS0gLlwiXG4gICAqL1xuICBzdGF0aWMgZXhlYyhjbWQ6IHN0cmluZykge1xuICAgIHJldHVybiBuZXcgUmVsZWFzYWJsZUNvbW1pdHMoY21kKTtcbiAgfVxuXG4gIHByaXZhdGUgY29uc3RydWN0b3IocHVibGljIGNtZDogc3RyaW5nKSB7fVxufVxuXG4vKipcbiAqIEFwcGVuZCBhIHBhdGggYXJndW1lbnQgdG8gYSBnaXQgY29tbWFuZCBpZiBvbmUgaXMgcHJvdmlkZWRcbiAqL1xuZnVuY3Rpb24gd2l0aFBhdGgoY21kOiBzdHJpbmcsIHBhdGg/OiBzdHJpbmcpOiBzdHJpbmcge1xuICBpZiAocGF0aCAhPT0gdW5kZWZpbmVkKSB7XG4gICAgcmV0dXJuIGAke2NtZH0gLS0gJHtwYXRofWA7XG4gIH1cblxuICByZXR1cm4gY21kO1xufVxuIl19