@aws-cdk/core
Version:
AWS Cloud Development Kit Core Library
210 lines • 24.4 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.isNameOfCloudFormationIntrinsic = exports.minimalCloudFormationJoin = exports.CLOUDFORMATION_TOKEN_RESOLVER = exports.CloudFormationLang = void 0;
const lazy_1 = require("../lazy");
const reference_1 = require("../reference");
const resolvable_1 = require("../resolvable");
const token_1 = require("../token");
const intrinsic_1 = require("./intrinsic");
const resolve_1 = require("./resolve");
/**
* Routines that know how to do operations at the CloudFormation document language level
*/
class CloudFormationLang {
/**
* Turn an arbitrary structure potentially containing Tokens into a JSON string.
*
* Returns a Token which will evaluate to CloudFormation expression that
* will be evaluated by CloudFormation to the JSON representation of the
* input structure.
*
* All Tokens substituted in this way must return strings, or the evaluation
* in CloudFormation will fail.
*
* @param obj The object to stringify
* @param space Indentation to use (default: no pretty-printing)
*/
static toJSON(obj, space) {
// This works in two stages:
//
// First, resolve everything. This gets rid of the lazy evaluations, evaluation
// to the real types of things (for example, would a function return a string, an
// intrinsic, or a number? We have to resolve to know).
//
// We then to through the returned result, identify things that evaluated to
// CloudFormation intrinsics, and re-wrap those in Tokens that have a
// toJSON() method returning their string representation. If we then call
// JSON.stringify() on that result, that gives us essentially the same
// string that we started with, except with the non-token characters quoted.
//
// {"field": "${TOKEN}"} --> {\"field\": \"${TOKEN}\"}
//
// A final resolve() on that string (done by the framework) will yield the string
// we're after.
//
// Resolving and wrapping are done in go using the resolver framework.
class IntrinsincWrapper extends resolvable_1.DefaultTokenResolver {
constructor() {
super(CLOUDFORMATION_CONCAT);
}
resolveToken(t, context, postProcess) {
// Return References directly, so their type is maintained and the references will
// continue to work. Only while preparing, because we do need the final value of the
// token while resolving.
if (reference_1.Reference.isReference(t) && context.preparing) {
return wrap(t);
}
// Deep-resolve and wrap. This is necessary for Lazy tokens so we can see "inside" them.
return wrap(super.resolveToken(t, context, postProcess));
}
resolveString(fragments, context) {
return wrap(super.resolveString(fragments, context));
}
resolveList(l, context) {
return wrap(super.resolveList(l, context));
}
}
// We need a ResolveContext to get started so return a Token
return lazy_1.Lazy.stringValue({
produce: (ctx) => JSON.stringify(resolve_1.resolve(obj, {
preparing: ctx.preparing,
scope: ctx.scope,
resolver: new IntrinsincWrapper(),
}), undefined, space),
});
function wrap(value) {
return isIntrinsic(value) ? new JsonToken(deepQuoteStringsForJSON(value)) : value;
}
}
/**
* Produce a CloudFormation expression to concat two arbitrary expressions when resolving
*/
static concat(left, right) {
if (left === undefined && right === undefined) {
return '';
}
const parts = new Array();
if (left !== undefined) {
parts.push(left);
}
if (right !== undefined) {
parts.push(right);
}
// Some case analysis to produce minimal expressions
if (parts.length === 1) {
return parts[0];
}
if (parts.length === 2 && typeof parts[0] === 'string' && typeof parts[1] === 'string') {
return parts[0] + parts[1];
}
// Otherwise return a Join intrinsic (already in the target document language to avoid taking
// circular dependencies on FnJoin & friends)
return { 'Fn::Join': ['', minimalCloudFormationJoin('', parts)] };
}
}
exports.CloudFormationLang = CloudFormationLang;
/**
* Token that also stringifies in the toJSON() operation.
*/
class JsonToken extends intrinsic_1.Intrinsic {
/**
* Special handler that gets called when JSON.stringify() is used.
*/
toJSON() {
return this.toString();
}
}
/**
* Deep escape strings for use in a JSON context
*/
function deepQuoteStringsForJSON(x) {
if (typeof x === 'string') {
// Whenever we escape a string we strip off the outermost quotes
// since we're already in a quoted context.
const stringified = JSON.stringify(x);
return stringified.substring(1, stringified.length - 1);
}
if (Array.isArray(x)) {
return x.map(deepQuoteStringsForJSON);
}
if (typeof x === 'object') {
for (const key of Object.keys(x)) {
x[key] = deepQuoteStringsForJSON(x[key]);
}
}
return x;
}
const CLOUDFORMATION_CONCAT = {
join(left, right) {
return CloudFormationLang.concat(left, right);
},
};
/**
* Default Token resolver for CloudFormation templates
*/
exports.CLOUDFORMATION_TOKEN_RESOLVER = new resolvable_1.DefaultTokenResolver(CLOUDFORMATION_CONCAT);
/**
* Do an intelligent CloudFormation join on the given values, producing a minimal expression
*/
function minimalCloudFormationJoin(delimiter, values) {
let i = 0;
while (i < values.length) {
const el = values[i];
if (isSplicableFnJoinIntrinsic(el)) {
values.splice(i, 1, ...el['Fn::Join'][1]);
}
else if (i > 0 && isPlainString(values[i - 1]) && isPlainString(values[i])) {
values[i - 1] += delimiter + values[i];
values.splice(i, 1);
}
else {
i += 1;
}
}
return values;
function isPlainString(obj) {
return typeof obj === 'string' && !token_1.Token.isUnresolved(obj);
}
function isSplicableFnJoinIntrinsic(obj) {
if (!isIntrinsic(obj)) {
return false;
}
if (Object.keys(obj)[0] !== 'Fn::Join') {
return false;
}
const [delim, list] = obj['Fn::Join'];
if (delim !== delimiter) {
return false;
}
if (token_1.Token.isUnresolved(list)) {
return false;
}
if (!Array.isArray(list)) {
return false;
}
return true;
}
}
exports.minimalCloudFormationJoin = minimalCloudFormationJoin;
/**
* Return whether the given value represents a CloudFormation intrinsic
*/
function isIntrinsic(x) {
if (Array.isArray(x) || x === null || typeof x !== 'object') {
return false;
}
const keys = Object.keys(x);
if (keys.length !== 1) {
return false;
}
return keys[0] === 'Ref' || isNameOfCloudFormationIntrinsic(keys[0]);
}
function isNameOfCloudFormationIntrinsic(name) {
if (!name.startsWith('Fn::')) {
return false;
}
// these are 'fake' intrinsics, only usable inside the parameter overrides of a CFN CodePipeline Action
return name !== 'Fn::GetArtifactAtt' && name !== 'Fn::GetParam';
}
exports.isNameOfCloudFormationIntrinsic = isNameOfCloudFormationIntrinsic;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xvdWRmb3JtYXRpb24tbGFuZy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbImNsb3VkZm9ybWF0aW9uLWxhbmcudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBQUEsa0NBQStCO0FBQy9CLDRDQUF5QztBQUN6Qyw4Q0FBMEg7QUFFMUgsb0NBQWlDO0FBQ2pDLDJDQUF3QztBQUN4Qyx1Q0FBb0M7QUFFcEM7O0dBRUc7QUFDSCxNQUFhLGtCQUFrQjtJQUM3Qjs7Ozs7Ozs7Ozs7O09BWUc7SUFDSSxNQUFNLENBQUMsTUFBTSxDQUFDLEdBQVEsRUFBRSxLQUFjO1FBQzNDLDRCQUE0QjtRQUM1QixFQUFFO1FBQ0YsK0VBQStFO1FBQy9FLGlGQUFpRjtRQUNqRix1REFBdUQ7UUFDdkQsRUFBRTtRQUNGLDRFQUE0RTtRQUM1RSxxRUFBcUU7UUFDckUseUVBQXlFO1FBQ3pFLHNFQUFzRTtRQUN0RSw0RUFBNEU7UUFDNUUsRUFBRTtRQUNGLHlEQUF5RDtRQUN6RCxFQUFFO1FBQ0YsaUZBQWlGO1FBQ2pGLGVBQWU7UUFDZixFQUFFO1FBQ0Ysc0VBQXNFO1FBQ3RFLE1BQU0saUJBQWtCLFNBQVEsaUNBQW9CO1lBQ2xEO2dCQUNFLEtBQUssQ0FBQyxxQkFBcUIsQ0FBQyxDQUFDO1lBQy9CLENBQUM7WUFFTSxZQUFZLENBQUMsQ0FBYyxFQUFFLE9BQXdCLEVBQUUsV0FBMkI7Z0JBQ3ZGLGtGQUFrRjtnQkFDbEYsb0ZBQW9GO2dCQUNwRix5QkFBeUI7Z0JBQ3pCLElBQUkscUJBQVMsQ0FBQyxXQUFXLENBQUMsQ0FBQyxDQUFDLElBQUksT0FBTyxDQUFDLFNBQVMsRUFBRTtvQkFBRSxPQUFPLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQztpQkFBRTtnQkFFdEUsd0ZBQXdGO2dCQUN4RixPQUFPLElBQUksQ0FBQyxLQUFLLENBQUMsWUFBWSxDQUFDLENBQUMsRUFBRSxPQUFPLEVBQUUsV0FBVyxDQUFDLENBQUMsQ0FBQztZQUMzRCxDQUFDO1lBQ00sYUFBYSxD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QUFJLElBQUksT0FBTyxDQUFDLEtBQUssUUFBUSxFQUFFO1FBQUUsT0FBTyxLQUFLLENBQUM7S0FBRTtJQUU5RSxNQUFNLElBQUksR0FBRyxNQUFNLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQzVCLElBQUksSUFBSSxDQUFDLE1BQU0sS0FBSyxDQUFDLEVBQUU7UUFBRSxPQUFPLEtBQUssQ0FBQztLQUFFO0lBRXhDLE9BQU8sSUFBSSxDQUFDLENBQUMsQ0FBQyxLQUFLLEtBQUssSUFBSSwrQkFBK0IsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztBQUN2RSxDQUFDO0FBRUQsU0FBZ0IsK0JBQStCLENBQUMsSUFBWTtJQUMxRCxJQUFJLENBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxNQUFNLENBQUMsRUFBRTtRQUM1QixPQUFPLEtBQUssQ0FBQztLQUNkO0lBQ0QsdUdBQXVHO0lBQ3ZHLE9BQU8sSUFBSSxLQUFLLG9CQUFvQixJQUFJLElBQUksS0FBSyxjQUFjLENBQUM7QUFDbEUsQ0FBQztBQU5ELDBFQU1DIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgTGF6eSB9IGZyb20gJy4uL2xhenknO1xuaW1wb3J0IHsgUmVmZXJlbmNlIH0gZnJvbSAnLi4vcmVmZXJlbmNlJztcbmltcG9ydCB7IERlZmF1bHRUb2tlblJlc29sdmVyLCBJRnJhZ21lbnRDb25jYXRlbmF0b3IsIElQb3N0UHJvY2Vzc29yLCBJUmVzb2x2YWJsZSwgSVJlc29sdmVDb250ZXh0IH0gZnJvbSAnLi4vcmVzb2x2YWJsZSc7XG5pbXBvcnQgeyBUb2tlbml6ZWRTdHJpbmdGcmFnbWVudHMgfSBmcm9tICcuLi9zdHJpbmctZnJhZ21lbnRzJztcbmltcG9ydCB7IFRva2VuIH0gZnJvbSAnLi4vdG9rZW4nO1xuaW1wb3J0IHsgSW50cmluc2ljIH0gZnJvbSAnLi9pbnRyaW5zaWMnO1xuaW1wb3J0IHsgcmVzb2x2ZSB9IGZyb20gJy4vcmVzb2x2ZSc7XG5cbi8qKlxuICogUm91dGluZXMgdGhhdCBrbm93IGhvdyB0byBkbyBvcGVyYXRpb25zIGF0IHRoZSBDbG91ZEZvcm1hdGlvbiBkb2N1bWVudCBsYW5ndWFnZSBsZXZlbFxuICovXG5leHBvcnQgY2xhc3MgQ2xvdWRGb3JtYXRpb25MYW5nIHtcbiAgLyoqXG4gICAqIFR1cm4gYW4gYXJiaXRyYXJ5IHN0cnVjdHVyZSBwb3RlbnRpYWxseSBjb250YWluaW5nIFRva2VucyBpbnRvIGEgSlNPTiBzdHJpbmcuXG4gICAqXG4gICAqIFJldHVybnMgYSBUb2tlbiB3aGljaCB3aWxsIGV2YWx1YXRlIHRvIENsb3VkRm9ybWF0aW9uIGV4cHJlc3Npb24gdGhhdFxuICAgKiB3aWxsIGJlIGV2YWx1YXRlZCBieSBDbG91ZEZvcm1hdGlvbiB0byB0aGUgSlNPTiByZXByZXNlbnRhdGlvbiBvZiB0aGVcbiAgICogaW5wdXQgc3RydWN0dXJlLlxuICAgKlxuICAgKiBBbGwgVG9rZW5zIHN1YnN0aXR1dGVkIGluIHRoaXMgd2F5IG11c3QgcmV0dXJuIHN0cmluZ3MsIG9yIHRoZSBldmFsdWF0aW9uXG4gICAqIGluIENsb3VkRm9ybWF0aW9uIHdpbGwgZmFpbC5cbiAgICpcbiAgICogQHBhcmFtIG9iaiBUaGUgb2JqZWN0IHRvIHN0cmluZ2lmeVxuICAgKiBAcGFyYW0gc3BhY2UgSW5kZW50YXRpb24gdG8gdXNlIChkZWZhdWx0OiBubyBwcmV0dHktcHJpbnRpbmcpXG4gICAqL1xuICBwdWJsaWMgc3RhdGljIHRvSlNPTihvYmo6IGFueSwgc3BhY2U/OiBudW1iZXIpOiBzdHJpbmcge1xuICAgIC8vIFRoaXMgd29ya3MgaW4gdHdvIHN0YWdlczpcbiAgICAvL1xuICAgIC8vIEZpcnN0LCByZXNvbHZlIGV2ZXJ5dGhpbmcuIFRoaXMgZ2V0cyByaWQgb2YgdGhlIGxhenkgZXZhbHVhdGlvbnMsIGV2YWx1YXRpb25cbiAgICAvLyB0byB0aGUgcmVhbCB0eXBlcyBvZiB0aGluZ3MgKGZvciBleGFtcGxlLCB3b3VsZCBhIGZ1bmN0aW9uIHJldHVybiBhIHN0cmluZywgYW5cbiAgICAvLyBpbnRyaW5zaWMsIG9yIGEgbnVtYmVyPyBXZSBoYXZlIHRvIHJlc29sdmUgdG8ga25vdykuXG4gICAgLy9cbiAgICAvLyBXZSB0aGVuIHRvIHRocm91Z2ggdGhlIHJldHVybmVkIHJlc3VsdCwgaWRlbnRpZnkgdGhpbmdzIHRoYXQgZXZhbHVhdGVkIHRvXG4gICAgLy8gQ2xvdWRGb3JtYXRpb24gaW50cmluc2ljcywgYW5kIHJlLXdyYXAgdGhvc2UgaW4gVG9rZW5zIHRoYXQgaGF2ZSBhXG4gICAgLy8gdG9KU09OKCkgbWV0aG9kIHJldHVybmluZyB0aGVpciBzdHJpbmcgcmVwcmVzZW50YXRpb24uIElmIHdlIHRoZW4gY2FsbFxuICAgIC8vIEpTT04uc3RyaW5naWZ5KCkgb24gdGhhdCByZXN1bHQsIHRoYXQgZ2l2ZXMgdXMgZXNzZW50aWFsbHkgdGhlIHNhbWVcbiAgICAvLyBzdHJpbmcgdGhhdCB3ZSBzdGFydGVkIHdpdGgsIGV4Y2VwdCB3aXRoIHRoZSBub24tdG9rZW4gY2hhcmFjdGVycyBxdW90ZWQuXG4gICAgLy9cbiAgICAvLyAgICB7XCJmaWVsZFwiOiBcIiR7VE9LRU59XCJ9IC0tPiB7XFxcImZpZWxkXFxcIjogXFxcIiR7VE9LRU59XFxcIn1cbiAgICAvL1xuICAgIC8vIEEgZmluYWwgcmVzb2x2ZSgpIG9uIHRoYXQgc3RyaW5nIChkb25lIGJ5IHRoZSBmcmFtZXdvcmspIHdpbGwgeWllbGQgdGhlIHN0cmluZ1xuICAgIC8vIHdlJ3JlIGFmdGVyLlxuICAgIC8vXG4gICAgLy8gUmVzb2x2aW5nIGFuZCB3cmFwcGluZyBhcmUgZG9uZSBpbiBnbyB1c2luZyB0aGUgcmVzb2x2ZXIgZnJhbWV3b3JrLlxuICAgIGNsYXNzIEludHJpbnNpbmNXcmFwcGVyIGV4dGVuZHMgRGVmYXVsdFRva2VuUmVzb2x2ZXIge1xuICAgICAgY29uc3RydWN0b3IoKSB7XG4gICAgICAgIHN1cGVyKENMT1VERk9STUFUSU9OX0NPTkNBVCk7XG4gICAgICB9XG5cbiAgICAgIHB1YmxpYyByZXNvbHZlVG9rZW4odDogSVJlc29sdmFibGUsIGNvbnRleHQ6IElSZXNvbHZlQ29udGV4dCwgcG9zdFByb2Nlc3M6IElQb3N0UHJvY2Vzc29yKSB7XG4gICAgICAgIC8vIFJldHVybiBSZWZlcmVuY2VzIGRpcmVjdGx5LCBzbyB0aGVpciB0eXBlIGlzIG1haW50YWluZWQgYW5kIHRoZSByZWZlcmVuY2VzIHdpbGxcbiAgICAgICAgLy8gY29udGludWUgdG8gd29yay4gT25seSB3aGlsZSBwcmVwYXJpbmcsIGJlY2F1c2Ugd2UgZG8gbmVlZCB0aGUgZmluYWwgdmFsdWUgb2YgdGhlXG4gICAgICAgIC8vIHRva2VuIHdoaWxlIHJlc29sdmluZy5cbiAgICAgICAgaWYgKFJlZmVyZW5jZS5pc1JlZmVyZW5jZSh0KSAmJiBjb250ZXh0LnByZXBhcmluZykgeyByZXR1cm4gd3JhcCh0KTsgfVxuXG4gICAgICAgIC8vIERlZXAtcmVzb2x2ZSBhbmQgd3JhcC4gVGhpcyBpcyBuZWNlc3NhcnkgZm9yIExhenkgdG9rZW5zIHNvIHdlIGNhbiBzZWUgXCJpbnNpZGVcIiB0aGVtLlxuICAgICAgICByZXR1cm4gd3JhcChzdXBlci5yZXNvbHZlVG9rZW4odCwgY29udGV4dCwgcG9zdFByb2Nlc3MpKTtcbiAgICAgIH1cbiAgICAgIHB1YmxpYyByZXNvbHZlU3RyaW5nKGZyYWdtZW50czogVG9rZW5pemVkU3RyaW5nRnJhZ21lbnRzLCBjb250ZXh0OiBJUmVzb2x2ZUNvbnRleHQpIHtcbiAgICAgICAgcmV0dXJuIHdyYXAoc3VwZXIucmVzb2x2ZVN0cmluZyhmcmFnbWVudHMsIGNvbnRleHQpKTtcbiAgICAgIH1cbiAgICAgIHB1YmxpYyByZXNvbHZlTGlzdChsOiBzdHJpbmdbXSwgY29udGV4dDogSVJlc29sdmVDb250ZXh0KSB7XG4gICAgICAgIHJldHVybiB3cmFwKHN1cGVyLnJlc29sdmVMaXN0KGwsIGNvbnRleHQpKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBXZSBuZWVkIGEgUmVzb2x2ZUNvbnRleHQgdG8gZ2V0IHN0YXJ0ZWQgc28gcmV0dXJuIGEgVG9rZW5cbiAgICByZXR1cm4gTGF6eS5zdHJpbmdWYWx1ZSh7XG4gICAgICBwcm9kdWNlOiAoY3R4OiBJUmVzb2x2ZUNvbnRleHQpID0+XG4gICAgICAgIEpTT04uc3RyaW5naWZ5KHJlc29sdmUob2JqLCB7XG4gICAgICAgICAgcHJlcGFyaW5nOiBjdHgucHJlcGFyaW5nLFxuICAgICAgICAgIHNjb3BlOiBjdHguc2NvcGUsXG4gICAgICAgICAgcmVzb2x2ZXI6IG5ldyBJbnRyaW5zaW5jV3JhcHBlcigpLFxuICAgICAgICB9KSwgdW5kZWZpbmVkLCBzcGFjZSksXG4gICAgfSk7XG5cbiAgICBmdW5jdGlvbiB3cmFwKHZhbHVlOiBhbnkpOiBhbnkge1xuICAgICAgcmV0dXJuIGlzSW50cmluc2ljKHZhbHVlKSA/IG5ldyBKc29uVG9rZW4oZGVlcFF1b3RlU3RyaW5nc0ZvckpTT04odmFsdWUpKSA6IHZhbHVlO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBQcm9kdWNlIGEgQ2xvdWRGb3JtYXRpb24gZXhwcmVzc2lvbiB0byBjb25jYXQgdHdvIGFyYml0cmFyeSBleHByZXNzaW9ucyB3aGVuIHJlc29sdmluZ1xuICAgKi9cbiAgcHVibGljIHN0YXRpYyBjb25jYXQobGVmdDogYW55IHwgdW5kZWZpbmVkLCByaWdodDogYW55IHwgdW5kZWZpbmVkKTogYW55IHtcbiAgICBpZiAobGVmdCA9PT0gdW5kZWZpbmVkICYmIHJpZ2h0ID09PSB1bmRlZmluZWQpIHsgcmV0dXJuICcnOyB9XG5cbiAgICBjb25zdCBwYXJ0cyA9IG5ldyBBcnJheTxhbnk+KCk7XG4gICAgaWYgKGxlZnQgIT09IHVuZGVmaW5lZCkgeyBwYXJ0cy5wdXNoKGxlZnQpOyB9XG4gICAgaWYgKHJpZ2h0ICE9PSB1bmRlZmluZWQpIHsgcGFydHMucHVzaChyaWdodCk7IH1cblxuICAgIC8vIFNvbWUgY2FzZSBhbmFseXNpcyB0byBwcm9kdWNlIG1pbmltYWwgZXhwcmVzc2lvbnNcbiAgICBpZiAocGFydHMubGVuZ3RoID09PSAxKSB7IHJldHVybiBwYXJ0c1swXTsgfVxuICAgIGlmIChwYXJ0cy5sZW5ndGggPT09IDIgJiYgdHlwZW9mIHBhcnRzWzBdID09PSAnc3RyaW5nJyAmJiB0eXBlb2YgcGFydHNbMV0gPT09ICdzdHJpbmcnKSB7XG4gICAgICByZXR1cm4gcGFydHNbMF0gKyBwYXJ0c1sxXTtcbiAgICB9XG5cbiAgICAvLyBPdGhlcndpc2UgcmV0dXJuIGEgSm9pbiBpbnRyaW5zaWMgKGFscmVhZHkgaW4gdGhlIHRhcmdldCBkb2N1bWVudCBsYW5ndWFnZSB0byBhdm9pZCB0YWtpbmdcbiAgICAvLyBjaXJjdWxhciBkZXBlbmRlbmNpZXMgb24gRm5Kb2luICYgZnJpZW5kcylcbiAgICByZXR1cm4geyAnRm46OkpvaW4nOiBbJycsIG1pbmltYWxDbG91ZEZvcm1hdGlvbkpvaW4oJycsIHBhcnRzKV0gfTtcbiAgfVxufVxuXG4vKipcbiAqIFRva2VuIHRoYXQgYWxzbyBzdHJpbmdpZmllcyBpbiB0aGUgdG9KU09OKCkgb3BlcmF0aW9uLlxuICovXG5jbGFzcyBKc29uVG9rZW4gZXh0ZW5kcyBJbnRyaW5zaWMge1xuICAvKipcbiAgICogU3BlY2lhbCBoYW5kbGVyIHRoYXQgZ2V0cyBjYWxsZWQgd2hlbiBKU09OLnN0cmluZ2lmeSgpIGlzIHVzZWQuXG4gICAqL1xuICBwdWJsaWMgdG9KU09OKCkge1xuICAgIHJldHVybiB0aGlzLnRvU3RyaW5nKCk7XG4gIH1cbn1cblxuLyoqXG4gKiBEZWVwIGVzY2FwZSBzdHJpbmdzIGZvciB1c2UgaW4gYSBKU09OIGNvbnRleHRcbiAqL1xuZnVuY3Rpb24gZGVlcFF1b3RlU3RyaW5nc0ZvckpTT04oeDogYW55KTogYW55IHtcbiAgaWYgKHR5cGVvZiB4ID09PSAnc3RyaW5nJykge1xuICAgIC8vIFdoZW5ldmVyIHdlIGVzY2FwZSBhIHN0cmluZyB3ZSBzdHJpcCBvZmYgdGhlIG91dGVybW9zdCBxdW90ZXNcbiAgICAvLyBzaW5jZSB3ZSdyZSBhbHJlYWR5IGluIGEgcXVvdGVkIGNvbnRleHQuXG4gICAgY29uc3Qgc3RyaW5naWZpZWQgPSBKU09OLnN0cmluZ2lmeSh4KTtcbiAgICByZXR1cm4gc3RyaW5naWZpZWQuc3Vic3RyaW5nKDEsIHN0cmluZ2lmaWVkLmxlbmd0aCAtIDEpO1xuICB9XG5cbiAgaWYgKEFycmF5LmlzQXJyYXkoeCkpIHtcbiAgICByZXR1cm4geC5tYXAoZGVlcFF1b3RlU3RyaW5nc0ZvckpTT04pO1xuICB9XG5cbiAgaWYgKHR5cGVvZiB4ID09PSAnb2JqZWN0Jykge1xuICAgIGZvciAoY29uc3Qga2V5IG9mIE9iamVjdC5rZXlzKHgpKSB7XG4gICAgICB4W2tleV0gPSBkZWVwUXVvdGVTdHJpbmdzRm9ySlNPTih4W2tleV0pO1xuICAgIH1cbiAgfVxuXG4gIHJldHVybiB4O1xufVxuXG5jb25zdCBDTE9VREZPUk1BVElPTl9DT05DQVQ6IElGcmFnbWVudENvbmNhdGVuYXRvciA9IHtcbiAgam9pbihsZWZ0OiBhbnksIHJpZ2h0OiBhbnkpIHtcbiAgICByZXR1cm4gQ2xvdWRGb3JtYXRpb25MYW5nLmNvbmNhdChsZWZ0LCByaWdodCk7XG4gIH0sXG59O1xuXG4vKipcbiAqIERlZmF1bHQgVG9rZW4gcmVzb2x2ZXIgZm9yIENsb3VkRm9ybWF0aW9uIHRlbXBsYXRlc1xuICovXG5leHBvcnQgY29uc3QgQ0xPVURGT1JNQVRJT05fVE9LRU5fUkVTT0xWRVIgPSBuZXcgRGVmYXVsdFRva2VuUmVzb2x2ZXIoQ0xPVURGT1JNQVRJT05fQ09OQ0FUKTtcblxuLyoqXG4gKiBEbyBhbiBpbnRlbGxpZ2VudCBDbG91ZEZvcm1hdGlvbiBqb2luIG9uIHRoZSBnaXZlbiB2YWx1ZXMsIHByb2R1Y2luZyBhIG1pbmltYWwgZXhwcmVzc2lvblxuICovXG5leHBvcnQgZnVuY3Rpb24gbWluaW1hbENsb3VkRm9ybWF0aW9uSm9pbihkZWxpbWl0ZXI6IHN0cmluZywgdmFsdWVzOiBhbnlbXSk6IGFueVtdIHtcbiAgbGV0IGkgPSAwO1xuICB3aGlsZSAoaSA8IHZhbHVlcy5sZW5ndGgpIHtcbiAgICBjb25zdCBlbCA9IHZhbHVlc1tpXTtcbiAgICBpZiAoaXNTcGxpY2FibGVGbkpvaW5JbnRyaW5zaWMoZWwpKSB7XG4gICAgICB2YWx1ZXMuc3BsaWNlKGksIDEsIC4uLmVsWydGbjo6Sm9pbiddWzFdKTtcbiAgICB9IGVsc2UgaWYgKGkgPiAwICYmIGlzUGxhaW5TdHJpbmcodmFsdWVzW2kgLSAxXSkgJiYgaXNQbGFpblN0cmluZyh2YWx1ZXNbaV0pKSB7XG4gICAgICB2YWx1ZXNbaSAtIDFdICs9IGRlbGltaXRlciArIHZhbHVlc1tpXTtcbiAgICAgIHZhbHVlcy5zcGxpY2UoaSwgMSk7XG4gICAgfSBlbHNlIHtcbiAgICAgIGkgKz0gMTtcbiAgICB9XG4gIH1cblxuICByZXR1cm4gdmFsdWVzO1xuXG4gIGZ1bmN0aW9uIGlzUGxhaW5TdHJpbmcob2JqOiBhbnkpOiBib29sZWFuIHtcbiAgICByZXR1cm4gdHlwZW9mIG9iaiA9PT0gJ3N0cmluZycgJiYgIVRva2VuLmlzVW5yZXNvbHZlZChvYmopO1xuICB9XG5cbiAgZnVuY3Rpb24gaXNTcGxpY2FibGVGbkpvaW5JbnRyaW5zaWMob2JqOiBhbnkpOiBib29sZWFuIHtcbiAgICBpZiAoIWlzSW50cmluc2ljKG9iaikpIHsgcmV0dXJuIGZhbHNlOyB9XG4gICAgaWYgKE9iamVjdC5rZXlzKG9iailbMF0gIT09ICdGbjo6Sm9pbicpIHsgcmV0dXJuIGZhbHNlOyB9XG5cbiAgICBjb25zdCBbZGVsaW0sIGxpc3RdID0gb2JqWydGbjo6Sm9pbiddO1xuICAgIGlmIChkZWxpbSAhPT0gZGVsaW1pdGVyKSB7IHJldHVybiBmYWxzZTsgfVxuXG4gICAgaWYgKFRva2VuLmlzVW5yZXNvbHZlZChsaXN0KSkgeyByZXR1cm4gZmFsc2U7IH1cbiAgICBpZiAoIUFycmF5LmlzQXJyYXkobGlzdCkpIHsgcmV0dXJuIGZhbHNlOyB9XG5cbiAgICByZXR1cm4gdHJ1ZTtcbiAgfVxufVxuXG4vKipcbiAqIFJldHVybiB3aGV0aGVyIHRoZSBnaXZlbiB2YWx1ZSByZXByZXNlbnRzIGEgQ2xvdWRGb3JtYXRpb24gaW50cmluc2ljXG4gKi9cbmZ1bmN0aW9uIGlzSW50cmluc2ljKHg6IGFueSkge1xuICBpZiAoQXJyYXkuaXNBcnJheSh4KSB8fCB4ID09PSBudWxsIHx8IHR5cGVvZiB4ICE9PSAnb2JqZWN0JykgeyByZXR1cm4gZmFsc2U7IH1cblxuICBjb25zdCBrZXlzID0gT2JqZWN0LmtleXMoeCk7XG4gIGlmIChrZXlzLmxlbmd0aCAhPT0gMSkgeyByZXR1cm4gZmFsc2U7IH1cblxuICByZXR1cm4ga2V5c1swXSA9PT0gJ1JlZicgfHwgaXNOYW1lT2ZDbG91ZEZvcm1hdGlvbkludHJpbnNpYyhrZXlzWzBdKTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGlzTmFtZU9mQ2xvdWRGb3JtYXRpb25JbnRyaW5zaWMobmFtZTogc3RyaW5nKTogYm9vbGVhbiB7XG4gIGlmICghbmFtZS5zdGFydHNXaXRoKCdGbjo6JykpIHtcbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cbiAgLy8gdGhlc2UgYXJlICdmYWtlJyBpbnRyaW5zaWNzLCBvbmx5IHVzYWJsZSBpbnNpZGUgdGhlIHBhcmFtZXRlciBvdmVycmlkZXMgb2YgYSBDRk4gQ29kZVBpcGVsaW5lIEFjdGlvblxuICByZXR1cm4gbmFtZSAhPT0gJ0ZuOjpHZXRBcnRpZmFjdEF0dCcgJiYgbmFtZSAhPT0gJ0ZuOjpHZXRQYXJhbSc7XG59XG4iXX0=