@aws-cdk/core
Version:
AWS Cloud Development Kit Core Library
399 lines • 39.9 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.unionValidator = exports.requireProperty = exports.requiredValidator = exports.propertyValidator = exports.hashValidator = exports.listValidator = exports.validateCfnTag = exports.validateObject = exports.validateDate = exports.validateBoolean = exports.validateNumber = exports.validateString = exports.canInspect = exports.VALIDATION_SUCCESS = exports.ValidationResults = exports.ValidationResult = exports.unionMapper = exports.hashMapper = exports.listMapper = exports.cfnTagToCloudFormation = exports.dateToCloudFormation = exports.numberToCloudFormation = exports.objectToCloudFormation = exports.booleanToCloudFormation = exports.stringToCloudFormation = void 0;
function identity(x) {
return x;
}
exports.stringToCloudFormation = identity;
exports.booleanToCloudFormation = identity;
exports.objectToCloudFormation = identity;
exports.numberToCloudFormation = identity;
/**
* The date needs to be formatted as an ISO date in UTC
*
* Some usage sites require a date, some require a timestamp. We'll
* always output a timestamp and hope the parser on the other end
* is smart enough to ignore the time part... (?)
*/
function dateToCloudFormation(x) {
if (!x) {
return undefined;
}
// eslint-disable-next-line max-len
return `${x.getUTCFullYear()}-${pad(x.getUTCMonth() + 1)}-${pad(x.getUTCDate())}T${pad(x.getUTCHours())}:${pad(x.getUTCMinutes())}:${pad(x.getUTCSeconds())}`;
}
exports.dateToCloudFormation = dateToCloudFormation;
/**
* Pad a number to 2 decimal places
*/
function pad(x) {
if (x < 10) {
return '0' + x.toString();
}
return x.toString();
}
/**
* Turn a tag object into the proper CloudFormation representation
*/
function cfnTagToCloudFormation(x) {
return {
Key: x.key,
Value: x.value,
};
}
exports.cfnTagToCloudFormation = cfnTagToCloudFormation;
function listMapper(elementMapper) {
return (x) => {
if (!canInspect(x)) {
return x;
}
return x.map(elementMapper);
};
}
exports.listMapper = listMapper;
function hashMapper(elementMapper) {
return (x) => {
if (!canInspect(x)) {
return x;
}
const ret = {};
Object.keys(x).forEach((key) => {
ret[key] = elementMapper(x[key]);
});
return ret;
};
}
exports.hashMapper = hashMapper;
/**
* Return a union mapper
*
* Takes a list of validators and a list of mappers, which should correspond pairwise.
*
* The mapper of the first successful validator will be called.
*/
function unionMapper(validators, mappers) {
if (validators.length !== mappers.length) {
throw Error('Not the same amount of validators and mappers passed to unionMapper()');
}
return (x) => {
if (!canInspect(x)) {
return x;
}
for (let i = 0; i < validators.length; i++) {
if (validators[i](x).isSuccess) {
return mappers[i](x);
}
}
// Should not be possible because the union must have passed validation before this function
// will be called, but catch it anyway.
throw new TypeError('No validators matched in the union()');
};
}
exports.unionMapper = unionMapper;
// ----------------------------------------------------------------------
// VALIDATORS
//
// These are used while checking that supplied property bags match the expected schema
//
// We have a couple of datatypes that model validation errors and collections of validation
// errors (together forming a tree of errors so that we can trace validation errors through
// an object graph), and validators.
//
// Validators are simply functions that take a value and return a validation results. Then
// we have some combinators to turn primitive validators into more complex validators.
//
/**
* Representation of validation results.
*
* Models a tree of validation errors so that we have as much information as possible
* about the failure that occurred.
*/
class ValidationResult {
/**
*
*/
constructor(errorMessage = '', results = new ValidationResults()) {
this.errorMessage = errorMessage;
this.results = results;
}
/**
*
*/
get isSuccess() {
return !this.errorMessage && this.results.isSuccess;
}
/**
* Turn a failed validation into an exception.
*/
assertSuccess() {
if (!this.isSuccess) {
let message = this.errorTree();
// The first letter will be lowercase, so uppercase it for a nicer error message
message = message.substr(0, 1).toUpperCase() + message.substr(1);
throw new CfnSynthesisError(message);
}
}
/**
* Return a string rendering of the tree of validation failures.
*/
errorTree() {
const childMessages = this.results.errorTreeList();
return this.errorMessage + (childMessages.length ? `\n ${childMessages.replace(/\n/g, '\n ')}` : '');
}
/**
* Wrap this result with an error message, if it concerns an error.
*/
prefix(message) {
if (this.isSuccess) {
return this;
}
return new ValidationResult(`${message}: ${this.errorMessage}`, this.results);
}
}
exports.ValidationResult = ValidationResult;
/**
* A collection of validation results.
*/
class ValidationResults {
/**
*
*/
constructor(results = []) {
this.results = results;
}
/**
*
*/
collect(result) {
// Only collect failures
if (!result.isSuccess) {
this.results.push(result);
}
}
/**
*
*/
get isSuccess() {
return this.results.every(x => x.isSuccess);
}
/**
*
*/
errorTreeList() {
return this.results.map(child => child.errorTree()).join('\n');
}
/**
* Wrap up all validation results into a single tree node.
*
* If there are failures in the collection, add a message, otherwise
* return a success.
*/
wrap(message) {
if (this.isSuccess) {
return exports.VALIDATION_SUCCESS;
}
return new ValidationResult(message, this);
}
}
exports.ValidationResults = ValidationResults;
// Singleton object to save on allocations
exports.VALIDATION_SUCCESS = new ValidationResult();
/**
* Return whether this object can be validated at all
*
* True unless it's undefined or a CloudFormation intrinsic
*/
function canInspect(x) {
// Note: using weak equality on purpose, we also want to catch undefined
return (x != null && !isCloudFormationIntrinsic(x));
}
exports.canInspect = canInspect;
// CloudFormation validators for primitive types
function validateString(x) {
if (canInspect(x) && typeof x !== 'string') {
return new ValidationResult(`${JSON.stringify(x)} should be a string`);
}
return exports.VALIDATION_SUCCESS;
}
exports.validateString = validateString;
function validateNumber(x) {
if (canInspect(x) && typeof x !== 'number') {
return new ValidationResult(`${JSON.stringify(x)} should be a number`);
}
return exports.VALIDATION_SUCCESS;
}
exports.validateNumber = validateNumber;
function validateBoolean(x) {
if (canInspect(x) && typeof x !== 'boolean') {
return new ValidationResult(`${JSON.stringify(x)} should be a boolean`);
}
return exports.VALIDATION_SUCCESS;
}
exports.validateBoolean = validateBoolean;
function validateDate(x) {
if (canInspect(x) && !(x instanceof Date)) {
return new ValidationResult(`${JSON.stringify(x)} should be a Date`);
}
if (x !== undefined && isNaN(x.getTime())) {
return new ValidationResult('got an unparseable Date');
}
return exports.VALIDATION_SUCCESS;
}
exports.validateDate = validateDate;
function validateObject(x) {
if (canInspect(x) && typeof x !== 'object') {
return new ValidationResult(`${JSON.stringify(x)} should be an 'object'`);
}
return exports.VALIDATION_SUCCESS;
}
exports.validateObject = validateObject;
function validateCfnTag(x) {
if (!canInspect(x)) {
return exports.VALIDATION_SUCCESS;
}
if (x.key == null || x.value == null) {
return new ValidationResult(`${JSON.stringify(x)} should have a 'key' and a 'value' property`);
}
return exports.VALIDATION_SUCCESS;
}
exports.validateCfnTag = validateCfnTag;
/**
* Return a list validator based on the given element validator
*/
function listValidator(elementValidator) {
return (x) => {
if (!canInspect(x)) {
return exports.VALIDATION_SUCCESS;
}
if (!x.forEach) {
return new ValidationResult(`${JSON.stringify(x)} should be a list`);
}
for (let i = 0; i < x.length; i++) {
const element = x[i];
const result = elementValidator(element);
if (!result.isSuccess) {
return result.prefix(`element ${i}`);
}
}
return exports.VALIDATION_SUCCESS;
};
}
exports.listValidator = listValidator;
/**
* Return a hash validator based on the given element validator
*/
function hashValidator(elementValidator) {
return (x) => {
if (!canInspect(x)) {
return exports.VALIDATION_SUCCESS;
}
for (const key of Object.keys(x)) {
const result = elementValidator(x[key]);
if (!result.isSuccess) {
return result.prefix(`element '${key}'`);
}
}
return exports.VALIDATION_SUCCESS;
};
}
exports.hashValidator = hashValidator;
/**
* Decorate a validator with a message clarifying the property the failure is for.
*/
function propertyValidator(propName, validator) {
return (x) => {
return validator(x).prefix(propName);
};
}
exports.propertyValidator = propertyValidator;
/**
* Return a validator that will fail if the passed property is not present
*
* Does not distinguish between the property actually not being present, vs being present but 'null'
* or 'undefined' (courtesy of JavaScript), which is generally the behavior that we want.
*
* Empty strings are considered "present"--don't know if this agrees with how CloudFormation looks
* at the world.
*/
function requiredValidator(x) {
if (x == null) {
return new ValidationResult('required but missing');
}
return exports.VALIDATION_SUCCESS;
}
exports.requiredValidator = requiredValidator;
/**
* Require a property from a property bag.
*
* @param props the property bag from which a property is required.
* @param name the name of the required property.
* @param typeName the name of the construct type that requires the property
*
* @returns the value of ``props[name]``
*
* @throws if the property ``name`` is not present in ``props``.
*/
function requireProperty(props, name, context) {
const value = props[name];
if (value == null) {
throw new Error(`${context.toString()} is missing required property: ${name}`);
}
// Possibly add type-checking here...
return value;
}
exports.requireProperty = requireProperty;
/**
* Validates if any of the given validators matches
*
* We add either/or words to the front of the error mesages so that they read
* more nicely. Example:
*
* Properties not correct for 'FunctionProps'
* codeUri: not one of the possible types
* either: properties not correct for 'S3LocationProperty'
* bucket: required but missing
* key: required but missing
* version: required but missing
* or: '3' should be a 'string'
*
*/
function unionValidator(...validators) {
return (x) => {
const results = new ValidationResults();
let eitherOr = 'either';
for (const validator of validators) {
const result = validator(x);
if (result.isSuccess) {
return result;
}
results.collect(result.prefix(eitherOr));
eitherOr = 'or';
}
return results.wrap('not one of the possible types');
};
}
exports.unionValidator = unionValidator;
/**
* Return whether the indicated value represents a CloudFormation intrinsic.
*
* CloudFormation intrinsics are modeled as objects with a single key, which
* look like: { "Fn::GetAtt": [...] } or similar.
*/
function isCloudFormationIntrinsic(x) {
if (!(typeof x === 'object')) {
return false;
}
const keys = Object.keys(x);
if (keys.length !== 1) {
return false;
}
return keys[0] === 'Ref' || keys[0].substr(0, 4) === 'Fn::';
}
// Cannot be public because JSII gets confused about es5.d.ts
class CfnSynthesisError extends Error {
constructor() {
super(...arguments);
this.type = 'CfnSynthesisError';
}
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicnVudGltZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbInJ1bnRpbWUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBWUEsU0FBUyxRQUFRLENBQUMsQ0FBTTtJQUN0QixPQUFPLENBQUMsQ0FBQztBQUNYLENBQUM7QUFFWSxRQUFBLHNCQUFzQixHQUFXLFFBQVEsQ0FBQztBQUMxQyxRQUFBLHVCQUF1QixHQUFXLFFBQVEsQ0FBQztBQUMzQyxRQUFBLHNCQUFzQixHQUFXLFFBQVEsQ0FBQztBQUMxQyxRQUFBLHNCQUFzQixHQUFXLFFBQVEsQ0FBQztBQUV2RDs7Ozs7O0dBTUc7QUFDSCxTQUFnQixvQkFBb0IsQ0FBQyxDQUFRO0lBQzNDLElBQUksQ0FBQyxDQUFDLEVBQUU7UUFDTixPQUFPLFNBQVMsQ0FBQztLQUNsQjtJQUVELG1DQUFtQztJQUNuQyxPQUFPLEdBQUcsQ0FBQyxDQUFDLGNBQWMsRUFBRSxJQUFJLEdBQUcsQ0FBQyxDQUFDLENBQUMsV0FBVyxFQUFFLEdBQUcsQ0FBQyxDQUFDLElBQUksR0FBRyxDQUFDLENBQUMsQ0FBQyxVQUFVLEVBQUUsQ0FBQyxJQUFJLEdBQUcsQ0FBQyxDQUFDLENBQUMsV0FBVyxFQUFFLENBQUMsSUFBSSxHQUFHLENBQUMsQ0FBQyxDQUFDLGFBQWEsRUFBRSxDQUFDLElBQUksR0FBRyxDQUFDLENBQUMsQ0FBQyxhQUFhLEVBQUUsQ0FBQyxFQUFFLENBQUM7QUFDaEssQ0FBQztBQVBELG9EQU9DO0FBRUQ7O0dBRUc7QUFDSCxTQUFTLEdBQUcsQ0FBQyxDQUFTO0lBQ3BCLElBQUksQ0FBQyxHQUFHLEVBQUUsRUFBRTtRQUNWLE9BQU8sR0FBRyxHQUFHLENBQUMsQ0FBQyxRQUFRLEVBQUUsQ0FBQztLQUMzQjtJQUNELE9BQU8sQ0FBQyxDQUFDLFFBQVEsRUFBRSxDQUFDO0FBQ3RCLENBQUM7QUFFRDs7R0FFRztBQUNILFNBQWdCLHNCQUFzQixDQUFDLENBQU07SUFDM0MsT0FBTztRQUNMLEdBQUcsRUFB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U0FBUSxLQUFLO0lBQXJDOztRQUNrQixTQUFJLEdBQUcsbUJBQW1CLENBQUM7SUFDN0MsQ0FBQztDQUFBIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgQ29uc3RydWN0IH0gZnJvbSAnLi9jb25zdHJ1Y3QtY29tcGF0JztcblxuLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuLy8gUFJPUEVSVFkgTUFQUEVSU1xuLy9cbi8vIFRoZXNlIGFyZSB1c2VkIHdoaWxlIGNvbnZlcnRpbmcgZ2VuZXJhdGVkIGNsYXNzZXMvcHJvcGVydHkgYmFncyB0byBDbG91ZEZvcm1hdGlvbiBwcm9wZXJ0eSBvYmplY3RzXG4vL1xuLy8gV2UgdXNlIGlkZW50aXR5IG1hcHBlcnMgZm9yIHRoZSBwcmltaXRpdmUgdHlwZXMuIFRoZXNlIGRvbid0IGRvIGFueXRoaW5nIGJ1dCBhcmUgdGhlcmUgdG8gbWFrZSB0aGUgY29kZVxuLy8gZ2VuZXJhdGlvbiB3b3JrIG91dCBuaWNlbHkgKHNvIHRoZSBjb2RlIGdlbmVyYXRvciBkb2Vzbid0IG5lZWQgdG8gZW1pdCBkaWZmZXJlbnQgY29kZSBmb3IgcHJpbWl0aXZlXG4vLyB2cy4gY29tcGxleCB0eXBlcykuXG5leHBvcnQgdHlwZSBNYXBwZXIgPSAoeDogYW55KSA9PiBhbnk7XG5cbmZ1bmN0aW9uIGlkZW50aXR5KHg6IGFueSkge1xuICByZXR1cm4geDtcbn1cblxuZXhwb3J0IGNvbnN0IHN0cmluZ1RvQ2xvdWRGb3JtYXRpb246IE1hcHBlciA9IGlkZW50aXR5O1xuZXhwb3J0IGNvbnN0IGJvb2xlYW5Ub0Nsb3VkRm9ybWF0aW9uOiBNYXBwZXIgPSBpZGVudGl0eTtcbmV4cG9ydCBjb25zdCBvYmplY3RUb0Nsb3VkRm9ybWF0aW9uOiBNYXBwZXIgPSBpZGVudGl0eTtcbmV4cG9ydCBjb25zdCBudW1iZXJUb0Nsb3VkRm9ybWF0aW9uOiBNYXBwZXIgPSBpZGVudGl0eTtcblxuLyoqXG4gKiBUaGUgZGF0ZSBuZWVkcyB0byBiZSBmb3JtYXR0ZWQgYXMgYW4gSVNPIGRhdGUgaW4gVVRDXG4gKlxuICogU29tZSB1c2FnZSBzaXRlcyByZXF1aXJlIGEgZGF0ZSwgc29tZSByZXF1aXJlIGEgdGltZXN0YW1wLiBXZSdsbFxuICogYWx3YXlzIG91dHB1dCBhIHRpbWVzdGFtcCBhbmQgaG9wZSB0aGUgcGFyc2VyIG9uIHRoZSBvdGhlciBlbmRcbiAqIGlzIHNtYXJ0IGVub3VnaCB0byBpZ25vcmUgdGhlIHRpbWUgcGFydC4uLiAoPylcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGRhdGVUb0Nsb3VkRm9ybWF0aW9uKHg/OiBEYXRlKTogYW55IHtcbiAgaWYgKCF4KSB7XG4gICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgfVxuXG4gIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBtYXgtbGVuXG4gIHJldHVybiBgJHt4LmdldFVUQ0Z1bGxZZWFyKCl9LSR7cGFkKHguZ2V0VVRDTW9udGgoKSArIDEpfS0ke3BhZCh4LmdldFVUQ0RhdGUoKSl9VCR7cGFkKHguZ2V0VVRDSG91cnMoKSl9OiR7cGFkKHguZ2V0VVRDTWludXRlcygpKX06JHtwYWQoeC5nZXRVVENTZWNvbmRzKCkpfWA7XG59XG5cbi8qKlxuICogUGFkIGEgbnVtYmVyIHRvIDIgZGVjaW1hbCBwbGFjZXNcbiAqL1xuZnVuY3Rpb24gcGFkKHg6IG51bWJlcikge1xuICBpZiAoeCA8IDEwKSB7XG4gICAgcmV0dXJuICcwJyArIHgudG9TdHJpbmcoKTtcbiAgfVxuICByZXR1cm4geC50b1N0cmluZygpO1xufVxuXG4vKipcbiAqIFR1cm4gYSB0YWcgb2JqZWN0IGludG8gdGhlIHByb3BlciBDbG91ZEZvcm1hdGlvbiByZXByZXNlbnRhdGlvblxuICovXG5leHBvcnQgZnVuY3Rpb24gY2ZuVGFnVG9DbG91ZEZvcm1hdGlvbih4OiBhbnkpOiBhbnkge1xuICByZXR1cm4ge1xuICAgIEtleTogeC5rZXksXG4gICAgVmFsdWU6IHgudmFsdWUsXG4gIH07XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBsaXN0TWFwcGVyKGVsZW1lbnRNYXBwZXI6IE1hcHBlcik6IE1hcHBlciB7XG4gIHJldHVybiAoeDogYW55KSA9PiB7XG4gICAgaWYgKCFjYW5JbnNwZWN0KHgpKSB7IHJldHVybiB4OyB9XG4gICAgcmV0dXJuIHgubWFwKGVsZW1lbnRNYXBwZXIpO1xuICB9O1xufVxuXG5leHBvcnQgZnVuY3Rpb24gaGFzaE1hcHBlcihlbGVtZW50TWFwcGVyOiBNYXBwZXIpOiBNYXBwZXIge1xuICByZXR1cm4gKHg6IGFueSkgPT4ge1xuICAgIGlmICghY2FuSW5zcGVjdCh4KSkgeyByZXR1cm4geDsgfVxuXG4gICAgY29uc3QgcmV0OiBhbnkgPSB7fTtcblxuICAgIE9iamVjdC5rZXlzKHgpLmZvckVhY2goKGtleSkgPT4ge1xuICAgICAgcmV0W2tleV0gPSBlbGVtZW50TWFwcGVyKHhba2V5XSk7XG4gICAgfSk7XG5cbiAgICByZXR1cm4gcmV0O1xuICB9O1xufVxuXG4vKipcbiAqIFJldHVybiBhIHVuaW9uIG1hcHBlclxuICpcbiAqIFRha2VzIGEgbGlzdCBvZiB2YWxpZGF0b3JzIGFuZCBhIGxpc3Qgb2YgbWFwcGVycywgd2hpY2ggc2hvdWxkIGNvcnJlc3BvbmQgcGFpcndpc2UuXG4gKlxuICogVGhlIG1hcHBlciBvZiB0aGUgZmlyc3Qgc3VjY2Vzc2Z1bCB2YWxpZGF0b3Igd2lsbCBiZSBjYWxsZWQuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiB1bmlvbk1hcHBlcih2YWxpZGF0b3JzOiBWYWxpZGF0b3JbXSwgbWFwcGVyczogTWFwcGVyW10pOiBNYXBwZXIge1xuICBpZiAodmFsaWRhdG9ycy5sZW5ndGggIT09IG1hcHBlcnMubGVuZ3RoKSB7XG4gICAgdGhyb3cgRXJyb3IoJ05vdCB0aGUgc2FtZSBhbW91bnQgb2YgdmFsaWRhdG9ycyBhbmQgbWFwcGVycyBwYXNzZWQgdG8gdW5pb25NYXBwZXIoKScpO1xuICB9XG5cbiAgcmV0dXJuICh4OiBhbnkpID0+IHtcbiAgICBpZiAoIWNhbkluc3BlY3QoeCkpIHsgcmV0dXJuIHg7IH1cblxuICAgIGZvciAobGV0IGkgPSAwOyBpIDwgdmFsaWRhdG9ycy5sZW5ndGg7IGkrKykge1xuICAgICAgaWYgKHZhbGlkYXRvcnNbaV0oeCkuaXNTdWNjZXNzKSB7XG4gICAgICAgIHJldHVybiBtYXBwZXJzW2ldKHgpO1xuICAgICAgfVxuICAgIH1cblxuICAgIC8vIFNob3VsZCBub3QgYmUgcG9zc2libGUgYmVjYXVzZSB0aGUgdW5pb24gbXVzdCBoYXZlIHBhc3NlZCB2YWxpZGF0aW9uIGJlZm9yZSB0aGlzIGZ1bmN0aW9uXG4gICAgLy8gd2lsbCBiZSBjYWxsZWQsIGJ1dCBjYXRjaCBpdCBhbnl3YXkuXG4gICAgdGhyb3cgbmV3IFR5cGVFcnJvcignTm8gdmFsaWRhdG9ycyBtYXRjaGVkIGluIHRoZSB1bmlvbigpJyk7XG4gIH07XG59XG5cbi8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbi8vIFZBTElEQVRPUlNcbi8vXG4vLyBUaGVzZSBhcmUgdXNlZCB3aGlsZSBjaGVja2luZyB0aGF0IHN1cHBsaWVkIHByb3BlcnR5IGJhZ3MgbWF0Y2ggdGhlIGV4cGVjdGVkIHNjaGVtYVxuLy9cbi8vIFdlIGhhdmUgYSBjb3VwbGUgb2YgZGF0YXR5cGVzIHRoYXQgbW9kZWwgdmFsaWRhdGlvbiBlcnJvcnMgYW5kIGNvbGxlY3Rpb25zIG9mIHZhbGlkYXRpb25cbi8vIGVycm9ycyAodG9nZXRoZXIgZm9ybWluZyBhIHRyZWUgb2YgZXJyb3JzIHNvIHRoYXQgd2UgY2FuIHRyYWNlIHZhbGlkYXRpb24gZXJyb3JzIHRocm91Z2hcbi8vIGFuIG9iamVjdCBncmFwaCksIGFuZCB2YWxpZGF0b3JzLlxuLy9cbi8vIFZhbGlkYXRvcnMgYXJlIHNpbXBseSBmdW5jdGlvbnMgdGhhdCB0YWtlIGEgdmFsdWUgYW5kIHJldHVybiBhIHZhbGlkYXRpb24gcmVzdWx0cy4gVGhlblxuLy8gd2UgaGF2ZSBzb21lIGNvbWJpbmF0b3JzIHRvIHR1cm4gcHJpbWl0aXZlIHZhbGlkYXRvcnMgaW50byBtb3JlIGNvbXBsZXggdmFsaWRhdG9ycy5cbi8vXG5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcbmV4cG9ydCBjbGFzcyBWYWxpZGF0aW9uUmVzdWx0IHtcbiAgY29uc3RydWN0b3IocmVhZG9ubHkgZXJyb3JNZXNzYWdlOiBzdHJpbmcgPSAnJywgcmVhZG9ubHkgcmVzdWx0czogVmFsaWRhdGlvblJlc3VsdHMgPSBuZXcgVmFsaWRhdGlvblJlc3VsdHMoKSkge1xuICB9XG5cbiAgcHVibGljIGdldCBpc1N1Y2Nlc3MoKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuICF0aGlzLmVycm9yTWVzc2FnZSAmJiB0aGlzLnJlc3VsdHMuaXNTdWNjZXNzO1xuICB9XG5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXG4gIHB1YmxpYyBhc3NlcnRTdWNjZXNzKCkge1xuICAgIGlmICghdGhpcy5pc1N1Y2Nlc3MpIHtcbiAgICAgIGxldCBtZXNzYWdlID0gdGhpcy5lcnJvclRyZWUoKTtcbiAgICAgIC8vIFRoZSBmaXJzdCBsZXR0ZXIgd2lsbCBiZSBsb3dlcmNhc2UsIHNvIHVwcGVyY2FzZSBpdCBmb3IgYSBuaWNlciBlcnJvciBtZXNzYWdlXG4gICAgICBtZXNzYWdlID0gbWVzc2FnZS5zdWJzdHIoMCwgMSkudG9VcHBlckNhc2UoKSArIG1lc3NhZ2Uuc3Vic3RyKDEpO1xuICAgICAgdGhyb3cgbmV3IENmblN5bnRoZXNpc0Vycm9yKG1lc3NhZ2UpO1xuICAgIH1cbiAgfVxuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFxuICBwdWJsaWMgZXJyb3JUcmVlKCk6IHN0cmluZyB7XG4gICAgY29uc3QgY2hpbGRNZXNzYWdlcyA9IHRoaXMucmVzdWx0cy5lcnJvclRyZWVMaXN0KCk7XG4gICAgcmV0dXJuIHRoaXMuZXJyb3JNZXNzYWdlICsgKGNoaWxkTWVzc2FnZXMubGVuZ3RoID8gYFxcbiAgJHtjaGlsZE1lc3NhZ2VzLnJlcGxhY2UoL1xcbi9nLCAnXFxuICAnKX1gIDogJycpO1xuICB9XG5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXG4gIHB1YmxpYyBwcmVmaXgobWVzc2FnZTogc3RyaW5nKTogVmFsaWRhdGlvblJlc3VsdCB7XG4gICAgaWYgKHRoaXMuaXNTdWNjZXNzKSB7IHJldHVybiB0aGlzOyB9XG4gICAgcmV0dXJuIG5ldyBWYWxpZGF0aW9uUmVzdWx0KGAke21lc3NhZ2V9OiAke3RoaXMuZXJyb3JNZXNzYWdlfWAsIHRoaXMucmVzdWx0cyk7XG4gIH1cbn1cblxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXG5leHBvcnQgY2xhc3MgVmFsaWRhdGlvblJlc3VsdHMge1xuICBjb25zdHJ1Y3RvcihwdWJsaWMgcmVzdWx0czogVmFsaWRhdGlvblJlc3VsdFtdID0gW10pIHtcbiAgfVxuXG4gIHB1YmxpYyBjb2xsZWN0KHJlc3VsdDogVmFsaWRhdGlvblJlc3VsdCkge1xuICAgIC8vIE9ubHkgY29sbGVjdCBmYWlsdXJlc1xuICAgIGlmICghcmVzdWx0LmlzU3VjY2Vzcykge1xuICAgICAgdGhpcy5yZXN1bHRzLnB1c2gocmVzdWx0KTtcbiAgICB9XG4gIH1cblxuICBwdWJsaWMgZ2V0IGlzU3VjY2VzcygpOiBib29sZWFuIHtcbiAgICByZXR1cm4gdGhpcy5yZXN1bHRzLmV2ZXJ5KHggPT4geC5pc1N1Y2Nlc3MpO1xuICB9XG5cbiAgcHVibGljIGVycm9yVHJlZUxpc3QoKTogc3RyaW5nIHtcbiAgICByZXR1cm4gdGhpcy5yZXN1bHRzLm1hcChjaGlsZCA9PiBjaGlsZC5lcnJvclRyZWUoKSkuam9pbignXFxuJyk7XG4gIH1cblxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcbiAgcHVibGljIHdyYXAobWVzc2FnZTogc3RyaW5nKTogVmFsaWRhdGlvblJlc3VsdCB7XG4gICAgaWYgKHRoaXMuaXNTdWNjZXNzKSB7wqByZXR1cm4gVkFMSURBVElPTl9TVUNDRVNTOyB9XG4gICAgcmV0dXJuIG5ldyBWYWxpZGF0aW9uUmVzdWx0KG1lc3NhZ2UsIHRoaXMpO1xuICB9XG59XG5cbi8vIFNpbmdsZXRvbiBvYmplY3QgdG8gc2F2ZSBvbiBhbGxvY2F0aW9uc1xuZXhwb3J0IGNvbnN0IFZBTElEQVRJT05fU1VDQ0VTUyA9IG5ldyBWYWxpZGF0aW9uUmVzdWx0KCk7XG5cbmV4cG9ydCB0eXBlIFZhbGlkYXRvciA9ICh4OiBhbnkpID0+IFZhbGlkYXRpb25SZXN1bHQ7XG5cbi8qKlxuICogUmV0dXJuIHdoZXRoZXIgdGhpcyBvYmplY3QgY2FuIGJlIHZhbGlkYXRlZCBhdCBhbGxcbiAqXG4gKiBUcnVlIHVubGVzcyBpdCdzIHVuZGVmaW5lZCBvciBhIENsb3VkRm9ybWF0aW9uIGludHJpbnNpY1xuICovXG5leHBvcnQgZnVuY3Rpb24gY2FuSW5zcGVjdCh4OiBhbnkpIHtcbiAgLy8gTm90ZTogdXNpbmcgd2VhayBlcXVhbGl0eSBvbiBwdXJwb3NlLCB3ZSBhbHNvIHdhbnQgdG8gY2F0Y2ggdW5kZWZpbmVkXG4gIHJldHVybiAoeCAhPSBudWxsICYmICFpc0Nsb3VkRm9ybWF0aW9uSW50cmluc2ljKHgpKTtcbn1cblxuLy8gQ2xvdWRGb3JtYXRpb24gdmFsaWRhdG9ycyBmb3IgcHJpbWl0aXZlIHR5cGVzXG5leHBvcnQgZnVuY3Rpb24gdmFsaWRhdGVTdHJpbmcoeDogYW55KTogVmFsaWRhdGlvblJlc3VsdCB7XG4gIGlmIChjYW5JbnNwZWN0KHgpICYmIHR5cGVvZiB4ICE9PSAnc3RyaW5nJykge1xuICAgIHJldHVybiBuZXcgVmFsaWRhdGlvblJlc3VsdChgJHtKU09OLnN0cmluZ2lmeSh4KX0gc2hvdWxkIGJlIGEgc3RyaW5nYCk7XG4gIH1cbiAgcmV0dXJuIFZBTElEQVRJT05fU1VDQ0VTUztcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIHZhbGlkYXRlTnVtYmVyKHg6IGFueSk6IFZhbGlkYXRpb25SZXN1bHQge1xuICBpZiAoY2FuSW5zcGVjdCh4KSAmJiB0eXBlb2YgeCAhPT0gJ251bWJlcicpIHtcbiAgICByZXR1cm4gbmV3IFZhbGlkYXRpb25SZXN1bHQoYCR7SlNPTi5zdHJpbmdpZnkoeCl9IHNob3VsZCBiZSBhIG51bWJlcmApO1xuICB9XG4gIHJldHVybiBWQUxJREFUSU9OX1NVQ0NFU1M7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiB2YWxpZGF0ZUJvb2xlYW4oeDogYW55KTogVmFsaWRhdGlvblJlc3VsdCB7XG4gIGlmIChjYW5JbnNwZWN0KHgpICYmIHR5cGVvZiB4ICE9PSAnYm9vbGVhbicpIHtcbiAgICByZXR1cm4gbmV3IFZhbGlkYXRpb25SZXN1bHQoYCR7SlNPTi5zdHJpbmdpZnkoeCl9IHNob3VsZCBiZSBhIGJvb2xlYW5gKTtcbiAgfVxuICByZXR1cm4gVkFMSURBVElPTl9TVUNDRVNTO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gdmFsaWRhdGVEYXRlKHg6IGFueSk6IFZhbGlkYXRpb25SZXN1bHQge1xuICBpZiAoY2FuSW5zcGVjdCh4KSAmJiAhKHggaW5zdGFuY2VvZiBEYXRlKSkge1xuICAgIHJldHVybiBuZXcgVmFsaWRhdGlvblJlc3VsdChgJHtKU09OLnN0cmluZ2lmeSh4KX0gc2hvdWxkIGJlIGEgRGF0ZWApO1xuICB9XG5cbiAgaWYgKHggIT09IHVuZGVmaW5lZCAmJiBpc05hTih4LmdldFRpbWUoKSkpIHtcbiAgICByZXR1cm4gbmV3IFZhbGlkYXRpb25SZXN1bHQoJ2dvdCBhbiB1bnBhcnNlYWJsZSBEYXRlJyk7XG4gIH1cblxuICByZXR1cm4gVkFMSURBVElPTl9TVUNDRVNTO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gdmFsaWRhdGVPYmplY3QoeDogYW55KTogVmFsaWRhdGlvblJlc3VsdCB7XG4gIGlmIChjYW5JbnNwZWN0KHgpICYmIHR5cGVvZiB4ICE9PSAnb2JqZWN0Jykge1xuICAgIHJldHVybiBuZXcgVmFsaWRhdGlvblJlc3VsdChgJHtKU09OLnN0cmluZ2lmeSh4KX0gc2hvdWxkIGJlIGFuICdvYmplY3QnYCk7XG4gIH1cbiAgcmV0dXJuIFZBTElEQVRJT05fU1VDQ0VTUztcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIHZhbGlkYXRlQ2ZuVGFnKHg6IGFueSk6IFZhbGlkYXRpb25SZXN1bHQge1xuICBpZiAoIWNhbkluc3BlY3QoeCkpIHsgcmV0dXJuIFZBTElEQVRJT05fU1VDQ0VTUzsgfVxuXG4gIGlmICh4LmtleSA9PSBudWxsIHx8IHgudmFsdWUgPT0gbnVsbCkge1xuICAgIHJldHVybiBuZXcgVmFsaWRhdGlvblJlc3VsdChgJHtKU09OLnN0cmluZ2lmeSh4KX0gc2hvdWxkIGhhdmUgYSAna2V5JyBhbmQgYSAndmFsdWUnIHByb3BlcnR5YCk7XG4gIH1cblxuICByZXR1cm4gVkFMSURBVElPTl9TVUNDRVNTO1xufVxuXG4vKipcbiAqIFJldHVybiBhIGxpc3QgdmFsaWRhdG9yIGJhc2VkIG9uIHRoZSBnaXZlbiBlbGVtZW50IHZhbGlkYXRvclxuICovXG5leHBvcnQgZnVuY3Rpb24gbGlzdFZhbGlkYXRvcihlbGVtZW50VmFsaWRhdG9yOiBWYWxpZGF0b3IpOiBWYWxpZGF0b3Ige1xuICByZXR1cm4gKHg6IGFueSkgPT4ge1xuICAgIGlmICghY2FuSW5zcGVjdCh4KSkgeyByZXR1cm4gVkFMSURBVElPTl9TVUNDRVNTOyB9XG5cbiAgICBpZiAoIXguZm9yRWFjaCkge1xuICAgICAgcmV0dXJuIG5ldyBWYWxpZGF0aW9uUmVzdWx0KGAke0pTT04uc3RyaW5naWZ5KHgpfSBzaG91bGQgYmUgYSBsaXN0YCk7XG4gICAgfVxuXG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCB4Lmxlbmd0aDsgaSsrKSB7XG4gICAgICBjb25zdCBlbGVtZW50ID0geFtpXTtcbiAgICAgIGNvbnN0IHJlc3VsdCA9IGVsZW1lbnRWYWxpZGF0b3IoZWxlbWVudCk7XG4gICAgICBpZiAoIXJlc3VsdC5pc1N1Y2Nlc3MpIHsgcmV0dXJuIHJlc3VsdC5wcmVmaXgoYGVsZW1lbnQgJHtpfWApOyB9XG4gICAgfVxuXG4gICAgcmV0dXJuIFZBTElEQVRJT05fU1VDQ0VTUztcbiAgfTtcbn1cblxuLyoqXG4gKiBSZXR1cm4gYSBoYXNoIHZhbGlkYXRvciBiYXNlZCBvbiB0aGUgZ2l2ZW4gZWxlbWVudCB2YWxpZGF0b3JcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGhhc2hWYWxpZGF0b3IoZWxlbWVudFZhbGlkYXRvcjogVmFsaWRhdG9yKTogVmFsaWRhdG9yIHtcbiAgcmV0dXJuICh4OiBhbnkpID0+IHtcbiAgICBpZiAoIWNhbkluc3BlY3QoeCkpIHsgcmV0dXJuIFZBTElEQVRJT05fU1VDQ0VTUzsgfVxuXG4gICAgZm9yIChjb25zdCBrZXkgb2YgT2JqZWN0LmtleXMoeCkpIHtcbiAgICAgIGNvbnN0IHJlc3VsdCA9IGVsZW1lbnRWYWxpZGF0b3IoeFtrZXldKTtcbiAgICAgIGlmICghcmVzdWx0LmlzU3VjY2VzcykgeyByZXR1cm4gcmVzdWx0LnByZWZpeChgZWxlbWVudCAnJHtrZXl9J2ApOyB9XG4gICAgfVxuXG4gICAgcmV0dXJuIFZBTElEQVRJT05fU1VDQ0VTUztcbiAgfTtcbn1cblxuLyoqXG4gKiBEZWNvcmF0ZSBhIHZhbGlkYXRvciB3aXRoIGEgbWVzc2FnZSBjbGFyaWZ5aW5nIHRoZSBwcm9wZXJ0eSB0aGUgZmFpbHVyZSBpcyBmb3IuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBwcm9wZXJ0eVZhbGlkYXRvcihwcm9wTmFtZTogc3RyaW5nLCB2YWxpZGF0b3I6IFZhbGlkYXRvcik6IFZhbGlkYXRvciB7XG4gIHJldHVybiAoeDogYW55KSA9PiB7XG4gICAgcmV0dXJuIHZhbGlkYXRvcih4KS5wcmVmaXgocHJvcE5hbWUpO1xuICB9O1xufVxuXG4vKipcbiAqIFJldHVybiBhIHZhbGlkYXRvciB0aGF0IHdpbGwgZmFpbCBpZiB0aGUgcGFzc2VkIHByb3BlcnR5IGlzIG5vdCBwcmVzZW50XG4gKlxuICogRG9lcyBub3QgZGlzdGluZ3Vpc2ggYmV0d2VlbiB0aGUgcHJvcGVydHkgYWN0dWFsbHkgbm90IGJlaW5nIHByZXNlbnQsIHZzIGJlaW5nIHByZXNlbnQgYnV0ICdudWxsJ1xuICogb3IgJ3VuZGVmaW5lZCcgKGNvdXJ0ZXN5IG9mIEphdmFTY3JpcHQpLCB3aGljaCBpcyBnZW5lcmFsbHkgdGhlIGJlaGF2aW9yIHRoYXQgd2Ugd2FudC5cbiAqXG4gKiBFbXB0eSBzdHJpbmdzIGFyZSBjb25zaWRlcmVkIFwicHJlc2VudFwiLS1kb24ndCBrbm93IGlmIHRoaXMgYWdyZWVzIHdpdGggaG93IENsb3VkRm9ybWF0aW9uIGxvb2tzXG4gKiBhdCB0aGUgd29ybGQuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiByZXF1aXJlZFZhbGlkYXRvcih4OiBhbnkpIHtcbiAgaWYgKHggPT0gbnVsbCkge1xuICAgIHJldHVybiBuZXcgVmFsaWRhdGlvblJlc3VsdCgncmVxdWlyZWQgYnV0IG1pc3NpbmcnKTtcbiAgfVxuICByZXR1cm4gVkFMSURBVElPTl9TVUNDRVNTO1xufVxuXG4vKipcbiAqIFJlcXVpcmUgYSBwcm9wZXJ0eSBmcm9tIGEgcHJvcGVydHkgYmFnLlxuICpcbiAqIEBwYXJhbSBwcm9wcyAgdGhlIHByb3BlcnR5IGJhZyBmcm9tIHdoaWNoIGEgcHJvcGVydHkgaXMgcmVxdWlyZWQuXG4gKiBAcGFyYW0gbmFtZSAgIHRoZSBuYW1lIG9mIHRoZSByZXF1aXJlZCBwcm9wZXJ0eS5cbiAqIEBwYXJhbSB0eXBlTmFtZSB0aGUgbmFtZSBvZiB0aGUgY29uc3RydWN0IHR5cGUgdGhhdCByZXF1aXJlcyB0aGUgcHJvcGVydHlcbiAqXG4gKiBAcmV0dXJucyB0aGUgdmFsdWUgb2YgYGBwcm9wc1tuYW1lXWBgXG4gKlxuICogQHRocm93cyBpZiB0aGUgcHJvcGVydHkgYGBuYW1lYGAgaXMgbm90IHByZXNlbnQgaW4gYGBwcm9wc2BgLlxuICovXG5leHBvcnQgZnVuY3Rpb24gcmVxdWlyZVByb3BlcnR5KHByb3BzOiB7IFtuYW1lOiBzdHJpbmddOiBhbnkgfSwgbmFtZTogc3RyaW5nLCBjb250ZXh0OiBDb25zdHJ1Y3QpOiBhbnkge1xuICBjb25zdCB2YWx1ZSA9IHByb3BzW25hbWVdO1xuICBpZiAodmFsdWUgPT0gbnVsbCkge1xuICAgIHRocm93IG5ldyBFcnJvcihgJHtjb250ZXh0LnRvU3RyaW5nKCl9IGlzIG1pc3NpbmcgcmVxdWlyZWQgcHJvcGVydHk6ICR7bmFtZX1gKTtcbiAgfVxuICAvLyBQb3NzaWJseSBhZGQgdHlwZS1jaGVja2luZyBoZXJlLi4uXG4gIHJldHVybiB2YWx1ZTtcbn1cblxuLyoqXG4gKiBWYWxpZGF0ZXMgaWYgYW55IG9mIHRoZSBnaXZlbiB2YWxpZGF0b3JzIG1hdGNoZXNcbiAqXG4gKiBXZSBhZGQgZWl0aGVyL29yIHdvcmRzIHRvIHRoZSBmcm9udCBvZiB0aGUgZXJyb3IgbWVzYWdlcyBzbyB0aGF0IHRoZXkgcmVhZFxuICogbW9yZSBuaWNlbHkuIEV4YW1wbGU6XG4gKlxuICogICBQcm9wZXJ0aWVzIG5vdCBjb3JyZWN0IGZvciAnRnVuY3Rpb25Qcm9wcydcbiAqICAgICBjb2RlVXJpOiBub3Qgb25lIG9mIHRoZSBwb3NzaWJsZSB0eXBlc1xuICogICAgICAgZWl0aGVyOiBwcm9wZXJ0aWVzIG5vdCBjb3JyZWN0IGZvciAnUzNMb2NhdGlvblByb3BlcnR5J1xuICogICAgICAgICBidWNrZXQ6IHJlcXVpcmVkIGJ1dCBtaXNzaW5nXG4gKiAgICAgICAgIGtleTogcmVxdWlyZWQgYnV0IG1pc3NpbmdcbiAqICAgICAgICAgdmVyc2lvbjogcmVxdWlyZWQgYnV0IG1pc3NpbmdcbiAqICAgICAgIG9yOiAnMycgc2hvdWxkIGJlIGEgJ3N0cmluZydcbiAqXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiB1bmlvblZhbGlkYXRvciguLi52YWxpZGF0b3JzOiBWYWxpZGF0b3JbXSk6IFZhbGlkYXRvciB7XG4gIHJldHVybiAoeDogYW55KSA9PiB7XG4gICAgY29uc3QgcmVzdWx0cyA9IG5ldyBWYWxpZGF0aW9uUmVzdWx0cygpO1xuICAgIGxldCBlaXRoZXJPciA9ICdlaXRoZXInO1xuXG4gICAgZm9yIChjb25zdCB2YWxpZGF0b3Igb2YgdmFsaWRhdG9ycykge1xuICAgICAgY29uc3QgcmVzdWx0ID0gdmFsaWRhdG9yKHgpO1xuICAgICAgaWYgKHJlc3VsdC5pc1N1Y2Nlc3MpIHsgcmV0dXJuIHJlc3VsdDsgfVxuICAgICAgcmVzdWx0cy5jb2xsZWN0KHJlc3VsdC5wcmVmaXgoZWl0aGVyT3IpKTtcbiAgICAgIGVpdGhlck9yID0gJ29yJztcbiAgICB9XG4gICAgcmV0dXJuIHJlc3VsdHMud3JhcCgnbm90IG9uZSBvZiB0aGUgcG9zc2libGUgdHlwZXMnKTtcbiAgfTtcbn1cblxuLyoqXG4gKiBSZXR1cm4gd2hldGhlciB0aGUgaW5kaWNhdGVkIHZhbHVlIHJlcHJlc2VudHMgYSBDbG91ZEZvcm1hdGlvbiBpbnRyaW5zaWMuXG4gKlxuICogQ2xvdWRGb3JtYXRpb24gaW50cmluc2ljcyBhcmUgbW9kZWxlZCBhcyBvYmplY3RzIHdpdGggYSBzaW5nbGUga2V5LCB3aGljaFxuICogbG9vayBsaWtlOiB7IFwiRm46OkdldEF0dFwiOiBbLi4uXSB9IG9yIHNpbWlsYXIuXG4gKi9cbmZ1bmN0aW9uIGlzQ2xvdWRGb3JtYXRpb25JbnRyaW5zaWMoeDogYW55KSB7XG4gIGlmICghKHR5cGVvZiB4ID09PSAnb2JqZWN0JykpIHsgcmV0dXJuIGZhbHNlOyB9XG4gIGNvbnN0IGtleXMgPSBPYmplY3Qua2V5cyh4KTtcbiAgaWYgKGtleXMubGVuZ3RoICE9PSAxKSB7IHJldHVybiBmYWxzZTsgfVxuXG4gIHJldHVybiBrZXlzWzBdID09PSAnUmVmJyB8fCBrZXlzWzBdLnN1YnN0cigwLCA0KSA9PT0gJ0ZuOjonO1xufVxuXG4vLyBDYW5ub3QgYmUgcHVibGljIGJlY2F1c2UgSlNJSSBnZXRzIGNvbmZ1c2VkIGFib3V0IGVzNS5kLnRzXG5jbGFzcyBDZm5TeW50aGVzaXNFcnJvciBleHRlbmRzIEVycm9yIHtcbiAgcHVibGljIHJlYWRvbmx5IHR5cGUgPSAnQ2ZuU3ludGhlc2lzRXJyb3InO1xufVxuIl19