@aws-cdk/core
Version:
AWS Cloud Development Kit Core Library
194 lines • 23.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) {
return isIntrinsic(obj)
&& Object.keys(obj)[0] === 'Fn::Join'
&& obj['Fn::Join'][0] === delimiter;
}
}
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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xvdWRmb3JtYXRpb24tbGFuZy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbImNsb3VkZm9ybWF0aW9uLWxhbmcudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUFBQSxrQ0FBK0I7QUFDL0IsNENBQXlDO0FBQ3pDLDhDQUEySDtBQUUzSCxvQ0FBaUM7QUFDakMsMkNBQXdDO0FBQ3hDLHVDQUFvQztBQUVwQzs7R0FFRztBQUNILE1BQWEsa0JBQWtCO0lBQzdCOzs7Ozs7Ozs7Ozs7T0FZRztJQUNJLE1BQU0sQ0FBQyxNQUFNLENBQUMsR0FBUSxFQUFFLEtBQWM7UUFDM0MsNEJBQTRCO1FBQzVCLEVBQUU7UUFDRiwrRUFBK0U7UUFDL0UsaUZBQWlGO1FBQ2pGLHVEQUF1RDtRQUN2RCxFQUFFO1FBQ0YsNEVBQTRFO1FBQzVFLHFFQUFxRTtRQUNyRSx5RUFBeUU7UUFDekUsc0VBQXNFO1FBQ3RFLDRFQUE0RTtRQUM1RSxFQUFFO1FBQ0YseURBQXlEO1FBQ3pELEVBQUU7UUFDRixpRkFBaUY7UUFDakYsZUFBZTtRQUNmLEVBQUU7UUFDRixzRUFBc0U7UUFDdEUsTUFBTSxpQkFBa0IsU0FBUSxpQ0FBb0I7WUFDbEQ7Z0JBQ0UsS0FBSyxDQUFDLHFCQUFxQixDQUFDLENBQUM7WUFDL0IsQ0FBQztZQUVNLFlBQVksQ0FBQyxDQUFjLEVBQUUsT0FBd0IsRUFBRSxXQUEyQjtnQkFDdkYsa0ZBQWtGO2dCQUNsRixvRkFBb0Y7Z0JBQ3BGLHlCQUF5QjtnQkFDekIsSUFBSSxxQkFBUyxDQUFDLFdBQVcsQ0FBQyxDQUFDLENBQUMsSUFBSSxPQUFPLENBQUMsU0FBUyxFQUFFO29CQUFFLE9BQU8sSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDO2lCQUFFO2dCQUV0RSx3RkFBd0Y7Z0JBQ3hGLE9BQU8sSUFBSSxDQUFDLEtBQUssQ0FBQyxZQUFZLENBQUMsQ0FBQyxFQUFFLE9BQU8sRUFBRSxXQUFXLENBQUMsQ0FBQyxDQUFDO1lBQzNELENBQUM7WUFDTSxhQUFhLENB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QVk7SUFDMUQsSUFBSSxDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsTUFBTSxDQUFDLEVBQUU7UUFDNUIsT0FBTyxLQUFLLENBQUM7S0FDZDtJQUNELHVHQUF1RztJQUN2RyxPQUFPLElBQUksS0FBSyxvQkFBb0IsSUFBSSxJQUFJLEtBQUssY0FBYyxDQUFDO0FBQ2xFLENBQUM7QUFORCwwRUFNQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IExhenkgfSBmcm9tIFwiLi4vbGF6eVwiO1xuaW1wb3J0IHsgUmVmZXJlbmNlIH0gZnJvbSBcIi4uL3JlZmVyZW5jZVwiO1xuaW1wb3J0IHsgRGVmYXVsdFRva2VuUmVzb2x2ZXIsIElGcmFnbWVudENvbmNhdGVuYXRvciwgSVBvc3RQcm9jZXNzb3IsIElSZXNvbHZhYmxlLCBJUmVzb2x2ZUNvbnRleHQgIH0gZnJvbSBcIi4uL3Jlc29sdmFibGVcIjtcbmltcG9ydCB7IFRva2VuaXplZFN0cmluZ0ZyYWdtZW50cyB9IGZyb20gXCIuLi9zdHJpbmctZnJhZ21lbnRzXCI7XG5pbXBvcnQgeyBUb2tlbiB9IGZyb20gXCIuLi90b2tlblwiO1xuaW1wb3J0IHsgSW50cmluc2ljIH0gZnJvbSBcIi4vaW50cmluc2ljXCI7XG5pbXBvcnQgeyByZXNvbHZlIH0gZnJvbSBcIi4vcmVzb2x2ZVwiO1xuXG4vKipcbiAqIFJvdXRpbmVzIHRoYXQga25vdyBob3cgdG8gZG8gb3BlcmF0aW9ucyBhdCB0aGUgQ2xvdWRGb3JtYXRpb24gZG9jdW1lbnQgbGFuZ3VhZ2UgbGV2ZWxcbiAqL1xuZXhwb3J0IGNsYXNzIENsb3VkRm9ybWF0aW9uTGFuZyB7XG4gIC8qKlxuICAgKiBUdXJuIGFuIGFyYml0cmFyeSBzdHJ1Y3R1cmUgcG90ZW50aWFsbHkgY29udGFpbmluZyBUb2tlbnMgaW50byBhIEpTT04gc3RyaW5nLlxuICAgKlxuICAgKiBSZXR1cm5zIGEgVG9rZW4gd2hpY2ggd2lsbCBldmFsdWF0ZSB0byBDbG91ZEZvcm1hdGlvbiBleHByZXNzaW9uIHRoYXRcbiAgICogd2lsbCBiZSBldmFsdWF0ZWQgYnkgQ2xvdWRGb3JtYXRpb24gdG8gdGhlIEpTT04gcmVwcmVzZW50YXRpb24gb2YgdGhlXG4gICAqIGlucHV0IHN0cnVjdHVyZS5cbiAgICpcbiAgICogQWxsIFRva2VucyBzdWJzdGl0dXRlZCBpbiB0aGlzIHdheSBtdXN0IHJldHVybiBzdHJpbmdzLCBvciB0aGUgZXZhbHVhdGlvblxuICAgKiBpbiBDbG91ZEZvcm1hdGlvbiB3aWxsIGZhaWwuXG4gICAqXG4gICAqIEBwYXJhbSBvYmogVGhlIG9iamVjdCB0byBzdHJpbmdpZnlcbiAgICogQHBhcmFtIHNwYWNlIEluZGVudGF0aW9uIHRvIHVzZSAoZGVmYXVsdDogbm8gcHJldHR5LXByaW50aW5nKVxuICAgKi9cbiAgcHVibGljIHN0YXRpYyB0b0pTT04ob2JqOiBhbnksIHNwYWNlPzogbnVtYmVyKTogc3RyaW5nIHtcbiAgICAvLyBUaGlzIHdvcmtzIGluIHR3byBzdGFnZXM6XG4gICAgLy9cbiAgICAvLyBGaXJzdCwgcmVzb2x2ZSBldmVyeXRoaW5nLiBUaGlzIGdldHMgcmlkIG9mIHRoZSBsYXp5IGV2YWx1YXRpb25zLCBldmFsdWF0aW9uXG4gICAgLy8gdG8gdGhlIHJlYWwgdHlwZXMgb2YgdGhpbmdzIChmb3IgZXhhbXBsZSwgd291bGQgYSBmdW5jdGlvbiByZXR1cm4gYSBzdHJpbmcsIGFuXG4gICAgLy8gaW50cmluc2ljLCBvciBhIG51bWJlcj8gV2UgaGF2ZSB0byByZXNvbHZlIHRvIGtub3cpLlxuICAgIC8vXG4gICAgLy8gV2UgdGhlbiB0byB0aHJvdWdoIHRoZSByZXR1cm5lZCByZXN1bHQsIGlkZW50aWZ5IHRoaW5ncyB0aGF0IGV2YWx1YXRlZCB0b1xuICAgIC8vIENsb3VkRm9ybWF0aW9uIGludHJpbnNpY3MsIGFuZCByZS13cmFwIHRob3NlIGluIFRva2VucyB0aGF0IGhhdmUgYVxuICAgIC8vIHRvSlNPTigpIG1ldGhvZCByZXR1cm5pbmcgdGhlaXIgc3RyaW5nIHJlcHJlc2VudGF0aW9uLiBJZiB3ZSB0aGVuIGNhbGxcbiAgICAvLyBKU09OLnN0cmluZ2lmeSgpIG9uIHRoYXQgcmVzdWx0LCB0aGF0IGdpdmVzIHVzIGVzc2VudGlhbGx5IHRoZSBzYW1lXG4gICAgLy8gc3RyaW5nIHRoYXQgd2Ugc3RhcnRlZCB3aXRoLCBleGNlcHQgd2l0aCB0aGUgbm9uLXRva2VuIGNoYXJhY3RlcnMgcXVvdGVkLlxuICAgIC8vXG4gICAgLy8gICAge1wiZmllbGRcIjogXCIke1RPS0VOfVwifSAtLT4ge1xcXCJmaWVsZFxcXCI6IFxcXCIke1RPS0VOfVxcXCJ9XG4gICAgLy9cbiAgICAvLyBBIGZpbmFsIHJlc29sdmUoKSBvbiB0aGF0IHN0cmluZyAoZG9uZSBieSB0aGUgZnJhbWV3b3JrKSB3aWxsIHlpZWxkIHRoZSBzdHJpbmdcbiAgICAvLyB3ZSdyZSBhZnRlci5cbiAgICAvL1xuICAgIC8vIFJlc29sdmluZyBhbmQgd3JhcHBpbmcgYXJlIGRvbmUgaW4gZ28gdXNpbmcgdGhlIHJlc29sdmVyIGZyYW1ld29yay5cbiAgICBjbGFzcyBJbnRyaW5zaW5jV3JhcHBlciBleHRlbmRzIERlZmF1bHRUb2tlblJlc29sdmVyIHtcbiAgICAgIGNvbnN0cnVjdG9yKCkge1xuICAgICAgICBzdXBlcihDTE9VREZPUk1BVElPTl9DT05DQVQpO1xuICAgICAgfVxuXG4gICAgICBwdWJsaWMgcmVzb2x2ZVRva2VuKHQ6IElSZXNvbHZhYmxlLCBjb250ZXh0OiBJUmVzb2x2ZUNvbnRleHQsIHBvc3RQcm9jZXNzOiBJUG9zdFByb2Nlc3Nvcikge1xuICAgICAgICAvLyBSZXR1cm4gUmVmZXJlbmNlcyBkaXJlY3RseSwgc28gdGhlaXIgdHlwZSBpcyBtYWludGFpbmVkIGFuZCB0aGUgcmVmZXJlbmNlcyB3aWxsXG4gICAgICAgIC8vIGNvbnRpbnVlIHRvIHdvcmsuIE9ubHkgd2hpbGUgcHJlcGFyaW5nLCBiZWNhdXNlIHdlIGRvIG5lZWQgdGhlIGZpbmFsIHZhbHVlIG9mIHRoZVxuICAgICAgICAvLyB0b2tlbiB3aGlsZSByZXNvbHZpbmcuXG4gICAgICAgIGlmIChSZWZlcmVuY2UuaXNSZWZlcmVuY2UodCkgJiYgY29udGV4dC5wcmVwYXJpbmcpIHsgcmV0dXJuIHdyYXAodCk7IH1cblxuICAgICAgICAvLyBEZWVwLXJlc29sdmUgYW5kIHdyYXAuIFRoaXMgaXMgbmVjZXNzYXJ5IGZvciBMYXp5IHRva2VucyBzbyB3ZSBjYW4gc2VlIFwiaW5zaWRlXCIgdGhlbS5cbiAgICAgICAgcmV0dXJuIHdyYXAoc3VwZXIucmVzb2x2ZVRva2VuKHQsIGNvbnRleHQsIHBvc3RQcm9jZXNzKSk7XG4gICAgICB9XG4gICAgICBwdWJsaWMgcmVzb2x2ZVN0cmluZyhmcmFnbWVudHM6IFRva2VuaXplZFN0cmluZ0ZyYWdtZW50cywgY29udGV4dDogSVJlc29sdmVDb250ZXh0KSB7XG4gICAgICAgIHJldHVybiB3cmFwKHN1cGVyLnJlc29sdmVTdHJpbmcoZnJhZ21lbnRzLCBjb250ZXh0KSk7XG4gICAgICB9XG4gICAgICBwdWJsaWMgcmVzb2x2ZUxpc3QobDogc3RyaW5nW10sIGNvbnRleHQ6IElSZXNvbHZlQ29udGV4dCkge1xuICAgICAgICByZXR1cm4gd3JhcChzdXBlci5yZXNvbHZlTGlzdChsLCBjb250ZXh0KSk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgLy8gV2UgbmVlZCBhIFJlc29sdmVDb250ZXh0IHRvIGdldCBzdGFydGVkIHNvIHJldHVybiBhIFRva2VuXG4gICAgcmV0dXJuIExhenkuc3RyaW5nVmFsdWUoeyBwcm9kdWNlOiAoY3R4OiBJUmVzb2x2ZUNvbnRleHQpID0+XG4gICAgICBKU09OLnN0cmluZ2lmeShyZXNvbHZlKG9iaiwge1xuICAgICAgICBwcmVwYXJpbmc6IGN0eC5wcmVwYXJpbmcsXG4gICAgICAgIHNjb3BlOiBjdHguc2NvcGUsXG4gICAgICAgIHJlc29sdmVyOiBuZXcgSW50cmluc2luY1dyYXBwZXIoKVxuICAgICAgfSksIHVuZGVmaW5lZCwgc3BhY2UpXG4gICAgfSk7XG5cbiAgICBmdW5jdGlvbiB3cmFwKHZhbHVlOiBhbnkpOiBhbnkge1xuICAgICAgcmV0dXJuIGlzSW50cmluc2ljKHZhbHVlKSA/IG5ldyBKc29uVG9rZW4oZGVlcFF1b3RlU3RyaW5nc0ZvckpTT04odmFsdWUpKSA6IHZhbHVlO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBQcm9kdWNlIGEgQ2xvdWRGb3JtYXRpb24gZXhwcmVzc2lvbiB0byBjb25jYXQgdHdvIGFyYml0cmFyeSBleHByZXNzaW9ucyB3aGVuIHJlc29sdmluZ1xuICAgKi9cbiAgcHVibGljIHN0YXRpYyBjb25jYXQobGVmdDogYW55IHwgdW5kZWZpbmVkLCByaWdodDogYW55IHwgdW5kZWZpbmVkKTogYW55IHtcbiAgICBpZiAobGVmdCA9PT0gdW5kZWZpbmVkICYmIHJpZ2h0ID09PSB1bmRlZmluZWQpIHsgcmV0dXJuICcnOyB9XG5cbiAgICBjb25zdCBwYXJ0cyA9IG5ldyBBcnJheTxhbnk+KCk7XG4gICAgaWYgKGxlZnQgIT09IHVuZGVmaW5lZCkgeyBwYXJ0cy5wdXNoKGxlZnQpOyB9XG4gICAgaWYgKHJpZ2h0ICE9PSB1bmRlZmluZWQpIHsgcGFydHMucHVzaChyaWdodCk7IH1cblxuICAgIC8vIFNvbWUgY2FzZSBhbmFseXNpcyB0byBwcm9kdWNlIG1pbmltYWwgZXhwcmVzc2lvbnNcbiAgICBpZiAocGFydHMubGVuZ3RoID09PSAxKSB7IHJldHVybiBwYXJ0c1swXTsgfVxuICAgIGlmIChwYXJ0cy5sZW5ndGggPT09IDIgJiYgdHlwZW9mIHBhcnRzWzBdID09PSAnc3RyaW5nJyAmJiB0eXBlb2YgcGFydHNbMV0gPT09ICdzdHJpbmcnKSB7XG4gICAgICByZXR1cm4gcGFydHNbMF0gKyBwYXJ0c1sxXTtcbiAgICB9XG5cbiAgICAvLyBPdGhlcndpc2UgcmV0dXJuIGEgSm9pbiBpbnRyaW5zaWMgKGFscmVhZHkgaW4gdGhlIHRhcmdldCBkb2N1bWVudCBsYW5ndWFnZSB0byBhdm9pZCB0YWtpbmdcbiAgICAvLyBjaXJjdWxhciBkZXBlbmRlbmNpZXMgb24gRm5Kb2luICYgZnJpZW5kcylcbiAgICByZXR1cm4geyAnRm46OkpvaW4nOiBbJycsIG1pbmltYWxDbG91ZEZvcm1hdGlvbkpvaW4oJycsIHBhcnRzKV0gfTtcbiAgfVxufVxuXG4vKipcbiAqIFRva2VuIHRoYXQgYWxzbyBzdHJpbmdpZmllcyBpbiB0aGUgdG9KU09OKCkgb3BlcmF0aW9uLlxuICovXG5jbGFzcyBKc29uVG9rZW4gZXh0ZW5kcyBJbnRyaW5zaWMge1xuICAvKipcbiAgICogU3BlY2lhbCBoYW5kbGVyIHRoYXQgZ2V0cyBjYWxsZWQgd2hlbiBKU09OLnN0cmluZ2lmeSgpIGlzIHVzZWQuXG4gICAqL1xuICBwdWJsaWMgdG9KU09OKCkge1xuICAgIHJldHVybiB0aGlzLnRvU3RyaW5nKCk7XG4gIH1cbn1cblxuLyoqXG4gKiBEZWVwIGVzY2FwZSBzdHJpbmdzIGZvciB1c2UgaW4gYSBKU09OIGNvbnRleHRcbiAqL1xuZnVuY3Rpb24gZGVlcFF1b3RlU3RyaW5nc0ZvckpTT04oeDogYW55KTogYW55IHtcbiAgaWYgKHR5cGVvZiB4ID09PSAnc3RyaW5nJykge1xuICAgIC8vIFdoZW5ldmVyIHdlIGVzY2FwZSBhIHN0cmluZyB3ZSBzdHJpcCBvZmYgdGhlIG91dGVybW9zdCBxdW90ZXNcbiAgICAvLyBzaW5jZSB3ZSdyZSBhbHJlYWR5IGluIGEgcXVvdGVkIGNvbnRleHQuXG4gICAgY29uc3Qgc3RyaW5naWZpZWQgPSBKU09OLnN0cmluZ2lmeSh4KTtcbiAgICByZXR1cm4gc3RyaW5naWZpZWQuc3Vic3RyaW5nKDEsIHN0cmluZ2lmaWVkLmxlbmd0aCAtIDEpO1xuICB9XG5cbiAgaWYgKEFycmF5LmlzQXJyYXkoeCkpIHtcbiAgICByZXR1cm4geC5tYXAoZGVlcFF1b3RlU3RyaW5nc0ZvckpTT04pO1xuICB9XG5cbiAgaWYgKHR5cGVvZiB4ID09PSAnb2JqZWN0Jykge1xuICAgIGZvciAoY29uc3Qga2V5IG9mIE9iamVjdC5rZXlzKHgpKSB7XG4gICAgICB4W2tleV0gPSBkZWVwUXVvdGVTdHJpbmdzRm9ySlNPTih4W2tleV0pO1xuICAgIH1cbiAgfVxuXG4gIHJldHVybiB4O1xufVxuXG5jb25zdCBDTE9VREZPUk1BVElPTl9DT05DQVQ6IElGcmFnbWVudENvbmNhdGVuYXRvciA9IHtcbiAgam9pbihsZWZ0OiBhbnksIHJpZ2h0OiBhbnkpIHtcbiAgICByZXR1cm4gQ2xvdWRGb3JtYXRpb25MYW5nLmNvbmNhdChsZWZ0LCByaWdodCk7XG4gIH1cbn07XG5cbi8qKlxuICogRGVmYXVsdCBUb2tlbiByZXNvbHZlciBmb3IgQ2xvdWRGb3JtYXRpb24gdGVtcGxhdGVzXG4gKi9cbmV4cG9ydCBjb25zdCBDTE9VREZPUk1BVElPTl9UT0tFTl9SRVNPTFZFUiA9IG5ldyBEZWZhdWx0VG9rZW5SZXNvbHZlcihDTE9VREZPUk1BVElPTl9DT05DQVQpO1xuXG4vKipcbiAqIERvIGFuIGludGVsbGlnZW50IENsb3VkRm9ybWF0aW9uIGpvaW4gb24gdGhlIGdpdmVuIHZhbHVlcywgcHJvZHVjaW5nIGEgbWluaW1hbCBleHByZXNzaW9uXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBtaW5pbWFsQ2xvdWRGb3JtYXRpb25Kb2luKGRlbGltaXRlcjogc3RyaW5nLCB2YWx1ZXM6IGFueVtdKTogYW55W10ge1xuICBsZXQgaSA9IDA7XG4gIHdoaWxlIChpIDwgdmFsdWVzLmxlbmd0aCkge1xuICAgIGNvbnN0IGVsID0gdmFsdWVzW2ldO1xuICAgIGlmIChpc1NwbGljYWJsZUZuSm9pbkludHJpbnNpYyhlbCkpIHtcbiAgICAgIHZhbHVlcy5zcGxpY2UoaSwgMSwgLi4uZWxbJ0ZuOjpKb2luJ11bMV0pO1xuICAgIH0gZWxzZSBpZiAoaSA+IDAgJiYgaXNQbGFpblN0cmluZyh2YWx1ZXNbaSAtIDFdKSAmJiBpc1BsYWluU3RyaW5nKHZhbHVlc1tpXSkpIHtcbiAgICAgIHZhbHVlc1tpIC0gMV0gKz0gZGVsaW1pdGVyICsgdmFsdWVzW2ldO1xuICAgICAgdmFsdWVzLnNwbGljZShpLCAxKTtcbiAgICB9IGVsc2Uge1xuICAgICAgaSArPSAxO1xuICAgIH1cbiAgfVxuXG4gIHJldHVybiB2YWx1ZXM7XG5cbiAgZnVuY3Rpb24gaXNQbGFpblN0cmluZyhvYmo6IGFueSk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0eXBlb2Ygb2JqID09PSAnc3RyaW5nJyAmJiAhVG9rZW4uaXNVbnJlc29sdmVkKG9iaik7XG4gIH1cblxuICBmdW5jdGlvbiBpc1NwbGljYWJsZUZuSm9pbkludHJpbnNpYyhvYmo6IGFueSk6IGJvb2xlYW4ge1xuICAgIHJldHVybiBpc0ludHJpbnNpYyhvYmopXG4gICAgICAmJiBPYmplY3Qua2V5cyhvYmopWzBdID09PSAnRm46OkpvaW4nXG4gICAgICAmJiBvYmpbJ0ZuOjpKb2luJ11bMF0gPT09IGRlbGltaXRlcjtcbiAgfVxufVxuXG4vKipcbiAqIFJldHVybiB3aGV0aGVyIHRoZSBnaXZlbiB2YWx1ZSByZXByZXNlbnRzIGEgQ2xvdWRGb3JtYXRpb24gaW50cmluc2ljXG4gKi9cbmZ1bmN0aW9uIGlzSW50cmluc2ljKHg6IGFueSkge1xuICBpZiAoQXJyYXkuaXNBcnJheSh4KSB8fCB4ID09PSBudWxsIHx8IHR5cGVvZiB4ICE9PSAnb2JqZWN0JykgeyByZXR1cm4gZmFsc2U7IH1cblxuICBjb25zdCBrZXlzID0gT2JqZWN0LmtleXMoeCk7XG4gIGlmIChrZXlzLmxlbmd0aCAhPT0gMSkgeyByZXR1cm4gZmFsc2U7IH1cblxuICByZXR1cm4ga2V5c1swXSA9PT0gJ1JlZicgfHwgaXNOYW1lT2ZDbG91ZEZvcm1hdGlvbkludHJpbnNpYyhrZXlzWzBdKTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGlzTmFtZU9mQ2xvdWRGb3JtYXRpb25JbnRyaW5zaWMobmFtZTogc3RyaW5nKTogYm9vbGVhbiB7XG4gIGlmICghbmFtZS5zdGFydHNXaXRoKCdGbjo6JykpIHtcbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cbiAgLy8gdGhlc2UgYXJlICdmYWtlJyBpbnRyaW5zaWNzLCBvbmx5IHVzYWJsZSBpbnNpZGUgdGhlIHBhcmFtZXRlciBvdmVycmlkZXMgb2YgYSBDRk4gQ29kZVBpcGVsaW5lIEFjdGlvblxuICByZXR1cm4gbmFtZSAhPT0gJ0ZuOjpHZXRBcnRpZmFjdEF0dCcgJiYgbmFtZSAhPT0gJ0ZuOjpHZXRQYXJhbSc7XG59XG4iXX0=