@aws-cdk/core
Version:
AWS Cloud Development Kit Core Library
208 lines • 24.2 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xvdWRmb3JtYXRpb24tbGFuZy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbImNsb3VkZm9ybWF0aW9uLWxhbmcudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUFBQSxrQ0FBK0I7QUFDL0IsNENBQXlDO0FBQ3pDLDhDQUEwSDtBQUUxSCxvQ0FBaUM7QUFDakMsMkNBQXdDO0FBQ3hDLHVDQUFvQztBQUVwQzs7R0FFRztBQUNILE1BQWEsa0JBQWtCO0lBQzdCOzs7Ozs7Ozs7Ozs7T0FZRztJQUNJLE1BQU0sQ0FBQyxNQUFNLENBQUMsR0FBUSxFQUFFLEtBQWM7UUFDM0MsNEJBQTRCO1FBQzVCLEVBQUU7UUFDRiwrRUFBK0U7UUFDL0UsaUZBQWlGO1FBQ2pGLHVEQUF1RDtRQUN2RCxFQUFFO1FBQ0YsNEVBQTRFO1FBQzVFLHFFQUFxRTtRQUNyRSx5RUFBeUU7UUFDekUsc0VBQXNFO1FBQ3RFLDRFQUE0RTtRQUM1RSxFQUFFO1FBQ0YseURBQXlEO1FBQ3pELEVBQUU7UUFDRixpRkFBaUY7UUFDakYsZUFBZTtRQUNmLEVBQUU7UUFDRixzRUFBc0U7UUFDdEUsTUFBTSxpQkFBa0IsU0FBUSxpQ0FBb0I7WUFDbEQ7Z0JBQ0UsS0FBSyxDQUFDLHFCQUFxQixDQUFDLENBQUM7WUFDL0IsQ0FBQztZQUVNLFlBQVksQ0FBQyxDQUFjLEVBQUUsT0FBd0IsRUFBRSxXQUEyQjtnQkFDdkYsa0ZBQWtGO2dCQUNsRixvRkFBb0Y7Z0JBQ3BGLHlCQUF5QjtnQkFDekIsSUFBSSxxQkFBUyxDQUFDLFdBQVcsQ0FBQyxDQUFDLENBQUMsSUFBSSxPQUFPLENBQUMsU0FBUyxFQUFFO29CQUFFLE9BQU8sSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDO2lCQUFFO2dCQUV0RSx3RkFBd0Y7Z0JBQ3hGLE9BQU8sSUFBSSxDQUFDLEtBQUssQ0FBQyxZQUFZLENBQUMsQ0FBQyxFQUFFLE9BQU8sRUFBRSxXQUFXLENBQUMsQ0FBQyxDQUFDO1lBQzNELENBQUM7WUFDTSxhQUFhLENB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SSxJQUFJLE9BQU8sQ0FBQyxLQUFLLFFBQVEsRUFBRTtRQUFFLE9BQU8sS0FBSyxDQUFDO0tBQUU7SUFFOUUsTUFBTSxJQUFJLEdBQUcsTUFBTSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUM1QixJQUFJLElBQUksQ0FBQyxNQUFNLEtBQUssQ0FBQyxFQUFFO1FBQUUsT0FBTyxLQUFLLENBQUM7S0FBRTtJQUV4QyxPQUFPLElBQUksQ0FBQyxDQUFDLENBQUMsS0FBSyxLQUFLLElBQUksK0JBQStCLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7QUFDdkUsQ0FBQztBQUVELFNBQWdCLCtCQUErQixDQUFDLElBQVk7SUFDMUQsSUFBSSxDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsTUFBTSxDQUFDLEVBQUU7UUFDNUIsT0FBTyxLQUFLLENBQUM7S0FDZDtJQUNELHVHQUF1RztJQUN2RyxPQUFPLElBQUksS0FBSyxvQkFBb0IsSUFBSSxJQUFJLEtBQUssY0FBYyxDQUFDO0FBQ2xFLENBQUM7QUFORCwwRUFNQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IExhenkgfSBmcm9tIFwiLi4vbGF6eVwiO1xuaW1wb3J0IHsgUmVmZXJlbmNlIH0gZnJvbSBcIi4uL3JlZmVyZW5jZVwiO1xuaW1wb3J0IHsgRGVmYXVsdFRva2VuUmVzb2x2ZXIsIElGcmFnbWVudENvbmNhdGVuYXRvciwgSVBvc3RQcm9jZXNzb3IsIElSZXNvbHZhYmxlLCBJUmVzb2x2ZUNvbnRleHQgfSBmcm9tIFwiLi4vcmVzb2x2YWJsZVwiO1xuaW1wb3J0IHsgVG9rZW5pemVkU3RyaW5nRnJhZ21lbnRzIH0gZnJvbSBcIi4uL3N0cmluZy1mcmFnbWVudHNcIjtcbmltcG9ydCB7IFRva2VuIH0gZnJvbSBcIi4uL3Rva2VuXCI7XG5pbXBvcnQgeyBJbnRyaW5zaWMgfSBmcm9tIFwiLi9pbnRyaW5zaWNcIjtcbmltcG9ydCB7IHJlc29sdmUgfSBmcm9tIFwiLi9yZXNvbHZlXCI7XG5cbi8qKlxuICogUm91dGluZXMgdGhhdCBrbm93IGhvdyB0byBkbyBvcGVyYXRpb25zIGF0IHRoZSBDbG91ZEZvcm1hdGlvbiBkb2N1bWVudCBsYW5ndWFnZSBsZXZlbFxuICovXG5leHBvcnQgY2xhc3MgQ2xvdWRGb3JtYXRpb25MYW5nIHtcbiAgLyoqXG4gICAqIFR1cm4gYW4gYXJiaXRyYXJ5IHN0cnVjdHVyZSBwb3RlbnRpYWxseSBjb250YWluaW5nIFRva2VucyBpbnRvIGEgSlNPTiBzdHJpbmcuXG4gICAqXG4gICAqIFJldHVybnMgYSBUb2tlbiB3aGljaCB3aWxsIGV2YWx1YXRlIHRvIENsb3VkRm9ybWF0aW9uIGV4cHJlc3Npb24gdGhhdFxuICAgKiB3aWxsIGJlIGV2YWx1YXRlZCBieSBDbG91ZEZvcm1hdGlvbiB0byB0aGUgSlNPTiByZXByZXNlbnRhdGlvbiBvZiB0aGVcbiAgICogaW5wdXQgc3RydWN0dXJlLlxuICAgKlxuICAgKiBBbGwgVG9rZW5zIHN1YnN0aXR1dGVkIGluIHRoaXMgd2F5IG11c3QgcmV0dXJuIHN0cmluZ3MsIG9yIHRoZSBldmFsdWF0aW9uXG4gICAqIGluIENsb3VkRm9ybWF0aW9uIHdpbGwgZmFpbC5cbiAgICpcbiAgICogQHBhcmFtIG9iaiBUaGUgb2JqZWN0IHRvIHN0cmluZ2lmeVxuICAgKiBAcGFyYW0gc3BhY2UgSW5kZW50YXRpb24gdG8gdXNlIChkZWZhdWx0OiBubyBwcmV0dHktcHJpbnRpbmcpXG4gICAqL1xuICBwdWJsaWMgc3RhdGljIHRvSlNPTihvYmo6IGFueSwgc3BhY2U/OiBudW1iZXIpOiBzdHJpbmcge1xuICAgIC8vIFRoaXMgd29ya3MgaW4gdHdvIHN0YWdlczpcbiAgICAvL1xuICAgIC8vIEZpcnN0LCByZXNvbHZlIGV2ZXJ5dGhpbmcuIFRoaXMgZ2V0cyByaWQgb2YgdGhlIGxhenkgZXZhbHVhdGlvbnMsIGV2YWx1YXRpb25cbiAgICAvLyB0byB0aGUgcmVhbCB0eXBlcyBvZiB0aGluZ3MgKGZvciBleGFtcGxlLCB3b3VsZCBhIGZ1bmN0aW9uIHJldHVybiBhIHN0cmluZywgYW5cbiAgICAvLyBpbnRyaW5zaWMsIG9yIGEgbnVtYmVyPyBXZSBoYXZlIHRvIHJlc29sdmUgdG8ga25vdykuXG4gICAgLy9cbiAgICAvLyBXZSB0aGVuIHRvIHRocm91Z2ggdGhlIHJldHVybmVkIHJlc3VsdCwgaWRlbnRpZnkgdGhpbmdzIHRoYXQgZXZhbHVhdGVkIHRvXG4gICAgLy8gQ2xvdWRGb3JtYXRpb24gaW50cmluc2ljcywgYW5kIHJlLXdyYXAgdGhvc2UgaW4gVG9rZW5zIHRoYXQgaGF2ZSBhXG4gICAgLy8gdG9KU09OKCkgbWV0aG9kIHJldHVybmluZyB0aGVpciBzdHJpbmcgcmVwcmVzZW50YXRpb24uIElmIHdlIHRoZW4gY2FsbFxuICAgIC8vIEpTT04uc3RyaW5naWZ5KCkgb24gdGhhdCByZXN1bHQsIHRoYXQgZ2l2ZXMgdXMgZXNzZW50aWFsbHkgdGhlIHNhbWVcbiAgICAvLyBzdHJpbmcgdGhhdCB3ZSBzdGFydGVkIHdpdGgsIGV4Y2VwdCB3aXRoIHRoZSBub24tdG9rZW4gY2hhcmFjdGVycyBxdW90ZWQuXG4gICAgLy9cbiAgICAvLyAgICB7XCJmaWVsZFwiOiBcIiR7VE9LRU59XCJ9IC0tPiB7XFxcImZpZWxkXFxcIjogXFxcIiR7VE9LRU59XFxcIn1cbiAgICAvL1xuICAgIC8vIEEgZmluYWwgcmVzb2x2ZSgpIG9uIHRoYXQgc3RyaW5nIChkb25lIGJ5IHRoZSBmcmFtZXdvcmspIHdpbGwgeWllbGQgdGhlIHN0cmluZ1xuICAgIC8vIHdlJ3JlIGFmdGVyLlxuICAgIC8vXG4gICAgLy8gUmVzb2x2aW5nIGFuZCB3cmFwcGluZyBhcmUgZG9uZSBpbiBnbyB1c2luZyB0aGUgcmVzb2x2ZXIgZnJhbWV3b3JrLlxuICAgIGNsYXNzIEludHJpbnNpbmNXcmFwcGVyIGV4dGVuZHMgRGVmYXVsdFRva2VuUmVzb2x2ZXIge1xuICAgICAgY29uc3RydWN0b3IoKSB7XG4gICAgICAgIHN1cGVyKENMT1VERk9STUFUSU9OX0NPTkNBVCk7XG4gICAgICB9XG5cbiAgICAgIHB1YmxpYyByZXNvbHZlVG9rZW4odDogSVJlc29sdmFibGUsIGNvbnRleHQ6IElSZXNvbHZlQ29udGV4dCwgcG9zdFByb2Nlc3M6IElQb3N0UHJvY2Vzc29yKSB7XG4gICAgICAgIC8vIFJldHVybiBSZWZlcmVuY2VzIGRpcmVjdGx5LCBzbyB0aGVpciB0eXBlIGlzIG1haW50YWluZWQgYW5kIHRoZSByZWZlcmVuY2VzIHdpbGxcbiAgICAgICAgLy8gY29udGludWUgdG8gd29yay4gT25seSB3aGlsZSBwcmVwYXJpbmcsIGJlY2F1c2Ugd2UgZG8gbmVlZCB0aGUgZmluYWwgdmFsdWUgb2YgdGhlXG4gICAgICAgIC8vIHRva2VuIHdoaWxlIHJlc29sdmluZy5cbiAgICAgICAgaWYgKFJlZmVyZW5jZS5pc1JlZmVyZW5jZSh0KSAmJiBjb250ZXh0LnByZXBhcmluZykgeyByZXR1cm4gd3JhcCh0KTsgfVxuXG4gICAgICAgIC8vIERlZXAtcmVzb2x2ZSBhbmQgd3JhcC4gVGhpcyBpcyBuZWNlc3NhcnkgZm9yIExhenkgdG9rZW5zIHNvIHdlIGNhbiBzZWUgXCJpbnNpZGVcIiB0aGVtLlxuICAgICAgICByZXR1cm4gd3JhcChzdXBlci5yZXNvbHZlVG9rZW4odCwgY29udGV4dCwgcG9zdFByb2Nlc3MpKTtcbiAgICAgIH1cbiAgICAgIHB1YmxpYyByZXNvbHZlU3RyaW5nKGZyYWdtZW50czogVG9rZW5pemVkU3RyaW5nRnJhZ21lbnRzLCBjb250ZXh0OiBJUmVzb2x2ZUNvbnRleHQpIHtcbiAgICAgICAgcmV0dXJuIHdyYXAoc3VwZXIucmVzb2x2ZVN0cmluZyhmcmFnbWVudHMsIGNvbnRleHQpKTtcbiAgICAgIH1cbiAgICAgIHB1YmxpYyByZXNvbHZlTGlzdChsOiBzdHJpbmdbXSwgY29udGV4dDogSVJlc29sdmVDb250ZXh0KSB7XG4gICAgICAgIHJldHVybiB3cmFwKHN1cGVyLnJlc29sdmVMaXN0KGwsIGNvbnRleHQpKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBXZSBuZWVkIGEgUmVzb2x2ZUNvbnRleHQgdG8gZ2V0IHN0YXJ0ZWQgc28gcmV0dXJuIGEgVG9rZW5cbiAgICByZXR1cm4gTGF6eS5zdHJpbmdWYWx1ZSh7IHByb2R1Y2U6IChjdHg6IElSZXNvbHZlQ29udGV4dCkgPT5cbiAgICAgIEpTT04uc3RyaW5naWZ5KHJlc29sdmUob2JqLCB7XG4gICAgICAgIHByZXBhcmluZzogY3R4LnByZXBhcmluZyxcbiAgICAgICAgc2NvcGU6IGN0eC5zY29wZSxcbiAgICAgICAgcmVzb2x2ZXI6IG5ldyBJbnRyaW5zaW5jV3JhcHBlcigpXG4gICAgICB9KSwgdW5kZWZpbmVkLCBzcGFjZSlcbiAgICB9KTtcblxuICAgIGZ1bmN0aW9uIHdyYXAodmFsdWU6IGFueSk6IGFueSB7XG4gICAgICByZXR1cm4gaXNJbnRyaW5zaWModmFsdWUpID8gbmV3IEpzb25Ub2tlbihkZWVwUXVvdGVTdHJpbmdzRm9ySlNPTih2YWx1ZSkpIDogdmFsdWU7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFByb2R1Y2UgYSBDbG91ZEZvcm1hdGlvbiBleHByZXNzaW9uIHRvIGNvbmNhdCB0d28gYXJiaXRyYXJ5IGV4cHJlc3Npb25zIHdoZW4gcmVzb2x2aW5nXG4gICAqL1xuICBwdWJsaWMgc3RhdGljIGNvbmNhdChsZWZ0OiBhbnkgfCB1bmRlZmluZWQsIHJpZ2h0OiBhbnkgfCB1bmRlZmluZWQpOiBhbnkge1xuICAgIGlmIChsZWZ0ID09PSB1bmRlZmluZWQgJiYgcmlnaHQgPT09IHVuZGVmaW5lZCkgeyByZXR1cm4gJyc7IH1cblxuICAgIGNvbnN0IHBhcnRzID0gbmV3IEFycmF5PGFueT4oKTtcbiAgICBpZiAobGVmdCAhPT0gdW5kZWZpbmVkKSB7IHBhcnRzLnB1c2gobGVmdCk7IH1cbiAgICBpZiAocmlnaHQgIT09IHVuZGVmaW5lZCkgeyBwYXJ0cy5wdXNoKHJpZ2h0KTsgfVxuXG4gICAgLy8gU29tZSBjYXNlIGFuYWx5c2lzIHRvIHByb2R1Y2UgbWluaW1hbCBleHByZXNzaW9uc1xuICAgIGlmIChwYXJ0cy5sZW5ndGggPT09IDEpIHsgcmV0dXJuIHBhcnRzWzBdOyB9XG4gICAgaWYgKHBhcnRzLmxlbmd0aCA9PT0gMiAmJiB0eXBlb2YgcGFydHNbMF0gPT09ICdzdHJpbmcnICYmIHR5cGVvZiBwYXJ0c1sxXSA9PT0gJ3N0cmluZycpIHtcbiAgICAgIHJldHVybiBwYXJ0c1swXSArIHBhcnRzWzFdO1xuICAgIH1cblxuICAgIC8vIE90aGVyd2lzZSByZXR1cm4gYSBKb2luIGludHJpbnNpYyAoYWxyZWFkeSBpbiB0aGUgdGFyZ2V0IGRvY3VtZW50IGxhbmd1YWdlIHRvIGF2b2lkIHRha2luZ1xuICAgIC8vIGNpcmN1bGFyIGRlcGVuZGVuY2llcyBvbiBGbkpvaW4gJiBmcmllbmRzKVxuICAgIHJldHVybiB7ICdGbjo6Sm9pbic6IFsnJywgbWluaW1hbENsb3VkRm9ybWF0aW9uSm9pbignJywgcGFydHMpXSB9O1xuICB9XG59XG5cbi8qKlxuICogVG9rZW4gdGhhdCBhbHNvIHN0cmluZ2lmaWVzIGluIHRoZSB0b0pTT04oKSBvcGVyYXRpb24uXG4gKi9cbmNsYXNzIEpzb25Ub2tlbiBleHRlbmRzIEludHJpbnNpYyB7XG4gIC8qKlxuICAgKiBTcGVjaWFsIGhhbmRsZXIgdGhhdCBnZXRzIGNhbGxlZCB3aGVuIEpTT04uc3RyaW5naWZ5KCkgaXMgdXNlZC5cbiAgICovXG4gIHB1YmxpYyB0b0pTT04oKSB7XG4gICAgcmV0dXJuIHRoaXMudG9TdHJpbmcoKTtcbiAgfVxufVxuXG4vKipcbiAqIERlZXAgZXNjYXBlIHN0cmluZ3MgZm9yIHVzZSBpbiBhIEpTT04gY29udGV4dFxuICovXG5mdW5jdGlvbiBkZWVwUXVvdGVTdHJpbmdzRm9ySlNPTih4OiBhbnkpOiBhbnkge1xuICBpZiAodHlwZW9mIHggPT09ICdzdHJpbmcnKSB7XG4gICAgLy8gV2hlbmV2ZXIgd2UgZXNjYXBlIGEgc3RyaW5nIHdlIHN0cmlwIG9mZiB0aGUgb3V0ZXJtb3N0IHF1b3Rlc1xuICAgIC8vIHNpbmNlIHdlJ3JlIGFscmVhZHkgaW4gYSBxdW90ZWQgY29udGV4dC5cbiAgICBjb25zdCBzdHJpbmdpZmllZCA9IEpTT04uc3RyaW5naWZ5KHgpO1xuICAgIHJldHVybiBzdHJpbmdpZmllZC5zdWJzdHJpbmcoMSwgc3RyaW5naWZpZWQubGVuZ3RoIC0gMSk7XG4gIH1cblxuICBpZiAoQXJyYXkuaXNBcnJheSh4KSkge1xuICAgIHJldHVybiB4Lm1hcChkZWVwUXVvdGVTdHJpbmdzRm9ySlNPTik7XG4gIH1cblxuICBpZiAodHlwZW9mIHggPT09ICdvYmplY3QnKSB7XG4gICAgZm9yIChjb25zdCBrZXkgb2YgT2JqZWN0LmtleXMoeCkpIHtcbiAgICAgIHhba2V5XSA9IGRlZXBRdW90ZVN0cmluZ3NGb3JKU09OKHhba2V5XSk7XG4gICAgfVxuICB9XG5cbiAgcmV0dXJuIHg7XG59XG5cbmNvbnN0IENMT1VERk9STUFUSU9OX0NPTkNBVDogSUZyYWdtZW50Q29uY2F0ZW5hdG9yID0ge1xuICBqb2luKGxlZnQ6IGFueSwgcmlnaHQ6IGFueSkge1xuICAgIHJldHVybiBDbG91ZEZvcm1hdGlvbkxhbmcuY29uY2F0KGxlZnQsIHJpZ2h0KTtcbiAgfVxufTtcblxuLyoqXG4gKiBEZWZhdWx0IFRva2VuIHJlc29sdmVyIGZvciBDbG91ZEZvcm1hdGlvbiB0ZW1wbGF0ZXNcbiAqL1xuZXhwb3J0IGNvbnN0IENMT1VERk9STUFUSU9OX1RPS0VOX1JFU09MVkVSID0gbmV3IERlZmF1bHRUb2tlblJlc29sdmVyKENMT1VERk9STUFUSU9OX0NPTkNBVCk7XG5cbi8qKlxuICogRG8gYW4gaW50ZWxsaWdlbnQgQ2xvdWRGb3JtYXRpb24gam9pbiBvbiB0aGUgZ2l2ZW4gdmFsdWVzLCBwcm9kdWNpbmcgYSBtaW5pbWFsIGV4cHJlc3Npb25cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIG1pbmltYWxDbG91ZEZvcm1hdGlvbkpvaW4oZGVsaW1pdGVyOiBzdHJpbmcsIHZhbHVlczogYW55W10pOiBhbnlbXSB7XG4gIGxldCBpID0gMDtcbiAgd2hpbGUgKGkgPCB2YWx1ZXMubGVuZ3RoKSB7XG4gICAgY29uc3QgZWwgPSB2YWx1ZXNbaV07XG4gICAgaWYgKGlzU3BsaWNhYmxlRm5Kb2luSW50cmluc2ljKGVsKSkge1xuICAgICAgdmFsdWVzLnNwbGljZShpLCAxLCAuLi5lbFsnRm46OkpvaW4nXVsxXSk7XG4gICAgfSBlbHNlIGlmIChpID4gMCAmJiBpc1BsYWluU3RyaW5nKHZhbHVlc1tpIC0gMV0pICYmIGlzUGxhaW5TdHJpbmcodmFsdWVzW2ldKSkge1xuICAgICAgdmFsdWVzW2kgLSAxXSArPSBkZWxpbWl0ZXIgKyB2YWx1ZXNbaV07XG4gICAgICB2YWx1ZXMuc3BsaWNlKGksIDEpO1xuICAgIH0gZWxzZSB7XG4gICAgICBpICs9IDE7XG4gICAgfVxuICB9XG5cbiAgcmV0dXJuIHZhbHVlcztcblxuICBmdW5jdGlvbiBpc1BsYWluU3RyaW5nKG9iajogYW55KTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHR5cGVvZiBvYmogPT09ICdzdHJpbmcnICYmICFUb2tlbi5pc1VucmVzb2x2ZWQob2JqKTtcbiAgfVxuXG4gIGZ1bmN0aW9uIGlzU3BsaWNhYmxlRm5Kb2luSW50cmluc2ljKG9iajogYW55KTogYm9vbGVhbiB7XG4gICAgaWYgKCFpc0ludHJpbnNpYyhvYmopKSB7IHJldHVybiBmYWxzZTsgfVxuICAgIGlmIChPYmplY3Qua2V5cyhvYmopWzBdICE9PSAnRm46OkpvaW4nKSB7IHJldHVybiBmYWxzZTsgIH1cblxuICAgIGNvbnN0IFsgZGVsaW0sIGxpc3QgXSA9IG9ialsnRm46OkpvaW4nXTtcbiAgICBpZiAoZGVsaW0gIT09IGRlbGltaXRlcikgeyByZXR1cm4gZmFsc2U7IH1cblxuICAgIGlmIChUb2tlbi5pc1VucmVzb2x2ZWQobGlzdCkpIHsgcmV0dXJuIGZhbHNlOyB9XG4gICAgaWYgKCFBcnJheS5pc0FycmF5KGxpc3QpKSB7IHJldHVybiBmYWxzZTsgfVxuXG4gICAgcmV0dXJuIHRydWU7XG4gIH1cbn1cblxuLyoqXG4gKiBSZXR1cm4gd2hldGhlciB0aGUgZ2l2ZW4gdmFsdWUgcmVwcmVzZW50cyBhIENsb3VkRm9ybWF0aW9uIGludHJpbnNpY1xuICovXG5mdW5jdGlvbiBpc0ludHJpbnNpYyh4OiBhbnkpIHtcbiAgaWYgKEFycmF5LmlzQXJyYXkoeCkgfHwgeCA9PT0gbnVsbCB8fCB0eXBlb2YgeCAhPT0gJ29iamVjdCcpIHsgcmV0dXJuIGZhbHNlOyB9XG5cbiAgY29uc3Qga2V5cyA9IE9iamVjdC5rZXlzKHgpO1xuICBpZiAoa2V5cy5sZW5ndGggIT09IDEpIHsgcmV0dXJuIGZhbHNlOyB9XG5cbiAgcmV0dXJuIGtleXNbMF0gPT09ICdSZWYnIHx8IGlzTmFtZU9mQ2xvdWRGb3JtYXRpb25JbnRyaW5zaWMoa2V5c1swXSk7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBpc05hbWVPZkNsb3VkRm9ybWF0aW9uSW50cmluc2ljKG5hbWU6IHN0cmluZyk6IGJvb2xlYW4ge1xuICBpZiAoIW5hbWUuc3RhcnRzV2l0aCgnRm46OicpKSB7XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG4gIC8vIHRoZXNlIGFyZSAnZmFrZScgaW50cmluc2ljcywgb25seSB1c2FibGUgaW5zaWRlIHRoZSBwYXJhbWV0ZXIgb3ZlcnJpZGVzIG9mIGEgQ0ZOIENvZGVQaXBlbGluZSBBY3Rpb25cbiAgcmV0dXJuIG5hbWUgIT09ICdGbjo6R2V0QXJ0aWZhY3RBdHQnICYmIG5hbWUgIT09ICdGbjo6R2V0UGFyYW0nO1xufVxuIl19