projen
Version:
CDK for software projects
531 lines • 64.4 kB
JavaScript
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.Project = void 0;
const JSII_RTTI_SYMBOL_1 = Symbol.for("jsii.rtti");
const fs_1 = require("fs");
const os_1 = require("os");
const path = __importStar(require("path"));
const constructs_1 = require("constructs");
const glob = __importStar(require("fast-glob"));
const cleanup_1 = require("./cleanup");
const common_1 = require("./common");
const dependencies_1 = require("./dependencies");
const file_1 = require("./file");
const gitattributes_1 = require("./gitattributes");
const ignore_file_1 = require("./ignore-file");
const render_options_1 = require("./javascript/render-options");
const json_1 = require("./json");
const logger_1 = require("./logger");
const object_file_1 = require("./object-file");
const project_build_1 = require("./project-build");
const project_tree_1 = require("./project-tree");
const projenrc_json_1 = require("./projenrc-json");
const renovatebot_1 = require("./renovatebot");
const tasks_1 = require("./tasks");
const util_1 = require("./util");
const constructs_2 = require("./util/constructs");
/**
* The default output directory for a project if none is specified.
*/
const DEFAULT_OUTDIR = ".";
/**
* Base project
*/
class Project extends constructs_1.Construct {
static [JSII_RTTI_SYMBOL_1] = { fqn: "projen.Project", version: "0.103.12" };
/**
* The name of the default task (the task executed when `projen` is run without arguments). Normally
* this task should synthesize the project files.
*/
static DEFAULT_TASK = common_1.DEFAULT_TASK;
/**
* Test whether the given construct is a project.
*/
static isProject(x) {
return (0, constructs_2.isProject)(x);
}
/**
* Find the closest ancestor project for given construct.
* When given a project, this it the project itself.
*
* @throws when no project is found in the path to the root
*/
static of(construct) {
return (0, constructs_2.findClosestProject)(construct, this.name);
}
/**
* Project name.
*/
name;
/**
* .gitignore
*/
gitignore;
/**
* The .gitattributes file for this repository.
*/
gitattributes;
/**
* A parent project. If undefined, this is the root project.
*/
parent;
/**
* Absolute output directory of this project.
*/
outdir;
/**
* Project tasks.
*/
tasks;
/**
* Project dependencies.
*/
deps;
/**
* Logging utilities.
*/
logger;
/**
* The options used when this project is bootstrapped via `projen new`. It
* includes the original set of options passed to the CLI and also the JSII
* FQN of the project type.
*
* @deprecated use the `initProject` argument passed to `Component.projectCreation()` instead.
*/
get initProject() {
return this._initProject;
}
/**
* The command to use in order to run the projen CLI.
*/
get projenCommand() {
return this._projenCommand ?? "npx projen";
}
/**
* This is the "default" task, the one that executes "projen". Undefined if
* the project is being ejected.
*/
defaultTask;
/**
* This task ejects the project from projen. This is undefined if the project
* it self is being ejected.
*
* See docs for more information.
*/
ejectTask;
/**
* Manages the build process of the project.
*/
projectBuild;
/**
* Whether to commit the managed files by default.
*/
commitGenerated;
_excludeFromCleanup;
_ejected;
_initProject;
_projenCommand;
constructor(options) {
const outdir = determineOutdir(options.parent, options.outdir);
const autoId = `${new.target.name}#${options.name}@${path.normalize(options.outdir ?? "<root>")}`;
if (options.parent?.subprojects.find((p) => p.outdir === outdir)) {
throw new Error(`There is already a subproject with "outdir": ${outdir}`);
}
super(options.parent, autoId);
(0, constructs_2.tagAsProject)(this);
this.node.addMetadata("type", "project");
this.node.addMetadata("construct", new.target.name);
this.node.addMetadata("projen.version", common_1.PROJEN_VERSION);
this._initProject = (0, render_options_1.resolveInitProject)(options);
this.name = options.name;
this.parent = options.parent;
this._excludeFromCleanup = [];
this._ejected = (0, util_1.isTruthy)(process.env.PROJEN_EJECTING);
this._projenCommand = options.projenCommand;
if (this.ejected) {
// `scripts/run-task.cjs` relies on its `#!/usr/bin/env node` shebang and
// the executable bit to run directly - neither exists on Windows, where
// there is no shebang support and npm invokes package.json scripts
// through cmd.exe. Prefixing with `node` resolves the script explicitly
// and works identically on every platform.
this._projenCommand = "node scripts/run-task.cjs";
}
this.outdir = outdir;
// ------------------------------------------------------------------------
this.gitattributes = new gitattributes_1.GitAttributesFile(this, {
endOfLine: options.gitOptions?.endOfLine,
});
this.annotateGenerated("/.projen/**"); // contents of the .projen/ directory are generated by projen
this.annotateGenerated(`/${this.gitattributes.path}`); // the .gitattributes file itself is generated
if (options.gitOptions?.lfsPatterns) {
for (const pattern of options.gitOptions.lfsPatterns) {
this.gitattributes.addAttributes(pattern, "filter=lfs", "diff=lfs", "merge=lfs", "-text");
}
}
this.gitignore = new ignore_file_1.IgnoreFile(this, ".gitignore", options.gitIgnoreOptions);
this.gitignore.exclude("node_modules/"); // created by running `npx projen`
this.gitignore.include(`/${this.gitattributes.path}`);
// oh no: tasks depends on gitignore so it has to be initialized after
// smells like dep injection but god forbid.
this.tasks = new tasks_1.Tasks(this);
if (!this.ejected) {
this.defaultTask = this.tasks.addTask(Project.DEFAULT_TASK, {
description: "Synthesize project files",
});
// Subtasks should call the root task for synth
if (this.parent) {
const cwd = path.relative(this.outdir, this.root.outdir);
const normalizedCwd = (0, util_1.normalizePersistedPath)(cwd);
this.defaultTask.exec(`${this.projenCommand} ${Project.DEFAULT_TASK}`, {
cwd: normalizedCwd,
});
}
if (!this.parent) {
this.ejectTask = this.tasks.addTask("eject", {
description: "Remove projen from the project",
env: {
PROJEN_EJECTING: "true",
},
});
this.ejectTask.spawn(this.defaultTask);
}
}
this.projectBuild = new project_build_1.ProjectBuild(this);
this.deps = new dependencies_1.Dependencies(this);
this.logger = new logger_1.Logger(this, options.logging);
const projenrcJson = options.projenrcJson ?? false;
if (!this.parent && projenrcJson) {
new projenrc_json_1.ProjenrcJson(this, options.projenrcJsonOptions);
}
if (options.renovatebot) {
new renovatebot_1.Renovatebot(this, options.renovatebotOptions);
}
if (options.projectTree) {
new project_tree_1.ProjectTree(this);
}
this.commitGenerated = options.commitGenerated ?? true;
if (!this.ejected) {
new json_1.JsonFile(this, cleanup_1.FILE_MANIFEST, {
omitEmpty: true,
obj: () => ({
// replace `\` with `/` to ensure paths match across platforms
files: this.files
.filter((f) => f.readonly)
.map((f) => (0, util_1.normalizePersistedPath)(f.path)),
}),
// This file is used by projen to track the generated files, so must be committed.
committed: true,
});
}
}
/**
* The root project.
*/
get root() {
return (0, constructs_2.isProject)(this.node.root) ? this.node.root : this;
}
/**
* Returns all the components within this project.
*/
get components() {
return this.node
.findAll()
.filter((c) => (0, constructs_2.isComponent)(c) && c.project.node.path === this.node.path);
}
/**
* Returns all the subprojects within this project.
*/
get subprojects() {
return this.node.children.filter(constructs_2.isProject);
}
/**
* All files in this project.
*/
get files() {
return this.components
.filter(isFile)
.sort((f1, f2) => f1.path.localeCompare(f2.path));
}
/**
* Adds a new task to this project. This will fail if the project already has
* a task with this name.
*
* @param name The task name to add
* @param props Task properties
*/
addTask(name, props = {}) {
return this.tasks.addTask(name, props);
}
/**
* Removes a task from a project.
*
* @param name The name of the task to remove.
*
* @returns The `Task` that was removed, otherwise `undefined`.
*/
removeTask(name) {
return this.tasks.removeTask(name);
}
get buildTask() {
return this.projectBuild.buildTask;
}
get compileTask() {
return this.projectBuild.compileTask;
}
get testTask() {
return this.projectBuild.testTask;
}
get preCompileTask() {
return this.projectBuild.preCompileTask;
}
get postCompileTask() {
return this.projectBuild.postCompileTask;
}
get packageTask() {
return this.projectBuild.packageTask;
}
/**
* Finds a file at the specified relative path within this project and all
* its subprojects.
*
* @param filePath The file path. If this path is relative, it will be resolved
* from the root of _this_ project.
* @returns a `FileBase` or undefined if there is no file in that path
*/
tryFindFile(filePath) {
const absolute = path.isAbsolute(filePath)
? filePath
: path.resolve(this.outdir, filePath);
const candidate = this.node
.findAll()
.find((c) => (0, constructs_2.isComponent)(c) && isFile(c) && c.absolutePath === absolute);
return candidate;
}
/**
* Finds an object file (like JsonFile, YamlFile, etc.) by name.
* @param filePath The file path.
*/
tryFindObjectFile(filePath) {
const file = this.tryFindFile(filePath);
if (!file) {
return undefined;
}
if (!(file instanceof object_file_1.ObjectFile)) {
throw new Error(`found file ${filePath} but it is not a ObjectFile. got: ${file.constructor.name}`);
}
return file;
}
/**
* Finds a file at the specified relative path within this project and removes
* it.
*
* @param filePath The file path. If this path is relative, it will be
* resolved from the root of _this_ project.
* @returns a `FileBase` if the file was found and removed, or undefined if
* the file was not found.
*/
tryRemoveFile(filePath) {
const candidate = this.tryFindFile(filePath);
if (candidate) {
candidate.node.scope?.node.tryRemoveChild(candidate.node.id);
return candidate;
}
return undefined;
}
/**
* Exclude the matching files from pre-synth cleanup. Can be used when, for example, some
* source files include the projen marker and we don't want them to be erased during synth.
*
* @param globs The glob patterns to match
*/
addExcludeFromCleanup(...globs) {
this._excludeFromCleanup.push(...globs);
}
/**
* Returns the shell command to execute in order to run a task.
*
* By default, this is `npx projen@<version> <task>`
*
* @param task The task for which the command is required
*/
runTaskCommand(task) {
const pj = this._projenCommand ?? `npx projen@${common_1.PROJEN_VERSION}`;
return `${pj} ${task.name}`;
}
/**
* Exclude these files from the bundled package. Implemented by project types based on the
* packaging mechanism. For example, `NodeProject` delegates this to `.npmignore`.
*
* @param _pattern The glob pattern to exclude
*/
addPackageIgnore(_pattern) {
// nothing to do at the abstract level
}
/**
* Adds a .gitignore pattern.
* @param pattern The glob pattern to ignore.
*/
addGitIgnore(pattern) {
this.gitignore.addPatterns(pattern);
}
/**
* Consider a set of files as "generated". This method is implemented by
* derived classes and used for example, to add git attributes to tell GitHub
* that certain files are generated.
*
* @param _glob the glob pattern to match (could be a file path).
*/
annotateGenerated(_glob) {
// nothing to do at the abstract level
}
/**
* Synthesize all project files into `outdir`.
*
* 1. Call "this.preSynthesize()"
* 2. Delete all generated files
* 3. Synthesize all subprojects
* 4. Synthesize all components of this project
* 5. Call "projectCreation()" for all components, only if the project is being created for the first time
* 6. Call "postSynthesize()" for all components of this project
* 7. Call "this.postSynthesize()"
* 8. Call "postProjectCreation()" for all components, only if the project is being created for the first time
*/
synth() {
if (this._initProject?.synth === false) {
// user request to not run full synth, instead we only run projectCreation hooks
for (const comp of this.components) {
comp.projectCreation(this._initProject);
}
return;
}
const outdir = this.outdir;
this.logger.debug("Synthesizing project...");
this.preSynthesize();
for (const comp of this.components) {
comp.preSynthesize();
}
// we exclude all subproject directories to ensure that when subproject.synth()
// gets called below after cleanup(), subproject generated files are left intact
for (const subproject of this.subprojects) {
this.addExcludeFromCleanup(subproject.outdir + "/**");
}
// delete orphaned files before we start synthesizing new ones
(0, cleanup_1.cleanup)(outdir, this.files.map((f) => (0, util_1.normalizePersistedPath)(f.path)), this._excludeFromCleanup);
for (const subproject of this.subprojects) {
subproject.synth();
}
for (const comp of this.components) {
comp.synthesize();
}
if (this._initProject) {
for (const comp of this.components) {
comp.projectCreation(this._initProject);
}
}
if (!(0, util_1.isTruthy)(process.env.PROJEN_DISABLE_POST)) {
for (const comp of this.components) {
comp.postSynthesize();
}
// project-level hook
this.postSynthesize();
if (this._initProject) {
for (const comp of this.components) {
comp.postProjectCreation(this._initProject);
}
}
}
if (this.ejected) {
this.logger.debug("Ejecting project...");
// Backup projenrc files
const files = glob.sync(".projenrc.*", {
cwd: this.outdir,
dot: true,
onlyFiles: true,
followSymbolicLinks: false,
absolute: true,
});
for (const file of files) {
(0, fs_1.renameSync)(file, `${file}.bak`);
}
}
this.logger.debug("Synthesis complete");
}
/**
* Whether or not the project is being ejected.
*/
get ejected() {
return this._ejected;
}
/**
* Called before all components are synthesized.
*/
preSynthesize() { }
/**
* Called after all components are synthesized. Order is *not* guaranteed.
*/
postSynthesize() { }
}
exports.Project = Project;
/**
* Resolves the project's output directory.
*/
function determineOutdir(parent, outdirOption) {
if (parent && outdirOption && path.isAbsolute(outdirOption)) {
throw new Error('"outdir" must be a relative path');
}
// if this is a subproject, it is relative to the parent
if (parent) {
if (!outdirOption) {
throw new Error('"outdir" must be specified for subprojects');
}
return path.resolve(parent.outdir, outdirOption);
}
// if this is running inside a test and outdir is not explicitly set
// use a temp directory (unless cwd is already under tmp)
if (common_1.IS_TEST_RUN && !outdirOption) {
const realCwd = (0, fs_1.realpathSync)(process.cwd());
const realTmp = (0, fs_1.realpathSync)((0, os_1.tmpdir)());
if (realCwd.startsWith(realTmp)) {
return path.resolve(realCwd, outdirOption ?? DEFAULT_OUTDIR);
}
return (0, fs_1.mkdtempSync)(path.join((0, os_1.tmpdir)(), "projen."));
}
return path.resolve(outdirOption ?? DEFAULT_OUTDIR);
}
function isFile(c) {
return c instanceof file_1.FileBase;
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicHJvamVjdC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9wcm9qZWN0LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFBQSwyQkFBMkQ7QUFDM0QsMkJBQTRCO0FBQzVCLDJDQUE2QjtBQUU3QiwyQ0FBdUM7QUFDdkMsZ0RBQWtDO0FBQ2xDLHVDQUFtRDtBQUNuRCxxQ0FBcUU7QUFFckUsaURBQThDO0FBQzlDLGlDQUFrQztBQUVsQyxtREFBb0Q7QUFFcEQsK0NBQTJDO0FBRTNDLGdFQUFpRTtBQUNqRSxpQ0FBa0M7QUFFbEMscUNBQWtDO0FBQ2xDLCtDQUEyQztBQUUzQyxtREFBK0Q7QUFDL0QsaURBQTZDO0FBRTdDLG1EQUErQztBQUUvQywrQ0FBNEM7QUFFNUMsbUNBQWdDO0FBQ2hDLGlDQUEwRDtBQUMxRCxrREFLMkI7QUFFM0I7O0dBRUc7QUFDSCxNQUFNLGNBQWMsR0FBRyxHQUFHLENBQUM7QUFrSTNCOztHQUVHO0FBQ0gsTUFBYSxPQUFRLFNBQVEsc0JBQVM7O0lBQ3BDOzs7T0FHRztJQUNJLE1BQU0sQ0FBVSxZQUFZLEdBQUcscUJBQVksQ0FBQztJQUVuRDs7T0FFRztJQUNJLE1BQU0sQ0FBQyxTQUFTLENBQUMsQ0FBTTtRQUM1QixPQUFPLElBQUEsc0JBQVMsRUFBQyxDQUFDLENBQUMsQ0FBQztJQUN0QixDQUFDO0lBRUQ7Ozs7O09BS0c7SUFDSSxNQUFNLENBQUMsRUFBRSxDQUFDLFNBQXFCO1FBQ3BDLE9BQU8sSUFBQSwrQkFBa0IsRUFBQyxTQUFTLEVBQUUsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDO0lBQ2xELENBQUM7SUFFRDs7T0FFRztJQUNhLElBQUksQ0FBUztJQUU3Qjs7T0FFRztJQUNhLFNBQVMsQ0FBYTtJQUV0Qzs7T0FFRztJQUNhLGFBQWEsQ0FBb0I7SUFFakQ7O09BRUc7SUFDYSxNQUFNLENBQVc7SUFFakM7O09BRUc7SUFDYSxNQUFN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QUM7SUFFRCxPQUFPLElBQUksQ0FBQyxPQUFPLENBQUMsWUFBWSxJQUFJLGNBQWMsQ0FBQyxDQUFDO0FBQ3RELENBQUM7QUFFRCxTQUFTLE1BQU0sQ0FBQyxDQUFZO0lBQzFCLE9BQU8sQ0FBQyxZQUFZLGVBQVEsQ0FBQztBQUMvQixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgbWtkdGVtcFN5bmMsIHJlYWxwYXRoU3luYywgcmVuYW1lU3luYyB9IGZyb20gXCJmc1wiO1xuaW1wb3J0IHsgdG1wZGlyIH0gZnJvbSBcIm9zXCI7XG5pbXBvcnQgKiBhcyBwYXRoIGZyb20gXCJwYXRoXCI7XG5pbXBvcnQgdHlwZSB7IElDb25zdHJ1Y3QgfSBmcm9tIFwiY29uc3RydWN0c1wiO1xuaW1wb3J0IHsgQ29uc3RydWN0IH0gZnJvbSBcImNvbnN0cnVjdHNcIjtcbmltcG9ydCAqIGFzIGdsb2IgZnJvbSBcImZhc3QtZ2xvYlwiO1xuaW1wb3J0IHsgY2xlYW51cCwgRklMRV9NQU5JRkVTVCB9IGZyb20gXCIuL2NsZWFudXBcIjtcbmltcG9ydCB7IERFRkFVTFRfVEFTSywgSVNfVEVTVF9SVU4sIFBST0pFTl9WRVJTSU9OIH0gZnJvbSBcIi4vY29tbW9uXCI7XG5pbXBvcnQgdHlwZSB7IENvbXBvbmVudCB9IGZyb20gXCIuL2NvbXBvbmVudFwiO1xuaW1wb3J0IHsgRGVwZW5kZW5jaWVzIH0gZnJvbSBcIi4vZGVwZW5kZW5jaWVzXCI7XG5pbXBvcnQgeyBGaWxlQmFzZSB9IGZyb20gXCIuL2ZpbGVcIjtcbmltcG9ydCB0eXBlIHsgRW5kT2ZMaW5lIH0gZnJvbSBcIi4vZ2l0YXR0cmlidXRlc1wiO1xuaW1wb3J0IHsgR2l0QXR0cmlidXRlc0ZpbGUgfSBmcm9tIFwiLi9naXRhdHRyaWJ1dGVzXCI7XG5pbXBvcnQgdHlwZSB7IElnbm9yZUZpbGVPcHRpb25zIH0gZnJvbSBcIi4vaWdub3JlLWZpbGVcIjtcbmltcG9ydCB7IElnbm9yZUZpbGUgfSBmcm9tIFwiLi9pZ25vcmUtZmlsZVwiO1xuaW1wb3J0IHR5cGUgKiBhcyBpbnZlbnRvcnkgZnJvbSBcIi4vaW52ZW50b3J5XCI7XG5pbXBvcnQgeyByZXNvbHZlSW5pdFByb2plY3QgfSBmcm9tIFwiLi9qYXZhc2NyaXB0L3JlbmRlci1vcHRpb25zXCI7XG5pbXBvcnQgeyBKc29uRmlsZSB9IGZyb20gXCIuL2pzb25cIjtcbmltcG9ydCB0eXBlIHsgTG9nZ2VyT3B0aW9ucyB9IGZyb20gXCIuL2xvZ2dlclwiO1xuaW1wb3J0IHsgTG9nZ2VyIH0gZnJvbSBcIi4vbG9nZ2VyXCI7XG5pbXBvcnQgeyBPYmplY3RGaWxlIH0gZnJvbSBcIi4vb2JqZWN0LWZpbGVcIjtcbmltcG9ydCB0eXBlIHsgSW5pdFByb2plY3RPcHRpb25IaW50cyB9IGZyb20gXCIuL29wdGlvbi1oaW50c1wiO1xuaW1wb3J0IHsgUHJvamVjdEJ1aWxkIGFzIFByb2plY3RCdWlsZCB9IGZyb20gXCIuL3Byb2plY3QtYnVpbGRcIjtcbmltcG9ydCB7IFByb2plY3RUcmVlIH0gZnJvbSBcIi4vcHJvamVjdC10cmVlXCI7XG5pbXBvcnQgdHlwZSB7IFByb2plbnJjSnNvbk9wdGlvbnMgfSBmcm9tIFwiLi9wcm9qZW5yYy1qc29uXCI7XG5pbXBvcnQgeyBQcm9qZW5yY0pzb24gfSBmcm9tIFwiLi9wcm9qZW5yYy1qc29uXCI7XG5pbXBvcnQgdHlwZSB7IFJlbm92YXRlYm90T3B0aW9ucyB9IGZyb20gXCIuL3Jlbm92YXRlYm90XCI7XG5pbXBvcnQgeyBSZW5vdmF0ZWJvdCB9IGZyb20gXCIuL3Jlbm92YXRlYm90XCI7XG5pbXBvcnQgdHlwZSB7IFRhc2ssIFRhc2tPcHRpb25zIH0gZnJvbSBcIi4vdGFza1wiO1xuaW1wb3J0IHsgVGFza3MgfSBmcm9tIFwiLi90YXNrc1wiO1xuaW1wb3J0IHsgaXNUcnV0aHksIG5vcm1hbGl6ZVBlcnNpc3RlZFBhdGggfSBmcm9tIFwiLi91dGlsXCI7XG5pbXBvcnQge1xuICBpc1Byb2plY3QsXG4gIGZpbmRDbG9zZXN0UHJvamVjdCxcbiAgdGFnQXNQcm9qZWN0LFxuICBpc0NvbXBvbmVudCxcbn0gZnJvbSBcIi4vdXRpbC9jb25zdHJ1Y3RzXCI7XG5cbi8qKlxuICogVGhlIGRlZmF1bHQgb3V0cHV0IGRpcmVjdG9yeSBmb3IgYSBwcm9qZWN0IGlmIG5vbmUgaXMgc3BlY2lmaWVkLlxuICovXG5jb25zdCBERUZBVUxUX09VVERJUiA9IFwiLlwiO1xuXG4vKipcbiAqIE9wdGlvbnMgZm9yIGBQcm9qZWN0YC5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBQcm9qZWN0T3B0aW9ucyB7XG4gIC8qKlxuICAgKiBUaGlzIGlzIHRoZSBuYW1lIG9mIHlvdXIgcHJvamVjdC5cbiAgICpcbiAgICogQGRlZmF1bHQgJEJBU0VESVJcbiAgICogQGZlYXR1cmVkXG4gICAqL1xuICByZWFkb25seSBuYW1lOiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIFRoZSBwYXJlbnQgcHJvamVjdCwgaWYgdGhpcyBwcm9qZWN0IGlzIHBhcnQgb2YgYSBiaWdnZXIgcHJvamVjdC5cbiAgICovXG4gIHJlYWRvbmx5IHBhcmVudD86IFByb2plY3Q7XG5cbiAgLyoqXG4gICAqIFRoZSByb290IGRpcmVjdG9yeSBvZiB0aGUgcHJvamVjdC5cbiAgICpcbiAgICogUmVsYXRpdmUgdG8gdGhpcyBkaXJlY3RvcnksIGFsbCBmaWxlcyBhcmUgc3ludGhlc2l6ZWQuXG4gICAqXG4gICAqIElmIHRoaXMgcHJvamVjdCBoYXMgYSBwYXJlbnQsIHRoaXMgZGlyZWN0b3J5IGlzIHJlbGF0aXZlIHRvIHRoZSBwYXJlbnRcbiAgICogZGlyZWN0b3J5IGFuZCBpdCBjYW5ub3QgYmUgdGhlIHNhbWUgYXMgdGhlIHBhcmVudCBvciBhbnkgb2YgaXQncyBvdGhlclxuICAgKiBzdWJwcm9qZWN0cy5cbiAgICpcbiAgICogQGRlZmF1bHQgXCIuXCJcbiAgICovXG4gIHJlYWRvbmx5IG91dGRpcj86IHN0cmluZztcblxuICAvKipcbiAgICogQ29uZmlndXJlIGxvZ2dpbmcgb3B0aW9ucyBzdWNoIGFzIHZlcmJvc2l0eS5cbiAgICogQGRlZmF1bHQge31cbiAgICovXG4gIHJlYWRvbmx5IGxvZ2dpbmc/OiBMb2dnZXJPcHRpb25zO1xuXG4gIC8qKlxuICAgKiBHZW5lcmF0ZSAob25jZSkgLnByb2plbnJjLmpzb24gKGluIEpTT04pLiBTZXQgdG8gYGZhbHNlYCBpbiBvcmRlciB0byBkaXNhYmxlXG4gICAqIC5wcm9qZW5yYy5qc29uIGdlbmVyYXRpb24uXG4gICAqXG4gICAqIEBkZWZhdWx0IGZhbHNlXG4gICAqL1xuICByZWFkb25seSBwcm9qZW5yY0pzb24/OiBib29sZWFuO1xuXG4gIC8qKlxuICAgKiBPcHRpb25zIGZvciAucHJvamVucmMuanNvblxuICAgKiBAZGVmYXVsdCAtIGRlZmF1bHQgb3B0aW9uc1xuICAgKi9cbiAgcmVhZG9ubHkgcHJvamVucmNKc29uT3B0aW9ucz86IFByb2plbnJjSnNvbk9wdGlvbnM7XG5cbiAgLyoqXG4gICAqIFRoZSBzaGVsbCBjb21tYW5kIHRvIHVzZSBpbiBvcmRlciB0byBydW4gdGhlIHByb2plbiBDTEkuXG4gICAqXG4gICAqIEluc2VydGVkIHZlcmJhdGltIGludG8gdGFzayBzdGVwcywgd29ya2Zsb3dzIGFuZCBJREUgY29uZmlndXJhdGlvbiwgYW5kIHJ1blxuICAgKiBieSBlYWNoIG9mIHRoZWlyIHNoZWxscyAtIGxvY2FsbHksIGluIENJIGFuZCBpbiBkZXYgY29udGFpbmVycy4gS2VlcCBpdCBhXG4gICAqIHBsYWluIHVucXVvdGVkIGNvbW1hbmQsIHNpbmNlIHNoZWxsIHN5bnRheCBpbiBpdCBleGVjdXRlcyBpbiBhbGwgb2YgdGhlbS5cbiAgICpcbiAgICogQ2FuIGJlIHVzZWQgdG8gY3VzdG9taXplIGluIHNwZWNpYWwgZW52aXJvbm1lbnRzLlxuICAgKlxuICAgKiBAZGVmYXVsdCBcIm5weCBwcm9qZW5cIlxuICAgKi9cbiAgcmVhZG9ubHkgcHJvamVuQ29tbWFuZD86IHN0cmluZztcblxuICAvKipcbiAgICogVXNlIHJlbm92YXRlYm90IHRvIGhhbmRsZSBkZXBlbmRlbmN5IHVwZ3JhZGVzLlxuICAgKlxuICAgKiBAZGVmYXVsdCBmYWxzZVxuICAgKi9cbiAgcmVhZG9ubHkgcmVub3ZhdGVib3Q/OiBib29sZWFuO1xuXG4gIC8qKlxuICAgKiBPcHRpb25zIGZvciByZW5vdmF0ZWJvdC5cbiAgICpcbiAgICogQGRlZmF1bHQgLSBkZWZhdWx0IG9wdGlvbnNcbiAgICovXG4gIHJlYWRvbmx5IHJlbm92YXRlYm90T3B0aW9ucz86IFJlbm92YXRlYm90T3B0aW9ucztcblxuICAvKipcbiAgICogV2hldGhlciB0byBjb21taXQgdGhlIG1hbmFnZWQgZmlsZXMgYnkgZGVmYXVsdC5cbiAgICpcbiAgICogQGRlZmF1bHQgdHJ1ZVxuICAgKi9cbiAgcmVhZG9ubHkgY29tbWl0R2VuZXJhdGVkPzogYm9vbGVhbjtcblxuICAvKipcbiAgICogQ29uZmlndXJhdGlvbiBvcHRpb25zIGZvciBnaXRcbiAgICovXG4gIHJlYWRvbmx5IGdpdE9wdGlvbnM/OiBHaXRPcHRpb25zO1xuXG4gIC8qKlxuICAgKiBDb25maWd1cmF0aW9uIG9wdGlvbnMgZm9yIC5naXRpZ25vcmUgZmlsZVxuICAgKi9cbiAgcmVhZG9ubHkgZ2l0SWdub3JlT3B0aW9ucz86IElnbm9yZUZpbGVPcHRpb25zO1xuXG4gIC8qKlxuICAgKiBHZW5lcmF0ZSBhIHByb2plY3QgdHJlZSBmaWxlIChgLnByb2plbi90cmVlLmpzb25gKSB0aGF0IHNob3dzIGFsbFxuICAgKiBjb21wb25lbnRzIGFuZCB0aGVpciByZWxhdGlvbnNoaXBzLiBVc2VmdWwgZm9yIHVuZGVyc3RhbmRpbmcgeW91clxuICAgKiBwcm9qZWN0IHN0cnVjdHVyZSBhbmQgZGVidWdnaW5nLlxuICAgKlxuICAgKiBAc3RhYmlsaXR5IGV4cGVyaW1lbnRhbFxuICAgKiBAZGVmYXVsdCBmYWxzZVxuICAgKi9cbiAgcmVhZG9ubHkgcHJvamVjdFRyZWU/OiBib29sZWFuO1xufVxuXG4vKipcbiAqIEdpdCBjb25maWd1cmF0aW9uIG9wdGlvbnNcbiAqL1xuZXhwb3J0IGludGVyZmFjZSBHaXRPcHRpb25zIHtcbiAgLyoqXG4gICAqIEZpbGUgcGF0dGVybnMgdG8gbWFyayBhcyBzdG9yZWQgaW4gR2l0IExGU1xuICAgKlxuICAgKiBAZGVmYXVsdCAtIE5vIGZpbGVzIHN0b3JlZCBpbiBMRlNcbiAgICovXG4gIHJlYWRvbmx5IGxmc1BhdHRlcm5zPzogc3RyaW5nW107XG5cbiAgLyoqXG4gICAqIFRoZSBkZWZhdWx0IGVuZCBvZiBsaW5lIGNoYXJhY3RlciBmb3IgdGV4dCBmaWxlcy5cbiAgICpcbiAgICogZW5kT2ZMaW5lIGl0J3MgdXNlZnVsIHRvIGtlZXAgdGhlIHNhbWUgZW5kIG9mIGxpbmUgYmV0d2VlbiBXaW5kb3dzIGFuZCBVbml4IG9wZXJhdGl2ZSBzeXN0ZW1zIGZvciBnaXQgY2hlY2tpbmcvY2hlY2tvdXQgb3BlcmF0aW9ucy5cbiAgICogSGVuY2UsIGl0IGNhbiBhdm9pZCBzaW1wbGUgcmVwb3NpdG9yeSBtdXRhdGlvbnMgY29uc2lzdGluZyBvbmx5IG9mIGNoYW5nZXMgaW4gdGhlIGVuZCBvZiBsaW5lIGNoYXJhY3RlcnMuXG4gICAqIEl0IHdpbGwgYmUgc2V0IGluIHRoZSBmaXJzdCBsaW5lIG9mIHRoZSAuZ2l0YXR0cmlidXRlcyBmaWxlIHRvIG1ha2UgaXQgdGhlIGZpcnN0IG1hdGNoIHdpdGggaGlnaCBwcmlvcml0eSBidXQgaXQgY2FuIGJlIG92ZXJyaWRlbiBpbiBhIGxhdGVyIGxpbmUuXG4gICAqIENhbiBiZSBkaXNhYmxlZCBieSBzZXR0aW5nOiBgZW5kT2ZMaW5lOiBFbmRPZkxpbmUuTk9ORWAuXG4gICAqXG4gICAqIEBkZWZhdWx0IEVuZE9mTGluZS5MRlxuICAgKi9cbiAgcmVhZG9ubHkgZW5kT2ZMaW5lPzogRW5kT2ZMaW5lO1xufVxuLyoqXG4gKiBCYXNlIHByb2plY3RcbiAqL1xuZXhwb3J0IGNsYXNzIFByb2plY3QgZXh0ZW5kcyBDb25zdHJ1Y3Qge1xuICAvKipcbiAgICogVGhlIG5hbWUgb2YgdGhlIGRlZmF1bHQgdGFzayAodGhlIHRhc2sgZXhlY3V0ZWQgd2hlbiBgcHJvamVuYCBpcyBydW4gd2l0aG91dCBhcmd1bWVudHMpLiBOb3JtYWxseVxuICAgKiB0aGlzIHRhc2sgc2hvdWxkIHN5bnRoZXNpemUgdGhlIHByb2plY3QgZmlsZXMuXG4gICAqL1xuICBwdWJsaWMgc3RhdGljIHJlYWRvbmx5IERFRkFVTFRfVEFTSyA9IERFRkFVTFRfVEFTSztcblxuICAvKipcbiAgICogVGVzdCB3aGV0aGVyIHRoZSBnaXZlbiBjb25zdHJ1Y3QgaXMgYSBwcm9qZWN0LlxuICAgKi9cbiAgcHVibGljIHN0YXRpYyBpc1Byb2plY3QoeDogYW55KTogeCBpcyBQcm9qZWN0IHtcbiAgICByZXR1cm4gaXNQcm9qZWN0KHgpO1xuICB9XG5cbiAgLyoqXG4gICAqIEZpbmQgdGhlIGNsb3Nlc3QgYW5jZXN0b3IgcHJvamVjdCBmb3IgZ2l2ZW4gY29uc3RydWN0LlxuICAgKiBXaGVuIGdpdmVuIGEgcHJvamVjdCwgdGhpcyBpdCB0aGUgcHJvamVjdCBpdHNlbGYuXG4gICAqXG4gICAqIEB0aHJvd3Mgd2hlbiBubyBwcm9qZWN0IGlzIGZvdW5kIGluIHRoZSBwYXRoIHRvIHRoZSByb290XG4gICAqL1xuICBwdWJsaWMgc3RhdGljIG9mKGNvbnN0cnVjdDogSUNvbnN0cnVjdCk6IFByb2plY3Qge1xuICAgIHJldHVybiBmaW5kQ2xvc2VzdFByb2plY3QoY29uc3RydWN0LCB0aGlzLm5hbWUpO1xuICB9XG5cbiAgLyoqXG4gICAqIFByb2plY3QgbmFtZS5cbiAgICovXG4gIHB1YmxpYyByZWFkb25seSBuYW1lOiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIC5naXRpZ25vcmVcbiAgICovXG4gIHB1YmxpYyByZWFkb25seSBnaXRpZ25vcmU6IElnbm9yZUZpbGU7XG5cbiAgLyoqXG4gICAqIFRoZSAuZ2l0YXR0cmlidXRlcyBmaWxlIGZvciB0aGlzIHJlcG9zaXRvcnkuXG4gICAqL1xuICBwdWJsaWMgcmVhZG9ubHkgZ2l0YXR0cmlidXRlczogR2l0QXR0cmlidXRlc0ZpbGU7XG5cbiAgLyoqXG4gICAqIEEgcGFyZW50IHByb2plY3QuIElmIHVuZGVmaW5lZCwgdGhpcyBpcyB0aGUgcm9vdCBwcm9qZWN0LlxuICAgKi9cbiAgcHVibGljIHJlYWRvbmx5IHBhcmVudD86IFByb2plY3Q7XG5cbiAgLyoqXG4gICAqIEFic29sdXRlIG91dHB1dCBkaXJlY3Rvcnkgb2YgdGhpcyBwcm9qZWN0LlxuICAgKi9cbiAgcHVibGljIHJlYWRvbmx5IG91dGRpcjogc3RyaW5nO1xuICAvKipcbiAgICogUHJvamVjdCB0YXNrcy5cbiAgICovXG4gIHB1YmxpYyByZWFkb25seSB0YXNrczogVGFza3M7XG5cbiAgLyoqXG4gICAqIFByb2plY3QgZGVwZW5kZW5jaWVzLlxuICAgKi9cbiAgcHVibGljIHJlYWRvbmx5IGRlcHM6IERlcGVuZGVuY2llcztcblxuICAvKipcbiAgICogTG9nZ2luZyB1dGlsaXRpZXMuXG4gICAqL1xuICBwdWJsaWMgcmVhZG9ubHkgbG9nZ2VyOiBMb2dnZXI7XG5cbiAgLyoqXG4gICAqIFRoZSBvcHRpb25zIHVzZWQgd2hlbiB0aGlzIHByb2plY3QgaXMgYm9vdHN0cmFwcGVkIHZpYSBgcHJvamVuIG5ld2AuIEl0XG4gICAqIGluY2x1ZGVzIHRoZSBvcmlnaW5hbCBzZXQgb2Ygb3B0aW9ucyBwYXNzZWQgdG8gdGhlIENMSSBhbmQgYWxzbyB0aGUgSlNJSVxuICAgKiBGUU4gb2YgdGhlIHByb2plY3QgdHlwZS5cbiAgICpcbiAgICogQGRlcHJlY2F0ZWQgdXNlIHRoZSBgaW5pdFByb2plY3RgIGFyZ3VtZW50IHBhc3NlZCB0byBgQ29tcG9uZW50LnByb2plY3RDcmVhdGlvbigpYCBpbnN0ZWFkLlxuICAgKi9cbiAgcHVibGljIGdldCBpbml0UHJvamVjdCgpOiBJbml0UHJvamVjdCB8IHVuZGVmaW5lZCB7XG4gICAgcmV0dXJuIHRoaXMuX2luaXRQcm9qZWN0O1xuICB9XG5cbiAgLyoqXG4gICAqIFRoZSBjb21tYW5kIHRvIHVzZSBpbiBvcmRlciB0byBydW4gdGhlIHByb2plbiBDTEkuXG4gICAqL1xuICBwdWJsaWMgZ2V0IHByb2plbkNvbW1hbmQoKTogc3RyaW5nIHtcbiAgICByZXR1cm4gdGhpcy5fcHJvamVuQ29tbWFuZCA/PyBcIm5weCBwcm9qZW5cIjtcbiAgfVxuXG4gIC8qKlxuICAgKiBUaGlzIGlzIHRoZSBcImRlZmF1bHRcIiB0YXNrLCB0aGUgb25lIHRoYXQgZXhlY3V0ZXMgXCJwcm9qZW5cIi4gVW5kZWZpbmVkIGlmXG4gICAqIHRoZSBwcm9qZWN0IGlzIGJlaW5nIGVqZWN0ZWQuXG4gICAqL1xuICBwdWJsaWMgcmVhZG9ubHkgZGVmYXVsdFRhc2s/OiBUYXNrO1xuXG4gIC8qKlxuICAgKiBUaGlzIHRhc2sgZWplY3RzIHRoZSBwcm9qZWN0IGZyb20gcHJvamVuLiBUaGlzIGlzIHVuZGVmaW5lZCBpZiB0aGUgcHJvamVjdFxuICAgKiBpdCBzZWxmIGlzIGJlaW5nIGVqZWN0ZWQuXG4gICAqXG4gICAqIFNlZSBkb2NzIGZvciBtb3JlIGluZm9ybWF0aW9uLlxuICAgKi9cbiAgcHJpdmF0ZSByZWFkb25seSBlamVjdFRhc2s/OiBUYXNrO1xuXG4gIC8qKlxuICAgKiBNYW5hZ2VzIHRoZSBidWlsZCBwcm9jZXNzIG9mIHRoZSBwcm9qZWN0LlxuICAgKi9cbiAgcHVibGljIHJlYWRvbmx5IHByb2plY3RCdWlsZDogUHJvamVjdEJ1aWxkO1xuXG4gIC8qKlxuICAgKiBXaGV0aGVyIHRvIGNvbW1pdCB0aGUgbWFuYWdlZCBmaWxlcyBieSBkZWZhdWx0LlxuICAgKi9cbiAgcHVibGljIHJlYWRvbmx5IGNvbW1pdEdlbmVyYXRlZDogYm9vbGVhbjtcblxuICBwcml2YXRlIHJlYWRvbmx5IF9leGNsdWRlRnJvbUNsZWFudXA6IHN0cmluZ1tdO1xuICBwcml2YXRlIHJlYWRvbmx5IF9lamVjdGVkOiBib29sZWFuO1xuICBwcml2YXRlIHJlYWRvbmx5IF9pbml0UHJvamVjdD86IEluaXRQcm9qZWN0O1xuICBwcml2YXRlIHJlYWRvbmx5IF9wcm9qZW5Db21tYW5kPzogc3RyaW5nO1xuXG4gIGNvbnN0cnVjdG9yKG9wdGlvbnM6IFByb2plY3RPcHRpb25zKSB7XG4gICAgY29uc3Qgb3V0ZGlyID0gZGV0ZXJtaW5lT3V0ZGlyKG9wdGlvbnMucGFyZW50LCBvcHRpb25zLm91dGRpcik7XG4gICAgY29uc3QgYXV0b0lkID0gYCR7bmV3LnRhcmdldC5uYW1lfSMke29wdGlvbnMubmFtZX1AJHtwYXRoLm5vcm1hbGl6ZShcbiAgICAgIG9wdGlvbnMub3V0ZGlyID8/IFwiPHJvb3Q+XCIsXG4gICAgKX1gO1xuXG4gICAgaWYgKG9wdGlvbnMucGFyZW50Py5zdWJwcm9qZWN0cy5maW5kKChwKSA9PiBwLm91dGRpciA9PT0gb3V0ZGlyKSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBUaGVyZSBpcyBhbHJlYWR5IGEgc3VicHJvamVjdCB3aXRoIFwib3V0ZGlyXCI6ICR7b3V0ZGlyfWApO1xuICAgIH1cblxuICAgIHN1cGVyKG9wdGlvbnMucGFyZW50IGFzIGFueSwgYXV0b0lkKTtcbiAgICB0YWdBc1Byb2plY3QodGhpcyk7XG4gICAgdGhpcy5ub2RlLmFkZE1ldGFkYXRhKFwidHlwZVwiLCBcInByb2plY3RcIik7XG4gICAgdGhpcy5ub2RlLmFkZE1ldGFkYXRhKFwiY29uc3RydWN0XCIsIG5ldy50YXJnZXQubmFtZSk7XG4gICAgdGhpcy5ub2RlLmFkZE1ldGFkYXRhKFwicHJvamVuLnZlcnNpb25cIiwgUFJPSkVOX1ZFUlNJT04pO1xuXG4gICAgdGhpcy5faW5pdFByb2plY3QgPSByZXNvbHZlSW5pdFByb2plY3Qob3B0aW9ucyk7XG5cbiAgICB0aGlzLm5hbWUgPSBvcHRpb25zLm5hbWU7XG4gICAgdGhpcy5wYXJlbnQgPSBvcHRpb25zLnBhcmVudDtcbiAgICB0aGlzLl9leGNsdWRlRnJvbUNsZWFudXAgPSBbXTtcblxuICAgIHRoaXMuX2VqZWN0ZWQgPSBpc1RydXRoeShwcm9jZXNzLmVudi5QUk9KRU5fRUpFQ1RJTkcpO1xuXG4gICAgdGhpcy5fcHJvamVuQ29tbWFuZCA9IG9wdGlvbnMucHJvamVuQ29tbWFuZDtcbiAgICBpZiAodGhpcy5lamVjdGVkKSB7XG4gICAgICAvLyBgc2NyaXB0cy9ydW4tdGFzay5janNgIHJlbGllcyBvbiBpdHMgYCMhL3Vzci9iaW4vZW52IG5vZGVgIHNoZWJhbmcgYW5kXG4gICAgICAvLyB0aGUgZXhlY3V0YWJsZSBiaXQgdG8gcnVuIGRpcmVjdGx5IC0gbmVpdGhlciBleGlzdHMgb24gV2luZG93cywgd2hlcmVcbiAgICAgIC8vIHRoZXJlIGlzIG5vIHNoZWJhbmcgc3VwcG9ydCBhbmQgbnBtIGludm9rZXMgcGFja2FnZS5qc29uIHNjcmlwdHNcbiAgICAgIC8vIHRocm91Z2ggY21kLmV4ZS4gUHJlZml4aW5nIHdpdGggYG5vZGVgIHJlc29sdmVzIHRoZSBzY3JpcHQgZXhwbGljaXRseVxuICAgICAgLy8gYW5kIHdvcmtzIGlkZW50aWNhbGx5IG9uIGV2ZXJ5IHBsYXRmb3JtLlxuICAgICAgdGhpcy5fcHJvamVuQ29tbWFuZCA9IFwibm9kZSBzY3JpcHRzL3J1bi10YXNrLmNqc1wiO1xuICAgIH1cblxuICAgIHRoaXMub3V0ZGlyID0gb3V0ZGlyO1xuXG4gICAgLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cbiAgICB0aGlzLmdpdGF0dHJpYnV0ZXMgPSBuZXcgR2l0QXR0cmlidXRlc0ZpbGUodGhpcywge1xuICAgICAgZW5kT2ZMaW5lOiBvcHRpb25zLmdpdE9wdGlvbnM/LmVuZE9mTGluZSxcbiAgICB9KTtcbiAgICB0aGlzLmFubm90YXRlR2VuZXJhdGVkKFwiLy5wcm9qZW4vKipcIik7IC8vIGNvbnRlbnRzICBvZiB0aGUgLnByb2plbi8gZGlyZWN0b3J5IGFyZSBnZW5lcmF0ZWQgYnkgcHJvamVuXG4gICAgdGhpcy5hbm5vdGF0ZUdlbmVyYXRlZChgLyR7dGhpcy5naXRhdHRyaWJ1dGVzLnBhdGh9YCk7IC8vIHRoZSAuZ2l0YXR0cmlidXRlcyBmaWxlIGl0c2VsZiBpcyBnZW5lcmF0ZWRcblxuICAgIGlmIChvcHRpb25zLmdpdE9wdGlvbnM/Lmxmc1BhdHRlcm5zKSB7XG4gICAgICBmb3IgKGNvbnN0IHBhdHRlcm4gb2Ygb3B0aW9ucy5naXRPcHRpb25zLmxmc1BhdHRlcm5zKSB7XG4gICAgICAgIHRoaXMuZ2l0YXR0cmlidXRlcy5hZGRBdHRyaWJ1dGVzKFxuICAgICAgICAgIHBhdHRlcm4sXG4gICAgICAgICAgXCJmaWx0ZXI9bGZzXCIsXG4gICAgICAgICAgXCJkaWZmPWxmc1wiLFxuICAgICAgICAgIFwibWVyZ2U9bGZzXCIsXG4gICAgICAgICAgXCItdGV4dFwiLFxuICAgICAgICApO1xuICAgICAgfVxuICAgIH1cblxuICAgIHRoaXMuZ2l0aWdub3JlID0gbmV3IElnbm9yZUZpbGUoXG4gICAgICB0aGlzLFxuICAgICAgXCIuZ2l0aWdub3JlXCIsXG4gICAgICBvcHRpb25zLmdpdElnbm9yZU9wdGlvbnMsXG4gICAgKTtcbiAgICB0aGlzLmdpdGlnbm9yZS5leGNsdWRlKFwibm9kZV9tb2R1bGVzL1wiKTsgLy8gY3JlYXRlZCBieSBydW5uaW5nIGBucHggcHJvamVuYFxuICAgIHRoaXMuZ2l0aWdub3JlLmluY2x1ZGUoYC8ke3RoaXMuZ2l0YXR0cmlidXRlcy5wYXRofWApO1xuXG4gICAgLy8gb2ggbm86IHRhc2tzIGRlcGVuZHMgb24gZ2l0aWdub3JlIHNvIGl0IGhhcyB0byBiZSBpbml0aWFsaXplZCBhZnRlclxuICAgIC8vIHNtZWxscyBsaWtlIGRlcCBpbmplY3Rpb24gYnV0IGdvZCBmb3JiaWQuXG4gICAgdGhpcy50YXNrcyA9IG5ldyBUYXNrcyh0aGlzKTtcblxuICAgIGlmICghdGhpcy5lamVjdGVkKSB7XG4gICAgICB0aGlzLmRlZmF1bHRUYXNrID0gdGhpcy50YXNrcy5hZGRUYXNrKFByb2plY3QuREVGQVVMVF9UQVNLLCB7XG4gICAgICAgIGRlc2NyaXB0aW9uOiBcIlN5bnRoZXNpemUgcHJvamVjdCBmaWxlc1wiLFxuICAgICAgfSk7XG5cbiAgICAgIC8vIFN1YnRhc2tzIHNob3VsZCBjYWxsIHRoZSByb290IHRhc2sgZm9yIHN5bnRoXG4gICAgICBpZiAodGhpcy5wYXJlbnQpIHtcbiAgICAgICAgY29uc3QgY3dkID0gcGF0aC5yZWxhdGl2ZSh0aGlzLm91dGRpciwgdGhpcy5yb290Lm91dGRpcik7XG4gICAgICAgIGNvbnN0IG5vcm1hbGl6ZWRDd2QgPSBub3JtYWxpemVQZXJzaXN0ZWRQYXRoKGN3ZCk7XG4gICAgICAgIHRoaXMuZGVmYXVsdFRhc2suZXhlYyhgJHt0aGlzLnByb2plbkNvbW1hbmR9ICR7UHJvamVjdC5ERUZBVUxUX1RBU0t9YCwge1xuICAgICAgICAgIGN3ZDogbm9ybWFsaXplZEN3ZCxcbiAgICAgICAgfSk7XG4gICAgICB9XG5cbiAgICAgIGlmICghdGhpcy5wYXJlbnQpIHtcbiAgICAgICAgdGhpcy5lamVjdFRhc2sgPSB0aGlzLnRhc2tzLmFkZFRhc2soXCJlamVjdFwiLCB7XG4gICAgICAgICAgZGVzY3JpcHRpb246IFwiUmVtb3ZlIHByb2plbiBmcm9tIHRoZSBwcm9qZWN0XCIsXG4gICAgICAgICAgZW52OiB7XG4gICAgICAgICAgICBQUk9KRU5fRUpFQ1RJTkc6IFwidHJ1ZVwiLFxuICAgICAgICAgIH0sXG4gICAgICAgIH0pO1xuICAgICAgICB0aGlzLmVqZWN0VGFzay5zcGF3bih0aGlzLmRlZmF1bHRUYXNrKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICB0aGlzLnByb2plY3RCdWlsZCA9IG5ldyBQcm9qZWN0QnVpbGQodGhpcyk7XG5cbiAgICB0aGlzLmRlcHMgPSBuZXcgRGVwZW5kZW5jaWVzKHRoaXMpO1xuXG4gICAgdGhpcy5sb2dnZXIgPSBuZXcgTG9nZ2VyKHRoaXMsIG9wdGlvbnMubG9nZ2luZyk7XG5cbiAgICBjb25zdCBwcm9qZW5yY0pzb24gPSBvcHRpb25zLnByb2plbnJjSnNvbiA/PyBmYWxzZTtcbiAgICBpZiAoIXRoaXMucGFyZW50ICYmIHByb2plbnJjSnNvbikge1xuICAgICAgbmV3IFByb2plbnJjSnNvbih0aGlzLCBvcHRpb25zLnByb2plbnJjSnNvbk9wdGlvbnMpO1xuICAgIH1cblxuICAgIGlmIChvcHRpb25zLnJlbm92YXRlYm90KSB7XG4gICAgICBuZXcgUmVub3ZhdGVib3QodGhpcywgb3B0aW9ucy5yZW5vdmF0ZWJvdE9wdGlvbnMpO1xuICAgIH1cblxuICAgIGlmIChvcHRpb25zLnByb2plY3RUcmVlKSB7XG4gICAgICBuZXcgUHJvamVjdFRyZWUodGhpcyk7XG4gICAgfVxuXG4gICAgdGhpcy5jb21taXRHZW5lcmF0ZWQgPSBvcHRpb25zLmNvbW1pdEdlbmVyYXRlZCA/PyB0cnVlO1xuXG4gICAgaWYgKCF0aGlzLmVqZWN0ZWQpIHtcbiAgICAgIG5ldyBKc29uRmlsZSh0aGlzLCBGSUxFX01BTklGRVNULCB7XG4gICAgICAgIG9taXRFbXB0eTogdHJ1ZSxcbiAgICAgICAgb2JqOiAoKSA9PiAoe1xuICAgICAgICAgIC8vIHJlcGxhY2UgYFxcYCB3aXRoIGAvYCB0byBlbnN1cmUgcGF0aHMgbWF0Y2ggYWNyb3NzIHBsYXRmb3Jtc1xuICAgICAgICAgIGZpbGVzOiB0aGlzLmZpbGVzXG4gICAgICAgICAgICAuZmlsdGVyKChmKSA9PiBmLnJlYWRvbmx5KVxuICAgICAgICAgICAgLm1hcCgoZikgPT4gbm9ybWFsaXplUGVyc2lzdGVkUGF0aChmLnBhdGgpKSxcbiAgICAgICAgfSksXG4gICAgICAgIC8vIFRoaXMgZmlsZSBpcyB1c2VkIGJ5IHByb2plbiB0byB0cmFjayB0aGUgZ2VuZXJhdGVkIGZpbGVzLCBzbyBtdXN0IGJlIGNvbW1pdHRlZC5cbiAgICAgICAgY29tbWl0dGVkOiB0cnVlLFxuICAgICAgfSk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFRoZSByb290IHByb2plY3QuXG4gICAqL1xuICBwdWJsaWMgZ2V0IHJvb3QoKTogUHJvamVjdCB7XG4gICAgcmV0dXJuIGlzUHJvamVjdCh0aGlzLm5vZGUucm9vdCkgPyB0aGlzLm5vZGUucm9vdCA6IHRoaXM7XG4gIH1cblxuICAvKipcbiAgICogUmV0dXJucyBhbGwgdGhlIGNvbXBvbmVudHMgd2l0aGluIHRoaXMgcHJvamVjdC5cbiAgICovXG4gIHB1YmxpYyBnZXQgY29tcG9uZW50cygpOiBDb21wb25lbnRbXSB7XG4gICAgcmV0dXJuIHRoaXMubm9kZVxuICAgICAgLmZpbmRBbGwoKVxuICAgICAgLmZpbHRlcihcbiAgICAgICAgKGMpOiBjIGlzIENvbXBvbmVudCA9PlxuICAgICAgICAgIGlzQ29tcG9uZW50KGMpICYmIGMucHJvamVjdC5ub2RlLnBhdGggPT09IHRoaXMubm9kZS5wYXRoLFxuICAgICAgKTtcbiAgfVxuICAvKipcbiAgICogUmV0dXJucyBhbGwgdGhlIHN1YnByb2plY3RzIHdpdGhpbiB0aGlzIHByb2plY3QuXG4gICAqL1xuICBwdWJsaWMgZ2V0IHN1YnByb2plY3RzKCk6IFByb2plY3RbXSB7XG4gICAgcmV0dXJuIHRoaXMubm9kZS5jaGlsZHJlbi5maWx0ZXIoaXNQcm9qZWN0KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBBbGwgZmlsZXMgaW4gdGhpcyBwcm9qZWN0LlxuICAgKi9cbiAgcHVibGljIGdldCBmaWxlcygpOiBGaWxlQmFzZVtdIHtcbiAgICByZXR1cm4gdGhpcy5jb21wb25lbnRzXG4gICAgICAuZmlsdGVyKGlzRmlsZSlcbiAgICAgIC5zb3J0KChmMSwgZjIpID0+IGYxLnBhdGgubG9jYWxlQ29tcGFyZShmMi5wYXRoKSk7XG4gIH1cblxuICAvKipcbiAgICogQWRkcyBhIG5ldyB0YXNrIHRvIHRoaXMgcHJvamVjdC4gVGhpcyB3aWxsIGZhaWwgaWYgdGhlIHByb2plY3QgYWxyZWFkeSBoYXNcbiAgICogYSB0YXNrIHdpdGggdGhpcyBuYW1lLlxuICAgKlxuICAgKiBAcGFyYW0gbmFtZSBUaGUgdGFzayBuYW1lIHRvIGFkZFxuICAgKiBAcGFyYW0gcHJvcHMgVGFzayBwcm9wZXJ0aWVzXG4gICAqL1xuICBwdWJsaWMgYWRkVGFzayhuYW1lOiBzdHJpbmcsIHByb3BzOiBUYXNrT3B0aW9ucyA9IHt9KSB7XG4gICAgcmV0dXJuIHRoaXMudGFza3MuYWRkVGFzayhuYW1lLCBwcm9wcyk7XG4gIH1cblxuICAvKipcbiAgICogUmVtb3ZlcyBhIHRhc2sgZnJvbSBhIHByb2plY3QuXG4gICAqXG4gICAqIEBwYXJhbSBuYW1lIFRoZSBuYW1lIG9mIHRoZSB0YXNrIHRvIHJlbW92ZS5cbiAgICpcbiAgICogQHJldHVybnMgVGhlIGBUYXNrYCB0aGF0IHdhcyByZW1vdmVkLCBvdGhlcndpc2UgYHVuZGVmaW5lZGAuXG4gICAqL1xuICBwdWJsaWMgcmVtb3ZlVGFzayhuYW1lOiBzdHJpbmcpIHtcbiAgICByZXR1cm4gdGhpcy50YXNrcy5yZW1vdmVUYXNrKG5hbWUpO1xuICB9XG5cbiAgcHVibGljIGdldCBidWlsZFRhc2soKSB7XG4gICAgcmV0dXJuIHRoaXMucHJvamVjdEJ1aWxkLmJ1aWxkVGFzaztcbiAgfVxuICBwdWJsaWMgZ2V0IGNvbXBpbGVUYXNrKCkge1xuICAgIHJldHVybiB0aGlzLnByb2plY3RCdWlsZC5jb21waWxlVGFzaztcbiAgfVxuICBwdWJsaWMgZ2V0IHRlc3RUYXNrKCkge1xuICAgIHJldHVybiB0aGlzLnByb2plY3RCdWlsZC50ZXN0VGFzaztcbiAgfVxuICBwdWJsaWMgZ2V0IHByZUNvbXBpbGVUYXNrKCkge1xuICAgIHJldHVybiB0aGlzLnByb2plY3RCdWlsZC5wcmVDb21waWxlVGFzaztcbiAgfVxuICBwdWJsaWMgZ2V0IHBvc3RDb21waWxlVGFzaygpIHtcbiAgICByZXR1cm4gdGhpcy5wcm9qZWN0QnVpbGQucG9zdENvbXBpbGVUYXNrO1xuICB9XG4gIHB1YmxpYyBnZXQgcGFja2FnZVRhc2soKSB7XG4gICAgcmV0dXJuIHRoaXMucHJvamVjdEJ1aWxkLnBhY2thZ2VUYXNrO1xuICB9XG5cbiAgLyoqXG4gICAqIEZpbmRzIGEgZmlsZSBhdCB0aGUgc3BlY2lmaWVkIHJlbGF0aXZlIHBhdGggd2l0aGluIHRoaXMgcHJvamVjdCBhbmQgYWxsXG4gICAqIGl0cyBzdWJwcm9qZWN0cy5cbiAgICpcbiAgICogQHBhcmFtIGZpbGVQYXRoIFRoZSBmaWxlIHBhdGguIElmIHRoaXMgcGF0aCBpcyByZWxhdGl2ZSwgaXQgd2lsbCBiZSByZXNvbHZlZFxuICAgKiBmcm9tIHRoZSByb290IG9mIF90aGlzXyBwcm9qZWN0LlxuICAgKiBAcmV0dXJucyBhIGBGaWxlQmFzZWAgb3IgdW5kZWZpbmVkIGlmIHRoZXJlIGlzIG5vIGZpbGUgaW4gdGhhdCBwYXRoXG4gICAqL1xuICBwdWJsaWMgdHJ5RmluZEZpbGUoZmlsZVBhdGg6IHN0cmluZyk6IEZpbGVCYXNlIHwgdW5kZWZpbmVkIHtcbiAgICBjb25zdCBhYnNvbHV0ZSA9IHBhdGguaXNBYnNvbHV0ZShmaWxlUGF0aClcbiAgICAgID8gZmlsZVBhdGhcbiAgICAgIDogcGF0aC5yZXNvbHZlKHRoaXMub3V0ZGlyLCBmaWxlUGF0aCk7XG5cbiAgICBjb25zdCBjYW5kaWRhdGUgPSB0aGlzLm5vZGVcbiAgICAgIC5maW5kQWxsKClcbiAgICAgIC5maW5kKFxuICAgICAgICAoYyk6IGMgaXMgRmlsZUJhc2UgPT5cbiAgICAgICAgICBpc0NvbXBvbmVudChjKSAmJiBpc0ZpbGUoYykgJiYgYy5hYnNvbHV0ZVBhdGggPT09IGFic29sdXRlLFxuICAgICAgKTtcblxuICAgIHJldHVybiBjYW5kaWRhdGU7XG4gIH1cblxuICAvKipcbiAgICogRmluZHMgYW4gb2JqZWN0IGZpbGUgKGxpa2UgSnNvbkZpbGUsIFlhbWxGaWxlLCBldGMuKSBieSBuYW1lLlxuICAgKiBAcGFyYW0gZmlsZVBhdGggVGhlIGZpbGUgcGF0aC5cbiAgICovXG4gIHB1YmxpYyB0cnlGaW5kT2JqZWN0RmlsZShmaWxlUGF0aDogc3RyaW5nKTogT2JqZWN0RmlsZSB8IHVuZGVmaW5lZCB7XG4gICAgY29uc3QgZmlsZSA9IHRoaXMudHJ5RmluZEZpbGUoZmlsZVBhdGgpO1xuICAgIGlmICghZmlsZSkge1xuICAgICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICB9XG5cbiAgICBpZiAoIShmaWxlIGluc3RhbmNlb2YgT2JqZWN0RmlsZSkpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgYGZvdW5kIGZpbGUgJHtmaWxlUGF0aH0gYnV0IGl0IGlzIG5vdCBhIE9iamVjdEZpbGUuIGdvdDogJHtmaWxlLmNvbnN0cnVjdG9yLm5hbWV9YCxcbiAgICAgICk7XG4gICAgfVxuXG4gICAgcmV0dXJuIGZpbGU7XG4gIH1cblxuICAvKipcbiAgICogRmluZHMgYSBmaWxlIGF0IHRoZSBzcGVjaWZpZWQgcmVsYXRpdmUgcGF0aCB3aXRoaW4gdGhpcyBwcm9qZWN0IGFuZCByZW1vdmVzXG4gICAqIGl0LlxuICAgKlxuICAgKiBAcGFyYW0gZmlsZVBhdGggVGhlIGZpbGUgcGF0aC4gSWYgdGhpcyBwYXRoIGlzIHJlbGF0aXZlLCBpdCB3aWxsIGJlXG4gICAqIHJlc29sdmVkIGZyb20gdGhlIHJvb3Qgb2YgX3RoaXNfIHByb2plY3QuXG4gICAqIEByZXR1cm5zIGEgYEZpbGVCYXNlYCBpZiB0aGUgZmlsZSB3YXMgZm91bmQgYW5kIHJlbW92ZWQsIG9yIHVuZGVmaW5lZCBpZlxuICAgKiB0aGUgZmlsZSB3YXMgbm90IGZvdW5kLlxuICAgKi9cbiAgcHVibGljIHRyeVJlbW92ZUZpbGUoZmlsZVBhdGg6IHN0cmluZyk6IEZpbGVCYXNlIHwgdW5kZWZpbmVkIHtcbiAgICBjb25zdCBjYW5kaWRhdGUgPSB0aGlzLnRyeUZpbmRGaWxlKGZpbGVQYXRoKTtcblxuICAgIGlmIChjYW5kaWRhdGUpIHtcbiAgICAgIGNhbmRpZGF0ZS5ub2RlLnNjb3BlPy5ub2RlLnRyeVJlbW92ZUNoaWxkKGNhbmRpZGF0ZS5ub2RlLmlkKTtcbiAgICAgIHJldHVybiBjYW5kaWRhdGU7XG4gICAgfVxuXG4gICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgfVxuXG4gIC8qKlxuICAgKiBFeGNsdWRlIHRoZSBtYXRjaGluZyBmaWxlcyBmcm9tIHByZS1zeW50aCBjbGVhbnVwLiBDYW4gYmUgdXNlZCB3aGVuLCBmb3IgZXhhbXBsZSwgc29tZVxuICAgKiBzb3VyY2UgZmlsZXMgaW5jbHVkZSB0aGUgcHJvamVuIG1hcmtlciBhbmQgd2UgZG9uJ3Qgd2FudCB0aGVtIHRvIGJlIGVyYXNlZCBkdXJpbmcgc3ludGguXG4gICAqXG4gICAqIEBwYXJhbSBnbG9icyBUaGUgZ2xvYiBwYXR0ZXJucyB0byBtYXRjaFxuICAgKi9cbiAgcHVibGljIGFkZEV4Y2x1ZGVGcm9tQ2xlYW51cCguLi5nbG9iczogc3RyaW5nW10pIHtcbiAgICB0aGlzLl9leGNsdWRlRnJvbUNsZWFudXAucHVzaCguLi5nbG9icyk7XG4gIH1cblxuICAvKipcbiAgICogUmV0dXJucyB0aGUgc2hlbGwgY29tbWFuZCB0byBleGVjdXRlIGluIG9yZGVyIHRvIHJ1biBhIHRhc2suXG4gICAqXG4gICAqIEJ5IGRlZmF1bHQsIHRoaXMgaXMgYG5weCBwcm9qZW5APHZlcnNpb24+IDx0YXNrPmBcbiAgICpcbiAgICogQHBhcmFtIHRhc2sgVGhlIHRhc2sgZm9yIHdoaWNoIHRoZSBjb21tYW5kIGlzIHJlcXVpcmVkXG4gICAqL1xuICBwdWJsaWMgcnVuVGFza0NvbW1hbmQodGFzazogVGFzaykge1xuICAgIGNvbnN0IHBqID0gdGhpcy5fcHJvamVuQ29tbWFuZCA/PyBgbnB4IHByb2plbkAke1BST0pFTl9WRVJTSU9OfWA7XG4gICAgcmV0dXJuIGAke3BqfSAke3Rhc2submFtZX1gO1xuICB9XG5cbiAgLyoqXG4gICAqIEV4Y2x1ZGUgdGhlc2UgZmlsZXMgZnJvbSB0aGUgYnVuZGxlZCBwYWNrYWdlLiBJbXBsZW1lbnRlZCBieSBwcm9qZWN0IHR5cGVzIGJhc2VkIG9uIHRoZVxuICAgKiBwYWNrYWdpbmcgbWVjaGFuaXNtLiBGb3IgZXhhbXBsZSwgYE5vZGVQcm9qZWN0YCBkZWxlZ2F0ZXMgdGhpcyB0byBgLm5wbWlnbm9yZWAuXG4gICAqXG4gICAqIEBwYXJhbSBfcGF0dGVybiBUaGUgZ2xvYiBwYXR0ZXJuIHRvIGV4Y2x1ZGVcbiAgICovXG4gIHB1YmxpYyBhZGRQYWNrYWdlSWdub3JlKF9wYXR0ZXJuOiBzdHJpbmcpIHtcbiAgICAvLyBub3RoaW5nIHRvIGRvIGF0IHRoZSBhYnN0cmFjdCBsZXZlbFxuICB9XG5cbiAgLyoqXG4gICAqIEFkZHMgYSAuZ2l0aWdub3JlIHBhdHRlcm4uXG4gICAqIEBwYXJhbSBwYXR0ZXJuIFRoZSBnbG9iIHBhdHRlcm4gdG8gaWdub3JlLlxuICAgKi9cbiAgcHVibGljIGFkZEdpdElnbm9yZShwYXR0ZXJuOiBzdHJpbmcpIHtcbiAgICB0aGlzLmdpdGlnbm9yZS5hZGRQYXR0ZXJucyhwYXR0ZXJuKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBDb25zaWRlciBhIHNldCBvZiBmaWxlcyBhcyBcImdlbmVyYXRlZFwiLiBUaGlzIG1ldGhvZCBpcyBpbXBsZW1lbnRlZCBieVxuICAgKiBkZXJpdmVkIGNsYXNzZXMgYW5kIHVzZWQgZm9yIGV4YW1wbGUsIHRvIGFkZCBnaXQgYXR0cmlidXRlcyB0byB0ZWxsIEdpdEh1YlxuICAgKiB0aGF0IGNlcnRhaW4gZmlsZXMgYXJlIGdlbmVyYXRlZC5cbiAgICpcbiAgICogQHBhcmFtIF9nbG9iIHRoZSBnbG9iIHBhdHRlcm4gdG8gbWF0Y2ggKGNvdWxkIGJlIGEgZmlsZSBwYXRoKS5cbiAgICovXG4gIHB1YmxpYyBhbm5vdGF0ZUdlbmVyYXRlZChfZ2xvYjogc3RyaW5nKTogdm9pZCB7XG4gICAgLy8gbm90aGluZyB0byBkbyBhdCB0aGUgYWJzdHJhY3QgbGV2ZWxcbiAgfVxuXG4gIC8qKlxuICAgKiBTeW50aGVzaXplIGFsbCBwcm9qZWN0IGZpbGVzIGludG8gYG91dGRpcmAuXG4gICAqXG4gICAqIDEuIENhbGwgXCJ0aGlzLnByZVN5bnRoZXNpemUoKVwiXG4gICAqIDIuIERlbGV0ZSBhbGwgZ2VuZXJhdGVkIGZpbGVzXG4gICAqIDMuIFN5bnRoZXNpemUgYWxsIHN1YnByb2plY3RzXG4gICAqIDQuIFN5bnRoZXNpemUgYWxsIGNvbXBvbmVudHMgb2YgdGhpcyBwcm9qZWN0XG4gICAqIDUuIENhbGwgXCJwcm9qZWN0Q3JlYXRpb24oKVwiIGZvciBhbGwgY29tcG9uZW50cywgb25seSBpZiB0aGUgcHJvamVjdCBpcyBiZWluZyBjcmVhdGVkIGZvciB0aGUgZmlyc3QgdGltZVxuICAgKiA2LiBDYWxsIFwicG9zdFN5bnRoZXNpemUoKVwiIGZvciBhbGwgY29tcG9uZW50cyBvZiB0aGlzIHByb2plY3RcbiAgICogNy4gQ2FsbCBcInRoaXMucG9zdFN5bnRoZXNpemUoKVwiXG4gICAqIDguIENhbGwgXCJwb3N0UHJvamVjdENyZWF0aW9uKClcIiBmb3IgYWxsIGNvbXBvbmVudHMsIG9ubHkgaWYgdGhlIHByb2plY3QgaXMgYmVpbmcgY3JlYXRlZCBmb3IgdGhlIGZpcnN0IHRpbWVcbiAgICovXG4gIHB1YmxpYyBzeW50aCgpOiB2b2lkIHtcbiAgICBpZiAodGhpcy5faW5pdFByb2plY3Q/LnN5bnRoID09PSBmYWxzZSkge1xuICAgICAgLy8gdXNlciByZXF1ZXN0IHRvIG5vdCBydW4gZnVsbCBzeW50aCwgaW5zdGVhZCB3ZSBvbmx5IHJ1biBwcm9qZWN0Q3JlYXRpb24gaG9va3NcbiAgICAgIGZvciAoY29uc3QgY29tcCBvZiB0aGlzLmNvbXBvbmVudHMpIHtcbiAgICAgICAgY29tcC5wcm9qZWN0Q3JlYXRpb24odGhpcy5faW5pdFByb2plY3QpO1xuICAgICAgfVxuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGNvbnN0IG91dGRpciA9IHRoaXMub3V0ZGlyO1xuICAgIHRoaXMubG9nZ2VyLmRlYnVnKFwiU3ludGhlc2l6aW5nIHByb2plY3QuLi5cIik7XG5cbiAgICB0aGlzLnByZVN5bnRoZXNpemUoKTtcblxuICAgIGZvciAoY29uc3QgY29tcCBvZiB0aGlzLmNvbXBvbmVudHMpIHtcbiAgICAgIGNvbXAucHJlU3ludGhlc2l6ZSgpO1xuICAgIH1cblxuICAgIC8vIHdlIGV4Y2x1ZGUgYWxsIHN1YnByb2plY3QgZGlyZWN0b3JpZXMgdG8gZW5zdXJlIHRoYXQgd2hlbiBzdWJwcm9qZWN0LnN5bnRoKClcbiAgICAvLyBnZXRzIGNhbGxlZCBiZWxvdyBhZnRlciBjbGVhbnVwKCksIHN1YnByb2plY3QgZ2VuZXJhdGVkIGZpbGVzIGFyZSBsZWZ0IGludGFjdFxuICAgIGZvciAoY29uc3Qgc3VicHJvamVjdCBvZiB0aGlzLnN1YnByb2plY3RzKSB7XG4gICAgICB0aGlzLmFkZEV4Y2x1ZGVGcm9tQ2xlYW51cChzdWJwcm9qZWN0Lm91dGRpciArIFwiLyoqXCIpO1xuICAgIH1cblxuICAgIC8vIGRlbGV0ZSBvcnBoYW5lZCBmaWxlcyBiZWZvcmUgd2Ugc3RhcnQgc3ludGhlc2l6aW5nIG5ldyBvbmVzXG4gICAgY2xlYW51cChcbiAgICAgIG91dGRpcixcbiAgICAgIHRoaXMuZmlsZXMubWFwKChmKSA9PiBub3JtYWxpemVQZXJzaXN0ZWRQYXRoKGYucGF0aCkpLFxuICAgICAgdGhpcy5fZXhjbHVkZUZyb21DbGVhbnVwLFxuICAgICk7XG5cbiAgICBmb3IgKGNvbnN0IHN1YnByb2plY3Qgb2YgdGhpcy5zdWJwcm9qZWN0cykge1xuICAgICAgc3VicHJvamVjdC5zeW50aCgpO1xuICAgIH1cblxuICAgIGZvciAoY29uc3QgY29tcCBvZiB0aGlzLmNvbXBvbmVudHMpIHtcbiAgICAgIGNvbXAuc3ludGhlc2l6ZSgpO1xuICAgIH1cblxuICAgIGlmICh0aGlzLl9pbml0UHJvamVjdCkge1xuICAgICAgZm9yIChjb25zdCBjb21wIG9mIHRoaXMuY29tcG9uZW50cykge1xuICAgICAgICBjb21wLnByb2plY3RDcmVhdGlvbih0aGlzLl9pbml0UHJvamVjdCk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgaWYgKCFpc1RydXRoeShwcm9jZXNzLmVudi5QUk9KRU5fRElTQUJMRV9QT1NUKSkge1xuICAgICAgZm9yIChjb25zdCBjb21wIG9mIHRoaXMuY29tcG9uZW50cykge1xuICAgICAgICBjb21wLnBvc3RTeW50aGVzaXplKCk7XG4gICAgICB9XG5cbiAgICAgIC8vIHByb2plY3QtbGV2ZWwgaG9va1xuICAgICAgdGhpcy5wb3N0U3ludGhlc2l6ZSgpO1xuXG4gICAgICBpZiAodGhpcy5faW5pdFByb2plY3QpIHtcbiAgICAgICAgZm9yIChjb25zdCBjb21wIG9mIHRoaXMuY29tcG9uZW50cykge1xuICAgICAgICAgIGNvbXAucG9zdFByb2plY3RDcmVhdGlvbih0aGlzLl9pbml0UHJvamVjdCk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG5cbiAgICBpZiAodGhpcy5lamVjdGVkKSB7XG4gICAgICB0aGlzLmxvZ2dlci5kZWJ1ZyhcIkVqZWN0aW5nIHByb2plY3QuLi5cIik7XG5cbiAgICAgIC8vIEJhY2t1cCBwcm9qZW5yYyBmaWxlc1xuICAgICAgY29uc3QgZmlsZXMgPSBnbG9iLnN5bmMoXCIucHJvamVucmMuKlwiLCB7XG4gICAgICAgIGN3ZDogdGhpcy5vdXRkaXIsXG4gICAgICAgIGRvdDogdHJ1ZSxcbiAgICAgICAgb25seUZpbGVzOiB0cnVlLFxuICAgICAgICBmb2xsb3dTeW1ib2xpY0xpbmtzOiBmYWxzZSxcbiAgICAgICAgYWJzb2x1dGU6IHRydWUsXG4gICAgICB9KTtcblxuICAgICAgZm9yIChjb25zdCBmaWxlIG9mIGZpbGVzKSB7XG4gICAgICAgIHJlbmFtZVN5bmMoZmlsZSwgYCR7ZmlsZX0uYmFrYCk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgdGhpcy5sb2dnZXIuZGVidWcoXCJTeW50aGVzaXMgY29tcGxldGVcIik7XG4gIH1cblxuICAvKipcbiAgICogV2hldGhlciBvciBub3QgdGhlIHByb2plY3QgaXMgYmVpbmcgZWplY3RlZC5cbiAgICovXG4gIHB1YmxpYyBnZXQgZWplY3RlZCgpOiBib29sZWFuIHtcbiAgICByZXR1cm4gdGhpcy5fZWplY3RlZDtcbiAgfVxuXG4gIC8qKlxuICAgKiBDYWxsZWQgYmVmb3JlIGFsbCBjb21wb25lbnRzIGFyZSBzeW50aGVzaXplZC5cbiAgICovXG4gIHB1YmxpYyBwcmVTeW50aGVzaXplKCkge31cblxuICAvKipcbiAgICogQ2FsbGVkIGFmdGVyIGFsbCBjb21wb25lbnRzIGFyZSBzeW50aGVzaXplZC4gT3JkZXIgaXMgKm5vdCogZ3VhcmFudGVlZC5cbiAgICovXG4gIHB1YmxpYyBwb3N0U3ludGhlc2l6ZSgpIHt9XG59XG5cbi8qKlxuICogSW5mb3JtYXRpb24gcGFzc2VkIGZyb20gYHByb2plbiBuZXdgIHRvIHRoZSBwcm9qZWN0IG9iamVjdCB3aGVuIHRoZSBwcm9qZWN0XG4gKiBpcyBmaXJzdCBjcmVhdGVkLiBJdCBpcyB1c2VkIHRvIGdlbmVyYXRlIHByb2plbnJjIGZpbGVzIGluIHZhcmlvdXMgbGFuZ3VhZ2VzLlxuICovXG5leHBvcnQgaW50ZXJmYWNlIEluaXRQcm9qZWN0IHtcbiAgLyoqXG4gICAqIFRoZSBKU0lJIEZRTiBvZiB0aGUgcHJvamVjdCB0eXBlLlxuICAgKi9cbiAgcmVhZG9ubHkgZnFuOiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIEluaXRpYWwgYXJndW1lbnRzIHBhc3NlZCB0byBgcHJvamVuIG5ld2AuXG4gICAqL1xuICByZWFkb25seSBhcmdzOiBSZWNvcmQ8c3RyaW5nLCBhbnk+O1xuXG4gIC8qKlxuICAgKiBQcm9qZWN0IG1ldGFkYXRhLlxuICAgKi9cbiAgcmVhZG9ubHkgdHlwZTogaW52ZW50b3J5LlByb2plY3RUeXBlO1xuXG4gIC8qKlxuICAgKiBJbmNsdWRlIGNvbW1lbnRlZCBvdXQgb3B0aW9ucy4gRG9lcyBub3QgYXBwbHkgdG8gcHJvamVucmMuanNvbiBmaWxlcy5cbiAgICogQGRlZmF1bHQgSW5pdFByb2plY3RPcHRpb25IaW50cy5GRUFUVVJFRFxuICAgKi9cbiAgcmVhZG9ubHkgY29tbWVudHM6IEluaXRQcm9qZWN0T3B0aW9uSGludHM7XG5cbiAgLyoqXG4gICAqIFdoZXRoZXIgYHByb2plbiBuZXdgIHNob3VsZCBjYWxsIGBwcm9qZWN0LnN5bnRoKClgIGFmdGVyIGNvbnN0cnVjdGlvbi5cbiAgICogQGRlZmF1bHQgdHJ1ZVxuICAgKi9cbiAgcmVhZG9ubHkgc3ludGg6IGJvb2xlYW47XG5cbiAgLyoqXG4gICAqIFdoZXRoZXIgYHByb2plbiBuZXdgIHNob3VsZCBydW4gcG9zdC1zeW50aGVzaXMgc3RlcHMgKGUuZy4gcGFja2FnZSBtYW5hZ2VyIGluc3RhbGwpLlxuICAgKiBAZGVmYXVsdCB0cnVlXG4gICAqL1xuICByZWFkb25seSBwb3N0OiBib29sZWFuO1xufVxuXG4vKipcbiAqIFJlc29sdmVzIHRoZSBwcm9qZWN0J3Mgb3V0cHV0IGRpcmVjdG9yeS5cbiAqL1xuZnVuY3Rpb24gZGV0ZXJtaW5lT3V0ZGlyKHBhcmVudD86IFByb2plY3QsIG91dGRpck9wdGlvbj86IHN0cmluZykge1xuICBpZiAocGFyZW50ICYmIG91dGRpck9wdGlvbiAmJiBwYXRoLmlzQWJzb2x1dGUob3V0ZGlyT3B0aW9uKSkge1xuICAgIHRocm93IG5ldyBFcnJvcignXCJvdXRkaXJcIiBtdXN0IGJlIGEgcmVsYXRpdmUgcGF0aCcpO1xuICB9XG5cbiAgLy8gaWYgdGhpcyBpcyBhIHN1YnByb2plY3QsIGl0IGlzIHJlbGF0aXZlIHRvIHRoZSBwYXJlbnRcbiAgaWYgKHBhcmVudCkge1xuICAgIGlmICghb3V0ZGlyT3B0aW9uKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ1wib3V0ZGlyXCIgbXVzdCBiZSBzcGVjaWZpZWQgZm9yIHN1YnByb2plY3RzJyk7XG4gICAgfVxuXG4gICAgcmV0dXJuIHBhdGgucmVzb2x2ZShwYXJlbnQub3V0ZGlyLCBvdXRkaXJPcHRpb24pO1xuICB9XG5cbiAgLy8gaWYgdGhpcyBpcyBydW5uaW5nIGluc2lkZSBhIHRlc3QgYW5kIG91dGRpciBpcyBub3QgZXhwbGljaXRseSBzZXRcbiAgLy8gdXNlIGEgdGVtcCBkaXJlY3RvcnkgKHVubGVzcyBjd2QgaXMgYWxyZWFkeSB1bmRlciB0bXApXG4gIGlmIChJU19URVNUX1JVTiAmJiAhb3V0ZGlyT3B0aW9uKSB7XG4gICAgY29uc3QgcmVhbEN3ZCA9IHJlYWxwYXRoU3luYyhwcm9jZXNzLmN3ZCgpKTtcbiAgICBjb25zdCByZWFsVG1wID0gcmVhbHBhdGhTeW5jKHRtcGRpcigpKTtcblxuICAgIGlmIChyZWFsQ3dkLnN0YXJ0c1dpdGgocmVhbFRtcCkpIHtcbiAgICAgIHJldHVybiBwYXRoLnJlc29sdmUocmVhbEN3ZCwgb3V0ZGlyT3B0aW9uID8/IERFRkFVTFRfT1VURElSKTtcbiAgICB9XG5cbiAgICByZXR1cm4gbWtkdGVtcFN5bmMocGF0aC5qb2luKHRtcGRpcigpLCBcInByb2plbi5cIikpO1xuICB9XG5cbiAgcmV0dXJuIHBhdGgucmVzb2x2ZShvdXRkaXJPcHRpb24gPz8gREVGQVVMVF9PVVRESVIpO1xufVxuXG5mdW5jdGlvbiBpc0ZpbGUoYzogQ29tcG9uZW50KTogYyBpcyBGaWxlQmFzZSB7XG4gIHJldHVybiBjIGluc3RhbmNlb2YgRmlsZUJhc2U7XG59XG4iXX0=