@glimmer/runtime
Version:
Minimal runtime needed to render Glimmer templates
534 lines (431 loc) • 53.6 kB
JavaScript
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,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3BhY2thZ2VzL0BnbGltbWVyL3J1bnRpbWUvbGliL3ZtL3JlaHlkcmF0ZS1idWlsZGVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUNBLFNBQVMsTUFBVCxRQUFtRSxlQUFuRTtBQVdBLFNBQVMsY0FBVCxFQUF5QixVQUF6QixRQUEyQyxXQUEzQztBQUNBLFNBQVMsWUFBVCxFQUF1QixpQkFBdkIsRUFBMEMsZUFBMUMsUUFBaUUsbUJBQWpFO0FBRUEsT0FBTyxNQUFNLCtCQUErQixHQUFHLFFBQXhDO0FBRVAsT0FBTSxTQUFVLHdCQUFWLENBQW1DLElBQW5DLEVBQW1EO0FBQ3ZELFNBQU8sSUFBSSxDQUFDLFNBQUwsS0FBbUIsK0JBQTFCO0FBQ0Q7QUFFRCxPQUFNLE1BQU8saUJBQVAsU0FBaUMsVUFBakMsQ0FBMkM7QUFJL0MsRUFBQSxXQUFBLENBQ0UsT0FERixFQUVFLFdBRkYsRUFHa0Isa0JBSGxCLEVBRzRDO0FBRTFDLFVBQU0sT0FBTixFQUFlLFdBQWY7QUFGZ0IsU0FBQSxrQkFBQSxHQUFBLGtCQUFBO0FBTmxCLFNBQUEsU0FBQSxHQUFnQyxJQUFoQztBQUVBLFNBQUEsbUJBQUEsR0FBc0IsS0FBdEI7QUFPRSxTQUFLLGNBQUwsR0FBc0Isa0JBQWtCLEdBQUcsQ0FBM0M7QUFDRDs7QUFYOEM7QUFjakQsT0FBTSxNQUFPLGdCQUFQLFNBQWdDLGlCQUFoQyxDQUFpRDtBQU1yRCxFQUFBLFdBQUEsQ0FBWSxHQUFaLEVBQThCLFVBQTlCLEVBQXlELFdBQXpELEVBQXdGO0FBQ3RGLFVBQU0sR0FBTixFQUFXLFVBQVgsRUFBdUIsV0FBdkI7QUFOTSxTQUFBLG1CQUFBLEdBQTRDLElBQTVDO0FBRVIsU0FBQSxVQUFBLEdBQWEsQ0FBYjtBQUtFLFFBQUksV0FBSixFQUFpQixNQUFNLElBQUksS0FBSixDQUFVLDRDQUFWLENBQU47QUFFakIsUUFBSSxJQUFJLEdBQUcsS0FBSyxhQUFMLENBQW9CLE9BQXBCLENBQTRCLFVBQXZDOztBQUVBLFdBQU8sSUFBSSxLQUFLLElBQWhCLEVBQXNCO0FBQ3BCLFVBQUksV0FBVyxDQUFDLElBQUQsQ0FBZixFQUF1QjtBQUNyQjtBQUNEOztBQUNELE1BQUEsSUFBSSxHQUFHLElBQUksQ0FBQyxXQUFaO0FBQ0Q7O0FBWHFGLGNBYXRGLE1BQU0sQ0FBQyxJQUFELEVBQU8sNENBQVAsQ0FiZ0Y7QUFjdEYsU0FBSyxTQUFMLEdBQWlCLElBQWpCO0FBQ0EsVUFBTSxtQkFBbUIsR0FBRyxhQUFhLENBQUMsSUFBRCxDQUF6Qzs7QUFDQSxRQUFJLG1CQUFtQixLQUFLLENBQTVCLEVBQStCO0FBQzdCO0FBQ0E7QUFDQTtBQUNBLFlBQU0sYUFBYSxHQUFHLG1CQUFtQixHQUFHLENBQTVDO0FBQ0EsWUFBTSxZQUFZLEdBQUcsS0FBSyxHQUFMLENBQVMsYUFBVCxDQUF1QixPQUFPLGFBQWEsR0FBM0MsQ0FBckI7QUFFQSxNQUFBLElBQUssQ0FBQyxVQUFOLENBQWtCLFlBQWxCLENBQStCLFlBQS9CLEVBQTZDLEtBQUssU0FBbEQ7QUFDQSxVQUFJLFdBQVcsR0FBRyxJQUFLLENBQUMsV0FBeEI7O0FBQ0EsYUFBTyxXQUFXLEtBQUssSUFBdkIsRUFBNkI7QUFDM0IsWUFBSSxZQUFZLENBQUMsV0FBRCxDQUFaLElBQTZCLGFBQWEsQ0FBQyxXQUFELENBQWIsS0FBK0IsbUJBQWhFLEVBQXFGO0FBQ25GO0FBQ0Q7O0FBQ0QsUUFBQSxXQUFXLEdBQUcsV0FBVyxDQUFDLFdBQTFCO0FBQ0Q7O0FBZDRCLGdCQWdCN0IsTUFBTSxDQUFDLFdBQUQsRUFBYyxzREFBZCxDQWhCdUI7QUFpQjdCLFlBQU0sZUFBZSxHQUFHLEtBQUssR0FBTCxDQUFTLGFBQVQsQ0FBdUIsT0FBTyxhQUFhLEdBQTNDLENBQXhCO0FBQ0EsTUFBQSxJQUFLLENBQUMsVUFBTixDQUFrQixZQUFsQixDQUErQixlQUEvQixFQUFnRCxXQUFZLENBQUMsV0FBN0Q7QUFDQSxXQUFLLFNBQUwsR0FBaUIsWUFBakI7QUFDQSxXQUFLLG1CQUFMLEdBQTJCLGFBQTNCO0FBQ0QsS0FyQkQsTUFxQk87QUFDTCxXQUFLLG1CQUFMLEdBQTJCLENBQTNCO0FBQ0Q7QUFDRjs7QUFFRCxNQUFJLGFBQUosR0FBaUI7QUFDZixXQUFPLEtBQUssWUFBTCxFQUFtQixPQUExQjtBQUNEOztBQUVELE1BQUksU0FBSixHQUFhO0FBQ1gsUUFBSSxLQUFLLGFBQVQsRUFBd0I7QUFDdEIsYUFBTyxLQUFLLGFBQUwsQ0FBbUIsU0FBMUI7QUFDRDs7QUFFRCxXQUFPLElBQVA7QUFDRDs7QUFFRCxNQUFJLFNBQUosQ0FBYyxJQUFkLEVBQXNDO0FBQ3BDLFFBQUksYUFBYSxHQUFHLEtBQUssYUFBekI7QUFFQSxJQUFBLGFBQWEsQ0FBQyxTQUFkLEdBQTBCLElBQTFCO0FBQ0Q7O0FBRUQsRUFBQSxrQkFBa0IsQ0FBQyxXQUFELEVBQWdDO0FBQ2hELFFBQUksYUFBYSxHQUFHLEtBQUssYUFBekIsQ0FEZ0QsQ0FHaEQ7QUFDQTtBQUNBO0FBQ0E7O0FBQ0EsSUFBQSxhQUFhLENBQUMsU0FBZCxHQUEwQixJQUExQjtBQUNBLElBQUEsYUFBYSxDQUFDLFdBQWQsR0FBNEIsV0FBNUI7QUFDRDs7QUFFRCxFQUFBLGlCQUFpQixDQUFDLFNBQUQsRUFBOEI7QUFDN0MsUUFBSSxhQUFhLEdBQUcsS0FBSyxhQUF6QjtBQUVBLElBQUEsYUFBYSxDQUFDLFNBQWQsR0FBMEIsU0FBMUI7QUFDQSxJQUFBLGFBQWEsQ0FBQyxXQUFkLEdBQTRCLElBQTVCO0FBQ0Q7O0FBRUQsRUFBQSxXQUFXLENBS1QsT0FMUyxFQU1ULFdBQUEsR0FBaUMsSUFOeEIsRUFNNEI7QUFFckMsUUFBSSxNQUFNLEdBQUcsSUFBSSxpQkFBSixDQUFzQixPQUF0QixFQUErQixXQUEvQixFQUE0QyxLQUFLLFVBQUwsSUFBbUIsQ0FBL0QsQ0FBYjtBQUVBOzs7Ozs7Ozs7OztBQVVBLFFBQUksS0FBSyxTQUFMLEtBQW1CLElBQXZCLEVBQTZCO0FBQzNCLE1BQUEsTUFBTSxDQUFDLFNBQVAsR0FBbUIsT0FBTyxDQUFDLFVBQTNCO0FBQ0EsV0FBSyxTQUFMLEdBQWlCLE9BQU8sQ0FBQyxXQUF6QjtBQUNEOztBQUVELFNBQUssWUFBTCxFQUFtQixJQUFuQixDQUF3QixNQUF4QjtBQUNELEdBOUdvRCxDQWdIckQ7QUFDQTs7O0FBQ1EsRUFBQSxhQUFhLENBQUMsU0FBRCxFQUFzQjtBQUN6QyxRQUFJLE9BQU8sR0FBdUIsU0FBbEM7QUFDQSxRQUFJLGFBQWEsR0FBRyxLQUFLLGFBQXpCOztBQUNBLFFBQUksYUFBYSxLQUFLLElBQXRCLEVBQTRCO0FBQzFCLFVBQUksY0FBYyxHQUFHLGFBQWEsQ0FBQyxjQUFuQzs7QUFDQSxVQUFJLGNBQWMsSUFBSSxhQUFhLENBQUMsa0JBQXBDLEVBQXdEO0FBQ3RELGVBQU8sT0FBUCxFQUFnQjtBQUNkLGNBQUksWUFBWSxDQUFDLE9BQUQsQ0FBaEIsRUFBMkI7QUFDekIsZ0JBQUksZUFBZSxHQUFHLHVCQUF1QixDQUFDLE9BQUQsRUFBVSxLQUFLLG1CQUFmLENBQTdDOztBQUNBLGdCQUFJLGNBQWMsSUFBSSxlQUF0QixFQUF1QztBQUNyQztBQUNEO0FBQ0Y7O0FBQ0QsVUFBQSxPQUFPLEdBQUcsS0FBSyxNQUFMLENBQVksT0FBWixDQUFWO0FBQ0Q7QUFDRixPQVZELE1BVU87QUFDTCxlQUFPLE9BQU8sS0FBSyxJQUFuQixFQUF5QjtBQUN2QixVQUFBLE9BQU8sR0FBRyxLQUFLLE1BQUwsQ0FBWSxPQUFaLENBQVY7QUFDRDtBQUNGLE9BaEJ5QixDQWlCMUI7QUFDQTs7O0FBQ0EsV0FBSyxrQkFBTCxDQUF3QixPQUF4QjtBQUNEO0FBQ0Y7O0FBRUQsRUFBQSxXQUFXLEdBQUE7QUFDVCxRQUFJO0FBQUUsTUFBQTtBQUFGLFFBQW9CLElBQXhCO0FBQ0EsUUFBSSxhQUFhLEtBQUssSUFBdEIsRUFBNEI7QUFFNUIsUUFBSSxVQUFVLEdBQUcsS0FBSyxVQUF0QjtBQUVBLFNBQUssVUFBTDtBQUVBLFFBQUk7QUFBRSxNQUFBO0FBQUYsUUFBZ0IsYUFBcEI7QUFDQSxRQUFJLFNBQVMsS0FBSyxJQUFsQixFQUF3QjtBQUV4QixRQUFJO0FBQUUsTUFBQTtBQUFGLFFBQWMsYUFBYSxDQUFDLE9BQWhDOztBQUVBLFFBQ0UsV0FBVyxDQUFDLFNBQUQsQ0FBWCxJQUNBLHVCQUF1QixDQUFDLFNBQUQsRUFBWSxLQUFLLG1CQUFqQixDQUF2QixLQUFpRSxVQUZuRSxFQUdFO0FBQ0EsV0FBSyxTQUFMLEdBQWlCLEtBQUssTUFBTCxDQUFZLFNBQVosQ0FBakI7QUFDQSxNQUFBLGFBQWEsQ0FBQyxjQUFkLEdBQStCLFVBQS9CO0FBQ0QsS0FORCxNQU1PLElBQUksT0FBTyxLQUFLLE9BQVosSUFBdUIsT0FBTyxLQUFLLFFBQW5DLElBQStDLE9BQU8sS0FBSyxPQUEvRCxFQUF3RTtBQUM3RSxXQUFLLGFBQUwsQ0FBbUIsU0FBbkI7QUFDRDtBQUNGOztBQUVELEVBQUEsWUFBWSxHQUFBO0FBQ1YsUUFBSTtBQUFFLE1BQUE7QUFBRixRQUFvQixJQUF4QjtBQUNBLFFBQUksYUFBYSxLQUFLLElBQXRCLEVBQTRCLE9BRmxCLENBSVY7O0FBQ0EsUUFBSSxjQUFjLEdBQUcsYUFBYSxDQUFDLGNBQW5DLENBTFUsQ0FPVjs7QUFDQSxTQUFLLFVBQUw7QUFFQSxRQUFJO0FBQUUsTUFBQTtBQUFGLFFBQWdCLGFBQXBCO0FBRUEsUUFBSSxhQUFhLEdBQUcsS0FBcEI7O0FBRUEsUUFBSSxTQUFTLEtBQUssSUFBbEIsRUFBd0I7QUFDdEIsTUFBQSxhQUFhLEdBQUcsSUFBaEIsQ0FEc0IsQ0FFdEI7QUFDQTtBQUNBO0FBQ0E7O0FBRUEsVUFDRSxZQUFZLENBQUMsU0FBRCxDQUFaLElBQ0EsdUJBQXVCLENBQUMsU0FBRCxFQUFZLEtBQUssbUJBQWpCLENBQXZCLEtBQWlFLGNBRm5FLEVBR0U7QUFDQSxZQUFJLFdBQVcsR0FBRyxLQUFLLE1BQUwsQ0FBWSxTQUFaLENBQWxCO0FBQ0EsYUFBSyxTQUFMLEdBQWlCLFdBQWpCO0FBQ0EsUUFBQSxhQUFhLENBQUMsY0FBZDtBQUNELE9BUEQsTUFPTztBQUNMO0FBQ0E7QUFDQTtBQUNBLGFBQUssYUFBTCxDQUFtQixTQUFuQjtBQUNBLFFBQUEsYUFBYSxHQUFHLEtBQWhCO0FBQ0Q7QUFDRjs7QUFFRCxRQUFJLGFBQWEsS0FBSyxLQUF0QixFQUE2QjtBQUMzQjtBQUNBO0FBQ0E7QUFDQSxVQUFJLFdBQVcsR0FBRyxhQUFhLENBQUMsV0FBaEM7O0FBQ0EsVUFDRSxXQUFXLEtBQUssSUFBaEIsSUFDQSxZQUFZLENBQUMsV0FBRCxDQURaLElBRUEsdUJBQXVCLENBQUMsV0FBRCxFQUFjLEtBQUssbUJBQW5CLENBQXZCLEtBQW1FLEtBQUssVUFIMUUsRUFJRTtBQUNBO0FBQ0EsWUFBSSxTQUFTLEdBQUcsS0FBSyxNQUFMLENBQVksV0FBWixDQUFoQjtBQUNBLGFBQUssaUJBQUwsQ0FBdUIsU0FBdkI7QUFFQSxRQUFBLGFBQWEsQ0FBQyxjQUFkO0FBQ0Q7QUFDRjtBQUNGOztBQUVELEVBQUEsWUFBWSxDQUFDLElBQUQsRUFBaUI7QUFDM0IsUUFBSTtBQUFFLE1BQUE7QUFBRixRQUFnQixJQUFwQixDQUQyQixDQUczQjtBQUNBO0FBQ0E7O0FBQ0EsUUFBSSxTQUFKLEVBQWU7QUFDYixhQUFPLFNBQVA7QUFDRCxLQUZELE1BRU87QUFDTCxhQUFPLE1BQU0sWUFBTixDQUFtQixJQUFuQixDQUFQO0FBQ0Q7QUFDRjs7QUFFRCxFQUFBLFlBQVksQ0FBQyxJQUFELEVBQWE7QUFDdkIsUUFBSSxlQUFlLEdBQUcsS0FBSyxZQUFMLEVBQXRCOztBQUVBLFFBQUksZUFBSixFQUFxQjtBQUNuQixVQUFJLEtBQUssR0FBRyxlQUFlLENBQUMsU0FBaEIsRUFBWjtBQUNBLFVBQUksSUFBSSxHQUFHLGVBQWUsQ0FBQyxRQUFoQixFQUFYO0FBRUEsVUFBSSxTQUFTLEdBQUcsSUFBSSxjQUFKLENBQW1CLEtBQUssT0FBeEIsRUFBaUMsS0FBSyxDQUFDLFdBQXZDLEVBQXFELElBQUksQ0FBQyxlQUExRCxDQUFoQjtBQUVBLFVBQUksbUJBQW1CLEdBQUcsS0FBSyxNQUFMLENBQVksS0FBWixDQUExQjtBQUNBLFdBQUssTUFBTCxDQUFZLElBQVo7O0FBRUEsVUFBSSxtQkFBbUIsS0FBSyxJQUF4QixJQUFnQyxPQUFPLENBQUMsbUJBQUQsQ0FBM0MsRUFBa0U7QUFDaEUsYUFBSyxTQUFMLEdBQWlCLEtBQUssTUFBTCxDQUFZLG1CQUFaLENBQWpCOztBQUVBLFlBQUksS0FBSyxTQUFMLEtBQW1CLElBQXZCLEVBQTZCO0FBQzNCLGVBQUssYUFBTCxDQUFtQixLQUFLLFNBQXhCO0FBQ0Q7QUFDRjs7QUFFRCxhQUFPLFNBQVA7QUFDRCxLQWxCRCxNQWtCTztBQUNMLGFBQU8sTUFBTSxZQUFOLENBQW1CLElBQW5CLENBQVA7QUFDRDtBQUNGOztBQUVTLEVBQUEsTUFBTSxDQUFDLElBQUQsRUFBaUI7QUFDL0IsUUFBSSxPQUFPLEdBQVUsSUFBSSxDQUFDLFVBQTFCO0FBQ0EsUUFBSSxJQUFJLEdBQUcsSUFBSSxDQUFDLFdBQWhCO0FBQ0EsSUFBQSxPQUFPLENBQUMsV0FBUixDQUFvQixJQUFwQjtBQUNBLFdBQU8sSUFBUDtBQUNEOztBQUVPLEVBQUEsWUFBWSxHQUFBO0FBQ2xCLFFBQUksVUFBVSxHQUFHLEtBQUssU0FBdEI7O0FBRUEsUUFBSSxVQUFVLElBQUksUUFBUSxDQUFDLFVBQUQsQ0FBMUIsRUFBd0M7QUFDdEMsVUFBSSxLQUFLLEdBQUcsVUFBWjtBQUNBLFVBQUksSUFBSSxHQUFVLEtBQUssQ0FBQyxXQUF4Qjs7QUFFQSxhQUFPLElBQUksSUFBSSxDQUFDLFFBQVEsQ0FBQyxJQUFELENBQXhCLEVBQWdDO0FBQzlCLFFBQUEsSUFBSSxHQUFVLElBQUksQ0FBQyxXQUFuQjtBQUNEOztBQUVELGFBQU8sSUFBSSxjQUFKLENBQW1CLEtBQUssT0FBeEIsRUFBaUMsS0FBakMsRUFBd0MsSUFBeEMsQ0FBUDtBQUNELEtBVEQsTUFTTztBQUNMLGFBQU8sSUFBUDtBQUNEO0FBQ0Y7O0FBRUQsRUFBQSxZQUFZLENBQUMsTUFBRCxFQUFlO0FBQ3pCLFFBQUk7QUFBRSxNQUFBO0FBQUYsUUFBZ0IsSUFBcEI7O0FBRUEsUUFBSSxTQUFKLEVBQWU7QUFDYixVQUFJLFVBQVUsQ0FBQyxTQUFELENBQWQsRUFBMkI7QUFDekIsWUFBSSxTQUFTLENBQUMsU0FBVixLQUF3QixNQUE1QixFQUFvQztBQUNsQyxVQUFBLFNBQVMsQ0FBQyxTQUFWLEdBQXNCLE1BQXRCO0FBQ0Q7O0FBQ0QsYUFBSyxTQUFMLEdBQWlCLFNBQVMsQ0FBQyxXQUEzQjtBQUVBLGVBQU8sU0FBUDtBQUNELE9BUEQsTUFPTyxJQUFJLFdBQVcsQ0FBQyxTQUFELENBQWYsRUFBNEI7QUFDakMsYUFBSyxTQUFMLEdBQWlCLEtBQUssTUFBTCxDQUFZLFNBQVosQ0FBakI7QUFFQSxlQUFPLEtBQUssWUFBTCxDQUFrQixNQUFsQixDQUFQO0FBQ0QsT0FKTSxNQUlBLElBQUksT0FBTyxDQUFDLFNBQUQsQ0FBUCxJQUFzQixNQUFNLEtBQUssRUFBckMsRUFBeUM7QUFDOUMsYUFBSyxTQUFMLEdBQWlCLEtBQUssTUFBTCxDQUFZLFNBQVosQ0FBakI7QUFFQSxlQUFPLEtBQUssWUFBTCxDQUFrQixNQUFsQixDQUFQO0FBQ0QsT0FKTSxNQUlBO0FBQ0wsYUFBSyxhQUFMLENBQW1CLFNBQW5CO0FBRUEsZUFBTyxNQUFNLFlBQU4sQ0FBbUIsTUFBbkIsQ0FBUDtBQUNEO0FBQ0YsS0FyQkQsTUFxQk87QUFDTCxhQUFPLE1BQU0sWUFBTixDQUFtQixNQUFuQixDQUFQO0FBQ0Q7QUFDRjs7QUFFRCxFQUFBLGVBQWUsQ0FBQyxNQUFELEVBQWU7QUFDNUIsUUFBSSxVQUFVLEdBQUcsS0FBSyxTQUF0Qjs7QUFDQSxRQUFJLFVBQVUsSUFBSSxTQUFTLENBQUMsVUFBRCxDQUEzQixFQUF5QztBQUN2QyxVQUFJLFVBQVUsQ0FBQyxTQUFYLEtBQXlCLE1BQTdCLEVBQXFDO0FBQ25DLFFBQUEsVUFBVSxDQUFDLFNBQVgsR0FBdUIsTUFBdkI7QUFDRDs7QUFFRCxXQUFLLFNBQUwsR0FBaUIsVUFBVSxDQUFDLFdBQTVCO0FBQ0EsYUFBTyxVQUFQO0FBQ0QsS0FQRCxNQU9PLElBQUksVUFBSixFQUFnQjtBQUNyQixXQUFLLGFBQUwsQ0FBbUIsVUFBbkI7QUFDRDs7QUFFRCxXQUFPLE1BQU0sZUFBTixDQUFzQixNQUF0QixDQUFQO0FBQ0Q7O0FBRUQsRUFBQSxhQUFhLENBQUMsR0FBRCxFQUFZO0FBQ3ZCLFFBQUksVUFBVSxHQUFHLEtBQUssU0FBdEI7O0FBRUEsUUFBSSxVQUFVLElBQUksU0FBUyxDQUFDLFVBQUQsQ0FBdkIsSUFBdUMsY0FBYyxDQUFDLFVBQUQsRUFBYSxHQUFiLENBQXpELEVBQTRFO0FBQzFFLFdBQUssbUJBQUwsR0FBMkIsR0FBRyxLQUFILENBQVMsSUFBVCxDQUFjLFVBQVUsQ0FBQyxVQUF6QixDQUEzQjtBQUNBLGFBQU8sVUFBUDtBQUNELEtBSEQsTUFHTyxJQUFJLFVBQUosRUFBZ0I7QUFDckIsVUFBSSxTQUFTLENBQUMsVUFBRCxDQUFULElBQXlCLFVBQVUsQ0FBQyxPQUFYLEtBQXVCLE9BQXBELEVBQTZEO0FBQzNELGFBQUssV0FBTCxDQUFpQixVQUFqQixFQUE2QixJQUE3QjtBQUNBLGFBQUssYUFBTCxDQUFvQixtQkFBcEIsR0FBMEMsSUFBMUM7QUFDQSxlQUFPLEtBQUssYUFBTCxDQUFtQixHQUFuQixDQUFQO0FBQ0Q7O0FBQ0QsV0FBSyxhQUFMLENBQW1CLFVBQW5CO0FBQ0Q7O0FBRUQsV0FBTyxNQUFNLGFBQU4sQ0FBb0IsR0FBcEIsQ0FBUDtBQUNEOztBQUVELEVBQUEsY0FBYyxDQUFDLElBQUQsRUFBZSxLQUFmLEVBQThCLFNBQTlCLEVBQThEO0FBQzFFLFFBQUksU0FBUyxHQUFHLEtBQUssbUJBQXJCOztBQUVBLFFBQUksU0FBSixFQUFlO0FBQ2IsVUFBSSxJQUFJLEdBQUcsVUFBVSxDQUFDLFNBQUQsRUFBWSxJQUFaLENBQXJCOztBQUNBLFVBQUksSUFBSixFQUFVO0FBQ1IsWUFBSSxJQUFJLENBQUMsS0FBTCxLQUFlLEtBQW5CLEVBQTBCO0FBQ3hCLFVBQUEsSUFBSSxDQUFDLEtBQUwsR0FBYSxLQUFiO0FBQ0Q7O0FBQ0QsUUFBQSxTQUFTLENBQUMsTUFBVixDQUFpQixTQUFTLENBQUMsT0FBVixDQUFrQixJQUFsQixDQUFqQixFQUEwQyxDQUExQztBQUNBO0FBQ0Q7QUFDRjs7QUFFRCxXQUFPLE1BQU0sY0FBTixDQUFxQixJQUFyQixFQUEyQixLQUEzQixFQUFrQyxTQUFsQyxDQUFQO0FBQ0Q7O0FBRUQsRUFBQSxhQUFhLENBQUMsSUFBRCxFQUFlLEtBQWYsRUFBNEI7QUFDdkMsUUFBSSxTQUFTLEdBQUcsS0FBSyxtQkFBckI7O0FBRUEsUUFBSSxTQUFKLEVBQWU7QUFDYixVQUFJLElBQUksR0FBRyxVQUFVLENBQUMsU0FBRCxFQUFZLElBQVosQ0FBckI7O0FBQ0EsVUFBSSxJQUFKLEVBQVU7QUFDUixZQUFJLElBQUksQ0FBQyxLQUFMLEtBQWUsS0FBbkIsRUFBMEI7QUFDeEIsVUFBQSxJQUFJLENBQUMsS0FBTCxHQUFhLEtBQWI7QUFDRDs7QUFDRCxRQUFBLFNBQVMsQ0FBQyxNQUFWLENBQWlCLFNBQVMsQ0FBQyxPQUFWLENBQWtCLElBQWxCLENBQWpCLEVBQTBDLENBQTFDO0FBQ0E7QUFDRDtBQUNGOztBQUVELFdBQU8sTUFBTSxhQUFOLENBQW9CLElBQXBCLEVBQTBCLEtBQTFCLENBQVA7QUFDRDs7QUFFRCxFQUFBLGNBQWMsQ0FBQyxNQUFELEVBQXdCLFlBQXhCLEVBQW1EO0FBQy9ELFFBQUk7QUFBRSxNQUFBLG1CQUFtQixFQUFFO0FBQXZCLFFBQXFDLElBQXpDOztBQUNBLFFBQUksU0FBSixFQUFlO0FBQ2IsV0FBSyxJQUFJLENBQUMsR0FBRyxDQUFiLEVBQWdCLENBQUMsR0FBRyxTQUFTLENBQUMsTUFBOUIsRUFBc0MsQ0FBQyxFQUF2QyxFQUEyQztBQUN6QyxhQUFLLFlBQUwsQ0FBbUIsZUFBbkIsQ0FBbUMsU0FBUyxDQUFDLENBQUQsQ0FBVCxDQUFhLElBQWhEO0FBQ0Q7O0FBQ0QsV0FBSyxtQkFBTCxHQUEyQixJQUEzQjtBQUNELEtBTEQsTUFLTztBQUNMLFlBQU0sY0FBTixDQUFxQixNQUFyQixFQUE2QixZQUE3QjtBQUNEO0FBQ0Y7O0FBRUQsRUFBQSxnQkFBZ0IsR0FBQTtBQUNkLFFBQUk7QUFBRSxNQUFBLFNBQUY7QUFBYSxNQUFBO0FBQWIsUUFBK0IsSUFBbkM7O0FBRUEsUUFBSSxTQUFTLEtBQUssSUFBbEIsRUFBd0I7QUFDdEIsV0FBSyxhQUFMLENBQW1CLFNBQW5CO0FBQ0Q7O0FBRUQsUUFBSSxhQUFhLElBQUksYUFBYSxDQUFDLG1CQUFuQyxFQUF3RDtBQUN0RCxXQUFLLFVBQUw7QUFDRDs7QUFFRCxVQUFNLGdCQUFOO0FBQ0Q7O0FBRUQsRUFBQSxTQUFTLENBQUMsT0FBRCxFQUF1QixJQUF2QixFQUFtQztBQUMxQyxRQUFJLE1BQU0sR0FBRyxPQUFPLENBQUMsYUFBUixDQUFzQixnQkFBZ0IsSUFBSSxJQUExQyxDQUFiOztBQUNBLFFBQUksTUFBSixFQUFZO0FBQ1YsYUFBb0IsTUFBcEI7QUFDRDs7QUFDRCxXQUFPLElBQVA7QUFDRDs7QUFFRCxFQUFBLG1CQUFtQixDQUNqQixPQURpQixFQUVqQixRQUZpQixFQUdqQixZQUhpQixFQUdjO0FBRS9CLFFBQUksTUFBTSxHQUFHLEtBQUssU0FBTCxDQUE2QixPQUE3QixFQUErQyxRQUEvQyxDQUFiO0FBRitCLGNBSS9CLE1BQU0sQ0FDSixDQUFDLE1BQUQsSUFBVyxNQUFNLENBQUMsVUFBUCxLQUFzQixPQUQ3QixFQUVKLHNFQUZJLENBSnlCLEdBUy9COztBQUNBLFFBQUksWUFBWSxLQUFLLFNBQXJCLEVBQWdDO0FBQzlCLGFBQU8sT0FBTyxDQUFDLFVBQVIsS0FBdUIsSUFBdkIsSUFBK0IsT0FBTyxDQUFDLFVBQVIsS0FBdUIsTUFBN0QsRUFBcUU7QUFDbkUsYUFBSyxNQUFMLENBQVksT0FBTyxDQUFDLFVBQXBCO0FBQ0Q7O0FBQ0QsTUFBQSxZQUFZLEdBQUcsSUFBZjtBQUNEOztBQUVELFFBQUksTUFBTSxHQUFHLElBQUksaUJBQUosQ0FBc0IsT0FBdEIsRUFBK0IsSUFBL0IsRUFBcUMsS0FBSyxVQUExQyxDQUFiO0FBQ0EsU0FBSyxZQUFMLEVBQW1CLElBQW5CLENBQXdCLE1BQXhCOztBQUVBLFFBQUksTUFBTSxLQUFLLElBQWYsRUFBcUI7QUFDbkIsV0FBSyxrQkFBTCxDQUF3QixZQUF4QjtBQUNELEtBRkQsTUFFTztBQUNMLFdBQUssU0FBTCxHQUFpQixLQUFLLE1BQUwsQ0FBWSxNQUFaLENBQWpCO0FBQ0Q7O0FBRUQsUUFBSSxLQUFLLEdBQUcsSUFBSSxlQUFKLENBQW9CLE9BQXBCLENBQVo7QUFDQSxXQUFPLEtBQUssYUFBTCxDQUFtQixLQUFuQixFQUEwQixJQUExQixDQUFQO0FBQ0Q7O0FBRUQsRUFBQSxlQUFlLENBQUMsTUFBRCxFQUFlO0FBQzVCLFVBQU0sZUFBTixDQUFzQixNQUF0Qjs7QUFDQSxRQUFJLEtBQUssU0FBVCxFQUFvQjtBQUNsQixVQUFJLElBQUksR0FBRyxNQUFNLENBQUMsUUFBUCxFQUFYO0FBQ0EsV0FBSyxTQUFMLEdBQWlCLElBQUksSUFBSSxJQUFJLENBQUMsV0FBOUI7QUFDRDs7QUFDRCxXQUFPLE1BQVA7QUFDRDs7QUF0Y29EOztBQXljdkQsU0FBUyxVQUFULENBQW9CLElBQXBCLEVBQW9DO0FBQ2xDLFNBQU8sSUFBSSxDQUFDLFFBQUwsS0FBa0IsQ0FBekI7QUFDRDs7QUFFRCxTQUFTLFNBQVQsQ0FBbUIsSUFBbkIsRUFBbUM7QUFDakMsU0FBTyxJQUFJLENBQUMsUUFBTCxLQUFrQixDQUF6QjtBQUNEOztBQUVELFNBQVMsV0FBVCxDQUFxQixJQUFyQixFQUFxQztBQUNuQyxTQUFPLElBQUksQ0FBQyxRQUFMLEtBQWE7QUFBQTtBQUFiLEtBQTJDLElBQUksQ0FBQyxTQUFMLENBQWUsV0FBZixDQUEyQixNQUEzQixFQUFtQyxDQUFuQyxNQUEwQyxDQUE1RjtBQUNEOztBQUVELFNBQVMsWUFBVCxDQUFzQixJQUF0QixFQUFzQztBQUNwQyxTQUFPLElBQUksQ0FBQyxRQUFMLEtBQWE7QUFBQTtBQUFiLEtBQTJDLElBQUksQ0FBQyxTQUFMLENBQWUsV0FBZixDQUEyQixNQUEzQixFQUFtQyxDQUFuQyxNQUEwQyxDQUE1RjtBQUNEOztBQUVELFNBQVMsYUFBVCxDQUF1QixJQUF2QixFQUEwQztBQUN4QyxTQUFPLFFBQVEsQ0FBQyxJQUFJLENBQUMsU0FBTCxDQUFlLEtBQWYsQ0FBcUIsQ0FBckIsQ0FBRCxFQUEwQixFQUExQixDQUFmO0FBQ0Q7O0FBRUQsU0FBUyx1QkFBVCxDQUFpQyxJQUFqQyxFQUFzRCxNQUF0RCxFQUFvRTtBQUNsRSxTQUFPLGFBQWEsQ0FBQyxJQUFELENBQWIsR0FBc0IsTUFBN0I7QUFDRDs7QUFFRCxTQUFTLFNBQVQsQ0FBbUIsSUFBbkIsRUFBbUM7QUFDakMsU0FBTyxJQUFJLENBQUMsUUFBTCxLQUFrQixDQUF6QjtBQUNEOztBQUVELFNBQVMsUUFBVCxDQUFrQixJQUFsQixFQUFrQztBQUNoQyxTQUFPLElBQUksQ0FBQyxRQUFMLEtBQWtCLENBQWxCLElBQXVCLElBQUksQ0FBQyxTQUFMLEtBQW1CLFFBQWpEO0FBQ0Q7O0FBRUQsU0FBUyxXQUFULENBQXFCLElBQXJCLEVBQXFDO0FBQ25DLFNBQU8sSUFBSSxDQUFDLFFBQUwsS0FBa0IsQ0FBbEIsSUFBdUIsSUFBSSxDQUFDLFNBQUwsS0FBbUIsS0FBakQ7QUFDRDs7QUFFRCxTQUFTLE9BQVQsQ0FBaUIsSUFBakIsRUFBaUM7QUFDL0IsU0FBTyxJQUFJLENBQUMsUUFBTCxLQUFrQixDQUFsQixJQUF1QixJQUFJLENBQUMsU0FBTCxLQUFtQixLQUFqRDtBQUNEOztBQUVELFNBQVMsY0FBVCxDQUF3QixTQUF4QixFQUFrRCxHQUFsRCxFQUE2RDtBQUMzRCxNQUFJLFNBQVMsQ0FBQyxZQUFWLEtBQXNCO0FBQUE7QUFBMUIsSUFBOEM7QUFDNUMsYUFBTyxTQUFTLENBQUMsT0FBVixLQUFzQixHQUE3QjtBQUNEOztBQUNELFNBQU8sU0FBUyxDQUFDLE9BQVYsS0FBc0IsR0FBRyxDQUFDLFdBQUosRUFBN0I7QUFDRDs7QUFFRCxTQUFTLFVBQVQsQ0FBb0IsS0FBcEIsRUFBeUMsSUFBekMsRUFBcUQ7QUFDbkQsT0FBSyxJQUFJLENBQUMsR0FBRyxDQUFiLEVBQWdCLENBQUMsR0FBRyxLQUFLLENBQUMsTUFBMUIsRUFBa0MsQ0FBQyxFQUFuQyxFQUF1QztBQUNyQyxRQUFJLElBQUksR0FBRyxLQUFLLENBQUMsQ0FBRCxDQUFoQjtBQUNBLFFBQUksSUFBSSxDQUFDLElBQUwsS0FBYyxJQUFsQixFQUF3QixPQUFPLElBQVA7QUFDekI7O0FBRUQsU0FBTyxTQUFQO0FBQ0Q7O0FBRUQsT0FBTSxTQUFVLGtCQUFWLENBQTZCLEdBQTdCLEVBQStDLE1BQS9DLEVBQWlFO0FBQ3JFLFNBQU8sZ0JBQWdCLENBQUMsZ0JBQWpCLENBQWtDLEdBQWxDLEVBQXVDLE1BQXZDLENBQVA7QUFDRCIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IEJvdW5kcywgRWxlbWVudEJ1aWxkZXIsIEVudmlyb25tZW50LCBPcHRpb24sIE1heWJlIH0gZnJvbSAnQGdsaW1tZXIvaW50ZXJmYWNlcyc7XG5pbXBvcnQgeyBhc3NlcnQsIGNhc3RUb0Jyb3dzZXIsIGNhc3RUb1NpbXBsZSwgZXhwZWN0LCBTdGFjayB9IGZyb20gJ0BnbGltbWVyL3V0aWwnO1xuaW1wb3J0IHtcbiAgQXR0ck5hbWVzcGFjZSxcbiAgTmFtZXNwYWNlLFxuICBOb2RlVHlwZSxcbiAgU2ltcGxlQXR0cixcbiAgU2ltcGxlQ29tbWVudCxcbiAgU2ltcGxlRWxlbWVudCxcbiAgU2ltcGxlTm9kZSxcbiAgU2ltcGxlVGV4dCxcbn0gZnJvbSAnQHNpbXBsZS1kb20vaW50ZXJmYWNlJztcbmltcG9ydCB7IENvbmNyZXRlQm91bmRzLCBDdXJzb3JJbXBsIH0gZnJvbSAnLi4vYm91bmRzJztcbmltcG9ydCB7IENVUlNPUl9TVEFDSywgTmV3RWxlbWVudEJ1aWxkZXIsIFJlbW90ZUxpdmVCbG9jayB9IGZyb20gJy4vZWxlbWVudC1idWlsZGVyJztcblxuZXhwb3J0IGNvbnN0IFNFUklBTElaQVRJT05fRklSU1RfTk9ERV9TVFJJTkcgPSAnJStiOjAlJztcblxuZXhwb3J0IGZ1bmN0aW9uIGlzU2VyaWFsaXphdGlvbkZpcnN0Tm9kZShub2RlOiBTaW1wbGVOb2RlKTogYm9vbGVhbiB7XG4gIHJldHVybiBub2RlLm5vZGVWYWx1ZSA9PT0gU0VSSUFMSVpBVElPTl9GSVJTVF9OT0RFX1NUUklORztcbn1cblxuZXhwb3J0IGNsYXNzIFJlaHlkcmF0aW5nQ3Vyc29yIGV4dGVuZHMgQ3Vyc29ySW1wbCB7XG4gIGNhbmRpZGF0ZTogT3B0aW9uPFNpbXBsZU5vZGU+ID0gbnVsbDtcbiAgb3BlbkJsb2NrRGVwdGg6IG51bWJlcjtcbiAgaW5qZWN0ZWRPbWl0dGVkTm9kZSA9IGZhbHNlO1xuICBjb25zdHJ1Y3RvcihcbiAgICBlbGVtZW50OiBTaW1wbGVFbGVtZW50LFxuICAgIG5leHRTaWJsaW5nOiBPcHRpb248U2ltcGxlTm9kZT4sXG4gICAgcHVibGljIHJlYWRvbmx5IHN0YXJ0aW5nQmxvY2tEZXB0aDogbnVtYmVyXG4gICkge1xuICAgIHN1cGVyKGVsZW1lbnQsIG5leHRTaWJsaW5nKTtcbiAgICB0aGlzLm9wZW5CbG9ja0RlcHRoID0gc3RhcnRpbmdCbG9ja0RlcHRoIC0gMTtcbiAgfVxufVxuXG5leHBvcnQgY2xhc3MgUmVoeWRyYXRlQnVpbGRlciBleHRlbmRzIE5ld0VsZW1lbnRCdWlsZGVyIGltcGxlbWVudHMgRWxlbWVudEJ1aWxkZXIge1xuICBwcml2YXRlIHVubWF0Y2hlZEF0dHJpYnV0ZXM6IE9wdGlvbjxTaW1wbGVBdHRyW10+ID0gbnVsbDtcbiAgW0NVUlNPUl9TVEFDS10hOiBTdGFjazxSZWh5ZHJhdGluZ0N1cnNvcj47IC8vIEhpZGVzIHByb3BlcnR5IG9uIGJhc2UgY2xhc3NcbiAgYmxvY2tEZXB0aCA9IDA7XG4gIHN0YXJ0aW5nQmxvY2tPZmZzZXQ6IG51bWJlcjtcblxuICBjb25zdHJ1Y3RvcihlbnY6IEVudmlyb25tZW50LCBwYXJlbnROb2RlOiBTaW1wbGVFbGVtZW50LCBuZXh0U2libGluZzogT3B0aW9uPFNpbXBsZU5vZGU+KSB7XG4gICAgc3VwZXIoZW52LCBwYXJlbnROb2RlLCBuZXh0U2libGluZyk7XG4gICAgaWYgKG5leHRTaWJsaW5nKSB0aHJvdyBuZXcgRXJyb3IoJ1JlaHlkcmF0aW9uIHdpdGggbmV4dFNpYmxpbmcgbm90IHN1cHBvcnRlZCcpO1xuXG4gICAgbGV0IG5vZGUgPSB0aGlzLmN1cnJlbnRDdXJzb3IhLmVsZW1lbnQuZmlyc3RDaGlsZDtcblxuICAgIHdoaWxlIChub2RlICE9PSBudWxsKSB7XG4gICAgICBpZiAoaXNPcGVuQmxvY2sobm9kZSkpIHtcbiAgICAgICAgYnJlYWs7XG4gICAgICB9XG4gICAgICBub2RlID0gbm9kZS5uZXh0U2libGluZztcbiAgICB9XG5cbiAgICBhc3NlcnQobm9kZSwgJ011c3QgaGF2ZSBvcGVuaW5nIGNvbW1lbnQgZm9yIHJlaHlkcmF0aW9uLicpO1xuICAgIHRoaXMuY2FuZGlkYXRlID0gbm9kZTtcbiAgICBjb25zdCBzdGFydGluZ0Jsb2NrT2Zmc2V0ID0gZ2V0QmxvY2tEZXB0aChub2RlIGFzIFNpbXBsZUNvbW1lbnQpO1xuICAgIGlmIChzdGFydGluZ0Jsb2NrT2Zmc2V0ICE9PSAwKSB7XG4gICAgICAvLyBXZSBhcmUgcmVoeWRyYXRpbmcgZnJvbSBhIHBhcnRpYWwgdHJlZSBhbmQgbm90IHRoZSByb290IGNvbXBvbmVudFxuICAgICAgLy8gV2UgbmVlZCB0byBhZGQgYW4gZXh0cmEgYmxvY2sgYmVmb3JlIHRoZSBmaXJzdCBibG9jayB0byByZWh5ZHJhdGUgY29ycmVjdGx5XG4gICAgICAvLyBUaGUgZXh0cmEgYmxvY2sgaXMgbmVlZGVkIHNpbmNlIHRoZSByZW5kZXJDb21wb25lbnQgQVBJIGNyZWF0ZXMgYSBzeW50aGV0aWMgY29tcG9uZW50IGludm9jYXRpb24gd2hpY2ggZ2VuZXJhdGVzIHRoZSBleHRyYSBibG9ja1xuICAgICAgY29uc3QgbmV3QmxvY2tEZXB0aCA9IHN0YXJ0aW5nQmxvY2tPZmZzZXQgLSAxO1xuICAgICAgY29uc3QgbmV3Q2FuZGlkYXRlID0gdGhpcy5kb20uY3JlYXRlQ29tbWVudChgJStiOiR7bmV3QmxvY2tEZXB0aH0lYCk7XG5cbiAgICAgIG5vZGUhLnBhcmVudE5vZGUhLmluc2VydEJlZm9yZShuZXdDYW5kaWRhdGUsIHRoaXMuY2FuZGlkYXRlKTtcbiAgICAgIGxldCBjbG9zaW5nTm9kZSA9IG5vZGUhLm5leHRTaWJsaW5nO1xuICAgICAgd2hpbGUgKGNsb3NpbmdOb2RlICE9PSBudWxsKSB7XG4gICAgICAgIGlmIChpc0Nsb3NlQmxvY2soY2xvc2luZ05vZGUpICYmIGdldEJsb2NrRGVwdGgoY2xvc2luZ05vZGUpID09PSBzdGFydGluZ0Jsb2NrT2Zmc2V0KSB7XG4gICAgICAgICAgYnJlYWs7XG4gICAgICAgIH1cbiAgICAgICAgY2xvc2luZ05vZGUgPSBjbG9zaW5nTm9kZS5uZXh0U2libGluZztcbiAgICAgIH1cblxuICAgICAgYXNzZXJ0KGNsb3NpbmdOb2RlLCAnTXVzdCBoYXZlIGNsb3NpbmcgY29tbWVudCBmb3Igc3RhcnRpbmcgYmxvY2sgY29tbWVudCcpO1xuICAgICAgY29uc3QgbmV3Q2xvc2luZ0Jsb2NrID0gdGhpcy5kb20uY3JlYXRlQ29tbWVudChgJS1iOiR7bmV3QmxvY2tEZXB0aH0lYCk7XG4gICAgICBub2RlIS5wYXJlbnROb2RlIS5pbnNlcnRCZWZvcmUobmV3Q2xvc2luZ0Jsb2NrLCBjbG9zaW5nTm9kZSEubmV4dFNpYmxpbmcpO1xuICAgICAgdGhpcy5jYW5kaWRhdGUgPSBuZXdDYW5kaWRhdGU7XG4gICAgICB0aGlzLnN0YXJ0aW5nQmxvY2tPZmZzZXQgPSBuZXdCbG9ja0RlcHRoO1xuICAgIH0gZWxzZSB7XG4gICAgICB0aGlzLnN0YXJ0aW5nQmxvY2tPZmZzZXQgPSAwO1xuICAgIH1cbiAgfVxuXG4gIGdldCBjdXJyZW50Q3Vyc29yKCk6IE9wdGlvbjxSZWh5ZHJhdGluZ0N1cnNvcj4ge1xuICAgIHJldHVybiB0aGlzW0NVUlNPUl9TVEFDS10uY3VycmVudDtcbiAgfVxuXG4gIGdldCBjYW5kaWRhdGUoKTogT3B0aW9uPFNpbXBsZU5vZGU+IHtcbiAgICBpZiAodGhpcy5jdXJyZW50Q3Vyc29yKSB7XG4gICAgICByZXR1cm4gdGhpcy5jdXJyZW50Q3Vyc29yLmNhbmRpZGF0ZSE7XG4gICAgfVxuXG4gICAgcmV0dXJuIG51bGw7XG4gIH1cblxuICBzZXQgY2FuZGlkYXRlKG5vZGU6IE9wdGlvbjxTaW1wbGVOb2RlPikge1xuICAgIGxldCBjdXJyZW50Q3Vyc29yID0gdGhpcy5jdXJyZW50Q3Vyc29yITtcblxuICAgIGN1cnJlbnRDdXJzb3IuY2FuZGlkYXRlID0gbm9kZTtcbiAgfVxuXG4gIGRpc2FibGVSZWh5ZHJhdGlvbihuZXh0U2libGluZzogT3B0aW9uPFNpbXBsZU5vZGU+KSB7XG4gICAgbGV0IGN1cnJlbnRDdXJzb3IgPSB0aGlzLmN1cnJlbnRDdXJzb3IhO1xuXG4gICAgLy8gcmVoeWRyYXRpb24gd2lsbCBiZSBkaXNhYmxlZCB1bnRpbCB3ZSBlaXRoZXI6XG4gICAgLy8gKiBoaXQgcG9wRWxlbWVudCAoYW5kIHJldHVybiB0byB1c2luZyB0aGUgcGFyZW50IGVsZW1lbnRzIGN1cnNvcilcbiAgICAvLyAqIGhpdCBjbG9zZUJsb2NrIGFuZCB0aGUgbmV4dCBzaWJsaW5nIGlzIGEgY2xvc2UgYmxvY2sgY29tbWVudFxuICAgIC8vICAgbWF0Y2hpbmcgdGhlIGV4cGVjdGVkIG9wZW5CbG9ja0RlcHRoXG4gICAgY3VycmVudEN1cnNvci5jYW5kaWRhdGUgPSBudWxsO1xuICAgIGN1cnJlbnRDdXJzb3IubmV4dFNpYmxpbmcgPSBuZXh0U2libGluZztcbiAgfVxuXG4gIGVuYWJsZVJlaHlkcmF0aW9uKGNhbmRpZGF0ZTogT3B0aW9uPFNpbXBsZU5vZGU+KSB7XG4gICAgbGV0IGN1cnJlbnRDdXJzb3IgPSB0aGlzLmN1cnJlbnRDdXJzb3IhO1xuXG4gICAgY3VycmVudEN1cnNvci5jYW5kaWRhdGUgPSBjYW5kaWRhdGU7XG4gICAgY3VycmVudEN1cnNvci5uZXh0U2libGluZyA9IG51bGw7XG4gIH1cblxuICBwdXNoRWxlbWVudChcbiAgICAvKiogY2FsbGVkIGZyb20gcGFyZW50IGNvbnN0cnVjdG9yIGJlZm9yZSB3ZSBpbml0aWFsaXplIHRoaXMgKi9cbiAgICB0aGlzOlxuICAgICAgfCBSZWh5ZHJhdGVCdWlsZGVyXG4gICAgICB8IChOZXdFbGVtZW50QnVpbGRlciAmIFBhcnRpYWw8UGljazxSZWh5ZHJhdGVCdWlsZGVyLCAnYmxvY2tEZXB0aCcgfCAnY2FuZGlkYXRlJz4+KSxcbiAgICBlbGVtZW50OiBTaW1wbGVFbGVtZW50LFxuICAgIG5leHRTaWJsaW5nOiBNYXliZTxTaW1wbGVOb2RlPiA9IG51bGxcbiAgKSB7XG4gICAgbGV0IGN1cnNvciA9IG5ldyBSZWh5ZHJhdGluZ0N1cnNvcihlbGVtZW50LCBuZXh0U2libGluZywgdGhpcy5ibG9ja0RlcHRoIHx8IDApO1xuXG4gICAgLyoqXG4gICAgICogPGRpdj4gICA8LS0tLS0tLS0tLS0tLS0tICBjdXJyZW50Q3Vyc29yLmVsZW1lbnRcbiAgICAgKiAgIDwhLS0lK2I6MSUtLT4gPC0tLS0tLS0gIHdvdWxkIGhhdmUgYmVlbiByZW1vdmVkIGR1cmluZyBvcGVuQmxvY2tcbiAgICAgKiAgIDxkaXY+IDwtLS0tLS0tLS0tLS0tLS0gIGN1cnJlbnRDdXJzb3IuY2FuZGlkYXRlIC0+IGN1cnNvci5lbGVtZW50XG4gICAgICogICAgIDwhLS0lK2I6MiUtLT4gPC0tLS0tICBjdXJyZW50Q3Vyc29yLmNhbmRpZGF0ZS5maXJzdENoaWxkIC0+IGN1cnNvci5jYW5kaWRhdGVcbiAgICAgKiAgICAgRm9vXG4gICAgICogICAgIDwhLS0lLWI6MiUtLT5cbiAgICAgKiAgIDwvZGl2PlxuICAgICAqICAgPCEtLSUtYjoxJS0tPiAgPC0tLS0tLSAgYmVjb21lcyBjdXJyZW50Q3Vyc29yLmNhbmRpZGF0ZVxuICAgICAqL1xuICAgIGlmICh0aGlzLmNhbmRpZGF0ZSAhPT0gbnVsbCkge1xuICAgICAgY3Vyc29yLmNhbmRpZGF0ZSA9IGVsZW1lbnQuZmlyc3RDaGlsZDtcbiAgICAgIHRoaXMuY2FuZGlkYXRlID0gZWxlbWVudC5uZXh0U2libGluZztcbiAgICB9XG5cbiAgICB0aGlzW0NVUlNPUl9TVEFDS10ucHVzaChjdXJzb3IpO1xuICB9XG5cbiAgLy8gY2xlYXJzIHVudGlsIHRoZSBlbmQgb2YgdGhlIGN1cnJlbnQgY29udGFpbmVyXG4gIC8vIGVpdGhlciB0aGUgY3VycmVudCBvcGVuIGJsb2NrIG9yIGhpZ2hlclxuICBwcml2YXRlIGNsZWFyTWlzbWF0Y2goY2FuZGlkYXRlOiBTaW1wbGVOb2RlKSB7XG4gICAgbGV0IGN1cnJlbnQ6IE9wdGlvbjxTaW1wbGVOb2RlPiA9IGNhbmRpZGF0ZTtcbiAgICBsZXQgY3VycmVudEN1cnNvciA9IHRoaXMuY3VycmVudEN1cnNvcjtcbiAgICBpZiAoY3VycmVudEN1cnNvciAhPT0gbnVsbCkge1xuICAgICAgbGV0IG9wZW5CbG9ja0RlcHRoID0gY3VycmVudEN1cnNvci5vcGVuQmxvY2tEZXB0aDtcbiAgICAgIGlmIChvcGVuQmxvY2tEZXB0aCA+PSBjdXJyZW50Q3Vyc29yLnN0YXJ0aW5nQmxvY2tEZXB0aCkge1xuICAgICAgICB3aGlsZSAoY3VycmVudCkge1xuICAgICAgICAgIGlmIChpc0Nsb3NlQmxvY2soY3VycmVudCkpIHtcbiAgICAgICAgICAgIGxldCBjbG9zZUJsb2NrRGVwdGggPSBnZXRCbG9ja0RlcHRoV2l0aE9mZnNldChjdXJyZW50LCB0aGlzLnN0YXJ0aW5nQmxvY2tPZmZzZXQpO1xuICAgICAgICAgICAgaWYgKG9wZW5CbG9ja0RlcHRoID49IGNsb3NlQmxvY2tEZXB0aCkge1xuICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgICAgY3VycmVudCA9IHRoaXMucmVtb3ZlKGN1cnJlbnQpO1xuICAgICAgICB9XG4gICAgICB9IGVsc2Uge1xuICAgICAgICB3aGlsZSAoY3VycmVudCAhPT0gbnVsbCkge1xuICAgICAgICAgIGN1cnJlbnQgPSB0aGlzLnJlbW92ZShjdXJyZW50KTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgLy8gY3VycmVudCBjdXJzb3IgcGFyZW50Tm9kZSBzaG91bGQgYmUgb3BlbkNhbmRpZGF0ZSBpZiBlbGVtZW50XG4gICAgICAvLyBvciBvcGVuQ2FuZGlkYXRlLnBhcmVudE5vZGUgaWYgY29tbWVudFxuICAgICAgdGhpcy5kaXNhYmxlUmVoeWRyYXRpb24oY3VycmVudCk7XG4gICAgfVxuICB9XG5cbiAgX19vcGVuQmxvY2soKTogdm9pZCB7XG4gICAgbGV0IHsgY3VycmVudEN1cnNvciB9ID0gdGhpcztcbiAgICBpZiAoY3VycmVudEN1cnNvciA9PT0gbnVsbCkgcmV0dXJuO1xuXG4gICAgbGV0IGJsb2NrRGVwdGggPSB0aGlzLmJsb2NrRGVwdGg7XG5cbiAgICB0aGlzLmJsb2NrRGVwdGgrKztcblxuICAgIGxldCB7IGNhbmRpZGF0ZSB9ID0gY3VycmVudEN1cnNvcjtcbiAgICBpZiAoY2FuZGlkYXRlID09PSBudWxsKSByZXR1cm47XG5cbiAgICBsZXQgeyB0YWdOYW1lIH0gPSBjdXJyZW50Q3Vyc29yLmVsZW1lbnQ7XG5cbiAgICBpZiAoXG4gICAgICBpc09wZW5CbG9jayhjYW5kaWRhdGUpICYmXG4gICAgICBnZXRCbG9ja0RlcHRoV2l0aE9mZnNldChjYW5kaWRhdGUsIHRoaXMuc3RhcnRpbmdCbG9ja09mZnNldCkgPT09IGJsb2NrRGVwdGhcbiAgICApIHtcbiAgICAgIHRoaXMuY2FuZGlkYXRlID0gdGhpcy5yZW1vdmUoY2FuZGlkYXRlKTtcbiAgICAgIGN1cnJlbnRDdXJzb3Iub3BlbkJsb2NrRGVwdGggPSBibG9ja0RlcHRoO1xuICAgIH0gZWxzZSBpZiAodGFnTmFtZSAhPT0gJ1RJVExFJyAmJiB0YWdOYW1lICE9PSAnU0NSSVBUJyAmJiB0YWdOYW1lICE9PSAnU1RZTEUnKSB7XG4gICAgICB0aGlzLmNsZWFyTWlzbWF0Y2goY2FuZGlkYXRlKTtcbiAgICB9XG4gIH1cblxuICBfX2Nsb3NlQmxvY2soKTogdm9pZCB7XG4gICAgbGV0IHsgY3VycmVudEN1cnNvciB9ID0gdGhpcztcbiAgICBpZiAoY3VycmVudEN1cnNvciA9PT0gbnVsbCkgcmV0dXJuO1xuXG4gICAgLy8gb3BlbkJsb2NrIGlzIHRoZSBsYXN0IHJlaHlkcmF0ZWQgb3BlbiBibG9ja1xuICAgIGxldCBvcGVuQmxvY2tEZXB0aCA9IGN1cnJlbnRDdXJzb3Iub3BlbkJsb2NrRGVwdGg7XG5cbiAgICAvLyB0aGlzIGN1cnJlbnRseSBpcyB0aGUgZXhwZWN0ZWQgbmV4dCBvcGVuIGJsb2NrIGRlcHRoXG4gICAgdGhpcy5ibG9ja0RlcHRoLS07XG5cbiAgICBsZXQgeyBjYW5kaWRhdGUgfSA9IGN1cnJlbnRDdXJzb3I7XG5cbiAgICBsZXQgaXNSZWh5ZHJhdGluZyA9IGZhbHNlO1xuXG4gICAgaWYgKGNhbmRpZGF0ZSAhPT0gbnVsbCkge1xuICAgICAgaXNSZWh5ZHJhdGluZyA9IHRydWU7XG4gICAgICAvL2Fzc2VydChcbiAgICAgIC8vICBvcGVuQmxvY2tEZXB0aCA9PT0gdGhpcy5ibG9ja0RlcHRoLFxuICAgICAgLy8gICd3aGVuIHJlaHlkcmF0aW5nLCBvcGVuQmxvY2tEZXB0aCBzaG91bGQgbWF0Y2ggdGhpcy5ibG9ja0RlcHRoIGhlcmUnXG4gICAgICAvLyk7XG5cbiAgICAgIGlmIChcbiAgICAgICAgaXNDbG9zZUJsb2NrKGNhbmRpZGF0ZSkgJiZcbiAgICAgICAgZ2V0QmxvY2tEZXB0aFdpdGhPZmZzZXQoY2FuZGlkYXRlLCB0aGlzLnN0YXJ0aW5nQmxvY2tPZmZzZXQpID09PSBvcGVuQmxvY2tEZXB0aFxuICAgICAgKSB7XG4gICAgICAgIGxldCBuZXh0U2libGluZyA9IHRoaXMucmVtb3ZlKGNhbmRpZGF0ZSk7XG4gICAgICAgIHRoaXMuY2FuZGlkYXRlID0gbmV4dFNpYmxpbmc7XG4gICAgICAgIGN1cnJlbnRDdXJzb3Iub3BlbkJsb2NrRGVwdGgtLTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIC8vIGNsb3NlIHRoZSBibG9jayBhbmQgY2xlYXIgbWlzbWF0Y2ggaW4gcGFyZW50IGNvbnRhaW5lclxuICAgICAgICAvLyB3ZSB3aWxsIGJlIGVpdGhlciBhdCB0aGUgZW5kIG9mIHRoZSBlbGVtZW50XG4gICAgICAgIC8vIG9yIGF0IHRoZSBlbmQgb2Ygb3VyIGNvbnRhaW5pbmcgYmxvY2tcbiAgICAgICAgdGhpcy5jbGVhck1pc21hdGNoKGNhbmRpZGF0ZSk7XG4gICAgICAgIGlzUmVoeWRyYXRpbmcgPSBmYWxzZTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICBpZiAoaXNSZWh5ZHJhdGluZyA9PT0gZmFsc2UpIHtcbiAgICAgIC8vIGNoZWNrIGlmIG5leHRTaWJsaW5nIG1hdGNoZXMgb3VyIGV4cGVjdGVkIGNsb3NlIGJsb2NrXG4gICAgICAvLyBpZiBzbywgd2UgcmVtb3ZlIHRoZSBjbG9zZSBibG9jayBjb21tZW50IGFuZFxuICAgICAgLy8gcmVzdG9yZSByZWh5ZHJhdGlvbiBhZnRlciBjbGVhck1pc21hdGNoIGRpc2FibGVkXG4gICAgICBsZXQgbmV4dFNpYmxpbmcgPSBjdXJyZW50Q3Vyc29yLm5leHRTaWJsaW5nO1xuICAgICAgaWYgKFxuICAgICAgICBuZXh0U2libGluZyAhPT0gbnVsbCAmJlxuICAgICAgICBpc0Nsb3NlQmxvY2sobmV4dFNpYmxpbmcpICYmXG4gICAgICAgIGdldEJsb2NrRGVwdGhXaXRoT2Zmc2V0KG5leHRTaWJsaW5nLCB0aGlzLnN0YXJ0aW5nQmxvY2tPZmZzZXQpID09PSB0aGlzLmJsb2NrRGVwdGhcbiAgICAgICkge1xuICAgICAgICAvLyByZXN0b3JlIHJlaHlkcmF0aW9uIHN0YXRlXG4gICAgICAgIGxldCBjYW5kaWRhdGUgPSB0aGlzLnJlbW92ZShuZXh0U2libGluZyk7XG4gICAgICAgIHRoaXMuZW5hYmxlUmVoeWRyYXRpb24oY2FuZGlkYXRlKTtcblxuICAgICAgICBjdXJyZW50Q3Vyc29yLm9wZW5CbG9ja0RlcHRoLS07XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgX19hcHBlbmROb2RlKG5vZGU6IFNpbXBsZU5vZGUpOiBTaW1wbGVOb2RlIHtcbiAgICBsZXQgeyBjYW5kaWRhdGUgfSA9IHRoaXM7XG5cbiAgICAvLyBUaGlzIGNvZGUgcGF0aCBpcyBvbmx5IHVzZWQgd2hlbiBpbnNlcnRpbmcgcHJlY2lzZWx5IG9uZSBub2RlLiBJdCBuZWVkcyBtb3JlXG4gICAgLy8gY29tcGFyaXNvbiBsb2dpYywgYnV0IHdlIGNhbiBwcm9iYWJseSBsZWFuIG9uIHRoZSBjYXNlcyB3aGVyZSB0aGlzIGNvZGUgcGF0aFxuICAgIC8vIGlzIGFjdHVhbGx5IHVzZWQuXG4gICAgaWYgKGNhbmRpZGF0ZSkge1xuICAgICAgcmV0dXJuIGNhbmRpZGF0ZTtcbiAgICB9IGVsc2Uge1xuICAgICAgcmV0dXJuIHN1cGVyLl9fYXBwZW5kTm9kZShub2RlKTtcbiAgICB9XG4gIH1cblxuICBfX2FwcGVuZEhUTUwoaHRtbDogc3RyaW5nKTogQm91bmRzIHtcbiAgICBsZXQgY2FuZGlkYXRlQm91bmRzID0gdGhpcy5tYXJrZXJCb3VuZHMoKTtcblxuICAgIGlmIChjYW5kaWRhdGVCb3VuZHMpIHtcbiAgICAgIGxldCBmaXJzdCA9IGNhbmRpZGF0ZUJvdW5kcy5maXJzdE5vZGUoKSE7XG4gICAgICBsZXQgbGFzdCA9IGNhbmRpZGF0ZUJvdW5kcy5sYXN0Tm9kZSgpITtcblxuICAgICAgbGV0IG5ld0JvdW5kcyA9IG5ldyBDb25jcmV0ZUJvdW5kcyh0aGlzLmVsZW1lbnQsIGZpcnN0Lm5leHRTaWJsaW5nISwgbGFzdC5wcmV2aW91c1NpYmxpbmchKTtcblxuICAgICAgbGV0IHBvc3NpYmxlRW1wdHlNYXJrZXIgPSB0aGlzLnJlbW92ZShmaXJzdCk7XG4gICAgICB0aGlzLnJlbW92ZShsYXN0KTtcblxuICAgICAgaWYgKHBvc3NpYmxlRW1wdHlNYXJrZXIgIT09IG51bGwgJiYgaXNFbXB0eShwb3NzaWJsZUVtcHR5TWFya2VyKSkge1xuICAgICAgICB0aGlzLmNhbmRpZGF0ZSA9IHRoaXMucmVtb3ZlKHBvc3NpYmxlRW1wdHlNYXJrZXIpO1xuXG4gICAgICAgIGlmICh0aGlzLmNhbmRpZGF0ZSAhPT0gbnVsbCkge1xuICAgICAgICAgIHRoaXMuY2xlYXJNaXNtYXRjaCh0aGlzLmNhbmRpZGF0ZSk7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgcmV0dXJuIG5ld0JvdW5kcztcbiAgICB9IGVsc2Uge1xuICAgICAgcmV0dXJuIHN1cGVyLl9fYXBwZW5kSFRNTChodG1sKTtcbiAgICB9XG4gIH1cblxuICBwcm90ZWN0ZWQgcmVtb3ZlKG5vZGU6IFNpbXBsZU5vZGUpOiBPcHRpb248U2ltcGxlTm9kZT4ge1xuICAgIGxldCBlbGVtZW50ID0gZXhwZWN0KG5vZGUucGFyZW50Tm9kZSwgYGNhbm5vdCByZW1vdmUgYSBkZXRhY2hlZCBub2RlYCkgYXMgU2ltcGxlRWxlbWVudDtcbiAgICBsZXQgbmV4dCA9IG5vZGUubmV4dFNpYmxpbmc7XG4gICAgZWxlbWVudC5yZW1vdmVDaGlsZChub2RlKTtcbiAgICByZXR1cm4gbmV4dDtcbiAgfVxuXG4gIHByaXZhdGUgbWFya2VyQm91bmRzKCk6IE9wdGlvbjxCb3VuZHM+IHtcbiAgICBsZXQgX2NhbmRpZGF0ZSA9IHRoaXMuY2FuZGlkYXRlO1xuXG4gICAgaWYgKF9jYW5kaWRhdGUgJiYgaXNNYXJrZXIoX2NhbmRpZGF0ZSkpIHtcbiAgICAgIGxldCBmaXJzdCA9IF9jYW5kaWRhdGU7XG4gICAgICBsZXQgbGFzdCA9IGV4cGVjdChmaXJzdC5uZXh0U2libGluZywgYEJVRzogc2VyaWFsaXphdGlvbiBtYXJrZXJzIG11c3QgYmUgcGFpcmVkYCk7XG5cbiAgICAgIHdoaWxlIChsYXN0ICYmICFpc01hcmtlcihsYXN0KSkge1xuICAgICAgICBsYXN0ID0gZXhwZWN0KGxhc3QubmV4dFNpYmxpbmcsIGBCVUc6IHNlcmlhbGl6YXRpb24gbWFya2VycyBtdXN0IGJlIHBhaXJlZGApO1xuICAgICAgfVxuXG4gICAgICByZXR1cm4gbmV3IENvbmNyZXRlQm91bmRzKHRoaXMuZWxlbWVudCwgZmlyc3QsIGxhc3QpO1xuICAgIH0gZWxzZSB7XG4gICAgICByZXR1cm4gbnVsbDtcbiAgICB9XG4gIH1cblxuICBfX2FwcGVuZFRleHQoc3RyaW5nOiBzdHJpbmcpOiBTaW1wbGVUZXh0IHtcbiAgICBsZXQgeyBjYW5kaWRhdGUgfSA9IHRoaXM7XG5cbiAgICBpZiAoY2FuZGlkYXRlKSB7XG4gICAgICBpZiAoaXNUZXh0Tm9kZShjYW5kaWRhdGUpKSB7XG4gICAgICAgIGlmIChjYW5kaWRhdGUubm9kZVZhbHVlICE9PSBzdHJpbmcpIHtcbiAgICAgICAgICBjYW5kaWRhdGUubm9kZVZhbHVlID0gc3RyaW5nO1xuICAgICAgICB9XG4gICAgICAgIHRoaXMuY2FuZGlkYXRlID0gY2FuZGlkYXRlLm5leHRTaWJsaW5nO1xuXG4gICAgICAgIHJldHVybiBjYW5kaWRhdGU7XG4gICAgICB9IGVsc2UgaWYgKGlzU2VwYXJhdG9yKGNhbmRpZGF0ZSkpIHtcbiAgICAgICAgdGhpcy5jYW5kaWRhdGUgPSB0aGlzLnJlbW92ZShjYW5kaWRhdGUpO1xuXG4gICAgICAgIHJldHVybiB0aGlzLl9fYXBwZW5kVGV4dChzdHJpbmcpO1xuICAgICAgfSBlbHNlIGlmIChpc0VtcHR5KGNhbmRpZGF0ZSkgJiYgc3RyaW5nID09PSAnJykge1xuICAgICAgICB0aGlzLmNhbmRpZGF0ZSA9IHRoaXMucmVtb3ZlKGNhbmRpZGF0ZSk7XG5cbiAgICAgICAgcmV0dXJuIHRoaXMuX19hcHBlbmRUZXh0KHN0cmluZyk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICB0aGlzLmNsZWFyTWlzbWF0Y2goY2FuZGlkYXRlKTtcblxuICAgICAgICByZXR1cm4gc3VwZXIuX19hcHBlbmRUZXh0KHN0cmluZyk7XG4gICAgICB9XG4gICAgfSBlbHNlIHtcbiAgICAgIHJldHVybiBzdXBlci5fX2FwcGVuZFRleHQoc3RyaW5nKTtcbiAgICB9XG4gIH1cblxuICBfX2FwcGVuZENvbW1lbnQoc3RyaW5nOiBzdHJpbmcpOiBTaW1wbGVDb21tZW50IHtcbiAgICBsZXQgX2NhbmRpZGF0ZSA9IHRoaXMuY2FuZGlkYXRlO1xuICAgIGlmIChfY2FuZGlkYXRlICYmIGlzQ29tbWVudChfY2FuZGlkYXRlKSkge1xuICAgICAgaWYgKF9jYW5kaWRhdGUubm9kZVZhbHVlICE9PSBzdHJpbmcpIHtcbiAgICAgICAgX2NhbmRpZGF0ZS5ub2RlVmFsdWUgPSBzdHJpbmc7XG4gICAgICB9XG5cbiAgICAgIHRoaXMuY2FuZGlkYXRlID0gX2NhbmRpZGF0ZS5uZXh0U2libGluZztcbiAgICAgIHJldHVybiBfY2FuZGlkYXRlO1xuICAgIH0gZWxzZSBpZiAoX2NhbmRpZGF0ZSkge1xuICAgICAgdGhpcy5jbGVhck1pc21hdGNoKF9jYW5kaWRhdGUpO1xuICAgIH1cblxuICAgIHJldHVybiBzdXBlci5fX2FwcGVuZENvbW1lbnQoc3RyaW5nKTtcbiAgfVxuXG4gIF9fb3BlbkVsZW1lbnQodGFnOiBzdHJpbmcpOiBTaW1wbGVFbGVtZW50IHtcbiAgICBsZXQgX2NhbmRpZGF0ZSA9IHRoaXMuY2FuZGlkYXRlO1xuXG4gICAgaWYgKF9jYW5kaWRhdGUgJiYgaXNFbGVtZW50KF9jYW5kaWRhdGUpICYmIGlzU2FtZU5vZGVUeXBlKF9jYW5kaWRhdGUsIHRhZykpIHtcbiAgICAgIHRoaXMudW5tYXRjaGVkQXR0cmlidXRlcyA9IFtdLnNsaWNlLmNhbGwoX2NhbmRpZGF0ZS5hdHRyaWJ1dGVzKTtcbiAgICAgIHJldHVybiBfY2FuZGlkYXRlO1xuICAgIH0gZWxzZSBpZiAoX2NhbmRpZGF0ZSkge1xuICAgICAgaWYgKGlzRWxlbWVudChfY2FuZGlkYXRlKSAmJiBfY2FuZGlkYXRlLnRhZ05hbWUgPT09ICdUQk9EWScpIHtcbiAgICAgICAgdGhpcy5wdXNoRWxlbWVudChfY2FuZGlkYXRlLCBudWxsKTtcbiAgICAgICAgdGhpcy5jdXJyZW50Q3Vyc29yIS5pbmplY3RlZE9taXR0ZWROb2RlID0gdHJ1ZTtcbiAgICAgICAgcmV0dXJuIHRoaXMuX19vcGVuRWxlbWVudCh0YWcpO1xuICAgICAgfVxuICAgICAgdGhpcy5jbGVhck1pc21hdGNoKF9jYW5kaWRhdGUpO1xuICAgIH1cblxuICAgIHJldHVybiBzdXBlci5fX29wZW5FbGVtZW50KHRhZyk7XG4gIH1cblxuICBfX3NldEF0dHJpYnV0ZShuYW1lOiBzdHJpbmcsIHZhbHVlOiBzdHJpbmcsIG5hbWVzcGFjZTogT3B0aW9uPEF0dHJOYW1lc3BhY2U+KTogdm9pZCB7XG4gICAgbGV0IHVubWF0Y2hlZCA9IHRoaXMudW5tYXRjaGVkQXR0cmlidXRlcztcblxuICAgIGlmICh1bm1hdGNoZWQpIHtcbiAgICAgIGxldCBhdHRyID0gZmluZEJ5TmFtZSh1bm1hdGNoZWQsIG5hbWUpO1xuICAgICAgaWYgKGF0dHIpIHtcbiAgICAgICAgaWYgKGF0dHIudmFsdWUgIT09IHZhbHVlKSB7XG4gICAgICAgICAgYXR0ci52YWx1ZSA9IHZhbHVlO1xuICAgICAgICB9XG4gICAgICAgIHVubWF0Y2hlZC5zcGxpY2UodW5tYXRjaGVkLmluZGV4T2YoYXR0ciksIDEpO1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIHN1cGVyLl9fc2V0QXR0cmlidXRlKG5hbWUsIHZhbHVlLCBuYW1lc3BhY2UpO1xuICB9XG5cbiAgX19zZXRQcm9wZXJ0eShuYW1lOiBzdHJpbmcsIHZhbHVlOiBzdHJpbmcpOiB2b2lkIHtcbiAgICBsZXQgdW5tYXRjaGVkID0gdGhpcy51bm1hdGNoZWRBdHRyaWJ1dGVzO1xuXG4gICAgaWYgKHVubWF0Y2hlZCkge1xuICAgICAgbGV0IGF0dHIgPSBmaW5kQnlOYW1lKHVubWF0Y2hlZCwgbmFtZSk7XG4gICAgICBpZiAoYXR0cikge1xuICAgICAgICBpZiAoYXR0ci52YWx1ZSAhPT0gdmFsdWUpIHtcbiAgICAgICAgICBhdHRyLnZhbHVlID0gdmFsdWU7XG4gICAgICAgIH1cbiAgICAgICAgdW5tYXRjaGVkLnNwbGljZSh1bm1hdGNoZWQuaW5kZXhPZihhdHRyKSwgMSk7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4gc3VwZXIuX19zZXRQcm9wZXJ0eShuYW1lLCB2YWx1ZSk7XG4gIH1cblxuICBfX2ZsdXNoRWxlbWVudChwYXJlbnQ6IFNpbXBsZUVsZW1lbnQsIGNvbnN0cnVjdGluZzogU2ltcGxlRWxlbWVudCk6IHZvaWQge1xuICAgIGxldCB7IHVubWF0Y2hlZEF0dHJpYnV0ZXM6IHVubWF0Y2hlZCB9ID0gdGhpcztcbiAgICBpZiAodW5tYXRjaGVkKSB7XG4gICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHVubWF0Y2hlZC5sZW5ndGg7IGkrKykge1xuICAgICAgICB0aGlzLmNvbnN0cnVjdGluZyEucmVtb3ZlQXR0cmlidXRlKHVubWF0Y2hlZFtpXS5uYW1lKTtcbiAgICAgIH1cbiAgICAgIHRoaXMudW5tYXRjaGVkQXR0cmlidXRlcyA9IG51bGw7XG4gICAgfSBlbHNlIHtcbiAgICAgIHN1cGVyLl9fZmx1c2hFbGVtZW50KHBhcmVudCwgY29uc3RydWN0aW5nKTtcbiAgICB9XG4gIH1cblxuICB3aWxsQ2xvc2VFbGVtZW50KCkge1xuICAgIGxldCB7IGNhbmRpZGF0ZSwgY3VycmVudEN1cnNvciB9ID0gdGhpcztcblxuICAgIGlmIChjYW5kaWRhdGUgIT09IG51bGwpIHtcbiAgICAgIHRoaXMuY2xlYXJNaXNtYXRjaChjYW5kaWRhdGUpO1xuICAgIH1cblxuICAgIGlmIChjdXJyZW50Q3Vyc29yICYmIGN1cnJlbnRDdXJzb3IuaW5qZWN0ZWRPbWl0dGVkTm9kZSkge1xuICAgICAgdGhpcy5wb3BFbGVtZW50KCk7XG4gICAgfVxuXG4gICAgc3VwZXIud2lsbENsb3NlRWxlbWVudCgpO1xuICB9XG5cbiAgZ2V0TWFya2VyKGVsZW1lbnQ6IEhUTUxFbGVtZW50LCBndWlkOiBzdHJpbmcpOiBPcHRpb248U2ltcGxlTm9kZT4ge1xuICAgIGxldCBtYXJrZXIgPSBlbGVtZW50LnF1ZXJ5U2VsZWN0b3IoYHNjcmlwdFtnbG1yPVwiJHtndWlkfVwiXWApO1xuICAgIGlmIChtYXJrZXIpIHtcbiAgICAgIHJldHVybiBjYXN0VG9TaW1wbGUobWFya2VyKTtcbiAgICB9XG4gICAgcmV0dXJuIG51bGw7XG4gIH1cblxuICBfX3B1c2hSZW1vdGVFbGVtZW50KFxuICAgIGVsZW1lbnQ6IFNpbXBsZUVsZW1lbnQsXG4gICAgY3Vyc29ySWQ6IHN0cmluZyxcbiAgICBpbnNlcnRCZWZvcmU6IE1heWJlPFNpbXBsZU5vZGU+XG4gICk6IE9wdGlvbjxSZW1vdGVMaXZlQmxvY2s+IHtcbiAgICBsZXQgbWFya2VyID0gdGhpcy5nZXRNYXJrZXIoY2FzdFRvQnJvd3NlcihlbGVtZW50LCAnSFRNTCcpLCBjdXJzb3JJZCk7XG5cbiAgICBhc3NlcnQoXG4gICAgICAhbWFya2VyIHx8IG1hcmtlci5wYXJlbnROb2RlID09PSBlbGVtZW50LFxuICAgICAgYGV4cGVjdGVkIHJlbW90ZSBlbGVtZW50IG1hcmtlcidzIHBhcmVudCBub2RlIHRvIG1hdGNoIHJlbW90ZSBlbGVtZW50YFxuICAgICk7XG5cbiAgICA