projen
Version:
CDK for software projects
434 lines • 59.6 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Eslint = void 0;
const JSII_RTTI_SYMBOL_1 = Symbol.for("jsii.rtti");
const prettier_1 = require("./prettier");
const component_1 = require("../component");
const json_1 = require("../json");
const yaml_1 = require("../yaml");
/**
* Represents eslint configuration.
*/
class Eslint extends component_1.Component {
static [JSII_RTTI_SYMBOL_1] = { fqn: "projen.javascript.Eslint", version: "0.103.12" };
/**
* Returns the singleton Eslint component of a project or undefined if there is none.
*/
static of(project) {
const isEslint = (c) => c instanceof Eslint;
return project.components.find(isEslint);
}
/**
* The underlying config file
*/
file;
/**
* eslint rules.
*/
rules;
/**
* eslint overrides.
*/
overrides = [];
/**
* eslint task.
*/
eslintTask;
/**
* Direct access to the eslint configuration (escape hatch)
*/
config;
/**
* File patterns that should not be linted
*/
ignorePatterns;
_formattingRules;
_allowDevDeps;
_allowDefaultProject = new Set();
_plugins = new Set();
_extends = new Set();
_fileExtensions;
_flagArgs;
_lintPatterns;
nodeProject;
sortExtends;
constructor(project, options) {
super(project);
this.nodeProject = project;
project.addDevDeps("eslint@^9", "@typescript-eslint/eslint-plugin@^8", "@typescript-eslint/parser@^8", "eslint-import-resolver-typescript", "eslint-plugin-import");
if (options.aliasMap) {
project.addDevDeps("eslint-import-resolver-alias");
}
const devdirs = options.devdirs ?? [];
this._lintPatterns = new Set([...options.dirs, ...devdirs]);
this._fileExtensions = new Set(options.fileExtensions ?? [".ts"]);
this._allowDevDeps = new Set((devdirs ?? []).map((dir) => `**/${dir}/**`));
const commandOptions = options.commandOptions ?? {};
const { fix = true, extraArgs: extraFlagArgs = [] } = commandOptions;
this._flagArgs = new Set(extraFlagArgs);
if (fix) {
this._flagArgs.add("--fix");
}
this._flagArgs.add("--no-error-on-unmatched-pattern");
this.sortExtends = options.sortExtends ?? new ExtendsDefaultOrder();
this.eslintTask = project.addTask("eslint", {
description: "Runs eslint against the codebase",
env: {
ESLINT_USE_FLAT_CONFIG: "false",
NODE_NO_WARNINGS: "1", // Suppress eslint warning about legacy config format, as it just confuses users. This will suppress all node warnings, but in practice users cannot action warnings from eslint anyway.
},
});
this.updateTask();
project.testTask.spawn(this.eslintTask);
// exclude some files
project.npmignore?.exclude("/.eslintrc.json");
this._formattingRules = {
// Style
"@stylistic/indent": ["error", 2],
"@stylistic/quotes": ["error", "single", { avoidEscape: true }],
"@stylistic/comma-dangle": ["error", "always-multiline"], // ensures clean diffs, see https://medium.com/@nikgraf/why-you-should-enforce-dangling-commas-for-multiline-statements-d034c98e36f8
"@stylistic/comma-spacing": ["error", { before: false, after: true }], // space after, no space before
"@stylistic/no-multi-spaces": ["error", { ignoreEOLComments: false }], // no multi spaces
"@stylistic/array-bracket-spacing": ["error", "never"], // [1, 2, 3]
"@stylistic/array-bracket-newline": ["error", "consistent"], // enforce consistent line breaks between brackets
"@stylistic/object-curly-spacing": ["error", "always"], // { key: 'value' }
"@stylistic/object-curly-newline": [
"error",
{ multiline: true, consistent: true },
], // enforce consistent line breaks between braces
"@stylistic/object-property-newline": [
"error",
{ allowAllPropertiesOnSameLine: true },
], // enforce "same line" or "multiple line" on object properties
"@stylistic/keyword-spacing": ["error"], // require a space before & after keywords
"@stylistic/brace-style": ["error", "1tbs", { allowSingleLine: true }], // enforce one true brace style
"@stylistic/space-before-blocks": ["error"], // require space before blocks
// @see https://github.com/typescript-eslint/typescript-eslint/issues/8072
"@stylistic/member-delimiter-style": ["error"],
// Require semicolons
"@stylistic/semi": ["error", "always"],
// Max line lengths
"@stylistic/max-len": [
"error",
{
code: 150,
ignoreUrls: true, // Most common reason to disable it
ignoreStrings: true, // These are not fantastic but necessary for error messages
ignoreTemplateLiterals: true,
ignoreComments: true,
ignoreRegExpLiterals: true,
},
],
// Don't unnecessarily quote properties
"@stylistic/quote-props": ["error", "consistent-as-needed"],
// Required spacing in property declarations (copied from TSLint, defaults are good)
"@stylistic/key-spacing": ["error"],
// No multiple empty lines
"@stylistic/no-multiple-empty-lines": ["error"],
// Useless diff results
"@stylistic/no-trailing-spaces": ["error"],
};
this.rules = {
// require curly braces for multiline control statements
curly: ["error", "multi-line", "consistent"],
// Require use of the `import { foo } from 'bar';` form instead of `import foo = require('bar');`
"@typescript-eslint/no-require-imports": "error",
// Require all imported dependencies are actually declared in package.json
"import/no-extraneous-dependencies": [
"error",
{
// Only allow importing devDependencies from "devdirs".
devDependencies: () => this.renderDevDepsAllowList(),
optionalDependencies: false, // Disallow importing optional dependencies (those shouldn't be in use in the project)
peerDependencies: true, // Allow importing peer dependencies (that aren't also direct dependencies)
},
],
// Require all imported libraries actually resolve (!!required for import/no-extraneous-dependencies to work!!)
"import/no-unresolved": ["error"],
// Require an ordering on all imports
"import/order": [
"warn",
{
groups: ["builtin", "external"],
alphabetize: { order: "asc", caseInsensitive: true },
},
],
// Cannot import from the same module twice
"import/no-duplicates": ["error"],
// Cannot shadow names
"no-shadow": ["off"],
"@typescript-eslint/no-shadow": "error",
// One of the easiest mistakes to make
"@typescript-eslint/no-floating-promises": "error",
// Make sure that inside try/catch blocks, promises are 'return await'ed
// (must disable the base rule as it can report incorrect errors)
"no-return-await": ["off"],
"@typescript-eslint/return-await": "error",
// Must use foo.bar instead of foo['bar'] if possible
"dot-notation": ["error"],
// Are you sure | is not a typo for || ?
"no-bitwise": ["error"],
// Member ordering
"@typescript-eslint/member-ordering": [
"error",
{
default: [
"public-static-field",
"public-static-method",
"protected-static-field",
"protected-static-method",
"private-static-field",
"private-static-method",
"field",
// Constructors
"constructor", // = ["public-constructor", "protected-constructor", "private-constructor"]
// Methods
"method",
],
},
],
};
this.ignorePatterns = options.ignorePatterns ?? [
"*.js",
"*.d.ts",
"node_modules/",
"*.generated.ts",
"coverage",
];
const tsconfig = options.tsconfigPath ?? "./tsconfig.json";
const projectService = options.projectService ?? false;
this.addPlugins("@typescript-eslint");
this.addPlugins("import");
this.addExtends("plugin:import/typescript");
this.config = {
env: {
jest: true,
node: true,
},
root: true,
plugins: this._plugins,
parser: "@typescript-eslint/parser",
parserOptions: {
ecmaVersion: 2018,
sourceType: "module",
// Either let typescript-eslint resolve the nearest tsconfig per file
// (project service), or pin all files to a single project.
...(projectService
? { projectService: () => this.renderProjectService(tsconfig) }
: { project: tsconfig }),
},
extends: () => Array.from(this._extends).sort((a, b) => this.sortExtends.compare(a, b)),
settings: {
"import/parsers": {
"@typescript-eslint/parser": [".ts", ".tsx"],
},
"import/resolver": {
...(options.aliasMap && {
alias: {
map: Object.entries(options.aliasMap).map(([k, v]) => [k, v]),
extensions: options.aliasExtensions,
},
}),
node: {},
typescript: {
project: tsconfig,
...(options.tsAlwaysTryTypes !== false && { alwaysTryTypes: true }),
},
},
},
ignorePatterns: this.ignorePatterns,
rules: () => ({ ...this._formattingRules, ...this.rules }),
overrides: this.overrides,
};
if (options.yaml) {
this.file = new yaml_1.YamlFile(project, ".eslintrc.yml", {
obj: this.config,
marker: true,
});
}
else {
this.file = new json_1.JsonFile(project, ".eslintrc.json", {
obj: this.config,
// https://eslint.org/docs/latest/user-guide/configuring/configuration-files#comments-in-configuration-files
marker: true,
allowComments: true,
});
}
// if the user enabled prettier explicitly _or_ if the project has a
// `Prettier` component, we shall tweak our configuration accordingly.
if (options.prettier || prettier_1.Prettier.of(project)) {
this.enablePrettier();
}
else {
this.nodeProject.addDevDeps("@stylistic/eslint-plugin@^2");
this.addPlugins("@stylistic");
}
}
/**
* Returns an immutable copy of the lintPatterns being used by this eslint configuration.
*/
get lintPatterns() {
if (this._lintPatterns && this._lintPatterns.size > 0) {
return [...this._lintPatterns];
}
return [];
}
/**
* Add a file, glob pattern or directory with source files to lint (e.g. [ "src" ])
*/
addLintPattern(pattern) {
this._lintPatterns.add(pattern);
this.updateTask();
}
/**
* Add an eslint rule.
*/
addRules(rules) {
for (const [k, v] of Object.entries(rules)) {
this.rules[k] = v;
}
}
/**
* Adds an eslint plugin
* @param plugins The names of plugins to add
*/
addPlugins(...plugins) {
for (const plugin of plugins) {
this._plugins.add(plugin);
}
}
/**
* Add an eslint override.
*/
addOverride(override) {
this.overrides.push(override);
}
/**
* Do not lint these files.
*/
addIgnorePattern(pattern) {
this.ignorePatterns.push(pattern);
}
/**
* Adds an `extends` item to the eslint configuration.
* @param extendList The list of "extends" to add.
*/
addExtends(...extendList) {
for (const extend of extendList) {
this._extends.add(extend);
}
}
/**
* Add a glob file pattern which allows importing dev dependencies.
* @param pattern glob pattern.
*/
allowDevDeps(pattern) {
this._allowDevDeps.add(pattern);
}
/**
* Allow files matching these patterns to be linted with the typescript-eslint
* "default project" when they are not included by any `tsconfig.json`.
*
* Only has an effect when the project service is enabled (see
* `EslintOptions.projectService`). This is typically used for loose files
* that live outside `src`/`test` (e.g. `.projenrc.ts`).
*
* @see https://typescript-eslint.io/packages/parser/#allowdefaultproject
* @param patterns glob patterns, relative to the project root.
*/
allowDefaultProjectFiles(...patterns) {
for (const pattern of patterns) {
this._allowDefaultProject.add(pattern);
}
}
/**
* Render the value of `parserOptions.projectService`. When loose files have
* been registered via `allowDefaultProjectFiles`, an options object is
* emitted; otherwise the plain `true` shorthand is used.
* @internal
*/
renderProjectService(defaultProject) {
if (this._allowDefaultProject.size === 0) {
return true;
}
return {
allowDefaultProject: Array.from(this._allowDefaultProject),
defaultProject,
};
}
/**
* Enables prettier for code formatting.
*/
enablePrettier() {
this.nodeProject.addDevDeps("prettier", "eslint-plugin-prettier", "eslint-config-prettier");
this._formattingRules = {};
this.addExtends("plugin:prettier/recommended");
}
renderDevDepsAllowList() {
return Array.from(this._allowDevDeps);
}
/**
* Runs eslint once, right after the project is first created, so the generated code is linted (and auto-fixed) immediately.
*/
postProjectCreation(_initProject) {
this.nodeProject.tasks.runTask(this.eslintTask.name);
}
/**
* Update the task with the current list of lint patterns and file extensions
*/
updateTask() {
const taskExecCommand = "eslint";
const argv = [taskExecCommand];
if (this._fileExtensions.size > 0) {
argv.push("--ext", [...this._fileExtensions].join(","));
}
argv.push(...this._flagArgs);
argv.push("$@"); // External args go here
argv.push(...this._lintPatterns);
// read before resetting: it inspects the current step to preserve any
// external edits
const stepOptions = this.buildTaskStepOptions(taskExecCommand);
this.eslintTask.reset();
this.eslintTask.execArgs(argv, stepOptions);
}
/**
* In case of external editing of the eslint task step, we preserve those changes.
* Otherwise, we return the default task step options.
*
* @param taskExecCommand The command that the ESLint tasks executes
* @returns Either the externally edited, or the default task step options
*/
buildTaskStepOptions(taskExecCommand) {
const currentEslintTaskStep = this.eslintTask?.steps?.find((step) => step?.execArgs?.[0] === taskExecCommand ||
step?.exec?.startsWith?.(taskExecCommand));
if (currentEslintTaskStep) {
const { args, condition, cwd, env, name, receiveArgs } = currentEslintTaskStep;
return {
args,
condition,
cwd,
env,
name,
receiveArgs,
};
}
return {
receiveArgs: true,
};
}
}
exports.Eslint = Eslint;
/**
* A compare protocol tp sort the extends array in eslint config using known ESLint best practices.
*
* Places "prettier" plugins at the end of the array
*/
class ExtendsDefaultOrder {
// This is the order that ESLint best practices suggest
static ORDER = ["plugin:prettier/recommended", "prettier"];
compare(a, b) {
return (ExtendsDefaultOrder.ORDER.indexOf(a) -
ExtendsDefaultOrder.ORDER.indexOf(b));
}
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZXNsaW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2phdmFzY3JpcHQvZXNsaW50LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7QUFBQSx5Q0FBc0M7QUFFdEMsNENBQXlDO0FBRXpDLGtDQUFtQztBQUtuQyxrQ0FBbUM7QUF5Sm5DOztHQUVHO0FBQ0gsTUFBYSxNQUFPLFNBQVEscUJBQVM7O0lBQ25DOztPQUVHO0lBQ0ksTUFBTSxDQUFDLEVBQUUsQ0FBQyxPQUFnQjtRQUMvQixNQUFNLFFBQVEsR0FBRyxDQUFDLENBQVksRUFBZSxFQUFFLENBQUMsQ0FBQyxZQUFZLE1BQU0sQ0FBQztRQUNwRSxPQUFPLE9BQU8sQ0FBQyxVQUFVLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxDQUFDO0lBQzNDLENBQUM7SUFFRDs7T0FFRztJQUNhLElBQUksQ0FBYTtJQUVqQzs7T0FFRztJQUNhLEtBQUssQ0FBMEI7SUFFL0M7O09BRUc7SUFDYSxTQUFTLEdBQXFCLEVBQUUsQ0FBQztJQUVqRDs7T0FFRztJQUNhLFVBQVUsQ0FBTztJQUVqQzs7T0FFRztJQUNhLE1BQU0sQ0FBTTtJQUU1Qjs7T0FFRztJQUNhLGNBQWMsQ0FBVztJQUVqQyxnQkFBZ0IsQ0FBc0I7SUFDN0IsYUFBYSxDQUFjO0lBQzNCLG9CQUFvQixHQUFHLElBQUksR0FBRyxFQUFVLENBQUM7SUFDekMsUUFBUSxHQUFHLElBQUksR0FBRyxFQUFVLENBQUM7SUFDN0IsUUFBUSxHQUFHLElBQUksR0FBRyxFQUFVLENBQUM7SUFDN0IsZUFBZSxDQUFjO0lBQzdCLFNBQVMsQ0FBYztJQUN2QixhQUFhLENBQWM7SUFDM0IsV0FBVyxDQUFjO0lBQ3pCLFdBQVcsQ0FBaUI7SUFFN0MsWUFBWSxPQUFvQixFQUFFLE9BQXNCO1FBQ3RELEtBQUssQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUVmLElBQUksQ0FBQyxXQUFXLEdBQUcsT0FBTyxDQUFDO1FBRTNCLE9BQU8sQ0FBQyxVQUFV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QUF4ZUgsd0JBeWVDO0FBRUQ7Ozs7R0FJRztBQUNILE1BQU0sbUJBQW1CO0lBQ3ZCLHVEQUF1RDtJQUMvQyxNQUFNLENBQUMsS0FBSyxHQUFHLENBQUMsNkJBQTZCLEVBQUUsVUFBVSxDQUFDLENBQUM7SUFFNUQsT0FBTyxDQUFDLENBQVMsRUFBRSxDQUFTO1FBQ2pDLE9BQU8sQ0FDTCxtQkFBbUIsQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQztZQUNwQyxtQkFBbUIsQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxDQUNyQyxDQUFDO0lBQ0osQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IFByZXR0aWVyIH0gZnJvbSBcIi4vcHJldHRpZXJcIjtcbmltcG9ydCB0eXBlIHsgSUNvbXBhcmVTdHJpbmcgfSBmcm9tIFwiLi4vY29tcGFyZVwiO1xuaW1wb3J0IHsgQ29tcG9uZW50IH0gZnJvbSBcIi4uL2NvbXBvbmVudFwiO1xuaW1wb3J0IHR5cGUgeyBOb2RlUHJvamVjdCB9IGZyb20gXCIuLi9qYXZhc2NyaXB0XCI7XG5pbXBvcnQgeyBKc29uRmlsZSB9IGZyb20gXCIuLi9qc29uXCI7XG5pbXBvcnQgdHlwZSB7IE9iamVjdEZpbGUgfSBmcm9tIFwiLi4vb2JqZWN0LWZpbGVcIjtcbmltcG9ydCB0eXBlIHsgSW5pdFByb2plY3QsIFByb2plY3QgfSBmcm9tIFwiLi4vcHJvamVjdFwiO1xuaW1wb3J0IHR5cGUgeyBUYXNrIH0gZnJvbSBcIi4uL3Rhc2tcIjtcbmltcG9ydCB0eXBlIHsgVGFza1N0ZXBPcHRpb25zIH0gZnJvbSBcIi4uL3Rhc2stbW9kZWxcIjtcbmltcG9ydCB7IFlhbWxGaWxlIH0gZnJvbSBcIi4uL3lhbWxcIjtcblxuZXhwb3J0IGludGVyZmFjZSBFc2xpbnRPcHRpb25zIHtcbiAgLyoqXG4gICAqIFBhdGggdG8gYHRzY29uZmlnLmpzb25gIHdoaWNoIHNob3VsZCBiZSB1c2VkIGJ5IGVzbGludC5cbiAgICogQGRlZmF1bHQgXCIuL3RzY29uZmlnLmpzb25cIlxuICAgKi9cbiAgcmVhZG9ubHkgdHNjb25maWdQYXRoPzogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBVc2UgdGhlIHR5cGVzY3JpcHQtZXNsaW50IFwicHJvamVjdCBzZXJ2aWNlXCIgZm9yIHR5cGVkIGxpbnRpbmcgaW5zdGVhZCBvZiBhXG4gICAqIHNpbmdsZSBgcGFyc2VyT3B0aW9ucy5wcm9qZWN0YC5cbiAgICpcbiAgICogV2hlbiBlbmFibGVkLCB0eXBlc2NyaXB0LWVzbGludCByZXNvbHZlcyB0aGUgbmVhcmVzdCBgdHNjb25maWcuanNvbmAgZm9yXG4gICAqIGVhY2ggbGludGVkIGZpbGUgKHRoZSBzYW1lIHJlc29sdXRpb24gbW9kZWwgdXNlZCBieSB0aGUgVHlwZVNjcmlwdCBsYW5ndWFnZVxuICAgKiBzZXJ2aWNlIC8gYHRzc2VydmVyYCkuIFRoaXMgYWxsb3dzIGZpbGVzIGluIGRpZmZlcmVudCBkaXJlY3RvcmllcyAoZS5nLlxuICAgKiBgc3JjYCBhbmQgYHRlc3RgKSB0byBiZSBsaW50ZWQgYWdhaW5zdCB0aGUgYHRzY29uZmlnLmpzb25gIHRoYXQgYWN0dWFsbHlcbiAgICogaW5jbHVkZXMgdGhlbSwgd2l0aG91dCBtYWludGFpbmluZyBhIHNpbmdsZSBjb25maWcgdGhhdCBsaXN0cyBldmVyeSBmaWxlLlxuICAgKlxuICAgKiBSZXF1aXJlcyBgQHR5cGVzY3JpcHQtZXNsaW50LypgIHY4IG9yIG5ld2VyLlxuICAgKlxuICAgKiBAc2VlIGh0dHBzOi8vdHlwZXNjcmlwdC1lc2xpbnQuaW8vYmxvZy9wcm9qZWN0LXNlcnZpY2UvXG4gICAqIEBkZWZhdWx0IGZhbHNlXG4gICAqL1xuICByZWFkb25seSBwcm9qZWN0U2VydmljZT86IGJvb2xlYW47XG5cbiAgLyoqXG4gICAqIEZpbGVzIG9yIGdsb2IgcGF0dGVybnMgb3IgZGlyZWN0b3JpZXMgd2l0aCBzb3VyY2UgZmlsZXMgdG8gbGludCAoZS5nLiBbIFwic3JjXCIgXSlcbiAgICovXG4gIHJlYWRvbmx5IGRpcnM6IHN0cmluZ1tdO1xuXG4gIC8qKlxuICAgKiBGaWxlcyBvciBnbG9iIHBhdHRlcm5zIG9yIGRpcmVjdG9yaWVzIHdpdGggc291cmNlIGZpbGVzIHRoYXQgaW5jbHVkZSB0ZXN0cyBhbmQgYnVpbGQgdG9vbHNcbiAgICpcbiAgICogVGhlc2Ugc291cmNlcyBhcmUgbGludGVkIGJ1dCBtYXkgYWxzbyBpbXBvcnQgcGFja2FnZXMgZnJvbSBgZGV2RGVwZW5kZW5jaWVzYC5cbiAgICogQGRlZmF1bHQgW11cbiAgICovXG4gIHJlYWRvbmx5IGRldmRpcnM/OiBzdHJpbmdbXTtcbiAgLyoqXG4gICAqIEZpbGUgdHlwZXMgdGhhdCBzaG91bGQgYmUgbGludGVkIChlLmcuIFsgXCIuanNcIiwgXCIudHNcIiBdKVxuICAgKiBAZGVmYXVsdCBbXCIudHNcIl1cbiAgICovXG4gIHJlYWRvbmx5IGZpbGVFeHRlbnNpb25zPzogc3RyaW5nW107XG5cbiAgLyoqXG4gICAqIE9wdGlvbnMgZm9yIGVzbGludCBjb21tYW5kIGV4ZWN1dGVkIGJ5IGVzbGludCB0YXNrXG4gICAqL1xuICByZWFkb25seSBjb21tYW5kT3B0aW9ucz86IEVzbGludENvbW1hbmRPcHRpb25zO1xuXG4gIC8qKlxuICAgKiBMaXN0IG9mIGZpbGUgcGF0dGVybnMgdGhhdCBzaG91bGQgbm90IGJlIGxpbnRlZCwgdXNpbmcgdGhlIHNhbWUgc3ludGF4XG4gICAqIGFzIC5naXRpZ25vcmUgcGF0dGVybnMuXG4gICAqXG4gICAqIEBkZWZhdWx0IFsgJyouanMnLCAnKi5kLnRzJywgJ25vZGVfbW9kdWxlcy8nLCAnKi5nZW5lcmF0ZWQudHMnLCAnY292ZXJhZ2UnIF1cbiAgICovXG4gIHJlYWRvbmx5IGlnbm9yZVBhdHRlcm5zPzogc3RyaW5nW107XG5cbiAgLyoqXG4gICAqIEVuYWJsZSBwcmV0dGllciBmb3IgY29kZSBmb3JtYXR0aW5nXG4gICAqIEBkZWZhdWx0IGZhbHNlXG4gICAqL1xuICByZWFkb25seSBwcmV0dGllcj86IGJvb2xlYW47XG5cbiAgLyoqXG4gICAqIFRoZSBleHRlbmRzIGFycmF5IGluIGVzbGludCBpcyBvcmRlciBkZXBlbmRlbnQuXG4gICAqIFRoaXMgb3B0aW9uIGFsbG93cyB0byBzb3J0IHRoZSBleHRlbmRzIGFycmF5IGluIGFueSB3YXkgc2VlbiBmaXQuXG4gICAqXG4gICAqIEBkZWZhdWx0IC0gVXNlIGtub3duIEVTTGludCBiZXN0IHByYWN0aWNlcyB0byBwbGFjZSBcInByZXR0aWVyXCIgcGx1Z2lucyBhdCB0aGUgZW5kIG9mIHRoZSBhcnJheVxuICAgKi9cbiAgcmVhZG9ubHkgc29ydEV4dGVuZHM/OiBJQ29tcGFyZVN0cmluZztcblxuICAvKipcbiAgICogRW5hYmxlIGltcG9ydCBhbGlhcyBmb3IgbW9kdWxlIHBhdGhzXG4gICAqIEBkZWZhdWx0IHVuZGVmaW5lZFxuICAgKi9cbiAgcmVhZG9ubHkgYWxpYXNNYXA/OiB7IFtrZXk6IHN0cmluZ106IHN0cmluZyB9O1xuXG4gIC8qKlxuICAgKiBFbmFibGUgaW1wb3J0IGFsaWFzIGZvciBtb2R1bGUgcGF0aHNcbiAgICogQGRlZmF1bHQgdW5kZWZpbmVkXG4gICAqL1xuICByZWFkb25seSBhbGlhc0V4dGVuc2lvbnM/OiBzdHJpbmdbXTtcblxuICAvKipcbiAgICogQWx3YXlzIHRyeSB0byByZXNvbHZlIHR5cGVzIHVuZGVyIGA8cm9vdD5AdHlwZXNgIGRpcmVjdG9yeSBldmVuIGl0IGRvZXNuJ3QgY29udGFpbiBhbnkgc291cmNlIGNvZGUuXG4gICAqIFRoaXMgcHJldmVudHMgYGltcG9ydC9uby11bnJlc29sdmVkYCBlc2xpbnQgZXJyb3JzIHdoZW4gaW1wb3J0aW5nIGEgYEB0eXBlcy8qYCBtb2R1bGUgdGhhdCB3b3VsZCBvdGhlcndpc2UgcmVtYWluIHVucmVzb2x2ZWQuXG4gICAqIEBkZWZhdWx0IHRydWVcbiAgICovXG4gIHJlYWRvbmx5IHRzQWx3YXlzVHJ5VHlwZXM/OiBib29sZWFuO1xuXG4gIC8qKlxuICAgKiBXcml0ZSBlc2xpbnQgY29uZmlndXJhdGlvbiBhcyBZQU1MIGluc3RlYWQgb2YgSlNPTlxuICAgKiBAZGVmYXVsdCBmYWxzZVxuICAgKi9cbiAgcmVhZG9ubHkgeWFtbD86IGJvb2xlYW47XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgRXNsaW50Q29tbWFuZE9wdGlvbnMge1xuICAvKipcbiAgICogV2hldGhlciB0byBmaXggZXNsaW50IGlzc3VlcyB3aGVuIHJ1bm5pbmcgdGhlIGVzbGludCB0YXNrXG4gICAqIEBkZWZhdWx0IHRydWVcbiAgICovXG4gIHJlYWRvbmx5IGZpeD86IGJvb2xlYW47XG5cbiAgLyoqXG4gICAqIEV4dHJhIGZsYWcgYXJndW1lbnRzIHRvIHBhc3MgdG8gZXNsaW50IGNvbW1hbmRcbiAgICpcbiAgICogRWFjaCBlbGVtZW50IGlzIHBhc3NlZCB0byBlc2xpbnQgYXMgYSBzaW5nbGUgYXJndW1lbnQsIGV4YWN0bHkgYXMgZ2l2ZW46IG5vXG4gICAqIHNoZWxsIHBhcnNlcyB0aGVzZSwgc28gYSBmbGFnIGFuZCBpdHMgdmFsdWUgbmVlZCBzZXBhcmF0ZSBlbGVtZW50c1xuICAgKiAoYFtcIi0tcnVsZXNkaXJcIiwgXCJteSBydWxlc1wiXWAsIG5vdCBgW1wiLS1ydWxlc2RpciAnbXkgcnVsZXMnXCJdYCkgYW5kIHZhbHVlc1xuICAgKiBtdXN0IG5vdCBiZSBxdW90ZWQuXG4gICAqXG4gICAqIEBleGFtcGxlIFtcIi0tY2FjaGVcIiwgXCItLW1heC13YXJuaW5ncz0wXCJdXG4gICAqL1xuICByZWFkb25seSBleHRyYUFyZ3M/OiBzdHJpbmdbXTtcbn1cblxuLyoqXG4gKiBlc2xpbnQgcnVsZXMgb3ZlcnJpZGVcbiAqL1xuZXhwb3J0IGludGVyZmFjZSBFc2xpbnRPdmVycmlkZSB7XG4gIC8qKlxuICAgKiBGaWxlcyBvciBmaWxlIHBhdHRlcm5zIG9uIHdoaWNoIHRvIGFwcGx5IHRoZSBvdmVycmlkZVxuICAgKi9cbiAgcmVhZG9ubHkgZmlsZXM6IHN0cmluZ1tdO1xuXG4gIC8qKlxuICAgKiBQYXR0ZXJuKHMpIHRvIGV4Y2x1ZGUgZnJvbSB0aGlzIG92ZXJyaWRlLlxuICAgKiBJZiBhIGZpbGUgbWF0Y2hlcyBhbnkgb2YgdGhlIGV4Y2x1ZGVkIHBhdHRlcm5zLCB0aGUgY29uZmlndXJhdGlvbiB3b27igJl0IGFwcGx5LlxuICAgKi9cbiAgcmVhZG9ubHkgZXhjbHVkZWRGaWxlcz86IHN0cmluZ1tdO1xuXG4gIC8qKlxuICAgKiBUaGUgb3ZlcnJpZGRlbiBydWxlc1xuICAgKi9cbiAgcmVhZG9ubHkgcnVsZXM/OiB7IFtydWxlOiBzdHJpbmddOiBhbnkgfTtcblxuICAvKipcbiAgICogVGhlIG92ZXJyaWRkZW4gcGFyc2VyXG4gICAqL1xuICByZWFkb25seSBwYXJzZXI/OiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIENvbmZpZyhzKSB0byBleHRlbmQgaW4gdGhpcyBvdmVycmlkZVxuICAgKi9cbiAgcmVhZG9ubHkgZXh0ZW5kcz86IHN0cmluZ1tdO1xuXG4gIC8qKlxuICAgKiBgcGx1Z2luc2Agb3ZlcnJpZGVcbiAgICovXG4gIHJlYWRvbmx5IHBsdWdpbnM/OiBzdHJpbmdbXTtcbn1cblxuLyoqXG4gKiBSZXByZXNlbnRzIGVzbGludCBjb25maWd1cmF0aW9uLlxuICovXG5leHBvcnQgY2xhc3MgRXNsaW50IGV4dGVuZHMgQ29tcG9uZW50IHtcbiAgLyoqXG4gICAqIFJldHVybnMgdGhlIHNpbmdsZXRvbiBFc2xpbnQgY29tcG9uZW50IG9mIGEgcHJvamVjdCBvciB1bmRlZmluZWQgaWYgdGhlcmUgaXMgbm9uZS5cbiAgICovXG4gIHB1YmxpYyBzdGF0aWMgb2YocHJvamVjdDogUHJvamVjdCk6IEVzbGludCB8IHVuZGVmaW5lZCB7XG4gICAgY29uc3QgaXNFc2xpbnQgPSAoYzogQ29tcG9uZW50KTogYyBpcyBFc2xpbnQgPT4gYyBpbnN0YW5jZW9mIEVzbGludDtcbiAgICByZXR1cm4gcHJvamVjdC5jb21wb25lbnRzLmZpbmQoaXNFc2xpbnQpO1xuICB9XG5cbiAgLyoqXG4gICAqIFRoZSB1bmRlcmx5aW5nIGNvbmZpZyBmaWxlXG4gICAqL1xuICBwdWJsaWMgcmVhZG9ubHkgZmlsZTogT2JqZWN0RmlsZTtcblxuICAvKipcbiAgICogZXNsaW50IHJ1bGVzLlxuICAgKi9cbiAgcHVibGljIHJlYWRvbmx5IHJ1bGVzOiB7IFtydWxlOiBzdHJpbmddOiBhbnkgfTtcblxuICAvKipcbiAgICogZXNsaW50IG92ZXJyaWRlcy5cbiAgICovXG4gIHB1YmxpYyByZWFkb25seSBvdmVycmlkZXM6IEVzbGludE92ZXJyaWRlW10gPSBbXTtcblxuICAvKipcbiAgICogZXNsaW50IHRhc2suXG4gICAqL1xuICBwdWJsaWMgcmVhZG9ubHkgZXNsaW50VGFzazogVGFzaztcblxuICAvKipcbiAgICogRGlyZWN0IGFjY2VzcyB0byB0aGUgZXNsaW50IGNvbmZpZ3VyYXRpb24gKGVzY2FwZSBoYXRjaClcbiAgICovXG4gIHB1YmxpYyByZWFkb25seSBjb25maWc6IGFueTtcblxuICAvKipcbiAgICogRmlsZSBwYXR0ZXJucyB0aGF0IHNob3VsZCBub3QgYmUgbGludGVkXG4gICAqL1xuICBwdWJsaWMgcmVhZG9ubHkgaWdub3JlUGF0dGVybnM6IHN0cmluZ1tdO1xuXG4gIHByaXZhdGUgX2Zvcm1hdHRpbmdSdWxlczogUmVjb3JkPHN0cmluZywgYW55PjtcbiAgcHJpdmF0ZSByZWFkb25seSBfYWxsb3dEZXZEZXBzOiBTZXQ8c3RyaW5nPjtcbiAgcHJpdmF0ZSByZWFkb25seSBfYWxsb3dEZWZhdWx0UHJvamVjdCA9IG5ldyBTZXQ8c3RyaW5nPigpO1xuICBwcml2YXRlIHJlYWRvbmx5IF9wbHVnaW5zID0gbmV3IFNldDxzdHJpbmc+KCk7XG4gIHByaXZhdGUgcmVhZG9ubHkgX2V4dGVuZHMgPSBuZXcgU2V0PHN0cmluZz4oKTtcbiAgcHJpdmF0ZSByZWFkb25seSBfZmlsZUV4dGVuc2lvbnM6IFNldDxzdHJpbmc+O1xuICBwcml2YXRlIHJlYWRvbmx5IF9mbGFnQXJnczogU2V0PHN0cmluZz47XG4gIHByaXZhdGUgcmVhZG9ubHkgX2xpbnRQYXR0ZXJuczogU2V0PHN0cmluZz47XG4gIHByaXZhdGUgcmVhZG9ubHkgbm9kZVByb2plY3Q6IE5vZGVQcm9qZWN0O1xuICBwcml2YXRlIHJlYWRvbmx5IHNvcnRFeHRlbmRzOiBJQ29tcGFyZVN0cmluZztcblxuICBjb25zdHJ1Y3Rvcihwcm9qZWN0OiBOb2RlUHJvamVjdCwgb3B0aW9uczogRXNsaW50T3B0aW9ucykge1xuICAgIHN1cGVyKHByb2plY3QpO1xuXG4gICAgdGhpcy5ub2RlUHJvamVjdCA9IHByb2plY3Q7XG5cbiAgICBwcm9qZWN0LmFkZERldkRlcHMoXG4gICAgICBcImVzbGludEBeOVwiLFxuICAgICAgXCJAdHlwZXNjcmlwdC1lc2xpbnQvZXNsaW50LXBsdWdpbkBeOFwiLFxuICAgICAgXCJAdHlwZXNjcmlwdC1lc2xpbnQvcGFyc2VyQF44XCIsXG4gICAgICBcImVzbGludC1pbXBvcnQtcmVzb2x2ZXItdHlwZXNjcmlwdFwiLFxuICAgICAgXCJlc2xpbnQtcGx1Z2luLWltcG9ydFwiLFxuICAgICk7XG5cbiAgICBpZiAob3B0aW9ucy5hbGlhc01hcCkge1xuICAgICAgcHJvamVjdC5hZGREZXZEZXBzKFwiZXNsaW50LWltcG9ydC1yZXNvbHZlci1hbGlhc1wiKTtcbiAgICB9XG5cbiAgICBjb25zdCBkZXZkaXJzID0gb3B0aW9ucy5kZXZkaXJzID8/IFtdO1xuXG4gICAgdGhpcy5fbGludFBhdHRlcm5zID0gbmV3IFNldChbLi4ub3B0aW9ucy5kaXJzLCAuLi5kZXZkaXJzXSk7XG4gICAgdGhpcy5fZmlsZUV4dGVuc2lvbnMgPSBuZXcgU2V0KG9wdGlvbnMuZmlsZUV4dGVuc2lvbnMgPz8gW1wiLnRzXCJdKTtcblxuICAgIHRoaXMuX2FsbG93RGV2RGVwcyA9IG5ldyBTZXQoKGRldmRpcnMgPz8gW10pLm1hcCgoZGlyKSA9PiBgKiovJHtkaXJ9LyoqYCkpO1xuXG4gICAgY29uc3QgY29tbWFuZE9wdGlvbnMgPSBvcHRpb25zLmNvbW1hbmRPcHRpb25zID8/IHt9O1xuICAgIGNvbnN0IHsgZml4ID0gdHJ1ZSwgZXh0cmFBcmdzOiBleHRyYUZsYWdBcmdzID0gW10gfSA9IGNvbW1hbmRPcHRpb25zO1xuICAgIHRoaXMuX2ZsYWdBcmdzID0gbmV3IFNldChleHRyYUZsYWdBcmdzKTtcbiAgICBpZiAoZml4KSB7XG4gICAgICB0aGlzLl9mbGFnQXJncy5hZGQoXCItLWZpeFwiKTtcbiAgICB9XG4gICAgdGhpcy5fZmxhZ0FyZ3MuYWRkKFwiLS1uby1lcnJvci1vbi11bm1hdGNoZWQtcGF0dGVyblwiKTtcblxuICAgIHRoaXMuc29ydEV4dGVuZHMgPSBvcHRpb25zLnNvcnRFeHRlbmRzID8/IG5ldyBFeHRlbmRzRGVmYXVsdE9yZGVyKCk7XG5cbiAgICB0aGlzLmVzbGludFRhc2sgPSBwcm9qZWN0LmFkZFRhc2soXCJlc2xpbnRcIiwge1xuICAgICAgZGVzY3JpcHRpb246IFwiUnVucyBlc2xpbnQgYWdhaW5zdCB0aGUgY29kZWJhc2VcIixcbiAgICAgIGVudjoge1xuICAgICAgICBFU0xJTlRfVVNFX0ZMQVRfQ09ORklHOiBcImZhbHNlXCIsXG4gICAgICAgIE5PREVfTk9fV0FSTklOR1M6IFwiMVwiLCAvLyBTdXBwcmVzcyBlc2xpbnQgd2FybmluZyBhYm91dCBsZWdhY3kgY29uZmlnIGZvcm1hdCwgYXMgaXQganVzdCBjb25mdXNlcyB1c2Vycy4gVGhpcyB3aWxsIHN1cHByZXNzIGFsbCBub2RlIHdhcm5pbmdzLCBidXQgaW4gcHJhY3RpY2UgdXNlcnMgY2Fubm90IGFjdGlvbiB3YXJuaW5ncyBmcm9tIGVzbGludCBhbnl3YXkuXG4gICAgICB9LFxuICAgIH0pO1xuICAgIHRoaXMudXBkYXRlVGFzaygpO1xuXG4gICAgcHJvamVjdC50ZXN0VGFzay5zcGF3bih0aGlzLmVzbGludFRhc2spO1xuXG4gICAgLy8gZXhjbHVkZSBzb21lIGZpbGVzXG4gICAgcHJvamVjdC5ucG1pZ25vcmU/LmV4Y2x1ZGUoXCIvLmVzbGludHJjLmpzb25cIik7XG5cbiAgICB0aGlzLl9mb3JtYXR0aW5nUnVsZXMgPSB7XG4gICAgICAvLyBTdHlsZVxuICAgICAgXCJAc3R5bGlzdGljL2luZGVudFwiOiBbXCJlcnJvclwiLCAyXSxcbiAgICAgIFwiQHN0eWxpc3RpYy9xdW90ZXNcIjogW1wiZXJyb3JcIiwgXCJzaW5nbGVcIiwgeyBhdm9pZEVzY2FwZTogdHJ1ZSB9XSxcbiAgICAgIFwiQHN0eWxpc3RpYy9jb21tYS1kYW5nbGVcIjogW1wiZXJyb3JcIiwgXCJhbHdheXMtbXVsdGlsaW5lXCJdLCAvLyBlbnN1cmVzIGNsZWFuIGRpZmZzLCBzZWUgaHR0cHM6Ly9tZWRpdW0uY29tL0BuaWtncmFmL3doeS15b3Utc2hvdWxkLWVuZm9yY2UtZGFuZ2xpbmctY29tbWFzLWZvci1tdWx0aWxpbmUtc3RhdGVtZW50cy1kMDM0Yzk4ZTM2ZjhcbiAgICAgIFwiQHN0eWxpc3RpYy9jb21tYS1zcGFjaW5nXCI6IFtcImVycm9yXCIsIHsgYmVmb3JlOiBmYWxzZSwgYWZ0ZXI6IHRydWUgfV0sIC8vIHNwYWNlIGFmdGVyLCBubyBzcGFjZSBiZWZvcmVcbiAgICAgIFwiQHN0eWxpc3RpYy9uby1tdWx0aS1zcGFjZXNcIjogW1wiZXJyb3JcIiwgeyBpZ25vcmVFT0xDb21tZW50czogZmFsc2UgfV0sIC8vIG5vIG11bHRpIHNwYWNlc1xuICAgICAgXCJAc3R5bGlzdGljL2FycmF5LWJyYWNrZXQtc3BhY2luZ1wiOiBbXCJlcnJvclwiLCBcIm5ldmVyXCJdLCAvLyBbMSwgMiwgM11cbiAgICAgIFwiQHN0eWxpc3RpYy9hcnJheS1icmFja2V0LW5ld2xpbmVcIjogW1wiZXJyb3JcIiwgXCJjb25zaXN0ZW50XCJdLCAvLyBlbmZvcmNlIGNvbnNpc3RlbnQgbGluZSBicmVha3MgYmV0d2VlbiBicmFja2V0c1xuICAgICAgXCJAc3R5bGlzdGljL29iamVjdC1jdXJseS1zcGFjaW5nXCI6IFtcImVycm9yXCIsIFwiYWx3YXlzXCJdLCAvLyB7IGtleTogJ3ZhbHVlJyB9XG4gICAgICBcIkBzdHlsaXN0aWMvb2JqZWN0LWN1cmx5LW5ld2xpbmVcIjogW1xuICAgICAgICBcImVycm9yXCIsXG4gICAgICAgIHsgbXVsdGlsaW5lOiB0cnVlLCBjb25zaXN0ZW50OiB0cnVlIH0sXG4gICAgICBdLCAvLyBlbmZvcmNlIGNvbnNpc3RlbnQgbGluZSBicmVha3MgYmV0d2VlbiBicmFjZXNcbiAgICAgIFwiQHN0eWxpc3RpYy9vYmplY3QtcHJvcGVydHktbmV3bGluZVwiOiBbXG4gICAgICAgIFwiZXJyb3JcIixcbiAgICAgICAgeyBhbGxvd0FsbFByb3BlcnRpZXNPblNhbWVMaW5lOiB0cnVlIH0sXG4gICAgICBdLCAvLyBlbmZvcmNlIFwic2FtZSBsaW5lXCIgb3IgXCJtdWx0aXBsZSBsaW5lXCIgb24gb2JqZWN0IHByb3BlcnRpZXNcbiAgICAgIFwiQHN0eWxpc3RpYy9rZXl3b3JkLXNwYWNpbmdcIjogW1wiZXJyb3JcIl0sIC8vIHJlcXVpcmUgYSBzcGFjZSBiZWZvcmUgJiBhZnRlciBrZXl3b3Jkc1xuICAgICAgXCJAc3R5bGlzdGljL2JyYWNlLXN0eWxlXCI6IFtcImVycm9yXCIsIFwiMXRic1wiLCB7IGFsbG93U2luZ2xlTGluZTogdHJ1ZSB9XSwgLy8gZW5mb3JjZSBvbmUgdHJ1ZSBicmFjZSBzdHlsZVxuICAgICAgXCJAc3R5bGlzdGljL3NwYWNlLWJlZm9yZS1ibG9ja3NcIjogW1wiZXJyb3JcIl0sIC8vIHJlcXVpcmUgc3BhY2UgYmVmb3JlIGJsb2Nrc1xuICAgICAgLy8gQHNlZSBodHRwczovL2dpdGh1Yi5jb20vdHlwZXNjcmlwdC1lc2xpbnQvdHlwZXNjcmlwdC1lc2xpbnQvaXNzdWVzLzgwNzJcbiAgICAgIFwiQHN0eWxpc3RpYy9tZW1iZXItZGVsaW1pdGVyLXN0eWxlXCI6IFtcImVycm9yXCJdLFxuXG4gICAgICAvLyBSZXF1aXJlIHNlbWljb2xvbnNcbiAgICAgIFwiQHN0eWxpc3RpYy9zZW1pXCI6IFtcImVycm9yXCIsIFwiYWx3YXlzXCJdLFxuXG4gICAgICAvLyBNYXggbGluZSBsZW5ndGhzXG4gICAgICBcIkBzdHlsaXN0aWMvbWF4LWxlblwiOiBbXG4gICAgICAgIFwiZXJyb3JcIixcbiAgICAgICAge1xuICAgICAgICAgIGNvZGU6IDE1MCxcbiAgICAgICAgICBpZ25vcmVVcmxzOiB0cnVlLCAvLyBNb3N0IGNvbW1vbiByZWFzb24gdG8gZGlzYWJsZSBpdFxuICAgICAgICAgIGlnbm9yZVN0cmluZ3M6IHRydWUsIC8vIFRoZXNlIGFyZSBub3QgZmFudGFzdGljIGJ1dCBuZWNlc3NhcnkgZm9yIGVycm9yIG1lc3NhZ2VzXG4gICAgICAgICAgaWdub3JlVGVtcGxhdGVMaXRlcmFsczogdHJ1ZSxcbiAgICAgICAgICBpZ25vcmVDb21tZW50czogdHJ1ZSxcbiAgICAgICAgICBpZ25vcmVSZWdFeHBMaXRlcmFsczogdHJ1ZSxcbiAgICAgICAgfSxcbiAgICAgIF0sXG5cbiAgICAgIC8vIERvbid0IHVubmVjZXNzYXJpbHkgcXVvdGUgcHJvcGVydGllc1xuICAgICAgXCJAc3R5bGlzdGljL3F1b3RlLXByb3BzXCI6IFtcImVycm9yXCIsIFwiY29uc2lzdGVudC1hcy1uZWVkZWRcIl0sXG5cbiAgICAgIC8vIFJlcXVpcmVkIHNwYWNpbmcgaW4gcHJvcGVydHkgZGVjbGFyYXRpb25zIChjb3BpZWQgZnJvbSBUU0xpbnQsIGRlZmF1bHRzIGFyZSBnb29kKVxuICAgICAgXCJAc3R5bGlzdGljL2tleS1zcGFjaW5nXCI6IFtcImVycm9yXCJdLFxuXG4gICAgICAvLyBObyBtdWx0aXBsZSBlbXB0eSBsaW5lc1xuICAgICAgXCJAc3R5bGlzdGljL25vLW11bHRpcGxlLWVtcHR5LWxpbmVzXCI6IFtcImVycm9yXCJdLFxuXG4gICAgICAvLyBVc2VsZXNzIGRpZmYgcmVzdWx0c1xuICAgICAgXCJAc3R5bGlzdGljL25vLXRyYWlsaW5nLXNwYWNlc1wiOiBbXCJlcnJvclwiXSxcbiAgICB9O1xuXG4gICAgdGhpcy5ydWxlcyA9IHtcbiAgICAgIC8vIHJlcXVpcmUgY3VybHkgYnJhY2VzIGZvciBtdWx0aWxpbmUgY29udHJvbCBzdGF0ZW1lbnRzXG4gICAgICBjdXJseTogW1wiZXJyb3JcIiwgXCJtdWx0aS1saW5lXCIsIFwiY29uc2lzdGVudFwiXSxcblxuICAgICAgLy8gUmVxdWlyZSB1c2Ugb2YgdGhlIGBpbXBvcnQgeyBmb28gfSBmcm9tICdiYXInO2AgZm9ybSBpbnN0ZWFkIG9mIGBpbXBvcnQgZm9vID0gcmVxdWlyZSgnYmFyJyk7YFxuICAgICAgXCJAdHlwZXNjcmlwdC1lc2xpbnQvbm8tcmVxdWlyZS1pbXBvcnRzXCI6IFwiZXJyb3JcIixcblxuICAgICAgLy8gUmVxdWlyZSBhbGwgaW1wb3J0ZWQgZGVwZW5kZW5jaWVzIGFyZSBhY3R1YWxseSBkZWNsYXJlZCBpbiBwYWNrYWdlLmpzb25cbiAgICAgIFwiaW1wb3J0L25vLWV4dHJhbmVvdXMtZGVwZW5kZW5jaWVzXCI6IFtcbiAgICAgICAgXCJlcnJvclwiLFxuICAgICAgICB7XG4gICAgICAgICAgLy8gT25seSBhbGxvdyBpbXBvcnRpbmcgZGV2RGVwZW5kZW5jaWVzIGZyb20gXCJkZXZkaXJzXCIuXG4gICAgICAgICAgZGV2RGVwZW5kZW5jaWVzOiAoKSA9PiB0aGlzLnJlbmRlckRldkRlcHNBbGxvd0xpc3QoKSxcbiAgICAgICAgICBvcHRpb25hbERlcGVuZGVuY2llczogZmFsc2UsIC8vIERpc2FsbG93IGltcG9ydGluZyBvcHRpb25hbCBkZXBlbmRlbmNpZXMgKHRob3NlIHNob3VsZG4ndCBiZSBpbiB1c2UgaW4gdGhlIHByb2plY3QpXG4gICAgICAgICAgcGVlckRlcGVuZGVuY2llczogdHJ1ZSwgLy8gQWxsb3cgaW1wb3J0aW5nIHBlZXIgZGVwZW5kZW5jaWVzICh0aGF0IGFyZW4ndCBhbHNvIGRpcmVjdCBkZXBlbmRlbmNpZXMpXG4gICAgICAgIH0sXG4gICAgICBdLFxuXG4gICAgICAvLyBSZXF1aXJlIGFsbCBpbXBvcnRlZCBsaWJyYXJpZXMgYWN0dWFsbHkgcmVzb2x2ZSAoISFyZXF1aXJlZCBmb3IgaW1wb3J0L25vLWV4dHJhbmVvdXMtZGVwZW5kZW5jaWVzIHRvIHdvcmshISlcbiAgICAgIFwiaW1wb3J0L25vLXVucmVzb2x2ZWRcIjogW1wiZXJyb3JcIl0sXG5cbiAgICAgIC8vIFJlcXVpcmUgYW4gb3JkZXJpbmcgb24gYWxsIGltcG9ydHNcbiAgICAgIFwiaW1wb3J0L29yZGVyXCI6IFtcbiAgICAgICAgXCJ3YXJuXCIsXG4gICAgICAgIHtcbiAgICAgICAgICBncm91cHM6IFtcImJ1aWx0aW5cIiwgXCJleHRlcm5hbFwiXSxcbiAgICAgICAgICBhbHBoYWJldGl6ZTogeyBvcmRlcjogXCJhc2NcIiwgY2FzZUluc2Vuc2l0aXZlOiB0cnVlIH0sXG4gICAgICAgIH0sXG4gICAgICBdLFxuXG4gICAgICAvLyBDYW5ub3QgaW1wb3J0IGZyb20gdGhlIHNhbWUgbW9kdWxlIHR3aWNlXG4gICAgICBcImltcG9ydC9uby1kdXBsaWNhdGVzXCI6IFtcImVycm9yXCJdLFxuXG4gICAgICAvLyBDYW5ub3Qgc2hhZG93IG5hbWVzXG4gICAgICBcIm5vLXNoYWRvd1wiOiBbXCJvZmZcIl0sXG4gICAgICBcIkB0eXBlc2NyaXB0LWVzbGludC9uby1zaGFkb3dcIjogXCJlcnJvclwiLFxuICAgICAgLy8gT25lIG9mIHRoZSBlYXNpZXN0IG1pc3Rha2VzIHRvIG1ha2VcbiAgICAgIFwiQHR5cGVzY3JpcHQtZXNsaW50L25vLWZsb2F0aW5nLXByb21pc2VzXCI6IFwiZXJyb3JcIixcblxuICAgICAgLy8gTWFrZSBzdXJlIHRoYXQgaW5zaWRlIHRyeS9jYXRjaCBibG9ja3MsIHByb21pc2VzIGFyZSAncmV0dXJuIGF3YWl0J2VkXG4gICAgICAvLyAobXVzdCBkaXNhYmxlIHRoZSBiYXNlIHJ1bGUgYXMgaXQgY2FuIHJlcG9ydCBpbmNvcnJlY3QgZXJyb3JzKVxuICAgICAgXCJuby1yZXR1cm4tYXdhaXRcIjogW1wib2ZmXCJdLFxuICAgICAgXCJAdHlwZXNjcmlwdC1lc2xpbnQvcmV0dXJuLWF3YWl0XCI6IFwiZXJyb3JcIixcblxuICAgICAgLy8gTXVzdCB1c2UgZm9vLmJhciBpbnN0ZWFkIG9mIGZvb1snYmFyJ10gaWYgcG9zc2libGVcbiAgICAgIFwiZG90LW5vdGF0aW9uXCI6IFtcImVycm9yXCJdLFxuXG4gICAgICAvLyBBcmUgeW91IHN1cmUgfCBpcyBub3QgYSB0eXBvIGZvciB8fCA/XG4gICAgICBcIm5vLWJpdHdpc2VcIjogW1wiZXJyb3JcIl0sXG5cbiAgICAgIC8vIE1lbWJlciBvcmRlcmluZ1xuICAgICAgXCJAdHlwZXNjcmlwdC1lc2xpbnQvbWVtYmVyLW9yZGVyaW5nXCI6IFtcbiAgICAgICAgXCJlcnJvclwiLFxuICAgICAgICB7XG4gICAgICAgICAgZGVmYXVsdDogW1xuICAgICAgICAgICAgXCJwdWJsaWMtc3RhdGljLWZpZWxkXCIsXG4gICAgICAgICAgICBcInB1YmxpYy1zdGF0aWMtbWV0aG9kXCIsXG4gICAgICAgICAgICBcInByb3RlY3RlZC1zdGF0aWMtZmllbGRcIixcbiAgICAgICAgICAgIFwicHJvdGVjdGVkLXN0YXRpYy1tZXRob2RcIixcbiAgICAgICAgICAgIFwicHJpdmF0ZS1zdGF0aWMtZmllbGRcIixcbiAgICAgICAgICAgIFwicHJpdmF0ZS1zdGF0aWMtbWV0aG9kXCIsXG5cbiAgICAgICAgICAgIFwiZmllbGRcIixcblxuICAgICAgICAgICAgLy8gQ29uc3RydWN0b3JzXG4gICAgICAgICAgICBcImNvbnN0cnVjdG9yXCIsIC8vID0gW1wicHVibGljLWNvbnN0cnVjdG9yXCIsIFwicHJvdGVjdGVkLWNvbnN0cnVjdG9yXCIsIFwicHJpdmF0ZS1jb25zdHJ1Y3RvclwiXVxuXG4gICAgICAgICAgICAvLyBNZXRob2RzXG4gICAgICAgICAgICBcIm1ldGhvZFwiLFxuICAgICAgICAgIF0sXG4gICAgICAgIH0sXG4gICAgICBdLFxuICAgIH07XG5cbiAgICB0aGlzLmlnbm9yZVBhdHRlcm5zID0gb3B0aW9ucy5pZ25vcmVQYXR0ZXJucyA/PyBbXG4gICAgICBcIiouanNcIixcbiAgICAgIFwiKi5kLnRzXCIsXG4gICAgICBcIm5vZGVfbW9kdWxlcy9cIixcbiAgICAgIFwiKi5nZW5lcmF0ZWQudHNcIixcbiAgICAgIFwiY292ZXJhZ2VcIixcbiAgICBdO1xuXG4gICAgY29uc3QgdHNjb25maWcgPSBvcHRpb25zLnRzY29uZmlnUGF0aCA/PyBcIi4vdHNjb25maWcuanNvblwiO1xuICAgIGNvbnN0IHByb2plY3RTZXJ2aWNlID0gb3B0aW9ucy5wcm9qZWN0U2VydmljZSA/PyBmYWxzZTtcblxuICAgIHRoaXMuYWRkUGx1Z2lucyhcIkB0eXBlc2NyaXB0LWVzbGludFwiKTtcbiAgICB0aGlzLmFkZFBsdWdpbnMoXCJpbXBvcnRcIik7XG4gICAgdGhpcy5hZGRFeHRlbmRzKFwicGx1Z2luOmltcG9ydC90eXBlc2NyaXB0XCIpO1xuXG4gICAgdGhpcy5jb25maWcgPSB7XG4gICAgICBlbnY6IHtcbiAgICAgICAgamVzdDogdHJ1ZSxcbiAgICAgICAgbm9kZTogdHJ1ZSxcbiAgICAgIH0sXG4gICAgICByb290OiB0cnVlLFxuICAgICAgcGx1Z2luczogdGhpcy5fcGx1Z2lucyxcbiAgICAgIHBhcnNlcjogXCJAdHlwZXNjcmlwdC1lc2xpbnQvcGFyc2VyXCIsXG4gICAgICBwYXJzZXJPcHRpb25zOiB7XG4gICAgICAgIGVjbWFWZXJzaW9uOiAyMDE4LFxuICAgICAgICBzb3VyY2VUeXBlOiBcIm1vZHVsZVwiLFxuICAgICAgICAvLyBFaXRoZXIgbGV0IHR5cGVzY3JpcHQtZXNsaW50IHJlc29sdmUgdGhlIG5lYXJlc3QgdHNjb25maWcgcGVyIGZpbGVcbiAgICAgICAgLy8gKHByb2plY3Qgc2VydmljZSksIG9yIHBpbiBhbGwgZmlsZXMgdG8gYSBzaW5nbGUgcHJvamVjdC5cbiAgICAgICAgLi4uKHByb2plY3RTZXJ2aWNlXG4gICAgICAgICAgPyB7IHByb2plY3RTZXJ2aWNlOiAoKSA9PiB0aGlzLnJlbmRlclByb2plY3RTZXJ2aWNlKHRzY29uZmlnKSB9XG4gICAgICAgICAgOiB7IHByb2plY3Q6IHRzY29uZmlnIH0pLFxuICAgICAgfSxcbiAgICAgIGV4dGVuZHM6ICgpID0+XG4gICAgICAgIEFycmF5LmZyb20odGhpcy5fZXh0ZW5kcykuc29ydCgoYSwgYikgPT5cbiAgICAgICAgICB0aGlzLnNvcnRFeHRlbmRzLmNvbXBhcmUoYSwgYiksXG4gICAgICAgICksXG4gICAgICBzZXR0aW5nczoge1xuICAgICAgICBcImltcG9ydC9wYXJzZXJzXCI6IHtcbiAgICAgICAgICBcIkB0eXBlc2NyaXB0LWVzbGludC9wYXJzZXJcIjogW1wiLnRzXCIsIFwiLnRzeFwiXSxcbiAgICAgICAgfSxcbiAgICAgICAgXCJpbXBvcnQvcmVzb2x2ZXJcIjoge1xuICAgICAgICAgIC4uLihvcHRpb25zLmFsaWFzTWFwICYmIHtcbiAgICAgICAgICAgIGFsaWFzOiB7XG4gICAgICAgICAgICAgIG1hcDogT2JqZWN0LmVudHJpZXMob3B0aW9ucy5hbGlhc01hcCkubWFwKChbaywgdl0pID0+IFtrLCB2XSksXG4gICAgICAgICAgICAgIGV4dGVuc2lvbnM6IG9wdGlvbnMuYWxpYXNFeHRlbnNpb25zLFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICB9KSxcbiAgICAgICAgICBub2RlOiB7fSxcbiAgICAgICAgICB0eXBlc2NyaXB0OiB7XG4gICAgICAgICAgICBwcm9qZWN0OiB0c2NvbmZpZyxcbiAgICAgICAgICAgIC4uLihvcHRpb25zLnRzQWx3YXlzVHJ5VHlwZXMgIT09IGZhbHNlICYmIHsgYWx3YXlzVHJ5VHlwZXM6IHRydWUgfSksXG4gICAgICAgICAgfSxcbiAgICAgICAgfSxcbiAgICAgIH0sXG4gICAgICBpZ25vcmVQYXR0ZXJuczogdGhpcy5pZ25vcmVQYXR0ZXJucyxcbiAgICAgIHJ1bGVzOiAoKSA9PiAoeyAuLi50aGlzLl9mb3JtYXR0aW5nUnVsZXMsIC4uLnRoaXMucnVsZXMgfSksXG4gICAgICBvdmVycmlkZXM6IHRoaXMub3ZlcnJpZGVzLFxuICAgIH07XG5cbiAgICBpZiAob3B0aW9ucy55YW1sKSB7XG4gICAgICB0aGlzLmZpbGUgPSBuZXcgWWFtbEZpbGUocHJvamVjdCwgXCIuZXNsaW50cmMueW1sXCIsIHtcbiAgICAgICAgb2JqOiB0aGlzLmNvbmZpZyxcbiAgICAgICAgbWFya2VyOiB0cnVlLFxuICAgICAgfSk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHRoaXMuZmlsZSA9IG5ldyBKc29uRmlsZShwcm9qZWN0LCBcIi5lc2xpbnRyYy5qc29uXCIsIHtcbiAgICAgICAgb2JqOiB0aGlzLmNvbmZpZyxcbiAgICAgICAgLy8gaHR0cHM6Ly9lc2xpbnQub3JnL2RvY3MvbGF0ZXN0L3VzZXItZ3VpZGUvY29uZmlndXJpbmcvY29uZmlndXJhdGlvbi1maWxlcyNjb21tZW50cy1pbi1jb25maWd1cmF0aW9uLWZpbGVzXG4gICAgICAgIG1hcmtlcjogdHJ1ZSxcbiAgICAgICAgYWxsb3dDb21tZW50czogdHJ1ZSxcbiAgICAgIH0pO1xuICAgIH1cblxuICAgIC8vIGlmIHRoZSB1c2VyIGVuYWJsZWQgcHJldHRpZXIgZXhwbGljaXRseSBfb3JfIGlmIHRoZSBwcm9qZWN0IGhhcyBhXG4gICAgLy8gYFByZXR0aWVyYCBjb21wb25lbnQsIHdlIHNoYWxsIHR3ZWFrIG91ciBjb25maWd1cmF0aW9uIGFjY29yZGluZ2x5LlxuICAgIGlmIChvcHRpb25zLnByZXR0aWVyIHx8IFByZXR0aWVyLm9mKHByb2plY3QpKSB7XG4gICAgICB0aGlzLmVuYWJsZVByZXR0aWVyKCk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHRoaXMubm9kZVByb2plY3QuYWRkRGV2RGVwcyhcIkBzdHlsaXN0aWMvZXNsaW50LXBsdWdpbkBeMlwiKTtcbiAgICAgIHRoaXMuYWRkUGx1Z2lucyhcIkBzdHlsaXN0aWNcIik7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgYW4gaW1tdXRhYmxlIGNvcHkgb2YgdGhlIGxpbnRQYXR0ZXJucyBiZWluZyB1c2VkIGJ5IHRoaXMgZXNsaW50IGNvbmZpZ3VyYXRpb24uXG4gICAqL1xuICBwdWJsaWMgZ2V0IGxpbnRQYXR0ZXJucygpOiBzdHJpbmdbXSB7XG4gICAgaWYgKHRoaXMuX2xpbnRQYXR0ZXJucyAmJiB0aGlzLl9saW50UGF0dGVybnMuc2l6ZSA+IDApIHtcbiAgICAgIHJldHVybiBbLi4udGhpcy5fbGludFBhdHRlcm5zXTtcbiAgICB9XG5cbiAgICByZXR1cm4gW107XG4gIH1cblxuICAvKipcbiAgICogQWRkIGEgZmlsZSwgZ2xvYiBwYXR0ZXJuIG9yIGRpcmVjdG9yeSB3aXRoIHNvdXJjZSBmaWxlcyB0byBsaW50IChlLmcuIFsgXCJzcmNcIiBdKVxuICAgKi9cbiAgcHVibGljIGFkZExpbnRQYXR0ZXJuKHBhdHRlcm46IHN0cmluZykge1xuICAgIHRoaXMuX2xpbnRQYXR0ZXJucy5hZGQocGF0dGVybik7XG4gICAgdGhpcy51cGRhdGVUYXNrKCk7XG4gIH1cblxuICAvKipcbiAgICogQWRkIGFuIGVzbGludCBydWxlLlxuICAgKi9cbiAgcHVibGljIGFkZFJ1bGVzKHJ1bGVzOiB7IFtydWxlOiBzdHJpbmddOiBhbnkgfSkge1xuICAgIGZvciAoY29uc3QgW2ssIHZdIG9mIE9iamVjdC5lbnRyaWVzKHJ1bGVzKSkge1xuICAgICAgdGhpcy5ydWxlc1trXSA9IHY7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIEFkZHMgYW4gZXNsaW50IHBsdWdpblxuICAgKiBAcGFyYW0gcGx1Z2lucyBUaGUgbmFtZXMgb2YgcGx1Z2lucyB0byBhZGRcbiAgICovXG4gIHB1YmxpYyBhZGRQbHVnaW5zKC4uLnBsdWdpbnM6IHN0cmluZ1tdKSB7XG4gICAgZm9yIChjb25zdCBwbHVnaW4gb2YgcGx1Z2lucykge1xuICAgICAgdGhpcy5fcGx1Z2lucy5hZGQocGx1Z2luKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogQWRkIGFuIGVzbGludCBvdmVycmlkZS5cbiAgICovXG4gIHB1YmxpYyBhZGRPdmVycmlkZShvdmVycmlkZTogRXNsaW50T3ZlcnJpZGUpIHtcbiAgICB0aGlzLm92ZXJyaWRlcy5wdXNoKG92ZXJyaWRlKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBEbyBub3QgbGludCB0aGVzZSBmaWxlcy5cbiAgICovXG4gIHB1YmxpYyBhZGRJZ25vcmVQYXR0ZXJuKHBhdHRlcm46IHN0cmluZykge1xuICAgIHRoaXMuaWdub3JlUGF0dGVybnMucHVzaChwYXR0ZXJuKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBBZGRzIGFuIGBleHRlbmRzYCBpdGVtIHRvIHRoZSBlc2xpbnQgY29uZmlndXJhdGlvbi5cbiAgICogQHBhcmFtIGV4dGVuZExpc3QgVGhlIGxpc3Qgb2YgXCJleHRlbmRzXCIgdG8gYWRkLlxuICAgKi9cbiAgcHVibGljIGFkZEV4dGVuZHMoLi4uZXh0ZW5kTGlzdDogc3RyaW5nW10pIHtcbiAgICBmb3IgKGNvbnN0IGV4dGVuZCBvZiBleHRlbmRMaXN0KSB7XG4gICAgICB0aGlzLl9leHRlbmRzLmFkZChleHRlbmQpO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBBZGQgYSBnbG9iIGZpbGUgcGF0dGVybiB3aGljaCBhbGxvd3MgaW1wb3J0aW5nIGRldiBkZXBlbmRlbmNpZXMuXG4gICAqIEBwYXJhbSBwYXR0ZXJuIGdsb2IgcGF0dGVybi5cbiAgICovXG4gIHB1YmxpYyBhbGxvd0RldkRlcHMocGF0dGVybjogc3RyaW5nKSB7XG4gICAgdGhpcy5fYWxsb3dEZXZEZXBzLmFkZChwYXR0ZXJuKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBBbGxvdyBmaWxlcyBtYXRjaGluZyB0aGVzZSBwYXR0ZXJucyB0byBiZSBsaW50ZWQgd2l0aCB0aGUgdHlwZXNjcmlwdC1lc2xpbnRcbiAgICogXCJkZWZhdWx0IHByb2plY3RcIiB3aGVuIHRoZXkgYXJlIG5vdCBpbmNsdWRlZCBieSBhbnkgYHRzY29uZmlnLmpzb25gLlxuICAgKlxuICAgKiBPbmx5IGhhcyBhbiBlZmZlY3Qgd2hlbiB0aGUgcHJvamVjdCBzZXJ2aWNlIGlzIGVuYWJsZWQgKHNlZVxuICAgKiBgRXNsaW50T3B0aW9ucy5wcm9qZWN0U2VydmljZWApLiBUaGlzIGlzIHR5cGljYWxseSB1c2VkIGZvciBsb29zZSBmaWxlc1xuICAgKiB0aGF0IGxpdmUgb3V0c2lkZSBgc3JjYC9gdGVzdGAgKGUuZy4gYC5wcm9qZW5yYy50c2ApLlxuICAgKlxuICAgKiBAc2VlIGh0dHBzOi8vdHlwZXNjcmlwdC1lc2xpbnQuaW8vcGFja2FnZXMvcGFyc2VyLyNhbGxvd2RlZmF1bHRwcm9qZWN0XG4gICAqIEBwYXJhbSBwYXR0ZXJucyBnbG9iIHBhdHRlcm5zLCByZWxhdGl2ZSB0byB0aGUgcHJvamVjdCByb290LlxuICAgKi9cbiAgcHVibGljIGFsbG93RGVmYXVsdFByb2plY3RGaWxlcyguLi5wYXR0ZXJuczogc3RyaW5nW10pIHtcbiAgICBmb3IgKGNvbnN0IHBhdHRlcm4gb2YgcGF0dGVybnMpIHtcbiAgICAgIHRoaXMuX2FsbG93RGVmYXVsdFByb2plY3QuYWRkKHBhdHRlcm4pO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBSZW5kZXIgdGhlIHZhbHVlIG9mIGBwYXJzZXJPcHRpb25zLnByb2plY3RTZXJ2aWNlYC4gV2hlbiBsb29zZSBmaWxlcyBoYXZlXG4gICAqIGJlZW4gcmVnaXN0ZXJlZCB2aWEgYGFsbG93RGVmYXVsdFByb2plY3RGaWxlc2AsIGFuIG9wdGlvbnMgb2JqZWN0IGlzXG4gICAqIGVtaXR0ZWQ7IG90aGVyd2lzZSB0aGUgcGxhaW4gYHRydWVgIHNob3J0aGFuZCBpcyB1c2VkLlxuICAgKiBAaW50ZXJuYWxcbiAgICovXG4gIHByaXZhdGUgcmVuZGVyUHJvamVjdFNlcnZpY2UoZGVmYXVsdFByb2plY3Q6IHN0cmluZyk6IGJvb2xlYW4gfCBvYmplY3Qge1xuICAgIGlmICh0aGlzLl9hbGxvd0RlZmF1bHRQcm9qZWN0LnNpemUgPT09IDApIHtcbiAgICAgIHJldHVybiB0cnVlO1xuICAgIH1cbiAgICByZXR1cm4ge1xuICAgICAgYWxsb3dEZWZhdWx0UHJvamVjdDogQXJyYXkuZnJvbSh0aGlzLl9hbGxvd0RlZmF1bHRQcm9qZWN0KSxcbiAgICAgIGRlZmF1bHRQcm9qZWN0LFxuICAgIH07XG4gIH1cblxuICAvKipcbiAgICogRW5hYmxlcyBwcmV0dGllciBmb3IgY29kZSBmb3JtYXR0aW5nLlxuICAgKi9cbiAgcHJpdmF0ZSBlbmFibGVQcmV0dGllcigpIHtcbiAgICB0aGlzLm5vZGVQcm9qZWN0LmFkZERldkRlcHMoXG4gICAgICBcInByZXR0aWVyXCIsXG4gICAgICBcImVzbGludC1wbHVnaW4tcHJldHRpZXJcIixcbiAgICAgIFwiZXNsaW50LWNvbmZpZy1wcmV0dGllclwiLFxuICAgICk7XG5cbiAgICB0aGlzLl9mb3JtYXR0aW5nUnVsZXMgPSB7fTtcblxuICAgIHRoaXMuYWRkRXh0ZW5kcyhcInBsdWdpbjpwcmV0dGllci9yZWNvbW1lbmRlZFwiKTtcbiAgfVxuXG4gIHByaXZhdGUgcmVuZGVyRGV2RGVwc0FsbG93TGlzdCgpIHtcbiAgICByZXR1cm4gQXJyYXkuZnJvbSh0aGlzLl9hbGxvd0RldkRlcHMpO1xuICB9XG5cbiAgLyoqXG4gICAqIFJ1bnMgZXNsaW50IG9uY2UsIHJpZ2h0IGFmdGVyIHRoZSBwcm9qZWN0IGlzIGZpcnN0IGNyZWF0ZWQsIHNvIHRoZSBnZW5lcmF0ZWQgY29kZSBpcyBsaW50ZWQgKGFuZCBhdXRvLWZpeGVkKSBpbW1lZGlhdGVseS5cbiAgICovXG4gIHB1YmxpYyBwb3N0UHJvamVjdENyZWF0aW9uKF9pbml0UHJvamVjdDogSW5pdFByb2plY3QpIHtcbiAgICB0aGlzLm5vZGVQcm9qZWN0LnRhc2tzLnJ1blRhc2sodGhpcy5lc2xpbnRUYXNrLm5hbWUpO1xuICB9XG5cbiAgLyoqXG4gICAqIFVwZGF0ZSB0aGUgdGFzayB3aXRoIHRoZSBjdXJyZW50IGxpc3Qgb2YgbGludCBwYXR0ZXJucyBhbmQgZmlsZSBleHRlbnNpb25zXG4gICAqL1xuICBwcml2YXRlIHVwZGF0ZVRhc2soKSB7XG4gICAgY29uc3QgdGFza0V4ZWNDb21tYW5kID0gXCJlc2xpbnRcIjtcbiAgICBjb25zdCBhcmd2ID0gW3Rhc2tFeGVjQ29tbWFuZF07XG5cbiAgICBpZiAodGhpcy5fZmlsZUV4dGVuc2lvbnMuc2l6ZSA+IDApIHtcbiAgICAgIGFyZ3YucHVzaChcIi0tZXh0XCIsIFsuLi50aGlzLl9maWxlRXh0ZW5zaW9uc10uam9pbihcIixcIikpO1xuICAgIH1cbiAgICBhcmd2LnB1c2goLi4udGhpcy5fZmxhZ0FyZ3MpO1xuICAgIGFyZ3YucHVzaChcIiRAXCIpOyAvLyBFeHRlcm5hbCBhcmdzIGdvIGhlcmVcbiAgICBhcmd2LnB1c2goLi4udGhpcy5fbGludFBhdHRlcm5zKTtcblxuICAgIC8vIHJlYWQgYmVmb3JlIHJlc2V0dGluZzogaXQgaW5zcGVjdHMgdGhlIGN1cnJlbnQgc3RlcCB0byBwcmVzZXJ2ZSBhbnlcbiAgICAvLyBleHRlcm5hbCBlZGl0c1xuICAgIGNvbnN0IHN0ZXBPcHRpb25zID0gdGhpcy5idWlsZFRhc2tTdGVwT3B0aW9ucyh0YXNrRXhlY0NvbW1hbmQpO1xuICAgIHRoaXMuZXNsaW50VGFzay5yZXNldCgpO1xuICAgIHRoaXMuZXNsaW50VGFzay5leGVjQXJncyhhcmd2LCBzdGVwT3B0aW9ucyk7XG4gIH1cblxuICAvKipcbiAgICogSW4gY2FzZSBvZiBleHRlcm5hbCBlZGl0aW5nIG9mIHRoZSBlc2xpbnQgdGFzayBzdGVwLCB3ZSBwcmVzZXJ2ZSB0aG9zZSBjaGFuZ2VzLlxuICAgKiBPdGhlcndpc2UsIHdlIHJldHVybiB0aGUgZGVmYXVsdCB0YXNrIHN0ZXAgb3B0aW9ucy5cbiAgICpcbiAgICogQHBhcmFtIHRhc2tFeGVjQ29tbWFuZCBUaGUgY29tbWFuZCB0aGF0IHRoZSBFU0xpbnQgdGFza3MgZXhlY3V0ZXNcbiAgICogQHJldHVybnMgRWl0aGVyIHRoZSBleHRlcm5hbGx5IGVkaXRlZCwgb3IgdGhlIGRlZmF1bHQgdGFzayBzdGVwIG9wdGlvbnNcbiAgICovXG4gIHByaXZhdGUgYnVpbGRUYXNrU3RlcE9wdGlvbnModGFza0V4ZWNDb21tYW5kOiBzdHJpbmcpOiBUYXNrU3RlcE9wdGlvbnMge1xuICAgIGNvbnN0IGN1cnJlbnRFc2xpbnRUYXNrU3RlcCA9IHRoaXMuZXNsaW50VGFzaz8uc3RlcHM/LmZpbmQoXG4gICAgICAoc3RlcCkgPT5cbiAgICAgICAgc3RlcD8uZXhlY0FyZ3M/LlswXSA9PT0gdGFza0V4ZWNDb21tYW5kIHx8XG4gICAgICAgIHN0ZXA/LmV4ZWM/LnN0YXJ0c1dpdGg/Lih0YXNrRXhlY0NvbW1hbmQpLFxuICAgICk7XG5cbiAgICBpZiAoY3VycmVudEVzbGludFRhc2tTdGVwKSB7XG4gICAgICBjb25zdCB7IGFyZ3MsIGNvbmRpdGlvbiwgY3dkLCBlbnYsIG5hbWUsIHJlY2VpdmVBcmdzIH0gPVxuICAgICAgICBjdXJyZW50RXNsaW50VGFza1N0ZXA7XG4gICAgICByZXR1cm4ge1xuICAgICAgICBhcmdzLFxuICAgICAgICBjb25kaXRpb24sXG4gICAgICAgIGN3ZCxcbiAgICAgICAgZW52LFxuICAgICAgICBuYW1lLFxuICAgICAgICByZWNlaXZlQXJncyxcbiAgICAgIH07XG4gICAgfVxuXG4gICAgcmV0dXJuIHtcbiAgICAgIHJlY2VpdmVBcmdzOiB0cnVlLFxuICAgIH07XG4gIH1cbn1cblxuLyoqXG4gKiBBIGNvbXBhcmUgcHJvdG9jb2wgdHAgc29ydCB0aGUgZXh0ZW5kcyBhcnJheSBpbiBlc2xpbnQgY29uZmlnIHVzaW5nIGtub3duIEVTTGludCBiZXN0IHByYWN0aWNlcy5cbiAqXG4gKiBQbGFjZXMgXCJwcmV0dGllclwiIHBsdWdpbnMgYXQgdGhlIGVuZCBvZiB0aGUgYXJyYXlcbiAqL1xuY2xhc3MgRXh0ZW5kc0RlZmF1bHRPcmRlciBpbXBsZW1lbnRzIElDb21wYXJlU3RyaW5nIHtcbiAgLy8gVGhpcyBpcyB0aGUgb3JkZXIgdGhhdCBFU0xpbnQgYmVzdCBwcmFjdGljZXMgc3VnZ2VzdFxuICBwcml2YXRlIHN0YXRpYyBPUkRFUiA9IFtcInBsdWdpbjpwcmV0dGllci9yZWNvbW1lbmRlZFwiLCBcInByZXR0aWVyXCJdO1xuXG4gIHB1YmxpYyBjb21wYXJlKGE6IHN0cmluZywgYjogc3RyaW5nKTogbnVtYmVyIHtcbiAgICByZXR1cm4gKFxuICAgICAgRXh0ZW5kc0RlZmF1bHRPcmRlci5PUkRFUi5pbmRleE9mKGEpIC1cbiAgICAgIEV4dGVuZHNEZWZhdWx0T3JkZXIuT1JERVIuaW5kZXhPZihiKVxuICAgICk7XG4gIH1cbn1cbiJdfQ==