UNPKG

@glimmer/runtime

Version:

Minimal runtime needed to render Glimmer templates

534 lines (431 loc) 53.6 kB
import { assert } from '@glimmer/util'; import { ConcreteBounds, CursorImpl } from '../bounds'; import { CURSOR_STACK, NewElementBuilder, RemoteLiveBlock } from './element-builder'; export const SERIALIZATION_FIRST_NODE_STRING = '%+b:0%'; export function isSerializationFirstNode(node) { return node.nodeValue === SERIALIZATION_FIRST_NODE_STRING; } export class RehydratingCursor extends CursorImpl { constructor(element, nextSibling, startingBlockDepth) { super(element, nextSibling); this.startingBlockDepth = startingBlockDepth; this.candidate = null; this.injectedOmittedNode = false; this.openBlockDepth = startingBlockDepth - 1; } } export class RehydrateBuilder extends NewElementBuilder { constructor(env, parentNode, nextSibling) { super(env, parentNode, nextSibling); this.unmatchedAttributes = null; this.blockDepth = 0; if (nextSibling) throw new Error('Rehydration with nextSibling not supported'); let node = this.currentCursor.element.firstChild; while (node !== null) { if (isOpenBlock(node)) { break; } node = node.nextSibling; } (false && assert(node, 'Must have opening comment for rehydration.')); this.candidate = node; const startingBlockOffset = getBlockDepth(node); if (startingBlockOffset !== 0) { // We are rehydrating from a partial tree and not the root component // We need to add an extra block before the first block to rehydrate correctly // The extra block is needed since the renderComponent API creates a synthetic component invocation which generates the extra block const newBlockDepth = startingBlockOffset - 1; const newCandidate = this.dom.createComment(`%+b:${newBlockDepth}%`); node.parentNode.insertBefore(newCandidate, this.candidate); let closingNode = node.nextSibling; while (closingNode !== null) { if (isCloseBlock(closingNode) && getBlockDepth(closingNode) === startingBlockOffset) { break; } closingNode = closingNode.nextSibling; } (false && assert(closingNode, 'Must have closing comment for starting block comment')); const newClosingBlock = this.dom.createComment(`%-b:${newBlockDepth}%`); node.parentNode.insertBefore(newClosingBlock, closingNode.nextSibling); this.candidate = newCandidate; this.startingBlockOffset = newBlockDepth; } else { this.startingBlockOffset = 0; } } get currentCursor() { return this[CURSOR_STACK].current; } get candidate() { if (this.currentCursor) { return this.currentCursor.candidate; } return null; } set candidate(node) { let currentCursor = this.currentCursor; currentCursor.candidate = node; } disableRehydration(nextSibling) { let currentCursor = this.currentCursor; // rehydration will be disabled until we either: // * hit popElement (and return to using the parent elements cursor) // * hit closeBlock and the next sibling is a close block comment // matching the expected openBlockDepth currentCursor.candidate = null; currentCursor.nextSibling = nextSibling; } enableRehydration(candidate) { let currentCursor = this.currentCursor; currentCursor.candidate = candidate; currentCursor.nextSibling = null; } pushElement(element, nextSibling = null) { let cursor = new RehydratingCursor(element, nextSibling, this.blockDepth || 0); /** * <div> <--------------- currentCursor.element * <!--%+b:1%--> <------- would have been removed during openBlock * <div> <--------------- currentCursor.candidate -> cursor.element * <!--%+b:2%--> <----- currentCursor.candidate.firstChild -> cursor.candidate * Foo * <!--%-b:2%--> * </div> * <!--%-b:1%--> <------ becomes currentCursor.candidate */ if (this.candidate !== null) { cursor.candidate = element.firstChild; this.candidate = element.nextSibling; } this[CURSOR_STACK].push(cursor); } // clears until the end of the current container // either the current open block or higher clearMismatch(candidate) { let current = candidate; let currentCursor = this.currentCursor; if (currentCursor !== null) { let openBlockDepth = currentCursor.openBlockDepth; if (openBlockDepth >= currentCursor.startingBlockDepth) { while (current) { if (isCloseBlock(current)) { let closeBlockDepth = getBlockDepthWithOffset(current, this.startingBlockOffset); if (openBlockDepth >= closeBlockDepth) { break; } } current = this.remove(current); } } else { while (current !== null) { current = this.remove(current); } } // current cursor parentNode should be openCandidate if element // or openCandidate.parentNode if comment this.disableRehydration(current); } } __openBlock() { let { currentCursor } = this; if (currentCursor === null) return; let blockDepth = this.blockDepth; this.blockDepth++; let { candidate } = currentCursor; if (candidate === null) return; let { tagName } = currentCursor.element; if (isOpenBlock(candidate) && getBlockDepthWithOffset(candidate, this.startingBlockOffset) === blockDepth) { this.candidate = this.remove(candidate); currentCursor.openBlockDepth = blockDepth; } else if (tagName !== 'TITLE' && tagName !== 'SCRIPT' && tagName !== 'STYLE') { this.clearMismatch(candidate); } } __closeBlock() { let { currentCursor } = this; if (currentCursor === null) return; // openBlock is the last rehydrated open block let openBlockDepth = currentCursor.openBlockDepth; // this currently is the expected next open block depth this.blockDepth--; let { candidate } = currentCursor; let isRehydrating = false; if (candidate !== null) { isRehydrating = true; //assert( // openBlockDepth === this.blockDepth, // 'when rehydrating, openBlockDepth should match this.blockDepth here' //); if (isCloseBlock(candidate) && getBlockDepthWithOffset(candidate, this.startingBlockOffset) === openBlockDepth) { let nextSibling = this.remove(candidate); this.candidate = nextSibling; currentCursor.openBlockDepth--; } else { // close the block and clear mismatch in parent container // we will be either at the end of the element // or at the end of our containing block this.clearMismatch(candidate); isRehydrating = false; } } if (isRehydrating === false) { // check if nextSibling matches our expected close block // if so, we remove the close block comment and // restore rehydration after clearMismatch disabled let nextSibling = currentCursor.nextSibling; if (nextSibling !== null && isCloseBlock(nextSibling) && getBlockDepthWithOffset(nextSibling, this.startingBlockOffset) === this.blockDepth) { // restore rehydration state let candidate = this.remove(nextSibling); this.enableRehydration(candidate); currentCursor.openBlockDepth--; } } } __appendNode(node) { let { candidate } = this; // This code path is only used when inserting precisely one node. It needs more // comparison logic, but we can probably lean on the cases where this code path // is actually used. if (candidate) { return candidate; } else { return super.__appendNode(node); } } __appendHTML(html) { let candidateBounds = this.markerBounds(); if (candidateBounds) { let first = candidateBounds.firstNode(); let last = candidateBounds.lastNode(); let newBounds = new ConcreteBounds(this.element, first.nextSibling, last.previousSibling); let possibleEmptyMarker = this.remove(first); this.remove(last); if (possibleEmptyMarker !== null && isEmpty(possibleEmptyMarker)) { this.candidate = this.remove(possibleEmptyMarker); if (this.candidate !== null) { this.clearMismatch(this.candidate); } } return newBounds; } else { return super.__appendHTML(html); } } remove(node) { let element = node.parentNode; let next = node.nextSibling; element.removeChild(node); return next; } markerBounds() { let _candidate = this.candidate; if (_candidate && isMarker(_candidate)) { let first = _candidate; let last = first.nextSibling; while (last && !isMarker(last)) { last = last.nextSibling; } return new ConcreteBounds(this.element, first, last); } else { return null; } } __appendText(string) { let { candidate } = this; if (candidate) { if (isTextNode(candidate)) { if (candidate.nodeValue !== string) { candidate.nodeValue = string; } this.candidate = candidate.nextSibling; return candidate; } else if (isSeparator(candidate)) { this.candidate = this.remove(candidate); return this.__appendText(string); } else if (isEmpty(candidate) && string === '') { this.candidate = this.remove(candidate); return this.__appendText(string); } else { this.clearMismatch(candidate); return super.__appendText(string); } } else { return super.__appendText(string); } } __appendComment(string) { let _candidate = this.candidate; if (_candidate && isComment(_candidate)) { if (_candidate.nodeValue !== string) { _candidate.nodeValue = string; } this.candidate = _candidate.nextSibling; return _candidate; } else if (_candidate) { this.clearMismatch(_candidate); } return super.__appendComment(string); } __openElement(tag) { let _candidate = this.candidate; if (_candidate && isElement(_candidate) && isSameNodeType(_candidate, tag)) { this.unmatchedAttributes = [].slice.call(_candidate.attributes); return _candidate; } else if (_candidate) { if (isElement(_candidate) && _candidate.tagName === 'TBODY') { this.pushElement(_candidate, null); this.currentCursor.injectedOmittedNode = true; return this.__openElement(tag); } this.clearMismatch(_candidate); } return super.__openElement(tag); } __setAttribute(name, value, namespace) { let unmatched = this.unmatchedAttributes; if (unmatched) { let attr = findByName(unmatched, name); if (attr) { if (attr.value !== value) { attr.value = value; } unmatched.splice(unmatched.indexOf(attr), 1); return; } } return super.__setAttribute(name, value, namespace); } __setProperty(name, value) { let unmatched = this.unmatchedAttributes; if (unmatched) { let attr = findByName(unmatched, name); if (attr) { if (attr.value !== value) { attr.value = value; } unmatched.splice(unmatched.indexOf(attr), 1); return; } } return super.__setProperty(name, value); } __flushElement(parent, constructing) { let { unmatchedAttributes: unmatched } = this; if (unmatched) { for (let i = 0; i < unmatched.length; i++) { this.constructing.removeAttribute(unmatched[i].name); } this.unmatchedAttributes = null; } else { super.__flushElement(parent, constructing); } } willCloseElement() { let { candidate, currentCursor } = this; if (candidate !== null) { this.clearMismatch(candidate); } if (currentCursor && currentCursor.injectedOmittedNode) { this.popElement(); } super.willCloseElement(); } getMarker(element, guid) { let marker = element.querySelector(`script[glmr="${guid}"]`); if (marker) { return marker; } return null; } __pushRemoteElement(element, cursorId, insertBefore) { let marker = this.getMarker(element, cursorId); (false && assert(!marker || marker.parentNode === element, `expected remote element marker's parent node to match remote element`)); // when insertBefore is not present, we clear the element if (insertBefore === undefined) { while (element.firstChild !== null && element.firstChild !== marker) { this.remove(element.firstChild); } insertBefore = null; } let cursor = new RehydratingCursor(element, null, this.blockDepth); this[CURSOR_STACK].push(cursor); if (marker === null) { this.disableRehydration(insertBefore); } else { this.candidate = this.remove(marker); } let block = new RemoteLiveBlock(element); return this.pushLiveBlock(block, true); } didAppendBounds(bounds) { super.didAppendBounds(bounds); if (this.candidate) { let last = bounds.lastNode(); this.candidate = last && last.nextSibling; } return bounds; } } function isTextNode(node) { return node.nodeType === 3; } function isComment(node) { return node.nodeType === 8; } function isOpenBlock(node) { return node.nodeType === 8 /* COMMENT_NODE */ && node.nodeValue.lastIndexOf('%+b:', 0) === 0; } function isCloseBlock(node) { return node.nodeType === 8 /* COMMENT_NODE */ && node.nodeValue.lastIndexOf('%-b:', 0) === 0; } function getBlockDepth(node) { return parseInt(node.nodeValue.slice(4), 10); } function getBlockDepthWithOffset(node, offset) { return getBlockDepth(node) - offset; } function isElement(node) { return node.nodeType === 1; } function isMarker(node) { return node.nodeType === 8 && node.nodeValue === '%glmr%'; } function isSeparator(node) { return node.nodeType === 8 && node.nodeValue === '%|%'; } function isEmpty(node) { return node.nodeType === 8 && node.nodeValue === '% %'; } function isSameNodeType(candidate, tag) { if (candidate.namespaceURI === "http://www.w3.org/2000/svg" /* SVG */ ) { return candidate.tagName === tag; } return candidate.tagName === tag.toUpperCase(); } function findByName(array, name) { for (let i = 0; i < array.length; i++) { let attr = array[i]; if (attr.name === name) return attr; } return undefined; } export function rehydrationBuilder(env, cursor) { return RehydrateBuilder.forInitialRender(env, cursor); } //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3BhY2thZ2VzL0BnbGltbWVyL3J1bnRpbWUvbGliL3ZtL3JlaHlkcmF0ZS1idWlsZGVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUNBLFNBQVMsTUFBVCxRQUFtRSxlQUFuRTtBQVdBLFNBQVMsY0FBVCxFQUF5QixVQUF6QixRQUEyQyxXQUEzQztBQUNBLFNBQVMsWUFBVCxFQUF1QixpQkFBdkIsRUFBMEMsZUFBMUMsUUFBaUUsbUJBQWpFO0FBRUEsT0FBTyxNQUFNLCtCQUErQixHQUFHLFFBQXhDO0FBRVAsT0FBTSxTQUFVLHdCQUFWLENBQW1DLElBQW5DLEVBQW1EO0FBQ3ZELFNBQU8sSUFBSSxDQUFDLFNBQUwsS0FBbUIsK0JBQTFCO0FBQ0Q7QUFFRCxPQUFNLE1BQU8saUJBQVAsU0FBaUMsVUFBakMsQ0FBMkM7QUFJL0MsRUFBQSxXQUFBLENBQ0UsT0FERixFQUVFLFdBRkYsRUFHa0Isa0JBSGxCLEVBRzRDO0FBRTFDLFVBQU0sT0FBTixFQUFlLFdBQWY7QUFGZ0IsU0FBQSxrQkFBQSxHQUFBLGtCQUFBO0FBTmxCLFNBQUEsU0FBQSxHQUFnQyxJQUFoQztBQUVBLFNBQUEsbUJBQUEsR0FBc0IsS0FBdEI7QUFPRSxTQUFLLGNBQUwsR0FBc0Isa0JBQWtCLEdBQUcsQ0FBM0M7QUFDRDs7QUFYOEM7QUFjakQsT0FBTSxNQUFPLGdCQUFQLFNBQWdDLGlCQUFoQyxDQUFpRDtBQU1yRCxFQUFBLFdBQUEsQ0FBWSxHQUFaLEVBQThCLFVBQTlCLEVBQXlELFdBQXpELEVBQXdGO0FBQ3RGLFVBQU0sR0FBTixFQUFXLFVBQVgsRUFBdUIsV0FBdkI7QUFOTSxTQUFBLG1CQUFBLEdBQTRDLElBQTVDO0FBRVIsU0FBQSxVQUFBLEdBQWEsQ0FBYjtBQUtFLFFBQUksV0FBSixFQUFpQixNQUFNLElBQUksS0FBSixDQUFVLDRDQUFWLENBQU47QUFFakIsUUFBSSxJQUFJLEdBQUcsS0FBSyxhQUFMLENBQW9CLE9BQXBCLENBQTRCLFVB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QyxFQUFuQyxFQUF1QztBQUNyQyxRQUFJLElBQUksR0FBRyxLQUFLLENBQUMsQ0FBRCxDQUFoQjtBQUNBLFFBQUksSUFBSSxDQUFDLElBQUwsS0FBYyxJQUFsQixFQUF3QixPQUFPLElBQVA7QUFDekI7O0FBRUQsU0FBTyxTQUFQO0FBQ0Q7O0FBRUQsT0FBTSxTQUFVLGtCQUFWLENBQTZCLEdBQTdCLEVBQStDLE1BQS9DLEVBQWlFO0FBQ3JFLFNBQU8sZ0JBQWdCLENBQUMsZ0JBQWpCLENBQWtDLEdBQWxDLEVBQXVDLE1BQXZDLENBQVA7QUFDRCIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IEJvdW5kcywgRWxlbWVudEJ1aWxkZXIsIEVudmlyb25tZW50LCBPcHRpb24sIE1heWJlIH0gZnJvbSAnQGdsaW1tZXIvaW50ZXJmYWNlcyc7XG5pbXBvcnQgeyBhc3NlcnQsIGNhc3RUb0Jyb3dzZXIsIGNhc3RUb1NpbXBsZSwgZXhwZWN0LCBTdGFjayB9IGZyb20gJ0BnbGltbWVyL3V0aWwnO1xuaW1wb3J0IHtcbiAgQXR0ck5hbWVzcGFjZSxcbiAgTmFtZXNwYWNlLFxuICBOb2RlVHlwZSxcbiAgU2ltcGxlQXR0cixcbiAgU2ltcGxlQ29tbWVudCxcbiAgU2ltcGxlRWxlbWVudCxcbiAgU2ltcGxlTm9kZSxcbiAgU2ltcGxlVGV4dCxcbn0gZnJvbSAnQHNpbXBsZS1kb20vaW50ZXJmYWNlJztcbmltcG9ydCB7IENvbmNyZXRlQm91bmRzLCBDdXJzb3JJbXBsIH0gZnJvbSAnLi4vYm91bmRzJztcbmltcG9ydCB7IENVUlNPUl9TVEFDSywgTmV3RWxlbWVudEJ1aWxkZXIsIFJlbW90ZUxpdmVCbG9jayB9IGZyb20gJy4vZWxlbWVudC1idWlsZGVyJztcblxuZXhwb3J0IGNvbnN0IFNFUklBTElaQVRJT05fRklSU1RfTk9ERV9TVFJJTkcgPSAnJStiOjAlJztcblxuZXhwb3J0IGZ1bmN0aW9uIGlzU2VyaWFsaXphdGlvbkZpcnN0Tm9kZShub2RlOiBTaW1wbGVOb2RlKTogYm9vbGVhbiB7XG4gIHJldHVybiBub2RlLm5vZGVWYWx1ZSA9PT0gU0VSSUFMSVpBVElPTl9GSVJTVF9OT0RFX1NUUklORztcbn1cblxuZXhwb3J0IGNsYXNzIFJlaHlkcmF0aW5nQ3Vyc29yIGV4dGVuZHMgQ3Vyc29ySW1wbCB7XG4gIGNhbmRpZGF0ZTogT3B0aW9uPFNpbXBsZU5vZGU+ID0gbnVsbDtcbiAgb3BlbkJsb2NrRGVwdGg6IG51bWJlcjtcbiAgaW5qZWN0ZWRPbWl0dGVkTm9kZSA9IGZhbHNlO1xuICBjb25zdHJ1Y3RvcihcbiAgICBlbGVtZW50OiBTaW1wbGVFbGVtZW50LFxuICAgIG5leHRTaWJsaW5nOiBPcHRpb248U2ltcGxlTm9kZT4sXG4gICAgcHVibGljIHJlYWRvbmx5IHN0YXJ0aW5nQmxvY2tEZXB0aDogbnVtYmVyXG4gICkge1xuICAgIHN1cGVyKGVsZW1lbnQsIG5leHRTaWJsaW5nKTtcbiAgICB0aGlzLm9wZW5CbG9ja0RlcHRoID0gc3RhcnRpbmdCbG9ja0RlcHRoIC0gMTtcbiAgfVxufVxuXG5leHBvcnQgY2xhc3MgUmVoeWRyYXRlQnVpbGRlciBleHRlbmRzIE5ld0VsZW1lbnRCdWlsZGVyIGltcGxlbWVudHMgRWxlbWVudEJ1aWxkZXIge1xuICBwcml2YXRlIHVubWF0Y2hlZEF0dHJpYnV0ZXM6IE9wdGlvbjxTaW1wbGVBdHRyW10+ID0gbnVsbDtcbiAgW0NVUlNPUl9TVEFDS10hOiBTdGFjazxSZWh5ZHJhdGluZ0N1cnNvcj47IC8vIEhpZGVzIHByb3BlcnR5IG9uIGJhc2UgY2xhc3NcbiAgYmxvY2tEZXB0aCA9IDA7XG4gIHN0YXJ0aW5nQmxvY2tPZmZzZXQ6IG51bWJlcjtcblxuICBjb25zdHJ1Y3RvcihlbnY6IEVudmlyb25tZW50LCBwYXJlbnROb2RlOiBTaW1wbGVFbGVtZW50LCBuZXh0U2libGluZzogT3B0aW9uPFNpbXBsZU5vZGU+KSB7XG4gICAgc3VwZXIoZW52LCBwYXJlbnROb2RlLCBuZXh0U2libGluZyk7XG4gICAgaWYgKG5leHRTaWJsaW5nKSB0aHJvdyBuZXcgRXJyb3IoJ1JlaHlkcmF0aW9uIHdpdGggbmV4dFNpYmxpbmcgbm90IHN1cHBvcnRlZCcpO1xuXG4gICAgbGV0IG5vZGUgPSB0aGlzLmN1cnJlbnRDdXJzb3IhLmVsZW1lbnQuZmlyc3RDaGlsZDtcblxuICAgIHdoaWxlIChub2RlICE9PSBudWxsKSB7XG4gICAgICBpZiAoaXNPcGVuQmxvY2sobm9kZSkpIHtcbiAgICAgICAgYnJlYWs7XG4gICAgICB9XG4gICAgICBub2RlID0gbm9kZS5uZXh0U2libGluZztcbiAgICB9XG5cbiAgICBhc3NlcnQobm9kZSwgJ011c3QgaGF2ZSBvcGVuaW5nIGNvbW1lbnQgZm9yIHJlaHlkcmF0aW9uLicpO1xuICAgIHRoaXMuY2FuZGlkYXRlID0gbm9kZTtcbiAgICBjb25zdCBzdGFydGluZ0Jsb2NrT2Zmc2V0ID0gZ2V0QmxvY2tEZXB0aChub2RlIGFzIFNpbXBsZUNvbW1lbnQpO1xuICAgIGlmIChzdGFydGluZ0Jsb2NrT2Zmc2V0ICE9PSAwKSB7XG4gICAgICAvLyBXZSBhcmUgcmVoeWRyYXRpbmcgZnJvbSBhIHBhcnRpYWwgdHJlZSBhbmQgbm90IHRoZSByb290IGNvbXBvbmVudFxuICAgICAgLy8gV2UgbmVlZCB0byBhZGQgYW4gZXh0cmEgYmxvY2sgYmVmb3JlIHRoZSBmaXJzdCBibG9jayB0byByZWh5ZHJhdGUgY29ycmVjdGx5XG4gICAgICAvLyBUaGUgZXh0cmEgYmxvY2sgaXMgbmVlZGVkIHNpbmNlIHRoZSByZW5kZXJDb21wb25lbnQgQVBJIGNyZWF0ZXMgYSBzeW50aGV0aWMgY29tcG9uZW50IGludm9jYXRpb24gd2hpY2ggZ2VuZXJhdGVzIHRoZSBleHRyYSBibG9ja1xuICAgICAgY29uc3QgbmV3QmxvY2tEZXB0aCA9IHN0YXJ0aW5nQmxvY2tPZmZzZXQgLSAxO1xuICAgICAgY29uc3QgbmV3Q2FuZGlkYXRlID0gdGhpcy5kb20uY3JlYXRlQ29tbWVudChgJStiOiR7bmV3QmxvY2tEZXB0aH0lYCk7XG5cbiAgICAgIG5vZGUhLnBhcmVudE5vZGUhLmluc2VydEJlZm9yZShuZXdDYW5kaWRhdGUsIHRoaXMuY2FuZGlkYXRlKTtcbiAgICAgIGxldCBjbG9zaW5nTm9kZSA9IG5vZGUhLm5leHRTaWJsaW5nO1xuICAgICAgd2hpbGUgKGNsb3NpbmdOb2RlICE9PSBudWxsKSB7XG4gICAgICAgIGlmIChpc0Nsb3NlQmxvY2soY2xvc2luZ05vZGUpICYmIGdldEJsb2NrRGVwdGgoY2xvc2luZ05vZGUpID09PSBzdGFydGluZ0Jsb2NrT2Zmc2V0KSB7XG4gICAgICAgICAgYnJlYWs7XG4gICAgICAgIH1cbiAgICAgICAgY2xvc2luZ05vZGUgPSBjbG9zaW5nTm9kZS5uZXh0U2libGluZztcbiAgICAgIH1cblxuICAgICAgYXNzZXJ0KGNsb3NpbmdOb2RlLCAnTXVzdCBoYXZlIGNsb3NpbmcgY29tbWVudCBmb3Igc3RhcnRpbmcgYmxvY2sgY29tbWVudCcpO1xuICAgICAgY29uc3QgbmV3Q2xvc2luZ0Jsb2NrID0gdGhpcy5kb20uY3JlYXRlQ29tbWVudChgJS1iOiR7bmV3QmxvY2tEZXB0aH0lYCk7XG4gICAgICBub2RlIS5wYXJlbnROb2RlIS5pbnNlcnRCZWZvcmUobmV3Q2xvc2luZ0Jsb2NrLCBjbG9zaW5nTm9kZSEubmV4dFNpYmxpbmcpO1xuICAgICAgdGhpcy5jYW5kaWRhdGUgPSBuZXdDYW5kaWRhdGU7XG4gICAgICB0aGlzLnN0YXJ0aW5nQmxvY2tPZmZzZXQgPSBuZXdCbG9ja0RlcHRoO1xuICAgIH0gZWxzZSB7XG4gICAgICB0aGlzLnN0YXJ0aW5nQmxvY2tPZmZzZXQgPSAwO1xuICAgIH1cbiAgfVxuXG4gIGdldCBjdXJyZW50Q3Vyc29yKCk6IE9wdGlvbjxSZWh5ZHJhdGluZ0N1cnNvcj4ge1xuICAgIHJldHVybiB0aGlzW0NVUlNPUl9TVEFDS10uY3VycmVudDtcbiAgfVxuXG4gIGdldCBjYW5kaWRhdGUoKTogT3B0aW9uPFNpbXBsZU5vZGU+IHtcbiAgICBpZiAodGhpcy5jdXJyZW50Q3Vyc29yKSB7XG4gICAgICByZXR1cm4gdGhpcy5jdXJyZW50Q3Vyc29yLmNhbmRpZGF0ZSE7XG4gICAgfVxuXG4gICAgcmV0dXJuIG51bGw7XG4gIH1cblxuICBzZXQgY2FuZGlkYXRlKG5vZGU6IE9wdGlvbjxTaW1wbGVOb2RlPikge1xuICAgIGxldCBjdXJyZW50Q3Vyc29yID0gdGhpcy5jdXJyZW50Q3Vyc29yITtcblxuICAgIGN1cnJlbnRDdXJzb3IuY2FuZGlkYXRlID0gbm9kZTtcbiAgfVxuXG4gIGRpc2FibGVSZWh5ZHJhdGlvbihuZXh0U2libGluZzogT3B0aW9uPFNpbXBsZU5vZGU+KSB7XG4gICAgbGV0IGN1cnJlbnRDdXJzb3IgPSB0aGlzLmN1cnJlbnRDdXJzb3IhO1xuXG4gICAgLy8gcmVoeWRyYXRpb24gd2lsbCBiZSBkaXNhYmxlZCB1bnRpbCB3ZSBlaXRoZXI6XG4gICAgLy8gKiBoaXQgcG9wRWxlbWVudCAoYW5kIHJldHVybiB0byB1c2luZyB0aGUgcGFyZW50IGVsZW1lbnRzIGN1cnNvcilcbiAgICAvLyAqIGhpdCBjbG9zZUJsb2NrIGFuZCB0aGUgbmV4dCBzaWJsaW5nIGlzIGEgY2xvc2UgYmxvY2sgY29tbWVudFxuICAgIC8vICAgbWF0Y2hpbmcgdGhlIGV4cGVjdGVkIG9wZW5CbG9ja0RlcHRoXG4gICAgY3VycmVudEN1cnNvci5jYW5kaWRhdGUgPSBudWxsO1xuICAgIGN1cnJlbnRDdXJzb3IubmV4dFNpYmxpbmcgPSBuZXh0U2libGluZztcbiAgfVxuXG4gIGVuYWJsZVJlaHlkcmF0aW9uKGNhbmRpZGF0ZTogT3B0aW9uPFNpbXBsZU5vZGU+KSB7XG4gICAgbGV0IGN1cnJlbnRDdXJzb3IgPSB0aGlzLmN1cnJlbnRDdXJzb3IhO1xuXG4gICAgY3VycmVudEN1cnNvci5jYW5kaWRhdGUgPSBjYW5kaWRhdGU7XG4gICAgY3VycmVudEN1cnNvci5uZXh0U2libGluZyA9IG51bGw7XG4gIH1cblxuICBwdXNoRWxlbWVudChcbiAgICAvKiogY2FsbGVkIGZyb20gcGFyZW50IGNvbnN0cnVjdG9yIGJlZm9yZSB3ZSBpbml0aWFsaXplIHRoaXMgKi9cbiAgICB0aGlzOlxuICAgICAgfCBSZWh5ZHJhdGVCdWlsZGVyXG4gICAgICB8IChOZXdFbGVtZW50QnVpbGRlciAmIFBhcnRpYWw8UGljazxSZWh5ZHJhdGVCdWlsZGVyLCAnYmxvY2tEZXB0aCcgfCAnY2FuZGlkYXRlJz4+KSxcbiAgICBlbGVtZW50OiBTaW1wbGVFbGVtZW50LFxuICAgIG5leHRTaWJsaW5nOiBNYXliZTxTaW1wbGVOb2RlPiA9IG51bGxcbiAgKSB7XG4gICAgbGV0IGN1cnNvciA9IG5ldyBSZWh5ZHJhdGluZ0N1cnNvcihlbGVtZW50LCBuZXh0U2libGluZywgdGhpcy5ibG9ja0RlcHRoIHx8IDApO1xuXG4gICAgLyoqXG4gICAgICogPGRpdj4gICA8LS0tLS0tLS0tLS0tLS0tICBjdXJyZW50Q3Vyc29yLmVsZW1lbnRcbiAgICAgKiAgIDwhLS0lK2I6MSUtLT4gPC0tLS0tLS0gIHdvdWxkIGhhdmUgYmVlbiByZW1vdmVkIGR1cmluZyBvcGVuQmxvY2tcbiAgICAgKiAgIDxkaXY+IDwtLS0tLS0tLS0tLS0tLS0gIGN1cnJlbnRDdXJzb3IuY2FuZGlkYXRlIC0+IGN1cnNvci5lbGVtZW50XG4gICAgICogICAgIDwhLS0lK2I6MiUtLT4gPC0tLS0tICBjdXJyZW50Q3Vyc29yLmNhbmRpZGF0ZS5maXJzdENoaWxkIC0+IGN1cnNvci5jYW5kaWRhdGVcbiAgICAgKiAgICAgRm9vXG4gICAgICogICAgIDwhLS0lLWI6MiUtLT5cbiAgICAgKiAgIDwvZGl2PlxuICAgICAqICAgPCEtLSUtYjoxJS0tPiAgPC0tLS0tLSAgYmVjb21lcyBjdXJyZW50Q3Vyc29yLmNhbmRpZGF0ZVxuICAgICAqL1xuICAgIGlmICh0aGlzLmNhbmRpZGF0ZSAhPT0gbnVsbCkge1xuICAgICAgY3Vyc29yLmNhbmRpZGF0ZSA9IGVsZW1lbnQuZmlyc3RDaGlsZDtcbiAgICAgIHRoaXMuY2FuZGlkYXRlID0gZWxlbWVudC5uZXh0U2libGluZztcbiAgICB9XG5cbiAgICB0aGlzW0NVUlNPUl9TVEFDS10ucHVzaChjdXJzb3IpO1xuICB9XG5cbiAgLy8gY2xlYXJzIHVudGlsIHRoZSBlbmQgb2YgdGhlIGN1cnJlbnQgY29udGFpbmVyXG4gIC8vIGVpdGhlciB0aGUgY3VycmVudCBvcGVuIGJsb2NrIG9yIGhpZ2hlclxuICBwcml2YXRlIGNsZWFyTWlzbWF0Y2goY2FuZGlkYXRlOiBTaW1wbGVOb2RlKSB7XG4gICAgbGV0IGN1cnJlbnQ6IE9wdGlvbjxTaW1wbGVOb2RlPiA9IGNhbmRpZGF0ZTtcbiAgICBsZXQgY3VycmVudEN1cnNvciA9IHRoaXMuY3VycmVudEN1cnNvcjtcbiAgICBpZiAoY3VycmVudEN1cnNvciAhPT0gbnVsbCkge1xuICAgICAgbGV0IG9wZW5CbG9ja0RlcHRoID0gY3VycmVudEN1cnNvci5vcGVuQmxvY2tEZXB0aDtcbiAgICAgIGlmIChvcGVuQmxvY2tEZXB0aCA+PSBjdXJyZW50Q3Vyc29yLnN0YXJ0aW5nQmxvY2tEZXB0aCkge1xuICAgICAgICB3aGlsZSAoY3VycmVudCkge1xuICAgICAgICAgIGlmIChpc0Nsb3NlQmxvY2soY3VycmVudCkpIHtcbiAgICAgICAgICAgIGxldCBjbG9zZUJsb2NrRGVwdGggPSBnZXRCbG9ja0RlcHRoV2l0aE9mZnNldChjdXJyZW50LCB0aGlzLnN0YXJ0aW5nQmxvY2tPZmZzZXQpO1xuICAgICAgICAgICAgaWYgKG9wZW5CbG9ja0RlcHRoID49IGNsb3NlQmxvY2tEZXB0aCkge1xuICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgICAgY3VycmVudCA9IHRoaXMucmVtb3ZlKGN1cnJlbnQpO1xuICAgICAgICB9XG4gICAgICB9IGVsc2Uge1xuICAgICAgICB3aGlsZSAoY3VycmVudCAhPT0gbnVsbCkge1xuICAgICAgICAgIGN1cnJlbnQgPSB0aGlzLnJlbW92ZShjdXJyZW50KTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgLy8gY3VycmVudCBjdXJzb3IgcGFyZW50Tm9kZSBzaG91bGQgYmUgb3BlbkNhbmRpZGF0ZSBpZiBlbGVtZW50XG4gICAgICAvLyBvciBvcGVuQ2FuZGlkYXRlLnBhcmVudE5vZGUgaWYgY29tbWVudFxuICAgICAgdGhpcy5kaXNhYmxlUmVoeWRyYXRpb24oY3VycmVudCk7XG4gICAgfVxuICB9XG5cbiAgX19vcGVuQmxvY2soKTogdm9pZCB7XG4gICAgbGV0IHsgY3VycmVudEN1cnNvciB9ID0gdGhpcztcbiAgICBpZiAoY3VycmVudEN1cnNvciA9PT0gbnVsbCkgcmV0dXJuO1xuXG4gICAgbGV0IGJsb2NrRGVwdGggPSB0aGlzLmJsb2NrRGVwdGg7XG5cbiAgICB0aGlzLmJsb2NrRGVwdGgrKztcblxuICAgIGxldCB7IGNhbmRpZGF0ZSB9ID0gY3VycmVudEN1cnNvcjtcbiAgICBpZiAoY2FuZGlkYXRlID09PSBudWxsKSByZXR1cm47XG5cbiAgICBsZXQgeyB0YWdOYW1lIH0gPSBjdXJyZW50Q3Vyc29yLmVsZW1lbnQ7XG5cbiAgICBpZiAoXG4gICAgICBpc09wZW5CbG9jayhjYW5kaWRhdGUpICYmXG4gICAgICBnZXRCbG9ja0RlcHRoV2l0aE9mZnNldChjYW5kaWRhdGUsIHRoaXMuc3RhcnRpbmdCbG9ja09mZnNldCkgPT09IGJsb2NrRGVwdGhcbiAgICApIHtcbiAgICAgIHRoaXMuY2FuZGlkYXRlID0gdGhpcy5yZW1vdmUoY2FuZGlkYXRlKTtcbiAgICAgIGN1cnJlbnRDdXJzb3Iub3BlbkJsb2NrRGVwdGggPSBibG9ja0RlcHRoO1xuICAgIH0gZWxzZSBpZiAodGFnTmFtZSAhPT0gJ1RJVExFJyAmJiB0YWdOYW1lICE9PSAnU0NSSVBUJyAmJiB0YWdOYW1lICE9PSAnU1RZTEUnKSB7XG4gICAgICB0aGlzLmNsZWFyTWlzbWF0Y2goY2FuZGlkYXRlKTtcbiAgICB9XG4gIH1cblxuICBfX2Nsb3NlQmxvY2soKTogdm9pZCB7XG4gICAgbGV0IHsgY3VycmVudEN1cnNvciB9ID0gdGhpcztcbiAgICBpZiAoY3VycmVudEN1cnNvciA9PT0gbnVsbCkgcmV0dXJuO1xuXG4gICAgLy8gb3BlbkJsb2NrIGlzIHRoZSBsYXN0IHJlaHlkcmF0ZWQgb3BlbiBibG9ja1xuICAgIGxldCBvcGVuQmxvY2tEZXB0aCA9IGN1cnJlbnRDdXJzb3Iub3BlbkJsb2NrRGVwdGg7XG5cbiAgICAvLyB0aGlzIGN1cnJlbnRseSBpcyB0aGUgZXhwZWN0ZWQgbmV4dCBvcGVuIGJsb2NrIGRlcHRoXG4gICAgdGhpcy5ibG9ja0RlcHRoLS07XG5cbiAgICBsZXQgeyBjYW5kaWRhdGUgfSA9IGN1cnJlbnRDdXJzb3I7XG5cbiAgICBsZXQgaXNSZWh5ZHJhdGluZyA9IGZhbHNlO1xuXG4gICAgaWYgKGNhbmRpZGF0ZSAhPT0gbnVsbCkge1xuICAgICAgaXNSZWh5ZHJhdGluZyA9IHRydWU7XG4gICAgICAvL2Fzc2VydChcbiAgICAgIC8vICBvcGVuQmxvY2tEZXB0aCA9PT0gdGhpcy5ibG9ja0RlcHRoLFxuICAgICAgLy8gICd3aGVuIHJlaHlkcmF0aW5nLCBvcGVuQmxvY2tEZXB0aCBzaG91bGQgbWF0Y2ggdGhpcy5ibG9ja0RlcHRoIGhlcmUnXG4gICAgICAvLyk7XG5cbiAgICAgIGlmIChcbiAgICAgICAgaXNDbG9zZUJsb2NrKGNhbmRpZGF0ZSkgJiZcbiAgICAgICAgZ2V0QmxvY2tEZXB0aFdpdGhPZmZzZXQoY2FuZGlkYXRlLCB0aGlzLnN0YXJ0aW5nQmxvY2tPZmZzZXQpID09PSBvcGVuQmxvY2tEZXB0aFxuICAgICAgKSB7XG4gICAgICAgIGxldCBuZXh0U2libGluZyA9IHRoaXMucmVtb3ZlKGNhbmRpZGF0ZSk7XG4gICAgICAgIHRoaXMuY2FuZGlkYXRlID0gbmV4dFNpYmxpbmc7XG4gICAgICAgIGN1cnJlbnRDdXJzb3Iub3BlbkJsb2NrRGVwdGgtLTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIC8vIGNsb3NlIHRoZSBibG9jayBhbmQgY2xlYXIgbWlzbWF0Y2ggaW4gcGFyZW50IGNvbnRhaW5lclxuICAgICAgICAvLyB3ZSB3aWxsIGJlIGVpdGhlciBhdCB0aGUgZW5kIG9mIHRoZSBlbGVtZW50XG4gICAgICAgIC8vIG9yIGF0IHRoZSBlbmQgb2Ygb3VyIGNvbnRhaW5pbmcgYmxvY2tcbiAgICAgICAgdGhpcy5jbGVhck1pc21hdGNoKGNhbmRpZGF0ZSk7XG4gICAgICAgIGlzUmVoeWRyYXRpbmcgPSBmYWxzZTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICBpZiAoaXNSZWh5ZHJhdGluZyA9PT0gZmFsc2UpIHtcbiAgICAgIC8vIGNoZWNrIGlmIG5leHRTaWJsaW5nIG1hdGNoZXMgb3VyIGV4cGVjdGVkIGNsb3NlIGJsb2NrXG4gICAgICAvLyBpZiBzbywgd2UgcmVtb3ZlIHRoZSBjbG9zZSBibG9jayBjb21tZW50IGFuZFxuICAgICAgLy8gcmVzdG9yZSByZWh5ZHJhdGlvbiBhZnRlciBjbGVhck1pc21hdGNoIGRpc2FibGVkXG4gICAgICBsZXQgbmV4dFNpYmxpbmcgPSBjdXJyZW50Q3Vyc29yLm5leHRTaWJsaW5nO1xuICAgICAgaWYgKFxuICAgICAgICBuZXh0U2libGluZyAhPT0gbnVsbCAmJlxuICAgICAgICBpc0Nsb3NlQmxvY2sobmV4dFNpYmxpbmcpICYmXG4gICAgICAgIGdldEJsb2NrRGVwdGhXaXRoT2Zmc2V0KG5leHRTaWJsaW5nLCB0aGlzLnN0YXJ0aW5nQmxvY2tPZmZzZXQpID09PSB0aGlzLmJsb2NrRGVwdGhcbiAgICAgICkge1xuICAgICAgICAvLyByZXN0b3JlIHJlaHlkcmF0aW9uIHN0YXRlXG4gICAgICAgIGxldCBjYW5kaWRhdGUgPSB0aGlzLnJlbW92ZShuZXh0U2libGluZyk7XG4gICAgICAgIHRoaXMuZW5hYmxlUmVoeWRyYXRpb24oY2FuZGlkYXRlKTtcblxuICAgICAgICBjdXJyZW50Q3Vyc29yLm9wZW5CbG9ja0RlcHRoLS07XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgX19hcHBlbmROb2RlKG5vZGU6IFNpbXBsZU5vZGUpOiBTaW1wbGVOb2RlIHtcbiAgICBsZXQgeyBjYW5kaWRhdGUgfSA9IHRoaXM7XG5cbiAgICAvLyBUaGlzIGNvZGUgcGF0aCBpcyBvbmx5IHVzZWQgd2hlbiBpbnNlcnRpbmcgcHJlY2lzZWx5IG9uZSBub2RlLiBJdCBuZWVkcyBtb3JlXG4gICAgLy8gY29tcGFyaXNvbiBsb2dpYywgYnV0IHdlIGNhbiBwcm9iYWJseSBsZWFuIG9uIHRoZSBjYXNlcyB3aGVyZSB0aGlzIGNvZGUgcGF0aFxuICAgIC8vIGlzIGFjdHVhbGx5IHVzZWQuXG4gICAgaWYgKGNhbmRpZGF0ZSkge1xuICAgICAgcmV0dXJuIGNhbmRpZGF0ZTtcbiAgICB9IGVsc2Uge1xuICAgICAgcmV0dXJuIHN1cGVyLl9fYXBwZW5kTm9kZShub2RlKTtcbiAgICB9XG4gIH1cblxuICBfX2FwcGVuZEhUTUwoaHRtbDogc3RyaW5nKTogQm91bmRzIHtcbiAgICBsZXQgY2FuZGlkYXRlQm91bmRzID0gdGhpcy5tYXJrZXJCb3VuZHMoKTtcblxuICAgIGlmIChjYW5kaWRhdGVCb3VuZHMpIHtcbiAgICAgIGxldCBmaXJzdCA9IGNhbmRpZGF0ZUJvdW5kcy5maXJzdE5vZGUoKSE7XG4gICAgICBsZXQgbGFzdCA9IGNhbmRpZGF0ZUJvdW5kcy5sYXN0Tm9kZSgpITtcblxuICAgICAgbGV0IG5ld0JvdW5kcyA9IG5ldyBDb25jcmV0ZUJvdW5kcyh0aGlzLmVsZW1lbnQsIGZpcnN0Lm5leHRTaWJsaW5nISwgbGFzdC5wcmV2aW91c1NpYmxpbmchKTtcblxuICAgICAgbGV0IHBvc3NpYmxlRW1wdHlNYXJrZXIgPSB0aGlzLnJlbW92ZShmaXJzdCk7XG4gICAgICB0aGlzLnJlbW92ZShsYXN0KTtcblxuICAgICAgaWYgKHBvc3NpYmxlRW1wdHlNYXJrZXIgIT09IG51bGwgJiYgaXNFbXB0eShwb3NzaWJsZUVtcHR5TWFya2VyKSkge1xuICAgICAgICB0aGlzLmNhbmRpZGF0ZSA9IHRoaXMucmVtb3ZlKHBvc3NpYmxlRW1wdHlNYXJrZXIpO1xuXG4gICAgICAgIGlmICh0aGlzLmNhbmRpZGF0ZSAhPT0gbnVsbCkge1xuICAgICAgICAgIHRoaXMuY2xlYXJNaXNtYXRjaCh0aGlzLmNhbmRpZGF0ZSk7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgcmV0dXJuIG5ld0JvdW5kcztcbiAgICB9IGVsc2Uge1xuICAgICAgcmV0dXJuIHN1cGVyLl9fYXBwZW5kSFRNTChodG1sKTtcbiAgICB9XG4gIH1cblxuICBwcm90ZWN0ZWQgcmVtb3ZlKG5vZGU6IFNpbXBsZU5vZGUpOiBPcHRpb248U2ltcGxlTm9kZT4ge1xuICAgIGxldCBlbGVtZW50ID0gZXhwZWN0KG5vZGUucGFyZW50Tm9kZSwgYGNhbm5vdCByZW1vdmUgYSBkZXRhY2hlZCBub2RlYCkgYXMgU2ltcGxlRWxlbWVudDtcbiAgICBsZXQgbmV4dCA9IG5vZGUubmV4dFNpYmxpbmc7XG4gICAgZWxlbWVudC5yZW1vdmVDaGlsZChub2RlKTtcbiAgICByZXR1cm4gbmV4dDtcbiAgfVxuXG4gIHByaXZhdGUgbWFya2VyQm91bmRzKCk6IE9wdGlvbjxCb3VuZHM+IHtcbiAgICBsZXQgX2NhbmRpZGF0ZSA9IHRoaXMuY2FuZGlkYXRlO1xuXG4gICAgaWYgKF9jYW5kaWRhdGUgJiYgaXNNYXJrZXIoX2NhbmRpZGF0ZSkpIHtcbiAgICAgIGxldCBmaXJzdCA9IF9jYW5kaWRhdGU7XG4gICAgICBsZXQgbGFzdCA9IGV4cGVjdChmaXJzdC5uZXh0U2libGluZywgYEJVRzogc2VyaWFsaXphdGlvbiBtYXJrZXJzIG11c3QgYmUgcGFpcmVkYCk7XG5cbiAgICAgIHdoaWxlIChsYXN0ICYmICFpc01hcmtlcihsYXN0KSkge1xuICAgICAgICBsYXN0ID0gZXhwZWN0KGxhc3QubmV4dFNpYmxpbmcsIGBCVUc6IHNlcmlhbGl6YXRpb24gbWFya2VycyBtdXN0IGJlIHBhaXJlZGApO1xuICAgICAgfVxuXG4gICAgICByZXR1cm4gbmV3IENvbmNyZXRlQm91bmRzKHRoaXMuZWxlbWVudCwgZmlyc3QsIGxhc3QpO1xuICAgIH0gZWxzZSB7XG4gICAgICByZXR1cm4gbnVsbDtcbiAgICB9XG4gIH1cblxuICBfX2FwcGVuZFRleHQoc3RyaW5nOiBzdHJpbmcpOiBTaW1wbGVUZXh0IHtcbiAgICBsZXQgeyBjYW5kaWRhdGUgfSA9IHRoaXM7XG5cbiAgICBpZiAoY2FuZGlkYXRlKSB7XG4gICAgICBpZiAoaXNUZXh0Tm9kZShjYW5kaWRhdGUpKSB7XG4gICAgICAgIGlmIChjYW5kaWRhdGUubm9kZVZhbHVlICE9PSBzdHJpbmcpIHtcbiAgICAgICAgICBjYW5kaWRhdGUubm9kZVZhbHVlID0gc3RyaW5nO1xuICAgICAgICB9XG4gICAgICAgIHRoaXMuY2FuZGlkYXRlID0gY2FuZGlkYXRlLm5leHRTaWJsaW5nO1xuXG4gICAgICAgIHJldHVybiBjYW5kaWRhdGU7XG4gICAgICB9IGVsc2UgaWYgKGlzU2VwYXJhdG9yKGNhbmRpZGF0ZSkpIHtcbiAgICAgICAgdGhpcy5jYW5kaWRhdGUgPSB0aGlzLnJlbW92ZShjYW5kaWRhdGUpO1xuXG4gICAgICAgIHJldHVybiB0aGlzLl9fYXBwZW5kVGV4dChzdHJpbmcpO1xuICAgICAgfSBlbHNlIGlmIChpc0VtcHR5KGNhbmRpZGF0ZSkgJiYgc3RyaW5nID09PSAnJykge1xuICAgICAgICB0aGlzLmNhbmRpZGF0ZSA9IHRoaXMucmVtb3ZlKGNhbmRpZGF0ZSk7XG5cbiAgICAgICAgcmV0dXJuIHRoaXMuX19hcHBlbmRUZXh0KHN0cmluZyk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICB0aGlzLmNsZWFyTWlzbWF0Y2goY2FuZGlkYXRlKTtcblxuICAgICAgICByZXR1cm4gc3VwZXIuX19hcHBlbmRUZXh0KHN0cmluZyk7XG4gICAgICB9XG4gICAgfSBlbHNlIHtcbiAgICAgIHJldHVybiBzdXBlci5fX2FwcGVuZFRleHQoc3RyaW5nKTtcbiAgICB9XG4gIH1cblxuICBfX2FwcGVuZENvbW1lbnQoc3RyaW5nOiBzdHJpbmcpOiBTaW1wbGVDb21tZW50IHtcbiAgICBsZXQgX2NhbmRpZGF0ZSA9IHRoaXMuY2FuZGlkYXRlO1xuICAgIGlmIChfY2FuZGlkYXRlICYmIGlzQ29tbWVudChfY2FuZGlkYXRlKSkge1xuICAgICAgaWYgKF9jYW5kaWRhdGUubm9kZVZhbHVlICE9PSBzdHJpbmcpIHtcbiAgICAgICAgX2NhbmRpZGF0ZS5ub2RlVmFsdWUgPSBzdHJpbmc7XG4gICAgICB9XG5cbiAgICAgIHRoaXMuY2FuZGlkYXRlID0gX2NhbmRpZGF0ZS5uZXh0U2libGluZztcbiAgICAgIHJldHVybiBfY2FuZGlkYXRlO1xuICAgIH0gZWxzZSBpZiAoX2NhbmRpZGF0ZSkge1xuICAgICAgdGhpcy5jbGVhck1pc21hdGNoKF9jYW5kaWRhdGUpO1xuICAgIH1cblxuICAgIHJldHVybiBzdXBlci5fX2FwcGVuZENvbW1lbnQoc3RyaW5nKTtcbiAgfVxuXG4gIF9fb3BlbkVsZW1lbnQodGFnOiBzdHJpbmcpOiBTaW1wbGVFbGVtZW50IHtcbiAgICBsZXQgX2NhbmRpZGF0ZSA9IHRoaXMuY2FuZGlkYXRlO1xuXG4gICAgaWYgKF9jYW5kaWRhdGUgJiYgaXNFbGVtZW50KF9jYW5kaWRhdGUpICYmIGlzU2FtZU5vZGVUeXBlKF9jYW5kaWRhdGUsIHRhZykpIHtcbiAgICAgIHRoaXMudW5tYXRjaGVkQXR0cmlidXRlcyA9IFtdLnNsaWNlLmNhbGwoX2NhbmRpZGF0ZS5hdHRyaWJ1dGVzKTtcbiAgICAgIHJldHVybiBfY2FuZGlkYXRlO1xuICAgIH0gZWxzZSBpZiAoX2NhbmRpZGF0ZSkge1xuICAgICAgaWYgKGlzRWxlbWVudChfY2FuZGlkYXRlKSAmJiBfY2FuZGlkYXRlLnRhZ05hbWUgPT09ICdUQk9EWScpIHtcbiAgICAgICAgdGhpcy5wdXNoRWxlbWVudChfY2FuZGlkYXRlLCBudWxsKTtcbiAgICAgICAgdGhpcy5jdXJyZW50Q3Vyc29yIS5pbmplY3RlZE9taXR0ZWROb2RlID0gdHJ1ZTtcbiAgICAgICAgcmV0dXJuIHRoaXMuX19vcGVuRWxlbWVudCh0YWcpO1xuICAgICAgfVxuICAgICAgdGhpcy5jbGVhck1pc21hdGNoKF9jYW5kaWRhdGUpO1xuICAgIH1cblxuICAgIHJldHVybiBzdXBlci5fX29wZW5FbGVtZW50KHRhZyk7XG4gIH1cblxuICBfX3NldEF0dHJpYnV0ZShuYW1lOiBzdHJpbmcsIHZhbHVlOiBzdHJpbmcsIG5hbWVzcGFjZTogT3B0aW9uPEF0dHJOYW1lc3BhY2U+KTogdm9pZCB7XG4gICAgbGV0IHVubWF0Y2hlZCA9IHRoaXMudW5tYXRjaGVkQXR0cmlidXRlcztcblxuICAgIGlmICh1bm1hdGNoZWQpIHtcbiAgICAgIGxldCBhdHRyID0gZmluZEJ5TmFtZSh1bm1hdGNoZWQsIG5hbWUpO1xuICAgICAgaWYgKGF0dHIpIHtcbiAgICAgICAgaWYgKGF0dHIudmFsdWUgIT09IHZhbHVlKSB7XG4gICAgICAgICAgYXR0ci52YWx1ZSA9IHZhbHVlO1xuICAgICAgICB9XG4gICAgICAgIHVubWF0Y2hlZC5zcGxpY2UodW5tYXRjaGVkLmluZGV4T2YoYXR0ciksIDEpO1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIHN1cGVyLl9fc2V0QXR0cmlidXRlKG5hbWUsIHZhbHVlLCBuYW1lc3BhY2UpO1xuICB9XG5cbiAgX19zZXRQcm9wZXJ0eShuYW1lOiBzdHJpbmcsIHZhbHVlOiBzdHJpbmcpOiB2b2lkIHtcbiAgICBsZXQgdW5tYXRjaGVkID0gdGhpcy51bm1hdGNoZWRBdHRyaWJ1dGVzO1xuXG4gICAgaWYgKHVubWF0Y2hlZCkge1xuICAgICAgbGV0IGF0dHIgPSBmaW5kQnlOYW1lKHVubWF0Y2hlZCwgbmFtZSk7XG4gICAgICBpZiAoYXR0cikge1xuICAgICAgICBpZiAoYXR0ci52YWx1ZSAhPT0gdmFsdWUpIHtcbiAgICAgICAgICBhdHRyLnZhbHVlID0gdmFsdWU7XG4gICAgICAgIH1cbiAgICAgICAgdW5tYXRjaGVkLnNwbGljZSh1bm1hdGNoZWQuaW5kZXhPZihhdHRyKSwgMSk7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4gc3VwZXIuX19zZXRQcm9wZXJ0eShuYW1lLCB2YWx1ZSk7XG4gIH1cblxuICBfX2ZsdXNoRWxlbWVudChwYXJlbnQ6IFNpbXBsZUVsZW1lbnQsIGNvbnN0cnVjdGluZzogU2ltcGxlRWxlbWVudCk6IHZvaWQge1xuICAgIGxldCB7IHVubWF0Y2hlZEF0dHJpYnV0ZXM6IHVubWF0Y2hlZCB9ID0gdGhpcztcbiAgICBpZiAodW5tYXRjaGVkKSB7XG4gICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHVubWF0Y2hlZC5sZW5ndGg7IGkrKykge1xuICAgICAgICB0aGlzLmNvbnN0cnVjdGluZyEucmVtb3ZlQXR0cmlidXRlKHVubWF0Y2hlZFtpXS5uYW1lKTtcbiAgICAgIH1cbiAgICAgIHRoaXMudW5tYXRjaGVkQXR0cmlidXRlcyA9IG51bGw7XG4gICAgfSBlbHNlIHtcbiAgICAgIHN1cGVyLl9fZmx1c2hFbGVtZW50KHBhcmVudCwgY29uc3RydWN0aW5nKTtcbiAgICB9XG4gIH1cblxuICB3aWxsQ2xvc2VFbGVtZW50KCkge1xuICAgIGxldCB7IGNhbmRpZGF0ZSwgY3VycmVudEN1cnNvciB9ID0gdGhpcztcblxuICAgIGlmIChjYW5kaWRhdGUgIT09IG51bGwpIHtcbiAgICAgIHRoaXMuY2xlYXJNaXNtYXRjaChjYW5kaWRhdGUpO1xuICAgIH1cblxuICAgIGlmIChjdXJyZW50Q3Vyc29yICYmIGN1cnJlbnRDdXJzb3IuaW5qZWN0ZWRPbWl0dGVkTm9kZSkge1xuICAgICAgdGhpcy5wb3BFbGVtZW50KCk7XG4gICAgfVxuXG4gICAgc3VwZXIud2lsbENsb3NlRWxlbWVudCgpO1xuICB9XG5cbiAgZ2V0TWFya2VyKGVsZW1lbnQ6IEhUTUxFbGVtZW50LCBndWlkOiBzdHJpbmcpOiBPcHRpb248U2ltcGxlTm9kZT4ge1xuICAgIGxldCBtYXJrZXIgPSBlbGVtZW50LnF1ZXJ5U2VsZWN0b3IoYHNjcmlwdFtnbG1yPVwiJHtndWlkfVwiXWApO1xuICAgIGlmIChtYXJrZXIpIHtcbiAgICAgIHJldHVybiBjYXN0VG9TaW1wbGUobWFya2VyKTtcbiAgICB9XG4gICAgcmV0dXJuIG51bGw7XG4gIH1cblxuICBfX3B1c2hSZW1vdGVFbGVtZW50KFxuICAgIGVsZW1lbnQ6IFNpbXBsZUVsZW1lbnQsXG4gICAgY3Vyc29ySWQ6IHN0cmluZyxcbiAgICBpbnNlcnRCZWZvcmU6IE1heWJlPFNpbXBsZU5vZGU+XG4gICk6IE9wdGlvbjxSZW1vdGVMaXZlQmxvY2s+IHtcbiAgICBsZXQgbWFya2VyID0gdGhpcy5nZXRNYXJrZXIoY2FzdFRvQnJvd3NlcihlbGVtZW50LCAnSFRNTCcpLCBjdXJzb3JJZCk7XG5cbiAgICBhc3NlcnQoXG4gICAgICAhbWFya2VyIHx8IG1hcmtlci5wYXJlbnROb2RlID09PSBlbGVtZW50LFxuICAgICAgYGV4cGVjdGVkIHJlbW90ZSBlbGVtZW50IG1hcmtlcidzIHBhcmVudCBub2RlIHRvIG1hdGNoIHJlbW90ZSBlbGVtZW50YFxuICAgICk7XG5cbiAgICA