Files
agent-claw/cdk/node_modules/aws-cdk/lib/commands/migrate.js
2026-05-06 18:55:16 -05:00

801 lines
113 KiB
JavaScript

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.FromScan = exports.CfnTemplateGeneratorProvider = exports.FilterType = exports.ScanStatus = exports.TemplateSourceOptions = void 0;
exports.generateCdkApp = generateCdkApp;
exports.generateStack = generateStack;
exports.readFromPath = readFromPath;
exports.readFromStack = readFromStack;
exports.generateTemplate = generateTemplate;
exports.chunks = chunks;
exports.setEnvironment = setEnvironment;
exports.parseSourceOptions = parseSourceOptions;
exports.printBar = printBar;
exports.printDots = printDots;
exports.rewriteLine = rewriteLine;
exports.writeMigrateJsonFile = writeMigrateJsonFile;
exports.getMigrateScanType = getMigrateScanType;
exports.isThereAWarning = isThereAWarning;
exports.buildGeneratedTemplateOutput = buildGeneratedTemplateOutput;
exports.buildCfnClient = buildCfnClient;
exports.appendWarningsToReadme = appendWarningsToReadme;
/* eslint-disable @typescript-eslint/no-require-imports */
/* eslint-disable @typescript-eslint/no-var-requires */
const fs = require("fs");
const path = require("path");
const cloud_assembly_api_1 = require("@aws-cdk/cloud-assembly-api");
const toolkit_lib_1 = require("@aws-cdk/toolkit-lib");
const cdk_from_cfn = require("cdk-from-cfn");
const chalk = require("chalk");
const init_1 = require("./init");
const cloudformation_1 = require("../api/cloudformation");
const plugin_1 = require("../api/plugin");
const util_1 = require("../util");
const camelCase = require('camelcase');
const decamelize = require('decamelize');
/** The list of languages supported by the built-in noctilucent binary. */
const MIGRATE_SUPPORTED_LANGUAGES = cdk_from_cfn.supported_languages();
/**
* Generates a CDK app from a yaml or json template.
*
* @param stackName - The name to assign to the stack in the generated app
* @param stack - The yaml or json template for the stack
* @param language - The language to generate the CDK app in
* @param outputPath - The path at which to generate the CDK app
*/
async function generateCdkApp(ioHelper, stackName, stack, language, outputPath, compress) {
const resolvedOutputPath = path.join(outputPath ?? process.cwd(), stackName);
const formattedStackName = decamelize(stackName);
try {
fs.rmSync(resolvedOutputPath, { recursive: true, force: true });
fs.mkdirSync(resolvedOutputPath, { recursive: true });
const generateOnly = compress;
await (0, init_1.cliInit)({
ioHelper,
type: 'app',
language,
canUseNetwork: true,
generateOnly,
workDir: resolvedOutputPath,
stackName,
migrate: true,
});
let stackFileName;
switch (language) {
case 'typescript':
stackFileName = `${resolvedOutputPath}/lib/${formattedStackName}-stack.ts`;
break;
case 'java':
stackFileName = `${resolvedOutputPath}/src/main/java/com/myorg/${camelCase(formattedStackName, { pascalCase: true })}Stack.java`;
break;
case 'python':
stackFileName = `${resolvedOutputPath}/${formattedStackName.replace(/-/g, '_')}/${formattedStackName.replace(/-/g, '_')}_stack.py`;
break;
case 'csharp':
stackFileName = `${resolvedOutputPath}/src/${camelCase(formattedStackName, { pascalCase: true })}/${camelCase(formattedStackName, { pascalCase: true })}Stack.cs`;
break;
case 'go':
stackFileName = `${resolvedOutputPath}/${formattedStackName}.go`;
break;
default:
throw new toolkit_lib_1.ToolkitError('UnsupportedMigrateLanguage', `${language} is not supported by CDK Migrate. Please choose from: ${MIGRATE_SUPPORTED_LANGUAGES.join(', ')}`);
}
fs.writeFileSync(stackFileName, stack);
if (compress) {
await (0, util_1.zipDirectory)(resolvedOutputPath, `${resolvedOutputPath}.zip`);
fs.rmSync(resolvedOutputPath, { recursive: true, force: true });
}
}
catch (error) {
fs.rmSync(resolvedOutputPath, { recursive: true, force: true });
throw error;
}
}
/**
* Generates a CDK stack file.
* @param template - The template to translate into a CDK stack
* @param stackName - The name to assign to the stack
* @param language - The language to generate the stack in
* @returns A string representation of a CDK stack file
*/
function generateStack(template, stackName, language) {
const formattedStackName = `${camelCase(decamelize(stackName), { pascalCase: true })}Stack`;
try {
return cdk_from_cfn.transmute(template, language, formattedStackName);
}
catch (e) {
throw new toolkit_lib_1.ToolkitError('StackGenerationFailed', `${formattedStackName} could not be generated because ${e.message}`);
}
}
/**
* Reads and returns a stack template from a local path.
*
* @param inputPath - The location of the template
* @returns A string representation of the template if present, otherwise undefined
*/
function readFromPath(inputPath) {
let readFile;
try {
readFile = fs.readFileSync(inputPath, 'utf8');
}
catch (e) {
throw new toolkit_lib_1.ToolkitError('InvalidPath', `'${inputPath}' is not a valid path.`);
}
if (readFile == '') {
throw new toolkit_lib_1.ToolkitError('EmptyTemplateFile', `Cloudformation template filepath: '${inputPath}' is an empty file.`);
}
return readFile;
}
/**
* Reads and returns a stack template from a deployed CloudFormation stack.
*
* @param stackName - The name of the stack
* @param sdkProvider - The sdk provider for making CloudFormation calls
* @param environment - The account and region where the stack is deployed
* @returns A string representation of the template if present, otherwise undefined
*/
async function readFromStack(stackName, sdkProvider, environment) {
const cloudFormation = (await sdkProvider.forEnvironment(environment, plugin_1.Mode.ForReading)).sdk.cloudFormation();
const stack = await cloudformation_1.CloudFormationStack.lookup(cloudFormation, stackName, true);
if (stack.stackStatus.isDeploySuccess || stack.stackStatus.isRollbackSuccess) {
return JSON.stringify(await stack.template());
}
else {
throw new toolkit_lib_1.ToolkitError('UnhealthyStackStatus', `Stack '${stackName}' in account ${environment.account} and region ${environment.region} has a status of '${stack.stackStatus.name}' due to '${stack.stackStatus.reason}'. The stack cannot be migrated until it is in a healthy state.`);
}
}
/**
* Takes in a stack name and account and region and returns a generated cloudformation template using the cloudformation
* template generator.
*
* @param GenerateTemplateOptions - An object containing the stack name, filters, sdkProvider, environment, and newScan flag
* @returns a generated cloudformation template
*/
async function generateTemplate(options) {
const cfn = new CfnTemplateGeneratorProvider(await buildCfnClient(options.sdkProvider, options.environment), options.ioHelper);
const ioHelper = options.ioHelper;
const scanId = await findLastSuccessfulScan(cfn, options);
// if a customer accidentally ctrl-c's out of the command and runs it again, this will continue the progress bar where it left off
const curScan = await cfn.describeResourceScan(scanId);
if (curScan.Status == ScanStatus.IN_PROGRESS) {
await ioHelper.defaults.info('Resource scan in progress. Please wait, this can take 10 minutes or longer.');
await scanProgressBar(ioHelper, scanId, cfn);
}
await displayTimeDiff(ioHelper, new Date(), new Date(curScan.StartTime));
let resources = await cfn.listResourceScanResources(scanId, options.filters);
await ioHelper.defaults.info('finding related resources.');
let relatedResources = await cfn.getResourceScanRelatedResources(scanId, resources);
await ioHelper.defaults.info(`Found ${relatedResources.length} resources.`);
await ioHelper.defaults.info('Generating CFN template from scanned resources.');
const templateArn = (await cfn.createGeneratedTemplate(options.stackName, relatedResources)).GeneratedTemplateId;
let generatedTemplate = await cfn.describeGeneratedTemplate(templateArn);
await ioHelper.defaults.info('Please wait, template creation in progress. This may take a couple minutes.');
while (generatedTemplate.Status !== ScanStatus.COMPLETE && generatedTemplate.Status !== ScanStatus.FAILED) {
await printDots(`[${generatedTemplate.Status}] Template Creation in Progress`, 400);
generatedTemplate = await cfn.describeGeneratedTemplate(templateArn);
}
await ioHelper.defaults.info('\nTemplate successfully generated!');
return buildGeneratedTemplateOutput(generatedTemplate, (await cfn.getGeneratedTemplate(templateArn)).TemplateBody, templateArn);
}
async function findLastSuccessfulScan(cfn, options) {
const ioHelper = options.ioHelper;
let resourceScanSummaries = [];
const clientRequestToken = `cdk-migrate-${options.environment.account}-${options.environment.region}`;
if (options.fromScan === FromScan.NEW) {
await ioHelper.defaults.info(`Starting new scan for account ${options.environment.account} in region ${options.environment.region}`);
try {
await cfn.startResourceScan(clientRequestToken);
resourceScanSummaries = (await cfn.listResourceScans()).ResourceScanSummaries;
}
catch (e) {
// continuing here because if the scan fails on a new-scan it is very likely because there is either already a scan in progress
// or the customer hit a rate limit. In either case we want to continue with the most recent scan.
// If this happens to fail for a credential error then that will be caught immediately after anyway.
await ioHelper.defaults.info(`Scan failed to start due to error '${e.message}', defaulting to latest scan.`);
}
}
else {
resourceScanSummaries = (await cfn.listResourceScans()).ResourceScanSummaries;
await cfn.checkForResourceScan(resourceScanSummaries, options, clientRequestToken);
}
// get the latest scan, which we know will exist
resourceScanSummaries = (await cfn.listResourceScans()).ResourceScanSummaries;
let scanId = resourceScanSummaries[0].ResourceScanId;
// find the most recent scan that isn't in a failed state in case we didn't start a new one
for (const summary of resourceScanSummaries) {
if (summary.Status !== ScanStatus.FAILED) {
scanId = summary.ResourceScanId;
break;
}
}
return scanId;
}
/**
* Takes a string of filters in the format of key1=value1,key2=value2 and returns a map of the filters.
*
* @param filters - a string of filters in the format of key1=value1,key2=value2
* @returns a map of the filters
*/
function parseFilters(filters) {
if (!filters) {
return {
'resource-identifier': undefined,
'resource-type-prefix': undefined,
'tag-key': undefined,
'tag-value': undefined,
};
}
const filterShorthands = {
'identifier': FilterType.RESOURCE_IDENTIFIER,
'id': FilterType.RESOURCE_IDENTIFIER,
'type': FilterType.RESOURCE_TYPE_PREFIX,
'type-prefix': FilterType.RESOURCE_TYPE_PREFIX,
};
const filterList = filters.split(',');
let filterMap = {
[FilterType.RESOURCE_IDENTIFIER]: undefined,
[FilterType.RESOURCE_TYPE_PREFIX]: undefined,
[FilterType.TAG_KEY]: undefined,
[FilterType.TAG_VALUE]: undefined,
};
for (const fil of filterList) {
const filter = fil.split('=');
let filterKey = filter[0];
const filterValue = filter[1];
// if the key is a shorthand, replace it with the full name
if (filterKey in filterShorthands) {
filterKey = filterShorthands[filterKey];
}
if (Object.values(FilterType).includes(filterKey)) {
filterMap[filterKey] = filterValue;
}
else {
throw new toolkit_lib_1.ToolkitError('InvalidFilter', `Invalid filter: ${filterKey}`);
}
}
return filterMap;
}
/**
* Takes a list of any type and breaks it up into chunks of a specified size.
*
* @param list - The list to break up
* @param chunkSize - The size of each chunk
* @returns A list of lists of the specified size
*/
function chunks(list, chunkSize) {
const chunkedList = [];
for (let i = 0; i < list.length; i += chunkSize) {
chunkedList.push(list.slice(i, i + chunkSize));
}
return chunkedList;
}
/**
* Sets the account and region for making CloudFormation calls.
* @param account - The account to use
* @param region - The region to use
* @returns The environment object
*/
function setEnvironment(account, region) {
return {
account: account ?? cloud_assembly_api_1.UNKNOWN_ACCOUNT,
region: region ?? cloud_assembly_api_1.UNKNOWN_REGION,
name: 'cdk-migrate-env',
};
}
/**
* Enum for the source options for the template
*/
var TemplateSourceOptions;
(function (TemplateSourceOptions) {
TemplateSourceOptions["PATH"] = "path";
TemplateSourceOptions["STACK"] = "stack";
TemplateSourceOptions["SCAN"] = "scan";
})(TemplateSourceOptions || (exports.TemplateSourceOptions = TemplateSourceOptions = {}));
/**
* Enum for the status of a resource scan
*/
var ScanStatus;
(function (ScanStatus) {
ScanStatus["IN_PROGRESS"] = "IN_PROGRESS";
ScanStatus["COMPLETE"] = "COMPLETE";
ScanStatus["FAILED"] = "FAILED";
})(ScanStatus || (exports.ScanStatus = ScanStatus = {}));
var FilterType;
(function (FilterType) {
FilterType["RESOURCE_IDENTIFIER"] = "resource-identifier";
FilterType["RESOURCE_TYPE_PREFIX"] = "resource-type-prefix";
FilterType["TAG_KEY"] = "tag-key";
FilterType["TAG_VALUE"] = "tag-value";
})(FilterType || (exports.FilterType = FilterType = {}));
/**
* Validates that exactly one source option has been provided.
* @param fromPath - The content of the flag `--from-path`
* @param fromStack - the content of the flag `--from-stack`
*/
function parseSourceOptions(fromPath, fromStack, stackName) {
if (fromPath && fromStack) {
throw new toolkit_lib_1.ToolkitError('ConflictingSourceOptions', 'Only one of `--from-path` or `--from-stack` may be provided.');
}
if (!stackName) {
throw new toolkit_lib_1.ToolkitError('MissingStackName', '`--stack-name` is a required field.');
}
if (!fromPath && !fromStack) {
return { source: TemplateSourceOptions.SCAN };
}
if (fromPath) {
return { source: TemplateSourceOptions.PATH, templatePath: fromPath };
}
return { source: TemplateSourceOptions.STACK, stackName: stackName };
}
/**
* Takes a set of resources and removes any with the managedbystack flag set to true.
*
* @param resourceList - the list of resources provided by the list scanned resources calls
* @returns a list of resources not managed by cfn stacks
*/
function excludeManaged(resourceList) {
return resourceList
.filter((r) => !r.ManagedByStack)
.map((r) => ({
ResourceType: r.ResourceType,
ResourceIdentifier: r.ResourceIdentifier,
}));
}
/**
* Transforms a list of resources into a list of resource identifiers by removing the ManagedByStack flag.
* Setting the value of the field to undefined effectively removes it from the object.
*
* @param resourceList - the list of resources provided by the list scanned resources calls
* @returns a list of ScannedResourceIdentifier[]
*/
function resourceIdentifiers(resourceList) {
const identifiers = [];
resourceList.forEach((r) => {
const identifier = {
ResourceType: r.ResourceType,
ResourceIdentifier: r.ResourceIdentifier,
};
identifiers.push(identifier);
});
return identifiers;
}
/**
* Takes a scan id and maintains a progress bar to display the progress of a scan to the user.
*
* @param scanId - A string representing the scan id
* @param cloudFormation - The CloudFormation sdk client to use
*/
async function scanProgressBar(ioHelper, scanId, cfn) {
let curProgress = 0.5;
// we know it's in progress initially since we wouldn't have gotten here if it wasn't
let curScan = {
Status: ScanStatus.IN_PROGRESS,
$metadata: {},
};
while (curScan.Status == ScanStatus.IN_PROGRESS) {
curScan = await cfn.describeResourceScan(scanId);
curProgress = curScan.PercentageCompleted ?? curProgress;
printBar(30, curProgress);
await new Promise((resolve) => setTimeout(resolve, 2000));
}
await ioHelper.defaults.info('\n✅ Scan Complete!');
}
/**
* Prints a progress bar to the console. To be used in a while loop to show progress of a long running task.
* The progress bar deletes the current line on the console and rewrites it with the progress amount.
*
* @param width - The width of the progress bar
* @param progress - The current progress to display as a percentage of 100
*/
function printBar(width, progress) {
if (!process.env.MIGRATE_INTEG_TEST) {
const FULL_BLOCK = '█';
const PARTIAL_BLOCK = ['', '▏', '▎', '▍', '▌', '▋', '▊', '▉'];
const fraction = Math.min(progress / 100, 1);
const innerWidth = Math.max(1, width - 2);
const chars = innerWidth * fraction;
const remainder = chars - Math.floor(chars);
const fullChars = FULL_BLOCK.repeat(Math.floor(chars));
const partialChar = PARTIAL_BLOCK[Math.floor(remainder * PARTIAL_BLOCK.length)];
const filler = '·'.repeat(innerWidth - Math.floor(chars) - (partialChar ? 1 : 0));
const color = chalk.green;
rewriteLine('[' + color(fullChars + partialChar) + filler + `] (${progress}%)`);
}
}
/**
* Prints a message to the console with a series periods appended to it. To be used in a while loop to show progress of a long running task.
* The message deletes the current line and rewrites it several times to display 1-3 periods to show the user that the task is still running.
*
* @param message - The message to display
* @param timeoutx4 - The amount of time to wait before printing the next period
*/
async function printDots(message, timeoutx4) {
if (!process.env.MIGRATE_INTEG_TEST) {
rewriteLine(message + ' .');
await new Promise((resolve) => setTimeout(resolve, timeoutx4));
rewriteLine(message + ' ..');
await new Promise((resolve) => setTimeout(resolve, timeoutx4));
rewriteLine(message + ' ...');
await new Promise((resolve) => setTimeout(resolve, timeoutx4));
rewriteLine(message);
await new Promise((resolve) => setTimeout(resolve, timeoutx4));
}
}
/**
* Rewrites the current line on the console and writes a new message to it.
* This is a helper funciton for printDots and printBar.
*
* @param message - The message to display
*/
function rewriteLine(message) {
process.stdout.clearLine(0);
process.stdout.cursorTo(0);
process.stdout.write(message);
}
/**
* Prints the time difference between two dates in days, hours, and minutes.
*
* @param time1 - The first date to compare
* @param time2 - The second date to compare
*/
async function displayTimeDiff(ioHelper, time1, time2) {
const diff = Math.abs(time1.getTime() - time2.getTime());
const days = Math.floor(diff / (1000 * 60 * 60 * 24));
const hours = Math.floor((diff % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
const minutes = Math.floor((diff % (1000 * 60 * 60)) / (1000 * 60));
await ioHelper.defaults.info(`Using the latest successful scan which is ${days} days, ${hours} hours, and ${minutes} minutes old.`);
}
/**
* Writes a migrate.json file to the output directory.
*
* @param outputPath - The path to write the migrate.json file to
* @param stackName - The name of the stack
* @param generatedOutput - The output of the template generator
*/
function writeMigrateJsonFile(outputPath, stackName, migrateJson) {
const outputToJson = {
'//': 'This file is generated by cdk migrate. It will be automatically deleted after the first successful deployment of this app to the environment of the original resources.',
'Source': migrateJson.source,
'Resources': migrateJson.resources,
};
fs.writeFileSync(`${path.join(outputPath ?? process.cwd(), stackName)}/migrate.json`, JSON.stringify(outputToJson, null, 2));
}
/**
* Takes a string representing the from-scan flag and returns a FromScan enum value.
*
* @param scanType - A string representing the from-scan flag
* @returns A FromScan enum value
*/
function getMigrateScanType(scanType) {
switch (scanType) {
case 'new':
return FromScan.NEW;
case 'most-recent':
return FromScan.MOST_RECENT;
case '':
return FromScan.DEFAULT;
case undefined:
return FromScan.DEFAULT;
default:
throw new toolkit_lib_1.ToolkitError('UnknownScanType', `Unknown scan type: ${scanType}`);
}
}
/**
* Takes a generatedTemplateOutput objct and returns a boolean representing whether there are any warnings on any rescources.
*
* @param generatedTemplateOutput - A GenerateTemplateOutput object
* @returns A boolean representing whether there are any warnings on any rescources
*/
function isThereAWarning(generatedTemplateOutput) {
if (generatedTemplateOutput.resources) {
for (const resource of generatedTemplateOutput.resources) {
if (resource.Warnings && resource.Warnings.length > 0) {
return true;
}
}
}
return false;
}
/**
* Builds the GenerateTemplateOutput object from the DescribeGeneratedTemplateOutput and the template body.
*
* @param generatedTemplateSummary - The output of the describe generated template call
* @param templateBody - The body of the generated template
* @returns A GenerateTemplateOutput object
*/
function buildGeneratedTemplateOutput(generatedTemplateSummary, templateBody, source) {
const resources = generatedTemplateSummary.Resources;
const migrateJson = {
templateBody: templateBody,
source: source,
resources: generatedTemplateSummary.Resources.map((r) => ({
ResourceType: r.ResourceType,
LogicalResourceId: r.LogicalResourceId,
ResourceIdentifier: r.ResourceIdentifier,
})),
};
const templateId = generatedTemplateSummary.GeneratedTemplateId;
return {
migrateJson: migrateJson,
resources: resources,
templateId: templateId,
};
}
/**
* Builds a CloudFormation sdk client for making requests with the CFN template generator.
*
* @param sdkProvider - The sdk provider for making CloudFormation calls
* @param environment - The account and region where the stack is deployed
* @returns A CloudFormation sdk client
*/
async function buildCfnClient(sdkProvider, environment) {
const sdk = (await sdkProvider.forEnvironment(environment, plugin_1.Mode.ForReading)).sdk;
sdk.appendCustomUserAgent('cdk-migrate');
return sdk.cloudFormation();
}
/**
* Appends a list of warnings to a readme file.
*
* @param filepath - The path to the readme file
* @param resources - A list of resources to append warnings for
*/
function appendWarningsToReadme(filepath, resources) {
const readme = fs.readFileSync(filepath, 'utf8');
const lines = readme.split('\n');
const index = lines.findIndex((line) => line.trim() === 'Enjoy!');
let linesToAdd = ['\n## Warnings'];
linesToAdd.push('### Write-only properties');
linesToAdd.push("Write-only properties are resource property values that can be written to but can't be read by AWS CloudFormation or CDK Migrate. For more information, see [IaC generator and write-only properties](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/generate-IaC-write-only-properties.html).");
linesToAdd.push('\n');
linesToAdd.push('Write-only properties discovered during migration are organized here by resource ID and categorized by write-only property type. Resolve write-only properties by providing property values in your CDK app. For guidance, see [Resolve write-only properties](https://docs.aws.amazon.com/cdk/v2/guide/migrate.html#migrate-resources-writeonly).');
for (const resource of resources) {
if (resource.Warnings && resource.Warnings.length > 0) {
linesToAdd.push(`### ${resource.LogicalResourceId}`);
for (const warning of resource.Warnings) {
linesToAdd.push(`- **${warning.Type}**: `);
for (const property of warning.Properties) {
linesToAdd.push(` - ${property.PropertyPath}: ${property.Description}`);
}
}
}
}
lines.splice(index, 0, ...linesToAdd);
fs.writeFileSync(filepath, lines.join('\n'));
}
/**
* takes a list of resources and returns a list of unique resources based on the resource type and logical resource id.
*
* @param resources - A list of resources to deduplicate
* @returns A list of unique resources
*/
function deduplicateResources(resources) {
let uniqueResources = {};
for (const resource of resources) {
const key = Object.keys(resource.ResourceIdentifier)[0];
// Creating our unique identifier using the resource type, the key, and the value of the resource identifier
// The resource identifier is a combination of a key value pair defined by a resource's schema, and the resource type of the resource.
const uniqueIdentifer = `${resource.ResourceType}:${key}:${resource.ResourceIdentifier[key]}`;
uniqueResources[uniqueIdentifer] = resource;
}
return Object.values(uniqueResources);
}
/**
* Class for making CloudFormation template generator calls
*/
class CfnTemplateGeneratorProvider {
constructor(cfn, ioHelper) {
this.cfn = cfn;
this.ioHelper = ioHelper;
}
async checkForResourceScan(resourceScanSummaries, options, clientRequestToken) {
if (!resourceScanSummaries || resourceScanSummaries.length === 0) {
if (options.fromScan === FromScan.MOST_RECENT) {
throw new toolkit_lib_1.ToolkitError('NoScansFound', 'No scans found. Please either start a new scan with the `--from-scan` new or do not specify a `--from-scan` option.');
}
else {
await this.ioHelper.defaults.info('No scans found. Initiating a new resource scan.');
await this.startResourceScan(clientRequestToken);
}
}
}
/**
* Retrieves a tokenized list of resources and their associated scan. If a token is present the function
* will loop through all pages and combine them into a single list of ScannedRelatedResources
*
* @param scanId - scan id for the to list resources for
* @param resources - A list of resources to find related resources for
*/
async getResourceScanRelatedResources(scanId, resources) {
let relatedResourceList = resources;
// break the list of resources into chunks of 100 to avoid hitting the 100 resource limit
for (const chunk of chunks(resources, 100)) {
// get the first page of related resources
const res = await this.cfn.listResourceScanRelatedResources({
ResourceScanId: scanId,
Resources: chunk,
});
// add the first page to the list
relatedResourceList.push(...(res.RelatedResources ?? []));
let nextToken = res.NextToken;
// if there are more pages, cycle through them and add them to the list before moving on to the next chunk
while (nextToken) {
const nextRelatedResources = await this.cfn.listResourceScanRelatedResources({
ResourceScanId: scanId,
Resources: resourceIdentifiers(resources),
NextToken: nextToken,
});
nextToken = nextRelatedResources.NextToken;
relatedResourceList.push(...(nextRelatedResources.RelatedResources ?? []));
}
}
relatedResourceList = deduplicateResources(relatedResourceList);
// prune the managedbystack flag off of them again.
return process.env.MIGRATE_INTEG_TEST
? resourceIdentifiers(relatedResourceList)
: resourceIdentifiers(excludeManaged(relatedResourceList));
}
/**
* Kicks off a scan of a customers account, returning the scan id. A scan can take
* 10 minutes or longer to complete. However this will return a scan id as soon as
* the scan has begun.
*
* @returns A string representing the scan id
*/
async startResourceScan(requestToken) {
return (await this.cfn.startResourceScan({
ClientRequestToken: requestToken,
})).ResourceScanId;
}
/**
* Gets the most recent scans a customer has completed
*
* @returns a list of resource scan summaries
*/
async listResourceScans() {
return this.cfn.listResourceScans();
}
/**
* Retrieves a tokenized list of resources from a resource scan. If a token is present, this function
* will loop through all pages and combine them into a single list of ScannedResource[].
* Additionally will apply any filters provided by the customer.
*
* @param scanId - scan id for the to list resources for
* @param filters - a string of filters in the format of key1=value1,key2=value2
* @returns a combined list of all resources from the scan
*/
async listResourceScanResources(scanId, filters = []) {
let resourceList = [];
let resourceScanInputs;
if (filters.length > 0) {
await this.ioHelper.defaults.info('Applying filters to resource scan.');
for (const filter of filters) {
const filterList = parseFilters(filter);
resourceScanInputs = {
ResourceScanId: scanId,
ResourceIdentifier: filterList[FilterType.RESOURCE_IDENTIFIER],
ResourceTypePrefix: filterList[FilterType.RESOURCE_TYPE_PREFIX],
TagKey: filterList[FilterType.TAG_KEY],
TagValue: filterList[FilterType.TAG_VALUE],
};
const resources = await this.cfn.listResourceScanResources(resourceScanInputs);
resourceList = resourceList.concat(resources.Resources ?? []);
let nextToken = resources.NextToken;
// cycle through the pages adding all resources to the list until we run out of pages
while (nextToken) {
resourceScanInputs.NextToken = nextToken;
const nextResources = await this.cfn.listResourceScanResources(resourceScanInputs);
nextToken = nextResources.NextToken;
resourceList = resourceList.concat(nextResources.Resources ?? []);
}
}
}
else {
await this.ioHelper.defaults.info('No filters provided. Retrieving all resources from scan.');
resourceScanInputs = {
ResourceScanId: scanId,
};
const resources = await this.cfn.listResourceScanResources(resourceScanInputs);
resourceList = resourceList.concat(resources.Resources ?? []);
let nextToken = resources.NextToken;
// cycle through the pages adding all resources to the list until we run out of pages
while (nextToken) {
resourceScanInputs.NextToken = nextToken;
const nextResources = await this.cfn.listResourceScanResources(resourceScanInputs);
nextToken = nextResources.NextToken;
resourceList = resourceList.concat(nextResources.Resources ?? []);
}
}
if (resourceList.length === 0) {
throw new toolkit_lib_1.ToolkitError('NoResourcesFound', `No resources found with filters ${filters.join(' ')}. Please try again with different filters.`);
}
resourceList = deduplicateResources(resourceList);
return process.env.MIGRATE_INTEG_TEST
? resourceIdentifiers(resourceList)
: resourceIdentifiers(excludeManaged(resourceList));
}
/**
* Retrieves information about a resource scan.
*
* @param scanId - scan id for the to list resources for
* @returns information about the scan
*/
async describeResourceScan(scanId) {
return this.cfn.describeResourceScan({
ResourceScanId: scanId,
});
}
/**
* Describes the current status of the template being generated.
*
* @param templateId - A string representing the template id
* @returns DescribeGeneratedTemplateOutput an object containing the template status and results
*/
async describeGeneratedTemplate(templateId) {
const generatedTemplate = await this.cfn.describeGeneratedTemplate({
GeneratedTemplateName: templateId,
});
if (generatedTemplate.Status == ScanStatus.FAILED) {
throw new toolkit_lib_1.ToolkitError('TemplateGenerationFailed', generatedTemplate.StatusReason);
}
return generatedTemplate;
}
/**
* Retrieves a completed generated cloudformation template from the template generator.
*
* @param templateId - A string representing the template id
* @param cloudFormation - The CloudFormation sdk client to use
* @returns DescribeGeneratedTemplateOutput an object containing the template status and body
*/
async getGeneratedTemplate(templateId) {
return this.cfn.getGeneratedTemplate({
GeneratedTemplateName: templateId,
});
}
/**
* Kicks off a template generation for a set of resources.
*
* @param stackName - The name of the stack
* @param resources - A list of resources to generate the template from
* @returns CreateGeneratedTemplateOutput an object containing the template arn to query on later
*/
async createGeneratedTemplate(stackName, resources) {
const createTemplateOutput = await this.cfn.createGeneratedTemplate({
Resources: resources,
GeneratedTemplateName: stackName,
});
if (createTemplateOutput.GeneratedTemplateId === undefined) {
throw new toolkit_lib_1.ToolkitError('MissingTemplateArn', 'CreateGeneratedTemplate failed to return an Arn.');
}
return createTemplateOutput;
}
/**
* Deletes a generated template from the template generator.
*
* @param templateArn - The arn of the template to delete
* @returns A promise that resolves when the template has been deleted
*/
async deleteGeneratedTemplate(templateArn) {
await this.cfn.deleteGeneratedTemplate({
GeneratedTemplateName: templateArn,
});
}
}
exports.CfnTemplateGeneratorProvider = CfnTemplateGeneratorProvider;
/**
* The possible ways to choose a scan to generate a CDK application from
*/
var FromScan;
(function (FromScan) {
/**
* Initiate a new resource scan to build the CDK application from.
*/
FromScan[FromScan["NEW"] = 0] = "NEW";
/**
* Use the last successful scan to build the CDK application from. Will fail if no scan is found.
*/
FromScan[FromScan["MOST_RECENT"] = 1] = "MOST_RECENT";
/**
* Starts a scan if none exists, otherwise uses the most recent successful scan to build the CDK application from.
*/
FromScan[FromScan["DEFAULT"] = 2] = "DEFAULT";
})(FromScan || (exports.FromScan = FromScan = {}));
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWlncmF0ZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIm1pZ3JhdGUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBd0NBLHdDQTBEQztBQVNELHNDQU9DO0FBUUQsb0NBV0M7QUFVRCxzQ0FnQkM7QUFTRCw0Q0FzQ0M7QUFpR0Qsd0JBTUM7QUFRRCx3Q0FNQztBQXdDRCxnREFjQztBQWlFRCw0QkFpQkM7QUFTRCw4QkFjQztBQVFELGtDQUlDO0FBeUJELG9EQWNDO0FBUUQsZ0RBYUM7QUFRRCwwQ0FTQztBQVNELG9FQXFCQztBQVNELHdDQUlDO0FBUUQsd0RBMEJDO0FBeG9CRCwwREFBMEQ7QUFDMUQsdURBQXVEO0FBQ3ZELHlCQUF5QjtBQUN6Qiw2QkFBNkI7QUFFN0Isb0VBQThFO0FBQzlFLHNEQUFvRDtBQWFwRCw2Q0FBNkM7QUFDN0MsK0JBQStCO0FBQy9CLGlDQUFpQztBQUVqQywwREFBNEQ7QUFDNUQsMENBQXFDO0FBRXJDLGtDQUF1QztBQUN2QyxNQUFNLFNBQVMsR0FBRyxPQUFPLENBQUMsV0FBVyxDQUFDLENBQUM7QUFDdkMsTUFBTSxVQUFVLEdBQUcsT0FBTyxDQUFDLFlBQVksQ0FBQyxDQUFDO0FBQ3pDLDBFQUEwRTtBQUMxRSxNQUFNLDJCQUEyQixHQUFzQixZQUFZLENBQUMsbUJBQW1CLEVBQUUsQ0FBQztBQUUxRjs7Ozs7OztHQU9HO0FBQ0ksS0FBSyxVQUFVLGNBQWMsQ0FDbEMsUUFBa0IsRUFDbEIsU0FBaUIsRUFDakIsS0FBYSxFQUNiLFFBQWdCLEVBQ2hCLFVBQW1CLEVBQ25CLFFBQWtCO0lBRWxCLE1BQU0sa0JBQWtCLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FBQyxVQUFVLElBQUksT0FBTyxDQUFDLEdBQUcsRUFBRSxFQUFFLFNBQVMsQ0FBQyxDQUFDO0lBQzdFLE1BQU0sa0JBQWtCLEdBQUcsVUFBVSxDQUFDLFNBQVMsQ0FBQyxDQUFDO0lBRWpELElBQUksQ0FBQztRQUNILEVBQUUsQ0FBQyxNQUFNLENBQUMs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RyxNQUFNLElBQUksQ0FBQyxHQUFHLENBQUMsdUJBQXVCLENBQUM7WUFDbEUsU0FBUyxFQUFFLFNBQVM7WUFDcEIscUJBQXFCLEVBQUUsU0FBUztTQUNqQyxDQUFDLENBQUM7UUFFSCxJQUFJLG9CQUFvQixDQUFDLG1CQUFtQixLQUFLLFNBQVMsRUFBRSxDQUFDO1lBQzNELE1BQU0sSUFBSSwwQkFBWSxDQUFDLG9CQUFvQixFQUFFLGtEQUFrRCxDQUFDLENBQUM7UUFDbkcsQ0FBQztRQUNELE9BQU8sb0JBQW9CLENBQUM7SUFDOUIsQ0FBQztJQUVEOzs7OztPQUtHO0lBQ0gsS0FBSyxDQUFDLHVCQUF1QixDQUFDLFdBQW1CO1FBQy9DLE1BQU0sSUFBSSxDQUFDLEdBQUcsQ0FBQyx1QkFBdUIsQ0FBQztZQUNyQyxxQkFBcUIsRUFBRSxXQUFXO1NBQ25DLENBQUMsQ0FBQztJQUNMLENBQUM7Q0FDRjtBQXZPRCxvRUF1T0M7QUFFRDs7R0FFRztBQUNILElBQVksUUFlWDtBQWZELFdBQVksUUFBUTtJQUNsQjs7T0FFRztJQUNILHFDQUFHLENBQUE7SUFFSDs7T0FFRztJQUNILHFEQUFXLENBQUE7SUFFWDs7T0FFRztJQUNILDZDQUFPLENBQUE7QUFDVCxDQUFDLEVBZlcsUUFBUSx3QkFBUixRQUFRLFFBZW5CIiwic291cmNlc0NvbnRlbnQiOlsiLyogZXNsaW50LWRpc2FibGUgQHR5cGVzY3JpcHQtZXNsaW50L25vLXJlcXVpcmUtaW1wb3J0cyAqL1xuLyogZXNsaW50LWRpc2FibGUgQHR5cGVzY3JpcHQtZXNsaW50L25vLXZhci1yZXF1aXJlcyAqL1xuaW1wb3J0ICogYXMgZnMgZnJvbSAnZnMnO1xuaW1wb3J0ICogYXMgcGF0aCBmcm9tICdwYXRoJztcbmltcG9ydCB0eXBlIHsgRW52aXJvbm1lbnQgfSBmcm9tICdAYXdzLWNkay9jbG91ZC1hc3NlbWJseS1hcGknO1xuaW1wb3J0IHsgVU5LTk9XTl9BQ0NPVU5ULCBVTktOT1dOX1JFR0lPTiB9IGZyb20gJ0Bhd3MtY2RrL2Nsb3VkLWFzc2VtYmx5LWFwaSc7XG5pbXBvcnQgeyBUb29sa2l0RXJyb3IgfSBmcm9tICdAYXdzLWNkay90b29sa2l0LWxpYic7XG5pbXBvcnQgdHlwZSB7XG4gIERlc2NyaWJlR2VuZXJhdGVkVGVtcGxhdGVDb21tYW5kT3V0cHV0LFxuICBEZXNjcmliZVJlc291cmNlU2NhbkNvbW1hbmRPdXRwdXQsXG4gIEdldEdlbmVyYXRlZFRlbXBsYXRlQ29tbWFuZE91dHB1dCxcbiAgTGlzdFJlc291cmNlU2NhblJlc291cmNlc0NvbW1hbmRJbnB1dCxcbiAgUmVzb3VyY2VEZWZpbml0aW9uLFxuICBSZXNvdXJjZURldGFpbCxcbiAgUmVzb3VyY2VJZGVudGlmaWVyU3VtbWFyeSxcbiAgUmVzb3VyY2VTY2FuU3VtbWFyeSxcbiAgU2Nhbm5lZFJlc291cmNlLFxuICBTY2FubmVkUmVzb3VyY2VJZGVudGlmaWVyLFxufSBmcm9tICdAYXdzLXNkay9jbGllbnQtY2xvdWRmb3JtYXRpb24nO1xuaW1wb3J0ICogYXMgY2RrX2Zyb21fY2ZuIGZyb20gJ2Nkay1mcm9tLWNmbic7XG5pbXBvcnQgKiBhcyBjaGFsayBmcm9tICdjaGFsayc7XG5pbXBvcnQgeyBjbGlJbml0IH0gZnJvbSAnLi9pbml0JztcbmltcG9ydCB0eXBlIHsgSUNsb3VkRm9ybWF0aW9uQ2xpZW50LCBTZGtQcm92aWRlciB9IGZyb20gJy4uL2FwaS9hd3MtYXV0aCc7XG5pbXBvcnQgeyBDbG91ZEZvcm1hdGlvblN0YWNrIH0gZnJvbSAnLi4vYXBpL2Nsb3VkZm9ybWF0aW9uJztcbmltcG9ydCB7IE1vZGUgfSBmcm9tICcuLi9hcGkvcGx1Z2luJztcbmltcG9ydCB0eXBlIHsgSW9IZWxwZXIgfSBmcm9tICcuLi9hcGktcHJpdmF0ZSc7XG5pbXBvcnQgeyB6aXBEaXJlY3RvcnkgfSBmcm9tICcuLi91dGlsJztcbmNvbnN0IGNhbWVsQ2FzZSA9IHJlcXVpcmUoJ2NhbWVsY2FzZScpO1xuY29uc3QgZGVjYW1lbGl6ZSA9IHJlcXVpcmUoJ2RlY2FtZWxpemUnKTtcbi8qKiBUaGUgbGlzdCBvZiBsYW5ndWFnZXMgc3VwcG9ydGVkIGJ5IHRoZSBidWlsdC1pbiBub2N0aWx1Y2VudCBiaW5hcnkuICovXG5jb25zdCBNSUdSQVRFX1NVUFBPUlRFRF9MQU5HVUFHRVM6IHJlYWRvbmx5IHN0cmluZ1tdID0gY2RrX2Zyb21fY2ZuLnN1cHBvcnRlZF9sYW5ndWFnZXMoKTtcblxuLyoqXG4gKiBHZW5lcmF0ZXMgYSBDREsgYXBwIGZyb20gYSB5YW1sIG9yIGpzb24gdGVtcGxhdGUuXG4gKlxuICogQHBhcmFtIHN0YWNrTmFtZSAtIFRoZSBuYW1lIHRvIGFzc2lnbiB0byB0aGUgc3RhY2sgaW4gdGhlIGdlbmVyYXRlZCBhcHBcbiAqIEBwYXJhbSBzdGFjayAtIFRoZSB5YW1sIG9yIGpzb24gdGVtcGxhdGUgZm9yIHRoZSBzdGFja1xuICogQHBhcmFtIGxhbmd1YWdlIC0gVGhlIGxhbmd1YWdlIHRvIGdlbmVyYXRlIHRoZSBDREsgYXBwIGluXG4gKiBAcGFyYW0gb3V0cHV0UGF0aCAtIFRoZSBwYXRoIGF0IHdoaWNoIHRvIGdlbmVyYXRlIHRoZSBDREsgYXBwXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBnZW5lcmF0ZUNka0FwcChcbiAgaW9IZWxwZXI6IElvSGVscGVyLFxuICBzdGFja05hbWU6IHN0cmluZyxcbiAgc3RhY2s6IHN0cmluZyxcbiAgbGFuZ3VhZ2U6IHN0cmluZyxcbiAgb3V0cHV0UGF0aD86IHN0cmluZyxcbiAgY29tcHJlc3M/OiBib29sZWFuLFxuKTogUHJvbWlzZTx2b2lkPiB7XG4gIGNvbnN0IHJlc29sdmVkT3V0cHV0UGF0aCA9IHBhdGguam9pbihvdXRwdXRQYXRoID8/IHByb2Nlc3MuY3dkKCksIHN0YWNrTmFtZSk7XG4gIGNvbnN0IGZvcm1hdHRlZFN0YWNrTmFtZSA9IGRlY2FtZWxpemUoc3RhY2tOYW1lKTtcblxuICB0cnkge1xuICAgIGZzLnJtU3luYyhyZXNvbHZlZE91dHB1dFBhdGgsIHsgcmVjdXJzaXZlOiB0cnVlLCBmb3JjZTogdHJ1ZSB9KTtcbiAgICBmcy5ta2RpclN5bmMocmVzb2x2ZWRPdXRwdXRQYXRoLCB7IHJlY3Vyc2l2ZTogdHJ1ZSB9KTtcbiAgICBjb25zdCBnZW5lcmF0ZU9ubHkgPSBjb21wcmVzcztcbiAgICBhd2FpdCBjbGlJbml0KHtcbiAgICAgIGlvSGVscGVyLFxuICAgICAgdHlwZTogJ2FwcCcsXG4gICAgICBsYW5ndWFnZSxcbiAgICAgIGNhblVzZU5ldHdvcms6IHRydWUsXG4gICAgICBnZW5lcmF0ZU9ubHksXG4gICAgICB3b3JrRGlyOiByZXNvbHZlZE91dHB1dFBhdGgsXG4gICAgICBzdGFja05hbWUsXG4gICAgICBtaWdyYXRlOiB0cnVlLFxuICAgIH0pO1xuXG4gICAgbGV0IHN0YWNrRmlsZU5hbWU6IHN0cmluZztcbiAgICBzd2l0Y2ggKGxhbmd1YWdlKSB7XG4gICAgICBjYXNlICd0eXBlc2NyaXB0JzpcbiAgICAgICAgc3RhY2tGaWxlTmFtZSA9IGAke3Jlc29sdmVkT3V0cHV0UGF0aH0vbGliLyR7Zm9ybWF0dGVkU3RhY2tOYW1lfS1zdGFjay50c2A7XG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSAnamF2YSc6XG4gICAgICAgIHN0YWNrRmlsZU5hbWUgPSBgJHtyZXNvbHZlZE91dHB1dFBhdGh9L3NyYy9tYWluL2phdmEvY29tL215b3JnLyR7Y2FtZWxDYXNlKGZvcm1hdHRlZFN0YWNrTmFtZSwgeyBwYXNjYWxDYXNlOiB0cnVlIH0pfVN0YWNrLmphdmFgO1xuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgJ3B5dGhvbic6XG4gICAgICAgIHN0YWNrRmlsZU5hbWUgPSBgJHtyZXNvbHZlZE91dHB1dFBhdGh9LyR7Zm9ybWF0dGVkU3RhY2tOYW1lLnJlcGxhY2UoLy0vZywgJ18nKX0vJHtmb3JtYXR0ZWRTdGFja05hbWUucmVwbGFjZSgvLS9nLCAnXycpfV9zdGFjay5weWA7XG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSAnY3NoYXJwJzpcbiAgICAgICAgc3RhY2tGaWxlTmFtZSA9IGAke3Jlc29sdmVkT3V0cHV0UGF0aH0vc3JjLyR7Y2FtZWxDYXNlKGZvcm1hdHRlZFN0YWNrTmFtZSwgeyBwYXNjYWxDYXNlOiB0cnVlIH0pfS8ke2NhbWVsQ2FzZShmb3JtYXR0ZWRTdGFja05hbWUsIHsgcGFzY2FsQ2FzZTogdHJ1ZSB9KX1TdGFjay5jc2A7XG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSAnZ28nOlxuICAgICAgICBzdGFja0ZpbGVOYW1lID0gYCR7cmVzb2x2ZWRPdXRwdXRQYXRofS8ke2Zvcm1hdHRlZFN0YWNrTmFtZX0uZ29gO1xuICAgICAgICBicmVhaztcbiAgICAgIGRlZmF1bHQ6XG4gICAgICAgIHRocm93IG5ldyBUb29sa2l0RXJyb3IoXG4gICAgICAgICAgJ1Vuc3VwcG9ydGVkTWlncmF0ZUxhbmd1YWdlJyxcbiAgICAgICAgICBgJHtsYW5ndWFnZX0gaXMgbm90IHN1cHBvcnRlZCBieSBDREsgTWlncmF0ZS4gUGxlYXNlIGNob29zZSBmcm9tOiAke01JR1JBVEVfU1VQUE9SVEVEX0xBTkdVQUdFUy5qb2luKCcsICcpfWAsXG4gICAgICAgICk7XG4gICAgfVxuICAgIGZzLndyaXRlRmlsZVN5bmMoc3RhY2tGaWxlTmFtZSwgc3RhY2spO1xuICAgIGlmIChjb21wcmVzcykge1xuICAgICAgYXdhaXQgemlwRGlyZWN0b3J5KHJlc29sdmVkT3V0cHV0UGF0aCwgYCR7cmVzb2x2ZWRPdXRwdXRQYXRofS56aXBgKTtcbiAgICAgIGZzLnJtU3luYyhyZXNvbHZlZE91dHB1dFBhdGgsIHsgcmVjdXJzaXZlOiB0cnVlLCBmb3JjZTogdHJ1ZSB9KTtcbiAgICB9XG4gIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgZnMucm1TeW5jKHJlc29sdmVkT3V0cHV0UGF0aCwgeyByZWN1cnNpdmU6IHRydWUsIGZvcmNlOiB0cnVlIH0pO1xuICAgIHRocm93IGVycm9yO1xuICB9XG59XG5cbi8qKlxuICogR2VuZXJhdGVzIGEgQ0RLIHN0YWNrIGZpbGUuXG4gKiBAcGFyYW0gdGVtcGxhdGUgLSBUaGUgdGVtcGxhdGUgdG8gdHJhbnNsYXRlIGludG8gYSBDREsgc3RhY2tcbiAqIEBwYXJhbSBzdGFja05hbWUgLSBUaGUgbmFtZSB0byBhc3NpZ24gdG8gdGhlIHN0YWNrXG4gKiBAcGFyYW0gbGFuZ3VhZ2UgLSBUaGUgbGFuZ3VhZ2UgdG8gZ2VuZXJhdGUgdGhlIHN0YWNrIGluXG4gKiBAcmV0dXJucyBBIHN0cmluZyByZXByZXNlbnRhdGlvbiBvZiBhIENESyBzdGFjayBmaWxlXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBnZW5lcmF0ZVN0YWNrKHRlbXBsYXRlOiBzdHJpbmcsIHN0YWNrTmFtZTogc3RyaW5nLCBsYW5ndWFnZTogc3RyaW5nKSB7XG4gIGNvbnN0IGZvcm1hdHRlZFN0YWNrTmFtZSA9IGAke2NhbWVsQ2FzZShkZWNhbWVsaXplKHN0YWNrTmFtZSksIHsgcGFzY2FsQ2FzZTogdHJ1ZSB9KX1TdGFja2A7XG4gIHRyeSB7XG4gICAgcmV0dXJuIGNka19mcm9tX2Nmbi50cmFuc211dGUodGVtcGxhdGUsIGxhbmd1YWdlLCBmb3JtYXR0ZWRTdGFja05hbWUpO1xuICB9IGNhdGNoIChlKSB7XG4gICAgdGhyb3cgbmV3IFRvb2xraXRFcnJvcignU3RhY2tHZW5lcmF0aW9uRmFpbGVkJywgYCR7Zm9ybWF0dGVkU3RhY2tOYW1lfSBjb3VsZCBub3QgYmUgZ2VuZXJhdGVkIGJlY2F1c2UgJHsoZSBhcyBFcnJvcikubWVzc2FnZX1gKTtcbiAgfVxufVxuXG4vKipcbiAqIFJlYWRzIGFuZCByZXR1cm5zIGEgc3RhY2sgdGVtcGxhdGUgZnJvbSBhIGxvY2FsIHBhdGguXG4gKlxuICogQHBhcmFtIGlucHV0UGF0aCAtIFRoZSBsb2NhdGlvbiBvZiB0aGUgdGVtcGxhdGVcbiAqIEByZXR1cm5zIEEgc3RyaW5nIHJlcHJlc2VudGF0aW9uIG9mIHRoZSB0ZW1wbGF0ZSBpZiBwcmVzZW50LCBvdGhlcndpc2UgdW5kZWZpbmVkXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiByZWFkRnJvbVBhdGgoaW5wdXRQYXRoOiBzdHJpbmcpOiBzdHJpbmcge1xuICBsZXQgcmVhZEZpbGU6IHN0cmluZztcbiAgdHJ5IHtcbiAgICByZWFkRmlsZSA9IGZzLnJlYWRGaWxlU3luYyhpbnB1dFBhdGgsICd1dGY4Jyk7XG4gIH0gY2F0Y2ggKGUpIHtcbiAgICB0aHJvdyBuZXcgVG9vbGtpdEVycm9yKCdJbnZhbGlkUGF0aCcsIGAnJHtpbnB1dFBhdGh9JyBpcyBub3QgYSB2YWxpZCBwYXRoLmApO1xuICB9XG4gIGlmIChyZWFkRmlsZSA9PSAnJykge1xuICAgIHRocm93IG5ldyBUb29sa2l0RXJyb3IoJ0VtcHR5VGVtcGxhdGVGaWxlJywgYENsb3VkZm9ybWF0aW9uIHRlbXBsYXRlIGZpbGVwYXRoOiAnJHtpbnB1dFBhdGh9JyBpcyBhbiBlbXB0eSBmaWxlLmApO1xuICB9XG4gIHJldHVybiByZWFkRmlsZTtcbn1cblxuLyoqXG4gKiBSZWFkcyBhbmQgcmV0dXJucyBhIHN0YWNrIHRlbXBsYXRlIGZyb20gYSBkZXBsb3llZCBDbG91ZEZvcm1hdGlvbiBzdGFjay5cbiAqXG4gKiBAcGFyYW0gc3RhY2tOYW1lIC0gVGhlIG5hbWUgb2YgdGhlIHN0YWNrXG4gKiBAcGFyYW0gc2RrUHJvdmlkZXIgLSBUaGUgc2RrIHByb3ZpZGVyIGZvciBtYWtpbmcgQ2xvdWRGb3JtYXRpb24gY2FsbHNcbiAqIEBwYXJhbSBlbnZpcm9ubWVudCAtIFRoZSBhY2NvdW50IGFuZCByZWdpb24gd2hlcmUgdGhlIHN0YWNrIGlzIGRlcGxveWVkXG4gKiBAcmV0dXJucyBBIHN0cmluZyByZXByZXNlbnRhdGlvbiBvZiB0aGUgdGVtcGxhdGUgaWYgcHJlc2VudCwgb3RoZXJ3aXNlIHVuZGVmaW5lZFxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gcmVhZEZyb21TdGFjayhcbiAgc3RhY2tOYW1lOiBzdHJpbmcsXG4gIHNka1Byb3ZpZGVyOiBTZGtQcm92aWRlcixcbiAgZW52aXJvbm1lbnQ6IEVudmlyb25tZW50LFxuKTogUHJvbWlzZTxzdHJpbmcgfCB1bmRlZmluZWQ+IHtcbiAgY29uc3QgY2xvdWRGb3JtYXRpb24gPSAoYXdhaXQgc2RrUHJvdmlkZXIuZm9yRW52aXJvbm1lbnQoZW52aXJvbm1lbnQsIE1vZGUuRm9yUmVhZGluZykpLnNkay5jbG91ZEZvcm1hdGlvbigpO1xuXG4gIGNvbnN0IHN0YWNrID0gYXdhaXQgQ2xvdWRGb3JtYXRpb25TdGFjay5sb29rdXAoY2xvdWRGb3JtYXRpb24sIHN0YWNrTmFtZSwgdHJ1ZSk7XG4gIGlmIChzdGFjay5zdGFja1N0YXR1cy5pc0RlcGxveVN1Y2Nlc3MgfHwgc3RhY2suc3RhY2tTdGF0dXMuaXNSb2xsYmFja1N1Y2Nlc3MpIHtcbiAgICByZXR1cm4gSlNPTi5zdHJpbmdpZnkoYXdhaXQgc3RhY2sudGVtcGxhdGUoKSk7XG4gIH0gZWxzZSB7XG4gICAgdGhyb3cgbmV3IFRvb2xraXRFcnJvcihcbiAgICAgICdVbmhlYWx0aHlTdGFja1N0YXR1cycsXG4gICAgICBgU3RhY2sgJyR7c3RhY2tOYW1lfScgaW4gYWNjb3VudCAke2Vudmlyb25tZW50LmFjY291bnR9IGFuZCByZWdpb24gJHtlbnZpcm9ubWVudC5yZWdpb259IGhhcyBhIHN0YXR1cyBvZiAnJHtzdGFjay5zdGFja1N0YXR1cy5uYW1lfScgZHVlIHRvICcke3N0YWNrLnN0YWNrU3RhdHVzLnJlYXNvbn0nLiBUaGUgc3RhY2sgY2Fubm90IGJlIG1pZ3JhdGVkIHVudGlsIGl0IGlzIGluIGEgaGVhbHRoeSBzdGF0ZS5gLFxuICAgICk7XG4gIH1cbn1cblxuLyoqXG4gKiBUYWtlcyBpbiBhIHN0YWNrIG5hbWUgYW5kIGFjY291bnQgYW5kIHJlZ2lvbiBhbmQgcmV0dXJucyBhIGdlbmVyYXRlZCBjbG91ZGZvcm1hdGlvbiB0ZW1wbGF0ZSB1c2luZyB0aGUgY2xvdWRmb3JtYXRpb25cbiAqIHRlbXBsYXRlIGdlbmVyYXRvci5cbiAqXG4gKiBAcGFyYW0gR2VuZXJhdGVUZW1wbGF0ZU9wdGlvbnMgLSBBbiBvYmplY3QgY29udGFpbmluZyB0aGUgc3RhY2sgbmFtZSwgZmlsdGVycywgc2RrUHJvdmlkZXIsIGVudmlyb25tZW50LCBhbmQgbmV3U2NhbiBmbGFnXG4gKiBAcmV0dXJucyBhIGdlbmVyYXRlZCBjbG91ZGZvcm1hdGlvbiB0ZW1wbGF0ZVxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gZ2VuZXJhdGVUZW1wbGF0ZShvcHRpb25zOiBHZW5lcmF0ZVRlbXBsYXRlT3B0aW9ucyk6IFByb21pc2U8R2VuZXJhdGVUZW1wbGF0ZU91dHB1dD4ge1xuICBjb25zdCBjZm4gPSBuZXcgQ2ZuVGVtcGxhdGVHZW5lcmF0b3JQcm92aWRlcihhd2FpdCBidWlsZENmbkNsaWVudChvcHRpb25zLnNka1Byb3ZpZGVyLCBvcHRpb25zLmVudmlyb25tZW50KSwgb3B0aW9ucy5pb0hlbHBlcik7XG4gIGNvbnN0IGlvSGVscGVyID0gb3B0aW9ucy5pb0hlbHBlcjtcblxuICBjb25zdCBzY2FuSWQgPSBhd2FpdCBmaW5kTGFzdFN1Y2Nlc3NmdWxTY2FuKGNmbiwgb3B0aW9ucyk7XG5cbiAgLy8gaWYgYSBjdXN0b21lciBhY2NpZGVudGFsbHkgY3RybC1jJ3Mgb3V0IG9mIHRoZSBjb21tYW5kIGFuZCBydW5zIGl0IGFnYWluLCB0aGlzIHdpbGwgY29udGludWUgdGhlIHByb2dyZXNzIGJhciB3aGVyZSBpdCBsZWZ0IG9mZlxuICBjb25zdCBjdXJTY2FuID0gYXdhaXQgY2ZuLmRlc2NyaWJlUmVzb3VyY2VTY2FuKHNjYW5JZCk7XG4gIGlmIChjdXJTY2FuLlN0YXR1cyA9PSBTY2FuU3RhdHVzLklOX1BST0dSRVNTKSB7XG4gICAgYXdhaXQgaW9IZWxwZXIuZGVmYXVsdHMuaW5mbygnUmVzb3VyY2Ugc2NhbiBpbiBwcm9ncmVzcy4gUGxlYXNlIHdhaXQsIHRoaXMgY2FuIHRha2UgMTAgbWludXRlcyBvciBsb25nZXIuJyk7XG4gICAgYXdhaXQgc2NhblByb2dyZXNzQmFyKGlvSGVscGVyLCBzY2FuSWQsIGNmbik7XG4gIH1cblxuICBhd2FpdCBkaXNwbGF5VGltZURpZmYoaW9IZWxwZXIsIG5ldyBEYXRlKCksIG5ldyBEYXRlKGN1clNjYW4uU3RhcnRUaW1lISkpO1xuXG4gIGxldCByZXNvdXJjZXM6IFNjYW5uZWRSZXNvdXJjZVtdID0gYXdhaXQgY2ZuLmxpc3RSZXNvdXJjZVNjYW5SZXNvdXJjZXMoc2NhbklkISwgb3B0aW9ucy5maWx0ZXJzKTtcblxuICBhd2FpdCBpb0hlbHBlci5kZWZhdWx0cy5pbmZvKCdmaW5kaW5nIHJlbGF0ZWQgcmVzb3VyY2VzLicpO1xuICBsZXQgcmVsYXRlZFJlc291cmNlcyA9IGF3YWl0IGNmbi5nZXRSZXNvdXJjZVNjYW5SZWxhdGVkUmVzb3VyY2VzKHNjYW5JZCEsIHJlc291cmNlcyk7XG5cbiAgYXdhaXQgaW9IZWxwZXIuZGVmYXVsdHMuaW5mbyhgRm91bmQgJHtyZWxhdGVkUmVzb3VyY2VzLmxlbmd0aH0gcmVzb3VyY2VzLmApO1xuXG4gIGF3YWl0IGlvSGVscGVyLmRlZmF1bHRzLmluZm8oJ0dlbmVyYXRpbmcgQ0ZOIHRlbXBsYXRlIGZyb20gc2Nhbm5lZCByZXNvdXJjZXMuJyk7XG4gIGNvbnN0IHRlbXBsYXRlQXJuID0gKGF3YWl0IGNmbi5jcmVhdGVHZW5lcmF0ZWRUZW1wbGF0ZShvcHRpb25zLnN0YWNrTmFtZSwgcmVsYXRlZFJlc291cmNlcykpLkdlbmVyYXRlZFRlbXBsYXRlSWQhO1xuXG4gIGxldCBnZW5lcmF0ZWRUZW1wbGF0ZSA9IGF3YWl0IGNmbi5kZXNjcmliZUdlbmVyYXRlZFRlbXBsYXRlKHRlbXBsYXRlQXJuKTtcblxuICBhd2FpdCBpb0hlbHBlci5kZWZhdWx0cy5pbmZvKCdQbGVhc2Ugd2FpdCwgdGVtcGxhdGUgY3JlYXRpb24gaW4gcHJvZ3Jlc3MuIFRoaXMgbWF5IHRha2UgYSBjb3VwbGUgbWludXRlcy4nKTtcbiAgd2hpbGUgKGdlbmVyYXRlZFRlbXBsYXRlLlN0YXR1cyAhPT0gU2NhblN0YXR1cy5DT01QTEVURSAmJiBnZW5lcmF0ZWRUZW1wbGF0ZS5TdGF0dXMgIT09IFNjYW5TdGF0dXMuRkFJTEVEKSB7XG4gICAgYXdhaXQgcHJpbnREb3RzKGBbJHtnZW5lcmF0ZWRUZW1wbGF0ZS5TdGF0dXN9XSBUZW1wbGF0ZSBDcmVhdGlvbiBpbiBQcm9ncmVzc2AsIDQwMCk7XG4gICAgZ2VuZXJhdGVkVGVtcGxhdGUgPSBhd2FpdCBjZm4uZGVzY3JpYmVHZW5lcmF0ZWRUZW1wbGF0ZSh0ZW1wbGF0ZUFybik7XG4gIH1cbiAgYXdhaXQgaW9IZWxwZXIuZGVmYXVsdHMuaW5mbygnXFxuVGVtcGxhdGUgc3VjY2Vzc2Z1bGx5IGdlbmVyYXRlZCEnKTtcbiAgcmV0dXJuIGJ1aWxkR2VuZXJhdGVkVGVtcGxhdGVPdXRwdXQoXG4gICAgZ2VuZXJhdGVkVGVtcGxhdGUsXG4gICAgKGF3YWl0IGNmbi5nZXRHZW5lcmF0ZWRUZW1wbGF0ZSh0ZW1wbGF0ZUFybikpLlRlbXBsYXRlQm9keSEsXG4gICAgdGVtcGxhdGVBcm4sXG4gICk7XG59XG5cbmFzeW5jIGZ1bmN0aW9uIGZpbmRMYXN0U3VjY2Vzc2Z1bFNjYW4oXG4gIGNmbjogQ2ZuVGVtcGxhdGVHZW5lcmF0b3JQcm92aWRlcixcbiAgb3B0aW9uczogR2VuZXJhdGVUZW1wbGF0ZU9wdGlvbnMsXG4pOiBQcm9taXNlPHN0cmluZz4ge1xuICBjb25zdCBpb0hlbHBlciA9IG9wdGlvbnMuaW9IZWxwZXI7XG4gIGxldCByZXNvdXJjZVNjYW5TdW1tYXJpZXM6IFJlc291cmNlU2NhblN1bW1hcnlbXSB8IHVuZGVmaW5lZCA9IFtdO1xuICBjb25zdCBjbGllbnRSZXF1ZXN0VG9rZW4gPSBgY2RrLW1pZ3JhdGUtJHtvcHRpb25zLmVudmlyb25tZW50LmFjY291bnR9LSR7b3B0aW9ucy5lbnZpcm9ubWVudC5yZWdpb259YDtcbiAgaWYgKG9wdGlvbnMuZnJvbVNjYW4gPT09IEZyb21TY2FuLk5FVykge1xuICAgIGF3YWl0IGlvSGVscGVyLmRlZmF1bHRzLmluZm8oYFN0YXJ0aW5nIG5ldyBzY2FuIGZvciBhY2NvdW50ICR7b3B0aW9ucy5lbnZpcm9ubWVudC5hY2NvdW50fSBpbiByZWdpb24gJHtvcHRpb25zLmVudmlyb25tZW50LnJlZ2lvbn1gKTtcbiAgICB0cnkge1xuICAgICAgYXdhaXQgY2ZuLnN0YXJ0UmVzb3VyY2VTY2FuKGNsaWVudFJlcXVlc3RUb2tlbik7XG4gICAgICByZXNvdXJjZVNjYW5TdW1tYXJpZXMgPSAoYXdhaXQgY2ZuLmxpc3RSZXNvdXJjZVNjYW5zKCkpLlJlc291cmNlU2NhblN1bW1hcmllcztcbiAgICB9IGNhdGNoIChlKSB7XG4gICAgICAvLyBjb250aW51aW5nIGhlcmUgYmVjYXVzZSBpZiB0aGUgc2NhbiBmYWlscyBvbiBhIG5ldy1zY2FuIGl0IGlzIHZlcnkgbGlrZWx5IGJlY2F1c2UgdGhlcmUgaXMgZWl0aGVyIGFscmVhZHkgYSBzY2FuIGluIHByb2dyZXNzXG4gICAgICAvLyBvciB0aGUgY3VzdG9tZXIgaGl0IGEgcmF0ZSBsaW1pdC4gSW4gZWl0aGVyIGNhc2Ugd2Ugd2FudCB0byBjb250aW51ZSB3aXRoIHRoZSBtb3N0IHJlY2VudCBzY2FuLlxuICAgICAgLy8gSWYgdGhpcyBoYXBwZW5zIHRvIGZhaWwgZm9yIGEgY3JlZGVudGlhbCBlcnJvciB0aGVuIHRoYXQgd2lsbCBiZSBjYXVnaHQgaW1tZWRpYXRlbHkgYWZ0ZXIgYW55d2F5LlxuICAgICAgYXdhaXQgaW9IZWxwZXIuZGVmYXVsdHMuaW5mbyhgU2NhbiBmYWlsZWQgdG8gc3RhcnQgZHVlIHRvIGVycm9yICckeyhlIGFzIEVycm9yKS5tZXNzYWdlfScsIGRlZmF1bHRpbmcgdG8gbGF0ZXN0IHNjYW4uYCk7XG4gICAgfVxuICB9IGVsc2Uge1xuICAgIHJlc291cmNlU2NhblN1bW1hcmllcyA9IChhd2FpdCBjZm4ubGlzdFJlc291cmNlU2NhbnMoKSkuUmVzb3VyY2VTY2FuU3VtbWFyaWVzO1xuICAgIGF3YWl0IGNmbi5jaGVja0ZvclJlc291cmNlU2NhbihyZXNvdXJjZVNjYW5TdW1tYXJpZXMsIG9wdGlvbnMsIGNsaWVudFJlcXVlc3RUb2tlbik7XG4gIH1cbiAgLy8gZ2V0IHRoZSBsYXRlc3Qgc2Nhbiwgd2hpY2ggd2Uga25vdyB3aWxsIGV4aXN0XG4gIHJlc291cmNlU2NhblN1bW1hcmllcyA9IChhd2FpdCBjZm4ubGlzdFJlc291cmNlU2NhbnMoKSkuUmVzb3VyY2VTY2FuU3VtbWFyaWVzO1xuICBsZXQgc2NhbklkOiBzdHJpbmcgfCB1bmRlZmluZWQgPSByZXNvdXJjZVNjYW5TdW1tYXJpZXMhWzBdLlJlc291cmNlU2NhbklkO1xuXG4gIC8vIGZpbmQgdGhlIG1vc3QgcmVjZW50IHNjYW4gdGhhdCBpc24ndCBpbiBhIGZhaWxlZCBzdGF0ZSBpbiBjYXNlIHdlIGRpZG4ndCBzdGFydCBhIG5ldyBvbmVcbiAgZm9yIChjb25zdCBzdW1tYXJ5IG9mIHJlc291cmNlU2NhblN1bW1hcmllcyEpIHtcbiAgICBpZiAoc3VtbWFyeS5TdGF0dXMgIT09IFNjYW5TdGF0dXMuRkFJTEVEKSB7XG4gICAgICBzY2FuSWQgPSBzdW1tYXJ5LlJlc291cmNlU2NhbklkITtcbiAgICAgIGJyZWFrO1xuICAgIH1cbiAgfVxuXG4gIHJldHVybiBzY2FuSWQhO1xufVxuXG4vKipcbiAqIFRha2VzIGEgc3RyaW5nIG9mIGZpbHRlcnMgaW4gdGhlIGZvcm1hdCBvZiBrZXkxPXZhbHVlMSxrZXkyPXZhbHVlMiBhbmQgcmV0dXJucyBhIG1hcCBvZiB0aGUgZmlsdGVycy5cbiAqXG4gKiBAcGFyYW0gZmlsdGVycyAtIGEgc3RyaW5nIG9mIGZpbHRlcnMgaW4gdGhlIGZvcm1hdCBvZiBrZXkxPXZhbHVlMSxrZXkyPXZhbHVlMlxuICogQHJldHVybnMgYSBtYXAgb2YgdGhlIGZpbHRlcnNcbiAqL1xuZnVuY3Rpb24gcGFyc2VGaWx0ZXJzKGZpbHRlcnM6IHN0cmluZyk6IHtcbiAgW2tleSBpbiBGaWx0ZXJUeXBlXTogc3RyaW5nIHwgdW5kZWZpbmVkO1xufSB7XG4gIGlmICghZmlsdGVycykge1xuICAgIHJldHVybiB7XG4gICAgICAncmVzb3VyY2UtaWRlbnRpZmllcic6IHVuZGVmaW5lZCxcbiAgICAgICdyZXNvdXJjZS10eXBlLXByZWZpeCc6IHVuZGVmaW5lZCxcbiAgICAgICd0YWcta2V5JzogdW5kZWZpbmVkLFxuICAgICAgJ3RhZy12YWx1ZSc6IHVuZGVmaW5lZCxcbiAgICB9O1xuICB9XG5cbiAgY29uc3QgZmlsdGVyU2hvcnRoYW5kczogeyBba2V5OiBzdHJpbmddOiBGaWx0ZXJUeXBlIH0gPSB7XG4gICAgJ2lkZW50aWZpZXInOiBGaWx0ZXJUeXBlLlJFU09VUkNFX0lERU5USUZJRVIsXG4gICAgJ2lkJzogRmlsdGVyVHlwZS5SRVNPVVJDRV9JREVOVElGSUVSLFxuICAgICd0eXBlJzogRmlsdGVyVHlwZS5SRVNPVVJDRV9UWVBFX1BSRUZJWCxcbiAgICAndHlwZS1wcmVmaXgnOiBGaWx0ZXJUeXBlLlJFU09VUkNFX1RZUEVfUFJFRklYLFxuICB9O1xuXG4gIGNvbnN0IGZpbHRlckxpc3QgPSBmaWx0ZXJzLnNwbGl0KCcsJyk7XG5cbiAgbGV0IGZpbHRlck1hcDogeyBba2V5IGluIEZpbHRlclR5cGVdOiBzdHJpbmcgfCB1bmRlZmluZWQgfSA9IHtcbiAgICBbRmlsdGVyVHlwZS5SRVNPVVJDRV9JREVOVElGSUVSXTogdW5kZWZpbmVkLFxuICAgIFtGaWx0ZXJUeXBlLlJFU09VUkNFX1RZUEVfUFJFRklYXTogdW5kZWZpbmVkLFxuICAgIFtGaWx0ZXJUeXBlLlRBR19LRVldOiB1bmRlZmluZWQsXG4gICAgW0ZpbHRlclR5cGUuVEFHX1ZBTFVFXTogdW5kZWZpbmVkLFxuICB9O1xuXG4gIGZvciAoY29uc3QgZmlsIG9mIGZpbHRlckxpc3QpIHtcbiAgICBjb25zdCBmaWx0ZXIgPSBmaWwuc3BsaXQoJz0nKTtcbiAgICBsZXQgZmlsdGVyS2V5ID0gZmlsdGVyWzBdO1xuICAgIGNvbnN0IGZpbHRlclZhbHVlID0gZmlsdGVyWzFdO1xuICAgIC8vIGlmIHRoZSBrZXkgaXMgYSBzaG9ydGhhbmQsIHJlcGxhY2UgaXQgd2l0aCB0aGUgZnVsbCBuYW1lXG4gICAgaWYgKGZpbHRlcktleSBpbiBmaWx0ZXJTaG9ydGhhbmRzKSB7XG4gICAgICBmaWx0ZXJLZXkgPSBmaWx0ZXJTaG9ydGhhbmRzW2ZpbHRlcktleV07XG4gICAgfVxuICAgIGlmIChPYmplY3QudmFsdWVzKEZpbHRlclR5cGUpLmluY2x1ZGVzKGZpbHRlcktleSBhcyBhbnkpKSB7XG4gICAgICBmaWx0ZXJNYXBbZmlsdGVyS2V5IGFzIGtleW9mIHR5cGVvZiBmaWx0ZXJNYXBdID0gZmlsdGVyVmFsdWU7XG4gICAgfSBlbHNlIHtcbiAgICAgIHRocm93IG5ldyBUb29sa2l0RXJyb3IoJ0ludmFsaWRGaWx0ZXInLCBgSW52YWxpZCBmaWx0ZXI6ICR7ZmlsdGVyS2V5fWApO1xuICAgIH1cbiAgfVxuICByZXR1cm4gZmlsdGVyTWFwO1xufVxuXG4vKipcbiAqIFRha2VzIGEgbGlzdCBvZiBhbnkgdHlwZSBhbmQgYnJlYWtzIGl0IHVwIGludG8gY2h1bmtzIG9mIGEgc3BlY2lmaWVkIHNpemUuXG4gKlxuICogQHBhcmFtIGxpc3QgLSBUaGUgbGlzdCB0byBicmVhayB1cFxuICogQHBhcmFtIGNodW5rU2l6ZSAtIFRoZSBzaXplIG9mIGVhY2ggY2h1bmtcbiAqIEByZXR1cm5zIEEgbGlzdCBvZiBsaXN0cyBvZiB0aGUgc3BlY2lmaWVkIHNpemVcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGNodW5rcyhsaXN0OiBhbnlbXSwgY2h1bmtTaXplOiBudW1iZXIpOiBhbnlbXVtdIHtcbiAgY29uc3QgY2h1bmtlZExpc3Q6IGFueVtdW10gPSBbXTtcbiAgZm9yIChsZXQgaSA9IDA7IGkgPCBsaXN0Lmxlbmd0aDsgaSArPSBjaHVua1NpemUpIHtcbiAgICBjaHVua2VkTGlzdC5wdXNoKGxpc3Quc2xpY2UoaSwgaSArIGNodW5rU2l6ZSkpO1xuICB9XG4gIHJldHVybiBjaHVua2VkTGlzdDtcbn1cblxuLyoqXG4gKiBTZXRzIHRoZSBhY2NvdW50IGFuZCByZWdpb24gZm9yIG1ha2luZyBDbG91ZEZvcm1hdGlvbiBjYWxscy5cbiAqIEBwYXJhbSBhY2NvdW50IC0gVGhlIGFjY291bnQgdG8gdXNlXG4gKiBAcGFyYW0gcmVnaW9uIC0gVGhlIHJlZ2lvbiB0byB1c2VcbiAqIEByZXR1cm5zIFRoZSBlbnZpcm9ubWVudCBvYmplY3RcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHNldEVudmlyb25tZW50KGFjY291bnQ/OiBzdHJpbmcsIHJlZ2lvbj86IHN0cmluZyk6IEVudmlyb25tZW50IHtcbiAgcmV0dXJuIHtcbiAgICBhY2NvdW50OiBhY2NvdW50ID8/IFVOS05PV05fQUNDT1VOVCxcbiAgICByZWdpb246IHJlZ2lvbiA/PyBVTktOT1dOX1JFR0lPTixcbiAgICBuYW1lOiAnY2RrLW1pZ3JhdGUtZW52JyxcbiAgfTtcbn1cblxuLyoqXG4gKiBFbnVtIGZvciB0aGUgc291cmNlIG9wdGlvbnMgZm9yIHRoZSB0ZW1wbGF0ZVxuICovXG5leHBvcnQgZW51bSBUZW1wbGF0ZVNvdXJjZU9wdGlvbnMge1xuICBQQVRIID0gJ3BhdGgnLFxuICBTVEFDSyA9ICdzdGFjaycsXG4gIFNDQU4gPSAnc2NhbicsXG59XG5cbi8qKlxuICogQW4gb2JqZWN0IHJlcHJlc2VudGluZyB0aGUgc291cmNlIG9mIGEgdGVtcGxhdGUuXG4gKi9cbnR5cGUgVGVtcGxhdGVTb3VyY2UgPVxuICB8IHsgc291cmNlOiBUZW1wbGF0ZVNvdXJjZU9wdGlvbnMuU0NBTiB9XG4gIHwgeyBzb3VyY2U6IFRlbXBsYXRlU291cmNlT3B0aW9ucy5QQVRIOyB0ZW1wbGF0ZVBhdGg6IHN0cmluZyB9XG4gIHwgeyBzb3VyY2U6IFRlbXBsYXRlU291cmNlT3B0aW9ucy5TVEFDSzsgc3RhY2tOYW1lOiBzdHJpbmcgfTtcblxuLyoqXG4gKiBFbnVtIGZvciB0aGUgc3RhdHVzIG9mIGEgcmVzb3VyY2Ugc2NhblxuICovXG5leHBvcnQgZW51bSBTY2FuU3RhdHVzIHtcbiAgSU5fUFJPR1JFU1MgPSAnSU5fUFJPR1JFU1MnLFxuICBDT01QTEVURSA9ICdDT01QTEVURScsXG4gIEZBSUxFRCA9ICdGQUlMRUQnLFxufVxuXG5leHBvcnQgZW51bSBGaWx0ZXJUeXBlIHtcbiAgUkVTT1VSQ0VfSURFTlRJRklFUiA9ICdyZXNvdXJjZS1pZGVudGlmaWVyJyxcbiAgUkVTT1VSQ0VfVFlQRV9QUkVGSVggPSAncmVzb3VyY2UtdHlwZS1wcmVmaXgnLFxuICBUQUdfS0VZID0gJ3RhZy1rZXknLFxuICBUQUdfVkFMVUUgPSAndGFnLXZhbHVlJyxcbn1cblxuLyoqXG4gKiBWYWxpZGF0ZXMgdGhhdCBleGFjdGx5IG9uZSBzb3VyY2Ugb3B0aW9uIGhhcyBiZWVuIHByb3ZpZGVkLlxuICogQHBhcmFtIGZyb21QYXRoIC0gVGhlIGNvbnRlbnQgb2YgdGhlIGZsYWcgYC0tZnJvbS1wYXRoYFxuICogQHBhcmFtIGZyb21TdGFjayAtIHRoZSBjb250ZW50IG9mIHRoZSBmbGFnIGAtLWZyb20tc3RhY2tgXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBwYXJzZVNvdXJjZU9wdGlvbnMoZnJvbVBhdGg/OiBzdHJpbmcsIGZyb21TdGFjaz86IGJvb2xlYW4sIHN0YWNrTmFtZT86IHN0cmluZyk6IFRlbXBsYXRlU291cmNlIHtcbiAgaWYgKGZyb21QYXRoICYmIGZyb21TdGFjaykge1xuICAgIHRocm93IG5ldyBUb29sa2l0RXJyb3IoJ0NvbmZsaWN0aW5nU291cmNlT3B0aW9ucycsICdPbmx5IG9uZSBvZiBgLS1mcm9tLXBhdGhgIG9yIGAtLWZyb20tc3RhY2tgIG1heSBiZSBwcm92aWRlZC4nKTtcbiAgfVxuICBpZiAoIXN0YWNrTmFtZSkge1xuICAgIHRocm93IG5ldyBUb29sa2l0RXJyb3IoJ01pc3NpbmdTdGFja05hbWUnLCAnYC0tc3RhY2stbmFtZWAgaXMgYSByZXF1aXJlZCBmaWVsZC4nKTtcbiAgfVxuICBpZiAoIWZyb21QYXRoICYmICFmcm9tU3RhY2spIHtcbiAgICByZXR1cm4geyBzb3VyY2U6IFRlbXBsYXRlU291cmNlT3B0aW9ucy5TQ0FOIH07XG4gIH1cbiAgaWYgKGZyb21QYXRoKSB7XG4gICAgcmV0dXJuIHsgc291cmNlOiBUZW1wbGF0ZVNvdXJjZU9wdGlvbnMuUEFUSCwgdGVtcGxhdGVQYXRoOiBmcm9tUGF0aCB9O1xuICB9XG4gIHJldHVybiB7IHNvdXJjZTogVGVtcGxhdGVTb3VyY2VPcHRpb25zLlNUQUNLLCBzdGFja05hbWU6IHN0YWNrTmFtZSEgfTtcbn1cblxuLyoqXG4gKiBUYWtlcyBhIHNldCBvZiByZXNvdXJjZXMgYW5kIHJlbW92ZXMgYW55IHdpdGggdGhlIG1hbmFnZWRieXN0YWNrIGZsYWcgc2V0IHRvIHRydWUuXG4gKlxuICogQHBhcmFtIHJlc291cmNlTGlzdCAtIHRoZSBsaXN0IG9mIHJlc291cmNlcyBwcm92aWRlZCBieSB0aGUgbGlzdCBzY2FubmVkIHJlc291cmNlcyBjYWxsc1xuICogQHJldHVybnMgYSBsaXN0IG9mIHJlc291cmNlcyBub3QgbWFuYWdlZCBieSBjZm4gc3RhY2tzXG4gKi9cbmZ1bmN0aW9uIGV4Y2x1ZGVNYW5hZ2VkKHJlc291cmNlTGlzdDogU2Nhbm5lZFJlc291cmNlW10pOiBTY2FubmVkUmVzb3VyY2VJZGVudGlmaWVyW10ge1xuICByZXR1cm4gcmVzb3VyY2VMaXN0XG4gICAgLmZpbHRlcigocikgPT4gIXIuTWFuYWdlZEJ5U3RhY2spXG4gICAgLm1hcCgocikgPT4gKHtcbiAgICAgIFJlc291cmNlVHlwZTogci5SZXNvdXJjZVR5cGUhLFxuICAgICAgUmVzb3VyY2VJZGVudGlmaWVyOiByLlJlc291cmNlSWRlbnRpZmllciEsXG4gICAgfSkpO1xufVxuXG4vKipcbiAqIFRyYW5zZm9ybXMgYSBsaXN0IG9mIHJlc291cmNlcyBpbnRvIGEgbGlzdCBvZiByZXNvdXJjZSBpZGVudGlmaWVycyBieSByZW1vdmluZyB0aGUgTWFuYWdlZEJ5U3RhY2sgZmxhZy5cbiAqIFNldHRpbmcgdGhlIHZhbHVlIG9mIHRoZSBmaWVsZCB0byB1bmRlZmluZWQgZWZmZWN0aXZlbHkgcmVtb3ZlcyBpdCBmcm9tIHRoZSBvYmplY3QuXG4gKlxuICogQHBhcmFtIHJlc291cmNlTGlzdCAtIHRoZSBsaXN0IG9mIHJlc291cmNlcyBwcm92aWRlZCBieSB0aGUgbGlzdCBzY2FubmVkIHJlc291cmNlcyBjYWxsc1xuICogQHJldHVybnMgYSBsaXN0IG9mIFNjYW5uZWRSZXNvdXJjZUlkZW50aWZpZXJbXVxuICovXG5mdW5jdGlvbiByZXNvdXJjZUlkZW50aWZpZXJzKHJlc291cmNlTGlzdDogU2Nhbm5lZFJlc291cmNlW10pOiBTY2FubmVkUmVzb3VyY2VJZGVudGlmaWVyW10ge1xuICBjb25zdCBpZGVudGlmaWVyczogU2Nhbm5lZFJlc291cmNlSWRlbnRpZmllcltdID0gW107XG4gIHJlc291cmNlTGlzdC5mb3JFYWNoKChyKSA9PiB7XG4gICAgY29uc3QgaWRlbnRpZmllcjogU2Nhbm5lZFJlc291cmNlSWRlbnRpZmllciA9IHtcbiAgICAgIFJlc291cmNlVHlwZTogci5SZXNvdXJjZVR5cGUhLFxuICAgICAgUmVzb3VyY2VJZGVudGlmaWVyOiByLlJlc291cmNlSWRlbnRpZmllciEsXG4gICAgfTtcbiAgICBpZGVudGlmaWVycy5wdXNoKGlkZW50aWZpZXIpO1xuICB9KTtcbiAgcmV0dXJuIGlkZW50aWZpZXJzO1xufVxuXG4vKipcbiAqIFRha2VzIGEgc2NhbiBpZCBhbmQgbWFpbnRhaW5zIGEgcHJvZ3Jlc3MgYmFyIHRvIGRpc3BsYXkgdGhlIHByb2dyZXNzIG9mIGEgc2NhbiB0byB0aGUgdXNlci5cbiAqXG4gKiBAcGFyYW0gc2NhbklkIC0gQSBzdHJpbmcgcmVwcmVzZW50aW5nIHRoZSBzY2FuIGlkXG4gKiBAcGFyYW0gY2xvdWRGb3JtYXRpb24gLSBUaGUgQ2xvdWRGb3JtYXRpb24gc2RrIGNsaWVudCB0byB1c2VcbiAqL1xuYXN5bmMgZnVuY3Rpb24gc2NhblByb2dyZXNzQmFyKGlvSGVscGVyOiBJb0hlbHBlciwgc2NhbklkOiBzdHJpbmcsIGNmbjogQ2ZuVGVtcGxhdGVHZW5lcmF0b3JQcm92aWRlcikge1xuICBsZXQgY3VyUHJvZ3Jlc3MgPSAwLjU7XG4gIC8vIHdlIGtub3cgaXQncyBpbiBwcm9ncmVzcyBpbml0aWFsbHkgc2luY2Ugd2Ugd291bGRuJ3QgaGF2ZSBnb3R0ZW4gaGVyZSBpZiBpdCB3YXNuJ3RcbiAgbGV0IGN1clNjYW46IERlc2NyaWJlUmVzb3VyY2VTY2FuQ29tbWFuZE91dHB1dCA9IHtcbiAgICBTdGF0dXM6IFNjYW5TdGF0dXMuSU5fUFJPR1JFU1MsXG4gICAgJG1ldGFkYXRhOiB7fSxcbiAgfTtcbiAgd2hpbGUgKGN1clNjYW4uU3RhdHVzID09IFNjYW5TdGF0dXMuSU5fUFJPR1JFU1MpIHtcbiAgICBjdXJTY2FuID0gYXdhaXQgY2ZuLmRlc2NyaWJlUmVzb3VyY2VTY2FuKHNjYW5JZCk7XG4gICAgY3VyUHJvZ3Jlc3MgPSBjdXJTY2FuLlBlcmNlbnRhZ2VDb21wbGV0ZWQgPz8gY3VyUHJvZ3Jlc3M7XG4gICAgcHJpbnRCYXIoMzAsIGN1clByb2dyZXNzKTtcbiAgICBhd2FpdCBuZXcgUHJvbWlzZSgocmVzb2x2ZSkgPT4gc2V0VGltZW91dChyZXNvbHZlLCAyMDAwKSk7XG4gIH1cbiAgYXdhaXQgaW9IZWxwZXIuZGVmYXVsdHMuaW5mbygnXFxu4pyFIFNjYW4gQ29tcGxldGUhJyk7XG59XG5cbi8qKlxuICogUHJpbnRzIGEgcHJvZ3Jlc3MgYmFyIHRvIHRoZSBjb25zb2xlLiBUbyBiZSB1c2VkIGluIGEgd2hpbGUgbG9vcCB0byBzaG93IHByb2dyZXNzIG9mIGEgbG9uZyBydW5uaW5nIHRhc2suXG4gKiBUaGUgcHJvZ3Jlc3MgYmFyIGRlbGV0ZXMgdGhlIGN1cnJlbnQgbGluZSBvbiB0aGUgY29uc29sZSBhbmQgcmV3cml0ZXMgaXQgd2l0aCB0aGUgcHJvZ3Jlc3MgYW1vdW50LlxuICpcbiAqIEBwYXJhbSB3aWR0aCAtIFRoZSB3aWR0aCBvZiB0aGUgcHJvZ3Jlc3MgYmFyXG4gKiBAcGFyYW0gcHJvZ3Jlc3MgLSBUaGUgY3VycmVudCBwcm9ncmVzcyB0byBkaXNwbGF5IGFzIGEgcGVyY2VudGFnZSBvZiAxMDBcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHByaW50QmFyKHdpZHRoOiBudW1iZXIsIHByb2dyZXNzOiBudW1iZXIpIHtcbiAgaWYgKCFwcm9jZXNzLmVudi5NSUdSQVRFX0lOVEVHX1RFU1QpIHtcbiAgICBjb25zdCBGVUxMX0JMT0NLID0gJ+KWiCc7XG4gICAgY29uc3QgUEFSVElBTF9CTE9DSyA9IFsnJywgJ+KWjycsICfilo4nLCAn4paNJywgJ+KWjCcsICfilosnLCAn4paKJywgJ+KWiSddO1xuICAgIGNvbnN0IGZyYWN0aW9uID0gTWF0aC5taW4ocHJvZ3Jlc3MgLyAxMDAsIDEpO1xuICAgIGNvbnN0IGlubmVyV2lkdGggPSBNYXRoLm1heCgxLCB3aWR0aCAtIDIpO1xuICAgIGNvbnN0IGNoYXJzID0gaW5uZXJXaWR0aCAqIGZyYWN0aW9uO1xuICAgIGNvbnN0IHJlbWFpbmRlciA9IGNoYXJzIC0gTWF0aC5mbG9vcihjaGFycyk7XG5cbiAgICBjb25zdCBmdWxsQ2hhcnMgPSBGVUxMX0JMT0NLLnJlcGVhdChNYXRoLmZsb29yKGNoYXJzKSk7XG4gICAgY29uc3QgcGFydGlhbENoYXIgPSBQQVJUSUFMX0JMT0NLW01hdGguZmxvb3IocmVtYWluZGVyICogUEFSVElBTF9CTE9DSy5sZW5ndGgpXTtcbiAgICBjb25zdCBmaWxsZXIgPSAnwrcnLnJlcGVhdChpbm5lcldpZHRoIC0gTWF0aC5mbG9vcihjaGFycykgLSAocGFydGlhbENoYXIgPyAxIDogMCkpO1xuXG4gICAgY29uc3QgY29sb3IgPSBjaGFsay5ncmVlbjtcblxuICAgIHJld3JpdGVMaW5lKCdbJyArIGNvbG9yKGZ1bGxDaGFycyArIHBhcnRpYWxDaGFyKSArIGZpbGxlciArIGBdICgke3Byb2dyZXNzfSUpYCk7XG4gIH1cbn1cblxuLyoqXG4gKiBQcmludHMgYSBtZXNzYWdlIHRvIHRoZSBjb25zb2xlIHdpdGggYSBzZXJpZXMgcGVyaW9kcyBhcHBlbmRlZCB0byBpdC4gVG8gYmUgdXNlZCBpbiBhIHdoaWxlIGxvb3AgdG8gc2hvdyBwcm9ncmVzcyBvZiBhIGxvbmcgcnVubmluZyB0YXNrLlxuICogVGhlIG1lc3NhZ2UgZGVsZXRlcyB0aGUgY3VycmVudCBsaW5lIGFuZCByZXdyaXRlcyBpdCBzZXZlcmFsIHRpbWVzIHRvIGRpc3BsYXkgMS0zIHBlcmlvZHMgdG8gc2hvdyB0aGUgdXNlciB0aGF0IHRoZSB0YXNrIGlzIHN0aWxsIHJ1bm5pbmcuXG4gKlxuICogQHBhcmFtIG1lc3NhZ2UgLSBUaGUgbWVzc2FnZSB0byBkaXNwbGF5XG4gKiBAcGFyYW0gdGltZW91dHg0IC0gVGhlIGFtb3VudCBvZiB0aW1lIHRvIHdhaXQgYmVmb3JlIHByaW50aW5nIHRoZSBuZXh0IHBlcmlvZFxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gcHJpbnREb3RzKG1lc3NhZ2U6IHN0cmluZywgdGltZW91dHg0OiBudW1iZXIpIHtcbiAgaWYgKCFwcm9jZXNzLmVudi5NSUdSQVRFX0lOVEVHX1RFU1QpIHtcbiAgICByZXdyaXRlTGluZShtZXNzYWdlICsgJyAuJyk7XG4gICAgYXdhaXQgbmV3IFByb21pc2UoKHJlc29sdmUpID0+IHNldFRpbWVvdXQocmVzb2x2ZSwgdGltZW91dHg0KSk7XG5cbiAgICByZXdyaXRlTGluZShtZXNzYWdlICsgJyAuLicpO1xuICAgIGF3YWl0IG5ldyBQcm9taXNlKChyZXNvbHZlKSA9PiBzZXRUaW1lb3V0KHJlc29sdmUsIHRpbWVvdXR4NCkpO1xuXG4gICAgcmV3cml0ZUxpbmUobWVzc2FnZSArICcgLi4uJyk7XG4gICAgYXdhaXQgbmV3IFByb21pc2UoKHJlc29sdmUpID0+IHNldFRpbWVvdXQocmVzb2x2ZSwgdGltZW91dHg0KSk7XG5cbiAgICByZXdyaXRlTGluZShtZXNzYWdlKTtcbiAgICBhd2FpdCBuZXcgUHJvbWlzZSgocmVzb2x2ZSkgPT4gc2V0VGltZW91dChyZXNvbHZlLCB0aW1lb3V0eDQpKTtcbiAgfVxufVxuXG4vKipcbiAqIFJld3JpdGVzIHRoZSBjdXJyZW50IGxpbmUgb24gdGhlIGNvbnNvbGUgYW5kIHdyaXRlcyBhIG5ldyBtZXNzYWdlIHRvIGl0LlxuICogVGhpcyBpcyBhIGhlbHBlciBmdW5jaXRvbiBmb3IgcHJpbnREb3RzIGFuZCBwcmludEJhci5cbiAqXG4gKiBAcGFyYW0gbWVzc2FnZSAtIFRoZSBtZXNzYWdlIHRvIGRpc3BsYXlcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJld3JpdGVMaW5lKG1lc3NhZ2U6IHN0cmluZykge1xuICBwcm9jZXNzLnN0ZG91dC5jbGVhckxpbmUoMCk7XG4gIHByb2Nlc3Muc3Rkb3V0LmN1cnNvclRvKDApO1xuICBwcm9jZXNzLnN0ZG91dC53cml0ZShtZXNzYWdlKTtcbn1cblxuLyoqXG4gKiBQcmludHMgdGhlIHRpbWUgZGlmZmVyZW5jZSBiZXR3ZWVuIHR3byBkYXRlcyBpbiBkYXlzLCBob3VycywgYW5kIG1pbnV0ZXMuXG4gKlxuICogQHBhcmFtIHRpbWUxIC0gVGhlIGZpcnN0IGRhdGUgdG8gY29tcGFyZVxuICogQHBhcmFtIHRpbWUyIC0gVGhlIHNlY29uZCBkYXRlIHRvIGNvbXBhcmVcbiAqL1xuYXN5bmMgZnVuY3Rpb24gZGlzcGxheVRpbWVEaWZmKGlvSGVscGVyOiBJb0hlbHBlciwgdGltZTE6IERhdGUsIHRpbWUyOiBEYXRlKTogUHJvbWlzZTx2b2lkPiB7XG4gIGNvbnN0IGRpZmYgPSBNYXRoLmFicyh0aW1lMS5nZXRUaW1lKCkgLSB0aW1lMi5nZXRUaW1lKCkpO1xuXG4gIGNvbnN0IGRheXMgPSBNYXRoLmZsb29yKGRpZmYgLyAoMTAwMCAqIDYwICogNjAgKiAyNCkpO1xuICBjb25zdCBob3VycyA9IE1hdGguZmxvb3IoKGRpZmYgJSAoMTAwMCAqIDYwICogNjAgKiAyNCkpIC8gKDEwMDAgKiA2MCAqIDYwKSk7XG4gIGNvbnN0IG1pbnV0ZXMgPSBNYXRoLmZsb29yKChkaWZmICUgKDEwMDAgKiA2MCAqIDYwKSkgLyAoMTAwMCAqIDYwKSk7XG5cbiAgYXdhaXQgaW9IZWxwZXIuZGVmYXVsdHMuaW5mbyhgVXNpbmcgdGhlIGxhdGVzdCBzdWNjZXNzZnVsIHNjYW4gd2hpY2ggaXMgJHtkYXlzfSBkYXlzLCAke2hvdXJzfSBob3VycywgYW5kICR7bWludXRlc30gbWludXRlcyBvbGQuYCk7XG59XG5cbi8qKlxuICogV3JpdGVzIGEgbWlncmF0ZS5qc29uIGZpbGUgdG8gdGhlIG91dHB1dCBkaXJlY3RvcnkuXG4gKlxuICogQHBhcmFtIG91dHB1dFBhdGggLSBUaGUgcGF0aCB0byB3cml0ZSB0aGUgbWlncmF0ZS5qc29uIGZpbGUgdG9cbiAqIEBwYXJhbSBzdGFja05hbWUgLSBUaGUgbmFtZSBvZiB0aGUgc3RhY2tcbiAqIEBwYXJhbSBnZW5lcmF0ZWRPdXRwdXQgLSBUaGUgb3V0cHV0IG9mIHRoZSB0ZW1wbGF0ZSBnZW5lcmF0b3JcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHdyaXRlTWlncmF0ZUpzb25GaWxlKFxuICBvdXRwdXRQYXRoOiBzdHJpbmcgfCB1bmRlZmluZWQsXG4gIHN0YWNrTmFtZTogc3RyaW5nLFxuICBtaWdyYXRlSnNvbjogTWlncmF0ZUpzb25Gb3JtYXQsXG4pIHtcbiAgY29uc3Qgb3V0cHV0VG9Kc29uID0ge1xuICAgICcvLyc6ICdUaGlzIGZpbGUgaXMgZ2VuZXJhdGVkIGJ5IGNkayBtaWdyYXRlLiBJdCB3aWxsIGJlIGF1dG9tYXRpY2FsbHkgZGVsZXRlZCBhZnRlciB0aGUgZmlyc3Qgc3VjY2Vzc2Z1bCBkZXBsb3ltZW50IG9mIHRoaXMgYXBwIHRvIHRoZSBlbnZpcm9ubWVudCBvZiB0aGUgb3JpZ2luYWwgcmVzb3VyY2VzLicsXG4gICAgJ1NvdXJjZSc6IG1pZ3JhdGVKc29uLnNvdXJjZSxcbiAgICAnUmVzb3VyY2VzJzogbWlncmF0ZUpzb24ucmVzb3VyY2VzLFxuICB9O1xuICBmcy53cml0ZUZpbGVTeW5jKFxuICAgIGAke3BhdGguam9pbihvdXRwdXRQYXRoID8/IHByb2Nlc3MuY3dkKCksIHN0YWNrTmFtZSl9L21pZ3JhdGUuanNvbmAsXG4gICAgSlNPTi5zdHJpbmdpZnkob3V0cHV0VG9Kc29uLCBudWxsLCAyKSxcbiAgKTtcbn1cblxuLyoqXG4gKiBUYWtlcyBhIHN0cmluZyByZXByZXNlbnRpbmcgdGhlIGZyb20tc2NhbiBmbGFnIGFuZCByZXR1cm5zIGEgRnJvbVNjYW4gZW51bSB2YWx1ZS5cbiAqXG4gKiBAcGFyYW0gc2NhblR5cGUgLSBBIHN0cmluZyByZXByZXNlbnRpbmcgdGhlIGZyb20tc2NhbiBmbGFnXG4gKiBAcmV0dXJucyBBIEZyb21TY2FuIGVudW0gdmFsdWVcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGdldE1pZ3JhdGVTY2FuVHlwZShzY2FuVHlwZTogc3RyaW5nKSB7XG4gIHN3aXRjaCAoc2NhblR5cGUpIHtcbiAgICBjYXNlICduZXcnOlxuICAgICAgcmV0dXJuIEZyb21TY2FuLk5FVztcbiAgICBjYXNlICdtb3N0LXJlY2VudCc6XG4gICAgICByZXR1cm4gRnJvbVNjYW4uTU9TVF9SRUNFTlQ7XG4gICAgY2FzZSAnJzpcbiAgICAgIHJldHVybiBGcm9tU2Nhbi5ERUZBVUxUO1xuICAgIGNhc2UgdW5kZWZpbmVkOlxuICAgICAgcmV0dXJuIEZyb21TY2FuLkRFRkFVTFQ7XG4gICAgZGVmYXVsdDpcbiAgICAgIHRocm93IG5ldyBUb29sa2l0RXJyb3IoJ1Vua25vd25TY2FuVHlwZScsIGBVbmtub3duIHNjYW4gdHlwZTogJHtzY2FuVHlwZX1gKTtcbiAgfVxufVxuXG4vKipcbiAqIFRha2VzIGEgZ2VuZXJhdGVkVGVtcGxhdGVPdXRwdXQgb2JqY3QgYW5kIHJldHVybnMgYSBib29sZWFuIHJlcHJlc2VudGluZyB3aGV0aGVyIHRoZXJlIGFyZSBhbnkgd2FybmluZ3Mgb24gYW55IHJlc2NvdXJjZXMuXG4gKlxuICogQHBhcmFtIGdlbmVyYXRlZFRlbXBsYXRlT3V0cHV0IC0gQSBHZW5lcmF0ZVRlbXBsYXRlT3V0cHV0IG9iamVjdFxuICogQHJldHVybnMgQSBib29sZWFuIHJlcHJlc2VudGluZyB3aGV0aGVyIHRoZXJlIGFyZSBhbnkgd2FybmluZ3Mgb24gYW55IHJlc2NvdXJjZXNcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGlzVGhlcmVBV2FybmluZyhnZW5lcmF0ZWRUZW1wbGF0ZU91dHB1dDogR2VuZXJhdGVUZW1wbGF0ZU91dHB1dCkge1xuICBpZiAoZ2VuZXJhdGVkVGVtcGxhdGVPdXRwdXQucmVzb3VyY2VzKSB7XG4gICAgZm9yIChjb25zdCByZXNvdXJjZSBvZiBnZW5lcmF0ZWRUZW1wbGF0ZU91dHB1dC5yZXNvdXJjZXMpIHtcbiAgICAgIGlmIChyZXNvdXJjZS5XYXJuaW5ncyAmJiByZXNvdXJjZS5XYXJuaW5ncy5sZW5ndGggPiAwKSB7XG4gICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgfVxuICAgIH1cbiAgfVxuICByZXR1cm4gZmFsc2U7XG59XG5cbi8qKlxuICogQnVpbGRzIHRoZSBHZW5lcmF0ZVRlbXBsYXRlT3V0cHV0IG9iamVjdCBmcm9tIHRoZSBEZXNjcmliZUdlbmVyYXRlZFRlbXBsYXRlT3V0cHV0IGFuZCB0aGUgdGVtcGxhdGUgYm9keS5cbiAqXG4gKiBAcGFyYW0gZ2VuZXJhdGVkVGVtcGxhdGVTdW1tYXJ5IC0gVGhlIG91dHB1dCBvZiB0aGUgZGVzY3JpYmUgZ2VuZXJhdGVkIHRlbXBsYXRlIGNhbGxcbiAqIEBwYXJhbSB0ZW1wbGF0ZUJvZHkgLSBUaGUgYm9keSBvZiB0aGUgZ2VuZXJhdGVkIHRlbXBsYXRlXG4gKiBAcmV0dXJucyBBIEdlbmVyYXRlVGVtcGxhdGVPdXRwdXQgb2JqZWN0XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBidWlsZEdlbmVyYXRlZFRlbXBsYXRlT3V0cHV0KFxuICBnZW5lcmF0ZWRUZW1wbGF0ZVN1bW1hcnk6IERlc2NyaWJlR2VuZXJhdGVkVGVtcGxhdGVDb21tYW5kT3V0cHV0LFxuICB0ZW1wbGF0ZUJvZHk6IHN0cmluZyxcbiAgc291cmNlOiBzdHJpbmcsXG4pOiBHZW5lcmF0ZVRlbXBsYXRlT3V0cHV0IHtcbiAgY29uc3QgcmVzb3VyY2VzOiBSZXNvdXJjZURldGFpbFtdIHwgdW5kZWZpbmVkID0gZ2VuZXJhdGVkVGVtcGxhdGVTdW1tYXJ5LlJlc291cmNlcztcbiAgY29uc3QgbWlncmF0ZUpzb246IE1pZ3JhdGVKc29uRm9ybWF0ID0ge1xuICAgIHRlbXBsYXRlQm9keTogdGVtcGxhdGVCb2R5LFxuICAgIHNvdXJjZTogc291cmNlLFxuICAgIHJlc291cmNlczogZ2VuZXJhdGVkVGVtcGxhdGVTdW1tYXJ5LlJlc291cmNlcyEubWFwKChyKSA9PiAoe1xuICAgICAgUmVzb3VyY2VUeXBlOiByLlJlc291cmNlVHlwZSEsXG4gICAgICBMb2dpY2FsUmVzb3VyY2VJZDogci5Mb2dpY2FsUmVzb3VyY2VJZCEsXG4gICAgICBSZXNvdXJjZUlkZW50aWZpZXI6IHIuUmVzb3VyY2VJZGVudGlmaWVyISxcbiAgICB9KSksXG4gIH07XG4gIGNvbnN0IHRlbXBsYXRlSWQgPSBnZW5lcmF0ZWRUZW1wbGF0ZVN1bW1hcnkuR2VuZXJhdGVkVGVtcGxhdGVJZCE7XG4gIHJldHVybiB7XG4gICAgbWlncmF0ZUpzb246IG1pZ3JhdGVKc29uLFxuICAgIHJlc291cmNlczogcmVzb3VyY2VzLFxuICAgIHRlbXBsYXRlSWQ6IHRlbXBsYXRlSWQsXG4gIH07XG59XG5cbi8qKlxuICogQnVpbGRzIGEgQ2xvdWRGb3JtYXRpb24gc2RrIGNsaWVudCBmb3IgbWFraW5nIHJlcXVlc3RzIHdpdGggdGhlIENGTiB0ZW1wbGF0ZSBnZW5lcmF0b3IuXG4gKlxuICogQHBhcmFtIHNka1Byb3ZpZGVyIC0gVGhlIHNkayBwcm92aWRlciBmb3IgbWFraW5nIENsb3VkRm9ybWF0aW9uIGNhbGxzXG4gKiBAcGFyYW0gZW52aXJvbm1lbnQgLSBUaGUgYWNjb3VudCBhbmQgcmVnaW9uIHdoZXJlIHRoZSBzdGFjayBpcyBkZXBsb3llZFxuICogQHJldHVybnMgQSBDbG91ZEZvcm1hdGlvbiBzZGsgY2xpZW50XG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBidWlsZENmbkNsaWVudChzZGtQcm92aWRlcjogU2RrUHJvdmlkZXIsIGVudmlyb25tZW50OiBFbnZpcm9ubWVudCkge1xuICBjb25zdCBzZGsgPSAoYXdhaXQgc2RrUHJvdmlkZXIuZm9yRW52aXJvbm1lbnQoZW52aXJvbm1lbnQsIE1vZGUuRm9yUmVhZGluZykpLnNkaztcbiAgc2RrLmFwcGVuZEN1c3RvbVVzZXJBZ2VudCgnY2RrLW1pZ3JhdGUnKTtcbiAgcmV0dXJuIHNkay5jbG91ZEZvcm1hdGlvbigpO1xufVxuXG4vKipcbiAqIEFwcGVuZHMgYSBsaXN0IG9mIHdhcm5pbmdzIHRvIGEgcmVhZG1lIGZpbGUuXG4gKlxuICogQHBhcmFtIGZpbGVwYXRoIC0gVGhlIHBhdGggdG8gdGhlIHJlYWRtZSBmaWxlXG4gKiBAcGFyYW0gcmVzb3VyY2VzIC0gQSBsaXN0IG9mIHJlc291cmNlcyB0byBhcHBlbmQgd2FybmluZ3MgZm9yXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBhcHBlbmRXYXJuaW5nc1RvUmVhZG1lKGZpbGVwYXRoOiBzdHJpbmcsIHJlc291cmNlczogUmVzb3VyY2VEZXRhaWxbXSkge1xuICBjb25zdCByZWFkbWUgPSBmcy5yZWFkRmlsZVN5bmMoZmlsZXBhdGgsICd1dGY4Jyk7XG4gIGNvbnN0IGxpbmVzID0gcmVhZG1lLnNwbGl0KCdcXG4nKTtcbiAgY29uc3QgaW5kZXggPSBsaW5lcy5maW5kSW5kZXgoKGxpbmUpID0+IGxpbmUudHJpbSgpID09PSAnRW5qb3khJyk7XG4gIGxldCBsaW5lc1RvQWRkID0gWydcXG4jIyBXYXJuaW5ncyddO1xuICBsaW5lc1RvQWRkLnB1c2goJyMjIyBXcml0ZS1vbmx5IHByb3BlcnRpZXMnKTtcbiAgbGluZXNUb0FkZC5wdXNoKFxuICAgIFwiV3JpdGUtb25seSBwcm9wZXJ0aWVzIGFyZSByZXNvdXJjZSBwcm9wZXJ0eSB2YWx1ZXMgdGhhdCBjYW4gYmUgd3JpdHRlbiB0byBidXQgY2FuJ3QgYmUgcmVhZCBieSBBV1MgQ2xvdWRGb3JtYXRpb24gb3IgQ0RLIE1pZ3JhdGUuIEZvciBtb3JlIGluZm9ybWF0aW9uLCBzZWUgW0lhQyBnZW5lcmF0b3IgYW5kIHdyaXRlLW9ubHkgcHJvcGVydGllc10oaHR0cHM6Ly9kb2NzLmF3cy5hbWF6b24uY29tL0FXU0Nsb3VkRm9ybWF0aW9uL2xhdGVzdC9Vc2VyR3VpZGUvZ2VuZXJhdGUtSWFDLXdyaXRlLW9ubHktcHJvcGVydGllcy5odG1sKS5cIixcbiAgKTtcbiAgbGluZXNUb0FkZC5wdXNoKCdcXG4nKTtcbiAgbGluZXNUb0FkZC5wdXNoKFxuICAgICdXcml0ZS1vbmx5IHByb3BlcnRpZXMgZGlzY292ZXJlZCBkdXJpbmcgbWlncmF0aW9uIGFyZSBvcmdhbml6ZWQgaGVyZSBieSByZXNvdXJjZSBJRCBhbmQgY2F0ZWdvcml6ZWQgYnkgd3JpdGUtb25seSBwcm9wZXJ0eSB0eXBlLiBSZXNvbHZlIHdyaXRlLW9ubHkgcHJvcGVydGllcyBieSBwcm92aWRpbmcgcHJvcGVydHkgdmFsdWVzIGluIHlvdXIgQ0RLIGFwcC4gRm9yIGd1aWRhbmNlLCBzZWUgW1Jlc29sdmUgd3JpdGUtb25seSBwcm9wZXJ0aWVzXShodHRwczovL2RvY3MuYXdzLmFtYXpvbi5jb20vY2RrL3YyL2d1aWRlL21pZ3JhdGUuaHRtbCNtaWdyYXRlLXJlc291cmNlcy13cml0ZW9ubHkpLicsXG4gICk7XG4gIGZvciAoY29uc3QgcmVzb3VyY2Ugb2YgcmVzb3VyY2VzKSB7XG4gICAgaWYgKHJlc291cmNlLldhcm5pbmdzICYmIHJlc291cmNlLldhcm5pbmdzLmxlbmd0aCA+IDApIHtcbiAgICAgIGxpbmVzVG9BZGQucHVzaChgIyMjICR7cmVzb3VyY2UuTG9naWNhbFJlc291cmNlSWR9YCk7XG4gICAgICBmb3IgKGNvbnN0IHdhcm5pbmcgb2YgcmVzb3VyY2UuV2FybmluZ3MpIHtcbiAgICAgICAgbGluZXNUb0FkZC5wdXNoKGAtICoqJHt3YXJuaW5nLlR5cGV9Kio6IGApO1xuICAgICAgICBmb3IgKGNvbnN0IHByb3BlcnR5IG9mIHdhcm5pbmcuUHJvcGVydGllcyEpIHtcbiAgICAgICAgICBsaW5lc1RvQWRkLnB1c2goYCAgLSAke3Byb3BlcnR5LlByb3BlcnR5UGF0aH06ICR7cHJvcGVydHkuRGVzY3JpcHRpb259YCk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG4gIH1cbiAgbGluZXMuc3BsaWNlKGluZGV4LCAwLCAuLi5saW5lc1RvQWRkKTtcbiAgZnMud3JpdGVGaWxlU3luYyhmaWxlcGF0aCwgbGluZXMuam9pbignXFxuJykpO1xufVxuXG4vKipcbiAqIHRha2VzIGEgbGlzdCBvZiByZXNvdXJjZXMgYW5kIHJldHVybnMgYSBsaXN0IG9mIHVuaXF1ZSByZXNvdXJjZXMgYmFzZWQgb24gdGhlIHJlc291cmNlIHR5cGUgYW5kIGxvZ2ljYWwgcmVzb3VyY2UgaWQuXG4gKlxuICogQHBhcmFtIHJlc291cmNlcyAtIEEgbGlzdCBvZiByZXNvdXJjZXMgdG8gZGVkdXBsaWNhdGVcbiAqIEByZXR1cm5zIEEgbGlzdCBvZiB1bmlxdWUgcmVzb3VyY2VzXG4gKi9cbmZ1bmN0aW9uIGRlZHVwbGljYXRlUmVzb3VyY2VzKHJlc291cmNlczogUmVzb3VyY2VEZXRhaWxbXSkge1xuICBsZXQgdW5pcXVlUmVzb3VyY2VzOiB7IFtrZXk6IHN0cmluZ106IFJlc291cmNlRGV0YWlsIH0gPSB7fTtcblxuICBmb3IgKGNvbnN0IHJlc291cmNlIG9mIHJlc291cmNlcykge1xuICAgIGNvbnN0IGtleSA9IE9iamVjdC5rZXlzKHJlc291cmNlLlJlc291cmNlSWRlbnRpZmllciEpWzBdO1xuXG4gICAgLy8gQ3JlYXRpbmcgb3VyIHVuaXF1ZSBpZGVudGlmaWVyIHVzaW5nIHRoZSByZXNvdXJjZSB0eXBlLCB0aGUga2V5LCBhbmQgdGhlIHZhbHVlIG9mIHRoZSByZXNvdXJjZSBpZGVudGlmaWVyXG4gICAgLy8gVGhlIHJlc291cmNlIGlkZW50aWZpZXIgaXMgYSBjb21iaW5hdGlvbiBvZiBhIGtleSB2YWx1ZSBwYWlyIGRlZmluZWQgYnkgYSByZXNvdXJjZSdzIHNjaGVtYSwgYW5kIHRoZSByZXNvdXJjZSB0eXBlIG9mIHRoZSByZXNvdXJjZS5cbiAgICBjb25zdCB1bmlxdWVJZGVudGlmZXIgPSBgJHtyZXNvdXJjZS5SZXNvdXJjZVR5cGV9OiR7a2V5fToke3Jlc291cmNlLlJlc291cmNlSWRlbnRpZmllciFba2V5XX1gO1xuICAgIHVuaXF1ZVJlc291cmNlc1t1bmlxdWVJZGVudGlmZXJdID0gcmVzb3VyY2U7XG4gIH1cblxuICByZXR1cm4gT2JqZWN0LnZhbHVlcyh1bmlxdWVSZXNvdXJjZXMpO1xufVxuXG4vKipcbiAqIENsYXNzIGZvciBtYWtpbmcgQ2xvdWRGb3JtYXRpb24gdGVtcGxhdGUgZ2VuZXJhdG9yIGNhbGxzXG4gKi9cbmV4cG9ydCBjbGFzcyBDZm5UZW1wbGF0ZUdlbmVyYXRvclByb3ZpZGVyIHtcbiAgcHJpdmF0ZSBjZm46IElDbG91ZEZvcm1hdGlvbkNsaWVudDtcbiAgcHJpdmF0ZSBpb0hlbHBlcjogSW9IZWxwZXI7XG4gIGNvbnN0cnVjdG9yKGNmbjogSUNsb3VkRm9ybWF0aW9uQ2xpZW50LCBpb0hlbHBlcjogSW9IZWxwZXIpIHtcbiAgICB0aGlzLmNmbiA9IGNmbjtcbiAgICB0aGlzLmlvSGVscGVyID0gaW9IZWxwZXI7XG4gIH1cblxuICBhc3luYyBjaGVja0ZvclJlc291cmNlU2NhbihcbiAgICByZXNvdXJjZVNjYW5TdW1tYXJpZXM6IFJlc291cmNlU2NhblN1bW1hcnlbXSB8IHVuZGVmaW5lZCxcbiAgICBvcHRpb25zOiBHZW5lcmF0ZVRlbXBsYXRlT3B0aW9ucyxcbiAgICBjbGllbnRSZXF1ZXN0VG9rZW46IHN0cmluZyxcbiAgKSB7XG4gICAgaWYgKCFyZXNvdXJjZVNjYW5TdW1tYXJpZXMgfHwgcmVzb3VyY2VTY2FuU3VtbWFyaWVzLmxlbmd0aCA9PT0gMCkge1xuICAgICAgaWYgKG9wdGlvbnMuZnJvbVNjYW4gPT09IEZyb21TY2FuLk1PU1RfUkVDRU5UKSB7XG4gICAgICAgIHRocm93IG5ldyBUb29sa2l0RXJyb3IoXG4gICAgICAgICAgJ05vU2NhbnNGb3VuZCcsXG4gICAgICAgICAgJ05vIHNjYW5zIGZvdW5kLiBQbGVhc2UgZWl0aGVyIHN0YXJ0IGEgbmV3IHNjYW4gd2l0aCB0aGUgYC0tZnJvbS1zY2FuYCBuZXcgb3IgZG8gbm90IHNwZWNpZnkgYSBgLS1mcm9tLXNjYW5gIG9wdGlvbi4nLFxuICAgICAgICApO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgYXdhaXQgdGhpcy5pb0hlbHBlci5kZWZhdWx0cy5pbmZvKCdObyBzY2FucyBmb3VuZC4gSW5pdGlhdGluZyBhIG5ldyByZXNvdXJjZSBzY2FuLicpO1xuICAgICAgICBhd2FpdCB0aGlzLnN0YXJ0UmVzb3VyY2VTY2FuKGNsaWVudFJlcXVlc3RUb2tlbik7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFJldHJpZXZlcyBhIHRva2VuaXplZCBsaXN0IG9mIHJlc291cmNlcyBhbmQgdGhlaXIgYXNzb2NpYXRlZCBzY2FuLiBJZiBhIHRva2VuIGlzIHByZXNlbnQgdGhlIGZ1bmN0aW9uXG4gICAqIHdpbGwgbG9vcCB0aHJvdWdoIGFsbCBwYWdlcyBhbmQgY29tYmluZSB0aGVtIGludG8gYSBzaW5nbGUgbGlzdCBvZiBTY2FubmVkUmVsYXRlZFJlc291cmNlc1xuICAgKlxuICAgKiBAcGFyYW0gc2NhbklkIC0gc2NhbiBpZCBmb3IgdGhlIHRvIGxpc3QgcmVzb3VyY2VzIGZvclxuICAgKiBAcGFyYW0gcmVzb3VyY2VzIC0gQSBsaXN0IG9mIHJlc291cmNlcyB0byBmaW5kIHJlbGF0ZWQgcmVzb3VyY2VzIGZvclxuICAgKi9cbiAgYXN5bmMgZ2V0UmVzb3VyY2VTY2FuUmVsYXRlZFJlc291cmNlcyhcbiAgICBzY2FuSWQ6IHN0cmluZyxcbiAgICByZXNvdXJjZXM6IFNjYW5uZWRSZXNvdXJjZVtdLFxuICApOiBQcm9taXNlPFNjYW5uZWRSZXNvdXJjZUlkZW50aWZpZXJbXT4ge1xuICAgIGxldCByZWxhdGVkUmVzb3VyY2VMaXN0ID0gcmVzb3VyY2VzO1xuXG4gICAgLy8gYnJlYWsgdGhlIGxpc3Qgb2YgcmVzb3VyY2VzIGludG8gY2h1bmtzIG9mIDEwMCB0byBhdm9pZCBoaXR0aW5nIHRoZSAxMDAgcmVzb3VyY2UgbGltaXRcbiAgICBmb3IgKGNvbnN0IGNodW5rIG9mIGNodW5rcyhyZXNvdXJjZXMsIDEwMCkpIHtcbiAgICAgIC8vIGdldCB0aGUgZmlyc3QgcGFnZSBvZiByZWxhdGVkIHJlc291cmNlc1xuICAgICAgY29uc3QgcmVzID0gYXdhaXQgdGhpcy5jZm4ubGlzdFJlc291cmNlU2NhblJlbGF0ZWRSZXNvdXJjZXMoe1xuICAgICAgICBSZXNvdXJjZVNjYW5JZDogc2NhbklkLFxuICAgICAgICBSZXNvdXJjZXM6IGNodW5rLFxuICAgICAgfSk7XG5cbiAgICAgIC8vIGFkZCB0aGUgZmlyc3QgcGFnZSB0byB0aGUgbGlzdFxuICAgICAgcmVsYXRlZFJlc291cmNlTGlzdC5wdXNoKC4uLihyZXMuUmVsYXRlZFJlc291cmNlcyA/PyBbXSkpO1xuICAgICAgbGV0IG5leHRUb2tlbiA9IHJlcy5OZXh0VG9rZW47XG5cbiAgICAgIC8vIGlmIHRoZXJlIGFyZSBtb3JlIHBhZ2VzLCBjeWNsZSB0aHJvdWdoIHRoZW0gYW5kIGFkZCB0aGVtIHRvIHRoZSBsaXN0IGJlZm9yZSBtb3Zpbmcgb24gdG8gdGhlIG5leHQgY2h1bmtcbiAgICAgIHdoaWxlIChuZXh0VG9rZW4pIHtcbiAgICAgICAgY29uc3QgbmV4dFJlbGF0ZWRSZXNvdXJjZXMgPSBhd2FpdCB0aGlzLmNmbi5saXN0UmVzb3VyY2VTY2FuUmVsYXRlZFJlc291cmNlcyh7XG4gICAgICAgICAgUmVzb3VyY2VTY2FuSWQ6IHNjYW5JZCxcbiAgICAgICAgICBSZXNvdXJjZXM6IHJlc291cmNlSWRlbnRpZmllcnMocmVzb3VyY2VzKSxcbiAgICAgICAgICBOZXh0VG9rZW46IG5leHRUb2tlbixcbiAgICAgICAgfSk7XG4gICAgICAgIG5leHRUb2tlbiA9IG5leHRSZWxhdGVkUmVzb3VyY2VzLk5leHRUb2tlbjtcbiAgICAgICAgcmVsYXRlZFJlc291cmNlTGlzdC5wdXNoKC4uLihuZXh0UmVsYXRlZFJlc291cmNlcy5SZWxhdGVkUmVzb3VyY2VzID8/IFtdKSk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgcmVsYXRlZFJlc291cmNlTGlzdCA9IGRlZHVwbGljYXRlUmVzb3VyY2VzKHJlbGF0ZWRSZXNvdXJjZUxpc3QpO1xuXG4gICAgLy8gcHJ1bmUgdGhlIG1hbmFnZWRieXN0YWNrIGZsYWcgb2ZmIG9mIHRoZW0gYWdhaW4uXG4gICAgcmV0dXJuIHByb2Nlc3MuZW52Lk1JR1JBVEVfSU5URUdfVEVTVFxuICAgICAgPyByZXNvdXJjZUlkZW50aWZpZXJzKHJlbGF0ZWRSZXNvdXJjZUxpc3QpXG4gICAgICA6IHJlc291cmNlSWRlbnRpZmllcnMoZXhjbHVkZU1hbmFnZWQocmVsYXRlZFJlc291cmNlTGlzdCkpO1xuICB9XG5cbiAgLyoqXG4gICAqIEtpY2tzIG9mZiBhIHNjYW4gb2YgYSBjdXN0b21lcnMgYWNjb3VudCwgcmV0dXJuaW5nIHRoZSBzY2FuIGlkLiBBIHNjYW4gY2FuIHRha2VcbiAgICogMTAgbWludXRlcyBvciBsb25nZXIgdG8gY29tcGxldGUuIEhvd2V2ZXIgdGhpcyB3aWxsIHJldHVybiBhIHNjYW4gaWQgYXMgc29vbiBhc1xuICAgKiB0aGUgc2NhbiBoYXMgYmVndW4uXG4gICAqXG4gICAqIEByZXR1cm5zIEEgc3RyaW5nIHJlcHJlc2VudGluZyB0aGUgc2NhbiBpZFxuICAgKi9cbiAgYXN5bmMgc3RhcnRSZXNvdXJjZVNjYW4ocmVxdWVzdFRva2VuOiBzdHJpbmcpIHtcbiAgICByZXR1cm4gKFxuICAgICAgYXdhaXQgdGhpcy5jZm4uc3RhcnRSZXNvdXJjZVNjYW4oe1xuICAgICAgICBDbGllbnRSZXF1ZXN0VG9rZW46IHJlcXVlc3RUb2tlbixcbiAgICAgIH0pXG4gICAgKS5SZXNvdXJjZVNjYW5JZDtcbiAgfVxuXG4gIC8qKlxuICAgKiBHZXRzIHRoZSBtb3N0IHJlY2VudCBzY2FucyBhIGN1c3RvbWVyIGhhcyBjb21wbGV0ZWRcbiAgICpcbiAgICogQHJldHVybnMgYSBsaXN0IG9mIHJlc291cmNlIHNjYW4gc3VtbWFyaWVzXG4gICAqL1xuICBhc3luYyBsaXN0UmVzb3VyY2VTY2FucygpIHtcbiAgICByZXR1cm4gdGhpcy5jZm4ubGlzdFJlc291cmNlU2NhbnMoKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXRyaWV2ZXMgYSB0b2tlbml6ZWQgbGlzdCBvZiByZXNvdXJjZXMgZnJvbSBhIHJlc291cmNlIHNjYW4uIElmIGEgdG9rZW4gaXMgcHJlc2VudCwgdGhpcyBmdW5jdGlvblxuICAgKiB3aWxsIGxvb3AgdGhyb3VnaCBhbGwgcGFnZXMgYW5kIGNvbWJpbmUgdGhlbSBpbnRvIGEgc2luZ2xlIGxpc3Qgb2YgU2Nhbm5lZFJlc291cmNlW10uXG4gICAqIEFkZGl0aW9uYWxseSB3aWxsIGFwcGx5IGFueSBmaWx0ZXJzIHByb3ZpZGVkIGJ5IHRoZSBjdXN0b21lci5cbiAgICpcbiAgICogQHBhcmFtIHNjYW5JZCAtIHNjYW4gaWQgZm9yIHRoZSB0byBsaXN0IHJlc291cmNlcyBmb3JcbiAgICogQHBhcmFtIGZpbHRlcnMgLSBhIHN0cmluZyBvZiBmaWx0ZXJzIGluIHRoZSBmb3JtYXQgb2Yga2V5MT12YWx1ZTEsa2V5Mj12YWx1ZTJcbiAgICogQHJldHVybnMgYSBjb21iaW5lZCBsaXN0IG9mIGFsbCByZXNvdXJjZXMgZnJvbSB0aGUgc2NhblxuICAgKi9cbiAgYXN5bmMgbGlzdFJlc291cmNlU2NhblJlc291cmNlcyhzY2FuSWQ6IHN0cmluZywgZmlsdGVyczogc3RyaW5nW10gPSBbXSk6IFByb21pc2U8U2Nhbm5lZFJlc291cmNlSWRlbnRpZmllcltdPiB7XG4gICAgbGV0IHJlc291cmNlTGlzdDogU2Nhbm5lZFJlc291cmNlW10gPSBbXTtcbiAgICBsZXQgcmVzb3VyY2VTY2FuSW5wdXRzOiBMaXN0UmVzb3VyY2VTY2FuUmVzb3VyY2VzQ29tbWFuZElucHV0O1xuXG4gICAgaWYgKGZpbHRlcnMubGVuZ3RoID4gMCkge1xuICAgICAgYXdhaXQgdGhpcy5pb0hlbHBlci5kZWZhdWx0cy5pbmZvKCdBcHBseWluZyBmaWx0ZXJzIHRvIHJlc291cmNlIHNjYW4uJyk7XG4gICAgICBmb3IgKGNvbnN0IGZpbHRlciBvZiBmaWx0ZXJzKSB7XG4gICAgICAgIGNvbnN0IGZpbHRlckxpc3QgPSBwYXJzZUZpbHRlcnMoZmlsdGVyKTtcbiAgICAgICAgcmVzb3VyY2VTY2FuSW5wdXRzID0ge1xuICAgICAgICAgIFJlc291cmNlU2NhbklkOiBzY2FuSWQsXG4gICAgICAgICAgUmVzb3VyY2VJZGVudGlmaWVyOiBmaWx0ZXJMaXN0W0ZpbHRlclR5cGUuUkVTT1VSQ0VfSURFTlRJRklFUl0sXG4gICAgICAgICAgUmVzb3VyY2VUeXBlUHJlZml4OiBmaWx0ZXJMaXN0W0ZpbHRlclR5cGUuUkVTT1VSQ0VfVFlQRV9QUkVGSVhdLFxuICAgICAgICAgIFRhZ0tleTogZmlsdGVyTGlzdFtGaWx0ZXJUeXBlLlRBR19LRVldLFxuICAgICAgICAgIFRhZ1ZhbHVlOiBmaWx0ZXJMaXN0W0ZpbHRlclR5cGUuVEFHX1ZBTFVFXSxcbiAgICAgICAgfTtcbiAgICAgICAgY29uc3QgcmVzb3VyY2VzID0gYXdhaXQgdGhpcy5jZm4ubGlzdFJlc291cmNlU2NhblJlc291cmNlcyhyZXNvdXJjZVNjYW5JbnB1dHMpO1xuICAgICAgICByZXNvdXJjZUxpc3QgPSByZXNvdXJjZUxpc3QuY29uY2F0KHJlc291cmNlcy5SZXNvdXJjZXMgPz8gW10pO1xuICAgICAgICBsZXQgbmV4dFRva2VuID0gcmVzb3VyY2VzLk5leHRUb2tlbjtcblxuICAgICAgICAvLyBjeWNsZSB0aHJvdWdoIHRoZSBwYWdlcyBhZGRpbmcgYWxsIHJlc291cmNlcyB0byB0aGUgbGlzdCB1bnRpbCB3ZSBydW4gb3V0IG9mIHBhZ2VzXG4gICAgICAgIHdoaWxlIChuZXh0VG9rZW4pIHtcbiAgICAgICAgICByZXNvdXJjZVNjYW5JbnB1dHMuTmV4dFRva2VuID0gbmV4dFRva2VuO1xuICAgICAgICAgIGNvbnN0IG5leHRSZXNvdXJjZXMgPSBhd2FpdCB0aGlzLmNmbi5saXN0UmVzb3VyY2VTY2FuUmVzb3VyY2VzKHJlc291cmNlU2NhbklucHV0cyk7XG4gICAgICAgICAgbmV4dFRva2VuID0gbmV4dFJlc291cmNlcy5OZXh0VG9rZW47XG4gICAgICAgICAgcmVzb3VyY2VMaXN0ID0gcmVzb3VyY2VMaXN0IS5jb25jYXQobmV4dFJlc291cmNlcy5SZXNvdXJjZXMgPz8gW10pO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfSBlbHNlIHtcbiAgICAgIGF3YWl0IHRoaXMuaW9IZWxwZXIuZGVmYXVsdHMuaW5mbygnTm8gZmlsdGVycyBwcm92aWRlZC4gUmV0cmlldmluZyBhbGwgcmVzb3VyY2VzIGZyb20gc2Nhbi4nKTtcbiAgICAgIHJlc291cmNlU2NhbklucHV0cyA9IHtcbiAgICAgICAgUmVzb3VyY2VTY2FuSWQ6IHNjYW5JZCxcbiAgICAgIH07XG4gICAgICBjb25zdCByZXNvdXJjZXMgPSBhd2FpdCB0aGlzLmNmbi5saXN0UmVzb3VyY2VTY2FuUmVzb3VyY2VzKHJlc291cmNlU2NhbklucHV0cyk7XG4gICAgICByZXNvdXJjZUxpc3QgPSByZXNvdXJjZUxpc3QhLmNvbmNhdChyZXNvdXJjZXMuUmVzb3VyY2VzID8/IFtdKTtcbiAgICAgIGxldCBuZXh0VG9rZW4gPSByZXNvdXJjZXMuTmV4dFRva2VuO1xuXG4gICAgICAvLyBjeWNsZSB0aHJvdWdoIHRoZSBwYWdlcyBhZGRpbmcgYWxsIHJlc291cmNlcyB0byB0aGUgbGlzdCB1bnRpbCB3ZSBydW4gb3V0IG9mIHBhZ2VzXG4gICAgICB3aGlsZSAobmV4dFRva2VuKSB7XG4gICAgICAgIHJlc291cmNlU2NhbklucHV0cy5OZXh0VG9rZW4gPSBuZXh0VG9rZW47XG4gICAgICAgIGNvbnN0IG5leHRSZXNvdXJjZXMgPSBhd2FpdCB0aGlzLmNmbi5saXN0UmVzb3VyY2VTY2FuUmVzb3VyY2VzKHJlc291cmNlU2NhbklucHV0cyk7XG4gICAgICAgIG5leHRUb2tlbiA9IG5leHRSZXNvdXJjZXMuTmV4dFRva2VuO1xuICAgICAgICByZXNvdXJjZUxpc3QgPSByZXNvdXJjZUxpc3QhLmNvbmNhdChuZXh0UmVzb3VyY2VzLlJlc291cmNlcyA/PyBbXSk7XG4gICAgICB9XG4gICAgfVxuICAgIGlmIChyZXNvdXJjZUxpc3QubGVuZ3RoID09PSAwKSB7XG4gICAgICB0aHJvdyBuZXcgVG9vbGtpdEVycm9yKCdOb1Jlc291cmNlc0ZvdW5kJywgYE5vIHJlc291cmNlcyBmb3VuZCB3aXRoIGZpbHRlcnMgJHtmaWx0ZXJzLmpvaW4oJyAnKX0uIFBsZWFzZSB0cnkgYWdhaW4gd2l0aCBkaWZmZXJlbnQgZmlsdGVycy5gKTtcbiAgICB9XG4gICAgcmVzb3VyY2VMaXN0ID0gZGVkdXBsaWNhdGVSZXNvdXJjZXMocmVzb3VyY2VMaXN0KTtcblxuICAgIHJldHVybiBwcm9jZXNzLmVudi5NSUdSQVRFX0lOVEVHX1RFU1RcbiAgICAgID8gcmVzb3VyY2VJZGVudGlmaWVycyhyZXNvdXJjZUxpc3QpXG4gICAgICA6IHJlc291cmNlSWRlbnRpZmllcnMoZXhjbHVkZU1hbmFnZWQocmVzb3VyY2VMaXN0KSk7XG4gIH1cblxuICAvKipcbiAgICogUmV0cmlldmVzIGluZm9ybWF0aW9uIGFib3V0IGEgcmVzb3VyY2Ugc2Nhbi5cbiAgICpcbiAgICogQHBhcmFtIHNjYW5JZCAtIHNjYW4gaWQgZm9yIHRoZSB0byBsaXN0IHJlc291cmNlcyBmb3JcbiAgICogQHJldHVybnMgaW5mb3JtYXRpb24gYWJvdXQgdGhlIHNjYW5cbiAgICovXG4gIGFzeW5jIGRlc2NyaWJlUmVzb3VyY2VTY2FuKHNjYW5JZDogc3RyaW5nKTogUHJvbWlzZTxEZXNjcmliZVJlc291cmNlU2NhbkNvbW1hbmRPdXRwdXQ+IHtcbiAgICByZXR1cm4gdGhpcy5jZm4uZGVzY3JpYmVSZXNvdXJjZVNjYW4oe1xuICAgICAgUmVzb3VyY2VTY2FuSWQ6IHNjYW5JZCxcbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBEZXNjcmliZXMgdGhlIGN1cnJlbnQgc3RhdHVzIG9mIHRoZSB0ZW1wbGF0ZSBiZWluZyBnZW5lcmF0ZWQuXG4gICAqXG4gICAqIEBwYXJhbSB0ZW1wbGF0ZUlkIC0gQSBzdHJpbmcgcmVwcmVzZW50aW5nIHRoZSB0ZW1wbGF0ZSBpZFxuICAgKiBAcmV0dXJucyBEZXNjcmliZUdlbmVyYXRlZFRlbXBsYXRlT3V0cHV0IGFuIG9iamVjdCBjb250YWluaW5nIHRoZSB0ZW1wbGF0ZSBzdGF0dXMgYW5kIHJlc3VsdHNcbiAgICovXG4gIGFzeW5jIGRlc2NyaWJlR2VuZXJhdGVkVGVtcGxhdGUodGVtcGxhdGVJZDogc3RyaW5nKTogUHJvbWlzZTxEZXNjcmliZUdlbmVyYXRlZFRlbXBsYXRlQ29tbWFuZE91dHB1dD4ge1xuICAgIGNvbnN0IGdlbmVyYXRlZFRlbXBsYXRlID0gYXdhaXQgdGhpcy5jZm4uZGVzY3JpYmVHZW5lcmF0ZWRUZW1wbGF0ZSh7XG4gICAgICBHZW5lcmF0ZWRUZW1wbGF0ZU5hbWU6IHRlbXBsYXRlSWQsXG4gICAgfSk7XG5cbiAgICBpZiAoZ2VuZXJhdGVkVGVtcGxhdGUuU3RhdHVzID09IFNjYW5TdGF0dXMuRkFJTEVEKSB7XG4gICAgICB0aHJvdyBuZXcgVG9vbGtpdEVycm9yKCdUZW1wbGF0ZUdlbmVyYXRpb25GYWlsZWQnLCBnZW5lcmF0ZWRUZW1wbGF0ZS5TdGF0dXNSZWFzb24hKTtcbiAgICB9XG5cbiAgICByZXR1cm4gZ2VuZXJhdGVkVGVtcGxhdGU7XG4gIH1cblxuICAvKipcbiAgICogUmV0cmlldmVzIGEgY29tcGxldGVkIGdlbmVyYXRlZCBjbG91ZGZvcm1hdGlvbiB0ZW1wbGF0ZSBmcm9tIHRoZSB0ZW1wbGF0ZSBnZW5lcmF0b3IuXG4gICAqXG4gICAqIEBwYXJhbSB0ZW1wbGF0ZUlkIC0gQSBzdHJpbmcgcmVwcmVzZW50aW5nIHRoZSB0ZW1wbGF0ZSBpZFxuICAgKiBAcGFyYW0gY2xvdWRGb3JtYXRpb24gLSBUaGUgQ2xvdWRGb3JtYXRpb24gc2RrIGNsaWVudCB0byB1c2VcbiAgICogQHJldHVybnMgRGVzY3JpYmVHZW5lcmF0ZWRUZW1wbGF0ZU91dHB1dCBhbiBvYmplY3QgY29udGFpbmluZyB0aGUgdGVtcGxhdGUgc3RhdHVzIGFuZCBib2R5XG4gICAqL1xuICBhc3luYyBnZXRHZW5lcmF0ZWRUZW1wbGF0ZSh0ZW1wbGF0ZUlkOiBzdHJpbmcpOiBQcm9taXNlPEdldEdlbmVyYXRlZFRlbXBsYXRlQ29tbWFuZE91dHB1dD4ge1xuICAgIHJldHVybiB0aGlzLmNmbi5nZXRHZW5lcmF0ZWRUZW1wbGF0ZSh7XG4gICAgICBHZW5lcmF0ZWRUZW1wbGF0ZU5hbWU6IHRlbXBsYXRlSWQsXG4gICAgfSk7XG4gIH1cblxuICAvKipcbiAgICogS2lja3Mgb2ZmIGEgdGVtcGxhdGUgZ2VuZXJhdGlvbiBmb3IgYSBzZXQgb2YgcmVzb3VyY2VzLlxuICAgKlxuICAgKiBAcGFyYW0gc3RhY2tOYW1lIC0gVGhlIG5hbWUgb2YgdGhlIHN0YWNrXG4gICAqIEBwYXJhbSByZXNvdXJjZXMgLSBBIGxpc3Qgb2YgcmVzb3VyY2VzIHRvIGdlbmVyYXRlIHRoZSB0ZW1wbGF0ZSBmcm9tXG4gICAqIEByZXR1cm5zIENyZWF0ZUdlbmVyYXRlZFRlbXBsYXRlT3V0cHV0IGFuIG9iamVjdCBjb250YWluaW5nIHRoZSB0ZW1wbGF0ZSBhcm4gdG8gcXVlcnkgb24gbGF0ZXJcbiAgICovXG4gIGFzeW5jIGNyZWF0ZUdlbmVyYXRlZFRlbXBsYXRlKHN0YWNrTmFtZTogc3RyaW5nLCByZXNvdXJjZXM6IFJlc291cmNlRGVmaW5pdGlvbltdKSB7XG4gICAgY29uc3QgY3JlYXRlVGVtcGxhdGVPdXRwdXQgPSBhd2FpdCB0aGlzLmNmbi5jcmVhdGVHZW5lcmF0ZWRUZW1wbGF0ZSh7XG4gICAgICBSZXNvdXJjZXM6IHJlc291cmNlcyxcbiAgICAgIEdlbmVyYXRlZFRlbXBsYXRlTmFtZTogc3RhY2tOYW1lLFxuICAgIH0pO1xuXG4gICAgaWYgKGNyZWF0ZVRlbXBsYXRlT3V0cHV0LkdlbmVyYXRlZFRlbXBsYXRlSWQgPT09IHVuZGVmaW5lZCkge1xuICAgICAgdGhyb3cgbmV3IFRvb2xraXRFcnJvcignTWlzc2luZ1RlbXBsYXRlQXJuJywgJ0NyZWF0ZUdlbmVyYXRlZFRlbXBsYXRlIGZhaWxlZCB0byByZXR1cm4gYW4gQXJuLicpO1xuICAgIH1cbiAgICByZXR1cm4gY3JlYXRlVGVtcGxhdGVPdXRwdXQ7XG4gIH1cblxuICAvKipcbiAgICogRGVsZXRlcyBhIGdlbmVyYXRlZCB0ZW1wbGF0ZSBmcm9tIHRoZSB0ZW1wbGF0ZSBnZW5lcmF0b3IuXG4gICAqXG4gICAqIEBwYXJhbSB0ZW1wbGF0ZUFybiAtIFRoZSBhcm4gb2YgdGhlIHRlbXBsYXRlIHRvIGRlbGV0ZVxuICAgKiBAcmV0dXJucyBBIHByb21pc2UgdGhhdCByZXNvbHZlcyB3aGVuIHRoZSB0ZW1wbGF0ZSBoYXMgYmVlbiBkZWxldGVkXG4gICAqL1xuICBhc3luYyBkZWxldGVHZW5lcmF0ZWRUZW1wbGF0ZSh0ZW1wbGF0ZUFybjogc3RyaW5nKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgYXdhaXQgdGhpcy5jZm4uZGVsZXRlR2VuZXJhdGVkVGVtcGxhdGUoe1xuICAgICAgR2VuZXJhdGVkVGVtcGxhdGVOYW1lOiB0ZW1wbGF0ZUFybixcbiAgICB9KTtcbiAgfVxufVxuXG4vKipcbiAqIFRoZSBwb3NzaWJsZSB3YXlzIHRvIGNob29zZSBhIHNjYW4gdG8gZ2VuZXJhdGUgYSBDREsgYXBwbGljYXRpb24gZnJvbVxuICovXG5leHBvcnQgZW51bSBGcm9tU2NhbiB7XG4gIC8qKlxuICAgKiBJbml0aWF0ZSBhIG5ldyByZXNvdXJjZSBzY2FuIHRvIGJ1aWxkIHRoZSBDREsgYXBwbGljYXRpb24gZnJvbS5cbiAgICovXG4gIE5FVyxcblxuICAvKipcbiAgICogVXNlIHRoZSBsYXN0IHN1Y2Nlc3NmdWwgc2NhbiB0byBidWlsZCB0aGUgQ0RLIGFwcGxpY2F0aW9uIGZyb20uIFdpbGwgZmFpbCBpZiBubyBzY2FuIGlzIGZvdW5kLlxuICAgKi9cbiAgTU9TVF9SRUNFTlQsXG5cbiAgLyoqXG4gICAqIFN0YXJ0cyBhIHNjYW4gaWYgbm9uZSBleGlzdHMsIG90aGVyd2lzZSB1c2VzIHRoZSBtb3N0IHJlY2VudCBzdWNjZXNzZnVsIHNjYW4gdG8gYnVpbGQgdGhlIENESyBhcHBsaWNhdGlvbiBmcm9tLlxuICAgKi9cbiAgREVGQVVMVCxcbn1cblxuLyoqXG4gKiBJbnRlcmZhY2UgZm9yIHRoZSBvcHRpb25zIG9iamVjdCBwYXNzZWQgdG8gdGhlIGdlbmVyYXRlVGVtcGxhdGUgZnVuY3Rpb25cbiAqXG4gKiBAcGFyYW0gc3RhY2tOYW1lIC0gVGhlIG5hbWUgb2YgdGhlIHN0YWNrXG4gKiBAcGFyYW0gZmlsdGVycyAtIEEgbGlzdCBvZiBmaWx0ZXJzIHRvIGFwcGx5IHRvIHRoZSBzY2FuXG4gKiBAcGFyYW0gZnJvbVNjYW4gLSBBbiBlbnVtIHZhbHVlIHNwZWNpZnlpbmcgd2hldGhlciBhIG5ldyBzY2FuIHNob3VsZCBiZSBzdGFydGVkIG9yIHRoZSBtb3N0IHJlY2VudCBzdWNjZXNzZnVsIHNjYW4gc2hvdWxkIGJlIHVzZWRcbiAqIEBwYXJhbSBzZGtQcm92aWRlciAtIFRoZSBzZGsgcHJvdmlkZXIgZm9yIG1ha2luZyBDbG91ZEZvcm1hdGlvbiBjYWxsc1xuICogQHBhcmFtIGVudmlyb25tZW50IC0gVGhlIGFjY291bnQgYW5kIHJlZ2lvbiB3aGVyZSB0aGUgc3RhY2sgaXMgZGVwbG95ZWRcbiAqL1xuZXhwb3J0IGludGVyZmFjZSBHZW5lcmF0ZVRlbXBsYXRlT3B0aW9ucyB7XG4gIHN0YWNrTmFtZTogc3RyaW5nO1xuICBmaWx0ZXJzPzogc3RyaW5nW107XG4gIGZyb21TY2FuPzogRnJvbVNjYW47XG4gIHNka1Byb3ZpZGVyOiBTZGtQcm92aWRlcjtcbiAgZW52aXJvbm1lbnQ6IEVudmlyb25tZW50O1xuICBpb0hlbHBlcjogSW9IZWxwZXI7XG59XG5cbi8qKlxuICogSW50ZXJmYWNlIGZvciB0aGUgb3V0cHV0IG9mIHRoZSBnZW5lcmF0ZVRlbXBsYXRlIGZ1bmN0aW9uXG4gKlxuICogQHBhcmFtIG1pZ3JhdGVKc29uIC0gVGhlIGdlbmVyYXRlZCBNaWdyYXRlLmpzb24gZmlsZVxuICogQHBhcmFtIHJlc291cmNlcyAtIFRoZSBnZW5lcmF0ZWQgdGVtcGxhdGVcbiAqL1xuZXhwb3J0IGludGVyZmFjZSBHZW5lcmF0ZVRlbXBsYXRlT3V0cHV0IHtcbiAgbWlncmF0ZUpzb246IE1pZ3JhdGVKc29uRm9ybWF0O1xuICByZXNvdXJjZXM/OiBSZXNvdXJjZURldGFpbFtdO1xuICB0ZW1wbGF0ZUlkPzogc3RyaW5nO1xufVxuXG4vKipcbiAqIEludGVyZmFjZSBkZWZpbmluZyB0aGUgZm9ybWF0IG9mIHRoZSBnZW5lcmF0ZWQgTWlncmF0ZS5qc29uIGZpbGVcbiAqXG4gKiBAcGFyYW0gVGVtcGxhdGVCb2R5IC0gVGhlIGdlbmVyYXRlZCB0ZW1wbGF0ZVxuICogQHBhcmFtIFNvdXJjZSAtIFRoZSBzb3VyY2Ugb2YgdGhlIHRlbXBsYXRlXG4gKiBAcGFyYW0gUmVzb3VyY2VzIC0gQSBsaXN0IG9mIHJlc291cmNlcyB0aGF0IHdlcmUgdXNlZCB0byBnZW5lcmF0ZSB0aGUgdGVtcGxhdGVcbiAqL1xuZXhwb3J0IGludGVyZmFjZSBNaWdyYXRlSnNvbkZvcm1hdCB7XG4gIHRlbXBsYXRlQm9keTogc3RyaW5nO1xuICBzb3VyY2U6IHN0cmluZztcbiAgcmVzb3VyY2VzPzogR2VuZXJhdGVkUmVzb3VyY2VJbXBvcnRJZGVudGlmaWVyW107XG59XG5cbi8qKlxuICogSW50ZXJmYWNlIHJlcHJlc2VudGluZyB0aGUgZm9ybWF0IG9mIGEgcmVzb3VyY2UgaWRlbnRpZmllciByZXF1aXJlZCBmb3IgcmVzb3VyY2UgaW1wb3J0XG4gKlxuICogQHBhcmFtIFJlc291cmNlVHlwZSAtIFRoZSB0eXBlIG9mIHJlc291cmNlXG4gKiBAcGFyYW0gTG9naWNhbFJlc291cmNlSWQgLSBUaGUgbG9naWNhbCBpZCBvZiB0aGUgcmVzb3VyY2VcbiAqIEBwYXJhbSBSZXNvdXJjZUlkZW50aWZpZXIgLSBUaGUgcmVzb3VyY2UgaWRlbnRpZmllciBvZiB0aGUgcmVzb3VyY2VcbiAqL1xuZXhwb3J0IGludGVyZmFjZSBHZW5lcmF0ZWRSZXNvdXJjZUltcG9ydElkZW50aWZpZXIge1xuICAvLyBjZGsgZGVwbG95IGV4cGVjdHMgdGhlIG1pZ3JhdGUuanNvbiByZXNvdXJjZSBpZGVudGlmaWVycyB0byBiZSBQYXNjYWxDYXNlLCBub3QgY2FtZWxDYXNlLlxuICBSZXNvdXJjZVR5cGU6IHN0cmluZztcbiAgTG9naWNhbFJlc291cmNlSWQ6IHN0cmluZztcbiAgUmVzb3VyY2VJZGVudGlmaWVyOiBSZXNvdXJjZUlkZW50aWZpZXJTdW1tYXJ5O1xufVxuIl19