tokenizer-event-handlers.js 40 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367
  1. import { assertPresent, assign } from '@glimmer/util';
  2. import { parse, parseWithoutProcessing } from '@handlebars/parser';
  3. import { EntityParser } from 'simple-html-tokenizer';
  4. import print from '../generation/print';
  5. import { voidMap } from '../generation/printer';
  6. import { Source } from '../source/source';
  7. import { SourceSpan } from '../source/span';
  8. import { generateSyntaxError } from '../syntax-error';
  9. import traverse from '../traversal/traverse';
  10. import Walker from '../traversal/walker';
  11. import { appendChild, parseElementBlockParams } from '../utils';
  12. import b from '../v1/parser-builders';
  13. import publicBuilder from '../v1/public-builders';
  14. import { HandlebarsNodeVisitors } from './handlebars-node-visitors';
  15. export class TokenizerEventHandlers extends HandlebarsNodeVisitors {
  16. constructor() {
  17. super(...arguments);
  18. this.tagOpenLine = 0;
  19. this.tagOpenColumn = 0;
  20. }
  21. reset() {
  22. this.currentNode = null;
  23. } // Comment
  24. beginComment() {
  25. this.currentNode = b.comment('', this.source.offsetFor(this.tagOpenLine, this.tagOpenColumn));
  26. }
  27. appendToCommentData(char) {
  28. this.currentComment.value += char;
  29. }
  30. finishComment() {
  31. appendChild(this.currentElement(), this.finish(this.currentComment));
  32. } // Data
  33. beginData() {
  34. this.currentNode = b.text({
  35. chars: '',
  36. loc: this.offset().collapsed()
  37. });
  38. }
  39. appendToData(char) {
  40. this.currentData.chars += char;
  41. }
  42. finishData() {
  43. this.currentData.loc = this.currentData.loc.withEnd(this.offset());
  44. appendChild(this.currentElement(), this.currentData);
  45. } // Tags - basic
  46. tagOpen() {
  47. this.tagOpenLine = this.tokenizer.line;
  48. this.tagOpenColumn = this.tokenizer.column;
  49. }
  50. beginStartTag() {
  51. this.currentNode = {
  52. type: 'StartTag',
  53. name: '',
  54. attributes: [],
  55. modifiers: [],
  56. comments: [],
  57. selfClosing: false,
  58. loc: this.source.offsetFor(this.tagOpenLine, this.tagOpenColumn)
  59. };
  60. }
  61. beginEndTag() {
  62. this.currentNode = {
  63. type: 'EndTag',
  64. name: '',
  65. attributes: [],
  66. modifiers: [],
  67. comments: [],
  68. selfClosing: false,
  69. loc: this.source.offsetFor(this.tagOpenLine, this.tagOpenColumn)
  70. };
  71. }
  72. finishTag() {
  73. let tag = this.finish(this.currentTag);
  74. if (tag.type === 'StartTag') {
  75. this.finishStartTag();
  76. if (tag.name === ':') {
  77. throw generateSyntaxError('Invalid named block named detected, you may have created a named block without a name, or you may have began your name with a number. Named blocks must have names that are at least one character long, and begin with a lower case letter', this.source.spanFor({
  78. start: this.currentTag.loc.toJSON(),
  79. end: this.offset().toJSON()
  80. }));
  81. }
  82. if (voidMap[tag.name] || tag.selfClosing) {
  83. this.finishEndTag(true);
  84. }
  85. } else if (tag.type === 'EndTag') {
  86. this.finishEndTag(false);
  87. }
  88. }
  89. finishStartTag() {
  90. let {
  91. name,
  92. attributes: attrs,
  93. modifiers,
  94. comments,
  95. selfClosing,
  96. loc
  97. } = this.finish(this.currentStartTag);
  98. let element = b.element({
  99. tag: name,
  100. selfClosing,
  101. attrs,
  102. modifiers,
  103. comments,
  104. children: [],
  105. blockParams: [],
  106. loc
  107. });
  108. this.elementStack.push(element);
  109. }
  110. finishEndTag(isVoid) {
  111. let tag = this.finish(this.currentTag);
  112. let element = this.elementStack.pop();
  113. let parent = this.currentElement();
  114. this.validateEndTag(tag, element, isVoid);
  115. element.loc = element.loc.withEnd(this.offset());
  116. parseElementBlockParams(element);
  117. appendChild(parent, element);
  118. }
  119. markTagAsSelfClosing() {
  120. this.currentTag.selfClosing = true;
  121. } // Tags - name
  122. appendToTagName(char) {
  123. this.currentTag.name += char;
  124. } // Tags - attributes
  125. beginAttribute() {
  126. let offset = this.offset();
  127. this.currentAttribute = {
  128. name: '',
  129. parts: [],
  130. currentPart: null,
  131. isQuoted: false,
  132. isDynamic: false,
  133. start: offset,
  134. valueSpan: offset.collapsed()
  135. };
  136. }
  137. appendToAttributeName(char) {
  138. this.currentAttr.name += char;
  139. }
  140. beginAttributeValue(isQuoted) {
  141. this.currentAttr.isQuoted = isQuoted;
  142. this.startTextPart();
  143. this.currentAttr.valueSpan = this.offset().collapsed();
  144. }
  145. appendToAttributeValue(char) {
  146. let parts = this.currentAttr.parts;
  147. let lastPart = parts[parts.length - 1];
  148. let current = this.currentAttr.currentPart;
  149. if (current) {
  150. current.chars += char; // update end location for each added char
  151. current.loc = current.loc.withEnd(this.offset());
  152. } else {
  153. // initially assume the text node is a single char
  154. let loc = this.offset(); // the tokenizer line/column have already been advanced, correct location info
  155. if (char === '\n') {
  156. loc = lastPart ? lastPart.loc.getEnd() : this.currentAttr.valueSpan.getStart();
  157. } else {
  158. loc = loc.move(-1);
  159. }
  160. this.currentAttr.currentPart = b.text({
  161. chars: char,
  162. loc: loc.collapsed()
  163. });
  164. }
  165. }
  166. finishAttributeValue() {
  167. this.finalizeTextPart();
  168. let tag = this.currentTag;
  169. let tokenizerPos = this.offset();
  170. if (tag.type === 'EndTag') {
  171. throw generateSyntaxError(`Invalid end tag: closing tag must not have attributes`, this.source.spanFor({
  172. start: tag.loc.toJSON(),
  173. end: tokenizerPos.toJSON()
  174. }));
  175. }
  176. let {
  177. name,
  178. parts,
  179. start,
  180. isQuoted,
  181. isDynamic,
  182. valueSpan
  183. } = this.currentAttr;
  184. let value = this.assembleAttributeValue(parts, isQuoted, isDynamic, start.until(tokenizerPos));
  185. value.loc = valueSpan.withEnd(tokenizerPos);
  186. let attribute = b.attr({
  187. name,
  188. value,
  189. loc: start.until(tokenizerPos)
  190. });
  191. this.currentStartTag.attributes.push(attribute);
  192. }
  193. reportSyntaxError(message) {
  194. throw generateSyntaxError(message, this.offset().collapsed());
  195. }
  196. assembleConcatenatedValue(parts) {
  197. for (let i = 0; i < parts.length; i++) {
  198. let part = parts[i];
  199. if (part.type !== 'MustacheStatement' && part.type !== 'TextNode') {
  200. throw generateSyntaxError('Unsupported node in quoted attribute value: ' + part['type'], part.loc);
  201. }
  202. }
  203. assertPresent(parts, `the concatenation parts of an element should not be empty`);
  204. let first = parts[0];
  205. let last = parts[parts.length - 1];
  206. return b.concat(parts, this.source.spanFor(first.loc).extend(this.source.spanFor(last.loc)));
  207. }
  208. validateEndTag(tag, element, selfClosing) {
  209. let error;
  210. if (voidMap[tag.name] && !selfClosing) {
  211. // EngTag is also called by StartTag for void and self-closing tags (i.e.
  212. // <input> or <br />, so we need to check for that here. Otherwise, we would
  213. // throw an error for those cases.
  214. error = `<${tag.name}> elements do not need end tags. You should remove it`;
  215. } else if (element.tag === undefined) {
  216. error = `Closing tag </${tag.name}> without an open tag`;
  217. } else if (element.tag !== tag.name) {
  218. error = `Closing tag </${tag.name}> did not match last open tag <${element.tag}> (on line ${element.loc.startPosition.line})`;
  219. }
  220. if (error) {
  221. throw generateSyntaxError(error, tag.loc);
  222. }
  223. }
  224. assembleAttributeValue(parts, isQuoted, isDynamic, span) {
  225. if (isDynamic) {
  226. if (isQuoted) {
  227. return this.assembleConcatenatedValue(parts);
  228. } else {
  229. if (parts.length === 1 || parts.length === 2 && parts[1].type === 'TextNode' && parts[1].chars === '/') {
  230. return parts[0];
  231. } else {
  232. throw generateSyntaxError(`An unquoted attribute value must be a string or a mustache, ` + `preceded by whitespace or a '=' character, and ` + `followed by whitespace, a '>' character, or '/>'`, span);
  233. }
  234. }
  235. } else {
  236. return parts.length > 0 ? parts[0] : b.text({
  237. chars: '',
  238. loc: span
  239. });
  240. }
  241. }
  242. }
  243. const syntax = {
  244. parse: preprocess,
  245. builders: publicBuilder,
  246. print,
  247. traverse,
  248. Walker
  249. };
  250. class CodemodEntityParser extends EntityParser {
  251. // match upstream types, but never match an entity
  252. constructor() {
  253. super({});
  254. }
  255. parse() {
  256. return undefined;
  257. }
  258. }
  259. export function preprocess(input, options = {}) {
  260. var _a, _b, _c;
  261. let mode = options.mode || 'precompile';
  262. let source;
  263. let ast;
  264. if (typeof input === 'string') {
  265. source = new Source(input, (_a = options.meta) === null || _a === void 0 ? void 0 : _a.moduleName);
  266. if (mode === 'codemod') {
  267. ast = parseWithoutProcessing(input, options.parseOptions);
  268. } else {
  269. ast = parse(input, options.parseOptions);
  270. }
  271. } else if (input instanceof Source) {
  272. source = input;
  273. if (mode === 'codemod') {
  274. ast = parseWithoutProcessing(input.source, options.parseOptions);
  275. } else {
  276. ast = parse(input.source, options.parseOptions);
  277. }
  278. } else {
  279. source = new Source('', (_b = options.meta) === null || _b === void 0 ? void 0 : _b.moduleName);
  280. ast = input;
  281. }
  282. let entityParser = undefined;
  283. if (mode === 'codemod') {
  284. entityParser = new CodemodEntityParser();
  285. }
  286. let offsets = SourceSpan.forCharPositions(source, 0, source.source.length);
  287. ast.loc = {
  288. source: '(program)',
  289. start: offsets.startPosition,
  290. end: offsets.endPosition
  291. };
  292. let program = new TokenizerEventHandlers(source, entityParser, mode).acceptTemplate(ast);
  293. if (options.strictMode) {
  294. program.blockParams = (_c = options.locals) !== null && _c !== void 0 ? _c : [];
  295. }
  296. if (options && options.plugins && options.plugins.ast) {
  297. for (let i = 0, l = options.plugins.ast.length; i < l; i++) {
  298. let transform = options.plugins.ast[i];
  299. let env = assign({}, options, {
  300. syntax
  301. }, {
  302. plugins: undefined
  303. });
  304. let pluginResult = transform(env);
  305. traverse(program, pluginResult.visitor);
  306. }
  307. }
  308. return program;
  309. }
  310. //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3BhY2thZ2VzL0BnbGltbWVyL3N5bnRheC9saWIvcGFyc2VyL3Rva2VuaXplci1ldmVudC1oYW5kbGVycy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFDQSxTQUFTLGFBQVQsRUFBd0IsTUFBeEIsUUFBc0MsZUFBdEM7QUFDQSxTQUFTLEtBQVQsRUFBZ0Isc0JBQWhCLFFBQThDLG9CQUE5QztBQUNBLFNBQVMsWUFBVCxRQUE2Qix1QkFBN0I7QUFFQSxPQUFPLEtBQVAsTUFBa0IscUJBQWxCO0FBQ0EsU0FBUyxPQUFULFFBQXdCLHVCQUF4QjtBQUVBLFNBQVMsTUFBVCxRQUF1QixrQkFBdkI7QUFDQSxTQUF1QixVQUF2QixRQUF5QyxnQkFBekM7QUFDQSxTQUFTLG1CQUFULFFBQW9DLGlCQUFwQztBQUNBLE9BQU8sUUFBUCxNQUFxQix1QkFBckI7QUFFQSxPQUFPLE1BQVAsTUFBbUIscUJBQW5CO0FBQ0EsU0FBUyxXQUFULEVBQXNCLHVCQUF0QixRQUFxRCxVQUFyRDtBQUdBLE9BQU8sQ0FBUCxNQUFjLHVCQUFkO0FBQ0EsT0FBTyxhQUFQLE1BQTBCLHVCQUExQjtBQUNBLFNBQVMsc0JBQVQsUUFBdUMsNEJBQXZDO0FBRUEsT0FBTSxNQUFPLHNCQUFQLFNBQXNDLHNCQUF0QyxDQUE0RDtBQUFsRSxFQUFBLFdBQUEsR0FBQTs7QUFDVSxTQUFBLFdBQUEsR0FBYyxDQUFkO0FBQ0EsU0FBQSxhQUFBLEdBQWdCLENBQWhCO0FBZ1NUOztBQTlSQyxFQUFBLEtBQUssR0FBQTtBQUNILFNBQUssV0FBTCxHQUFtQixJQUFuQjtBQUNELEdBTitELENBUWhFOzs7QUFFQSxFQUFBLFlBQVksR0FBQTtBQUNWLFNBQUssV0FBTCxHQUFtQixDQUFDLENBQUMsT0FBRixDQUFVLEVBQVYsRUFBYyxLQUFLLE1BQUwsQ0FBWSxTQUFaLENBQXNCLEtBQUssV0FBM0IsRUFBd0MsS0FBSyxhQUE3QyxDQUFkLENBQW5CO0FBQ0Q7O0FBRUQsRUFBQSxt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LEVBQUssT0FBTCxFQUFjO0FBQUUsUUFBQTtBQUFGLE9BQWQsRUFBMEI7QUFBRSxRQUFBLE9BQU8sRUFBRTtBQUFYLE9BQTFCLENBQXRDO0FBRUEsVUFBSSxZQUFZLEdBQUcsU0FBUyxDQUFDLEdBQUQsQ0FBNUI7QUFFQSxNQUFBLFFBQVEsQ0FBQyxPQUFELEVBQVUsWUFBWSxDQUFDLE9BQXZCLENBQVI7QUFDRDtBQUNGOztBQUVELFNBQU8sT0FBUDtBQUNEIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgT3B0aW9uIH0gZnJvbSAnQGdsaW1tZXIvaW50ZXJmYWNlcyc7XG5pbXBvcnQgeyBhc3NlcnRQcmVzZW50LCBhc3NpZ24gfSBmcm9tICdAZ2xpbW1lci91dGlsJztcbmltcG9ydCB7IHBhcnNlLCBwYXJzZVdpdGhvdXRQcm9jZXNzaW5nIH0gZnJvbSAnQGhhbmRsZWJhcnMvcGFyc2VyJztcbmltcG9ydCB7IEVudGl0eVBhcnNlciB9IGZyb20gJ3NpbXBsZS1odG1sLXRva2VuaXplcic7XG5cbmltcG9ydCBwcmludCBmcm9tICcuLi9nZW5lcmF0aW9uL3ByaW50JztcbmltcG9ydCB7IHZvaWRNYXAgfSBmcm9tICcuLi9nZW5lcmF0aW9uL3ByaW50ZXInO1xuaW1wb3J0IHsgVGFnIH0gZnJvbSAnLi4vcGFyc2VyJztcbmltcG9ydCB7IFNvdXJjZSB9IGZyb20gJy4uL3NvdXJjZS9zb3VyY2UnO1xuaW1wb3J0IHsgU291cmNlT2Zmc2V0LCBTb3VyY2VTcGFuIH0gZnJvbSAnLi4vc291cmNlL3NwYW4nO1xuaW1wb3J0IHsgZ2VuZXJhdGVTeW50YXhFcnJvciB9IGZyb20gJy4uL3N5bnRheC1lcnJvcic7XG5pbXBvcnQgdHJhdmVyc2UgZnJvbSAnLi4vdHJhdmVyc2FsL3RyYXZlcnNlJztcbmltcG9ydCB7IE5vZGVWaXNpdG9yIH0gZnJvbSAnLi4vdHJhdmVyc2FsL3Zpc2l0b3InO1xuaW1wb3J0IFdhbGtlciBmcm9tICcuLi90cmF2ZXJzYWwvd2Fsa2VyJztcbmltcG9ydCB7IGFwcGVuZENoaWxkLCBwYXJzZUVsZW1lbnRCbG9ja1BhcmFtcyB9IGZyb20gJy4uL3V0aWxzJztcbmltcG9ydCAqIGFzIEFTVHYxIGZyb20gJy4uL3YxL2FwaSc7XG5pbXBvcnQgKiBhcyBIQlMgZnJvbSAnLi4vdjEvaGFuZGxlYmFycy1hc3QnO1xuaW1wb3J0IGIgZnJvbSAnLi4vdjEvcGFyc2VyLWJ1aWxkZXJzJztcbmltcG9ydCBwdWJsaWNCdWlsZGVyIGZyb20gJy4uL3YxL3B1YmxpYy1idWlsZGVycyc7XG5pbXBvcnQgeyBIYW5kbGViYXJzTm9kZVZpc2l0b3JzIH0gZnJvbSAnLi9oYW5kbGViYXJzLW5vZGUtdmlzaXRvcnMnO1xuXG5leHBvcnQgY2xhc3MgVG9rZW5pemVyRXZlbnRIYW5kbGVycyBleHRlbmRzIEhhbmRsZWJhcnNOb2RlVmlzaXRvcnMge1xuICBwcml2YXRlIHRhZ09wZW5MaW5lID0gMDtcbiAgcHJpdmF0ZSB0YWdPcGVuQ29sdW1uID0gMDtcblxuICByZXNldCgpOiB2b2lkIHtcbiAgICB0aGlzLmN1cnJlbnROb2RlID0gbnVsbDtcbiAgfVxuXG4gIC8vIENvbW1lbnRcblxuICBiZWdpbkNvbW1lbnQoKTogdm9pZCB7XG4gICAgdGhpcy5jdXJyZW50Tm9kZSA9IGIuY29tbWVudCgnJywgdGhpcy5zb3VyY2Uub2Zmc2V0Rm9yKHRoaXMudGFnT3BlbkxpbmUsIHRoaXMudGFnT3BlbkNvbHVtbikpO1xuICB9XG5cbiAgYXBwZW5kVG9Db21tZW50RGF0YShjaGFyOiBzdHJpbmcpOiB2b2lkIHtcbiAgICB0aGlzLmN1cnJlbnRDb21tZW50LnZhbHVlICs9IGNoYXI7XG4gIH1cblxuICBmaW5pc2hDb21tZW50KCk6IHZvaWQge1xuICAgIGFwcGVuZENoaWxkKHRoaXMuY3VycmVudEVsZW1lbnQoKSwgdGhpcy5maW5pc2godGhpcy5jdXJyZW50Q29tbWVudCkpO1xuICB9XG5cbiAgLy8gRGF0YVxuXG4gIGJlZ2luRGF0YSgpOiB2b2lkIHtcbiAgICB0aGlzLmN1cnJlbnROb2RlID0gYi50ZXh0KHtcbiAgICAgIGNoYXJzOiAnJyxcbiAgICAgIGxvYzogdGhpcy5vZmZzZXQoKS5jb2xsYXBzZWQoKSxcbiAgICB9KTtcbiAgfVxuXG4gIGFwcGVuZFRvRGF0YShjaGFyOiBzdHJpbmcpOiB2b2lkIHtcbiAgICB0aGlzLmN1cnJlbnREYXRhLmNoYXJzICs9IGNoYXI7XG4gIH1cblxuICBmaW5pc2hEYXRhKCk6IHZvaWQge1xuICAgIHRoaXMuY3VycmVudERhdGEubG9jID0gdGhpcy5jdXJyZW50RGF0YS5sb2Mud2l0aEVuZCh0aGlzLm9mZnNldCgpKTtcblxuICAgIGFwcGVuZENoaWxkKHRoaXMuY3VycmVudEVsZW1lbnQoKSwgdGhpcy5jdXJyZW50RGF0YSk7XG4gIH1cblxuICAvLyBUYWdzIC0gYmFzaWNcblxuICB0YWdPcGVuKCk6IHZvaWQge1xuICAgIHRoaXMudGFnT3BlbkxpbmUgPSB0aGlzLnRva2VuaXplci5saW5lO1xuICAgIHRoaXMudGFnT3BlbkNvbHVtbiA9IHRoaXMudG9rZW5pemVyLmNvbHVtbjtcbiAgfVxuXG4gIGJlZ2luU3RhcnRUYWcoKTogdm9pZCB7XG4gICAgdGhpcy5jdXJyZW50Tm9kZSA9IHtcbiAgICAgIHR5cGU6ICdTdGFydFRhZycsXG4gICAgICBuYW1lOiAnJyxcbiAgICAgIGF0dHJpYnV0ZXM6IFtdLFxuICAgICAgbW9kaWZpZXJzOiBbXSxcbiAgICAgIGNvbW1lbnRzOiBbXSxcbiAgICAgIHNlbGZDbG9zaW5nOiBmYWxzZSxcbiAgICAgIGxvYzogdGhpcy5zb3VyY2Uub2Zmc2V0Rm9yKHRoaXMudGFnT3BlbkxpbmUsIHRoaXMudGFnT3BlbkNvbHVtbiksXG4gICAgfTtcbiAgfVxuXG4gIGJlZ2luRW5kVGFnKCk6IHZvaWQge1xuICAgIHRoaXMuY3VycmVudE5vZGUgPSB7XG4gICAgICB0eXBlOiAnRW5kVGFnJyxcbiAgICAgIG5hbWU6ICcnLFxuICAgICAgYXR0cmlidXRlczogW10sXG4gICAgICBtb2RpZmllcnM6IFtdLFxuICAgICAgY29tbWVudHM6IFtdLFxuICAgICAgc2VsZkNsb3Npbmc6IGZhbHNlLFxuICAgICAgbG9jOiB0aGlzLnNvdXJjZS5vZmZzZXRGb3IodGhpcy50YWdPcGVuTGluZSwgdGhpcy50YWdPcGVuQ29sdW1uKSxcbiAgICB9O1xuICB9XG5cbiAgZmluaXNoVGFnKCk6IHZvaWQge1xuICAgIGxldCB0YWcgPSB0aGlzLmZpbmlzaCh0aGlzLmN1cnJlbnRUYWcpO1xuXG4gICAgaWYgKHRhZy50eXBlID09PSAnU3RhcnRUYWcnKSB7XG4gICAgICB0aGlzLmZpbmlzaFN0YXJ0VGFnKCk7XG5cbiAgICAgIGlmICh0YWcubmFtZSA9PT0gJzonKSB7XG4gICAgICAgIHRocm93IGdlbmVyYXRlU3ludGF4RXJyb3IoXG4gICAgICAgICAgJ0ludmFsaWQgbmFtZWQgYmxvY2sgbmFtZWQgZGV0ZWN0ZWQsIHlvdSBtYXkgaGF2ZSBjcmVhdGVkIGEgbmFtZWQgYmxvY2sgd2l0aG91dCBhIG5hbWUsIG9yIHlvdSBtYXkgaGF2ZSBiZWdhbiB5b3VyIG5hbWUgd2l0aCBhIG51bWJlci4gTmFtZWQgYmxvY2tzIG11c3QgaGF2ZSBuYW1lcyB0aGF0IGFyZSBhdCBsZWFzdCBvbmUgY2hhcmFjdGVyIGxvbmcsIGFuZCBiZWdpbiB3aXRoIGEgbG93ZXIgY2FzZSBsZXR0ZXInLFxuICAgICAgICAgIHRoaXMuc291cmNlLnNwYW5Gb3Ioe1xuICAgICAgICAgICAgc3RhcnQ6IHRoaXMuY3VycmVudFRhZy5sb2MudG9KU09OKCksXG4gICAgICAgICAgICBlbmQ6IHRoaXMub2Zmc2V0KCkudG9KU09OKCksXG4gICAgICAgICAgfSlcbiAgICAgICAgKTtcbiAgICAgIH1cblxuICAgICAgaWYgKHZvaWRNYXBbdGFnLm5hbWVdIHx8IHRhZy5zZWxmQ2xvc2luZykge1xuICAgICAgICB0aGlzLmZpbmlzaEVuZFRhZyh0cnVlKTtcbiAgICAgIH1cbiAgICB9IGVsc2UgaWYgKHRhZy50eXBlID09PSAnRW5kVGFnJykge1xuICAgICAgdGhpcy5maW5pc2hFbmRUYWcoZmFsc2UpO1xuICAgIH1cbiAgfVxuXG4gIGZpbmlzaFN0YXJ0VGFnKCk6IHZvaWQge1xuICAgIGxldCB7IG5hbWUsIGF0dHJpYnV0ZXM6IGF0dHJzLCBtb2RpZmllcnMsIGNvbW1lbnRzLCBzZWxmQ2xvc2luZywgbG9jIH0gPSB0aGlzLmZpbmlzaChcbiAgICAgIHRoaXMuY3VycmVudFN0YXJ0VGFnXG4gICAgKTtcblxuICAgIGxldCBlbGVtZW50ID0gYi5lbGVtZW50KHtcbiAgICAgIHRhZzogbmFtZSxcbiAgICAgIHNlbGZDbG9zaW5nLFxuICAgICAgYXR0cnMsXG4gICAgICBtb2RpZmllcnMsXG4gICAgICBjb21tZW50cyxcbiAgICAgIGNoaWxkcmVuOiBbXSxcbiAgICAgIGJsb2NrUGFyYW1zOiBbXSxcbiAgICAgIGxvYyxcbiAgICB9KTtcbiAgICB0aGlzLmVsZW1lbnRTdGFjay5wdXNoKGVsZW1lbnQpO1xuICB9XG5cbiAgZmluaXNoRW5kVGFnKGlzVm9pZDogYm9vbGVhbik6IHZvaWQge1xuICAgIGxldCB0YWcgPSB0aGlzLmZpbmlzaCh0aGlzLmN1cnJlbnRUYWcpO1xuXG4gICAgbGV0IGVsZW1lbnQgPSB0aGlzLmVsZW1lbnRTdGFjay5wb3AoKSBhcyBBU1R2MS5FbGVtZW50Tm9kZTtcbiAgICBsZXQgcGFyZW50ID0gdGhpcy5jdXJyZW50RWxlbWVudCgpO1xuXG4gICAgdGhpcy52YWxpZGF0ZUVuZFRhZyh0YWcsIGVsZW1lbnQsIGlzVm9pZCk7XG5cbiAgICBlbGVtZW50LmxvYyA9IGVsZW1lbnQubG9jLndpdGhFbmQodGhpcy5vZmZzZXQoKSk7XG4gICAgcGFyc2VFbGVtZW50QmxvY2tQYXJhbXMoZWxlbWVudCk7XG4gICAgYXBwZW5kQ2hpbGQocGFyZW50LCBlbGVtZW50KTtcbiAgfVxuXG4gIG1hcmtUYWdBc1NlbGZDbG9zaW5nKCk6IHZvaWQge1xuICAgIHRoaXMuY3VycmVudFRhZy5zZWxmQ2xvc2luZyA9IHRydWU7XG4gIH1cblxuICAvLyBUYWdzIC0gbmFtZVxuXG4gIGFwcGVuZFRvVGFnTmFtZShjaGFyOiBzdHJpbmcpOiB2b2lkIHtcbiAgICB0aGlzLmN1cnJlbnRUYWcubmFtZSArPSBjaGFyO1xuICB9XG5cbiAgLy8gVGFncyAtIGF0dHJpYnV0ZXNcblxuICBiZWdpbkF0dHJpYnV0ZSgpOiB2b2lkIHtcbiAgICBsZXQgb2Zmc2V0ID0gdGhpcy5vZmZzZXQoKTtcblxuICAgIHRoaXMuY3VycmVudEF0dHJpYnV0ZSA9IHtcbiAgICAgIG5hbWU6ICcnLFxuICAgICAgcGFydHM6IFtdLFxuICAgICAgY3VycmVudFBhcnQ6IG51bGwsXG4gICAgICBpc1F1b3RlZDogZmFsc2UsXG4gICAgICBpc0R5bmFtaWM6IGZhbHNlLFxuICAgICAgc3RhcnQ6IG9mZnNldCxcbiAgICAgIHZhbHVlU3Bhbjogb2Zmc2V0LmNvbGxhcHNlZCgpLFxuICAgIH07XG4gIH1cblxuICBhcHBlbmRUb0F0dHJpYnV0ZU5hbWUoY2hhcjogc3RyaW5nKTogdm9pZCB7XG4gICAgdGhpcy5jdXJyZW50QXR0ci5uYW1lICs9IGNoYXI7XG4gIH1cblxuICBiZWdpbkF0dHJpYnV0ZVZhbHVlKGlzUXVvdGVkOiBib29sZWFuKTogdm9pZCB7XG4gICAgdGhpcy5jdXJyZW50QXR0ci5pc1F1b3RlZCA9IGlzUXVvdGVkO1xuICAgIHRoaXMuc3RhcnRUZXh0UGFydCgpO1xuICAgIHRoaXMuY3VycmVudEF0dHIudmFsdWVTcGFuID0gdGhpcy5vZmZzZXQoKS5jb2xsYXBzZWQoKTtcbiAgfVxuXG4gIGFwcGVuZFRvQXR0cmlidXRlVmFsdWUoY2hhcjogc3RyaW5nKTogdm9pZCB7XG4gICAgbGV0IHBhcnRzID0gdGhpcy5jdXJyZW50QXR0ci5wYXJ0cztcbiAgICBsZXQgbGFzdFBhcnQgPSBwYXJ0c1twYXJ0cy5sZW5ndGggLSAxXTtcblxuICAgIGxldCBjdXJyZW50ID0gdGhpcy5jdXJyZW50QXR0ci5jdXJyZW50UGFydDtcblxuICAgIGlmIChjdXJyZW50KSB7XG4gICAgICBjdXJyZW50LmNoYXJzICs9IGNoYXI7XG5cbiAgICAgIC8vIHVwZGF0ZSBlbmQgbG9jYXRpb24gZm9yIGVhY2ggYWRkZWQgY2hhclxuICAgICAgY3VycmVudC5sb2MgPSBjdXJyZW50LmxvYy53aXRoRW5kKHRoaXMub2Zmc2V0KCkpO1xuICAgIH0gZWxzZSB7XG4gICAgICAvLyBpbml0aWFsbHkgYXNzdW1lIHRoZSB0ZXh0IG5vZGUgaXMgYSBzaW5nbGUgY2hhclxuICAgICAgbGV0IGxvYzogU291cmNlT2Zmc2V0ID0gdGhpcy5vZmZzZXQoKTtcblxuICAgICAgLy8gdGhlIHRva2VuaXplciBsaW5lL2NvbHVtbiBoYXZlIGFscmVhZHkgYmVlbiBhZHZhbmNlZCwgY29ycmVjdCBsb2NhdGlvbiBpbmZvXG4gICAgICBpZiAoY2hhciA9PT0gJ1xcbicpIHtcbiAgICAgICAgbG9jID0gbGFzdFBhcnQgPyBsYXN0UGFydC5sb2MuZ2V0RW5kKCkgOiB0aGlzLmN1cnJlbnRBdHRyLnZhbHVlU3Bhbi5nZXRTdGFydCgpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgbG9jID0gbG9jLm1vdmUoLTEpO1xuICAgICAgfVxuXG4gICAgICB0aGlzLmN1cnJlbnRBdHRyLmN1cnJlbnRQYXJ0ID0gYi50ZXh0KHsgY2hhcnM6IGNoYXIsIGxvYzogbG9jLmNvbGxhcHNlZCgpIH0pO1xuICAgIH1cbiAgfVxuXG4gIGZpbmlzaEF0dHJpYnV0ZVZhbHVlKCk6IHZvaWQge1xuICAgIHRoaXMuZmluYWxpemVUZXh0UGFydCgpO1xuXG4gICAgbGV0IHRhZyA9IHRoaXMuY3VycmVudFRhZztcbiAgICBsZXQgdG9rZW5pemVyUG9zID0gdGhpcy5vZmZzZXQoKTtcblxuICAgIGlmICh0YWcudHlwZSA9PT0gJ0VuZFRhZycpIHtcbiAgICAgIHRocm93IGdlbmVyYXRlU3ludGF4RXJyb3IoXG4gICAgICAgIGBJbnZhbGlkIGVuZCB0YWc6IGNsb3NpbmcgdGFnIG11c3Qgbm90IGhhdmUgYXR0cmlidXRlc2AsXG4gICAgICAgIHRoaXMuc291cmNlLnNwYW5Gb3IoeyBzdGFydDogdGFnLmxvYy50b0pTT04oKSwgZW5kOiB0b2tlbml6ZXJQb3MudG9KU09OKCkgfSlcbiAgICAgICk7XG4gICAgfVxuXG4gICAgbGV0IHsgbmFtZSwgcGFydHMsIHN0YXJ0LCBpc1F1b3RlZCwgaXNEeW5hbWljLCB2YWx1ZVNwYW4gfSA9IHRoaXMuY3VycmVudEF0dHI7XG4gICAgbGV0IHZhbHVlID0gdGhpcy5hc3NlbWJsZUF0dHJpYnV0ZVZhbHVlKHBhcnRzLCBpc1F1b3RlZCwgaXNEeW5hbWljLCBzdGFydC51bnRpbCh0b2tlbml6ZXJQb3MpKTtcbiAgICB2YWx1ZS5sb2MgPSB2YWx1ZVNwYW4ud2l0aEVuZCh0b2tlbml6ZXJQb3MpO1xuXG4gICAgbGV0IGF0dHJpYnV0ZSA9IGIuYXR0cih7IG5hbWUsIHZhbHVlLCBsb2M6IHN0YXJ0LnVudGlsKHRva2VuaXplclBvcykgfSk7XG5cbiAgICB0aGlzLmN1cnJlbnRTdGFydFRhZy5hdHRyaWJ1dGVzLnB1c2goYXR0cmlidXRlKTtcbiAgfVxuXG4gIHJlcG9ydFN5bnRheEVycm9yKG1lc3NhZ2U6IHN0cmluZyk6IHZvaWQge1xuICAgIHRocm93IGdlbmVyYXRlU3ludGF4RXJyb3IobWVzc2FnZSwgdGhpcy5vZmZzZXQoKS5jb2xsYXBzZWQoKSk7XG4gIH1cblxuICBhc3NlbWJsZUNvbmNhdGVuYXRlZFZhbHVlKFxuICAgIHBhcnRzOiAoQVNUdjEuTXVzdGFjaGVTdGF0ZW1lbnQgfCBBU1R2MS5UZXh0Tm9kZSlbXVxuICApOiBBU1R2MS5Db25jYXRTdGF0ZW1lbnQge1xuICAgIGZvciAobGV0IGkgPSAwOyBpIDwgcGFydHMubGVuZ3RoOyBpKyspIHtcbiAgICAgIGxldCBwYXJ0OiBBU1R2MS5CYXNlTm9kZSA9IHBhcnRzW2ldO1xuXG4gICAgICBpZiAocGFydC50eXBlICE9PSAnTXVzdGFjaGVTdGF0ZW1lbnQnICYmIHBhcnQudHlwZSAhPT0gJ1RleHROb2RlJykge1xuICAgICAgICB0aHJvdyBnZW5lcmF0ZVN5bnRheEVycm9yKFxuICAgICAgICAgICdVbnN1cHBvcnRlZCBub2RlIGluIHF1b3RlZCBhdHRyaWJ1dGUgdmFsdWU6ICcgKyBwYXJ0Wyd0eXBlJ10sXG4gICAgICAgICAgcGFydC5sb2NcbiAgICAgICAgKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICBhc3NlcnRQcmVzZW50KHBhcnRzLCBgdGhlIGNvbmNhdGVuYXRpb24gcGFydHMgb2YgYW4gZWxlbWVudCBzaG91bGQgbm90IGJlIGVtcHR5YCk7XG5cbiAgICBsZXQgZmlyc3QgPSBwYXJ0c1swXTtcbiAgICBsZXQgbGFzdCA9IHBhcnRzW3BhcnRzLmxlbmd0aCAtIDFdO1xuXG4gICAgcmV0dXJuIGIuY29uY2F0KHBhcnRzLCB0aGlzLnNvdXJjZS5zcGFuRm9yKGZpcnN0LmxvYykuZXh0ZW5kKHRoaXMuc291cmNlLnNwYW5Gb3IobGFzdC5sb2MpKSk7XG4gIH1cblxuICB2YWxpZGF0ZUVuZFRhZyhcbiAgICB0YWc6IFRhZzwnU3RhcnRUYWcnIHwgJ0VuZFRhZyc+LFxuICAgIGVsZW1lbnQ6IEFTVHYxLkVsZW1lbnROb2RlLFxuICAgIHNlbGZDbG9zaW5nOiBib29sZWFuXG4gICk6IHZvaWQge1xuICAgIGxldCBlcnJvcjtcblxuICAgIGlmICh2b2lkTWFwW3RhZy5uYW1lXSAmJiAhc2VsZkNsb3NpbmcpIHtcbiAgICAgIC8vIEVuZ1RhZyBpcyBhbHNvIGNhbGxlZCBieSBTdGFydFRhZyBmb3Igdm9pZCBhbmQgc2VsZi1jbG9zaW5nIHRhZ3MgKGkuZS5cbiAgICAgIC8vIDxpbnB1dD4gb3IgPGJyIC8+LCBzbyB3ZSBuZWVkIHRvIGNoZWNrIGZvciB0aGF0IGhlcmUuIE90aGVyd2lzZSwgd2Ugd291bGRcbiAgICAgIC8vIHRocm93IGFuIGVycm9yIGZvciB0aG9zZSBjYXNlcy5cbiAgICAgIGVycm9yID0gYDwke3RhZy5uYW1lfT4gZWxlbWVudHMgZG8gbm90IG5lZWQgZW5kIHRhZ3MuIFlvdSBzaG91bGQgcmVtb3ZlIGl0YDtcbiAgICB9IGVsc2UgaWYgKGVsZW1lbnQudGFnID09PSB1bmRlZmluZWQpIHtcbiAgICAgIGVycm9yID0gYENsb3NpbmcgdGFnIDwvJHt0YWcubmFtZX0+IHdpdGhvdXQgYW4gb3BlbiB0YWdgO1xuICAgIH0gZWxzZSBpZiAoZWxlbWVudC50YWcgIT09IHRhZy5uYW1lKSB7XG4gICAgICBlcnJvciA9IGBDbG9zaW5nIHRhZyA8LyR7dGFnLm5hbWV9PiBkaWQgbm90IG1hdGNoIGxhc3Qgb3BlbiB0YWcgPCR7ZWxlbWVudC50YWd9PiAob24gbGluZSAke2VsZW1lbnQubG9jLnN0YXJ0UG9zaXRpb24ubGluZX0pYDtcbiAgICB9XG5cbiAgICBpZiAoZXJyb3IpIHtcbiAgICAgIHRocm93IGdlbmVyYXRlU3ludGF4RXJyb3IoZXJyb3IsIHRhZy5sb2MpO1xuICAgIH1cbiAgfVxuXG4gIGFzc2VtYmxlQXR0cmlidXRlVmFsdWUoXG4gICAgcGFydHM6IChBU1R2MS5NdXN0YWNoZVN0YXRlbWVudCB8IEFTVHYxLlRleHROb2RlKVtdLFxuICAgIGlzUXVvdGVkOiBib29sZWFuLFxuICAgIGlzRHluYW1pYzogYm9vbGVhbixcbiAgICBzcGFuOiBTb3VyY2VTcGFuXG4gICk6IEFTVHYxLkNvbmNhdFN0YXRlbWVudCB8IEFTVHYxLk11c3RhY2hlU3RhdGVtZW50IHwgQVNUdjEuVGV4dE5vZGUge1xuICAgIGlmIChpc0R5bmFtaWMpIHtcbiAgICAgIGlmIChpc1F1b3RlZCkge1xuICAgICAgICByZXR1cm4gdGhpcy5hc3NlbWJsZUNvbmNhdGVuYXRlZFZhbHVlKHBhcnRzKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGlmIChcbiAgICAgICAgICBwYXJ0cy5sZW5ndGggPT09IDEgfHxcbiAgICAgICAgICAocGFydHMubGVuZ3RoID09PSAyICYmXG4gICAgICAgICAgICBwYXJ0c1sxXS50eXBlID09PSAnVGV4dE5vZGUnICYmXG4gICAgICAgICAgICAocGFydHNbMV0gYXMgQVNUdjEuVGV4dE5vZGUpLmNoYXJzID09PSAnLycpXG4gICAgICAgICkge1xuICAgICAgICAgIHJldHVybiBwYXJ0c1swXTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICB0aHJvdyBnZW5lcmF0ZVN5bnRheEVycm9yKFxuICAgICAgICAgICAgYEFuIHVucXVvdGVkIGF0dHJpYnV0ZSB2YWx1ZSBtdXN0IGJlIGEgc3RyaW5nIG9yIGEgbXVzdGFjaGUsIGAgK1xuICAgICAgICAgICAgICBgcHJlY2VkZWQgYnkgd2hpdGVzcGFjZSBvciBhICc9JyBjaGFyYWN0ZXIsIGFuZCBgICtcbiAgICAgICAgICAgICAgYGZvbGxvd2VkIGJ5IHdoaXRlc3BhY2UsIGEgJz4nIGNoYXJhY3Rlciwgb3IgJy8+J2AsXG4gICAgICAgICAgICBzcGFuXG4gICAgICAgICAgKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH0gZWxzZSB7XG4gICAgICByZXR1cm4gcGFydHMubGVuZ3RoID4gMCA/IHBhcnRzWzBdIDogYi50ZXh0KHsgY2hhcnM6ICcnLCBsb2M6IHNwYW4gfSk7XG4gICAgfVxuICB9XG59XG5cbi8qKlxuICBBU1RQbHVnaW5zIGNhbiBtYWtlIGNoYW5nZXMgdG8gdGhlIEdsaW1tZXIgdGVtcGxhdGUgQVNUIGJlZm9yZVxuICBjb21waWxhdGlvbiBiZWdpbnMuXG4qL1xuZXhwb3J0IGludGVyZmFjZSBBU1RQbHVnaW5CdWlsZGVyPFRFbnYgZXh0ZW5kcyBBU1RQbHVnaW5FbnZpcm9ubWVudCA9IEFTVFBsdWdpbkVudmlyb25tZW50PiB7XG4gIChlbnY6IFRFbnYpOiBBU1RQbHVnaW47XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgQVNUUGx1Z2luIHtcbiAgbmFtZTogc3RyaW5nO1xuICB2aXNpdG9yOiBOb2RlVmlzaXRvcjtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBBU1RQbHVnaW5FbnZpcm9ubWVudCB7XG4gIG1ldGE/OiBvYmplY3Q7XG4gIHN5bnRheDogU3ludGF4O1xufVxuXG5pbnRlcmZhY2UgSGFuZGxlYmFyc1BhcnNlT3B0aW9ucyB7XG4gIHNyY05hbWU/OiBzdHJpbmc7XG4gIGlnbm9yZVN0YW5kYWxvbmU/OiBib29sZWFuO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIFRlbXBsYXRlSWRGbiB7XG4gIChzcmM6IHN0cmluZyk6IE9wdGlvbjxzdHJpbmc+O1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIFByZWNvbXBpbGVPcHRpb25zIGV4dGVuZHMgUHJlcHJvY2Vzc09wdGlvbnMge1xuICBpZD86IFRlbXBsYXRlSWRGbjtcbiAgY3VzdG9taXplQ29tcG9uZW50TmFtZT8oaW5wdXQ6IHN0cmluZyk6IHN0cmluZztcbn1cblxuZXhwb3J0IGludGVyZmFjZSBQcmVwcm9jZXNzT3B0aW9ucyB7XG4gIHN0cmljdE1vZGU/OiBib29sZWFuO1xuICBsb2NhbHM/OiBzdHJpbmdbXTtcbiAgbWV0YT86IHtcbiAgICBtb2R1bGVOYW1lPzogc3RyaW5nO1xuICB9O1xuICBwbHVnaW5zPzoge1xuICAgIGFzdD86IEFTVFBsdWdpbkJ1aWxkZXJbXTtcbiAgfTtcbiAgcGFyc2VPcHRpb25zPzogSGFuZGxlYmFyc1BhcnNlT3B0aW9ucztcbiAgY3VzdG9taXplQ29tcG9uZW50TmFtZT8oaW5wdXQ6IHN0cmluZyk6IHN0cmluZztcblxuICAvKipcbiAgICBVc2VmdWwgZm9yIHNwZWNpZnlpbmcgYSBncm91cCBvZiBvcHRpb25zIHRvZ2V0aGVyLlxuXG4gICAgV2hlbiBgJ2NvZGVtb2QnYCB3ZSBkaXNhYmxlIGFsbCB3aGl0ZXNwYWNlIGNvbnRyb2wgaW4gaGFuZGxlYmFyc1xuICAgICh0byBwcmVzZXJ2ZSBhcyBtdWNoIGFzIHBvc3NpYmxlKSBhbmQgd2UgYWxzbyBhdm9pZCBhbnlcbiAgICBlc2NhcGluZy91bmVzY2FwaW5nIG9mIEhUTUwgZW50aXR5IGNvZGVzLlxuICAgKi9cbiAgbW9kZT86ICdjb2RlbW9kJyB8ICdwcmVjb21waWxlJztcbn1cblxuZXhwb3J0IGludGVyZmFjZSBTeW50YXgge1xuICBwYXJzZTogdHlwZW9mIHByZXByb2Nlc3M7XG4gIGJ1aWxkZXJzOiB0eXBlb2YgcHVibGljQnVpbGRlcjtcbiAgcHJpbnQ6IHR5cGVvZiBwcmludDtcbiAgdHJhdmVyc2U6IHR5cGVvZiB0cmF2ZXJzZTtcbiAgV2Fsa2VyOiB0eXBlb2YgV2Fsa2VyO1xufVxuXG5jb25zdCBzeW50YXg6IFN5bnRheCA9IHtcbiAgcGFyc2U6IHByZXByb2Nlc3MsXG4gIGJ1aWxkZXJzOiBwdWJsaWNCdWlsZGVyLFxuICBwcmludCxcbiAgdHJhdmVyc2UsXG4gIFdhbGtlcixcbn07XG5cbmNsYXNzIENvZGVtb2RFbnRpdHlQYXJzZXIgZXh0ZW5kcyBFbnRpdHlQYXJzZXIge1xuICAvLyBtYXRjaCB1cHN0cmVhbSB0eXBlcywgYnV0IG5ldmVyIG1hdGNoIGFuIGVudGl0eVxuICBjb25zdHJ1Y3RvcigpIHtcbiAgICBzdXBlcih7fSk7XG4gIH1cblxuICBwYXJzZSgpOiBzdHJpbmcgfCB1bmRlZmluZWQge1xuICAgIHJldHVybiB1bmRlZmluZWQ7XG4gIH1cbn1cblxuZXhwb3J0IGZ1bmN0aW9uIHByZXByb2Nlc3MoXG4gIGlucHV0OiBzdHJpbmcgfCBTb3VyY2UgfCBIQlMuUHJvZ3JhbSxcbiAgb3B0aW9uczogUHJlcHJvY2Vzc09wdGlvbnMgPSB7fVxuKTogQVNUdjEuVGVtcGxhdGUge1xuICBsZXQgbW9kZSA9IG9wdGlvbnMubW9kZSB8fCAncHJlY29tcGlsZSc7XG5cbiAgbGV0IHNvdXJjZTogU291cmNlO1xuICBsZXQgYXN0OiBIQlMuUHJvZ3JhbTtcbiAgaWYgKHR5cGVvZiBpbnB1dCA9PT0gJ3N0cmluZycpIHtcbiAgICBzb3VyY2UgPSBuZXcgU291cmNlKGlucHV0LCBvcHRpb25zLm1ldGE/Lm1vZHVsZU5hbWUpO1xuXG4gICAgaWYgKG1vZGUgPT09ICdjb2RlbW9kJykge1xuICAgICAgYXN0ID0gcGFyc2VXaXRob3V0UHJvY2Vzc2luZyhpbnB1dCwgb3B0aW9ucy5wYXJzZU9wdGlvbnMpIGFzIEhCUy5Qcm9ncmFtO1xuICAgIH0gZWxzZSB7XG4gICAgICBhc3QgPSBwYXJzZShpbnB1dCwgb3B0aW9ucy5wYXJzZU9wdGlvbnMpIGFzIEhCUy5Qcm9ncmFtO1xuICAgIH1cbiAgfSBlbHNlIGlmIChpbnB1dCBpbnN0YW5jZW9mIFNvdXJjZSkge1xuICAgIHNvdXJjZSA9IGlucHV0O1xuXG4gICAgaWYgKG1vZGUgPT09ICdjb2RlbW9kJykge1xuICAgICAgYXN0ID0gcGFyc2VXaXRob3V0UHJvY2Vzc2luZyhpbnB1dC5zb3VyY2UsIG9wdGlvbnMucGFyc2VPcHRpb25zKSBhcyBIQlMuUHJvZ3JhbTtcbiAgICB9IGVsc2Uge1xuICAgICAgYXN0ID0gcGFyc2UoaW5wdXQuc291cmNlLCBvcHRpb25zLnBhcnNlT3B0aW9ucykgYXMgSEJTLlByb2dyYW07XG4gICAgfVxuICB9IGVsc2Uge1xuICAgIHNvdXJjZSA9IG5ldyBTb3VyY2UoJycsIG9wdGlvbnMubWV0YT8ubW9kdWxlTmFtZSk7XG4gICAgYXN0ID0gaW5wdXQ7XG4gIH1cblxuICBsZXQgZW50aXR5UGFyc2VyID0gdW5kZWZpbmVkO1xuICBpZiAobW9kZSA9PT0gJ2NvZGVtb2QnKSB7XG4gICAgZW50aXR5UGFyc2VyID0gbmV3IENvZGVtb2RFbnRpdHlQYXJzZXIoKTtcbiAgfVxuXG4gIGxldCBvZmZzZXRzID0gU291cmNlU3Bhbi5mb3JDaGFyUG9zaXRpb25zKHNvdXJjZSwgMCwgc291cmNlLnNvdXJjZS5sZW5ndGgpO1xuICBhc3QubG9jID0ge1xuICAgIHNvdXJjZTogJyhwcm9ncmFtKScsXG4gICAgc3RhcnQ6IG9mZnNldHMuc3RhcnRQb3NpdGlvbixcbiAgICBlbmQ6IG9mZnNldHMuZW5kUG9zaXRpb24sXG4gIH07XG5cbiAgbGV0IHByb2dyYW0gPSBuZXcgVG9rZW5pemVyRXZlbnRIYW5kbGVycyhzb3VyY2UsIGVudGl0eVBhcnNlciwgbW9kZSkuYWNjZXB0VGVtcGxhdGUoYXN0KTtcblxuICBpZiAob3B0aW9ucy5zdHJpY3RNb2RlKSB7XG4gICAgcHJvZ3JhbS5ibG9ja1BhcmFtcyA9IG9wdGlvbnMubG9jYWxzID8/IFtdO1xuICB9XG5cbiAgaWYgKG9wdGlvbnMgJiYgb3B0aW9ucy5wbHVnaW5zICYmIG9wdGlvbnMucGx1Z2lucy5hc3QpIHtcbiAgICBmb3IgKGxldCBpID0gMCwgbCA9IG9wdGlvbnMucGx1Z2lucy5hc3QubGVuZ3RoOyBpIDwgbDsgaSsrKSB7XG4gICAgICBsZXQgdHJhbnNmb3JtID0gb3B0aW9ucy5wbHVnaW5zLmFzdFtpXTtcbiAgICAgIGxldCBlbnY6IEFTVFBsdWdpbkVudmlyb25tZW50ID0gYXNzaWduKHt9LCBvcHRpb25zLCB7IHN5bnRheCB9LCB7IHBsdWdpbnM6IHVuZGVmaW5lZCB9KTtcblxuICAgICAgbGV0IHBsdWdpblJlc3VsdCA9IHRyYW5zZm9ybShlbnYpO1xuXG4gICAgICB0cmF2ZXJzZShwcm9ncmFtLCBwbHVnaW5SZXN1bHQudmlzaXRvcik7XG4gICAgfVxuICB9XG5cbiAgcmV0dXJuIHByb2dyYW07XG59XG4iXSwic291cmNlUm9vdCI6IiJ9