aws-cloudformation-custom-resource
Version:
Helper for managing custom AWS CloudFormation resources in a Lambda function
284 lines • 39.4 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.StandardLogger = exports.LogLevel = exports.CustomResource = void 0;
const https = require("https");
/**
* Custom CloudFormation resource helper
*/
class CustomResource {
constructor(event, context, callback, createFunction, updateFunction, deleteFunction) {
/**
* Stores values returned to CloudFormation
*/
this.responseData = {};
/**
* Indicates whether to mask the output of the custom resource when it's retrieved by using the `Fn::GetAtt` function.
*
* If set to `true`, all returned values are masked with asterisks (*****), except for information stored in the locations specified below. By default, this value is `false`.
*/
this.noEcho = false;
/**
* Proxy handler for ResourceProperties
*/
this.propertiesProxyHandler = {
get: (target, propertyKey) => {
if (typeof propertyKey === 'symbol') {
return undefined; // Symbols are not supported as property keys
}
// Return another proxy for the given property key to handle value, changed, and before.
return new Proxy({ key: propertyKey }, {
get: (_, property) => {
var _a, _b;
if (property === 'value') {
return target[propertyKey];
}
if (property === 'toString' || property === 'valueOf') {
return () => target[propertyKey];
}
if (property === 'changed') {
const before = (_a = this.event.OldResourceProperties) === null || _a === void 0 ? void 0 : _a[propertyKey];
const newValue = target[propertyKey];
const changed = JSON.stringify(before) !== JSON.stringify(newValue);
return changed;
}
// When '.before' is accessed, return the old value.
if (property === 'before') {
return (_b = this.event.OldResourceProperties) === null || _b === void 0 ? void 0 : _b[propertyKey];
}
// Fallback handler for other properties on the second-level proxy.
return undefined;
},
});
},
};
this.event = event;
this.context = context;
this.callback = callback;
this.properties = new Proxy(event.ResourceProperties, this.propertiesProxyHandler);
this.createFunction = createFunction;
this.updateFunction = updateFunction;
this.deleteFunction = deleteFunction;
this.logger = new StandardLogger();
if (this.event.PhysicalResourceId) {
this.setPhysicalResourceId(this.event.PhysicalResourceId);
}
setTimeout(() => {
this.handle();
});
}
/**
* Adds values to the response returned to CloudFormation
*/
addResponseValue(key, value) {
this.responseData[key] = value;
}
/**
* Set the physical ID of the resource
*/
setPhysicalResourceId(value) {
this.physicalResourceId = value;
}
/**
* Get the physical ID of the resource
*/
getPhysicalResourceId() {
return this.physicalResourceId;
}
/**
* Set whether to mask the output of the custom resource when it's retrieved by using the `Fn::GetAtt` function.
*
* If set to `true`, all returned values are masked with asterisks (*****), except for information stored in the locations specified below. By default, this value is `false`.
*/
setNoEcho(value) {
this.noEcho = value;
}
/**
* Get whether to mask the output of the custom resource when it's retrieved by using the `Fn::GetAtt` function.
*/
getNoEcho() {
return this.noEcho;
}
/**
* Set the logger class
*/
setLogger(logger) {
this.logger = logger;
}
/**
* Handles the Lambda event
*/
handle() {
if (typeof this.event.ResponseURL === 'undefined') {
throw new Error('ResponseURL missing');
}
this.logger.info('REQUEST RECEIVED:', JSON.stringify(this.event));
this.timeout();
try {
let handlerFunction;
switch (this.event.RequestType // Changed to switch for better readability
) {
case 'Create':
handlerFunction = this.createFunction;
break;
case 'Update':
handlerFunction = this.updateFunction;
break;
case 'Delete':
handlerFunction = this.deleteFunction;
break;
default:
this.sendResponse('FAILED',
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
`Unexpected request type: ${this.event.RequestType}`);
return;
}
handlerFunction(this, this.logger)
.then(() => {
this.sendResponse('SUCCESS', `${this.event.RequestType} completed successfully`);
})
.catch((err) => {
this.handleError(err);
});
}
catch (err) {
this.handleError(err);
}
}
handleError(err) {
console.log(err);
this.logger.error(JSON.stringify(err, null, 2));
let errorMessage;
if (err instanceof Error) {
errorMessage = err.message;
}
else if (typeof err === 'string') {
errorMessage = err;
}
else {
errorMessage = `Unknown error: ${JSON.stringify(err)}`;
}
this.sendResponse('FAILED', errorMessage);
}
/**
* Sends CloudFormation response just before the Lambda times out
*/
timeout() {
const handler = () => {
this.logger.error('Timeout FAILURE!');
new Promise(() => this.sendResponse('FAILED', 'Function timed out'))
.then(() => this.callback(new Error('Function timed out')))
.catch((err) => {
this.handleError(err);
});
};
this.timeoutTimer = setTimeout(handler, this.context.getRemainingTimeInMillis() - 1000);
}
/**
* Sends CloudFormation response
*/
sendResponse(responseStatus, responseData) {
var _a, _b;
this.logger.debug(`Clearing timeout timer, as we're about to send a response...`);
clearTimeout(this.timeoutTimer);
this.logger.debug(`Sending response ${responseStatus}:`, JSON.stringify(responseData, null, 2));
const body = {
/* eslint-disable @typescript-eslint/naming-convention */
Status: responseStatus,
Reason: `${responseData} | ${responseStatus === 'FAILED' ? 'Full error' : 'Details'} in CloudWatch ${this.context.logStreamName}`,
PhysicalResourceId: (_b = (_a = this.physicalResourceId) !== null && _a !== void 0 ? _a : this.event.ResourceProperties.name) !== null && _b !== void 0 ? _b : this.context.logStreamName,
StackId: this.event.StackId,
RequestId: this.event.RequestId,
LogicalResourceId: this.event.LogicalResourceId,
Data: this.responseData,
NoEcho: this.noEcho,
/* eslint-enable @typescript-eslint/naming-convention */
};
const bodyString = JSON.stringify(body);
const url = new URL(this.event.ResponseURL);
const options = {
hostname: url.hostname,
port: 443,
path: `${url.pathname}${url.search}`,
method: 'PUT',
headers: {
/* eslint-disable @typescript-eslint/naming-convention */
'content-type': '',
'content-length': bodyString.length,
/* eslint-enable @typescript-eslint/naming-convention */
},
};
this.logger.info('SENDING RESPONSE...', JSON.stringify({ options, body }, null, 2));
const request = https.request(options, (response) => {
this.logger.debug('RESULT:', {
status: response.statusCode,
headers: response.headers,
});
this.callback(null, 'done');
});
request.on('error', (error) => {
this.logger.error('sendResponse Error:', JSON.stringify(error));
this.callback(error);
});
request.write(bodyString);
request.end();
}
}
exports.CustomResource = CustomResource;
/**
* LogLevels supported by the logger
*/
var LogLevel;
(function (LogLevel) {
LogLevel[LogLevel["error"] = 0] = "error";
LogLevel[LogLevel["warn"] = 1] = "warn";
LogLevel[LogLevel["info"] = 2] = "info";
LogLevel[LogLevel["debug"] = 3] = "debug";
})(LogLevel || (exports.LogLevel = LogLevel = {}));
/**
* Standard logger class
*/
class StandardLogger {
constructor(level) {
this.level = level !== null && level !== void 0 ? level : LogLevel.warn;
}
/**
* Logs message with level ERROR
*/
error(message, ...optionalParams) {
if (this.level < LogLevel.error)
return;
console.error(message, ...optionalParams);
}
/**
* Logs message with level WARN
*/
warn(message, ...optionalParams) {
if (this.level < LogLevel.warn)
return;
console.warn(message, ...optionalParams);
}
/**
* Logs message with level INFO
*/
info(message, ...optionalParams) {
if (this.level < LogLevel.info)
return;
console.info(message, ...optionalParams);
}
/**
* Logs message with level DEBUG
*/
debug(message, ...optionalParams) {
if (this.level < LogLevel.debug)
return;
console.debug(message, ...optionalParams);
}
/**
* Alias for info
*/
log(message, ...optionalParams) {
this.info(message, ...optionalParams);
}
}
exports.StandardLogger = StandardLogger;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJpbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFBQSwrQkFBZ0M7QUE2RmhDOztHQUVHO0FBQ0gsTUFBYSxjQUFjO0lBb0V6QixZQUNFLEtBQWdDLEVBQ2hDLE9BQWdCLEVBQ2hCLFFBQWtCLEVBQ2xCLGNBQW1ELEVBQ25ELGNBQW1ELEVBQ25ELGNBQW1EO1FBcENyRDs7V0FFRztRQUNLLGlCQUFZLEdBQWtDLEVBQUUsQ0FBQztRQU96RDs7OztXQUlHO1FBQ0ssV0FBTSxHQUFHLEtBQUssQ0FBQztRQTBDdkI7O1dBRUc7UUFDSywyQkFBc0IsR0FFMUI7WUFDRixHQUFHLEVBQUUsQ0FDSCxNQUFvRCxFQUNwRCxXQUE0QixFQUM1QixFQUFFO2dCQUNGLElBQUksT0FBTyxXQUFXLEtBQUssUUFBUSxFQUFFLENBQUM7b0JBQ3BDLE9BQU8sU0FBUyxDQUFDLENBQUMsNkNBQTZDO2dCQUNqRSxDQUFDO2dCQUVELHdGQUF3RjtnQkFDeEYsT0FBTyxJQUFJLEtBQUssQ0FDZCxFQUFFLEdBQUcsRUFBRSxXQUFXLEVBQUUsRUFDcEI7b0JBQ0UsR0FBRyxFQUFFLENBQUMsQ0FBQyxFQUFFLFFBQXlCLEVBQUUsRUFBRTs7d0JBQ3BDLElBQUksUUFBUSxLQUFLLE9BQU8sRUFBRSxDQUFDOzRCQUN6QixPQUFPLE1BQU0sQ0FBQyxXQUF1QyxDQUFDLENBQUM7d0JBQ3pELENBQUM7d0JBRUQsSUFBSSxRQUFRLEtBQUssVUFBVSxJQUFJLFFBQVEsS0FBSyxTQUFTLEVBQUUsQ0FBQzs0QkFDdEQsT0FBTyxHQUFHLEVBQUUsQ0FBQyxNQUFNLENBQUMsV0FBdUMsQ0FBQyxDQUFDO3dCQUMvRCxDQUFDO3dCQUVELElBQUksUUFBUSxLQUFLLFNBQVMsRUFBRSxDQUFDOzRCQUMzQixNQUFNLE1BQU0sR0FDVixNQUFBLElBQUksQ0FBQyxLQUFLLENBQUMscUJBQXFCLDBDQUM5QixXQUF1QyxDQUN4QyxDQUFD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QUFnQixFQUFFLEdBQUcsY0FBeUI7UUFDaEQsSUFBSSxDQUFDLElBQUksQ0FBQyxPQUFPLEVBQUUsR0FBRyxjQUFjLENBQUMsQ0FBQztJQUN4QyxDQUFDO0NBQ0Y7QUFqREQsd0NBaURDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IGh0dHBzID0gcmVxdWlyZSgnaHR0cHMnKTtcblxuZXhwb3J0IHR5cGUgQ2FsbGJhY2s8VFJlc3VsdCA9IHVua25vd24+ID0gKFxuICBlcnJvcj86IEVycm9yIHwgc3RyaW5nIHwgbnVsbCxcbiAgcmVzdWx0PzogVFJlc3VsdCxcbikgPT4gdm9pZDtcblxuZXhwb3J0IGludGVyZmFjZSBDb250ZXh0IHtcbiAgY2FsbGJhY2tXYWl0c0ZvckVtcHR5RXZlbnRMb29wOiBib29sZWFuO1xuICBmdW5jdGlvbk5hbWU6IHN0cmluZztcbiAgZnVuY3Rpb25WZXJzaW9uOiBzdHJpbmc7XG4gIGludm9rZWRGdW5jdGlvbkFybjogc3RyaW5nO1xuICBtZW1vcnlMaW1pdEluTUI6IHN0cmluZztcbiAgYXdzUmVxdWVzdElkOiBzdHJpbmc7XG4gIGxvZ0dyb3VwTmFtZTogc3RyaW5nO1xuICBsb2dTdHJlYW1OYW1lOiBzdHJpbmc7XG4gIGdldFJlbWFpbmluZ1RpbWVJbk1pbGxpcygpOiBudW1iZXI7XG59XG5cbi8qKlxuICogRGVmYXVsdCByZXNvdXJjZSBwcm9wZXJ0aWVzLCBpZiB1c2VyIGRvZXMgbm90IHByb3ZpZGUgYW55IHZpYSBnZW5lcmljXG4gKi9cbnR5cGUgRGVmYXVsdFJlc291cmNlUHJvcGVydGllcyA9IFJlY29yZDxzdHJpbmcsIHN0cmluZz47XG5cbmludGVyZmFjZSBSZXNvdXJjZVByb3BlcnR5PFQ+IHtcbiAgLyoqXG4gICAqIFRoZSB2YWx1ZSBvZiB0aGUgcHJvcGVydHlcbiAgICovXG4gIHZhbHVlOiBUO1xuXG4gIC8qKlxuICAgKiBUaGUgdmFsdWUgb2YgdGhlIHByb3BlcnR5IGJlZm9yZSB0aGUgdXBkYXRlXG4gICAqXG4gICAqIE9ubHkgYXZhaWxhYmxlIGR1cmluZyBhIHJlc291cmNlIHVwZGF0ZVxuICAgKi9cbiAgYmVmb3JlPzogVDtcblxuICAvKipcbiAgICogSW5kaWNhdGVzIHdoZXRoZXIgdGhlIHZhbHVlIG9mIHRoZSBwcm9wZXJ0eSBoYXMgY2hhbmdlZFxuICAgKi9cbiAgY2hhbmdlZDogYm9vbGVhbjtcblxuICAvKipcbiAgICogUmV0dXJucyB0aGUgdmFsdWUgb2YgdGhlIHByb3BlcnR5XG4gICAqIEByZXR1cm5zIFRoZSB2YWx1ZSBvZiB0aGUgcHJvcGVydHlcbiAgICovXG4gIHRvU3RyaW5nKCk6IHN0cmluZztcblxuICAvKipcbiAgICogUmV0dXJucyB0aGUgdmFsdWUgb2YgdGhlIHByb3BlcnR5XG4gICAqIEByZXR1cm5zIFRoZSB2YWx1ZSBvZiB0aGUgcHJvcGVydHlcbiAgICovXG4gIHZhbHVlT2YoKTogc3RyaW5nO1xufVxuXG50eXBlIEN1c3RvbVJlc291cmNlUHJvcGVydGllczxSZXNvdXJjZVByb3BlcnRpZXMgZXh0ZW5kcyBvYmplY3Q+ID0ge1xuICBbUCBpbiBrZXlvZiBSZXNvdXJjZVByb3BlcnRpZXNdOiBSZXNvdXJjZVByb3BlcnR5PFJlc291cmNlUHJvcGVydGllc1tQXT47XG59O1xuXG4vKipcbiAqIFRoZSBldmVudCBwYXNzZWQgdG8gdGhlIExhbWJkYSBoYW5kbGVyXG4gKi9cbmV4cG9ydCB0eXBlIEV2ZW50PFJlc291cmNlUHJvcGVydGllcyA9IERlZmF1bHRSZXNvdXJjZVByb3BlcnRpZXM+ID0gT21pdDxcbiAgUmVjb3JkPHN0cmluZywgdW5rbm93bj4sXG4gICdSZXNvdXJjZVByb3BlcnRpZXMnXG4+ICYge1xuICAvKiBlc2xpbnQtZGlzYWJsZSBAdHlwZXNjcmlwdC1lc2xpbnQvbmFtaW5nLWNvbnZlbnRpb24gKi9cbiAgUGh5c2ljYWxSZXNvdXJjZUlkPzogc3RyaW5nO1xuICBTdGFja0lkOiBzdHJpbmc7XG4gIFJlcXVlc3RJZDogc3RyaW5nO1xuICBMb2dpY2FsUmVzb3VyY2VJZDogc3RyaW5nO1xuICBSZXNwb25zZVVSTD86IHN0cmluZztcbiAgUmVxdWVzdFR5cGU6ICdDcmVhdGUnIHwgJ1VwZGF0ZScgfCAnRGVsZXRlJztcbiAgUmVzb3VyY2VQcm9wZXJ0aWVzOiBSZXNvdXJjZVByb3BlcnRpZXM7XG4gIE9sZFJlc291cmNlUHJvcGVydGllcz86IFJlc291cmNlUHJvcGVydGllcztcbiAgLyogZXNsaW50LWVuYWJsZSBAdHlwZXNjcmlwdC1lc2xpbnQvbmFtaW5nLWNvbnZlbnRpb24gKi9cbn07XG5cbi8qKlxuICogQSByZXNwb25zZSB2YWx1ZSByZXR1cm5lZCB0byBDbG91ZEZvcm1hdGlvbi5cbiAqL1xuLy8gQXMgQ2xvdWRmb3JtYXRpb24gd2lsbCB0cmFuc2Zvcm0gYW55IHZhbHVlIHRvIGEgc3RyaW5nLCB3ZSdyZSB1cGZyb250IGV4cGxpY2l0IGFuZCBvbmx5IGFsbG93IHN0cmluZ3MgdG8gYXZvaWQgc3VycHJpc2VzXG4vLyBUZWNobmljYWxseSBpdCB3b3VsZCBiZSBwb3NzaWJsZSB0aG91Z2gsIHRvIGFjY2VwdCBib29sZWFucyBhbmQgbnVtYmVycyBhcyB3ZWxsLlxudHlwZSBSZXNwb25zZVZhbHVlID0gc3RyaW5nO1xuXG4vKipcbiAqIEZ1bmN0aW9uIHNpZ25hdHVyZVxuICovXG5leHBvcnQgdHlwZSBIYW5kbGVyRnVuY3Rpb248UmVzb3VyY2VQcm9wZXJ0aWVzIGV4dGVuZHMgb2JqZWN0PiA9IChcbiAgcmVzb3VyY2U6IEN1c3RvbVJlc291cmNlPFJlc291cmNlUHJvcGVydGllcz4sXG4gIGxvZ2dlcjogTG9nZ2VyLFxuKSA9PiBQcm9taXNlPHZvaWQ+O1xuXG4vKipcbiAqIEN1c3RvbSBDbG91ZEZvcm1hdGlvbiByZXNvdXJjZSBoZWxwZXJcbiAqL1xuZXhwb3J0IGNsYXNzIEN1c3RvbVJlc291cmNlPFxuICBSZXNvdXJjZVByb3BlcnRpZXMgZXh0ZW5kcyBvYmplY3QgPSBEZWZhdWx0UmVzb3VyY2VQcm9wZXJ0aWVzLFxuPiB7XG4gIC8qKlxuICAgKiBTdG9yZXMgZnVuY3Rpb24gZXhlY3V0ZWQgd2hlbiByZXNvdXJjZSBjcmVhdGlvbiBpcyByZXF1ZXN0ZWRcbiAgICovXG4gIHByaXZhdGUgY3JlYXRlRnVuY3Rpb246IEhhbmRsZXJGdW5jdGlvbjxSZXNvdXJjZVByb3BlcnRpZXM+O1xuXG4gIC8qKlxuICAgKiBTdG9yZXMgZnVuY3Rpb24gZXhlY3V0ZWQgd2hlbiByZXNvdXJjZSB1cGRhdGUgaXMgcmVxdWVzdGVkXG4gICAqL1xuICBwcml2YXRlIHVwZGF0ZUZ1bmN0aW9uOiBIYW5kbGVyRnVuY3Rpb248UmVzb3VyY2VQcm9wZXJ0aWVzPjtcblxuICAvKipcbiAgICogU3RvcmVzIGZ1bmN0aW9uIGV4ZWN1dGVkIHdoZW4gcmVzb3VyY2UgZGVsZXRpb24gaXMgcmVxdWVzdGVkXG4gICAqL1xuICBwcml2YXRlIGRlbGV0ZUZ1bmN0aW9uOiBIYW5kbGVyRnVuY3Rpb248UmVzb3VyY2VQcm9wZXJ0aWVzPjtcblxuICAvKipcbiAgICogVGhlIGV2ZW50IHBhc3NlZCB0byB0aGUgTGFtYmRhIGhhbmRsZXJcbiAgICovXG4gIHB1YmxpYyByZWFkb25seSBldmVudDogRXZlbnQ8UmVzb3VyY2VQcm9wZXJ0aWVzPjtcblxuICAvKipcbiAgICogVGhlIGNvbnRleHQgcGFzc2VkIHRvIHRoZSBMYW1iZGEgaGFuZGxlclxuICAgKi9cbiAgcHVibGljIHJlYWRvbmx5IGNvbnRleHQ6IENvbnRleHQ7XG5cbiAgLyoqXG4gICAqIFRoZSBjYWxsYmFjayBmdW5jdGlvbiBwYXNzZWQgdG8gdGhlIExhbWJkYSBoYW5kbGVyXG4gICAqL1xuICBwdWJsaWMgcmVhZG9ubHkgY2FsbGJhY2s6IENhbGxiYWNrO1xuXG4gIC8qKlxuICAgKiBUaGUgcHJvcGVydGllcyBwYXNzZWQgdG8gdGhlIExhbWJkYSBmdW5jdGlvblxuICAgKi9cbiAgcHVibGljIHJlYWRvbmx5IHByb3BlcnRpZXM6IEN1c3RvbVJlc291cmNlUHJvcGVydGllczxSZXNvdXJjZVByb3BlcnRpZXM+O1xuXG4gIC8qKlxuICAgKiBTdG9yZXMgdmFsdWVzIHJldHVybmVkIHRvIENsb3VkRm9ybWF0aW9uXG4gICAqL1xuICBwcml2YXRlIHJlc3BvbnNlRGF0YTogUmVjb3JkPHN0cmluZywgUmVzcG9uc2VWYWx1ZT4gPSB7fTtcblxuICAvKipcbiAgICogU3RvcmVzIHZhbHVlcyBwaHlzaWNhbCBJRCBvZiB0aGUgcmVzb3VyY2VcbiAgICovXG4gIHByaXZhdGUgcGh5c2ljYWxSZXNvdXJjZUlkPzogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBJbmRpY2F0ZXMgd2hldGhlciB0byBtYXNrIHRoZSBvdXRwdXQgb2YgdGhlIGN1c3RvbSByZXNvdXJjZSB3aGVuIGl0J3MgcmV0cmlldmVkIGJ5IHVzaW5nIHRoZSBgRm46OkdldEF0dGAgZnVuY3Rpb24uXG4gICAqXG4gICAqIElmIHNldCB0byBgdHJ1ZWAsIGFsbCByZXR1cm5lZCB2YWx1ZXMgYXJlIG1hc2tlZCB3aXRoIGFzdGVyaXNrcyAoKioqKiopLCBleGNlcHQgZm9yIGluZm9ybWF0aW9uIHN0b3JlZCBpbiB0aGUgbG9jYXRpb25zIHNwZWNpZmllZCBiZWxvdy4gQnkgZGVmYXVsdCwgdGhpcyB2YWx1ZSBpcyBgZmFsc2VgLlxuICAgKi9cbiAgcHJpdmF0ZSBub0VjaG8gPSBmYWxzZTtcblxuICAvKipcbiAgICogTG9nZ2VyIGNsYXNzXG4gICAqL1xuICBwcml2YXRlIGxvZ2dlcjogTG9nZ2VyO1xuXG4gIC8qKlxuICAgKiBUaW1lciBmb3IgdGhlIExhbWJkYSB0aW1lb3V0XG4gICAqXG4gICAqIE9uZSBzZWNvbmQgYmVmb3JlIHRoZSBMYW1iZGEgdGltZXMgb3V0LCB3ZSBzZW5kIGEgRkFJTEVEIHJlc3BvbnNlIHRvIENsb3VkRm9ybWF0aW9uLlxuICAgKiBXZSBzdG9yZSB0aGUgdGltZXIsIHNvIHdlIGNhbiBjbGVhciBpdCB3aGVuIHdlIHNlbmQgdGhlIHJlc3BvbnNlLlxuICAgKi9cbiAgcHJpdmF0ZSB0aW1lb3V0VGltZXI/OiBOb2RlSlMuVGltZW91dDtcblxuICBjb25zdHJ1Y3RvcihcbiAgICBldmVudDogRXZlbnQ8UmVzb3VyY2VQcm9wZXJ0aWVzPixcbiAgICBjb250ZXh0OiBDb250ZXh0LFxuICAgIGNhbGxiYWNrOiBDYWxsYmFjayxcbiAgICBjcmVhdGVGdW5jdGlvbjogSGFuZGxlckZ1bmN0aW9uPFJlc291cmNlUHJvcGVydGllcz4sXG4gICAgdXBkYXRlRnVuY3Rpb246IEhhbmRsZXJGdW5jdGlvbjxSZXNvdXJjZVByb3BlcnRpZXM+LFxuICAgIGRlbGV0ZUZ1bmN0aW9uOiBIYW5kbGVyRnVuY3Rpb248UmVzb3VyY2VQcm9wZXJ0aWVzPixcbiAgKSB7XG4gICAgdGhpcy5ldmVudCA9IGV2ZW50O1xuICAgIHRoaXMuY29udGV4dCA9IGNvbnRleHQ7XG4gICAgdGhpcy5jYWxsYmFjayA9IGNhbGxiYWNrO1xuICAgIHRoaXMucHJvcGVydGllcyA9IG5ldyBQcm94eShcbiAgICAgIGV2ZW50LlJlc291cmNlUHJvcGVydGllcyBhcyBDdXN0b21SZXNvdXJjZVByb3BlcnRpZXM8UmVzb3VyY2VQcm9wZXJ0aWVzPixcbiAgICAgIHRoaXMucHJvcGVydGllc1Byb3h5SGFuZGxlcixcbiAgICApO1xuICAgIHRoaXMuY3JlYXRlRnVuY3Rpb24gPSBjcmVhdGVGdW5jdGlvbjtcbiAgICB0aGlzLnVwZGF0ZUZ1bmN0aW9uID0gdXBkYXRlRnVuY3Rpb247XG4gICAgdGhpcy5kZWxldGVGdW5jdGlvbiA9IGRlbGV0ZUZ1bmN0aW9uO1xuICAgIHRoaXMubG9nZ2VyID0gbmV3IFN0YW5kYXJkTG9nZ2VyKCk7XG4gICAgaWYgKHRoaXMuZXZlbnQuUGh5c2ljYWxSZXNvdXJjZUlkKSB7XG4gICAgICB0aGlzLnNldFBoeXNpY2FsUmVzb3VyY2VJZCh0aGlzLmV2ZW50LlBoeXNpY2FsUmVzb3VyY2VJZCk7XG4gICAgfVxuICAgIHNldFRpbWVvdXQoKCkgPT4ge1xuICAgICAgdGhpcy5oYW5kbGUoKTtcbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBQcm94eSBoYW5kbGVyIGZvciBSZXNvdXJjZVByb3BlcnRpZXNcbiAgICovXG4gIHByaXZhdGUgcHJvcGVydGllc1Byb3h5SGFuZGxlcjogUHJveHlIYW5kbGVyPFxuICAgIEN1c3RvbVJlc291cmNlUHJvcGVydGllczxSZXNvdXJjZVByb3BlcnRpZXM+XG4gID4gPSB7XG4gICAgZ2V0OiAoXG4gICAgICB0YXJnZXQ6IEN1c3RvbVJlc291cmNlUHJvcGVydGllczxSZXNvdXJjZVByb3BlcnRpZXM+LFxuICAgICAgcHJvcGVydHlLZXk6IHN0cmluZyB8IHN5bWJvbCxcbiAgICApID0+IHtcbiAgICAgIGlmICh0eXBlb2YgcHJvcGVydHlLZXkgPT09ICdzeW1ib2wnKSB7XG4gICAgICAgIHJldHVybiB1bmRlZmluZWQ7IC8vIFN5bWJvbHMgYXJlIG5vdCBzdXBwb3J0ZWQgYXMgcHJvcGVydHkga2V5c1xuICAgICAgfVxuXG4gICAgICAvLyBSZXR1cm4gYW5vdGhlciBwcm94eSBmb3IgdGhlIGdpdmVuIHByb3BlcnR5IGtleSB0byBoYW5kbGUgdmFsdWUsIGNoYW5nZWQsIGFuZCBiZWZvcmUuXG4gICAgICByZXR1cm4gbmV3IFByb3h5KFxuICAgICAgICB7IGtleTogcHJvcGVydHlLZXkgfSxcbiAgICAgICAge1xuICAgICAgICAgIGdldDogKF8sIHByb3BlcnR5OiBzdHJpbmcgfCBzeW1ib2wpID0+IHtcbiAgICAgICAgICAgIGlmIChwcm9wZXJ0eSA9PT0gJ3ZhbHVlJykge1xuICAgICAgICAgICAgICByZXR1cm4gdGFyZ2V0W3Byb3BlcnR5S2V5IGFzIGtleW9mIFJlc291cmNlUHJvcGVydGllc107XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGlmIChwcm9wZXJ0eSA9PT0gJ3RvU3RyaW5nJyB8fCBwcm9wZXJ0eSA9PT0gJ3ZhbHVlT2YnKSB7XG4gICAgICAgICAgICAgIHJldHVybiAoKSA9PiB0YXJnZXRbcHJvcGVydHlLZXkgYXMga2V5b2YgUmVzb3VyY2VQcm9wZXJ0aWVzXTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgaWYgKHByb3BlcnR5ID09PSAnY2hhbmdlZCcpIHtcbiAgICAgICAgICAgICAgY29uc3QgYmVmb3JlID1cbiAgICAgICAgICAgICAgICB0aGlzLmV2ZW50Lk9sZFJlc291cmNlUHJvcGVydGllcz8uW1xuICAgICAgICAgICAgICAgICAgcHJvcGVydHlLZXkgYXMga2V5b2YgUmVzb3VyY2VQcm9wZXJ0aWVzXG4gICAgICAgICAgICAgICAgXTtcbiAgICAgICAgICAgICAgY29uc3QgbmV3VmFsdWUgPSB0YXJnZXRbcHJvcGVydHlLZXkgYXMga2V5b2YgUmVzb3VyY2VQcm9wZXJ0aWVzXTtcbiAgICAgICAgICAgICAgY29uc3QgY2hhbmdlZCA9XG4gICAgICAgICAgICAgICAgSlNPTi5zdHJpbmdpZnkoYmVmb3JlKSAhPT0gSlNPTi5zdHJpbmdpZnkobmV3VmFsdWUpO1xuICAgICAgICAgICAgICByZXR1cm4gY2hhbmdlZDtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgLy8gV2hlbiAnLmJlZm9yZScgaXMgYWNjZXNzZWQsIHJldHVybiB0aGUgb2xkIHZhbHVlLlxuICAgICAgICAgICAgaWYgKHByb3BlcnR5ID09PSAnYmVmb3JlJykge1xuICAgICAgICAgICAgICByZXR1cm4gdGhpcy5ldmVudC5PbGRSZXNvdXJjZVByb3BlcnRpZXM/LltcbiAgICAgICAgICAgICAgICBwcm9wZXJ0eUtleSBhcyBrZXlvZiBSZXNvdXJjZVByb3BlcnRpZXNcbiAgICAgICAgICAgICAgXTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgLy8gRmFsbGJhY2sgaGFuZGxlciBmb3Igb3RoZXIgcHJvcGVydGllcyBvbiB0aGUgc2Vjb25kLWxldmVsIHByb3h5LlxuICAgICAgICAgICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICAgICAgICB9LFxuICAgICAgICB9LFxuICAgICAgKTtcbiAgICB9LFxuICB9O1xuXG4gIC8qKlxuICAgKiBBZGRzIHZhbHVlcyB0byB0aGUgcmVzcG9uc2UgcmV0dXJuZWQgdG8gQ2xvdWRGb3JtYXRpb25cbiAgICovXG4gIGFkZFJlc3BvbnNlVmFsdWUoa2V5OiBzdHJpbmcsIHZhbHVlOiBSZXNwb25zZVZhbHVlKSB7XG4gICAgdGhpcy5yZXNwb25zZURhdGFba2V5XSA9IHZhbHVlO1xuICB9XG5cbiAgLyoqXG4gICAqIFNldCB0aGUgcGh5c2ljYWwgSUQgb2YgdGhlIHJlc291cmNlXG4gICAqL1xuICBzZXRQaHlzaWNhbFJlc291cmNlSWQodmFsdWU6IHN0cmluZykge1xuICAgIHRoaXMucGh5c2ljYWxSZXNvdXJjZUlkID0gdmFsdWU7XG4gIH1cblxuICAvKipcbiAgICogR2V0IHRoZSBwaHlzaWNhbCBJRCBvZiB0aGUgcmVzb3VyY2VcbiAgICovXG4gIGdldFBoeXNpY2FsUmVzb3VyY2VJZCgpIHtcbiAgICByZXR1cm4gdGhpcy5waHlzaWNhbFJlc291cmNlSWQ7XG4gIH1cblxuICAvKipcbiAgICogU2V0IHdoZXRoZXIgdG8gbWFzayB0aGUgb3V0cHV0IG9mIHRoZSBjdXN0b20gcmVzb3VyY2Ugd2hlbiBpdCdzIHJldHJpZXZlZCBieSB1c2luZyB0aGUgYEZuOjpHZXRBdHRgIGZ1bmN0aW9uLlxuICAgKlxuICAgKiBJZiBzZXQgdG8gYHRydWVgLCBhbGwgcmV0dXJuZWQgdmFsdWVzIGFyZSBtYXNrZWQgd2l0aCBhc3Rlcmlza3MgKCoqKioqKSwgZXhjZXB0IGZvciBpbmZvcm1hdGlvbiBzdG9yZWQgaW4gdGhlIGxvY2F0aW9ucyBzcGVjaWZpZWQgYmVsb3cuIEJ5IGRlZmF1bHQsIHRoaXMgdmFsdWUgaXMgYGZhbHNlYC5cbiAgICovXG4gIHNldE5vRWNobyh2YWx1ZTogYm9vbGVhbikge1xuICAgIHRoaXMubm9FY2hvID0gdmFsdWU7XG4gIH1cblxuICAvKipcbiAgICogR2V0IHdoZXRoZXIgdG8gbWFzayB0aGUgb3V0cHV0IG9mIHRoZSBjdXN0b20gcmVzb3VyY2Ugd2hlbiBpdCdzIHJldHJpZXZlZCBieSB1c2luZyB0aGUgYEZuOjpHZXRBdHRgIGZ1bmN0aW9uLlxuICAgKi9cbiAgZ2V0Tm9FY2hvKCkge1xuICAgIHJldHVybiB0aGlzLm5vRWNobztcbiAgfVxuXG4gIC8qKlxuICAgKiBTZXQgdGhlIGxvZ2dlciBjbGFzc1xuICAgKi9cbiAgc2V0TG9nZ2VyKGxvZ2dlcjogTG9nZ2VyKSB7XG4gICAgdGhpcy5sb2dnZXIgPSBsb2dnZXI7XG4gIH1cblxuICAvKipcbiAgICogSGFuZGxlcyB0aGUgTGFtYmRhIGV2ZW50XG4gICAqL1xuICBwcml2YXRlIGhhbmRsZSgpIHtcbiAgICBpZiAodHlwZW9mIHRoaXMuZXZlbnQuUmVzcG9uc2VVUkwgPT09ICd1bmRlZmluZWQnKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ1Jlc3BvbnNlVVJMIG1pc3NpbmcnKTtcbiAgICB9XG5cbiAgICB0aGlzLmxvZ2dlci5pbmZvKCdSRVFVRVNUIFJFQ0VJVkVEOicsIEpTT04uc3RyaW5naWZ5KHRoaXMuZXZlbnQpKTtcbiAgICB0aGlzLnRpbWVvdXQoKTtcblxuICAgIHRyeSB7XG4gICAgICBsZXQgaGFuZGxlckZ1bmN0aW9uOiBIYW5kbGVyRnVuY3Rpb248UmVzb3VyY2VQcm9wZXJ0aWVzPjtcbiAgICAgIHN3aXRjaCAoXG4gICAgICAgIHRoaXMuZXZlbnQuUmVxdWVzdFR5cGUgLy8gQ2hhbmdlZCB0byBzd2l0Y2ggZm9yIGJldHRlciByZWFkYWJpbGl0eVxuICAgICAgKSB7XG4gICAgICAgIGNhc2UgJ0NyZWF0ZSc6XG4gICAgICAgICAgaGFuZGxlckZ1bmN0aW9uID0gdGhpcy5jcmVhdGVGdW5jdGlvbjtcbiAgICAgICAgICBicmVhaztcbiAgICAgICAgY2FzZSAnVXBkYXRlJzpcbiAgICAgICAgICBoYW5kbGVyRnVuY3Rpb24gPSB0aGlzLnVwZGF0ZUZ1bmN0aW9uO1xuICAgICAgICAgIGJyZWFrO1xuICAgICAgICBjYXNlICdEZWxldGUnOlxuICAgICAgICAgIGhhbmRsZXJGdW5jdGlvbiA9IHRoaXMuZGVsZXRlRnVuY3Rpb247XG4gICAgICAgICAgYnJlYWs7XG4gICAgICAgIGRlZmF1bHQ6XG4gICAgICAgICAgdGhpcy5zZW5kUmVzcG9uc2UoXG4gICAgICAgICAgICAnRkFJTEVEJyxcbiAgICAgICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBAdHlwZXNjcmlwdC1lc2xpbnQvcmVzdHJpY3QtdGVtcGxhdGUtZXhwcmVzc2lvbnNcbiAgICAgICAgICAgIGBVbmV4cGVjdGVkIHJlcXVlc3QgdHlwZTogJHt0aGlzLmV2ZW50LlJlcXVlc3RUeXBlfWAsXG4gICAgICAgICAgKTtcbiAgICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIGhhbmRsZXJGdW5jdGlvbih0aGlzLCB0aGlzLmxvZ2dlcilcbiAgICAgICAgLnRoZW4oKCkgPT4ge1xuICAgICAgICAgIHRoaXMuc2VuZFJlc3BvbnNlKFxuICAgICAgICAgICAgJ1NVQ0NFU1MnLFxuICAgICAgICAgICAgYCR7dGhpcy5ldmVudC5SZXF1ZXN0VHlwZX0gY29tcGxldGVkIHN1Y2Nlc3NmdWxseWAsXG4gICAgICAgICAgKTtcbiAgICAgICAgfSlcbiAgICAgICAgLmNhdGNoKChlcnI6IHVua25vd24pID0+IHtcbiAgICAgICAgICB0aGlzLmhhbmRsZUVycm9yKGVycik7XG4gICAgICAgIH0pO1xuICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgdGhpcy5oYW5kbGVFcnJvcihlcnIpO1xuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgaGFuZGxlRXJyb3IoZXJyOiB1bmtub3duKSB7XG4gICAgY29uc29sZS5sb2coZXJyKTtcbiAgICB0aGlzLmxvZ2dlci5lcnJvcihKU09OLnN0cmluZ2lmeShlcnIsIG51bGwsIDIpKTtcblxuICAgIGxldCBlcnJvck1lc3NhZ2U6IHN0cmluZztcbiAgICBpZiAoZXJyIGluc3RhbmNlb2YgRXJyb3IpIHtcbiAgICAgIGVycm9yTWVzc2FnZSA9IGVyci5tZXNzYWdlO1xuICAgIH0gZWxzZSBpZiAodHlwZW9mIGVyciA9PT0gJ3N0cmluZycpIHtcbiAgICAgIGVycm9yTWVzc2FnZSA9IGVycjtcbiAgICB9IGVsc2Uge1xuICAgICAgZXJyb3JNZXNzYWdlID0gYFVua25vd24gZXJyb3I6ICR7SlNPTi5zdHJpbmdpZnkoZXJyKX1gO1xuICAgIH1cblxuICAgIHRoaXMuc2VuZFJlc3BvbnNlKCdGQUlMRUQnLCBlcnJvck1lc3NhZ2UpO1xuICB9XG5cbiAgLyoqXG4gICAqIFNlbmRzIENsb3VkRm9ybWF0aW9uIHJlc3BvbnNlIGp1c3QgYmVmb3JlIHRoZSBMYW1iZGEgdGltZXMgb3V0XG4gICAqL1xuICBwcml2YXRlIHRpbWVvdXQoKSB7XG4gICAgY29uc3QgaGFuZGxlciA9ICgpID0+IHtcbiAgICAgIHRoaXMubG9nZ2VyLmVycm9yKCdUaW1lb3V0IEZBSUxVUkUhJyk7XG4gICAgICBuZXcgUHJvbWlzZSgoKSA9PiB0aGlzLnNlbmRSZXNwb25zZSgnRkFJTEVEJywgJ0Z1bmN0aW9uIHRpbWVkIG91dCcpKVxuICAgICAgICAudGhlbigoKSA9PiB0aGlzLmNhbGxiYWNrKG5ldyBFcnJvcignRnVuY3Rpb24gdGltZWQgb3V0JykpKVxuICAgICAgICAuY2F0Y2goKGVycjogdW5rbm93bikgPT4ge1xuICAgICAgICAgIHRoaXMuaGFuZGxlRXJyb3IoZXJyKTtcbiAgICAgICAgfSk7XG4gICAgfTtcbiAgICB0aGlzLnRpbWVvdXRUaW1lciA9IHNldFRpbWVvdXQoXG4gICAgICBoYW5kbGVyLFxuICAgICAgdGhpcy5jb250ZXh0LmdldFJlbWFpbmluZ1RpbWVJbk1pbGxpcygpIC0gMTAwMCxcbiAgICApO1xuICB9XG5cbiAgLyoqXG4gICAqIFNlbmRzIENsb3VkRm9ybWF0aW9uIHJlc3BvbnNlXG4gICAqL1xuICBwcml2YXRlIHNlbmRSZXNwb25zZShcbiAgICByZXNwb25zZVN0YXR1czogJ1NVQ0NFU1MnIHwgJ0ZBSUxFRCcsXG4gICAgcmVzcG9uc2VEYXRhOiBzdHJpbmcsXG4gICkge1xuICAgIHRoaXMubG9nZ2VyLmRlYnVnKFxuICAgICAgYENsZWFyaW5nIHRpbWVvdXQgdGltZXIsIGFzIHdlJ3JlIGFib3V0IHRvIHNlbmQgYSByZXNwb25zZS4uLmAsXG4gICAgKTtcbiAgICBjbGVhclRpbWVvdXQodGhpcy50aW1lb3V0VGltZXIpO1xuXG4gICAgdGhpcy5sb2dnZXIuZGVidWcoXG4gICAgICBgU2VuZGluZyByZXNwb25zZSAke3Jlc3BvbnNlU3RhdHVzfTpgLFxuICAgICAgSlNPTi5zdHJpbmdpZnkocmVzcG9uc2VEYXRhLCBudWxsLCAyKSxcbiAgICApO1xuXG4gICAgY29uc3QgYm9keSA9IHtcbiAgICAgIC8qIGVzbGludC1kaXNhYmxlIEB0eXBlc2NyaXB0LWVzbGludC9uYW1pbmctY29udmVudGlvbiAqL1xuICAgICAgU3RhdHVzOiByZXNwb25zZVN0YXR1cyxcbiAgICAgIFJlYXNvbjogYCR7cmVzcG9uc2VEYXRhfSB8ICR7cmVzcG9uc2VTdGF0dXMgPT09ICdGQUlMRUQnID8gJ0Z1bGwgZXJyb3InIDogJ0RldGFpbHMnfSBpbiBDbG91ZFdhdGNoICR7dGhpcy5jb250ZXh0LmxvZ1N0cmVhbU5hbWV9YCxcbiAgICAgIFBoeXNpY2FsUmVzb3VyY2VJZDpcbiAgICAgICAgdGhpcy5waHlzaWNhbFJlc291cmNlSWQgPz9cbiAgICAgICAgKHRoaXMuZXZlbnQuUmVzb3VyY2VQcm9wZXJ0aWVzIGFzIERlZmF1bHRSZXNvdXJjZVByb3BlcnRpZXMpLm5hbWUgPz9cbiAgICAgICAgdGhpcy5jb250ZXh0LmxvZ1N0cmVhbU5hbWUsXG4gICAgICBTdGFja0lkOiB0aGlzLmV2ZW50LlN0YWNrSWQsXG4gICAgICBSZXF1ZXN0SWQ6IHRoaXMuZXZlbnQuUmVxdWVzdElkLFxuICAgICAgTG9naWNhbFJlc291cmNlSWQ6IHRoaXMuZXZlbnQuTG9naWNhbFJlc291cmNlSWQsXG4gICAgICBEYXRhOiB0aGlzLnJlc3BvbnNlRGF0YSxcbiAgICAgIE5vRWNobzogdGhpcy5ub0VjaG8sXG4gICAgICAvKiBlc2xpbnQtZW5hYmxlIEB0eXBlc2NyaXB0LWVzbGludC9uYW1pbmctY29udmVudGlvbiAqL1xuICAgIH07XG5cbiAgICBjb25zdCBib2R5U3RyaW5nID0gSlNPTi5zdHJpbmdpZnkoYm9keSk7XG5cbiAgICBjb25zdCB1cmwgPSBuZXcgVVJMKHRoaXMuZXZlbnQuUmVzcG9uc2VVUkwhKTtcblxuICAgIGNvbnN0IG9wdGlvbnMgPSB7XG4gICAgICBob3N0bmFtZTogdXJsLmhvc3RuYW1lLFxuICAgICAgcG9ydDogNDQzLFxuICAgICAgcGF0aDogYCR7dXJsLnBhdGhuYW1lfSR7dXJsLnNlYXJjaH1gLFxuICAgICAgbWV0aG9kOiAnUFVUJyxcbiAgICAgIGhlYWRlcnM6IHtcbiAgICAgICAgLyogZXNsaW50LWRpc2FibGUgQHR5cGVzY3JpcHQtZXNsaW50L25hbWluZy1jb252ZW50aW9uICovXG4gICAgICAgICdjb250ZW50LXR5cGUnOiAnJyxcbiAgICAgICAgJ2NvbnRlbnQtbGVuZ3RoJzogYm9keVN0cmluZy5sZW5ndGgsXG4gICAgICAgIC8qIGVzbGludC1lbmFibGUgQHR5cGVzY3JpcHQtZXNsaW50L25hbWluZy1jb252ZW50aW9uICovXG4gICAgICB9LFxuICAgIH07XG5cbiAgICB0aGlzLmxvZ2dlci5pbmZvKFxuICAgICAgJ1NFTkRJTkcgUkVTUE9OU0UuLi4nLFxuICAgICAgSlNPTi5zdHJpbmdpZnkoeyBvcHRpb25zLCBib2R5IH0sIG51bGwsIDIpLFxuICAgICk7XG5cbiAgICBjb25zdCByZXF1ZXN0ID0gaHR0cHMucmVxdWVzdChvcHRpb25zLCAocmVzcG9uc2UpID0+IHtcbiAgICAgIHRoaXMubG9nZ2VyLmRlYnVnKCdSRVNVTFQ6Jywge1xuICAgICAgICBzdGF0dXM6IHJlc3BvbnNlLnN0YXR1c0NvZGUsXG4gICAgICAgIGhlYWRlcnM6IHJlc3BvbnNlLmhlYWRlcnMsXG4gICAgICB9KTtcbiAgICAgIHRoaXMuY2FsbGJhY2sobnVsbCwgJ2RvbmUnKTtcbiAgICB9KTtcblxuICAgIHJlcXVlc3Qub24oJ2Vycm9yJywgKGVycm9yKSA9PiB7XG4gICAgICB0aGlzLmxvZ2dlci5lcnJvcignc2VuZFJlc3BvbnNlIEVycm9yOicsIEpTT04uc3RyaW5naWZ5KGVycm9yKSk7XG4gICAgICB0aGlzLmNhbGxiYWNrKGVycm9yKTtcbiAgICB9KTtcblxuICAgIHJlcXVlc3Qud3JpdGUoYm9keVN0cmluZyk7XG4gICAgcmVxdWVzdC5lbmQoKTtcbiAgfVxufVxuXG4vKipcbiAqIExvZ2dlciBjbGFzc1xuICovXG5leHBvcnQgaW50ZXJmYWNlIExvZ2dlciB7XG4gIGxvZyhtZXNzYWdlOiB1bmtub3duLCAuLi5vcHRpb25hbFBhcmFtczogdW5rbm93bltdKTogdm9pZDtcbiAgaW5mbyhtZXNzYWdlOiB1bmtub3duLCAuLi5vcHRpb25hbFBhcmFtczogdW5rbm93bltdKTogdm9pZDtcbiAgZGVidWcobWVzc2FnZTogdW5rbm93biwgLi4ub3B0aW9uYWxQYXJhbXM6IHVua25vd25bXSk6IHZvaWQ7XG4gIHdhcm4obWVzc2FnZTogdW5rbm93biwgLi4ub3B0aW9uYWxQYXJhbXM6IHVua25vd25bXSk6IHZvaWQ7XG4gIGVycm9yKG1lc3NhZ2U6IHVua25vd24sIC4uLm9wdGlvbmFsUGFyYW1zOiB1bmtub3duW10pOiB2b2lkO1xufVxuXG4vKipcbiAqIExvZ0xldmVscyBzdXBwb3J0ZWQgYnkgdGhlIGxvZ2dlclxuICovXG5leHBvcnQgZW51bSBMb2dMZXZlbCB7XG4gIGVycm9yLFxuICB3YXJuLFxuICBpbmZvLFxuICBkZWJ1Zyxcbn1cblxuLyoqXG4gKiBTdGFuZGFyZCBsb2dnZXIgY2xhc3NcbiAqL1xuZXhwb3J0IGNsYXNzIFN0YW5kYXJkTG9nZ2VyIHtcbiAgLyoqXG4gICAqIFRoZSBsb2cgbGV2ZWxcbiAgICpcbiAgICogQGRlZmF1bHQgTG9nTGV2ZWwud2FyblxuICAgKi9cbiAgbGV2ZWw6IExvZ0xldmVsO1xuXG4gIGNvbnN0cnVjdG9yKGxldmVsPzogTG9nTGV2ZWwpIHtcbiAgICB0aGlzLmxldmVsID0gbGV2ZWwgPz8gTG9nTGV2ZWwud2FybjtcbiAgfVxuICAvKipcbiAgICogTG9ncyBtZXNzYWdlIHdpdGggbGV2ZWwgRVJST1JcbiAgICovXG4gIGVycm9yKG1lc3NhZ2U6IHVua25vd24sIC4uLm9wdGlvbmFsUGFyYW1zOiB1bmtub3duW10pIHtcbiAgICBpZiAodGhpcy5sZXZlbCA8IExvZ0xldmVsLmVycm9yKSByZXR1cm47XG4gICAgY29uc29sZS5lcnJvcihtZXNzYWdlLCAuLi5vcHRpb25hbFBhcmFtcyk7XG4gIH1cblxuICAvKipcbiAgICogTG9ncyBtZXNzYWdlIHdpdGggbGV2ZWwgV0FSTlxuICAgKi9cbiAgd2FybihtZXNzYWdlOiB1bmtub3duLCAuLi5vcHRpb25hbFBhcmFtczogdW5rbm93bltdKSB7XG4gICAgaWYgKHRoaXMubGV2ZWwgPCBMb2dMZXZlbC53YXJuKSByZXR1cm47XG4gICAgY29uc29sZS53YXJuKG1lc3NhZ2UsIC4uLm9wdGlvbmFsUGFyYW1zKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBMb2dzIG1lc3NhZ2Ugd2l0aCBsZXZlbCBJTkZPXG4gICAqL1xuICBpbmZvKG1lc3NhZ2U6IHVua25vd24sIC4uLm9wdGlvbmFsUGFyYW1zOiB1bmtub3duW10pIHtcbiAgICBpZiAodGhpcy5sZXZlbCA8IExvZ0xldmVsLmluZm8pIHJldHVybjtcbiAgICBjb25zb2xlLmluZm8obWVzc2FnZSwgLi4ub3B0aW9uYWxQYXJhbXMpO1xuICB9XG5cbiAgLyoqXG4gICAqIExvZ3MgbWVzc2FnZSB3aXRoIGxldmVsIERFQlVHXG4gICAqL1xuICBkZWJ1ZyhtZXNzYWdlOiB1bmtub3duLCAuLi5vcHRpb25hbFBhcmFtczogdW5rbm93bltdKSB7XG4gICAgaWYgKHRoaXMubGV2ZWwgPCBMb2dMZXZlbC5kZWJ1ZykgcmV0dXJuO1xuICAgIGNvbnNvbGUuZGVidWcobWVzc2FnZSwgLi4ub3B0aW9uYWxQYXJhbXMpO1xuICB9XG5cbiAgLyoqXG4gICAqIEFsaWFzIGZvciBpbmZvXG4gICAqL1xuICBsb2cobWVzc2FnZTogdW5rbm93biwgLi4ub3B0aW9uYWxQYXJhbXM6IHVua25vd25bXSkge1xuICAgIHRoaXMuaW5mbyhtZXNzYWdlLCAuLi5vcHRpb25hbFBhcmFtcyk7XG4gIH1cbn1cbiJdfQ==