aws-cdk
Version:
AWS CDK Toolkit CLI, the command line tool for CDK apps
521 lines • 78.3 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;
};
})();
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.FlagOperations = void 0;
exports.isEffectiveValueEqualToRecommended = isEffectiveValueEqualToRecommended;
const os = __importStar(require("os"));
const path = __importStar(require("path"));
const cloudformation_diff_1 = require("@aws-cdk/cloudformation-diff");
const toolkit_lib_1 = require("@aws-cdk/toolkit-lib");
const chalk_1 = __importDefault(require("chalk"));
const fs = __importStar(require("fs-extra"));
const p_queue_1 = __importDefault(require("p-queue"));
const obsolete_flags_1 = require("./obsolete-flags");
const api_1 = require("../../api");
class FlagOperations {
flags;
toolkit;
ioHelper;
cliContextValues;
/**
* Returns only those feature flags that need configuration
*
* That is those flags:
* - That are unconfigured
* - That are not obsolete
* - Whose default value is different from the recommended value
*
* The default value being equal to the recommended value sounds odd, but
* crops up in a number of situtations:
*
* - Security-related fixes that we want to force on people, but want to
* give them a flag to back out of the changes if they really need to.
* - Flags that changed their default value in the most recent major
* version.
* - Flags that we've introduced at some point in the past, but have gone
* back on.
*/
static filterNeedsAttention(flags) {
return flags
.filter(flag => !obsolete_flags_1.OBSOLETE_FLAGS.includes(flag.name))
.filter(flag => flag.userValue === undefined)
.filter(flag => defaultValue(flag) !== flag.recommendedValue);
}
app;
baseContextValues;
allStacks;
queue;
baselineTempDir;
originalTempDir;
modifiedTempDir;
constructor(flags, toolkit, ioHelper, cliContextValues = {}) {
this.flags = flags;
this.toolkit = toolkit;
this.ioHelper = ioHelper;
this.cliContextValues = cliContextValues;
this.app = '';
this.baseContextValues = {};
this.allStacks = [];
this.queue = new p_queue_1.default({ concurrency: 4 });
}
/** Main entry point that routes to either flag setting or display operations */
async execute(params) {
if (params.set) {
if (params.FLAGNAME && params.value) {
await this.setFlag(params);
}
else {
await this.setMultipleFlags(params);
}
}
else {
await this.displayFlags(params);
}
}
/** Sets a single specific flag with validation and user confirmation */
async setFlag(params) {
const flagName = params.FLAGNAME[0];
const flag = this.flags.find(f => f.name === flagName);
if (!flag) {
await this.ioHelper.defaults.error('Flag not found.');
return;
}
if (!this.isBooleanFlag(flag)) {
await this.ioHelper.defaults.error(`Flag '${flagName}' is not a boolean flag. Only boolean flags are currently supported.`);
return;
}
const prototypeSuccess = await this.prototypeChanges([flagName], params);
if (prototypeSuccess) {
await this.handleUserResponse([flagName], params);
}
}
/** Sets multiple flags (all or unconfigured) with validation and user confirmation */
async setMultipleFlags(params) {
if (params.default && !this.flags.some(f => f.unconfiguredBehavesLike)) {
await this.ioHelper.defaults.error('The --default options are not compatible with the AWS CDK library used by your application. Please upgrade to 2.212.0 or above.');
return;
}
const flagsToSet = this.getFlagsToSet(params);
const prototypeSuccess = await this.prototypeChanges(flagsToSet, params);
if (prototypeSuccess) {
await this.handleUserResponse(flagsToSet, params);
}
}
/** Determines which flags should be set based on the provided parameters */
getFlagsToSet(params) {
if (params.all && params.default) {
return this.flags
.filter(flag => this.isBooleanFlag(flag))
.map(flag => flag.name);
}
else if (params.all) {
return this.flags
.filter(flag => flag.userValue === undefined || !isEffectiveValueEqualToRecommended(flag))
.filter(flag => this.isBooleanFlag(flag))
.map(flag => flag.name);
}
else {
return this.flags
.filter(flag => flag.userValue === undefined)
.filter(flag => this.isBooleanFlag(flag))
.map(flag => flag.name);
}
}
/** Sets flags that don't cause template changes */
async setSafeFlags(params) {
const cdkJson = await JSON.parse(await fs.readFile(path.join(process.cwd(), 'cdk.json'), 'utf-8'));
this.app = params.app || cdkJson.app;
const isUsingTsNode = this.app.includes('ts-node');
if (isUsingTsNode && !this.app.includes('-T') && !this.app.includes('--transpileOnly')) {
await this.ioHelper.defaults.info('Repeated synths with ts-node will type-check the application on every synth. Add --transpileOnly to cdk.json\'s "app" command to make this operation faster.');
}
const unconfiguredFlags = this.flags.filter(flag => flag.userValue === undefined && this.isBooleanFlag(flag));
if (unconfiguredFlags.length === 0) {
await this.ioHelper.defaults.info('All feature flags are configured.');
return;
}
await this.initializeSafetyCheck();
const safeFlags = await this.batchTestFlags(unconfiguredFlags);
await this.cleanupSafetyCheck();
if (safeFlags.length > 0) {
await this.ioHelper.defaults.info('Flags that can be set without template changes:');
for (const flag of safeFlags) {
await this.ioHelper.defaults.info(`- ${flag.name} -> ${flag.recommendedValue}`);
}
await this.handleUserResponse(safeFlags.map(flag => flag.name), { ...params, recommended: true });
}
else {
await this.ioHelper.defaults.info('No more flags can be set without causing template changes.');
}
}
/** Initializes the safety check by reading context and synthesizing baseline templates */
async initializeSafetyCheck() {
const baseContext = new toolkit_lib_1.CdkAppMultiContext(process.cwd());
this.baseContextValues = { ...await baseContext.read(), ...this.cliContextValues };
this.baselineTempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'cdk-baseline-'));
const mergedContext = new toolkit_lib_1.MemoryContext(this.baseContextValues);
const baseSource = await this.toolkit.fromCdkApp(this.app, {
contextStore: mergedContext,
outdir: this.baselineTempDir,
});
const baseCx = await this.toolkit.synth(baseSource);
const baseAssembly = baseCx.cloudAssembly;
this.allStacks = baseAssembly.stacksRecursively;
this.queue = new p_queue_1.default({ concurrency: 4 });
}
/** Cleans up temporary directories created during safety checks */
async cleanupSafetyCheck() {
if (this.baselineTempDir) {
await fs.remove(this.baselineTempDir);
this.baselineTempDir = undefined;
}
}
/** Tests multiple flags together and isolates unsafe ones using binary search */
async batchTestFlags(flags) {
if (flags.length === 0)
return [];
const allFlagsContext = { ...this.baseContextValues };
flags.forEach(flag => {
allFlagsContext[flag.name] = flag.recommendedValue;
});
const allSafe = await this.testBatch(allFlagsContext);
if (allSafe)
return flags;
return this.isolateUnsafeFlags(flags);
}
/** Tests if a set of context values causes template changes by synthesizing and diffing */
async testBatch(contextValues) {
const testContext = new toolkit_lib_1.MemoryContext(contextValues);
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'cdk-test-'));
const testSource = await this.toolkit.fromCdkApp(this.app, {
contextStore: testContext,
outdir: tempDir,
});
const testCx = await this.toolkit.synth(testSource);
try {
for (const stack of this.allStacks) {
const templatePath = stack.templateFullPath;
const diff = await this.toolkit.diff(testCx, {
method: toolkit_lib_1.DiffMethod.LocalFile(templatePath),
stacks: {
strategy: api_1.StackSelectionStrategy.PATTERN_MUST_MATCH_SINGLE,
patterns: [stack.hierarchicalId],
},
});
for (const stackDiff of Object.values(diff)) {
if (stackDiff.differenceCount > 0) {
return false;
}
}
}
return true;
}
finally {
await fs.remove(tempDir);
}
}
/** Uses binary search to isolate which flags are safe to set without template changes */
async isolateUnsafeFlags(flags) {
const safeFlags = [];
const processBatch = async (batch, contextValues) => {
if (batch.length === 1) {
const isSafe = await this.testBatch({ ...contextValues, [batch[0].name]: batch[0].recommendedValue });
if (isSafe)
safeFlags.push(batch[0]);
return;
}
const batchContext = { ...contextValues };
batch.forEach(flag => {
batchContext[flag.name] = flag.recommendedValue;
});
const isSafeBatch = await this.testBatch(batchContext);
if (isSafeBatch) {
safeFlags.push(...batch);
return;
}
const mid = Math.floor(batch.length / 2);
const left = batch.slice(0, mid);
const right = batch.slice(mid);
void this.queue.add(() => processBatch(left, contextValues));
void this.queue.add(() => processBatch(right, contextValues));
};
void this.queue.add(() => processBatch(flags, this.baseContextValues));
await this.queue.onIdle();
return safeFlags;
}
/** Prototypes flag changes by synthesizing templates and showing diffs to the user */
async prototypeChanges(flagNames, params) {
const baseContext = new toolkit_lib_1.CdkAppMultiContext(process.cwd());
const baseContextValues = { ...await baseContext.read(), ...this.cliContextValues };
const memoryContext = new toolkit_lib_1.MemoryContext(baseContextValues);
const cdkJson = await JSON.parse(await fs.readFile(path.join(process.cwd(), 'cdk.json'), 'utf-8'));
const app = cdkJson.app;
this.originalTempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'cdk-original-'));
const source = await this.toolkit.fromCdkApp(app, {
contextStore: memoryContext,
outdir: this.originalTempDir,
});
const updateObj = await this.buildUpdateObject(flagNames, params, baseContextValues);
if (!updateObj) {
await this.cleanupTempDirectories();
return false;
}
await memoryContext.update(updateObj);
const cx = await this.toolkit.synth(source);
const assembly = cx.cloudAssembly;
this.modifiedTempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'cdk-temp-'));
const modifiedSource = await this.toolkit.fromCdkApp(app, {
contextStore: memoryContext,
outdir: this.modifiedTempDir,
});
const modifiedCx = await this.toolkit.synth(modifiedSource);
const allStacks = assembly.stacksRecursively;
for (const stack of allStacks) {
const templatePath = stack.templateFullPath;
await this.toolkit.diff(modifiedCx, {
method: toolkit_lib_1.DiffMethod.LocalFile(templatePath),
stacks: {
strategy: api_1.StackSelectionStrategy.PATTERN_MUST_MATCH_SINGLE,
patterns: [stack.hierarchicalId],
},
});
}
await this.displayFlagChanges(updateObj, baseContextValues);
return true;
}
/** Displays a summary of flag changes showing old and new values */
async displayFlagChanges(updateObj, baseContextValues) {
await this.ioHelper.defaults.info('\nFlag changes:');
for (const [flagName, newValue] of Object.entries(updateObj)) {
const currentValue = baseContextValues[flagName];
const currentDisplay = currentValue === undefined ? '<unset>' : String(currentValue);
await this.ioHelper.defaults.info(` ${flagName}: ${currentDisplay} → ${newValue}`);
}
}
/** Builds the update object with new flag values based on parameters and current context */
async buildUpdateObject(flagNames, params, baseContextValues) {
const updateObj = {};
if (flagNames.length === 1 && params.value !== undefined) {
const flagName = flagNames[0];
const boolValue = params.value === 'true';
if (baseContextValues[flagName] === boolValue) {
await this.ioHelper.defaults.info('Flag is already set to the specified value. No changes needed.');
return null;
}
updateObj[flagName] = boolValue;
}
else {
for (const flagName of flagNames) {
const flag = this.flags.find(f => f.name === flagName);
if (!flag) {
await this.ioHelper.defaults.error(`Flag ${flagName} not found.`);
return null;
}
const newValue = params.recommended
? flag.recommendedValue
: String(defaultValue(flag)) === 'true';
updateObj[flagName] = newValue;
}
}
return updateObj;
}
/** Prompts user for confirmation and applies changes if accepted */
async handleUserResponse(flagNames, params) {
const userAccepted = await this.ioHelper.requestResponse({
time: new Date(),
level: 'info',
code: 'CDK_TOOLKIT_I9300',
message: 'Do you want to accept these changes?',
data: {
flagNames,
responseDescription: 'Enter "y" to apply changes or "n" to cancel',
},
defaultResponse: false,
});
if (!userAccepted) {
await this.cleanupTempDirectories();
throw new toolkit_lib_1.AbortError('FlagsAborted', 'Flag update cancelled');
}
await this.modifyValues(flagNames, params);
await this.ioHelper.defaults.info('Flag value(s) updated successfully.');
await this.cleanupTempDirectories();
}
/** Removes temporary directories created during flag operations */
async cleanupTempDirectories() {
if (this.originalTempDir) {
await fs.remove(this.originalTempDir);
this.originalTempDir = undefined;
}
if (this.modifiedTempDir) {
await fs.remove(this.modifiedTempDir);
this.modifiedTempDir = undefined;
}
}
/** Actually modifies the cdk.json file with the new flag values */
async modifyValues(flagNames, params) {
const cdkJsonPath = path.join(process.cwd(), 'cdk.json');
const cdkJsonContent = await fs.readFile(cdkJsonPath, 'utf-8');
const cdkJson = JSON.parse(cdkJsonContent);
if (flagNames.length === 1 && !params.safe && !params.all) {
const boolValue = params.value === 'true';
cdkJson.context[String(flagNames[0])] = boolValue;
await this.ioHelper.defaults.info(`Setting flag '${flagNames}' to: ${boolValue}`);
}
else {
for (const flagName of flagNames) {
const flag = this.flags.find(f => f.name === flagName);
const newValue = params.recommended || params.safe
? flag.recommendedValue
: String(defaultValue(flag)) === 'true';
cdkJson.context[flagName] = newValue;
}
}
await fs.writeFile(cdkJsonPath, JSON.stringify(cdkJson, null, 2), 'utf-8');
}
/** Displays flags in a table format, either specific flags or filtered by criteria */
async displayFlags(params) {
const { FLAGNAME, all } = params;
if (FLAGNAME && FLAGNAME.length > 0) {
await this.displaySpecificFlags(FLAGNAME);
return;
}
const [flagsToDisplay, header] = all
? [this.flags, 'All feature flags']
: [FlagOperations.filterNeedsAttention(this.flags), 'Unconfigured feature flags'];
await this.ioHelper.defaults.info(header);
await this.displayFlagTable(flagsToDisplay);
// Add helpful message after empty table when not using --all
if (!all && flagsToDisplay.length === 0) {
await this.ioHelper.defaults.info('');
await this.ioHelper.defaults.info('✅ All feature flags are already set to their recommended values.');
await this.ioHelper.defaults.info('Use \'cdk flags --all --unstable=flags\' to see all flags and their current values.');
}
}
/** Displays detailed information for specific flags matching the given names */
async displaySpecificFlags(flagNames) {
const matchingFlags = this.flags.filter(f => flagNames.some(searchTerm => f.name.toLowerCase().includes(searchTerm.toLowerCase())));
if (matchingFlags.length === 0) {
await this.ioHelper.defaults.error(`Flag matching "${flagNames.join(', ')}" not found.`);
return;
}
if (matchingFlags.length === 1) {
const flag = matchingFlags[0];
await this.ioHelper.defaults.info(`Flag name: ${flag.name}`);
await this.ioHelper.defaults.info(`Description: ${flag.explanation}`);
await this.ioHelper.defaults.info(`Recommended value: ${flag.recommendedValue}`);
await this.ioHelper.defaults.info(`Default value: ${defaultValue(flag)}`);
await this.ioHelper.defaults.info(`User value: ${flag.userValue}`);
await this.ioHelper.defaults.info(`Effective value: ${effectiveValue(flag)}`);
return;
}
await this.ioHelper.defaults.info(`Found ${matchingFlags.length} flags matching "${flagNames.join(', ')}"`);
await this.displayFlagTable(matchingFlags);
}
/** Returns sort order for flags */
getFlagSortOrder(flag) {
if (flag.userValue === undefined)
return 3;
if (isEffectiveValueEqualToRecommended(flag))
return 1;
return 2;
}
/** Displays flags in a formatted table grouped by module and sorted */
async displayFlagTable(flags) {
const sortedFlags = [...flags].sort((a, b) => {
const orderA = this.getFlagSortOrder(a);
const orderB = this.getFlagSortOrder(b);
if (orderA !== orderB)
return orderA - orderB;
if (a.module !== b.module)
return a.module.localeCompare(b.module);
return a.name.localeCompare(b.name);
});
const rows = [['Feature Flag', 'Recommended', 'User', 'Effective']];
let currentModule = '';
sortedFlags.forEach((flag) => {
if (flag.module !== currentModule) {
rows.push([chalk_1.default.bold(`Module: ${flag.module}`), '', '', '']);
currentModule = flag.module;
}
rows.push([
` ${flag.name}`,
String(flag.recommendedValue),
flag.userValue === undefined ? '<unset>' : String(flag.userValue),
String(effectiveValue(flag)),
]);
});
const formattedTable = (0, cloudformation_diff_1.formatTable)(rows, undefined, true);
await this.ioHelper.defaults.info(formattedTable);
}
/** Checks if a flag has a boolean recommended value */
isBooleanFlag(flag) {
const recommended = flag.recommendedValue;
return typeof recommended === 'boolean' ||
recommended === 'true' ||
recommended === 'false';
}
/** Shows helpful usage examples and available command options */
async displayHelpMessage() {
await this.ioHelper.defaults.info('\n' + chalk_1.default.bold('Available options:'));
await this.ioHelper.defaults.info(' cdk flags --interactive # Interactive menu to manage flags');
await this.ioHelper.defaults.info(' cdk flags --all # Show all flags (including configured ones)');
await this.ioHelper.defaults.info(' cdk flags --set --all --recommended # Set all flags to recommended values');
await this.ioHelper.defaults.info(' cdk flags --set --all --default # Set all flags to default values');
await this.ioHelper.defaults.info(' cdk flags --set --unconfigured --recommended # Set unconfigured flags to recommended');
await this.ioHelper.defaults.info(' cdk flags --set <flag-name> --value <true|false> # Set specific flag');
await this.ioHelper.defaults.info(' cdk flags --safe # Safely set flags that don\'t change templates');
}
}
exports.FlagOperations = FlagOperations;
/** Checks if the flags current effective value matches the recommended value */
function isEffectiveValueEqualToRecommended(flag) {
return String(effectiveValue(flag)) === String(flag.recommendedValue);
}
/**
* Return the effective value of a flag (user value or default)
*/
function effectiveValue(flag) {
return flag.userValue ?? defaultValue(flag);
}
/**
* Return the default value for a flag, assume it's `false` if not given
*/
function defaultValue(flag) {
return flag.unconfiguredBehavesLike?.v2 ?? false;
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoib3BlcmF0aW9ucy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIm9wZXJhdGlvbnMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0FBZ2hCQSxnRkFFQztBQWxoQkQsdUNBQXlCO0FBQ3pCLDJDQUE2QjtBQUU3QixzRUFBMkQ7QUFFM0Qsc0RBQWlHO0FBQ2pHLGtEQUEwQjtBQUMxQiw2Q0FBK0I7QUFDL0Isc0RBQTZCO0FBQzdCLHFEQUFrRDtBQUVsRCxtQ0FBbUQ7QUFHbkQsTUFBYSxjQUFjO0lBbUNOO0lBQ0E7SUFDQTtJQUNBO0lBckNuQjs7Ozs7Ozs7Ozs7Ozs7Ozs7T0FpQkc7SUFDSSxNQUFNLENBQUMsb0JBQW9CLENBQUMsS0FBb0I7UUFDckQsT0FBTyxLQUFLO2FBQ1QsTUFBTSxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsQ0FBQywrQkFBYyxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUM7YUFDbkQsTUFBTSxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsSUFBSSxDQUFDLFNBQVMsS0FBSyxTQUFTLENBQUM7YUFDNUMsTUFBTSxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsWUFBWSxDQUFDLElBQUksQ0FBQyxLQUFLLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxDQUFDO0lBQ2xFLENBQUM7SUFFTyxHQUFHLENBQVM7SUFDWixpQkFBaUIsQ0FBc0I7SUFDdkMsU0FBUyxDQUFnQztJQUN6QyxLQUFLLENBQVM7SUFDZCxlQUFlLENBQVU7SUFDekIsZUFBZSxDQUFVO0lBQ3pCLGVBQWUsQ0FBVTtJQUVqQyxZQUNtQixLQUFvQixFQUNwQixPQUFnQixFQUNoQixRQUFrQixFQUNsQixtQkFBd0MsRUFBRTtRQUgxQyxVQUFLLEdBQUwsS0FBSyxDQUFlO1FBQ3BCLFlBQU8sR0FBUCxPQUFPLENBQVM7UUFDaEIsYUFBUSxHQUFSLFFBQVEsQ0FBVTtRQUNsQixxQkFB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QUNoSCxNQUFNLElBQUksQ0FBQyxRQUFRLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyxnRkFBZ0YsQ0FBQyxDQUFDO1FBQ3BILE1BQU0sSUFBSSxDQUFDLFFBQVEsQ0FBQyxRQUFRLENBQUMsSUFBSSxDQUFDLDJFQUEyRSxDQUFDLENBQUM7UUFDL0csTUFBTSxJQUFJLENBQUMsUUFBUSxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUMseUZBQXlGLENBQUMsQ0FBQztRQUM3SCxNQUFNLElBQUksQ0FBQyxRQUFRLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyx5RUFBeUUsQ0FBQyxDQUFDO1FBQzdHLE1BQU0sSUFBSSxDQUFDLFFBQVEsQ0FBQyxRQUFRLENBQUMsSUFBSSxDQUFDLCtFQUErRSxDQUFDLENBQUM7SUFDckgsQ0FBQztDQUNGO0FBL2ZELHdDQStmQztBQUVELGdGQUFnRjtBQUNoRixTQUFnQixrQ0FBa0MsQ0FBQyxJQUFpQjtJQUNsRSxPQUFPLE1BQU0sQ0FBQyxjQUFjLENBQUMsSUFBSSxDQUFDLENBQUMsS0FBSyxNQUFNLENBQUMsSUFBSSxDQUFDLGdCQUFnQixDQUFDLENBQUM7QUFDeEUsQ0FBQztBQUVEOztHQUVHO0FBQ0gsU0FBUyxjQUFjLENBQUMsSUFBaUI7SUFDdkMsT0FBTyxJQUFJLENBQUMsU0FBUyxJQUFJLFlBQVksQ0FBQyxJQUFJLENBQUMsQ0FBQztBQUM5QyxDQUFDO0FBRUQ7O0dBRUc7QUFDSCxTQUFTLFlBQVksQ0FBQyxJQUFpQjtJQUNyQyxPQUFPLElBQUksQ0FBQyx1QkFBdUIsRUFBRSxFQUFFLElBQUksS0FBSyxDQUFDO0FBQ25ELENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgKiBhcyBvcyBmcm9tICdvcyc7XG5pbXBvcnQgKiBhcyBwYXRoIGZyb20gJ3BhdGgnO1xuaW1wb3J0IHR5cGUgeyBDbG91ZEZvcm1hdGlvblN0YWNrQXJ0aWZhY3QgfSBmcm9tICdAYXdzLWNkay9jbG91ZC1hc3NlbWJseS1hcGknO1xuaW1wb3J0IHsgZm9ybWF0VGFibGUgfSBmcm9tICdAYXdzLWNkay9jbG91ZGZvcm1hdGlvbi1kaWZmJztcbmltcG9ydCB0eXBlIHsgRmVhdHVyZUZsYWcsIFRvb2xraXQgfSBmcm9tICdAYXdzLWNkay90b29sa2l0LWxpYic7XG5pbXBvcnQgeyBDZGtBcHBNdWx0aUNvbnRleHQsIE1lbW9yeUNvbnRleHQsIERpZmZNZXRob2QsIEFib3J0RXJyb3IgfSBmcm9tICdAYXdzLWNkay90b29sa2l0LWxpYic7XG5pbXBvcnQgY2hhbGsgZnJvbSAnY2hhbGsnO1xuaW1wb3J0ICogYXMgZnMgZnJvbSAnZnMtZXh0cmEnO1xuaW1wb3J0IFBRdWV1ZSBmcm9tICdwLXF1ZXVlJztcbmltcG9ydCB7IE9CU09MRVRFX0ZMQUdTIH0gZnJvbSAnLi9vYnNvbGV0ZS1mbGFncyc7XG5pbXBvcnQgdHlwZSB7IEZsYWdPcGVyYXRpb25zUGFyYW1zIH0gZnJvbSAnLi90eXBlcyc7XG5pbXBvcnQgeyBTdGFja1NlbGVjdGlvblN0cmF0ZWd5IH0gZnJvbSAnLi4vLi4vYXBpJztcbmltcG9ydCB0eXBlIHsgSW9IZWxwZXIgfSBmcm9tICcuLi8uLi9hcGktcHJpdmF0ZSc7XG5cbmV4cG9ydCBjbGFzcyBGbGFnT3BlcmF0aW9ucyB7XG4gIC8qKlxuICAgKiBSZXR1cm5zIG9ubHkgdGhvc2UgZmVhdHVyZSBmbGFncyB0aGF0IG5lZWQgY29uZmlndXJhdGlvblxuICAgKlxuICAgKiBUaGF0IGlzIHRob3NlIGZsYWdzOlxuICAgKiAtIFRoYXQgYXJlIHVuY29uZmlndXJlZFxuICAgKiAtIFRoYXQgYXJlIG5vdCBvYnNvbGV0ZVxuICAgKiAtIFdob3NlIGRlZmF1bHQgdmFsdWUgaXMgZGlmZmVyZW50IGZyb20gdGhlIHJlY29tbWVuZGVkIHZhbHVlXG4gICAqXG4gICAqIFRoZSBkZWZhdWx0IHZhbHVlIGJlaW5nIGVxdWFsIHRvIHRoZSByZWNvbW1lbmRlZCB2YWx1ZSBzb3VuZHMgb2RkLCBidXRcbiAgICogY3JvcHMgdXAgaW4gYSBudW1iZXIgb2Ygc2l0dXRhdGlvbnM6XG4gICAqXG4gICAqIC0gU2VjdXJpdHktcmVsYXRlZCBmaXhlcyB0aGF0IHdlIHdhbnQgdG8gZm9yY2Ugb24gcGVvcGxlLCBidXQgd2FudCB0b1xuICAgKiAgIGdpdmUgdGhlbSBhIGZsYWcgdG8gYmFjayBvdXQgb2YgdGhlIGNoYW5nZXMgaWYgdGhleSByZWFsbHkgbmVlZCB0by5cbiAgICogLSBGbGFncyB0aGF0IGNoYW5nZWQgdGhlaXIgZGVmYXVsdCB2YWx1ZSBpbiB0aGUgbW9zdCByZWNlbnQgbWFqb3JcbiAgICogICB2ZXJzaW9uLlxuICAgKiAtIEZsYWdzIHRoYXQgd2UndmUgaW50cm9kdWNlZCBhdCBzb21lIHBvaW50IGluIHRoZSBwYXN0LCBidXQgaGF2ZSBnb25lXG4gICAqICAgYmFjayBvbi5cbiAgICovXG4gIHB1YmxpYyBzdGF0aWMgZmlsdGVyTmVlZHNBdHRlbnRpb24oZmxhZ3M6IEZlYXR1cmVGbGFnW10pOiBGZWF0dXJlRmxhZ1tdIHtcbiAgICByZXR1cm4gZmxhZ3NcbiAgICAgIC5maWx0ZXIoZmxhZyA9PiAhT0JTT0xFVEVfRkxBR1MuaW5jbHVkZXMoZmxhZy5uYW1lKSlcbiAgICAgIC5maWx0ZXIoZmxhZyA9PiBmbGFnLnVzZXJWYWx1ZSA9PT0gdW5kZWZpbmVkKVxuICAgICAgLmZpbHRlcihmbGFnID0+IGRlZmF1bHRWYWx1ZShmbGFnKSAhPT0gZmxhZy5yZWNvbW1lbmRlZFZhbHVlKTtcbiAgfVxuXG4gIHByaXZhdGUgYXBwOiBzdHJpbmc7XG4gIHByaXZhdGUgYmFzZUNvbnRleHRWYWx1ZXM6IFJlY29yZDxzdHJpbmcsIGFueT47XG4gIHByaXZhdGUgYWxsU3RhY2tzOiBDbG91ZEZvcm1hdGlvblN0YWNrQXJ0aWZhY3RbXTtcbiAgcHJpdmF0ZSBxdWV1ZTogUFF1ZXVlO1xuICBwcml2YXRlIGJhc2VsaW5lVGVtcERpcj86IHN0cmluZztcbiAgcHJpdmF0ZSBvcmlnaW5hbFRlbXBEaXI/OiBzdHJpbmc7XG4gIHByaXZhdGUgbW9kaWZpZWRUZW1wRGlyPzogc3RyaW5nO1xuXG4gIGNvbnN0cnVjdG9yKFxuICAgIHByaXZhdGUgcmVhZG9ubHkgZmxhZ3M6IEZlYXR1cmVGbGFnW10sXG4gICAgcHJpdmF0ZSByZWFkb25seSB0b29sa2l0OiBUb29sa2l0LFxuICAgIHByaXZhdGUgcmVhZG9ubHkgaW9IZWxwZXI6IElvSGVscGVyLFxuICAgIHByaXZhdGUgcmVhZG9ubHkgY2xpQ29udGV4dFZhbHVlczogUmVjb3JkPHN0cmluZywgYW55PiA9IHt9LFxuICApIHtcbiAgICB0aGlzLmFwcCA9ICcnO1xuICAgIHRoaXMuYmFzZUNvbnRleHRWYWx1ZXMgPSB7fTtcbiAgICB0aGlzLmFsbFN0YWNrcyA9IFtdO1xuICAgIHRoaXMucXVldWUgPSBuZXcgUFF1ZXVlKHsgY29uY3VycmVuY3k6IDQgfSk7XG4gIH1cblxuICAvKiogTWFpbiBlbnRyeSBwb2ludCB0aGF0IHJvdXRlcyB0byBlaXRoZXIgZmxhZyBzZXR0aW5nIG9yIGRpc3BsYXkgb3BlcmF0aW9ucyAqL1xuICBhc3luYyBleGVjdXRlKHBhcmFtczogRmxhZ09wZXJhdGlvbnNQYXJhbXMpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBpZiAocGFyYW1zLnNldCkge1xuICAgICAgaWYgKHBhcmFtcy5GTEFHTkFNRSAmJiBwYXJhbXMudmFsdWUpIHtcbiAgICAgICAgYXdhaXQgdGhpcy5zZXRGbGFnKHBhcmFtcyk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBhd2FpdCB0aGlzLnNldE11bHRpcGxlRmxhZ3MocGFyYW1zKTtcbiAgICAgIH1cbiAgICB9IGVsc2Uge1xuICAgICAgYXdhaXQgdGhpcy5kaXNwbGF5RmxhZ3MocGFyYW1zKTtcbiAgICB9XG4gIH1cblxuICAvKiogU2V0cyBhIHNpbmdsZSBzcGVjaWZpYyBmbGFnIHdpdGggdmFsaWRhdGlvbiBhbmQgdXNlciBjb25maXJtYXRpb24gKi9cbiAgYXN5bmMgc2V0RmxhZyhwYXJhbXM6IEZsYWdPcGVyYXRpb25zUGFyYW1zKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgY29uc3QgZmxhZ05hbWUgPSBwYXJhbXMuRkxBR05BTUUhWzBdO1xuICAgIGNvbnN0IGZsYWcgPSB0aGlzLmZsYWdzLmZpbmQoZiA9PiBmLm5hbWUgPT09IGZsYWdOYW1lKTtcblxuICAgIGlmICghZmxhZykge1xuICAgICAgYXdhaXQgdGhpcy5pb0hlbHBlci5kZWZhdWx0cy5lcnJvcignRmxhZyBub3QgZm91bmQuJyk7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgaWYgKCF0aGlzLmlzQm9vbGVhbkZsYWcoZmxhZykpIHtcbiAgICAgIGF3YWl0IHRoaXMuaW9IZWxwZXIuZGVmYXVsdHMuZXJyb3IoYEZsYWcgJyR7ZmxhZ05hbWV9JyBpcyBub3QgYSBib29sZWFuIGZsYWcuIE9ubHkgYm9vbGVhbiBmbGFncyBhcmUgY3VycmVudGx5IHN1cHBvcnRlZC5gKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBjb25zdCBwcm90b3R5cGVTdWNjZXNzID0gYXdhaXQgdGhpcy5wcm90b3R5cGVDaGFuZ2VzKFtmbGFnTmFtZV0sIHBhcmFtcyk7XG4gICAgaWYgKHByb3RvdHlwZVN1Y2Nlc3MpIHtcbiAgICAgIGF3YWl0IHRoaXMuaGFuZGxlVXNlclJlc3BvbnNlKFtmbGFnTmFtZV0sIHBhcmFtcyk7XG4gICAgfVxuICB9XG5cbiAgLyoqIFNldHMgbXVsdGlwbGUgZmxhZ3MgKGFsbCBvciB1bmNvbmZpZ3VyZWQpIHdpdGggdmFsaWRhdGlvbiBhbmQgdXNlciBjb25maXJtYXRpb24gKi9cbiAgYXN5bmMgc2V0TXVsdGlwbGVGbGFncyhwYXJhbXM6IEZsYWdPcGVyYXRpb25zUGFyYW1zKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgaWYgKHBhcmFtcy5kZWZhdWx0ICYmICF0aGlzLmZsYWdzLnNvbWUoZiA9PiBmLnVuY29uZmlndXJlZEJlaGF2ZXNMaWtlKSkge1xuICAgICAgYXdhaXQgdGhpcy5pb0hlbHBlci5kZWZhdWx0cy5lcnJvcignVGhlIC0tZGVmYXVsdCBvcHRpb25zIGFyZSBub3QgY29tcGF0aWJsZSB3aXRoIHRoZSBBV1MgQ0RLIGxpYnJhcnkgdXNlZCBieSB5b3VyIGFwcGxpY2F0aW9uLiBQbGVhc2UgdXBncmFkZSB0byAyLjIxMi4wIG9yIGFib3ZlLicpO1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGNvbnN0IGZsYWdzVG9TZXQgPSB0aGlzLmdldEZsYWdzVG9TZXQocGFyYW1zKTtcbiAgICBjb25zdCBwcm90b3R5cGVTdWNjZXNzID0gYXdhaXQgdGhpcy5wcm90b3R5cGVDaGFuZ2VzKGZsYWdzVG9TZXQsIHBhcmFtcyk7XG5cbiAgICBpZiAocHJvdG90eXBlU3VjY2Vzcykge1xuICAgICAgYXdhaXQgdGhpcy5oYW5kbGVVc2VyUmVzcG9uc2UoZmxhZ3NUb1NldCwgcGFyYW1zKTtcbiAgICB9XG4gIH1cblxuICAvKiogRGV0ZXJtaW5lcyB3aGljaCBmbGFncyBzaG91bGQgYmUgc2V0IGJhc2VkIG9uIHRoZSBwcm92aWRlZCBwYXJhbWV0ZXJzICovXG4gIHByaXZhdGUgZ2V0RmxhZ3NUb1NldChwYXJhbXM6IEZsYWdPcGVyYXRpb25zUGFyYW1zKTogc3RyaW5nW10ge1xuICAgIGlmIChwYXJhbXMuYWxsICYmIHBhcmFtcy5kZWZhdWx0KSB7XG4gICAgICByZXR1cm4gdGhpcy5mbGFnc1xuICAgICAgICAuZmlsdGVyKGZsYWcgPT4gdGhpcy5pc0Jvb2xlYW5GbGFnKGZsYWcpKVxuICAgICAgICAubWFwKGZsYWcgPT4gZmxhZy5uYW1lKTtcbiAgICB9IGVsc2UgaWYgKHBhcmFtcy5hbGwpIHtcbiAgICAgIHJldHVybiB0aGlzLmZsYWdzXG4gICAgICAgIC5maWx0ZXIoZmxhZyA9PiBmbGFnLnVzZXJWYWx1ZSA9PT0gdW5kZWZpbmVkIHx8ICFpc0VmZmVjdGl2ZVZhbHVlRXF1YWxUb1JlY29tbWVuZGVkKGZsYWcpKVxuICAgICAgICAuZmlsdGVyKGZsYWcgPT4gdGhpcy5pc0Jvb2xlYW5GbGFnKGZsYWcpKVxuICAgICAgICAubWFwKGZsYWcgPT4gZmxhZy5uYW1lKTtcbiAgICB9IGVsc2Uge1xuICAgICAgcmV0dXJuIHRoaXMuZmxhZ3NcbiAgICAgICAgLmZpbHRlcihmbGFnID0+IGZsYWcudXNlclZhbHVlID09PSB1bmRlZmluZWQpXG4gICAgICAgIC5maWx0ZXIoZmxhZyA9PiB0aGlzLmlzQm9vbGVhbkZsYWcoZmxhZykpXG4gICAgICAgIC5tYXAoZmxhZyA9PiBmbGFnLm5hbWUpO1xuICAgIH1cbiAgfVxuXG4gIC8qKiBTZXRzIGZsYWdzIHRoYXQgZG9uJ3QgY2F1c2UgdGVtcGxhdGUgY2hhbmdlcyAqL1xuICBhc3luYyBzZXRTYWZlRmxhZ3MocGFyYW1zOiBGbGFnT3BlcmF0aW9uc1BhcmFtcyk6IFByb21pc2U8dm9pZD4ge1xuICAgIGNvbnN0IGNka0pzb24gPSBhd2FpdCBKU09OLnBhcnNlKGF3YWl0IGZzLnJlYWRGaWxlKHBhdGguam9pbihwcm9jZXNzLmN3ZCgpLCAnY2RrLmpzb24nKSwgJ3V0Zi04JykpO1xuICAgIHRoaXMuYXBwID0gcGFyYW1zLmFwcCB8fCBjZGtKc29uLmFwcDtcblxuICAgIGNvbnN0IGlzVXNpbmdUc05vZGUgPSB0aGlzLmFwcC5pbmNsdWRlcygndHMtbm9kZScpO1xuICAgIGlmIChpc1VzaW5nVHNOb2RlICYmICF0aGlzLmFwcC5pbmNsdWRlcygnLVQnKSAmJiAhdGhpcy5hcHAuaW5jbHVkZXMoJy0tdHJhbnNwaWxlT25seScpKSB7XG4gICAgICBhd2FpdCB0aGlzLmlvSGVscGVyLmRlZmF1bHRzLmluZm8oJ1JlcGVhdGVkIHN5bnRocyB3aXRoIHRzLW5vZGUgd2lsbCB0eXBlLWNoZWNrIHRoZSBhcHBsaWNhdGlvbiBvbiBldmVyeSBzeW50aC4gQWRkIC0tdHJhbnNwaWxlT25seSB0byBjZGsuanNvblxcJ3MgXCJhcHBcIiBjb21tYW5kIHRvIG1ha2UgdGhpcyBvcGVyYXRpb24gZmFzdGVyLicpO1xuICAgIH1cblxuICAgIGNvbnN0IHVuY29uZmlndXJlZEZsYWdzID0gdGhpcy5mbGFncy5maWx0ZXIoZmxhZyA9PlxuICAgICAgZmxhZy51c2VyVmFsdWUgPT09IHVuZGVmaW5lZCAmJiB0aGlzLmlzQm9vbGVhbkZsYWcoZmxhZykpO1xuXG4gICAgaWYgKHVuY29uZmlndXJlZEZsYWdzLmxlbmd0aCA9PT0gMCkge1xuICAgICAgYXdhaXQgdGhpcy5pb0hlbHBlci5kZWZhdWx0cy5pbmZvKCdBbGwgZmVhdHVyZSBmbGFncyBhcmUgY29uZmlndXJlZC4nKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBhd2FpdCB0aGlzLmluaXRpYWxpemVTYWZldHlDaGVjaygpO1xuICAgIGNvbnN0IHNhZmVGbGFncyA9IGF3YWl0IHRoaXMuYmF0Y2hUZXN0RmxhZ3ModW5jb25maWd1cmVkRmxhZ3MpO1xuICAgIGF3YWl0IHRoaXMuY2xlYW51cFNhZmV0eUNoZWNrKCk7XG5cbiAgICBpZiAoc2FmZUZsYWdzLmxlbmd0aCA+IDApIHtcbiAgICAgIGF3YWl0IHRoaXMuaW9IZWxwZXIuZGVmYXVsdHMuaW5mbygnRmxhZ3MgdGhhdCBjYW4gYmUgc2V0IHdpdGhvdXQgdGVtcGxhdGUgY2hhbmdlczonKTtcbiAgICAgIGZvciAoY29uc3QgZmxhZyBvZiBzYWZlRmxhZ3MpIHtcbiAgICAgICAgYXdhaXQgdGhpcy5pb0hlbHBlci5kZWZhdWx0cy5pbmZvKGAtICR7ZmxhZy5uYW1lfSAtPiAke2ZsYWcucmVjb21tZW5kZWRWYWx1ZX1gKTtcbiAgICAgIH1cbiAgICAgIGF3YWl0IHRoaXMuaGFuZGxlVXNlclJlc3BvbnNlKHNhZmVGbGFncy5tYXAoZmxhZyA9PiBmbGFnLm5hbWUpLCB7IC4uLnBhcmFtcywgcmVjb21tZW5kZWQ6IHRydWUgfSk7XG4gICAgfSBlbHNlIHtcbiAgICAgIGF3YWl0IHRoaXMuaW9IZWxwZXIuZGVmYXVsdHMuaW5mbygnTm8gbW9yZSBmbGFncyBjYW4gYmUgc2V0IHdpdGhvdXQgY2F1c2luZyB0ZW1wbGF0ZSBjaGFuZ2VzLicpO1xuICAgIH1cbiAgfVxuXG4gIC8qKiBJbml0aWFsaXplcyB0aGUgc2FmZXR5IGNoZWNrIGJ5IHJlYWRpbmcgY29udGV4dCBhbmQgc3ludGhlc2l6aW5nIGJhc2VsaW5lIHRlbXBsYXRlcyAqL1xuICBwcml2YXRlIGFzeW5jIGluaXRpYWxpemVTYWZldHlDaGVjaygpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBjb25zdCBiYXNlQ29udGV4dCA9IG5ldyBDZGtBcHBNdWx0aUNvbnRleHQocHJvY2Vzcy5jd2QoKSk7XG4gICAgdGhpcy5iYXNlQ29udGV4dFZhbHVlcyA9IHsgLi4uYXdhaXQgYmFzZUNvbnRleHQucmVhZCgpLCAuLi50aGlzLmNsaUNvbnRleHRWYWx1ZXMgfTtcblxuICAgIHRoaXMuYmFzZWxpbmVUZW1wRGlyID0gZnMubWtkdGVtcFN5bmMocGF0aC5qb2luKG9zLnRtcGRpcigpLCAnY2RrLWJhc2VsaW5lLScpKTtcbiAgICBjb25zdCBtZXJnZWRDb250ZXh0ID0gbmV3IE1lbW9yeUNvbnRleHQodGhpcy5iYXNlQ29udGV4dFZhbHVlcyk7XG4gICAgY29uc3QgYmFzZVNvdXJjZSA9IGF3YWl0IHRoaXMudG9vbGtpdC5mcm9tQ2RrQXBwKHRoaXMuYXBwLCB7XG4gICAgICBjb250ZXh0U3RvcmU6IG1lcmdlZENvbnRleHQsXG4gICAgICBvdXRkaXI6IHRoaXMuYmFzZWxpbmVUZW1wRGlyLFxuICAgIH0pO1xuXG4gICAgY29uc3QgYmFzZUN4ID0gYXdhaXQgdGhpcy50b29sa2l0LnN5bnRoKGJhc2VTb3VyY2UpO1xuICAgIGNvbnN0IGJhc2VBc3NlbWJseSA9IGJhc2VDeC5jbG91ZEFzc2VtYmx5O1xuICAgIHRoaXMuYWxsU3RhY2tzID0gYmFzZUFzc2VtYmx5LnN0YWNrc1JlY3Vyc2l2ZWx5O1xuICAgIHRoaXMucXVldWUgPSBuZXcgUFF1ZXVlKHsgY29uY3VycmVuY3k6IDQgfSk7XG4gIH1cblxuICAvKiogQ2xlYW5zIHVwIHRlbXBvcmFyeSBkaXJlY3RvcmllcyBjcmVhdGVkIGR1cmluZyBzYWZldHkgY2hlY2tzICovXG4gIHByaXZhdGUgYXN5bmMgY2xlYW51cFNhZmV0eUNoZWNrKCk6IFByb21pc2U8dm9pZD4ge1xuICAgIGlmICh0aGlzLmJhc2VsaW5lVGVtcERpcikge1xuICAgICAgYXdhaXQgZnMucmVtb3ZlKHRoaXMuYmFzZWxpbmVUZW1wRGlyKTtcbiAgICAgIHRoaXMuYmFzZWxpbmVUZW1wRGlyID0gdW5kZWZpbmVkO1xuICAgIH1cbiAgfVxuXG4gIC8qKiBUZXN0cyBtdWx0aXBsZSBmbGFncyB0b2dldGhlciBhbmQgaXNvbGF0ZXMgdW5zYWZlIG9uZXMgdXNpbmcgYmluYXJ5IHNlYXJjaCAqL1xuICBwcml2YXRlIGFzeW5jIGJhdGNoVGVzdEZsYWdzKGZsYWdzOiBGZWF0dXJlRmxhZ1tdKTogUHJvbWlzZTxGZWF0dXJlRmxhZ1tdPiB7XG4gICAgaWYgKGZsYWdzLmxlbmd0aCA9PT0gMCkgcmV0dXJuIFtdO1xuXG4gICAgY29uc3QgYWxsRmxhZ3NDb250ZXh0ID0geyAuLi50aGlzLmJhc2VDb250ZXh0VmFsdWVzIH07XG4gICAgZmxhZ3MuZm9yRWFjaChmbGFnID0+IHtcbiAgICAgIGFsbEZsYWdzQ29udGV4dFtmbGFnLm5hbWVdID0gZmxhZy5yZWNvbW1lbmRlZFZhbHVlO1xuICAgIH0pO1xuXG4gICAgY29uc3QgYWxsU2FmZSA9IGF3YWl0IHRoaXMudGVzdEJhdGNoKGFsbEZsYWdzQ29udGV4dCk7XG4gICAgaWYgKGFsbFNhZmUpIHJldHVybiBmbGFncztcblxuICAgIHJldHVybiB0aGlzLmlzb2xhdGVVbnNhZmVGbGFncyhmbGFncyk7XG4gIH1cblxuICAvKiogVGVzdHMgaWYgYSBzZXQgb2YgY29udGV4dCB2YWx1ZXMgY2F1c2VzIHRlbXBsYXRlIGNoYW5nZXMgYnkgc3ludGhlc2l6aW5nIGFuZCBkaWZmaW5nICovXG4gIHByaXZhdGUgYXN5bmMgdGVzdEJhdGNoKGNvbnRleHRWYWx1ZXM6IFJlY29yZDxzdHJpbmcsIGFueT4pOiBQcm9taXNlPGJvb2xlYW4+IHtcbiAgICBjb25zdCB0ZXN0Q29udGV4dCA9IG5ldyBNZW1vcnlDb250ZXh0KGNvbnRleHRWYWx1ZXMpO1xuICAgIGNvbnN0IHRlbXBEaXIgPSBmcy5ta2R0ZW1wU3luYyhwYXRoLmpvaW4ob3MudG1wZGlyKCksICdjZGstdGVzdC0nKSk7XG4gICAgY29uc3QgdGVzdFNvdXJjZSA9IGF3YWl0IHRoaXMudG9vbGtpdC5mcm9tQ2RrQXBwKHRoaXMuYXBwLCB7XG4gICAgICBjb250ZXh0U3RvcmU6IHRlc3RDb250ZXh0LFxuICAgICAgb3V0ZGlyOiB0ZW1wRGlyLFxuICAgIH0pO1xuXG4gICAgY29uc3QgdGVzdEN4ID0gYXdhaXQgdGhpcy50b29sa2l0LnN5bnRoKHRlc3RTb3VyY2UpO1xuXG4gICAgdHJ5IHtcbiAgICAgIGZvciAoY29uc3Qgc3RhY2sgb2YgdGhpcy5hbGxTdGFja3MpIHtcbiAgICAgICAgY29uc3QgdGVtcGxhdGVQYXRoID0gc3RhY2sudGVtcGxhdGVGdWxsUGF0aDtcbiAgICAgICAgY29uc3QgZGlmZiA9IGF3YWl0IHRoaXMudG9vbGtpdC5kaWZmKHRlc3RDeCwge1xuICAgICAgICAgIG1ldGhvZDogRGlmZk1ldGhvZC5Mb2NhbEZpbGUodGVtcGxhdGVQYXRoKSxcbiAgICAgICAgICBzdGFja3M6IHtcbiAgICAgICAgICAgIHN0cmF0ZWd5OiBTdGFja1NlbGVjdGlvblN0cmF0ZWd5LlBBVFRFUk5fTVVTVF9NQVRDSF9TSU5HTEUsXG4gICAgICAgICAgICBwYXR0ZXJuczogW3N0YWNrLmhpZXJhcmNoaWNhbElkXSxcbiAgICAgICAgICB9LFxuICAgICAgICB9KTtcblxuICAgICAgICBmb3IgKGNvbnN0IHN0YWNrRGlmZiBvZiBPYmplY3QudmFsdWVzKGRpZmYpKSB7XG4gICAgICAgICAgaWYgKHN0YWNrRGlmZi5kaWZmZXJlbmNlQ291bnQgPiAwKSB7XG4gICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9XG4gICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9IGZpbmFsbHkge1xuICAgICAgYXdhaXQgZnMucmVtb3ZlKHRlbXBEaXIpO1xuICAgIH1cbiAgfVxuXG4gIC8qKiBVc2VzIGJpbmFyeSBzZWFyY2ggdG8gaXNvbGF0ZSB3aGljaCBmbGFncyBhcmUgc2FmZSB0byBzZXQgd2l0aG91dCB0ZW1wbGF0ZSBjaGFuZ2VzICovXG4gIHByaXZhdGUgYXN5bmMgaXNvbGF0ZVVuc2FmZUZsYWdzKGZsYWdzOiBGZWF0dXJlRmxhZ1tdKTogUHJvbWlzZTxGZWF0dXJlRmxhZ1tdPiB7XG4gICAgY29uc3Qgc2FmZUZsYWdzOiBGZWF0dXJlRmxhZ1tdID0gW107XG5cbiAgICBjb25zdCBwcm9jZXNzQmF0Y2ggPSBhc3luYyAoYmF0Y2g6IEZlYXR1cmVGbGFnW10sIGNvbnRleHRWYWx1ZXM6IFJlY29yZDxzdHJpbmcsIGFueT4pOiBQcm9taXNlPHZvaWQ+ID0+IHtcbiAgICAgIGlmIChiYXRjaC5sZW5ndGggPT09IDEpIHtcbiAgICAgICAgY29uc3QgaXNTYWZlID0gYXdhaXQgdGhpcy50ZXN0QmF0Y2goXG4gICAgICAgICAgeyAuLi5jb250ZXh0VmFsdWVzLCBbYmF0Y2hbMF0ubmFtZV06IGJhdGNoWzBdLnJlY29tbWVuZGVkVmFsdWUgfSxcbiAgICAgICAgKTtcbiAgICAgICAgaWYgKGlzU2FmZSkgc2FmZUZsYWdzLnB1c2goYmF0Y2hbMF0pO1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IGJhdGNoQ29udGV4dCA9IHsgLi4uY29udGV4dFZhbHVlcyB9O1xuICAgICAgYmF0Y2guZm9yRWFjaChmbGFnID0+IHtcbiAgICAgICAgYmF0Y2hDb250ZXh0W2ZsYWcubmFtZV0gPSBmbGFnLnJlY29tbWVuZGVkVmFsdWU7XG4gICAgICB9KTtcblxuICAgICAgY29uc3QgaXNTYWZlQmF0Y2ggPSBhd2FpdCB0aGlzLnRlc3RCYXRjaChiYXRjaENvbnRleHQpO1xuICAgICAgaWYgKGlzU2FmZUJhdGNoKSB7XG4gICAgICAgIHNhZmVGbGFncy5wdXNoKC4uLmJhdGNoKTtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICBjb25zdCBtaWQgPSBNYXRoLmZsb29yKGJhdGNoLmxlbmd0aCAvIDIpO1xuICAgICAgY29uc3QgbGVmdCA9IGJhdGNoLnNsaWNlKDAsIG1pZCk7XG4gICAgICBjb25zdCByaWdodCA9IGJhdGNoLnNsaWNlKG1pZCk7XG5cbiAgICAgIHZvaWQgdGhpcy5xdWV1ZS5hZGQoKCkgPT4gcHJvY2Vzc0JhdGNoKGxlZnQsIGNvbnRleHRWYWx1ZXMpKTtcbiAgICAgIHZvaWQgdGhpcy5xdWV1ZS5hZGQoKCkgPT4gcHJvY2Vzc0JhdGNoKHJpZ2h0LCBjb250ZXh0VmFsdWVzKSk7XG4gICAgfTtcblxuICAgIHZvaWQgdGhpcy5xdWV1ZS5hZGQoKCkgPT4gcHJvY2Vzc0JhdGNoKGZsYWdzLCB0aGlzLmJhc2VDb250ZXh0VmFsdWVzKSk7XG4gICAgYXdhaXQgdGhpcy5xdWV1ZS5vbklkbGUoKTtcbiAgICByZXR1cm4gc2FmZUZsYWdzO1xuICB9XG5cbiAgLyoqIFByb3RvdHlwZXMgZmxhZyBjaGFuZ2VzIGJ5IHN5bnRoZXNpemluZyB0ZW1wbGF0ZXMgYW5kIHNob3dpbmcgZGlmZnMgdG8gdGhlIHVzZXIgKi9cbiAgcHJpdmF0ZSBhc3luYyBwcm90b3R5cGVDaGFuZ2VzKGZsYWdOYW1lczogc3RyaW5nW10sIHBhcmFtczogRmxhZ09wZXJhdGlvbnNQYXJhbXMpOiBQcm9taXNlPGJvb2xlYW4+IHtcbiAgICBjb25zdCBiYXNlQ29udGV4dCA9IG5ldyBDZGtBcHBNdWx0aUNvbnRleHQocHJvY2Vzcy5jd2QoKSk7XG4gICAgY29uc3QgYmFzZUNvbnRleHRWYWx1ZXMgPSB7IC4uLmF3YWl0IGJhc2VDb250ZXh0LnJlYWQoKSwgLi4udGhpcy5jbGlDb250ZXh0VmFsdWVzIH07XG4gICAgY29uc3QgbWVtb3J5Q29udGV4dCA9IG5ldyBNZW1vcnlDb250ZXh0KGJhc2VDb250ZXh0VmFsdWVzKTtcblxuICAgIGNvbnN0IGNka0pzb24gPSBhd2FpdCBKU09OLnBhcnNlKGF3YWl0IGZzLnJlYWRGaWxlKHBhdGguam9pbihwcm9jZXNzLmN3ZCgpLCAnY2RrLmpzb24nKSwgJ3V0Zi04JykpO1xuICAgIGNvbnN0IGFwcCA9IGNka0pzb24uYXBwO1xuXG4gICAgdGhpcy5vcmlnaW5hbFRlbXBEaXIgPSBmcy5ta2R0ZW1wU3luYyhwYXRoLmpvaW4ob3MudG1wZGlyKCksICdjZGstb3JpZ2luYWwtJykpO1xuICAgIGNvbnN0IHNvdXJjZSA9IGF3YWl0IHRoaXMudG9vbGtpdC5mcm9tQ2RrQXBwKGFwcCwge1xuICAgICAgY29udGV4dFN0b3JlOiBtZW1vcnlDb250ZXh0LFxuICAgICAgb3V0ZGlyOiB0aGlzLm9yaWdpbmFsVGVtcERpcixcbiAgICB9KTtcblxuICAgIGNvbnN0IHVwZGF0ZU9iaiA9IGF3YWl0IHRoaXMuYnVpbGRVcGRhdGVPYmplY3QoZmxhZ05hbWVzLCBwYXJhbXMsIGJhc2VDb250ZXh0VmFsdWVzKTtcbiAgICBpZiAoIXVwZGF0ZU9iaikge1xuICAgICAgYXdhaXQgdGhpcy5jbGVhbnVwVGVtcERpcmVjdG9yaWVzKCk7XG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuXG4gICAgYXdhaXQgbWVtb3J5Q29udGV4dC51cGRhdGUodXBkYXRlT2JqKTtcbiAgICBjb25zdCBjeCA9IGF3YWl0IHRoaXMudG9vbGtpdC5zeW50aChzb3VyY2UpO1xuICAgIGNvbnN0IGFzc2VtYmx5ID0gY3guY2xvdWRBc3NlbWJseTtcblxuICAgIHRoaXMubW9kaWZpZWRUZW1wRGlyID0gZnMubWtkdGVtcFN5bmMocGF0aC5qb2luKG9zLnRtcGRpcigpLCAnY2RrLXRlbXAtJykpO1xuICAgIGNvbnN0IG1vZGlmaWVkU291cmNlID0gYXdhaXQgdGhpcy50b29sa2l0LmZyb21DZGtBcHAoYXBwLCB7XG4gICAgICBjb250ZXh0U3RvcmU6IG1lbW9yeUNvbnRleHQsXG4gICAgICBvdXRkaXI6IHRoaXMubW9kaWZpZWRUZW1wRGlyLFxuICAgIH0pO1xuXG4gICAgY29uc3QgbW9kaWZpZWRDeCA9IGF3YWl0IHRoaXMudG9vbGtpdC5zeW50aChtb2RpZmllZFNvdXJjZSk7XG4gICAgY29uc3QgYWxsU3RhY2tzID0gYXNzZW1ibHkuc3RhY2tzUmVjdXJzaXZlbHk7XG5cbiAgICBmb3IgKGNvbnN0IHN0YWNrIG9mIGFsbFN0YWNrcykge1xuICAgICAgY29uc3QgdGVtcGxhdGVQYXRoID0gc3RhY2sudGVtcGxhdGVGdWxsUGF0aDtcbiAgICAgIGF3YWl0IHRoaXMudG9vbGtpdC5kaWZmKG1vZGlmaWVkQ3gsIHtcbiAgICAgICAgbWV0aG9kOiBEaWZmTWV0aG9kLkxvY2FsRmlsZSh0ZW1wbGF0ZVBhdGgpLFxuICAgICAgICBzdGFja3M6IHtcbiAgICAgICAgICBzdHJhdGVneTogU3RhY2tTZWxlY3Rpb25TdHJhdGVneS5QQVRURVJOX01VU1RfTUFUQ0hfU0lOR0xFLFxuICAgICAgICAgIHBhdHRlcm5zOiBbc3RhY2suaGllcmFyY2hpY2FsSWRdLFxuICAgICAgICB9LFxuICAgICAgfSk7XG4gICAgfVxuXG4gICAgYXdhaXQgdGhpcy5kaXNwbGF5RmxhZ0NoYW5nZXModXBkYXRlT2JqLCBiYXNlQ29udGV4dFZhbHVlcyk7XG4gICAgcmV0dXJuIHRydWU7XG4gIH1cblxuICAvKiogRGlzcGxheXMgYSBzdW1tYXJ5IG9mIGZsYWcgY2hhbmdlcyBzaG93aW5nIG9sZCBhbmQgbmV3IHZhbHVlcyAqL1xuICBwcml2YXRlIGFzeW5jIGRpc3BsYXlGbGFnQ2hhbmdlcyh1cGRhdGVPYmo6IFJlY29yZDxzdHJpbmcsIGJvb2xlYW4+LCBiYXNlQ29udGV4dFZhbHVlczogUmVjb3JkPHN0cmluZywgYW55Pik6IFByb21pc2U8dm9pZD4ge1xuICAgIGF3YWl0IHRoaXMuaW9IZWxwZXIuZGVmYXVsdHMuaW5mbygnXFxuRmxhZyBjaGFuZ2VzOicpO1xuICAgIGZvciAoY29uc3QgW2ZsYWdOYW1lLCBuZXdWYWx1ZV0gb2YgT2JqZWN0LmVudHJpZXModXBkYXRlT2JqKSkge1xuICAgICAgY29uc3QgY3VycmVudFZhbHVlID0gYmFzZUNvbnRleHRWYWx1ZXNbZmxhZ05hbWVdO1xuICAgICAgY29uc3QgY3VycmVudERpc3BsYXkgPSBjdXJyZW50VmFsdWUgPT09IHVuZGVmaW5lZCA/ICc8dW5zZXQ+JyA6IFN0cmluZyhjdXJyZW50VmFsdWUpO1xuICAgICAgYXdhaXQgdGhpcy5pb0hlbHBlci5kZWZhdWx0cy5pbmZvKGAgICR7ZmxhZ05hbWV9OiAke2N1cnJlbnREaXNwbGF5fSDihpIgJHtuZXdWYWx1ZX1gKTtcbiAgICB9XG4gIH1cblxuICAvKiogQnVpbGRzIHRoZSB1cGRhdGUgb2JqZWN0IHdpdGggbmV3IGZsYWcgdmFsdWVzIGJhc2VkIG9uIHBhcmFtZXRlcnMgYW5kIGN1cnJlbnQgY29udGV4dCAqL1xuICBwcml2YXRlIGFzeW5jIGJ1aWxkVXBkYXRlT2JqZWN0KGZsYWdOYW1lczogc3RyaW5nW10sIHBhcmFtczogRmxhZ09wZXJhdGlvbnNQYXJhbXMsIGJhc2VDb250ZXh0VmFsdWVzOiBSZWNvcmQ8c3RyaW5nLCBhbnk+KVxuICAgIDogUHJvbWlzZTxSZWNvcmQ8c3RyaW5nLCBib29sZWFuPiB8IG51bGw+IHtcbiAgICBjb25zdCB1cGRhdGVPYmo6IFJlY29yZDxzdHJpbmcsIGJvb2xlYW4+ID0ge307XG5cbiAgICBpZiAoZmxhZ05hbWVzLmxlbmd0aCA9PT0gMSAmJiBwYXJhbXMudmFsdWUgIT09IHVuZGVmaW5lZCkge1xuICAgICAgY29uc3QgZmxhZ05hbWUgPSBmbGFnTmFtZXNbMF07XG4gICAgICBjb25zdCBib29sVmFsdWUgPSBwYXJhbXMudmFsdWUgPT09ICd0cnVlJztcbiAgICAgIGlmIChiYXNlQ29udGV4dFZhbHVlc1tmbGFnTmFtZV0gPT09IGJvb2xWYWx1ZSkge1xuICAgICAgICBhd2FpdCB0aGlzLmlvSGVscGVyLmRlZmF1bHRzLmluZm8oJ0ZsYWcgaXMgYWxyZWFkeSBzZXQgdG8gdGhlIHNwZWNpZmllZCB2YWx1ZS4gTm8gY2hhbmdlcyBuZWVkZWQuJyk7XG4gICAgICAgIHJldHVybiBudWxsO1xuICAgICAgfVxuICAgICAgdXBkYXRlT2JqW2ZsYWdOYW1lXSA9IGJvb2xWYWx1ZTtcbiAgICB9IGVsc2Uge1xuICAgICAgZm9yIChjb25zdCBmbGFnTmFtZSBvZiBmbGFnTmFtZXMpIHtcbiAgICAgICAgY29uc3QgZmxhZyA9IHRoaXMuZmxhZ3MuZmluZChmID0+IGYubmFtZSA9PT0gZmxhZ05hbWUpO1xuICAgICAgICBpZiAoIWZsYWcpIHtcbiAgICAgICAgICBhd2FpdCB0aGlzLmlvSGVscGVyLmRlZmF1bHRzLmVycm9yKGBGbGFnICR7ZmxhZ05hbWV9IG5vdCBmb3VuZC5gKTtcbiAgICAgICAgICByZXR1cm4gbnVsbDtcbiAgICAgICAgfVxuICAgICAgICBjb25zdCBuZXdWYWx1ZSA9IHBhcmFtcy5yZWNvbW1lbmRlZFxuICAgICAgICAgID8gZmxhZy5yZWNvbW1lbmRlZFZhbHVlIGFzIGJvb2xlYW5cbiAgICAgICAgICA6IFN0cmluZyhkZWZhdWx0VmFsdWUoZmxhZykpID09PSAndHJ1ZSc7XG4gICAgICAgIHVwZGF0ZU9ialtmbGFnTmFtZV0gPSBuZXdWYWx1ZTtcbiAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIHVwZGF0ZU9iajtcbiAgfVxuXG4gIC8qKiBQcm9tcHRzIHVzZXIgZm9yIGNvbmZpcm1hdGlvbiBhbmQgYXBwbGllcyBjaGFuZ2VzIGlmIGFjY2VwdGVkICovXG4gIHByaXZhdGUgYXN5bmMgaGFuZGxlVXNlclJlc3BvbnNlKGZsYWdOYW1lczogc3RyaW5nW10sIHBhcmFtczogRmxhZ09wZXJhdGlvbnNQYXJhbXMpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBjb25zdCB1c2VyQWNjZXB0ZWQgPSBhd2FpdCB0aGlzLmlvSGVscGVyLnJlcXVlc3RSZXNwb25zZSh7XG4gICAgICB0aW1lOiBuZXcgRGF0ZSgpLFxuICAgICAgbGV2ZWw6ICdpbmZvJyxcbiAgICAgIGNvZGU6ICdDREtfVE9PTEtJVF9JOTMwMCcsXG4gICAgICBtZXNzYWdlOiAnRG8geW91IHdhbnQgdG8gYWNjZXB0IHRoZXNlIGNoYW5nZXM/JyxcbiAgICAgIGRhdGE6IHtcbiAgICAgICAgZmxhZ05hbWVzLFxuICAgICAgICByZXNwb25zZURlc2NyaXB0aW9uOiAnRW50ZXIgXCJ5XCIgdG8gYXBwbHkgY2hhbmdlcyBvciBcIm5cIiB0byBjYW5jZWwnLFxuICAgICAgfSxcbiAgICAgIGRlZmF1bHRSZXNwb25zZTogZmFsc2UsXG4gICAgfSk7XG5cbiAgICBpZiAoIXVzZXJBY2NlcHRlZCkge1xuICAgICAgYXdhaXQgdGhpcy5jbGVhbnVwVGVtcERpcmVjdG9yaWVzKCk7XG4gICAgICB0aHJvdyBuZXcgQWJvcnRFcnJvcignRmxhZ3NBYm9ydGVkJywgJ0ZsYWcgdXBkYXRlIGNhbmNlbGxlZCcpO1xuICAgIH1cblxuICAgIGF3YWl0IHRoaXMubW9kaWZ5VmFsdWVzKGZsYWdOYW1lcywgcGFyYW1zKTtcbiAgICBhd2FpdCB0aGlzLmlvSGVscGVyLmRlZmF1bHRzLmluZm8oJ0ZsYWcgdmFsdWUocykgdXBkYXRlZCBzdWNjZXNzZnVsbHkuJyk7XG4gICAgYXdhaXQgdGhpcy5jbGVhbnVwVGVtcERpcmVjdG9yaWVzKCk7XG4gIH1cblxuICAvKiogUmVtb3ZlcyB0ZW1wb3JhcnkgZGlyZWN0b3JpZXMgY3JlYXRlZCBkdXJpbmcgZmxhZyBvcGVyYXRpb25zICovXG4gIHByaXZhdGUgYXN5bmMgY2xlYW51cFRlbXBEaXJlY3RvcmllcygpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBpZiAodGhpcy5vcmlnaW5hbFRlbXBEaXIpIHtcbiAgICAgIGF3YWl0IGZzLnJlbW92ZSh0aGlzLm9yaWdpbmFsVGVtcERpcik7XG4gICAgICB0aGlzLm9yaWdpbmFsVGVtcERpciA9IHVuZGVmaW5lZDtcbiAgICB9XG4gICAgaWYgKHRoaXMubW9kaWZpZWRUZW1wRGlyKSB7XG4gICAgICBhd2FpdCBmcy5yZW1vdmUodGhpcy5tb2RpZmllZFRlbXBEaXIpO1xuICAgICAgdGhpcy5tb2RpZmllZFRlbXBEaXIgPSB1bmRlZmluZWQ7XG4gICAgfVxuICB9XG5cbiAgLyoqIEFjdHVhbGx5IG1vZGlmaWVzIHRoZSBjZGsuanNvbiBmaWxlIHdpdGggdGhlIG5ldyBmbGFnIHZhbHVlcyAqL1xuICBwcml2YXRlIGFzeW5jIG1vZGlmeVZhbHVlcyhmbGFnTmFtZXM6IHN0cmluZ1tdLCBwYXJhbXM6IEZsYWdPcGVyYXRpb25zUGFyYW1zKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgY29uc3QgY2RrSnNvblBhdGggPSBwYXRoLmpvaW4ocHJvY2Vzcy5jd2QoKSwgJ2Nkay5qc29uJyk7XG4gICAgY29uc3QgY2RrSnNvbkNvbnRlbnQgPSBhd2FpdCBmcy5yZWFkRmlsZShjZGtKc29uUGF0aCwgJ3V0Zi04Jyk7XG4gICAgY29uc3QgY2RrSnNvbiA9IEpTT04ucGFyc2UoY2RrSnNvbkNvbnRlbnQpO1xuXG4gICAgaWYgKGZsYWdOYW1lcy5sZW5ndGggPT09IDEgJiYgIXBhcmFtcy5zYWZlICYmICFwYXJhbXMuYWxsKSB7XG4gICAgICBjb25zdCBib29sVmFsdWUgPSBwYXJhbXMudmFsdWUgPT09ICd0cnVlJztcbiAgICAgIGNka0pzb24uY29udGV4dFtTdHJpbmcoZmxhZ05hbWVzWzBdKV0gPSBib29sVmFsdWU7XG4gICAgICBhd2FpdCB0aGlzLmlvSGVscGVyLmRlZmF1bHRzLmluZm8oYFNldHRpbmcgZmxhZyAnJHtmbGFnTmFtZXN9JyB0bzogJHtib29sVmFsdWV9YCk7XG4gICAgfSBlbHNlIHtcbiAgICAgIGZvciAoY29uc3QgZmxhZ05hbWUgb2YgZmxhZ05hbWVzKSB7XG4gICAgICAgIGNvbnN0IGZsYWcgPSB0aGlzLmZsYWdzLmZpbmQoZiA9PiBmLm5hbWUgPT09IGZsYWdOYW1lKSE7XG4gICAgICAgIGNvbnN0IG5ld1ZhbHVlID0gcGFyYW1zLnJlY29tbWVuZGVkIHx8IHBhcmFtcy5zYWZlXG4gICAgICAgICAgPyBmbGFnLnJlY29tbWVuZGVkVmFsdWUgYXMgYm9vbGVhblxuICAgICAgICAgIDogU3RyaW5nKGRlZmF1bHRWYWx1ZShmbGFnKSkgPT09ICd0cnVlJztcbiAgICAgICAgY2RrSnNvbi5jb250ZXh0W2ZsYWdOYW1lXSA9IG5ld1ZhbHVlO1xuICAgICAgfVxuICAgIH1cbiAgICBhd2FpdCBmcy53cml0ZUZpbGUoY2RrSnNvblBhdGgsIEpTT04uc3RyaW5naWZ5KGNka0pzb24sIG51bGwsIDIpLCAndXRmLTgnKTtcbiAgfVxuXG4gIC8qKiBEaXNwbGF5cyBmbGFncyBpbiBhIHRhYmxlIGZvcm1hdCwgZWl0aGVyIHNwZWNpZmljIGZsYWdzIG9yIGZpbHRlcmVkIGJ5IGNyaXRlcmlhICovXG4gIGFzeW5jIGRpc3BsYXlGbGFncyhwYXJhbXM6IEZsYWdPcGVyYXRpb25zUGFyYW1zKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgY29uc3QgeyBGTEFHTkFNRSwgYWxsIH0gPSBwYXJhbXM7XG5cbiAgICBpZiAoRkxBR05BTUUgJiYgRkxBR05BTUUubGVuZ3RoID4gMCkge1xuICAgICAgYXdhaXQgdGhpcy5kaXNwbGF5U3BlY2lmaWNGbGFncyhGTEFHTkFNRSk7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgY29uc3QgW2ZsYWdzVG9EaXNwbGF5LCBoZWFkZXJdID0gYWxsXG4gICAgICA/IFt0aGlzLmZsYWdzLCAnQWxsIGZlYXR1cmUgZmxhZ3MnXVxuICAgICAgOiBbRmxhZ09wZXJhdGlvbnMuZmlsdGVyTmVlZHNBdHRlbnRpb24odGhpcy5mbGFncyksICdVbmNvbmZpZ3VyZWQgZmVhdHVyZSBmbGFncyddO1xuXG4gICAgYXdhaXQgdGhpcy5pb0hlbHBlci5kZWZhdWx0cy5pbmZvKGhlYWRlcik7XG4gICAgYXdhaXQgdGhpcy5kaXNwbGF5RmxhZ1RhYmxlKGZsYWdzVG9EaXNwbGF5KTtcblxuICAgIC8vIEFkZCBoZWxwZnVsIG1lc3NhZ2UgYWZ0ZXIgZW1wdHkgdGFibGUgd2hlbiBub3QgdXNpbmcgLS1hbGxcbiAgICBpZiAoIWFsbCAmJiBmbGFnc1RvRGlzcGxheS5sZW5ndGggPT09IDApIHtcbiAgICAgIGF3YWl0IHRoaXMuaW9IZWxwZXIuZGVmYXVsdHMuaW5mbygnJyk7XG4gICAgICBhd2FpdCB0aGlzLmlvSGVscGVyLmRlZmF1bHRzLmluZm8oJ+KchSBBbGwgZmVhdHVyZSBmbGFncyBhcmUgYWxyZWFkeSBzZXQgdG8gdGhlaXIgcmVjb21tZW5kZWQgdmFsdWVzLicpO1xuICAgICAgYXdhaXQgdGhpcy5pb0hlbHBlci5kZWZhdWx0cy5pbmZvKCdVc2UgXFwnY2RrIGZsYWdzIC0tYWxsIC0tdW5zdGFibGU9ZmxhZ3NcXCcgdG8gc2VlIGFsbCBmbGFncyBhbmQgdGhlaXIgY3VycmVudCB2YWx1ZXMuJyk7XG4gICAgfVxuICB9XG5cbiAgLyoqIERpc3BsYXlzIGRldGFpbGVkIGluZm9ybWF0aW9uIGZvciBzcGVjaWZpYyBmbGFncyBtYXRjaGluZyB0aGUgZ2l2ZW4gbmFtZXMgKi9cbiAgcHJpdmF0ZSBhc3luYyBkaXNwbGF5U3BlY2lmaWNGbGFncyhmbGFnTmFtZXM6IHN0cmluZ1tdKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgY29uc3QgbWF0Y2hpbmdGbGFncyA9IHRoaXMuZmxhZ3MuZmlsdGVyKGYgPT5cbiAgICAgIGZsYWdOYW1lcy5zb21lKHNlYXJjaFRlcm0gPT4gZi5uYW1lLnRvTG93ZXJDYXNlKCkuaW5jbHVkZXMoc2VhcmNoVGVybS50b0xvd2VyQ2FzZSgpKSkpO1xuXG4gICAgaWYgKG1hdGNoaW5nRmxhZ3MubGVuZ3RoID09PSAwKSB7XG4gICAgICBhd2FpdCB0aGlzLmlvSGVscGVyLmRlZmF1bHRzLmVycm9yKGBGbGFnIG1hdGNoaW5nIFwiJHtmbGFnTmFtZXMuam9pbignLCAnKX1cIiBub3QgZm91bmQuYCk7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgaWYgKG1hdGNoaW5nRmxhZ3MubGVuZ3RoID09PSAxKSB7XG4gICAgICBjb25zdCBmbGFnID0gbWF0Y2hpbmdGbGFnc1swXTtcbiAgICAgIGF3YWl0IHRoaXMuaW9IZWxwZXIuZGVmYXVsdHMuaW5mbyhgRmxhZyBuYW1lOiAke2ZsYWcubmFtZX1gKTtcbiAgICAgIGF3YWl0IHRoaXMuaW9IZWxwZXIuZGVmYXVsdHMuaW5mbyhgRGVzY3JpcHRpb246ICR7ZmxhZy5leHBsYW5hdGlvbn1gKTtcbiAgICAgIGF3YWl0IHRoaXMuaW9IZWxwZXIuZGVmYXVsdHMuaW5mbyhgUmVjb21tZW5kZWQgdmFsdWU6ICR7ZmxhZy5yZWNvbW1lbmRlZFZhbHVlfWApO1xuICAgICAgYXdhaXQgdGhpcy5pb0hlbHBlci5kZWZhdWx0cy5pbmZvKGBEZWZhdWx0IHZhbHVlOiAke2RlZmF1bHRWYWx1ZShmbGFnKX1gKTtcbiAgICAgIGF3YWl0IHRoaXMuaW9IZWxwZXIuZGVmYXVsdHMuaW5mbyhgVXNlciB2YWx1ZTogJHtmbGFnLnVzZXJWYWx1ZX1gKTtcbiAgICAgIGF3YWl0IHRoaXMuaW9IZWxwZXIuZGVmYXVsdHMuaW5mbyhgRWZmZWN0aXZlIHZhbHVlOiAke2VmZmVjdGl2ZVZhbHVlKGZsYWcpfWApO1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGF3YWl0IHRoaXMuaW9IZWxwZXIuZGVmYXVsdHMuaW5mbyhgRm91bmQgJHttYXRjaGluZ0ZsYWdzLmxlbmd0aH0gZmxhZ3MgbWF0Y2hpbmcgXCIke2ZsYWdOYW1lcy5qb2luKCcsICcpfVwiYCk7XG4gICAgYXdhaXQgdGhpcy5kaXNwbGF5RmxhZ1RhYmxlKG1hdGNoaW5nRmxhZ3MpO1xuICB9XG5cbiAgLyoqIFJldHVybnMgc29ydCBvcmRlciBmb3IgZmxhZ3MgKi9cbiAgcHJpdmF0ZSBnZXRGbGFnU29ydE9yZGVyKGZsYWc6IEZlYXR1cmVGbGFnKTogbnVtYmVyIHtcbiAgICBpZiAoZmxhZy51c2VyVmFsdWUgPT09IHVuZGVmaW5lZCkgcmV0dXJuIDM7XG4gICAgaWYgKGlzRWZmZWN0aXZlVmFsdWVFcXVhbFRvUmVjb21tZW5kZWQoZmxhZykpIHJldHVybiAxO1xuICAgIHJldHVybiAyO1xuICB9XG5cbiAgLyoqIERpc3BsYXlzIGZsYWdzIGluIGEgZm9ybWF0dGVkIHRhYmxlIGdyb3VwZWQgYnkgbW9kdWxlIGFuZCBzb3J0ZWQgKi9cbiAgYXN5bmMgZGlzcGxheUZsYWdUYWJsZShmbGFnczogRmVhdHVyZUZsYWdbXSk6IFByb21pc2U8dm9pZD4ge1xuICAgIGNvbnN0IHNvcnRlZEZsYWdzID0gWy4uLmZsYWdzXS5zb3J0KChhLCBiKSA9PiB7XG4gICAgICBjb25zdCBvcmRlckEgPSB0aGlzLmdldEZsYWdTb3J0T3JkZXIoYSk7XG4gICAgICBjb25zdCBvcmRlckIgPSB0aGlzLmdldEZsYWdTb3J0T3JkZXIoYik7XG5cbiAgICAgIGlmIChvcmRlckEgIT09IG9yZGVyQikgcmV0dXJuIG9yZGVyQSAtIG9yZGVyQjtcbiAgICAgIGlmIChhLm1vZHVsZSAhPT0gYi5tb2R1bGUpIHJldHVybiBhLm1vZHVsZS5sb2NhbGVDb21wYXJlKGIubW9kdWxlKTtcbiAgICAgIHJldHVybiBhLm5hbWUubG9jYWxlQ29tcGFyZShiLm5hbWUpO1xuICAgIH0pO1xuXG4gICAgY29uc3Qgcm93czogc3RyaW5nW11bXSA9IFtbJ0ZlYXR1cmUgRmxhZycsICdSZWNvbW1lbmRlZCcsICdVc2VyJywgJ0VmZmVjdGl2ZSddXTtcbiAgICBsZXQgY3VycmVudE1vZHVsZSA9ICcnO1xuXG4gICAgc29ydGVkRmxhZ3MuZm9yRWFjaCgoZmxhZykgPT4ge1xuICAgICAgaWYgKGZsYWcubW9kdWxlICE9PSBjdXJyZW50TW9kdWxlKSB7XG4gICAgICAgIHJvd3MucHVzaChbY2hhbGsuYm9sZChgTW9kdWxlOiAke2ZsYWcubW9kdWxlfWApLCAnJywgJycsICcnXSk7XG4gICAgICAgIGN1cnJlbnRNb2R1bGUgPSBmbGFnLm1vZHVsZTtcbiAgICAgIH1cbiAgICAgIHJvd3MucHVzaChbXG4gICAgICAgIGAgICR7ZmxhZy5uYW1lfWAsXG4gICAgICAgIFN0cmluZyhmbGFnLnJlY29tbWVuZGVkVmFsdWUpLFxuICAgICAgICBmbGFnLnVzZXJWYWx1ZSA9PT0gdW5kZWZpbmVkID8gJzx1bnNldD4nIDogU3RyaW5nKGZsYWcudXNlclZhbHVlKSxcbiAgICAgICAgU3RyaW5nKGVmZmVjdGl2ZVZhbHVlKGZsYWcpKSxcbiAgICAgIF0pO1xuICAgIH0pO1xuXG4gICAgY29uc3QgZm9ybWF0dGVkVGFibGUgPSBmb3JtYXRUYWJsZShyb3dzLCB1bmRlZmluZWQsIHRydWUpO1xuICAgIGF3YWl0IHRoaXMuaW9IZWxwZXIuZGVmYXVsdHMuaW5mbyhmb3JtYXR0ZWRUYWJsZSk7XG4gIH1cblxuICAvKiogQ2hlY2tzIGlmIGEgZmxhZyBoYXMgYSBib29sZWFuIHJlY29tbWVuZGVkIHZhbHVlICovXG4gIGlzQm9vbGVhbkZsYWcoZmxhZzogRmVhdHVyZUZsYWcpOiBib29sZWFuIHtcbiAgICBjb25zdCByZWNvbW1lbmRlZCA9IGZsYWcucmVjb21tZW5kZWRWYWx1ZTtcbiAgICByZXR1cm4gdHlwZW9mIHJlY29tbWVuZGVkID09PSAnYm9vbGVhbicgfHxcbiAgICAgIHJlY29tbWVuZGVkID09PSAndHJ1ZScgfHxcbiAgICAgIHJlY29tbWVuZGVkID09PSAnZmFsc2UnO1xuICB9XG5cbiAgLyoqIFNob3dzIGhlbHBmdWwgdXNhZ2UgZXhhbXBsZXMgYW5kIGF2YWlsYWJsZSBjb21tYW5kIG9wdGlvbnMgKi9cbiAgYXN5bmMgZGlzcGxheUhlbHBNZXNzYWdlKCk6IFByb21pc2U8dm9pZD4ge1xuICAgIGF3YWl0IHRoaXMuaW9IZWxwZXIuZGVmYXVsdHMuaW5mbygnXFxuJyArIGNoYWxrLmJvbGQoJ0F2YWlsYWJsZSBvcHRpb25zOicpKTtcbiAgICBhd2FpdCB0aGlzLmlvSGVscGVyLmRlZmF1bHRzLmluZm8oJyAgY2RrIGZsYWdzIC0taW50ZXJhY3RpdmUgICAgICMgSW50ZXJhY3RpdmUgbWVudSB0byBtYW5hZ2UgZmxhZ3MnKTtcbiAgICBhd2FpdCB0aGlzLmlvSGVscGVyLmRlZmF1bHRzLmluZm8oJyAgY2RrIGZsYWdzIC0tYWxsICAgICAgICAgICAgICMgU2hvdyBhbGwgZmxhZ3MgKGluY2x1ZGluZyBjb25maWd1cmVkIG9uZXMpJyk7XG4gICAgYXdhaXQgdGhpcy5pb0hlbHBlci5kZWZhdWx0cy5pbmZvKCcgIGNkayBmbGFncyAtLXNldCAtLWFsbCAtLXJlY29tbWVuZGVkICAgICMgU2V0IGFsbCBmbGFncyB0byByZWNvbW1lbmRlZCB2YWx1ZXMnKTtcbiAgICBhd2FpdCB0aGlzLmlvSGVscGVyLmRlZmF1bHRzLmluZm8oJyAgY2RrIGZsYWdzIC0tc2V0IC0tYWxsIC0tZGVmYXVsdCAgICAgICAjIFNldCBhbGwgZmxhZ3MgdG8gZGVmYXVsdCB2YWx1ZXMnKTtcbiAgICBhd2FpdCB0aGlzLmlvSGVscGVyLmRlZmF1bHRzLmluZm8oJyAgY2RrIGZsYWdzIC0tc2V0IC0tdW5jb25maWd1cmVkIC0tcmVjb21tZW5kZWQgICMgU2V0IHVuY29uZmlndXJlZCBmbGFncyB0byByZWNvbW1lbmRlZCcpO1xuICAgIGF3YWl0IHRoaXMuaW9IZWxwZXIuZGVmYXVsdHMuaW5mbygnICBjZGsgZmxhZ3MgLS1zZXQgPGZsYWctbmFtZT4gLS12YWx1ZSA8dHJ1ZXxmYWxzZT4gICMgU2V0IHNwZWNpZmljIGZsYWcnKTtcbiAgICBhd2FpdCB0aGlzLmlvSGVscGVyLmRlZmF1bHRzLmluZm8oJyAgY2RrIGZsYWdzIC0tc2FmZSAgICAgICAgICAgICMgU2FmZWx5IHNldCBmbGFncyB0aGF0IGRvblxcJ3QgY2hhbmdlIHRlbXBsYXRlcycpO1xuICB9XG59XG5cbi8qKiBDaGVja3MgaWYgdGhlIGZsYWdzIGN1cnJlbnQgZWZmZWN0aXZlIHZhbHVlIG1hdGNoZXMgdGhlIHJlY29tbWVuZGVkIHZhbHVlICovXG5leHBvcnQgZnVuY3Rpb24gaXNFZmZlY3RpdmVWYWx1ZUVxdWFsVG9SZWNvbW1lbmRlZChmbGFnOiBGZWF0dXJlRmxhZyk6IGJvb2xlYW4ge1xuICByZXR1cm4gU3RyaW5nKGVmZmVjdGl2ZVZhbHVlKGZsYWcpKSA9PT0gU3RyaW5nKGZsYWcucmVjb21tZW5kZWRWYWx1ZSk7XG59XG5cbi8qKlxuICogUmV0dXJuIHRoZSBlZmZlY3RpdmUgdmFsdWUgb2YgYSBmbGFnICh1c2VyIHZhbHVlIG9yIGRlZmF1bHQpXG4gKi9cbmZ1bmN0aW9uIGVmZmVjdGl2ZVZhbHVlKGZsYWc6IEZlYXR1cmVGbGFnKSB7XG4gIHJldHVybiBmbGFnLnVzZXJWYWx1ZSA/PyBkZWZhdWx0VmFsdWUoZmxhZyk7XG59XG5cbi8qKlxuICogUmV0dXJuIHRoZSBkZWZhdWx0IHZhbHVlIGZvciBhIGZsYWcsIGFzc3VtZSBpdCdzIGBmYWxzZWAgaWYgbm90IGdpdmVuXG4gKi9cbmZ1bmN0aW9uIGRlZmF1bHRWYWx1ZShmbGFnOiBGZWF0dXJlRmxhZykge1xuICByZXR1cm4gZmxhZy51bmNvbmZpZ3VyZWRCZWhhdmVzTGlrZT8udjIgPz8gZmFsc2U7XG59XG4iXX0=