@glimmer/compiler
Version:
257 lines (218 loc) • 26.1 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.keyword = keyword;
exports.keywords = keywords;
exports.Keywords = exports.KEYWORD_NODES = void 0;
var _syntax = require("@glimmer/syntax");
var _util = require("@glimmer/util");
var _result = require("../../../shared/result");
class KeywordImpl {
constructor(keyword, type, delegate) {
this.keyword = keyword;
this.delegate = delegate;
let nodes = new Set();
for (let nodeType of KEYWORD_NODES[type]) {
nodes.add(nodeType);
}
this.types = nodes;
}
match(node) {
if (!this.types.has(node.type)) {
return false;
}
let path = getCalleeExpression(node);
if (path !== null && path.type === 'Path' && path.ref.type === 'Free') {
if (path.tail.length > 0) {
if (path.ref.resolution.serialize() === 'Loose') {
// cannot be a keyword reference, keywords do not allow paths (must be
// relying on implicit this fallback)
return false;
}
}
return path.ref.name === this.keyword;
} else {
return false;
}
}
translate(node, state) {
if (this.match(node)) {
let path = getCalleeExpression(node);
if (path !== null && path.type === 'Path' && path.tail.length > 0) {
return (0, _result.Err)((0, _syntax.generateSyntaxError)(`The \`${this.keyword}\` keyword was used incorrectly. It was used as \`${path.loc.asString()}\`, but it cannot be used with additional path segments. \n\nError caused by`, node.loc));
}
let param = this.delegate.assert(node, state);
return param.andThen(param => this.delegate.translate({
node,
state
}, param));
} else {
return null;
}
}
}
const KEYWORD_NODES = {
Call: ['Call'],
Block: ['InvokeBlock'],
Append: ['AppendContent'],
Modifier: ['ElementModifier']
};
exports.KEYWORD_NODES = KEYWORD_NODES;
function keyword(keyword, type, delegate) {
return new KeywordImpl(keyword, type, delegate);
}
function getCalleeExpression(node) {
switch (node.type) {
// This covers the inside of attributes and expressions, as well as the callee
// of call nodes
case 'Path':
return node;
case 'AppendContent':
return getCalleeExpression(node.value);
case 'Call':
case 'InvokeBlock':
case 'ElementModifier':
return node.callee;
default:
return null;
}
}
class Keywords {
constructor(type) {
this._keywords = [];
this._type = type;
}
kw(name, delegate) {
this._keywords.push(keyword(name, this._type, delegate));
return this;
}
translate(node, state) {
for (let keyword of this._keywords) {
let result = keyword.translate(node, state);
if (result !== null) {
return result;
}
}
let path = getCalleeExpression(node);
if (path && path.type === 'Path' && path.ref.type === 'Free' && (0, _syntax.isKeyword)(path.ref.name)) {
let {
name
} = path.ref;
let usedType = this._type;
let validTypes = _syntax.KEYWORDS_TYPES[name];
if (validTypes.indexOf(usedType) === -1) {
return (0, _result.Err)((0, _syntax.generateSyntaxError)(`The \`${name}\` keyword was used incorrectly. It was used as ${typesToReadableName[usedType]}, but its valid usages are:\n\n${generateTypesMessage(name, validTypes)}\n\nError caused by`, node.loc));
}
}
return null;
}
}
exports.Keywords = Keywords;
const typesToReadableName = {
Append: 'an append statement',
Block: 'a block statement',
Call: 'a call expression',
Modifier: 'a modifier'
};
function generateTypesMessage(name, types) {
return types.map(type => {
switch (type) {
case 'Append':
return `- As an append statement, as in: {{${name}}}`;
case 'Block':
return `- As a block statement, as in: {{#${name}}}{{/${name}}}`;
case 'Call':
return `- As an expression, as in: (${name})`;
case 'Modifier':
return `- As a modifier, as in: <div {{${name}}}></div>`;
default:
return (0, _util.exhausted)(type);
}
}).join('\n\n');
}
/**
* This function builds keyword definitions for a particular type of AST node (`KeywordType`).
*
* You can build keyword definitions for:
*
* - `Expr`: A `SubExpression` or `PathExpression`
* - `Block`: A `BlockStatement`
* - A `BlockStatement` is a keyword candidate if its head is a
* `PathExpression`
* - `Append`: An `AppendStatement`
*
* A node is a keyword candidate if:
*
* - A `PathExpression` is a keyword candidate if it has no tail, and its
* head expression is a `LocalVarHead` or `FreeVarHead` whose name is
* the keyword's name.
* - A `SubExpression`, `AppendStatement`, or `BlockStatement` is a keyword
* candidate if its head is a keyword candidate.
*
* The keyword infrastructure guarantees that:
*
* - If a node is not a keyword candidate, it is never passed to any keyword's
* `assert` method.
* - If a node is not the `KeywordType` for a particular keyword, it will not
* be passed to the keyword's `assert` method.
*
* `Expr` keywords are used in expression positions and should return HIR
* expressions. `Block` and `Append` keywords are used in statement
* positions and should return HIR statements.
*
* A keyword definition has two parts:
*
* - `match`, which determines whether an AST node matches the keyword, and can
* optionally return some information extracted from the AST node.
* - `translate`, which takes a matching AST node as well as the extracted
* information and returns an appropriate HIR instruction.
*
* # Example
*
* This keyword:
*
* - turns `(hello)` into `"hello"`
* - as long as `hello` is not in scope
* - makes it an error to pass any arguments (such as `(hello world)`)
*
* ```ts
* keywords('SubExpr').kw('hello', {
* assert(node: ExprKeywordNode): Result<void> | false {
* // we don't want to transform `hello` as a `PathExpression`
* if (node.type !== 'SubExpression') {
* return false;
* }
*
* // node.head would be `LocalVarHead` if `hello` was in scope
* if (node.head.type !== 'FreeVarHead') {
* return false;
* }
*
* if (node.params.length || node.hash) {
* return Err(generateSyntaxError(`(hello) does not take any arguments`), node.loc);
* } else {
* return Ok();
* }
* },
*
* translate(node: ASTv2.SubExpression): hir.Expression {
* return ASTv2.builders.literal("hello", node.loc)
* }
* })
* ```
*
* The keyword infrastructure checks to make sure that the node is the right
* type before calling `assert`, so you only need to consider `SubExpression`
* and `PathExpression` here. It also checks to make sure that the node passed
* to `assert` has the keyword name in the right place.
*
* Note the important difference between returning `false` from `assert`,
* which just means that the node didn't match, and returning `Err`, which
* means that the node matched, but there was a keyword-specific syntax
* error.
*/
function keywords(type) {
return new Keywords(type);
}
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uLy4uL3BhY2thZ2VzL0BnbGltbWVyL2NvbXBpbGVyL2xpYi9wYXNzZXMvMS1ub3JtYWxpemF0aW9uL2tleXdvcmRzL2ltcGwudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7O0FBQUE7O0FBT0E7O0FBRUE7O0FBZ0JBLE1BQUEsV0FBQSxDQUFpQjtBQVFmLEVBQUEsV0FBQSxDQUFBLE9BQUEsRUFBQSxJQUFBLEVBQUEsUUFBQSxFQUdrRTtBQUZ0RCxTQUFBLE9BQUEsR0FBQSxPQUFBO0FBRUYsU0FBQSxRQUFBLEdBQUEsUUFBQTtBQUVSLFFBQUksS0FBSyxHQUFHLElBQVosR0FBWSxFQUFaOztBQUNBLFNBQUssSUFBTCxRQUFBLElBQXFCLGFBQWEsQ0FBbEMsSUFBa0MsQ0FBbEMsRUFBMEM7QUFDeEMsTUFBQSxLQUFLLENBQUwsR0FBQSxDQUFBLFFBQUE7QUFDRDs7QUFFRCxTQUFBLEtBQUEsR0FBQSxLQUFBO0FBQ0Q7O0FBRVMsRUFBQSxLQUFLLENBQUEsSUFBQSxFQUEyQjtBQUN4QyxRQUFJLENBQUMsS0FBQSxLQUFBLENBQUEsR0FBQSxDQUFlLElBQUksQ0FBeEIsSUFBSyxDQUFMLEVBQWdDO0FBQzlCLGFBQUEsS0FBQTtBQUNEOztBQUVELFFBQUksSUFBSSxHQUFHLG1CQUFtQixDQUE5QixJQUE4QixDQUE5Qjs7QUFFQSxRQUFJLElBQUksS0FBSixJQUFBLElBQWlCLElBQUksQ0FBSixJQUFBLEtBQWpCLE1BQUEsSUFBeUMsSUFBSSxDQUFKLEdBQUEsQ0FBQSxJQUFBLEtBQTdDLE1BQUEsRUFBdUU7QUFDckUsVUFBSSxJQUFJLENBQUosSUFBQSxDQUFBLE1BQUEsR0FBSixDQUFBLEVBQTBCO0FBQ3hCLFlBQUksSUFBSSxDQUFKLEdBQUEsQ0FBQSxVQUFBLENBQUEsU0FBQSxPQUFKLE9BQUEsRUFBaUQ7QUFDL0M7QUFDQTtBQUNBLGlCQUFBLEtBQUE7QUFDRDtBQUNGOztBQUVELGFBQU8sSUFBSSxDQUFK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LElBQUEsQ0FBUCxNQUFPLENBQVA7QUFnQkQ7QUFFRDs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFpRk0sU0FBQSxRQUFBLENBQUEsSUFBQSxFQUFpRDtBQUNyRCxTQUFPLElBQUEsUUFBQSxDQUFQLElBQU8sQ0FBUDtBQUNEIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHtcbiAgQVNUdjIsXG4gIGdlbmVyYXRlU3ludGF4RXJyb3IsXG4gIGlzS2V5d29yZCxcbiAgS0VZV09SRFNfVFlQRVMsXG4gIEtleXdvcmRUeXBlLFxufSBmcm9tICdAZ2xpbW1lci9zeW50YXgnO1xuaW1wb3J0IHsgZXhoYXVzdGVkIH0gZnJvbSAnQGdsaW1tZXIvdXRpbCc7XG5cbmltcG9ydCB7IEVyciwgUmVzdWx0IH0gZnJvbSAnLi4vLi4vLi4vc2hhcmVkL3Jlc3VsdCc7XG5pbXBvcnQgeyBOb3JtYWxpemF0aW9uU3RhdGUgfSBmcm9tICcuLi9jb250ZXh0JztcblxuZXhwb3J0IGludGVyZmFjZSBLZXl3b3JkRGVsZWdhdGU8TWF0Y2ggZXh0ZW5kcyBLZXl3b3JkTWF0Y2gsIFYsIE91dD4ge1xuICBhc3NlcnQob3B0aW9uczogTWF0Y2gsIHN0YXRlOiBOb3JtYWxpemF0aW9uU3RhdGUpOiBSZXN1bHQ8Vj47XG4gIHRyYW5zbGF0ZShvcHRpb25zOiB7IG5vZGU6IE1hdGNoOyBzdGF0ZTogTm9ybWFsaXphdGlvblN0YXRlIH0sIHBhcmFtOiBWKTogUmVzdWx0PE91dD47XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgS2V5d29yZDxLIGV4dGVuZHMgS2V5d29yZFR5cGUgPSBLZXl3b3JkVHlwZSwgT3V0ID0gdW5rbm93bj4ge1xuICB0cmFuc2xhdGUobm9kZTogS2V5d29yZENhbmRpZGF0ZXNbS10sIHN0YXRlOiBOb3JtYWxpemF0aW9uU3RhdGUpOiBSZXN1bHQ8T3V0PiB8IG51bGw7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgQmxvY2tLZXl3b3JkPE91dCA9IHVua25vd24+IHtcbiAgdHJhbnNsYXRlKG5vZGU6IEFTVHYyLkludm9rZUJsb2NrLCBzdGF0ZTogTm9ybWFsaXphdGlvblN0YXRlKTogUmVzdWx0PE91dD4gfCBudWxsO1xufVxuXG5jbGFzcyBLZXl3b3JkSW1wbDxcbiAgSyBleHRlbmRzIEtleXdvcmRUeXBlLFxuICBTIGV4dGVuZHMgc3RyaW5nID0gc3RyaW5nLFxuICBQYXJhbSA9IHVua25vd24sXG4gIE91dCA9IHVua25vd25cbj4ge1xuICBwcm90ZWN0ZWQgdHlwZXM6IFNldDxLZXl3b3JkQ2FuZGlkYXRlc1tLXVsndHlwZSddPjtcblxuICBjb25zdHJ1Y3RvcihcbiAgICBwcm90ZWN0ZWQga2V5d29yZDogUyxcbiAgICB0eXBlOiBLZXl3b3JkVHlwZSxcbiAgICBwcml2YXRlIGRlbGVnYXRlOiBLZXl3b3JkRGVsZWdhdGU8S2V5d29yZE1hdGNoZXNbS10sIFBhcmFtLCBPdXQ+XG4gICkge1xuICAgIGxldCBub2RlcyA9IG5ldyBTZXQ8S2V5d29yZE5vZGVbJ3R5cGUnXT4oKTtcbiAgICBmb3IgKGxldCBub2RlVHlwZSBvZiBLRVlXT1JEX05PREVTW3R5cGVdKSB7XG4gICAgICBub2Rlcy5hZGQobm9kZVR5cGUpO1xuICAgIH1cblxuICAgIHRoaXMudHlwZXMgPSBub2RlcztcbiAgfVxuXG4gIHByb3RlY3RlZCBtYXRjaChub2RlOiBLZXl3b3JkQ2FuZGlkYXRlc1tLXSk6IG5vZGUgaXMgS2V5d29yZE1hdGNoZXNbS10ge1xuICAgIGlmICghdGhpcy50eXBlcy5oYXMobm9kZS50eXBlKSkge1xuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cblxuICAgIGxldCBwYXRoID0gZ2V0Q2FsbGVlRXhwcmVzc2lvbihub2RlKTtcblxuICAgIGlmIChwYXRoICE9PSBudWxsICYmIHBhdGgudHlwZSA9PT0gJ1BhdGgnICYmIHBhdGgucmVmLnR5cGUgPT09ICdGcmVlJykge1xuICAgICAgaWYgKHBhdGgudGFpbC5sZW5ndGggPiAwKSB7XG4gICAgICAgIGlmIChwYXRoLnJlZi5yZXNvbHV0aW9uLnNlcmlhbGl6ZSgpID09PSAnTG9vc2UnKSB7XG4gICAgICAgICAgLy8gY2Fubm90IGJlIGEga2V5d29yZCByZWZlcmVuY2UsIGtleXdvcmRzIGRvIG5vdCBhbGxvdyBwYXRocyAobXVzdCBiZVxuICAgICAgICAgIC8vIHJlbHlpbmcgb24gaW1wbGljaXQgdGhpcyBmYWxsYmFjaylcbiAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgcmV0dXJuIHBhdGgucmVmLm5hbWUgPT09IHRoaXMua2V5d29yZDtcbiAgICB9IGVsc2Uge1xuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbiAgfVxuXG4gIHRyYW5zbGF0ZShub2RlOiBLZXl3b3JkTWF0Y2hlc1tLXSwgc3RhdGU6IE5vcm1hbGl6YXRpb25TdGF0ZSk6IFJlc3VsdDxPdXQ+IHwgbnVsbCB7XG4gICAgaWYgKHRoaXMubWF0Y2gobm9kZSkpIHtcbiAgICAgIGxldCBwYXRoID0gZ2V0Q2FsbGVlRXhwcmVzc2lvbihub2RlKTtcblxuICAgICAgaWYgKHBhdGggIT09IG51bGwgJiYgcGF0aC50eXBlID09PSAnUGF0aCcgJiYgcGF0aC50YWlsLmxlbmd0aCA+IDApIHtcbiAgICAgICAgcmV0dXJuIEVycihcbiAgICAgICAgICBnZW5lcmF0ZVN5bnRheEVycm9yKFxuICAgICAgICAgICAgYFRoZSBcXGAke1xuICAgICAgICAgICAgICB0aGlzLmtleXdvcmRcbiAgICAgICAgICAgIH1cXGAga2V5d29yZCB3YXMgdXNlZCBpbmNvcnJlY3RseS4gSXQgd2FzIHVzZWQgYXMgXFxgJHtwYXRoLmxvYy5hc1N0cmluZygpfVxcYCwgYnV0IGl0IGNhbm5vdCBiZSB1c2VkIHdpdGggYWRkaXRpb25hbCBwYXRoIHNlZ21lbnRzLiBcXG5cXG5FcnJvciBjYXVzZWQgYnlgLFxuICAgICAgICAgICAgbm9kZS5sb2NcbiAgICAgICAgICApXG4gICAgICAgICk7XG4gICAgICB9XG5cbiAgICAgIGxldCBwYXJhbSA9IHRoaXMuZGVsZWdhdGUuYXNzZXJ0KG5vZGUsIHN0YXRlKTtcbiAgICAgIHJldHVybiBwYXJhbS5hbmRUaGVuKChwYXJhbSkgPT4gdGhpcy5kZWxlZ2F0ZS50cmFuc2xhdGUoeyBub2RlLCBzdGF0ZSB9LCBwYXJhbSkpO1xuICAgIH0gZWxzZSB7XG4gICAgICByZXR1cm4gbnVsbDtcbiAgICB9XG4gIH1cbn1cblxuZXhwb3J0IHR5cGUgUG9zc2libGVOb2RlID1cbiAgfCBBU1R2Mi5QYXRoRXhwcmVzc2lvblxuICB8IEFTVHYyLkFwcGVuZENvbnRlbnRcbiAgfCBBU1R2Mi5DYWxsRXhwcmVzc2lvblxuICB8IEFTVHYyLkludm9rZUJsb2NrO1xuXG5leHBvcnQgY29uc3QgS0VZV09SRF9OT0RFUyA9IHtcbiAgQ2FsbDogWydDYWxsJ10sXG4gIEJsb2NrOiBbJ0ludm9rZUJsb2NrJ10sXG4gIEFwcGVuZDogWydBcHBlbmRDb250ZW50J10sXG4gIE1vZGlmaWVyOiBbJ0VsZW1lbnRNb2RpZmllciddLFxufSBhcyBjb25zdDtcblxuZXhwb3J0IGludGVyZmFjZSBLZXl3b3JkQ2FuZGlkYXRlcyB7XG4gIENhbGw6IEFTVHYyLkV4cHJlc3Npb25Ob2RlO1xuICBCbG9jazogQVNUdjIuSW52b2tlQmxvY2s7XG4gIEFwcGVuZDogQVNUdjIuQXBwZW5kQ29udGVudDtcbiAgTW9kaWZpZXI6IEFTVHYyLkVsZW1lbnRNb2RpZmllcjtcbn1cblxuZXhwb3J0IHR5cGUgS2V5d29yZENhbmRpZGF0ZSA9IEtleXdvcmRDYW5kaWRhdGVzW2tleW9mIEtleXdvcmRDYW5kaWRhdGVzXTtcblxuZXhwb3J0IGludGVyZmFjZSBLZXl3b3JkTWF0Y2hlcyB7XG4gIENhbGw6IEFTVHYyLkNhbGxFeHByZXNzaW9uO1xuICBCbG9jazogQVNUdjIuSW52b2tlQmxvY2s7XG4gIEFwcGVuZDogQVNUdjIuQXBwZW5kQ29udGVudDtcbiAgTW9kaWZpZXI6IEFTVHYyLkVsZW1lbnRNb2RpZmllcjtcbn1cblxuZXhwb3J0IHR5cGUgS2V5d29yZE1hdGNoID0gS2V5d29yZE1hdGNoZXNba2V5b2YgS2V5d29yZE1hdGNoZXNdO1xuXG4vKipcbiAqIEEgXCJnZW5lcmljXCIga2V5d29yZCBpcyBzb21ldGhpbmcgbGlrZSBgaGFzLWJsb2NrYCwgd2hpY2ggbWFrZXMgc2Vuc2UgaW4gdGhlIGNvbnRleHRcbiAqIG9mIHN1Yi1leHByZXNzaW9uIG9yIGFwcGVuZFxuICovXG5leHBvcnQgdHlwZSBHZW5lcmljS2V5d29yZE5vZGUgPSBBU1R2Mi5BcHBlbmRDb250ZW50IHwgQVNUdjIuQ2FsbEV4cHJlc3Npb247XG5cbmV4cG9ydCB0eXBlIEtleXdvcmROb2RlID1cbiAgfCBHZW5lcmljS2V5d29yZE5vZGVcbiAgfCBBU1R2Mi5DYWxsRXhwcmVzc2lvblxuICB8IEFTVHYyLkludm9rZUJsb2NrXG4gIHwgQVNUdjIuRWxlbWVudE1vZGlmaWVyO1xuXG5leHBvcnQgZnVuY3Rpb24ga2V5d29yZDxcbiAgSyBleHRlbmRzIEtleXdvcmRUeXBlLFxuICBEIGV4dGVuZHMgS2V5d29yZERlbGVnYXRlPEtleXdvcmRNYXRjaGVzW0tdLCB1bmtub3duLCBPdXQ+LFxuICBPdXQgPSB1bmtub3duXG4+KGtleXdvcmQ6IHN0cmluZywgdHlwZTogSywgZGVsZWdhdGU6IEQpOiBLZXl3b3JkPEssIE91dD4ge1xuICByZXR1cm4gbmV3IEtleXdvcmRJbXBsKGtleXdvcmQsIHR5cGUsIGRlbGVnYXRlIGFzIEtleXdvcmREZWxlZ2F0ZTxLZXl3b3JkTWF0Y2gsIHVua25vd24sIE91dD4pO1xufVxuXG5leHBvcnQgdHlwZSBQb3NzaWJsZUtleXdvcmQgPSBLZXl3b3JkTm9kZTtcbnR5cGUgT3V0Rm9yPEsgZXh0ZW5kcyBLZXl3b3JkIHwgQmxvY2tLZXl3b3JkPiA9IEsgZXh0ZW5kcyBCbG9ja0tleXdvcmQ8aW5mZXIgT3V0PlxuICA/IE91dFxuICA6IEsgZXh0ZW5kcyBLZXl3b3JkPEtleXdvcmRUeXBlLCBpbmZlciBPdXQ+XG4gID8gT3V0XG4gIDogbmV2ZXI7XG5cbmZ1bmN0aW9uIGdldENhbGxlZUV4cHJlc3Npb24oXG4gIG5vZGU6IEtleXdvcmROb2RlIHwgQVNUdjIuRXhwcmVzc2lvbk5vZGVcbik6IEFTVHYyLkV4cHJlc3Npb25Ob2RlIHwgbnVsbCB7XG4gIHN3aXRjaCAobm9kZS50eXBlKSB7XG4gICAgLy8gVGhpcyBjb3ZlcnMgdGhlIGluc2lkZSBvZiBhdHRyaWJ1dGVzIGFuZCBleHByZXNzaW9ucywgYXMgd2VsbCBhcyB0aGUgY2FsbGVlXG4gICAgLy8gb2YgY2FsbCBub2Rlc1xuICAgIGNhc2UgJ1BhdGgnOlxuICAgICAgcmV0dXJuIG5vZGU7XG4gICAgY2FzZSAnQXBwZW5kQ29udGVudCc6XG4gICAgICByZXR1cm4gZ2V0Q2FsbGVlRXhwcmVzc2lvbihub2RlLnZhbHVlKTtcbiAgICBjYXNlICdDYWxsJzpcbiAgICBjYXNlICdJbnZva2VCbG9jayc6XG4gICAgY2FzZSAnRWxlbWVudE1vZGlmaWVyJzpcbiAgICAgIHJldHVybiBub2RlLmNhbGxlZTtcbiAgICBkZWZhdWx0OlxuICAgICAgcmV0dXJuIG51bGw7XG4gIH1cbn1cblxuZXhwb3J0IGNsYXNzIEtleXdvcmRzPEsgZXh0ZW5kcyBLZXl3b3JkVHlwZSwgS2V5d29yZExpc3QgZXh0ZW5kcyBLZXl3b3JkPEs+ID0gbmV2ZXI+XG4gIGltcGxlbWVudHMgS2V5d29yZDxLLCBPdXRGb3I8S2V5d29yZExpc3Q+PiB7XG4gIF9rZXl3b3JkczogS2V5d29yZFtdID0gW107XG4gIF90eXBlOiBLO1xuXG4gIGNvbnN0cnVjdG9yKHR5cGU6IEspIHtcbiAgICB0aGlzLl90eXBlID0gdHlwZTtcbiAgfVxuXG4gIGt3PFMgZXh0ZW5kcyBzdHJpbmcgPSBzdHJpbmcsIE91dCA9IHVua25vd24+KFxuICAgIG5hbWU6IFMsXG4gICAgZGVsZWdhdGU6IEtleXdvcmREZWxlZ2F0ZTxLZXl3b3JkTWF0Y2hlc1tLXSwgdW5rbm93biwgT3V0PlxuICApOiBLZXl3b3JkczxLLCBLZXl3b3JkTGlzdCB8IEtleXdvcmQ8SywgT3V0Pj4ge1xuICAgIHRoaXMuX2tleXdvcmRzLnB1c2goa2V5d29yZChuYW1lLCB0aGlzLl90eXBlLCBkZWxlZ2F0ZSkpO1xuXG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cblxuICB0cmFuc2xhdGUoXG4gICAgbm9kZTogS2V5d29yZENhbmRpZGF0ZXNbS10sXG4gICAgc3RhdGU6IE5vcm1hbGl6YXRpb25TdGF0ZVxuICApOiBSZXN1bHQ8T3V0Rm9yPEtleXdvcmRMaXN0Pj4gfCBudWxsIHtcbiAgICBmb3IgKGxldCBrZXl3b3JkIG9mIHRoaXMuX2tleXdvcmRzKSB7XG4gICAgICBsZXQgcmVzdWx0ID0ga2V5d29yZC50cmFuc2xhdGUobm9kZSwgc3RhdGUpIGFzIFJlc3VsdDxPdXRGb3I8S2V5d29yZExpc3Q+PjtcbiAgICAgIGlmIChyZXN1bHQgIT09IG51bGwpIHtcbiAgICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICAgIH1cbiAgICB9XG5cbiAgICBsZXQgcGF0aCA9IGdldENhbGxlZUV4cHJlc3Npb24obm9kZSk7XG5cbiAgICBpZiAocGF0aCAmJiBwYXRoLnR5cGUgPT09ICdQYXRoJyAmJiBwYXRoLnJlZi50eXBlID09PSAnRnJlZScgJiYgaXNLZXl3b3JkKHBhdGgucmVmLm5hbWUpKSB7XG4gICAgICBsZXQgeyBuYW1lIH0gPSBwYXRoLnJlZjtcblxuICAgICAgbGV0IHVzZWRUeXBlID0gdGhpcy5fdHlwZTtcbiAgICAgIGxldCB2YWxpZFR5cGVzID0gS0VZV09SRFNfVFlQRVNbbmFtZV07XG5cbiAgICAgIGlmICh2YWxpZFR5cGVzLmluZGV4T2YodXNlZFR5cGUpID09PSAtMSkge1xuICAgICAgICByZXR1cm4gRXJyKFxuICAgICAgICAgIGdlbmVyYXRlU3ludGF4RXJyb3IoXG4gICAgICAgICAgICBgVGhlIFxcYCR7bmFtZX1cXGAga2V5d29yZCB3YXMgdXNlZCBpbmNvcnJlY3RseS4gSXQgd2FzIHVzZWQgYXMgJHtcbiAgICAgICAgICAgICAgdHlwZXNUb1JlYWRhYmxlTmFtZVt1c2VkVHlwZV1cbiAgICAgICAgICAgIH0sIGJ1dCBpdHMgdmFsaWQgdXNhZ2VzIGFyZTpcXG5cXG4ke2dlbmVyYXRlVHlwZXNNZXNzYWdlKFxuICAgICAgICAgICAgICBuYW1lLFxuICAgICAgICAgICAgICB2YWxpZFR5cGVzXG4gICAgICAgICAgICApfVxcblxcbkVycm9yIGNhdXNlZCBieWAsXG4gICAgICAgICAgICBub2RlLmxvY1xuICAgICAgICAgIClcbiAgICAgICAgKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4gbnVsbDtcbiAgfVxufVxuXG5jb25zdCB0eXBlc1RvUmVhZGFibGVOYW1lID0ge1xuICBBcHBlbmQ6ICdhbiBhcHBlbmQgc3RhdGVtZW50JyxcbiAgQmxvY2s6ICdhIGJsb2NrIHN0YXRlbWVudCcsXG4gIENhbGw6ICdhIGNhbGwgZXhwcmVzc2lvbicsXG4gIE1vZGlmaWVyOiAnYSBtb2RpZmllcicsXG59O1xuXG5mdW5jdGlvbiBnZW5lcmF0ZVR5cGVzTWVzc2FnZShuYW1lOiBzdHJpbmcsIHR5cGVzOiBLZXl3b3JkVHlwZVtdKTogc3RyaW5nIHtcbiAgcmV0dXJuIHR5cGVzXG4gICAgLm1hcCgodHlwZSkgPT4ge1xuICAgICAgc3dpdGNoICh0eXBlKSB7XG4gICAgICAgIGNhc2UgJ0FwcGVuZCc6XG4gICAgICAgICAgcmV0dXJuIGAtIEFzIGFuIGFwcGVuZCBzdGF0ZW1lbnQsIGFzIGluOiB7eyR7bmFtZX19fWA7XG4gICAgICAgIGNhc2UgJ0Jsb2NrJzpcbiAgICAgICAgICByZXR1cm4gYC0gQXMgYSBibG9jayBzdGF0ZW1lbnQsIGFzIGluOiB7eyMke25hbWV9fX17ey8ke25hbWV9fX1gO1xuICAgICAgICBjYXNlICdDYWxsJzpcbiAgICAgICAgICByZXR1cm4gYC0gQXMgYW4gZXhwcmVzc2lvbiwgYXMgaW46ICgke25hbWV9KWA7XG4gICAgICAgIGNhc2UgJ01vZGlmaWVyJzpcbiAgICAgICAgICByZXR1cm4gYC0gQXMgYSBtb2RpZmllciwgYXMgaW46IDxkaXYge3ske25hbWV9fX0+PC9kaXY+YDtcbiAgICAgICAgZGVmYXVsdDpcbiAgICAgICAgICByZXR1cm4gZXhoYXVzdGVkKHR5cGUpO1xuICAgICAgfVxuICAgIH0pXG4gICAgLmpvaW4oJ1xcblxcbicpO1xufVxuXG4vKipcbiAqIFRoaXMgZnVuY3Rpb24gYnVpbGRzIGtleXdvcmQgZGVmaW5pdGlvbnMgZm9yIGEgcGFydGljdWxhciB0eXBlIG9mIEFTVCBub2RlIChgS2V5d29yZFR5cGVgKS5cbiAqXG4gKiBZb3UgY2FuIGJ1aWxkIGtleXdvcmQgZGVmaW5pdGlvbnMgZm9yOlxuICpcbiAqIC0gYEV4cHJgOiBBIGBTdWJFeHByZXNzaW9uYCBvciBgUGF0aEV4cHJlc3Npb25gXG4gKiAtIGBCbG9ja2A6IEEgYEJsb2NrU3RhdGVtZW50YFxuICogICAtIEEgYEJsb2NrU3RhdGVtZW50YCBpcyBhIGtleXdvcmQgY2FuZGlkYXRlIGlmIGl0cyBoZWFkIGlzIGFcbiAqICAgICBgUGF0aEV4cHJlc3Npb25gXG4gKiAtIGBBcHBlbmRgOiBBbiBgQXBwZW5kU3RhdGVtZW50YFxuICpcbiAqIEEgbm9kZSBpcyBhIGtleXdvcmQgY2FuZGlkYXRlIGlmOlxuICpcbiAqIC0gQSBgUGF0aEV4cHJlc3Npb25gIGlzIGEga2V5d29yZCBjYW5kaWRhdGUgaWYgaXQgaGFzIG5vIHRhaWwsIGFuZCBpdHNcbiAqICAgaGVhZCBleHByZXNzaW9uIGlzIGEgYExvY2FsVmFySGVhZGAgb3IgYEZyZWVWYXJIZWFkYCB3aG9zZSBuYW1lIGlzXG4gKiAgIHRoZSBrZXl3b3JkJ3MgbmFtZS5cbiAqIC0gQSBgU3ViRXhwcmVzc2lvbmAsIGBBcHBlbmRTdGF0ZW1lbnRgLCBvciBgQmxvY2tTdGF0ZW1lbnRgIGlzIGEga2V5d29yZFxuICogICBjYW5kaWRhdGUgaWYgaXRzIGhlYWQgaXMgYSBrZXl3b3JkIGNhbmRpZGF0ZS5cbiAqXG4gKiBUaGUga2V5d29yZCBpbmZyYXN0cnVjdHVyZSBndWFyYW50ZWVzIHRoYXQ6XG4gKlxuICogLSBJZiBhIG5vZGUgaXMgbm90IGEga2V5d29yZCBjYW5kaWRhdGUsIGl0IGlzIG5ldmVyIHBhc3NlZCB0byBhbnkga2V5d29yZCdzXG4gKiAgIGBhc3NlcnRgIG1ldGhvZC5cbiAqIC0gSWYgYSBub2RlIGlzIG5vdCB0aGUgYEtleXdvcmRUeXBlYCBmb3IgYSBwYXJ0aWN1bGFyIGtleXdvcmQsIGl0IHdpbGwgbm90XG4gKiAgIGJlIHBhc3NlZCB0byB0aGUga2V5d29yZCdzIGBhc3NlcnRgIG1ldGhvZC5cbiAqXG4gKiBgRXhwcmAga2V5d29yZHMgYXJlIHVzZWQgaW4gZXhwcmVzc2lvbiBwb3NpdGlvbnMgYW5kIHNob3VsZCByZXR1cm4gSElSXG4gKiBleHByZXNzaW9ucy4gYEJsb2NrYCBhbmQgYEFwcGVuZGAga2V5d29yZHMgYXJlIHVzZWQgaW4gc3RhdGVtZW50XG4gKiBwb3NpdGlvbnMgYW5kIHNob3VsZCByZXR1cm4gSElSIHN0YXRlbWVudHMuXG4gKlxuICogQSBrZXl3b3JkIGRlZmluaXRpb24gaGFzIHR3byBwYXJ0czpcbiAqXG4gKiAtIGBtYXRjaGAsIHdoaWNoIGRldGVybWluZXMgd2hldGhlciBhbiBBU1Qgbm9kZSBtYXRjaGVzIHRoZSBrZXl3b3JkLCBhbmQgY2FuXG4gKiAgIG9wdGlvbmFsbHkgcmV0dXJuIHNvbWUgaW5mb3JtYXRpb24gZXh0cmFjdGVkIGZyb20gdGhlIEFTVCBub2RlLlxuICogLSBgdHJhbnNsYXRlYCwgd2hpY2ggdGFrZXMgYSBtYXRjaGluZyBBU1Qgbm9kZSBhcyB3ZWxsIGFzIHRoZSBleHRyYWN0ZWRcbiAqICAgaW5mb3JtYXRpb24gYW5kIHJldHVybnMgYW4gYXBwcm9wcmlhdGUgSElSIGluc3RydWN0aW9uLlxuICpcbiAqICMgRXhhbXBsZVxuICpcbiAqIFRoaXMga2V5d29yZDpcbiAqXG4gKiAtIHR1cm5zIGAoaGVsbG8pYCBpbnRvIGBcImhlbGxvXCJgXG4gKiAgIC0gYXMgbG9uZyBhcyBgaGVsbG9gIGlzIG5vdCBpbiBzY29wZVxuICogLSBtYWtlcyBpdCBhbiBlcnJvciB0byBwYXNzIGFueSBhcmd1bWVudHMgKHN1Y2ggYXMgYChoZWxsbyB3b3JsZClgKVxuICpcbiAqIGBgYHRzXG4gKiBrZXl3b3JkcygnU3ViRXhwcicpLmt3KCdoZWxsbycsIHtcbiAqICAgYXNzZXJ0KG5vZGU6IEV4cHJLZXl3b3JkTm9kZSk6IFJlc3VsdDx2b2lkPiB8IGZhbHNlIHtcbiAqICAgICAvLyB3ZSBkb24ndCB3YW50IHRvIHRyYW5zZm9ybSBgaGVsbG9gIGFzIGEgYFBhdGhFeHByZXNzaW9uYFxuICogICAgIGlmIChub2RlLnR5cGUgIT09ICdTdWJFeHByZXNzaW9uJykge1xuICogICAgICAgcmV0dXJuIGZhbHNlO1xuICogICAgIH1cbiAqXG4gKiAgICAgLy8gbm9kZS5oZWFkIHdvdWxkIGJlIGBMb2NhbFZhckhlYWRgIGlmIGBoZWxsb2Agd2FzIGluIHNjb3BlXG4gKiAgICAgaWYgKG5vZGUuaGVhZC50eXBlICE9PSAnRnJlZVZhckhlYWQnKSB7XG4gKiAgICAgICByZXR1cm4gZmFsc2U7XG4gKiAgICAgfVxuICpcbiAqICAgICBpZiAobm9kZS5wYXJhbXMubGVuZ3RoIHx8IG5vZGUuaGFzaCkge1xuICogICAgICAgcmV0dXJuIEVycihnZW5lcmF0ZVN5bnRheEVycm9yKGAoaGVsbG8pIGRvZXMgbm90IHRha2UgYW55IGFyZ3VtZW50c2ApLCBub2RlLmxvYyk7XG4gKiAgICAgfSBlbHNlIHtcbiAqICAgICAgIHJldHVybiBPaygpO1xuICogICAgIH1cbiAqICAgfSxcbiAqXG4gKiAgIHRyYW5zbGF0ZShub2RlOiBBU1R2Mi5TdWJFeHByZXNzaW9uKTogaGlyLkV4cHJlc3Npb24ge1xuICogICAgIHJldHVybiBBU1R2Mi5idWlsZGVycy5saXRlcmFsKFwiaGVsbG9cIiwgbm9kZS5sb2MpXG4gKiAgIH1cbiAqIH0pXG4gKiBgYGBcbiAqXG4gKiBUaGUga2V5d29yZCBpbmZyYXN0cnVjdHVyZSBjaGVja3MgdG8gbWFrZSBzdXJlIHRoYXQgdGhlIG5vZGUgaXMgdGhlIHJpZ2h0XG4gKiB0eXBlIGJlZm9yZSBjYWxsaW5nIGBhc3NlcnRgLCBzbyB5b3Ugb25seSBuZWVkIHRvIGNvbnNpZGVyIGBTdWJFeHByZXNzaW9uYFxuICogYW5kIGBQYXRoRXhwcmVzc2lvbmAgaGVyZS4gSXQgYWxzbyBjaGVja3MgdG8gbWFrZSBzdXJlIHRoYXQgdGhlIG5vZGUgcGFzc2VkXG4gKiB0byBgYXNzZXJ0YCBoYXMgdGhlIGtleXdvcmQgbmFtZSBpbiB0aGUgcmlnaHQgcGxhY2UuXG4gKlxuICogTm90ZSB0aGUgaW1wb3J0YW50IGRpZmZlcmVuY2UgYmV0d2VlbiByZXR1cm5pbmcgYGZhbHNlYCBmcm9tIGBhc3NlcnRgLFxuICogd2hpY2gganVzdCBtZWFucyB0aGF0IHRoZSBub2RlIGRpZG4ndCBtYXRjaCwgYW5kIHJldHVybmluZyBgRXJyYCwgd2hpY2hcbiAqIG1lYW5zIHRoYXQgdGhlIG5vZGUgbWF0Y2hlZCwgYnV0IHRoZXJlIHdhcyBhIGtleXdvcmQtc3BlY2lmaWMgc3ludGF4XG4gKiBlcnJvci5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGtleXdvcmRzPEsgZXh0ZW5kcyBLZXl3b3JkVHlwZT4odHlwZTogSyk6IEtleXdvcmRzPEs+IHtcbiAgcmV0dXJuIG5ldyBLZXl3b3Jkcyh0eXBlKTtcbn1cbiJdLCJzb3VyY2VSb290IjoiIn0=