UNPKG

@aws-cdk/core

Version:

AWS Cloud Development Kit Core Library

380 lines 39.2 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); 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; } // tslint:disable-next-line:max-line-length 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) { if (!(name in props)) { throw new Error(`${context.toString()} is missing required property: ${name}`); } const value = props[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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicnVudGltZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbInJ1bnRpbWUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUFZQSxTQUFTLFFBQVEsQ0FBQyxDQUFNO0lBQ3RCLE9BQU8sQ0FBQyxDQUFDO0FBQ1gsQ0FBQztBQUVZLFFBQUEsc0JBQXNCLEdBQVcsUUFBUSxDQUFDO0FBQzFDLFFBQUEsdUJBQXVCLEdBQVcsUUFBUSxDQUFDO0FBQzNDLFFBQUEsc0JBQXNCLEdBQVcsUUFBUSxDQUFDO0FBQzFDLFFBQUEsc0JBQXNCLEdBQVcsUUFBUSxDQUFDO0FBRXZEOzs7Ozs7R0FNRztBQUNILFNBQWdCLG9CQUFvQixDQUFDLENBQVE7SUFDM0MsSUFBSSxDQUFDLENBQUMsRUFBRTtRQUNOLE9BQU8sU0FBUyxDQUFDO0tBQ2xCO0lBRUQsMkNBQTJDO0lBQzNDLE9BQU8sR0FBRyxDQUFDLENBQUMsY0FBYyxFQUFFLElBQUksR0FBRyxDQUFDLENBQUMsQ0FBQyxXQUFXLEVBQUUsR0FBRyxDQUFDLENBQUMsSUFBSSxHQUFHLENBQUMsQ0FBQyxDQUFDLFVBQVUsRUFBRSxDQUFDLElBQUksR0FBRyxDQUFDLENBQUMsQ0FBQyxXQUFXLEVBQUUsQ0FBQyxJQUFJLEdBQUcsQ0FBQyxDQUFDLENBQUMsYUFBYSxFQUFFLENBQUMsSUFBSSxHQUFHLENBQUMsQ0FBQyxDQUFDLGFBQWEsRUFBRSxDQUFDLEVBQUUsQ0FBQztBQUNoSyxDQUFDO0FBUEQsb0RBT0M7QUFFRDs7R0FFRztBQUNILFNBQVMsR0FBRyxDQUFDLENBQVM7SUFDcEIsSUFBSSxDQUFDLEdBQUcsRUFBRSxFQUFFO1FBQ1YsT0FBTyxHQUFHLEdBQUcsQ0FBQyxDQUFDLFFBQVEsRUFBRSxDQUFDO0tBQzNCO0lBQ0QsT0FBTyxDQUFDLENBQUMsUUFBUSxFQUFFLENBQUM7QUFDdEIsQ0FBQztBQUVEOztHQUVHO0FBQ0gsU0FBZ0Isc0JBQXNCLENBQUMsQ0FBTTtJQUMzQyxPQUFPO1FBQ0wsR0FBRyxFQUFF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QUM7QUFDOUQsQ0FBQztBQUVELDZEQUE2RDtBQUM3RCxNQUFNLGlCQUFrQixTQUFRLEtBQUs7SUFBckM7O1FBQ2tCLFNBQUksR0FBRyxtQkFBbUIsQ0FBQztJQUM3QyxDQUFDO0NBQUEiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBDb25zdHJ1Y3QgfSBmcm9tICcuL2NvbnN0cnVjdCc7XG5cbi8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbi8vIFBST1BFUlRZIE1BUFBFUlNcbi8vXG4vLyBUaGVzZSBhcmUgdXNlZCB3aGlsZSBjb252ZXJ0aW5nIGdlbmVyYXRlZCBjbGFzc2VzL3Byb3BlcnR5IGJhZ3MgdG8gQ2xvdWRGb3JtYXRpb24gcHJvcGVydHkgb2JqZWN0c1xuLy9cbi8vIFdlIHVzZSBpZGVudGl0eSBtYXBwZXJzIGZvciB0aGUgcHJpbWl0aXZlIHR5cGVzLiBUaGVzZSBkb24ndCBkbyBhbnl0aGluZyBidXQgYXJlIHRoZXJlIHRvIG1ha2UgdGhlIGNvZGVcbi8vIGdlbmVyYXRpb24gd29yayBvdXQgbmljZWx5IChzbyB0aGUgY29kZSBnZW5lcmF0b3IgZG9lc24ndCBuZWVkIHRvIGVtaXQgZGlmZmVyZW50IGNvZGUgZm9yIHByaW1pdGl2ZVxuLy8gdnMuIGNvbXBsZXggdHlwZXMpLlxuZXhwb3J0IHR5cGUgTWFwcGVyID0gKHg6IGFueSkgPT4gYW55O1xuXG5mdW5jdGlvbiBpZGVudGl0eSh4OiBhbnkpIHtcbiAgcmV0dXJuIHg7XG59XG5cbmV4cG9ydCBjb25zdCBzdHJpbmdUb0Nsb3VkRm9ybWF0aW9uOiBNYXBwZXIgPSBpZGVudGl0eTtcbmV4cG9ydCBjb25zdCBib29sZWFuVG9DbG91ZEZvcm1hdGlvbjogTWFwcGVyID0gaWRlbnRpdHk7XG5leHBvcnQgY29uc3Qgb2JqZWN0VG9DbG91ZEZvcm1hdGlvbjogTWFwcGVyID0gaWRlbnRpdHk7XG5leHBvcnQgY29uc3QgbnVtYmVyVG9DbG91ZEZvcm1hdGlvbjogTWFwcGVyID0gaWRlbnRpdHk7XG5cbi8qKlxuICogVGhlIGRhdGUgbmVlZHMgdG8gYmUgZm9ybWF0dGVkIGFzIGFuIElTTyBkYXRlIGluIFVUQ1xuICpcbiAqIFNvbWUgdXNhZ2Ugc2l0ZXMgcmVxdWlyZSBhIGRhdGUsIHNvbWUgcmVxdWlyZSBhIHRpbWVzdGFtcC4gV2UnbGxcbiAqIGFsd2F5cyBvdXRwdXQgYSB0aW1lc3RhbXAgYW5kIGhvcGUgdGhlIHBhcnNlciBvbiB0aGUgb3RoZXIgZW5kXG4gKiBpcyBzbWFydCBlbm91Z2ggdG8gaWdub3JlIHRoZSB0aW1lIHBhcnQuLi4gKD8pXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBkYXRlVG9DbG91ZEZvcm1hdGlvbih4PzogRGF0ZSk6IGFueSB7XG4gIGlmICgheCkge1xuICAgIHJldHVybiB1bmRlZmluZWQ7XG4gIH1cblxuICAvLyB0c2xpbnQ6ZGlzYWJsZS1uZXh0LWxpbmU6bWF4LWxpbmUtbGVuZ3RoXG4gIHJldHVybiBgJHt4LmdldFVUQ0Z1bGxZZWFyKCl9LSR7cGFkKHguZ2V0VVRDTW9udGgoKSArIDEpfS0ke3BhZCh4LmdldFVUQ0RhdGUoKSl9VCR7cGFkKHguZ2V0VVRDSG91cnMoKSl9OiR7cGFkKHguZ2V0VVRDTWludXRlcygpKX06JHtwYWQoeC5nZXRVVENTZWNvbmRzKCkpfWA7XG59XG5cbi8qKlxuICogUGFkIGEgbnVtYmVyIHRvIDIgZGVjaW1hbCBwbGFjZXNcbiAqL1xuZnVuY3Rpb24gcGFkKHg6IG51bWJlcikge1xuICBpZiAoeCA8IDEwKSB7XG4gICAgcmV0dXJuIFwiMFwiICsgeC50b1N0cmluZygpO1xuICB9XG4gIHJldHVybiB4LnRvU3RyaW5nKCk7XG59XG5cbi8qKlxuICogVHVybiBhIHRhZyBvYmplY3QgaW50byB0aGUgcHJvcGVyIENsb3VkRm9ybWF0aW9uIHJlcHJlc2VudGF0aW9uXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBjZm5UYWdUb0Nsb3VkRm9ybWF0aW9uKHg6IGFueSk6IGFueSB7XG4gIHJldHVybiB7XG4gICAgS2V5OiB4LmtleSxcbiAgICBWYWx1ZTogeC52YWx1ZVxuICB9O1xufVxuXG5leHBvcnQgZnVuY3Rpb24gbGlzdE1hcHBlcihlbGVtZW50TWFwcGVyOiBNYXBwZXIpOiBNYXBwZXIge1xuICByZXR1cm4gKHg6IGFueSkgPT4ge1xuICAgIGlmICghY2FuSW5zcGVjdCh4KSkgeyByZXR1cm4geDsgfVxuICAgIHJldHVybiB4Lm1hcChlbGVtZW50TWFwcGVyKTtcbiAgfTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGhhc2hNYXBwZXIoZWxlbWVudE1hcHBlcjogTWFwcGVyKTogTWFwcGVyIHtcbiAgcmV0dXJuICh4OiBhbnkpID0+IHtcbiAgICBpZiAoIWNhbkluc3BlY3QoeCkpIHsgcmV0dXJuIHg7IH1cblxuICAgIGNvbnN0IHJldDogYW55ID0ge307XG5cbiAgICBPYmplY3Qua2V5cyh4KS5mb3JFYWNoKChrZXkpID0+IHtcbiAgICAgIHJldFtrZXldID0gZWxlbWVudE1hcHBlcih4W2tleV0pO1xuICAgIH0pO1xuXG4gICAgcmV0dXJuIHJldDtcbiAgfTtcbn1cblxuLyoqXG4gKiBSZXR1cm4gYSB1bmlvbiBtYXBwZXJcbiAqXG4gKiBUYWtlcyBhIGxpc3Qgb2YgdmFsaWRhdG9ycyBhbmQgYSBsaXN0IG9mIG1hcHBlcnMsIHdoaWNoIHNob3VsZCBjb3JyZXNwb25kIHBhaXJ3aXNlLlxuICpcbiAqIFRoZSBtYXBwZXIgb2YgdGhlIGZpcnN0IHN1Y2Nlc3NmdWwgdmFsaWRhdG9yIHdpbGwgYmUgY2FsbGVkLlxuICovXG5leHBvcnQgZnVuY3Rpb24gdW5pb25NYXBwZXIodmFsaWRhdG9yczogVmFsaWRhdG9yW10sIG1hcHBlcnM6IE1hcHBlcltdKTogTWFwcGVyIHtcbiAgaWYgKHZhbGlkYXRvcnMubGVuZ3RoICE9PSBtYXBwZXJzLmxlbmd0aCkge1xuICAgIHRocm93IEVycm9yKCdOb3QgdGhlIHNhbWUgYW1vdW50IG9mIHZhbGlkYXRvcnMgYW5kIG1hcHBlcnMgcGFzc2VkIHRvIHVuaW9uTWFwcGVyKCknKTtcbiAgfVxuXG4gIHJldHVybiAoeDogYW55KSA9PiB7XG4gICAgaWYgKCFjYW5JbnNwZWN0KHgpKSB7IHJldHVybiB4OyB9XG5cbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IHZhbGlkYXRvcnMubGVuZ3RoOyBpKyspIHtcbiAgICAgIGlmICh2YWxpZGF0b3JzW2ldKHgpLmlzU3VjY2Vzcykge1xuICAgICAgICByZXR1cm4gbWFwcGVyc1tpXSh4KTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBTaG91bGQgbm90IGJlIHBvc3NpYmxlIGJlY2F1c2UgdGhlIHVuaW9uIG11c3QgaGF2ZSBwYXNzZWQgdmFsaWRhdGlvbiBiZWZvcmUgdGhpcyBmdW5jdGlvblxuICAgIC8vIHdpbGwgYmUgY2FsbGVkLCBidXQgY2F0Y2ggaXQgYW55d2F5LlxuICAgIHRocm93IG5ldyBUeXBlRXJyb3IoJ05vIHZhbGlkYXRvcnMgbWF0Y2hlZCBpbiB0aGUgdW5pb24oKScpO1xuICB9O1xufVxuXG4vLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4vLyBWQUxJREFUT1JTXG4vL1xuLy8gVGhlc2UgYXJlIHVzZWQgd2hpbGUgY2hlY2tpbmcgdGhhdCBzdXBwbGllZCBwcm9wZXJ0eSBiYWdzIG1hdGNoIHRoZSBleHBlY3RlZCBzY2hlbWFcbi8vXG4vLyBXZSBoYXZlIGEgY291cGxlIG9mIGRhdGF0eXBlcyB0aGF0IG1vZGVsIHZhbGlkYXRpb24gZXJyb3JzIGFuZCBjb2xsZWN0aW9ucyBvZiB2YWxpZGF0aW9uXG4vLyBlcnJvcnMgKHRvZ2V0aGVyIGZvcm1pbmcgYSB0cmVlIG9mIGVycm9ycyBzbyB0aGF0IHdlIGNhbiB0cmFjZSB2YWxpZGF0aW9uIGVycm9ycyB0aHJvdWdoXG4vLyBhbiBvYmplY3QgZ3JhcGgpLCBhbmQgdmFsaWRhdG9ycy5cbi8vXG4vLyBWYWxpZGF0b3JzIGFyZSBzaW1wbHkgZnVuY3Rpb25zIHRoYXQgdGFrZSBhIHZhbHVlIGFuZCByZXR1cm4gYSB2YWxpZGF0aW9uIHJlc3VsdHMuIFRoZW5cbi8vIHdlIGhhdmUgc29tZSBjb21iaW5hdG9ycyB0byB0dXJuIHByaW1pdGl2ZSB2YWxpZGF0b3JzIGludG8gbW9yZSBjb21wbGV4IHZhbGlkYXRvcnMuXG4vL1xuXG4vKipcbiAqIFJlcHJlc2VudGF0aW9uIG9mIHZhbGlkYXRpb24gcmVzdWx0c1xuICpcbiAqIE1vZGVscyBhIHRyZWUgb2YgdmFsaWRhdGlvbiBlcnJvcnMgc28gdGhhdCB3ZSBoYXZlIGFzIG11Y2ggaW5mb3JtYXRpb24gYXMgcG9zc2libGVcbiAqIGFib3V0IHRoZSBmYWlsdXJlIHRoYXQgb2NjdXJyZWQuXG4gKi9cbmV4cG9ydCBjbGFzcyBWYWxpZGF0aW9uUmVzdWx0IHtcbiAgY29uc3RydWN0b3IocmVhZG9ubHkgZXJyb3JNZXNzYWdlOiBzdHJpbmcgPSAnJywgcmVhZG9ubHkgcmVzdWx0czogVmFsaWRhdGlvblJlc3VsdHMgPSBuZXcgVmFsaWRhdGlvblJlc3VsdHMoKSkge1xuICB9XG5cbiAgcHVibGljIGdldCBpc1N1Y2Nlc3MoKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuICF0aGlzLmVycm9yTWVzc2FnZSAmJiB0aGlzLnJlc3VsdHMuaXNTdWNjZXNzO1xuICB9XG5cbiAgLyoqXG4gICAqIFR1cm4gYSBmYWlsZWQgdmFsaWRhdGlvbiBpbnRvIGFuIGV4Y2VwdGlvblxuICAgKi9cbiAgcHVibGljIGFzc2VydFN1Y2Nlc3MoKSB7XG4gICAgaWYgKCF0aGlzLmlzU3VjY2Vzcykge1xuICAgICAgbGV0IG1lc3NhZ2UgPSB0aGlzLmVycm9yVHJlZSgpO1xuICAgICAgLy8gVGhlIGZpcnN0IGxldHRlciB3aWxsIGJlIGxvd2VyY2FzZSwgc28gdXBwZXJjYXNlIGl0IGZvciBhIG5pY2VyIGVycm9yIG1lc3NhZ2VcbiAgICAgIG1lc3NhZ2UgPSBtZXNzYWdlLnN1YnN0cigwLCAxKS50b1VwcGVyQ2FzZSgpICsgbWVzc2FnZS5zdWJzdHIoMSk7XG4gICAgICB0aHJvdyBuZXcgQ2ZuU3ludGhlc2lzRXJyb3IobWVzc2FnZSk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybiBhIHN0cmluZyByZW5kZXJpbmcgb2YgdGhlIHRyZWUgb2YgdmFsaWRhdGlvbiBmYWlsdXJlc1xuICAgKi9cbiAgcHVibGljIGVycm9yVHJlZSgpOiBzdHJpbmcge1xuICAgIGNvbnN0IGNoaWxkTWVzc2FnZXMgPSB0aGlzLnJlc3VsdHMuZXJyb3JUcmVlTGlzdCgpO1xuICAgIHJldHVybiB0aGlzLmVycm9yTWVzc2FnZSArIChjaGlsZE1lc3NhZ2VzLmxlbmd0aCA/IGBcXG4gICR7Y2hpbGRNZXNzYWdlcy5yZXBsYWNlKC9cXG4vZywgJ1xcbiAgJyl9YCA6ICcnKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBXcmFwIHRoaXMgcmVzdWx0IHdpdGggYW4gZXJyb3IgbWVzc2FnZSwgaWYgaXQgY29uY2VybnMgYW4gZXJyb3JcbiAgICovXG4gIHB1YmxpYyBwcmVmaXgobWVzc2FnZTogc3RyaW5nKTogVmFsaWRhdGlvblJlc3VsdCB7XG4gICAgaWYgKHRoaXMuaXNTdWNjZXNzKSB7IHJldHVybiB0aGlzOyB9XG4gICAgcmV0dXJuIG5ldyBWYWxpZGF0aW9uUmVzdWx0KGAke21lc3NhZ2V9OiAke3RoaXMuZXJyb3JNZXNzYWdlfWAsIHRoaXMucmVzdWx0cyk7XG4gIH1cbn1cblxuLyoqXG4gKiBBIGNvbGxlY3Rpb24gb2YgdmFsaWRhdGlvbiByZXN1bHRzXG4gKi9cbmV4cG9ydCBjbGFzcyBWYWxpZGF0aW9uUmVzdWx0cyB7XG4gIGNvbnN0cnVjdG9yKHB1YmxpYyByZXN1bHRzOiBWYWxpZGF0aW9uUmVzdWx0W10gPSBbXSkge1xuICB9XG5cbiAgcHVibGljIGNvbGxlY3QocmVzdWx0OiBWYWxpZGF0aW9uUmVzdWx0KSB7XG4gICAgLy8gT25seSBjb2xsZWN0IGZhaWx1cmVzXG4gICAgaWYgKCFyZXN1bHQuaXNTdWNjZXNzKSB7XG4gICAgICB0aGlzLnJlc3VsdHMucHVzaChyZXN1bHQpO1xuICAgIH1cbiAgfVxuXG4gIHB1YmxpYyBnZXQgaXNTdWNjZXNzKCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLnJlc3VsdHMuZXZlcnkoeCA9PiB4LmlzU3VjY2Vzcyk7XG4gIH1cblxuICBwdWJsaWMgZXJyb3JUcmVlTGlzdCgpOiBzdHJpbmcge1xuICAgIHJldHVybiB0aGlzLnJlc3VsdHMubWFwKGNoaWxkID0+IGNoaWxkLmVycm9yVHJlZSgpKS5qb2luKCdcXG4nKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBXcmFwIHVwIGFsbCB2YWxpZGF0aW9uIHJlc3VsdHMgaW50byBhIHNpbmdsZSB0cmVlIG5vZGVcbiAgICpcbiAgICogSWYgdGhlcmUgYXJlIGZhaWx1cmVzIGluIHRoZSBjb2xsZWN0aW9uLCBhZGQgYSBtZXNzYWdlLCBvdGhlcndpc2VcbiAgICogcmV0dXJuIGEgc3VjY2Vzcy5cbiAgICovXG4gIHB1YmxpYyB3cmFwKG1lc3NhZ2U6IHN0cmluZyk6IFZhbGlkYXRpb25SZXN1bHQge1xuICAgIGlmICh0aGlzLmlzU3VjY2Vzcykge8KgcmV0dXJuIFZBTElEQVRJT05fU1VDQ0VTUzsgfVxuICAgIHJldHVybiBuZXcgVmFsaWRhdGlvblJlc3VsdChtZXNzYWdlLCB0aGlzKTtcbiAgfVxufVxuXG4vLyBTaW5nbGV0b24gb2JqZWN0IHRvIHNhdmUgb24gYWxsb2NhdGlvbnNcbmV4cG9ydCBjb25zdCBWQUxJREFUSU9OX1NVQ0NFU1MgPSBuZXcgVmFsaWRhdGlvblJlc3VsdCgpO1xuXG5leHBvcnQgdHlwZSBWYWxpZGF0b3IgPSAoeDogYW55KSA9PiBWYWxpZGF0aW9uUmVzdWx0O1xuXG4vKipcbiAqIFJldHVybiB3aGV0aGVyIHRoaXMgb2JqZWN0IGNhbiBiZSB2YWxpZGF0ZWQgYXQgYWxsXG4gKlxuICogVHJ1ZSB1bmxlc3MgaXQncyB1bmRlZmluZWQgb3IgYSBDbG91ZEZvcm1hdGlvbiBpbnRyaW5zaWNcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGNhbkluc3BlY3QoeDogYW55KSB7XG4gIC8vIE5vdGU6IHVzaW5nIHdlYWsgZXF1YWxpdHkgb24gcHVycG9zZSwgd2UgYWxzbyB3YW50IHRvIGNhdGNoIHVuZGVmaW5lZFxuICByZXR1cm4gKHggIT0gbnVsbCAmJiAhaXNDbG91ZEZvcm1hdGlvbkludHJpbnNpYyh4KSk7XG59XG5cbi8vIENsb3VkRm9ybWF0aW9uIHZhbGlkYXRvcnMgZm9yIHByaW1pdGl2ZSB0eXBlc1xuZXhwb3J0IGZ1bmN0aW9uIHZhbGlkYXRlU3RyaW5nKHg6IGFueSk6IFZhbGlkYXRpb25SZXN1bHQge1xuICBpZiAoY2FuSW5zcGVjdCh4KSAmJiB0eXBlb2YgeCAhPT0gJ3N0cmluZycpIHtcbiAgICByZXR1cm4gbmV3IFZhbGlkYXRpb25SZXN1bHQoYCR7SlNPTi5zdHJpbmdpZnkoeCl9IHNob3VsZCBiZSBhIHN0cmluZ2ApO1xuICB9XG4gIHJldHVybiBWQUxJREFUSU9OX1NVQ0NFU1M7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiB2YWxpZGF0ZU51bWJlcih4OiBhbnkpOiBWYWxpZGF0aW9uUmVzdWx0IHtcbiAgaWYgKGNhbkluc3BlY3QoeCkgJiYgdHlwZW9mIHggIT09ICdudW1iZXInKSB7XG4gICAgcmV0dXJuIG5ldyBWYWxpZGF0aW9uUmVzdWx0KGAke0pTT04uc3RyaW5naWZ5KHgpfSBzaG91bGQgYmUgYSBudW1iZXJgKTtcbiAgfVxuICByZXR1cm4gVkFMSURBVElPTl9TVUNDRVNTO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gdmFsaWRhdGVCb29sZWFuKHg6IGFueSk6IFZhbGlkYXRpb25SZXN1bHQge1xuICBpZiAoY2FuSW5zcGVjdCh4KSAmJiB0eXBlb2YgeCAhPT0gJ2Jvb2xlYW4nKSB7XG4gICAgcmV0dXJuIG5ldyBWYWxpZGF0aW9uUmVzdWx0KGAke0pTT04uc3RyaW5naWZ5KHgpfSBzaG91bGQgYmUgYSBib29sZWFuYCk7XG4gIH1cbiAgcmV0dXJuIFZBTElEQVRJT05fU1VDQ0VTUztcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIHZhbGlkYXRlRGF0ZSh4OiBhbnkpOiBWYWxpZGF0aW9uUmVzdWx0IHtcbiAgaWYgKGNhbkluc3BlY3QoeCkgJiYgISh4IGluc3RhbmNlb2YgRGF0ZSkpIHtcbiAgICByZXR1cm4gbmV3IFZhbGlkYXRpb25SZXN1bHQoYCR7SlNPTi5zdHJpbmdpZnkoeCl9IHNob3VsZCBiZSBhIERhdGVgKTtcbiAgfVxuXG4gIGlmICh4ICE9PSB1bmRlZmluZWQgJiYgaXNOYU4oeC5nZXRUaW1lKCkpKSB7XG4gICAgcmV0dXJuIG5ldyBWYWxpZGF0aW9uUmVzdWx0KCdnb3QgYW4gdW5wYXJzZWFibGUgRGF0ZScpO1xuICB9XG5cbiAgcmV0dXJuIFZBTElEQVRJT05fU1VDQ0VTUztcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIHZhbGlkYXRlT2JqZWN0KHg6IGFueSk6IFZhbGlkYXRpb25SZXN1bHQge1xuICBpZiAoY2FuSW5zcGVjdCh4KSAmJiB0eXBlb2YgeCAhPT0gJ29iamVjdCcpIHtcbiAgICByZXR1cm4gbmV3IFZhbGlkYXRpb25SZXN1bHQoYCR7SlNPTi5zdHJpbmdpZnkoeCl9IHNob3VsZCBiZSBhbiAnb2JqZWN0J2ApO1xuICB9XG4gIHJldHVybiBWQUxJREFUSU9OX1NVQ0NFU1M7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiB2YWxpZGF0ZUNmblRhZyh4OiBhbnkpOiBWYWxpZGF0aW9uUmVzdWx0IHtcbiAgaWYgKCFjYW5JbnNwZWN0KHgpKSB7IHJldHVybiBWQUxJREFUSU9OX1NVQ0NFU1M7IH1cblxuICBpZiAoeC5rZXkgPT0gbnVsbCB8fCB4LnZhbHVlID09IG51bGwpIHtcbiAgICByZXR1cm4gbmV3IFZhbGlkYXRpb25SZXN1bHQoYCR7SlNPTi5zdHJpbmdpZnkoeCl9IHNob3VsZCBoYXZlIGEgJ2tleScgYW5kIGEgJ3ZhbHVlJyBwcm9wZXJ0eWApO1xuICB9XG5cbiAgcmV0dXJuIFZBTElEQVRJT05fU1VDQ0VTUztcbn1cblxuLyoqXG4gKiBSZXR1cm4gYSBsaXN0IHZhbGlkYXRvciBiYXNlZCBvbiB0aGUgZ2l2ZW4gZWxlbWVudCB2YWxpZGF0b3JcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGxpc3RWYWxpZGF0b3IoZWxlbWVudFZhbGlkYXRvcjogVmFsaWRhdG9yKTogVmFsaWRhdG9yIHtcbiAgcmV0dXJuICh4OiBhbnkpID0+IHtcbiAgICBpZiAoIWNhbkluc3BlY3QoeCkpIHsgcmV0dXJuIFZBTElEQVRJT05fU1VDQ0VTUzsgfVxuXG4gICAgaWYgKCF4LmZvckVhY2gpIHtcbiAgICAgIHJldHVybiBuZXcgVmFsaWRhdGlvblJlc3VsdChgJHtKU09OLnN0cmluZ2lmeSh4KX0gc2hvdWxkIGJlIGEgbGlzdGApO1xuICAgIH1cblxuICAgIGZvciAobGV0IGkgPSAwOyBpIDwgeC5sZW5ndGg7IGkrKykge1xuICAgICAgY29uc3QgZWxlbWVudCA9IHhbaV07XG4gICAgICBjb25zdCByZXN1bHQgPSBlbGVtZW50VmFsaWRhdG9yKGVsZW1lbnQpO1xuICAgICAgaWYgKCFyZXN1bHQuaXNTdWNjZXNzKSB7IHJldHVybiByZXN1bHQucHJlZml4KGBlbGVtZW50ICR7aX1gKTsgfVxuICAgIH1cblxuICAgIHJldHVybiBWQUxJREFUSU9OX1NVQ0NFU1M7XG4gIH07XG59XG5cbi8qKlxuICogUmV0dXJuIGEgaGFzaCB2YWxpZGF0b3IgYmFzZWQgb24gdGhlIGdpdmVuIGVsZW1lbnQgdmFsaWRhdG9yXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBoYXNoVmFsaWRhdG9yKGVsZW1lbnRWYWxpZGF0b3I6IFZhbGlkYXRvcik6IFZhbGlkYXRvciB7XG4gIHJldHVybiAoeDogYW55KSA9PiB7XG4gICAgaWYgKCFjYW5JbnNwZWN0KHgpKSB7IHJldHVybiBWQUxJREFUSU9OX1NVQ0NFU1M7IH1cblxuICAgIGZvciAoY29uc3Qga2V5IG9mIE9iamVjdC5rZXlzKHgpKSB7XG4gICAgICBjb25zdCByZXN1bHQgPSBlbGVtZW50VmFsaWRhdG9yKHhba2V5XSk7XG4gICAgICBpZiAoIXJlc3VsdC5pc1N1Y2Nlc3MpIHsgcmV0dXJuIHJlc3VsdC5wcmVmaXgoYGVsZW1lbnQgJyR7a2V5fSdgKTsgfVxuICAgIH1cblxuICAgIHJldHVybiBWQUxJREFUSU9OX1NVQ0NFU1M7XG4gIH07XG59XG5cbi8qKlxuICogRGVjb3JhdGUgYSB2YWxpZGF0b3Igd2l0aCBhIG1lc3NhZ2UgY2xhcmlmeWluZyB0aGUgcHJvcGVydHkgdGhlIGZhaWx1cmUgaXMgZm9yLlxuICovXG5leHBvcnQgZnVuY3Rpb24gcHJvcGVydHlWYWxpZGF0b3IocHJvcE5hbWU6IHN0cmluZywgdmFsaWRhdG9yOiBWYWxpZGF0b3IpOiBWYWxpZGF0b3Ige1xuICByZXR1cm4gKHg6IGFueSkgPT4ge1xuICAgIHJldHVybiB2YWxpZGF0b3IoeCkucHJlZml4KHByb3BOYW1lKTtcbiAgfTtcbn1cblxuLyoqXG4gKiBSZXR1cm4gYSB2YWxpZGF0b3IgdGhhdCB3aWxsIGZhaWwgaWYgdGhlIHBhc3NlZCBwcm9wZXJ0eSBpcyBub3QgcHJlc2VudFxuICpcbiAqIERvZXMgbm90IGRpc3Rpbmd1aXNoIGJldHdlZW4gdGhlIHByb3BlcnR5IGFjdHVhbGx5IG5vdCBiZWluZyBwcmVzZW50LCB2cyBiZWluZyBwcmVzZW50IGJ1dCAnbnVsbCdcbiAqIG9yICd1bmRlZmluZWQnIChjb3VydGVzeSBvZiBKYXZhU2NyaXB0KSwgd2hpY2ggaXMgZ2VuZXJhbGx5IHRoZSBiZWhhdmlvciB0aGF0IHdlIHdhbnQuXG4gKlxuICogRW1wdHkgc3RyaW5ncyBhcmUgY29uc2lkZXJlZCBcInByZXNlbnRcIi0tZG9uJ3Qga25vdyBpZiB0aGlzIGFncmVlcyB3aXRoIGhvdyBDbG91ZEZvcm1hdGlvbiBsb29rc1xuICogYXQgdGhlIHdvcmxkLlxuICovXG5leHBvcnQgZnVuY3Rpb24gcmVxdWlyZWRWYWxpZGF0b3IoeDogYW55KSB7XG4gIGlmICh4ID09IG51bGwpIHtcbiAgICByZXR1cm4gbmV3IFZhbGlkYXRpb25SZXN1bHQoYHJlcXVpcmVkIGJ1dCBtaXNzaW5nYCk7XG4gIH1cbiAgcmV0dXJuIFZBTElEQVRJT05fU1VDQ0VTUztcbn1cblxuLyoqXG4gKiBSZXF1aXJlIGEgcHJvcGVydHkgZnJvbSBhIHByb3BlcnR5IGJhZy5cbiAqXG4gKiBAcGFyYW0gcHJvcHMgIHRoZSBwcm9wZXJ0eSBiYWcgZnJvbSB3aGljaCBhIHByb3BlcnR5IGlzIHJlcXVpcmVkLlxuICogQHBhcmFtIG5hbWUgICB0aGUgbmFtZSBvZiB0aGUgcmVxdWlyZWQgcHJvcGVydHkuXG4gKiBAcGFyYW0gdHlwZU5hbWUgdGhlIG5hbWUgb2YgdGhlIGNvbnN0cnVjdCB0eXBlIHRoYXQgcmVxdWlyZXMgdGhlIHByb3BlcnR5XG4gKlxuICogQHJldHVybnMgdGhlIHZhbHVlIG9mIGBgcHJvcHNbbmFtZV1gYFxuICpcbiAqIEB0aHJvd3MgaWYgdGhlIHByb3BlcnR5IGBgbmFtZWBgIGlzIG5vdCBwcmVzZW50IGluIGBgcHJvcHNgYC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJlcXVpcmVQcm9wZXJ0eShwcm9wczogeyBbbmFtZTogc3RyaW5nXTogYW55IH0sIG5hbWU6IHN0cmluZywgY29udGV4dDogQ29uc3RydWN0KTogYW55IHtcbiAgaWYgKCEobmFtZSBpbiBwcm9wcykpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoYCR7Y29udGV4dC50b1N0cmluZygpfSBpcyBtaXNzaW5nIHJlcXVpcmVkIHByb3BlcnR5OiAke25hbWV9YCk7XG4gIH1cbiAgY29uc3QgdmFsdWUgPSBwcm9wc1tuYW1lXTtcbiAgLy8gUG9zc2libHkgYWRkIHR5cGUtY2hlY2tpbmcgaGVyZS4uLlxuICByZXR1cm4gdmFsdWU7XG59XG5cbi8qKlxuICogVmFsaWRhdGVzIGlmIGFueSBvZiB0aGUgZ2l2ZW4gdmFsaWRhdG9ycyBtYXRjaGVzXG4gKlxuICogV2UgYWRkIGVpdGhlci9vciB3b3JkcyB0byB0aGUgZnJvbnQgb2YgdGhlIGVycm9yIG1lc2FnZXMgc28gdGhhdCB0aGV5IHJlYWRcbiAqIG1vcmUgbmljZWx5LiBFeGFtcGxlOlxuICpcbiAqICAgUHJvcGVydGllcyBub3QgY29ycmVjdCBmb3IgJ0Z1bmN0aW9uUHJvcHMnXG4gKiAgICAgY29kZVVyaTogbm90IG9uZSBvZiB0aGUgcG9zc2libGUgdHlwZXNcbiAqICAgICAgIGVpdGhlcjogcHJvcGVydGllcyBub3QgY29ycmVjdCBmb3IgJ1MzTG9jYXRpb25Qcm9wZXJ0eSdcbiAqICAgICAgICAgYnVja2V0OiByZXF1aXJlZCBidXQgbWlzc2luZ1xuICogICAgICAgICBrZXk6IHJlcXVpcmVkIGJ1dCBtaXNzaW5nXG4gKiAgICAgICAgIHZlcnNpb246IHJlcXVpcmVkIGJ1dCBtaXNzaW5nXG4gKiAgICAgICBvcjogJzMnIHNob3VsZCBiZSBhICdzdHJpbmcnXG4gKlxuICovXG5leHBvcnQgZnVuY3Rpb24gdW5pb25WYWxpZGF0b3IoLi4udmFsaWRhdG9yczogVmFsaWRhdG9yW10pOiBWYWxpZGF0b3Ige1xuICByZXR1cm4gKHg6IGFueSkgPT4ge1xuICAgIGNvbnN0IHJlc3VsdHMgPSBuZXcgVmFsaWRhdGlvblJlc3VsdHMoKTtcbiAgICBsZXQgZWl0aGVyT3IgPSAnZWl0aGVyJztcblxuICAgIGZvciAoY29uc3QgdmFsaWRhdG9yIG9mIHZhbGlkYXRvcnMpIHtcbiAgICAgIGNvbnN0IHJlc3VsdCA9IHZhbGlkYXRvcih4KTtcbiAgICAgIGlmIChyZXN1bHQuaXNTdWNjZXNzKSB7IHJldHVybiByZXN1bHQ7IH1cbiAgICAgIHJlc3VsdHMuY29sbGVjdChyZXN1bHQucHJlZml4KGVpdGhlck9yKSk7XG4gICAgICBlaXRoZXJPciA9ICdvcic7XG4gICAgfVxuICAgIHJldHVybiByZXN1bHRzLndyYXAoJ25vdCBvbmUgb2YgdGhlIHBvc3NpYmxlIHR5cGVzJyk7XG4gIH07XG59XG5cbi8qKlxuICogUmV0dXJuIHdoZXRoZXIgdGhlIGluZGljYXRlZCB2YWx1ZSByZXByZXNlbnRzIGEgQ2xvdWRGb3JtYXRpb24gaW50cmluc2ljLlxuICpcbiAqIENsb3VkRm9ybWF0aW9uIGludHJpbnNpY3MgYXJlIG1vZGVsZWQgYXMgb2JqZWN0cyB3aXRoIGEgc2luZ2xlIGtleSwgd2hpY2hcbiAqIGxvb2sgbGlrZTogeyBcIkZuOjpHZXRBdHRcIjogWy4uLl0gfSBvciBzaW1pbGFyLlxuICovXG5mdW5jdGlvbiBpc0Nsb3VkRm9ybWF0aW9uSW50cmluc2ljKHg6IGFueSkge1xuICBpZiAoISh0eXBlb2YgeCA9PT0gJ29iamVjdCcpKSB7IHJldHVybiBmYWxzZTsgfVxuICBjb25zdCBrZXlzID0gT2JqZWN0LmtleXMoeCk7XG4gIGlmIChrZXlzLmxlbmd0aCAhPT0gMSkgeyByZXR1cm4gZmFsc2U7IH1cblxuICByZXR1cm4ga2V5c1swXSA9PT0gJ1JlZicgfHwga2V5c1swXS5zdWJzdHIoMCwgNCkgPT09ICdGbjo6Jztcbn1cblxuLy8gQ2Fubm90IGJlIHB1YmxpYyBiZWNhdXNlIEpTSUkgZ2V0cyBjb25mdXNlZCBhYm91dCBlczUuZC50c1xuY2xhc3MgQ2ZuU3ludGhlc2lzRXJyb3IgZXh0ZW5kcyBFcnJvciB7XG4gIHB1YmxpYyByZWFkb25seSB0eXBlID0gJ0NmblN5bnRoZXNpc0Vycm9yJztcbn1cbiJdfQ==