UNPKG

@desertnet/html-parser

Version:

HTML parser and non-strict validator

493 lines (420 loc) 45.8 kB
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); var _Instr = require('./Instr'); var _Instr2 = _interopRequireDefault(_Instr); var _Op = require('./Op'); var _Op2 = _interopRequireDefault(_Op); var _scanner = require('@desertnet/scanner'); var _scanner2 = _interopRequireDefault(_scanner); var _HTMLNode = require('./HTMLNode'); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } var Compiler = function () { function Compiler() { _classCallCheck(this, Compiler); var entityStart = /&(?=[a-z0-9#]+;)/i; var attributeStart = /[^>=\s\/]+/i; /** * The tokenizing scanner for the input string. HTML contains * many contexts where the scanner needs to accept differnt * sets of tokens. The @desertnet/scanner module calls these * sets of token definitions "dialects". Below, we're initializing * our scanner with all these different dialects. * @private * @type {Scanner} */ this._scanner = new _scanner2.default({ // Starting dialect, for content "outside of a tag". "content": [{ "text": /[^<>&]+/ }, { "commentStart": /<!--/ }, { "entityStart": entityStart }, { "tagStart": /<[a-z][^\t\n\ \/\>\0\xff]*/i }, { "closeTagStart": /<\/[a-z][^\t\n\ \/\>\0\xff]*/i }, { "error": /[<>&]/ }], // Dialect for the inside of comment tags. "comment": [{ "commentEnd": /-->/ }, { "dash": /-/ }, { "text": /[^-]+/ }], // Dialect for the inside of HTML entities. "entity": [{ "entityEnd": /;/ }, { "hex": /#x[a-f0-9]+/i }, { "dec": /#\d+/ }, { "named": /[a-z][a-z0-9]*/i }, { "error": /[^]/ }], // Dialect for the inside of tags. "tag": [{ "tagEnd": />/ }, { "whitespace": /\s+/ }, { "selfClose": /\// }, { "error": /['"<=]/ }, { "attributeStart": attributeStart }], // Initial dialect for attributes. "attribute": [{ "whitespace": /\s+/ }, { "attributeValueQuotedStart": /=['"]/ }, { "attributeValueStart": /=/ }, { "tagEnd": />/ }, { "selfClose": /\// }, { "error": /['"<]/ }, { "attributeStart": attributeStart }], // Dialect for unquoted attribute values. "attributeValue": [{ "whitespace": /\s+/ }, { "entityStart": entityStart }, { "tagEnd": />/ }, { "error": /['"<=`&]/ }, { "text": /[^'"<>=`&\s]+/ }], // Dialect for quoted attribute values. "attributeValueQuoted": [{ "dquo": /"/ }, { "squo": /'/ }, { "entityStart": entityStart }, { "error": /&/ }, { "text": /[^"'&]+/ }], // Dialect for closing tags. "closeTag": [{ "tagEnd": />/ }, { "whitespace": /\s+/ }, { "error": /[^\s>]+/ }], // Dialect for inside of script, style, and xmp tags "rawtext": [{ "closeTag": /<\/[a-z]+\s*>/i }, { "text": /[^<]+/ }, { "lt": /</ }] }); /** * @private * @type {string} */ this._expectedAttributeValueEndTokenType; /** * @private * @type {string} */ this._expectedRawtextClosingTagName; } /** * @param {string} html */ _createClass(Compiler, [{ key: 'setInput', value: function setInput(html) { this._scanner.setSource(html); this._scanner.pushDialect("content"); } /** * @private * @param {string} dialect */ }, { key: 'pushDialect', value: function pushDialect(dialect) { this._scanner.pushDialect(dialect); } /** * @private */ }, { key: 'popDialect', value: function popDialect() { this._scanner.popDialect(); } /** * @private * @return {string} */ }, { key: 'currentDialect', value: function currentDialect() { var dialect = this._scanner.currentDialect(); if (dialect === null) { throw new Error("Scanner dialect unexpectedly null."); } return dialect; } /** * @private * @param {string} tokenType */ }, { key: 'setExpectedAttributeValueEndTokenType', value: function setExpectedAttributeValueEndTokenType(tokenType) { this._expectedAttributeValueEndTokenType = tokenType; } /** * @private * @return {string} */ }, { key: 'expectedAttributeValueEndTokenType', value: function expectedAttributeValueEndTokenType() { return this._expectedAttributeValueEndTokenType; } /** * @private * @param {string} name */ }, { key: 'setExpectedRawtextClosingTagName', value: function setExpectedRawtextClosingTagName(name) { this._expectedRawtextClosingTagName = name.toLowerCase(); } /** * @private * @return {string} */ }, { key: 'expectedRawtextClosingTagName', value: function expectedRawtextClosingTagName() { return this._expectedRawtextClosingTagName; } /** * @param {string} tagName */ }, { key: 'setRawtextModeForTag', value: function setRawtextModeForTag(tagName) { this.pushDialect("rawtext"); this.setExpectedRawtextClosingTagName(tagName); } /** * @return {Array.<Op>} */ }, { key: 'generateNextCodeFragment', value: function generateNextCodeFragment() { var token = this._scanner.nextToken(); if (token === null) { return null; } return this.generateCodeForTokenInDialect(token, this.currentDialect()); } /** * Take a node and the dialect in which it was found, and tell the * parser what to do next. * @private * @param {Foundation.Scanner.Token} token * @param {string} dialect * @return {Array.<Op>} */ }, { key: 'generateCodeForTokenInDialect', value: function generateCodeForTokenInDialect(token, dialect) { switch (dialect) { case "content": return this.generateCodeForContentToken(token); case "comment": return this.generateCodeForCommentToken(token); case "entity": return this.generateCodeForEntityToken(token); case "tag": return this.generateCodeForTagToken(token); case "attribute": return this.generateCodeForAttributeToken(token); case "attributeValue": return this.generateCodeForAttributeValueToken(token); case "attributeValueQuoted": return this.generateCodeForAttributeValueQuotedToken(token); case "closeTag": return this.generateCodeForCloseTagToken(token); case "rawtext": return this.generateCodeForRawtextToken(token); default: throw new Error("Called compileTokenForDialect on unsuppoted dialect."); } } /** * @private * @param {Foundation.Scanner.Token} token * @return {Array.<Op>} */ }, { key: 'generateCodeForContentToken', value: function generateCodeForContentToken(token) { switch (token.type) { case "text": case "error": return [new _Op2.default(_Instr2.default.PUSH_NODE, new _HTMLNode.TextNode()), new _Op2.default(_Instr2.default.ADD_TOKEN, token), new _Op2.default(_Instr2.default.POP_NODE)]; case "commentStart": this.pushDialect("comment"); return [new _Op2.default(_Instr2.default.PUSH_NODE, new _HTMLNode.CommentNode()), new _Op2.default(_Instr2.default.ADD_TOKEN, token)]; case "entityStart": this.pushDialect("entity"); return [new _Op2.default(_Instr2.default.PUSH_NODE, new _HTMLNode.EntityNode()), new _Op2.default(_Instr2.default.ADD_TOKEN, token)]; case "tagStart": this.pushDialect("tag"); return [new _Op2.default(_Instr2.default.PUSH_NODE, new _HTMLNode.TagNode()), new _Op2.default(_Instr2.default.ADD_TOKEN, token)]; case "closeTagStart": this.pushDialect("closeTag"); return [new _Op2.default(_Instr2.default.PUSH_NODE, new _HTMLNode.CloseTagNode()), new _Op2.default(_Instr2.default.ADD_TOKEN, token)]; default: throw unknownTokenAssertion(token); } } /** * @private * @param {Foundation.Scanner.Token} token * @return {Array.<Op>} */ }, { key: 'generateCodeForCommentToken', value: function generateCodeForCommentToken(token) { switch (token.type) { case "text": case "dash": return [new _Op2.default(_Instr2.default.ADD_TOKEN, token)]; case "commentEnd": this.popDialect(); return [new _Op2.default(_Instr2.default.ADD_TOKEN, token), new _Op2.default(_Instr2.default.POP_NODE)]; default: throw unknownTokenAssertion(token); } } /** * @private * @param {Foundation.Scanner.Token} token */ }, { key: 'generateCodeForEntityToken', value: function generateCodeForEntityToken(token) { switch (token.type) { case "hex": case "dec": case "named": return [new _Op2.default(_Instr2.default.ADD_TOKEN, token)]; case "error": case "entityEnd": this.popDialect(); return [new _Op2.default(_Instr2.default.ADD_TOKEN, token), new _Op2.default(_Instr2.default.POP_NODE)]; default: throw unknownTokenAssertion(token); } } /** * @private * @param {Foundation.Scanner.Token} token * @return {Array.<Op>} */ }, { key: 'generateCodeForTagToken', value: function generateCodeForTagToken(token) { switch (token.type) { case "tagEnd": this.popDialect(); return [new _Op2.default(_Instr2.default.ADD_TOKEN, token), new _Op2.default(_Instr2.default.POP_NODE)]; case "whitespace": case "selfClose": return [new _Op2.default(_Instr2.default.ADD_TOKEN, token)]; case "attributeStart": case "error": this.pushDialect("attribute"); return [new _Op2.default(_Instr2.default.PUSH_NODE, new _HTMLNode.AttrNode()), new _Op2.default(_Instr2.default.ADD_TOKEN, token)]; default: throw unknownTokenAssertion(token); } } /** * @private * @param {Foundation.Scanner.Token} token * @return {Array.<Op>} */ }, { key: 'generateCodeForAttributeToken', value: function generateCodeForAttributeToken(token) { switch (token.type) { case "attributeValueQuotedStart": var isDquo = !!token.value.match(/"$/); this.setExpectedAttributeValueEndTokenType(isDquo ? "dquo" : "squo"); // continue into next case... case "attributeValueStart": this.popDialect(); this.pushDialect(token.type.replace(/Start$/, "")); // continue into next case... case "whitespace": return [new _Op2.default(_Instr2.default.ADD_TOKEN, token)]; case "tagEnd": this.popDialect(); // pop out of attribute dialect this.popDialect(); // pop out of tag dialect return [new _Op2.default(_Instr2.default.POP_NODE), new _Op2.default(_Instr2.default.ADD_TOKEN, token), new _Op2.default(_Instr2.default.POP_NODE)]; case "selfClose": this.popDialect(); return [new _Op2.default(_Instr2.default.POP_NODE), new _Op2.default(_Instr2.default.ADD_TOKEN, token)]; case "attributeStart": case "error": return [new _Op2.default(_Instr2.default.POP_NODE), new _Op2.default(_Instr2.default.PUSH_NODE, new _HTMLNode.AttrNode()), new _Op2.default(_Instr2.default.ADD_TOKEN, token)]; default: throw unknownTokenAssertion(token); } } /** * @private * @param {Foundation.Scanner.Token} token * @return {Array.<Op>} */ }, { key: 'generateCodeForAttributeValueToken', value: function generateCodeForAttributeValueToken(token) { switch (token.type) { case "whitespace": this.popDialect(); return [new _Op2.default(_Instr2.default.POP_NODE), new _Op2.default(_Instr2.default.ADD_TOKEN, token)]; case "entityStart": this.pushDialect("entity"); return [new _Op2.default(_Instr2.default.PUSH_NODE, new _HTMLNode.EntityNode()), new _Op2.default(_Instr2.default.ADD_TOKEN, token)]; case "tagEnd": this.popDialect(); // pop out of attributeValue dialect this.popDialect(); // pop out of tag dialect return [new _Op2.default(_Instr2.default.POP_NODE), new _Op2.default(_Instr2.default.ADD_TOKEN, token), new _Op2.default(_Instr2.default.POP_NODE)]; case "text": case "error": return [new _Op2.default(_Instr2.default.ADD_TOKEN, token)]; default: throw unknownTokenAssertion(token); } } /** * @private * @param {Foundation.Scanner.Token} token * @return {Array.<Op>} */ }, { key: 'generateCodeForAttributeValueQuotedToken', value: function generateCodeForAttributeValueQuotedToken(token) { switch (token.type) { case "dquo": case "squo": if (token.type === this.expectedAttributeValueEndTokenType()) { this.popDialect(); return [new _Op2.default(_Instr2.default.ADD_TOKEN, token), new _Op2.default(_Instr2.default.POP_NODE)]; } else { token.type = "text"; return [new _Op2.default(_Instr2.default.ADD_TOKEN, token)]; } case "entityStart": this.pushDialect("entity"); return [new _Op2.default(_Instr2.default.PUSH_NODE, new _HTMLNode.EntityNode()), new _Op2.default(_Instr2.default.ADD_TOKEN, token)]; case "error": case "text": return [new _Op2.default(_Instr2.default.ADD_TOKEN, token)]; default: throw unknownTokenAssertion(token); } } /** * @private * @param {Foundation.Scanner.Token} token * @return {Array.<Op>} */ }, { key: 'generateCodeForCloseTagToken', value: function generateCodeForCloseTagToken(token) { switch (token.type) { case "whitespace": case "error": return [new _Op2.default(_Instr2.default.ADD_TOKEN, token)]; case "tagEnd": this.popDialect(); return [new _Op2.default(_Instr2.default.ADD_TOKEN, token), new _Op2.default(_Instr2.default.POP_NODE)]; default: throw unknownTokenAssertion(token); } } /** * @private * @param {Foundation.Scanner.Token} token * @return {Array.<Op>} */ }, { key: 'generateCodeForRawtextToken', value: function generateCodeForRawtextToken(token) { switch (token.type) { case "closeTag": var closeTagName = token.value.toLowerCase().replace(/\W/g, ""); if (closeTagName === this.expectedRawtextClosingTagName()) { this.popDialect(); return [new _Op2.default(_Instr2.default.PUSH_NODE, new _HTMLNode.CloseTagNode()), new _Op2.default(_Instr2.default.ADD_TOKEN, token), new _Op2.default(_Instr2.default.POP_NODE)]; } case "text": case "lt": return [new _Op2.default(_Instr2.default.PUSH_NODE, new _HTMLNode.TextNode()), new _Op2.default(_Instr2.default.ADD_TOKEN, token), new _Op2.default(_Instr2.default.POP_NODE)]; default: throw unknownTokenAssertion(token); } } }]); return Compiler; }(); /** * @private * @param {Foundation.Scanner.Token} token * @return {Error} */ exports.default = Compiler; function unknownTokenAssertion(token) { return new Error("failed assertion: unkown token type: " + token.type); } //# sourceMappingURL=data:application/json;base64,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QkFBTSxzQkFBc0IsS0FBdEIsQ0FBTjtBQWJKO0FBZUQ7O0FBRUQ7Ozs7Ozs7O2dEQUs2QixLLEVBQU87QUFDbEMsY0FBUSxNQUFNLElBQWQ7QUFDRSxhQUFLLFVBQUw7QUFDRSxjQUFJLGVBQWUsTUFBTSxLQUFOLENBQVksV0FBWixHQUEwQixPQUExQixDQUFrQyxLQUFsQyxFQUF5QyxFQUF6QyxDQUFuQjtBQUNBLGNBQUksaUJBQWlCLEtBQUssNkJBQUwsRUFBckIsRUFBMkQ7QUFDekQsaUJBQUssVUFBTDtBQUNBLG1CQUFPLENBQ0wsaUJBQU8sZ0JBQU0sU0FBYixFQUF3Qiw0QkFBeEIsQ0FESyxFQUVMLGlCQUFPLGdCQUFNLFNBQWIsRUFBd0IsS0FBeEIsQ0FGSyxFQUdMLGlCQUFPLGdCQUFNLFFBQWIsQ0FISyxDQUFQO0FBS0Q7QUFDSCxhQUFLLE1BQUw7QUFDQSxhQUFLLElBQUw7QUFDRSxpQkFBTyxDQUNMLGlCQUFPLGdCQUFNLFNBQWIsRUFBd0Isd0JBQXhCLENBREssRUFFTCxpQkFBTyxnQkFBTSxTQUFiLEVBQXdCLEtBQXhCLENBRkssRUFHTCxpQkFBTyxnQkFBTSxRQUFiLENBSEssQ0FBUDtBQUtGO0FBQ0UsZ0JBQU0sc0JBQXNCLEtBQXRCLENBQU47QUFuQko7QUFxQkQ7Ozs7OztBQUdIOzs7Ozs7O2tCQTVnQnFCLFE7QUFpaEJyQixTQUFTLHFCQUFULENBQWdDLEtBQWhDLEVBQXVDO0FBQ3JDLFNBQU8sSUFBSSxLQUFKLENBQVUsMENBQTBDLE1BQU0sSUFBMUQsQ0FBUDtBQUNEIiwiZmlsZSI6IkNvbXBpbGVyLmpzIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IEluc3RyIGZyb20gJy4vSW5zdHInXG5pbXBvcnQgT3AgZnJvbSAnLi9PcCdcbmltcG9ydCBTY2FubmVyIGZyb20gJ0BkZXNlcnRuZXQvc2Nhbm5lcidcbmltcG9ydCB7VGFnTm9kZSwgVGV4dE5vZGUsIEF0dHJOb2RlLCBDbG9zZVRhZ05vZGUsIENvbW1lbnROb2RlLCBFbnRpdHlOb2RlfSBmcm9tICcuL0hUTUxOb2RlJ1xuXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBDb21waWxlciB7XG4gIGNvbnN0cnVjdG9yICgpIHtcbiAgICB2YXIgZW50aXR5U3RhcnQgPSAvJig/PVthLXowLTkjXSs7KS9pO1xuICAgIHZhciBhdHRyaWJ1dGVTdGFydCA9IC9bXj49XFxzXFwvXSsvaTtcblxuICAgIC8qKlxuICAgICAqIFRoZSB0b2tlbml6aW5nIHNjYW5uZXIgZm9yIHRoZSBpbnB1dCBzdHJpbmcuIEhUTUwgY29udGFpbnNcbiAgICAgKiBtYW55IGNvbnRleHRzIHdoZXJlIHRoZSBzY2FubmVyIG5lZWRzIHRvIGFjY2VwdCBkaWZmZXJudFxuICAgICAqIHNldHMgb2YgdG9rZW5zLiBUaGUgQGRlc2VydG5ldC9zY2FubmVyIG1vZHVsZSBjYWxscyB0aGVzZVxuICAgICAqIHNldHMgb2YgdG9rZW4gZGVmaW5pdGlvbnMgXCJkaWFsZWN0c1wiLiBCZWxvdywgd2UncmUgaW5pdGlhbGl6aW5nXG4gICAgICogb3VyIHNjYW5uZXIgd2l0aCBhbGwgdGhlc2UgZGlmZmVyZW50IGRpYWxlY3RzLlxuICAgICAqIEBwcml2YXRlXG4gICAgICogQHR5cGUge1NjYW5uZXJ9XG4gICAgICovXG4gICAgdGhpcy5fc2Nhbm5lciA9IG5ldyBTY2FubmVyKHtcbiAgICAgIC8vIFN0YXJ0aW5nIGRpYWxlY3QsIGZvciBjb250ZW50IFwib3V0c2lkZSBvZiBhIHRhZ1wiLlxuICAgICAgXCJjb250ZW50XCI6IFtcbiAgICAgICAge1widGV4dFwiOiAvW148PiZdKy99LFxuICAgICAgICB7XCJjb21tZW50U3RhcnRcIjogLzwhLS0vfSxcbiAgICAgICAge1wiZW50aXR5U3RhcnRcIjogZW50aXR5U3RhcnR9LFxuICAgICAgICB7XCJ0YWdTdGFydFwiOiAvPFthLXpdW15cXHRcXG5cXCBcXC9cXD5cXDBcXHhmZl0qL2l9LFxuICAgICAgICB7XCJjbG9zZVRhZ1N0YXJ0XCI6IC88XFwvW2Etel1bXlxcdFxcblxcIFxcL1xcPlxcMFxceGZmXSovaX0sXG4gICAgICAgIHtcImVycm9yXCI6IC9bPD4mXS99XG4gICAgICBdLFxuXG4gICAgICAvLyBEaWFsZWN0IGZvciB0aGUgaW5zaWRlIG9mIGNvbW1lbnQgdGFncy5cbiAgICAgIFwiY29tbWVudFwiOiBbXG4gICAgICAgIHtcImNvbW1lbnRFbmRcIjogLy0tPi99LFxuICAgICAgICB7XCJkYXNoXCI6IC8tL30sXG4gICAgICAgIHtcInRleHRcIjogL1teLV0rL31cbiAgICAgIF0sXG5cbiAgICAgIC8vIERpYWxlY3QgZm9yIHRoZSBpbnNpZGUgb2YgSFRNTCBlbnRpdGllcy5cbiAgICAgIFwiZW50aXR5XCI6IFtcbiAgICAgICAge1wiZW50aXR5RW5kXCI6IC87L30sXG4gICAgICAgIHtcImhleFwiOiAvI3hbYS1mMC05XSsvaX0sXG4gICAgICAgIHtcImRlY1wiOiAvI1xcZCsvfSxcbiAgICAgICAge1wibmFtZWRcIjogL1thLXpdW2EtejAtOV0qL2l9LFxuICAgICAgICB7XCJlcnJvclwiOiAvW15dL31cbiAgICAgIF0sXG5cbiAgICAgIC8vIERpYWxlY3QgZm9yIHRoZSBpbnNpZGUgb2YgdGFncy5cbiAgICAgIFwidGFnXCI6IFtcbiAgICAgICAge1widGFnRW5kXCI6IC8+L30sXG4gICAgICAgIHtcIndoaXRlc3BhY2VcIjogL1xccysvfSxcbiAgICAgICAge1wic2VsZkNsb3NlXCI6IC9cXC8vfSxcbiAgICAgICAge1wiZXJyb3JcIjogL1snXCI8PV0vfSxcbiAgICAgICAge1wiYXR0cmlidXRlU3RhcnRcIjogYXR0cmlidXRlU3RhcnR9XG4gICAgICBdLFxuXG4gICAgICAvLyBJbml0aWFsIGRpYWxlY3QgZm9yIGF0dHJpYnV0ZXMuXG4gICAgICBcImF0dHJpYnV0ZVwiOiBbXG4gICAgICAgIHtcIndoaXRlc3BhY2VcIjogL1xccysvfSxcbiAgICAgICAge1wiYXR0cmlidXRlVmFsdWVRdW90ZWRTdGFydFwiOiAvPVsnXCJdL30sXG4gICAgICAgIHtcImF0dHJpYnV0ZVZhbHVlU3RhcnRcIjogLz0vfSxcbiAgICAgICAge1widGFnRW5kXCI6IC8+L30sXG4gICAgICAgIHtcInNlbGZDbG9zZVwiOiAvXFwvL30sXG4gICAgICAgIHtcImVycm9yXCI6IC9bJ1wiPF0vfSxcbiAgICAgICAge1wiYXR0cmlidXRlU3RhcnRcIjogYXR0cmlidXRlU3RhcnR9XG4gICAgICBdLFxuXG4gICAgICAvLyBEaWFsZWN0IGZvciB1bnF1b3RlZCBhdHRyaWJ1dGUgdmFsdWVzLlxuICAgICAgXCJhdHRyaWJ1dGVWYWx1ZVwiOiBbXG4gICAgICAgIHtcIndoaXRlc3BhY2VcIjogL1xccysvfSxcbiAgICAgICAge1wiZW50aXR5U3RhcnRcIjogZW50aXR5U3RhcnR9LFxuICAgICAgICB7XCJ0YWdFbmRcIjogLz4vfSxcbiAgICAgICAge1wiZXJyb3JcIjogL1snXCI8PWAmXS99LFxuICAgICAgICB7XCJ0ZXh0XCI6IC9bXidcIjw+PWAmXFxzXSsvfVxuICAgICAgXSxcblxuICAgICAgLy8gRGlhbGVjdCBmb3IgcXVvdGVkIGF0dHJpYnV0ZSB2YWx1ZXMuXG4gICAgICBcImF0dHJpYnV0ZVZhbHVlUXVvdGVkXCI6IFtcbiAgICAgICAge1wiZHF1b1wiOiAvXCIvfSxcbiAgICAgICAge1wic3F1b1wiOiAvJy99LFxuICAgICAgICB7XCJlbnRpdHlTdGFydFwiOiBlbnRpdHlTdGFydH0sXG4gICAgICAgIHtcImVycm9yXCI6IC8mL30sXG4gICAgICAgIHtcInRleHRcIjogL1teXCInJl0rL31cbiAgICAgIF0sXG5cbiAgICAgIC8vIERpYWxlY3QgZm9yIGNsb3NpbmcgdGFncy5cbiAgICAgIFwiY2xvc2VUYWdcIjogW1xuICAgICAgICB7XCJ0YWdFbmRcIjogLz4vfSxcbiAgICAgICAge1wid2hpdGVzcGFjZVwiOiAvXFxzKy99LFxuICAgICAgICB7XCJlcnJvclwiOiAvW15cXHM+XSsvfVxuICAgICAgXSxcblxuICAgICAgLy8gRGlhbGVjdCBmb3IgaW5zaWRlIG9mIHNjcmlwdCwgc3R5bGUsIGFuZCB4bXAgdGFnc1xuICAgICAgXCJyYXd0ZXh0XCI6IFtcbiAgICAgICAge1wiY2xvc2VUYWdcIjogLzxcXC9bYS16XStcXHMqPi9pfSxcbiAgICAgICAge1widGV4dFwiOiAvW148XSsvfSxcbiAgICAgICAge1wibHRcIjogLzwvfVxuICAgICAgXVxuICAgIH0pO1xuXG4gICAgLyoqXG4gICAgICogQHByaXZhdGVcbiAgICAgKiBAdHlwZSB7c3RyaW5nfVxuICAgICAqL1xuICAgIHRoaXMuX2V4cGVjdGVkQXR0cmlidXRlVmFsdWVFbmRUb2tlblR5cGU7XG5cbiAgICAvKipcbiAgICAgKiBAcHJpdmF0ZVxuICAgICAqIEB0eXBlIHtzdHJpbmd9XG4gICAgICovXG4gICAgdGhpcy5fZXhwZWN0ZWRSYXd0ZXh0Q2xvc2luZ1RhZ05hbWU7XG4gIH1cblxuXG4gIC8qKlxuICAgKiBAcGFyYW0ge3N0cmluZ30gaHRtbFxuICAgKi9cbiAgc2V0SW5wdXQgKGh0bWwpIHtcbiAgICB0aGlzLl9zY2FubmVyLnNldFNvdXJjZShodG1sKTtcbiAgICB0aGlzLl9zY2FubmVyLnB1c2hEaWFsZWN0KFwiY29udGVudFwiKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBAcHJpdmF0ZVxuICAgKiBAcGFyYW0ge3N0cmluZ30gZGlhbGVjdFxuICAgKi9cbiAgcHVzaERpYWxlY3QgKGRpYWxlY3QpIHtcbiAgICB0aGlzLl9zY2FubmVyLnB1c2hEaWFsZWN0KGRpYWxlY3QpO1xuICB9XG5cbiAgLyoqXG4gICAqIEBwcml2YXRlXG4gICAqL1xuICBwb3BEaWFsZWN0ICgpIHtcbiAgICB0aGlzLl9zY2FubmVyLnBvcERpYWxlY3QoKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBAcHJpdmF0ZVxuICAgKiBAcmV0dXJuIHtzdHJpbmd9XG4gICAqL1xuICBjdXJyZW50RGlhbGVjdCAoKSB7XG4gICAgdmFyIGRpYWxlY3QgPSB0aGlzLl9zY2FubmVyLmN1cnJlbnREaWFsZWN0KCk7XG5cbiAgICBpZiAoZGlhbGVjdCA9PT0gbnVsbCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKFwiU2Nhbm5lciBkaWFsZWN0IHVuZXhwZWN0ZWRseSBudWxsLlwiKTtcbiAgICB9XG5cbiAgICByZXR1cm4gZGlhbGVjdDtcbiAgfVxuXG4gIC8qKlxuICAgKiBAcHJpdmF0ZVxuICAgKiBAcGFyYW0ge3N0cmluZ30gdG9rZW5UeXBlXG4gICAqL1xuICBzZXRFeHBlY3RlZEF0dHJpYnV0ZVZhbHVlRW5kVG9rZW5UeXBlICh0b2tlblR5cGUpIHtcbiAgICB0aGlzLl9leHBlY3RlZEF0dHJpYnV0ZVZhbHVlRW5kVG9rZW5UeXBlID0gdG9rZW5UeXBlO1xuICB9XG5cbiAgLyoqXG4gICAqIEBwcml2YXRlXG4gICAqIEByZXR1cm4ge3N0cmluZ31cbiAgICovXG4gIGV4cGVjdGVkQXR0cmlidXRlVmFsdWVFbmRUb2tlblR5cGUgKCkge1xuICAgIHJldHVybiB0aGlzLl9leHBlY3RlZEF0dHJpYnV0ZVZhbHVlRW5kVG9rZW5UeXBlO1xuICB9XG5cbiAgLyoqXG4gICAqIEBwcml2YXRlXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBuYW1lXG4gICAqL1xuICBzZXRFeHBlY3RlZFJhd3RleHRDbG9zaW5nVGFnTmFtZSAobmFtZSkge1xuICAgIHRoaXMuX2V4cGVjdGVkUmF3dGV4dENsb3NpbmdUYWdOYW1lID0gbmFtZS50b0xvd2VyQ2FzZSgpO1xuICB9XG5cbiAgLyoqXG4gICAqIEBwcml2YXRlXG4gICAqIEByZXR1cm4ge3N0cmluZ31cbiAgICovXG4gIGV4cGVjdGVkUmF3dGV4dENsb3NpbmdUYWdOYW1lICgpIHtcbiAgICByZXR1cm4gdGhpcy5fZXhwZWN0ZWRSYXd0ZXh0Q2xvc2luZ1RhZ05hbWU7XG4gIH1cblxuICAvKipcbiAgICogQHBhcmFtIHtzdHJpbmd9IHRhZ05hbWVcbiAgICovXG4gIHNldFJhd3RleHRNb2RlRm9yVGFnICh0YWdOYW1lKSB7XG4gICAgdGhpcy5wdXNoRGlhbGVjdChcInJhd3RleHRcIik7XG4gICAgdGhpcy5zZXRFeHBlY3RlZFJhd3RleHRDbG9zaW5nVGFnTmFtZSh0YWdOYW1lKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBAcmV0dXJuIHtBcnJheS48T3A+fVxuICAgKi9cbiAgZ2VuZXJhdGVOZXh0Q29kZUZyYWdtZW50ICgpIHtcbiAgICB2YXIgdG9rZW4gPSB0aGlzLl9zY2FubmVyLm5leHRUb2tlbigpO1xuXG4gICAgaWYgKHRva2VuID09PSBudWxsKSB7XG4gICAgICByZXR1cm4gbnVsbDtcbiAgICB9XG5cbiAgICByZXR1cm4gdGhpcy5nZW5lcmF0ZUNvZGVGb3JUb2tlbkluRGlhbGVjdCh0b2tlbiwgdGhpcy5jdXJyZW50RGlhbGVjdCgpKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBUYWtlIGEgbm9kZSBhbmQgdGhlIGRpYWxlY3QgaW4gd2hpY2ggaXQgd2FzIGZvdW5kLCBhbmQgdGVsbCB0aGVcbiAgICogcGFyc2VyIHdoYXQgdG8gZG8gbmV4dC5cbiAgICogQHByaXZhdGVcbiAgICogQHBhcmFtIHtGb3VuZGF0aW9uLlNjYW5uZXIuVG9rZW59IHRva2VuXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBkaWFsZWN0XG4gICAqIEByZXR1cm4ge0FycmF5LjxPcD59XG4gICAqL1xuICBnZW5lcmF0ZUNvZGVGb3JUb2tlbkluRGlhbGVjdCAodG9rZW4sIGRpYWxlY3QpIHtcbiAgICBzd2l0Y2ggKGRpYWxlY3QpIHtcbiAgICAgIGNhc2UgXCJjb250ZW50XCI6XG4gICAgICAgIHJldHVybiB0aGlzLmdlbmVyYXRlQ29kZUZvckNvbnRlbnRUb2tlbih0b2tlbik7XG4gICAgICBjYXNlIFwiY29tbWVudFwiOlxuICAgICAgICByZXR1cm4gdGhpcy5nZW5lcmF0ZUNvZGVGb3JDb21tZW50VG9rZW4odG9rZW4pO1xuICAgICAgY2FzZSBcImVudGl0eVwiOlxuICAgICAgICByZXR1cm4gdGhpcy5nZW5lcmF0ZUNvZGVGb3JFbnRpdHlUb2tlbih0b2tlbik7XG4gICAgICBjYXNlIFwidGFnXCI6XG4gICAgICAgIHJldHVybiB0aGlzLmdlbmVyYXRlQ29kZUZvclRhZ1Rva2VuKHRva2VuKTtcbiAgICAgIGNhc2UgXCJhdHRyaWJ1dGVcIjpcbiAgICAgICAgcmV0dXJuIHRoaXMuZ2VuZXJhdGVDb2RlRm9yQXR0cmlidXRlVG9rZW4odG9rZW4pO1xuICAgICAgY2FzZSBcImF0dHJpYnV0ZVZhbHVlXCI6XG4gICAgICAgIHJldHVybiB0aGlzLmdlbmVyYXRlQ29kZUZvckF0dHJpYnV0ZVZhbHVlVG9rZW4odG9rZW4pO1xuICAgICAgY2FzZSBcImF0dHJpYnV0ZVZhbHVlUXVvdGVkXCI6XG4gICAgICAgIHJldHVybiB0aGlzLmdlbmVyYXRlQ29kZUZvckF0dHJpYnV0ZVZhbHVlUXVvdGVkVG9rZW4odG9rZW4pO1xuICAgICAgY2FzZSBcImNsb3NlVGFnXCI6XG4gICAgICAgIHJldHVybiB0aGlzLmdlbmVyYXRlQ29kZUZvckNsb3NlVGFnVG9rZW4odG9rZW4pO1xuICAgICAgY2FzZSBcInJhd3RleHRcIjpcbiAgICAgICAgcmV0dXJuIHRoaXMuZ2VuZXJhdGVDb2RlRm9yUmF3dGV4dFRva2VuKHRva2VuKTtcbiAgICAgIGRlZmF1bHQ6XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihcIkNhbGxlZCBjb21waWxlVG9rZW5Gb3JEaWFsZWN0IG9uIHVuc3VwcG90ZWQgZGlhbGVjdC5cIik7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIEBwcml2YXRlXG4gICAqIEBwYXJhbSB7Rm91bmRhdGlvbi5TY2FubmVyLlRva2VufSB0b2tlblxuICAgKiBAcmV0dXJuIHtBcnJheS48T3A+fVxuICAgKi9cbiAgZ2VuZXJhdGVDb2RlRm9yQ29udGVudFRva2VuICh0b2tlbikge1xuICAgIHN3aXRjaCAodG9rZW4udHlwZSkge1xuICAgICAgY2FzZSBcInRleHRcIjpcbiAgICAgIGNhc2UgXCJlcnJvclwiOlxuICAgICAgICByZXR1cm4gW1xuICAgICAgICAgIG5ldyBPcChJbnN0ci5QVVNIX05PREUsIG5ldyBUZXh0Tm9kZSgpKSxcbiAgICAgICAgICBuZXcgT3AoSW5zdHIuQUREX1RPS0VOLCB0b2tlbiksXG4gICAgICAgICAgbmV3IE9wKEluc3RyLlBPUF9OT0RFKVxuICAgICAgICBdO1xuICAgICAgY2FzZSBcImNvbW1lbnRTdGFydFwiOlxuICAgICAgICB0aGlzLnB1c2hEaWFsZWN0KFwiY29tbWVudFwiKTtcbiAgICAgICAgcmV0dXJuIFtcbiAgICAgICAgICBuZXcgT3AoSW5zdHIuUFVTSF9OT0RFLCBuZXcgQ29tbWVudE5vZGUoKSksXG4gICAgICAgICAgbmV3IE9wKEluc3RyLkFERF9UT0tFTiwgdG9rZW4pXG4gICAgICAgIF07XG4gICAgICBjYXNlIFwiZW50aXR5U3RhcnRcIjpcbiAgICAgICAgdGhpcy5wdXNoRGlhbGVjdChcImVudGl0eVwiKTtcbiAgICAgICAgcmV0dXJuIFtcbiAgICAgICAgICBuZXcgT3AoSW5zdHIuUFVTSF9OT0RFLCBuZXcgRW50aXR5Tm9kZSgpKSxcbiAgICAgICAgICBuZXcgT3AoSW5zdHIuQUREX1RPS0VOLCB0b2tlbilcbiAgICAgICAgXTtcbiAgICAgIGNhc2UgXCJ0YWdTdGFydFwiOlxuICAgICAgICB0aGlzLnB1c2hEaWFsZWN0KFwidGFnXCIpO1xuICAgICAgICByZXR1cm4gW1xuICAgICAgICAgIG5ldyBPcChJbnN0ci5QVVNIX05PREUsIG5ldyBUYWdOb2RlKCkpLFxuICAgICAgICAgIG5ldyBPcChJbnN0ci5BRERfVE9LRU4sIHRva2VuKVxuICAgICAgICBdO1xuICAgICAgY2FzZSBcImNsb3NlVGFnU3RhcnRcIjpcbiAgICAgICAgdGhpcy5wdXNoRGlhbGVjdChcImNsb3NlVGFnXCIpO1xuICAgICAgICByZXR1cm4gW1xuICAgICAgICAgIG5ldyBPcChJbnN0ci5QVVNIX05PREUsIG5ldyBDbG9zZVRhZ05vZGUoKSksXG4gICAgICAgICAgbmV3IE9wKEluc3RyLkFERF9UT0tFTiwgdG9rZW4pXG4gICAgICAgIF07XG4gICAgICBkZWZhdWx0OlxuICAgICAgICB0aHJvdyB1bmtub3duVG9rZW5Bc3NlcnRpb24odG9rZW4pO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBAcHJpdmF0ZVxuICAgKiBAcGFyYW0ge0ZvdW5kYXRpb24uU2Nhbm5lci5Ub2tlbn0gdG9rZW5cbiAgICogQHJldHVybiB7QXJyYXkuPE9wPn1cbiAgICovXG4gIGdlbmVyYXRlQ29kZUZvckNvbW1lbnRUb2tlbiAodG9rZW4pIHtcbiAgICBzd2l0Y2ggKHRva2VuLnR5cGUpIHtcbiAgICAgIGNhc2UgXCJ0ZXh0XCI6XG4gICAgICBjYXNlIFwiZGFzaFwiOlxuICAgICAgICByZXR1cm4gW1xuICAgICAgICAgIG5ldyBPcChJbnN0ci5BRERfVE9LRU4sIHRva2VuKVxuICAgICAgICBdO1xuICAgICAgY2FzZSBcImNvbW1lbnRFbmRcIjpcbiAgICAgICAgdGhpcy5wb3BEaWFsZWN0KCk7XG4gICAgICAgIHJldHVybiBbXG4gICAgICAgICAgbmV3IE9wKEluc3RyLkFERF9UT0tFTiwgdG9rZW4pLFxuICAgICAgICAgIG5ldyBPcChJbnN0ci5QT1BfTk9ERSlcbiAgICAgICAgXTtcbiAgICAgIGRlZmF1bHQ6XG4gICAgICAgICB0aHJvdyB1bmtub3duVG9rZW5Bc3NlcnRpb24odG9rZW4pO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBAcHJpdmF0ZVxuICAgKiBAcGFyYW0ge0ZvdW5kYXRpb24uU2Nhbm5lci5Ub2tlbn0gdG9rZW5cbiAgICovXG4gIGdlbmVyYXRlQ29kZUZvckVudGl0eVRva2VuICh0b2tlbikge1xuICAgIHN3aXRjaCAodG9rZW4udHlwZSkge1xuICAgICAgY2FzZSBcImhleFwiOlxuICAgICAgY2FzZSBcImRlY1wiOlxuICAgICAgY2FzZSBcIm5hbWVkXCI6XG4gICAgICAgIHJldHVybiBbXG4gICAgICAgICAgbmV3IE9wKEluc3RyLkFERF9UT0tFTiwgdG9rZW4pXG4gICAgICAgIF07XG4gICAgICBjYXNlIFwiZXJyb3JcIjpcbiAgICAgIGNhc2UgXCJlbnRpdHlFbmRcIjpcbiAgICAgICAgdGhpcy5wb3BEaWFsZWN0KCk7XG4gICAgICAgIHJldHVybiBbXG4gICAgICAgICAgbmV3IE9wKEluc3RyLkFERF9UT0tFTiwgdG9rZW4pLFxuICAgICAgICAgIG5ldyBPcChJbnN0ci5QT1BfTk9ERSlcbiAgICAgICAgXTtcbiAgICAgIGRlZmF1bHQ6XG4gICAgICAgIHRocm93IHVua25vd25Ub2tlbkFzc2VydGlvbih0b2tlbik7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIEBwcml2YXRlXG4gICAqIEBwYXJhbSB7Rm91bmRhdGlvbi5TY2FubmVyLlRva2VufSB0b2tlblxuICAgKiBAcmV0dXJuIHtBcnJheS48T3A+fVxuICAgKi9cbiAgZ2VuZXJhdGVDb2RlRm9yVGFnVG9rZW4gKHRva2VuKSB7XG4gICAgc3dpdGNoICh0b2tlbi50eXBlKSB7XG4gICAgICBjYXNlIFwidGFnRW5kXCI6XG4gICAgICAgIHRoaXMucG9wRGlhbGVjdCgpO1xuICAgICAgICByZXR1cm4gW1xuICAgICAgICAgIG5ldyBPcChJbnN0ci5BRERfVE9LRU4sIHRva2VuKSxcbiAgICAgICAgICBuZXcgT3AoSW5zdHIuUE9QX05PREUpXG4gICAgICAgIF07XG4gICAgICBjYXNlIFwid2hpdGVzcGFjZVwiOlxuICAgICAgY2FzZSBcInNlbGZDbG9zZVwiOlxuICAgICAgICByZXR1cm4gW1xuICAgICAgICAgIG5ldyBPcChJbnN0ci5BRERfVE9LRU4sIHRva2VuKVxuICAgICAgICBdO1xuICAgICAgY2FzZSBcImF0dHJpYnV0ZVN0YXJ0XCI6XG4gICAgICBjYXNlIFwiZXJyb3JcIjpcbiAgICAgICAgdGhpcy5wdXNoRGlhbGVjdChcImF0dHJpYnV0ZVwiKTtcbiAgICAgICAgcmV0dXJuIFtcbiAgICAgICAgICBuZXcgT3AoSW5zdHIuUFVTSF9OT0RFLCBuZXcgQXR0ck5vZGUoKSksXG4gICAgICAgICAgbmV3IE9wKEluc3RyLkFERF9UT0tFTiwgdG9rZW4pXG4gICAgICAgIF07XG4gICAgICBkZWZhdWx0OlxuICAgICAgICB0aHJvdyB1bmtub3duVG9rZW5Bc3NlcnRpb24odG9rZW4pO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBAcHJpdmF0ZVxuICAgKiBAcGFyYW0ge0ZvdW5kYXRpb24uU2Nhbm5lci5Ub2tlbn0gdG9rZW5cbiAgICogQHJldHVybiB7QXJyYXkuPE9wPn1cbiAgICovXG4gIGdlbmVyYXRlQ29kZUZvckF0dHJpYnV0ZVRva2VuICh0b2tlbikge1xuICAgIHN3aXRjaCAodG9rZW4udHlwZSkge1xuICAgICAgY2FzZSBcImF0dHJpYnV0ZVZhbHVlUXVvdGVkU3RhcnRcIjpcbiAgICAgICAgdmFyIGlzRHF1byA9ICEhdG9rZW4udmFsdWUubWF0Y2goL1wiJC8pO1xuICAgICAgICB0aGlzLnNldEV4cGVjdGVkQXR0cmlidXRlVmFsdWVFbmRUb2tlblR5cGUoaXNEcXVvID8gXCJkcXVvXCIgOiBcInNxdW9cIik7XG4gICAgICAgIC8vIGNvbnRpbnVlIGludG8gbmV4dCBjYXNlLi4uXG4gICAgICBjYXNlIFwiYXR0cmlidXRlVmFsdWVTdGFydFwiOlxuICAgICAgICB0aGlzLnBvcERpYWxlY3QoKTtcbiAgICAgICAgdGhpcy5wdXNoRGlhbGVjdCh0b2tlbi50eXBlLnJlcGxhY2UoL1N0YXJ0JC8sIFwiXCIpKTtcbiAgICAgICAgLy8gY29udGludWUgaW50byBuZXh0IGNhc2UuLi5cbiAgICAgIGNhc2UgXCJ3aGl0ZXNwYWNlXCI6XG4gICAgICAgIHJldHVybiBbXG4gICAgICAgICAgbmV3IE9wKEluc3RyLkFERF9UT0tFTiwgdG9rZW4pXG4gICAgICAgIF07XG4gICAgICBjYXNlIFwidGFnRW5kXCI6XG4gICAgICAgIHRoaXMucG9wRGlhbGVjdCgpOyAgLy8gcG9wIG91dCBvZiBhdHRyaWJ1dGUgZGlhbGVjdFxuICAgICAgICB0aGlzLnBvcERpYWxlY3QoKTsgIC8vIHBvcCBvdXQgb2YgdGFnIGRpYWxlY3RcbiAgICAgICAgcmV0dXJuIFtcbiAgICAgICAgICBuZXcgT3AoSW5zdHIuUE9QX05PREUpLFxuICAgICAgICAgIG5ldyBPcChJbnN0ci5BRERfVE9LRU4sIHRva2VuKSxcbiAgICAgICAgICBuZXcgT3AoSW5zdHIuUE9QX05PREUpXG4gICAgICAgIF07XG4gICAgICBjYXNlIFwic2VsZkNsb3NlXCI6XG4gICAgICAgIHRoaXMucG9wRGlhbGVjdCgpO1xuICAgICAgICByZXR1cm4gW1xuICAgICAgICAgIG5ldyBPcChJbnN0ci5QT1BfTk9ERSksXG4gICAgICAgICAgbmV3IE9wKEluc3RyLkFERF9UT0tFTiwgdG9rZW4pXG4gICAgICAgIF07XG4gICAgICBjYXNlIFwiYXR0cmlidXRlU3RhcnRcIjpcbiAgICAgIGNhc2UgXCJlcnJvclwiOlxuICAgICAgICByZXR1cm4gW1xuICAgICAgICAgIG5ldyBPcChJbnN0ci5QT1BfTk9ERSksXG4gICAgICAgICAgbmV3IE9wKEluc3RyLlBVU0hfTk9ERSwgbmV3IEF0dHJOb2RlKCkpLFxuICAgICAgICAgIG5ldyBPcChJbnN0ci5BRERfVE9LRU4sIHRva2VuKVxuICAgICAgICBdO1xuICAgICAgZGVmYXVsdDpcbiAgICAgICAgdGhyb3cgdW5rbm93blRva2VuQXNzZXJ0aW9uKHRva2VuKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogQHByaXZhdGVcbiAgICogQHBhcmFtIHtGb3VuZGF0aW9uLlNjYW5uZXIuVG9rZW59IHRva2VuXG4gICAqIEByZXR1cm4ge0FycmF5LjxPcD59XG4gICAqL1xuICBnZW5lcmF0ZUNvZGVGb3JBdHRyaWJ1dGVWYWx1ZVRva2VuICh0b2tlbikge1xuICAgIHN3aXRjaCAodG9rZW4udHlwZSkge1xuICAgICAgY2FzZSBcIndoaXRlc3BhY2VcIjpcbiAgICAgICAgdGhpcy5wb3BEaWFsZWN0KCk7XG4gICAgICAgIHJldHVybiBbXG4gICAgICAgICAgbmV3IE9wKEluc3RyLlBPUF9OT0RFKSxcbiAgICAgICAgICBuZXcgT3AoSW5zdHIuQUREX1RPS0VOLCB0b2tlbilcbiAgICAgICAgXTtcbiAgICAgIGNhc2UgXCJlbnRpdHlTdGFydFwiOlxuICAgICAgICB0aGlzLnB1c2hEaWFsZWN0KFwiZW50aXR5XCIpO1xuICAgICAgICByZXR1cm4gW1xuICAgICAgICAgIG5ldyBPcChJbnN0ci5QVVNIX05PREUsIG5ldyBFbnRpdHlOb2RlKCkpLFxuICAgICAgICAgIG5ldyBPcChJbnN0ci5BRERfVE9LRU4sIHRva2VuKVxuICAgICAgICBdO1xuICAgICAgY2FzZSBcInRhZ0VuZFwiOlxuICAgICAgICB0aGlzLnBvcERpYWxlY3QoKTsgIC8vIHBvcCBvdXQgb2YgYXR0cmlidXRlVmFsdWUgZGlhbGVjdFxuICAgICAgICB0aGlzLnBvcERpYWxlY3QoKTsgIC8vIHBvcCBvdXQgb2YgdGFnIGRpYWxlY3RcbiAgICAgICAgcmV0dXJuIFtcbiAgICAgICAgICBuZXcgT3AoSW5zdHIuUE9QX05PREUpLFxuICAgICAgICAgIG5ldyBPcChJbnN0ci5BRERfVE9LRU4sIHRva2VuKSxcbiAgICAgICAgICBuZXcgT3AoSW5zdHIuUE9QX05PREUpXG4gICAgICAgIF07XG4gICAgICBjYXNlIFwidGV4dFwiOlxuICAgICAgY2FzZSBcImVycm9yXCI6XG4gICAgICAgIHJldHVybiBbXG4gICAgICAgICAgbmV3IE9wKEluc3RyLkFERF9UT0tFTiwgdG9rZW4pXG4gICAgICAgIF07XG4gICAgICBkZWZhdWx0OlxuICAgICAgICB0aHJvdyB1bmtub3duVG9rZW5Bc3NlcnRpb24odG9rZW4pO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBAcHJpdmF0ZVxuICAgKiBAcGFyYW0ge0ZvdW5kYXRpb24uU2Nhbm5lci5Ub2tlbn0gdG9rZW5cbiAgICogQHJldHVybiB7QXJyYXkuPE9wPn1cbiAgICovXG4gIGdlbmVyYXRlQ29kZUZvckF0dHJpYnV0ZVZhbHVlUXVvdGVkVG9rZW4gKHRva2VuKSB7XG4gICAgc3dpdGNoICh0b2tlbi50eXBlKSB7XG4gICAgICBjYXNlIFwiZHF1b1wiOlxuICAgICAgY2FzZSBcInNxdW9cIjpcbiAgICAgICAgaWYgKHRva2VuLnR5cGUgPT09IHRoaXMuZXhwZWN0ZWRBdHRyaWJ1dGVWYWx1ZUVuZFRva2VuVHlwZSgpKSB7XG4gICAgICAgICAgdGhpcy5wb3BEaWFsZWN0KCk7XG4gICAgICAgICAgcmV0dXJuIFtcbiAgICAgICAgICAgIG5ldyBPcChJbnN0ci5BRERfVE9LRU4sIHRva2VuKSxcbiAgICAgICAgICAgIG5ldyBPcChJbnN0ci5QT1BfTk9ERSlcbiAgICAgICAgICBdO1xuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgIHRva2VuLnR5cGUgPSBcInRleHRcIjtcbiAgICAgICAgICByZXR1cm4gW1xuICAgICAgICAgICAgbmV3IE9wKEluc3RyLkFERF9UT0tFTiwgdG9rZW4pXG4gICAgICAgICAgXTtcbiAgICAgICAgfVxuICAgICAgY2FzZSBcImVudGl0eVN0YXJ0XCI6XG4gICAgICAgIHRoaXMucHVzaERpYWxlY3QoXCJlbnRpdHlcIik7XG4gICAgICAgIHJldHVybiBbXG4gICAgICAgICAgbmV3IE9wKEluc3RyLlBVU0hfTk9ERSwgbmV3IEVudGl0eU5vZGUoKSksXG4gICAgICAgICAgbmV3IE9wKEluc3RyLkFERF9UT0tFTiwgdG9rZW4pXG4gICAgICAgIF07XG4gICAgICBjYXNlIFwiZXJyb3JcIjpcbiAgICAgIGNhc2UgXCJ0ZXh0XCI6XG4gICAgICAgIHJldHVybiBbXG4gICAgICAgICAgbmV3IE9wKEluc3RyLkFERF9UT0tFTiwgdG9rZW4pXG4gICAgICAgIF07XG4gICAgICBkZWZhdWx0OlxuICAgICAgICB0aHJvdyB1bmtub3duVG9rZW5Bc3NlcnRpb24odG9rZW4pO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBAcHJpdmF0ZVxuICAgKiBAcGFyYW0ge0ZvdW5kYXRpb24uU2Nhbm5lci5Ub2tlbn0gdG9rZW5cbiAgICogQHJldHVybiB7QXJyYXkuPE9wPn1cbiAgICovXG4gIGdlbmVyYXRlQ29kZUZvckNsb3NlVGFnVG9rZW4gKHRva2VuKSB7XG4gICAgc3dpdGNoICh0b2tlbi50eXBlKSB7XG4gICAgICBjYXNlIFwid2hpdGVzcGFjZVwiOlxuICAgICAgY2FzZSBcImVycm9yXCI6XG4gICAgICAgIHJldHVybiBbXG4gICAgICAgICAgbmV3IE9wKEluc3RyLkFERF9UT0tFTiwgdG9rZW4pXG4gICAgICAgIF07XG4gICAgICBjYXNlIFwidGFnRW5kXCI6XG4gICAgICAgIHRoaXMucG9wRGlhbGVjdCgpO1xuICAgICAgICByZXR1cm4gW1xuICAgICAgICAgIG5ldyBPcChJbnN0ci5BRERfVE9LRU4sIHRva2VuKSxcbiAgICAgICAgICBuZXcgT3AoSW5zdHIuUE9QX05PREUpXG4gICAgICAgIF07XG4gICAgICBkZWZhdWx0OlxuICAgICAgICB0aHJvdyB1bmtub3duVG9rZW5Bc3NlcnRpb24odG9rZW4pO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBAcHJpdmF0ZVxuICAgKiBAcGFyYW0ge0ZvdW5kYXRpb24uU2Nhbm5lci5Ub2tlbn0gdG9rZW5cbiAgICogQHJldHVybiB7QXJyYXkuPE9wPn1cbiAgICovXG4gIGdlbmVyYXRlQ29kZUZvclJhd3RleHRUb2tlbiAodG9rZW4pIHtcbiAgICBzd2l0Y2ggKHRva2VuLnR5cGUpIHtcbiAgICAgIGNhc2UgXCJjbG9zZVRhZ1wiOlxuICAgICAgICB2YXIgY2xvc2VUYWdOYW1lID0gdG9rZW4udmFsdWUudG9Mb3dlckNhc2UoKS5yZXBsYWNlKC9cXFcvZywgXCJcIik7XG4gICAgICAgIGlmIChjbG9zZVRhZ05hbWUgPT09IHRoaXMuZXhwZWN0ZWRSYXd0ZXh0Q2xvc2luZ1RhZ05hbWUoKSkge1xuICAgICAgICAgIHRoaXMucG9wRGlhbGVjdCgpO1xuICAgICAgICAgIHJldHVybiBbXG4gICAgICAgICAgICBuZXcgT3AoSW5zdHIuUFVTSF9OT0RFLCBuZXcgQ2xvc2VUYWdOb2RlKCkpLFxuICAgICAgICAgICAgbmV3IE9wKEluc3RyLkFERF9UT0tFTiwgdG9rZW4pLFxuICAgICAgICAgICAgbmV3IE9wKEluc3RyLlBPUF9OT0RFKVxuICAgICAgICAgIF07XG4gICAgICAgIH1cbiAgICAgIGNhc2UgXCJ0ZXh0XCI6XG4gICAgICBjYXNlIFwibHRcIjpcbiAgICAgICAgcmV0dXJuIFtcbiAgICAgICAgICBuZXcgT3AoSW5zdHIuUFVTSF9OT0RFLCBuZXcgVGV4dE5vZGUoKSksXG4gICAgICAgICAgbmV3IE9wKEluc3RyLkFERF9UT0tFTiwgdG9rZW4pLFxuICAgICAgICAgIG5ldyBPcChJbnN0ci5QT1BfTk9ERSlcbiAgICAgICAgXTtcbiAgICAgIGRlZmF1bHQ6XG4gICAgICAgIHRocm93IHVua25vd25Ub2tlbkFzc2VydGlvbih0b2tlbik7XG4gICAgfVxuICB9XG59XG5cbi8qKlxuICogQHByaXZhdGVcbiAqIEBwYXJhbSB7Rm91bmRhdGlvbi5TY2FubmVyLlRva2VufSB0b2tlblxuICogQHJldHVybiB7RXJyb3J9XG4gKi9cbmZ1bmN0aW9uIHVua25vd25Ub2tlbkFzc2VydGlvbiAodG9rZW4pIHtcbiAgcmV0dXJuIG5ldyBFcnJvcihcImZhaWxlZCBhc3NlcnRpb246IHVua293biB0b2tlbiB0eXBlOiBcIiArIHRva2VuLnR5cGUpO1xufVxuIl19