"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