UNPKG

matrix-react-sdk

Version:
597 lines (492 loc) 57 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty")); var _diff = require("./diff"); var _position = _interopRequireDefault(require("./position")); var _range = _interopRequireDefault(require("./range")); /* Copyright 2019 New Vector Ltd Copyright 2019 The Matrix.org Foundation C.I.C. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ class EditorModel { constructor(parts /*: Part[]*/ , partCreator /*: PartCreator*/ , updateCallback /*: UpdateCallback*/ = null) { this.updateCallback /*:: */ = updateCallback /*:: */ ; (0, _defineProperty2.default)(this, "_parts", void 0); (0, _defineProperty2.default)(this, "_partCreator", void 0); (0, _defineProperty2.default)(this, "activePartIdx", null); (0, _defineProperty2.default)(this, "_autoComplete", null); (0, _defineProperty2.default)(this, "autoCompletePartIdx", null); (0, _defineProperty2.default)(this, "autoCompletePartCount", 0); (0, _defineProperty2.default)(this, "transformCallback", null); (0, _defineProperty2.default)(this, "onAutoComplete", ({ replaceParts, close } /*: ICallback*/ ) => { let pos; if (replaceParts) { this._parts.splice(this.autoCompletePartIdx, this.autoCompletePartCount, ...replaceParts); this.autoCompletePartCount = replaceParts.length; const lastPart = replaceParts[replaceParts.length - 1]; const lastPartIndex = this.autoCompletePartIdx + replaceParts.length - 1; pos = new _position.default(lastPartIndex, lastPart.text.length); } if (close) { this._autoComplete = null; this.autoCompletePartIdx = null; this.autoCompletePartCount = 0; } // rerender even if editor contents didn't change // to make sure the MessageEditor checks // model.autoComplete being empty and closes it this.updateCallback(pos); }); this._parts = parts; this._partCreator = partCreator; this.transformCallback = null; } /** * Set a callback for the transformation step. * While processing an update, right before calling the update callback, * a transform callback can be called, which serves to do modifications * on the model that can span multiple parts. Also see `startRange()`. * @param {TransformCallback} transformCallback */ setTransformCallback(transformCallback /*: TransformCallback*/ ) { this.transformCallback = transformCallback; } /** * Set a callback for rerendering the model after it has been updated. * @param {ModelCallback} updateCallback */ setUpdateCallback(updateCallback /*: UpdateCallback*/ ) { this.updateCallback = updateCallback; } get partCreator() { return this._partCreator; } get isEmpty() { return this._parts.reduce((len, part) => len + part.text.length, 0) === 0; } clone() { return new EditorModel(this._parts, this._partCreator, this.updateCallback); } insertPart(index /*: number*/ , part /*: Part*/ ) { this._parts.splice(index, 0, part); if (this.activePartIdx >= index) { ++this.activePartIdx; } if (this.autoCompletePartIdx >= index) { ++this.autoCompletePartIdx; } } removePart(index /*: number*/ ) { this._parts.splice(index, 1); if (index === this.activePartIdx) { this.activePartIdx = null; } else if (this.activePartIdx > index) { --this.activePartIdx; } if (index === this.autoCompletePartIdx) { this.autoCompletePartIdx = null; } else if (this.autoCompletePartIdx > index) { --this.autoCompletePartIdx; } } replacePart(index /*: number*/ , part /*: Part*/ ) { this._parts.splice(index, 1, part); } get parts() { return this._parts; } get autoComplete() { if (this.activePartIdx === this.autoCompletePartIdx) { return this._autoComplete; } return null; } getPositionAtEnd() { if (this._parts.length) { const index = this._parts.length - 1; const part = this._parts[index]; return new _position.default(index, part.text.length); } else { // part index -1, as there are no parts to point at return new _position.default(-1, 0); } } serializeParts() { return this._parts.map(p => p.serialize()); } diff(newValue /*: string*/ , inputType /*: string*/ , caret /*: DocumentOffset*/ ) { const previousValue = this.parts.reduce((text, p) => text + p.text, ""); // can't use caret position with drag and drop if (inputType === "deleteByDrag") { return (0, _diff.diffDeletion)(previousValue, newValue); } else { return (0, _diff.diffAtCaret)(previousValue, newValue, caret.offset); } } reset(serializedParts /*: SerializedPart[]*/ , caret /*: Caret*/ , inputType /*: string*/ ) { this._parts = serializedParts.map(p => this._partCreator.deserializePart(p)); if (!caret) { caret = this.getPositionAtEnd(); } // close auto complete if open // this would happen when clearing the composer after sending // a message with the autocomplete still open if (this._autoComplete) { this._autoComplete = null; this.autoCompletePartIdx = null; } this.updateCallback(caret, inputType); } /** * Inserts the given parts at the given position. * Should be run inside a `model.transform()` callback. * @param {Part[]} parts the parts to replace the range with * @param {DocumentPosition} position the position to start inserting at * @return {Number} the amount of characters added */ insert(parts /*: Part[]*/ , position /*: IPosition*/ ) { const insertIndex = this.splitAt(position); let newTextLength = 0; for (let i = 0; i < parts.length; ++i) { const part = parts[i]; newTextLength += part.text.length; this.insertPart(insertIndex + i, part); } return newTextLength; } update(newValue /*: string*/ , inputType /*: string*/ , caret /*: DocumentOffset*/ ) { const diff = this.diff(newValue, inputType, caret); const position = this.positionForOffset(diff.at, caret.atNodeEnd); let removedOffsetDecrease = 0; if (diff.removed) { removedOffsetDecrease = this.removeText(position, diff.removed.length); } let addedLen = 0; if (diff.added) { addedLen = this.addText(position, diff.added, inputType); } this.mergeAdjacentParts(); const caretOffset = diff.at - removedOffsetDecrease + addedLen; let newPosition = this.positionForOffset(caretOffset, true); const canOpenAutoComplete = inputType !== "insertFromPaste" && inputType !== "insertFromDrop"; const acPromise = this.setActivePart(newPosition, canOpenAutoComplete); if (this.transformCallback) { const transformAddedLen = this.getTransformAddedLen(newPosition, inputType, diff); newPosition = this.positionForOffset(caretOffset + transformAddedLen, true); } this.updateCallback(newPosition, inputType, diff); return acPromise; } getTransformAddedLen(newPosition /*: DocumentPosition*/ , inputType /*: string*/ , diff /*: IDiff*/ ) /*: number*/ { const result = this.transformCallback(newPosition, inputType, diff); return Number.isFinite(result) ? result : 0; } setActivePart(pos /*: DocumentPosition*/ , canOpenAutoComplete /*: boolean*/ ) { const { index } = pos; const part = this._parts[index]; if (part) { if (index !== this.activePartIdx) { this.activePartIdx = index; if (canOpenAutoComplete && this.activePartIdx !== this.autoCompletePartIdx) { // else try to create one const ac = part.createAutoComplete(this.onAutoComplete); if (ac) { // make sure that react picks up the difference between both acs this._autoComplete = ac; this.autoCompletePartIdx = index; this.autoCompletePartCount = 1; } } } // not _autoComplete, only there if active part is autocomplete part if (this.autoComplete) { return this.autoComplete.onPartUpdate(part, pos); } } else { this.activePartIdx = null; this._autoComplete = null; this.autoCompletePartIdx = null; this.autoCompletePartCount = 0; } return Promise.resolve(); } mergeAdjacentParts() { let prevPart; for (let i = 0; i < this._parts.length; ++i) { let part = this._parts[i]; const isEmpty = !part.text.length; const isMerged = !isEmpty && prevPart && prevPart.merge(part); if (isEmpty || isMerged) { // remove empty or merged part part = prevPart; this.removePart(i); //repeat this index, as it's removed now --i; } prevPart = part; } } /** * removes `len` amount of characters at `pos`. * @param {Object} pos * @param {Number} len * @return {Number} how many characters before pos were also removed, * usually because of non-editable parts that can only be removed in their entirety. */ removeText(pos /*: IPosition*/ , len /*: number*/ ) { let { index, offset } = pos; let removedOffsetDecrease = 0; while (len > 0) { // part might be undefined here let part = this._parts[index]; const amount = Math.min(len, part.text.length - offset); // don't allow 0 amount deletions if (amount) { if (part.canEdit) { const replaceWith = part.remove(offset, amount); if (typeof replaceWith === "string") { this.replacePart(index, this._partCreator.createDefaultPart(replaceWith)); } part = this._parts[index]; // remove empty part if (!part.text.length) { this.removePart(index); } else { index += 1; } } else { removedOffsetDecrease += offset; this.removePart(index); } } else { index += 1; } len -= amount; offset = 0; } return removedOffsetDecrease; } // return part index where insertion will insert between at offset splitAt(pos /*: IPosition*/ ) { if (pos.index === -1) { return 0; } if (pos.offset === 0) { return pos.index; } const part = this._parts[pos.index]; if (pos.offset >= part.text.length) { return pos.index + 1; } const secondPart = part.split(pos.offset); this.insertPart(pos.index + 1, secondPart); return pos.index + 1; } /** * inserts `str` into the model at `pos`. * @param {Object} pos * @param {string} str * @param {string} inputType the source of the input, see html InputEvent.inputType * @param {bool} options.validate Whether characters will be validated by the part. * Validating allows the inserted text to be parsed according to the part rules. * @return {Number} how far from position (in characters) the insertion ended. * This can be more than the length of `str` when crossing non-editable parts, which are skipped. */ addText(pos /*: IPosition*/ , str /*: string*/ , inputType /*: string*/ ) { let { index } = pos; const { offset } = pos; let addLen = str.length; const part = this._parts[index]; if (part) { if (part.canEdit) { if (part.validateAndInsert(offset, str, inputType)) { str = null; } else { const splitPart = part.split(offset); index += 1; this.insertPart(index, splitPart); } } else if (offset !== 0) { // not-editable part, caret is not at start, // so insert str after this part addLen += part.text.length - offset; index += 1; } } else if (index < 0) { // if position was not found (index: -1, as happens for empty editor) // reset it to insert as first part index = 0; } while (str) { const newPart = this._partCreator.createPartForInput(str, index, inputType); str = newPart.appendUntilRejected(str, inputType); this.insertPart(index, newPart); index += 1; } return addLen; } positionForOffset(totalOffset /*: number*/ , atPartEnd /*: boolean*/ ) { let currentOffset = 0; const index = this._parts.findIndex(part => { const partLen = part.text.length; if (atPartEnd && currentOffset + partLen >= totalOffset || !atPartEnd && currentOffset + partLen > totalOffset) { return true; } currentOffset += partLen; return false; }); if (index === -1) { return this.getPositionAtEnd(); } else { return new _position.default(index, totalOffset - currentOffset); } } /** * Starts a range, which can span across multiple parts, to find and replace text. * @param {DocumentPosition} positionA a boundary of the range * @param {DocumentPosition?} positionB the other boundary of the range, optional * @return {Range} */ startRange(positionA /*: DocumentPosition*/ , positionB = positionA) { return new _range.default(this, positionA, positionB); } replaceRange(startPosition /*: DocumentPosition*/ , endPosition /*: DocumentPosition*/ , parts /*: Part[]*/ ) { // convert end position to offset, so it is independent of how the document is split into parts // which we'll change when splitting up at the start position const endOffset = endPosition.asOffset(this); const newStartPartIndex = this.splitAt(startPosition); // convert it back to position once split at start endPosition = endOffset.asPosition(this); const newEndPartIndex = this.splitAt(endPosition); for (let i = newEndPartIndex - 1; i >= newStartPartIndex; --i) { this.removePart(i); } let insertIdx = newStartPartIndex; for (const part of parts) { this.insertPart(insertIdx, part); insertIdx += 1; } this.mergeAdjacentParts(); } /** * Performs a transformation not part of an update cycle. * Modifying the model should only happen inside a transform call if not part of an update call. * @param {ManualTransformCallback} callback to run the transformations in * @return {Promise} a promise when auto-complete (if applicable) is done updating */ transform(callback /*: ManualTransformCallback*/ ) { const pos = callback(); let acPromise = null; if (!(pos instanceof _range.default)) { acPromise = this.setActivePart(pos, true); } else { acPromise = Promise.resolve(); } this.updateCallback(pos); return acPromise; } } exports.default = EditorModel; //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9lZGl0b3IvbW9kZWwudHMiXSwibmFtZXMiOlsiRWRpdG9yTW9kZWwiLCJjb25zdHJ1Y3RvciIsInBhcnRzIiwicGFydENyZWF0b3IiLCJ1cGRhdGVDYWxsYmFjayIsInJlcGxhY2VQYXJ0cyIsImNsb3NlIiwicG9zIiwiX3BhcnRzIiwic3BsaWNlIiwiYXV0b0NvbXBsZXRlUGFydElkeCIsImF1dG9Db21wbGV0ZVBhcnRDb3VudCIsImxlbmd0aCIsImxhc3RQYXJ0IiwibGFzdFBhcnRJbmRleCIsIkRvY3VtZW50UG9zaXRpb24iLCJ0ZXh0IiwiX2F1dG9Db21wbGV0ZSIsIl9wYXJ0Q3JlYXRvciIsInRyYW5zZm9ybUNhbGxiYWNrIiwic2V0VHJhbnNmb3JtQ2FsbGJhY2siLCJzZXRVcGRhdGVDYWxsYmFjayIsImlzRW1wdHkiLCJyZWR1Y2UiLCJsZW4iLCJwYXJ0IiwiY2xvbmUiLCJpbnNlcnRQYXJ0IiwiaW5kZXgiLCJhY3RpdmVQYXJ0SWR4IiwicmVtb3ZlUGFydCIsInJlcGxhY2VQYXJ0IiwiYXV0b0NvbXBsZXRlIiwiZ2V0UG9zaXRpb25BdEVuZCIsInNlcmlhbGl6ZVBhcnRzIiwibWFwIiwicCIsInNlcmlhbGl6ZSIsImRpZmYiLCJuZXdWYWx1ZSIsImlucHV0VHlwZSIsImNhcmV0IiwicHJldmlvdXNWYWx1ZSIsIm9mZnNldCIsInJlc2V0Iiwic2VyaWFsaXplZFBhcnRzIiwiZGVzZXJpYWxpemVQYXJ0IiwiaW5zZXJ0IiwicG9zaXRpb24iLCJpbnNlcnRJbmRleCIsInNwbGl0QXQiLCJuZXdUZXh0TGVuZ3RoIiwiaSIsInVwZGF0ZSIsInBvc2l0aW9uRm9yT2Zmc2V0IiwiYXQiLCJhdE5vZGVFbmQiLCJyZW1vdmVkT2Zmc2V0RGVjcmVhc2UiLCJyZW1vdmVkIiwicmVtb3ZlVGV4dCIsImFkZGVkTGVuIiwiYWRkZWQiLCJhZGRUZXh0IiwibWVyZ2VBZGphY2VudFBhcnRzIiwiY2FyZXRPZmZzZXQiLCJuZXdQb3NpdGlvbiIsImNhbk9wZW5BdXRvQ29tcGxldGUiLCJhY1Byb21pc2UiLCJzZXRBY3RpdmVQYXJ0IiwidHJhbnNmb3JtQWRkZWRMZW4iLCJnZXRUcmFuc2Zvcm1BZGRlZExlbiIsInJlc3VsdCIsIk51bWJlciIsImlzRmluaXRlIiwiYWMiLCJjcmVhdGVBdXRvQ29tcGxldGUiLCJvbkF1dG9Db21wbGV0ZSIsIm9uUGFydFVwZGF0ZSIsIlByb21pc2UiLCJyZXNvbHZlIiwicHJldlBhcnQiLCJpc01lcmdlZCIsIm1lcmdlIiwiYW1vdW50IiwiTWF0aCIsIm1pbiIsImNhbkVkaXQiLCJyZXBsYWNlV2l0aCIsInJlbW92ZSIsImNyZWF0ZURlZmF1bHRQYXJ0Iiwic2Vjb25kUGFydCIsInNwbGl0Iiwic3RyIiwiYWRkTGVuIiwidmFsaWRhdGVBbmRJbnNlcnQiLCJzcGxpdFBhcnQiLCJuZXdQYXJ0IiwiY3JlYXRlUGFydEZvcklucHV0IiwiYXBwZW5kVW50aWxSZWplY3RlZCIsInRvdGFsT2Zmc2V0IiwiYXRQYXJ0RW5kIiwiY3VycmVudE9mZnNldCIsImZpbmRJbmRleCIsInBhcnRMZW4iLCJzdGFydFJhbmdlIiwicG9zaXRpb25BIiwicG9zaXRpb25CIiwiUmFuZ2UiLCJyZXBsYWNlUmFuZ2UiLCJzdGFydFBvc2l0aW9uIiwiZW5kUG9zaXRpb24iLCJlbmRPZmZzZXQiLCJhc09mZnNldCIsIm5ld1N0YXJ0UGFydEluZGV4IiwiYXNQb3NpdGlvbiIsIm5ld0VuZFBhcnRJbmRleCIsImluc2VydElkeCIsInRyYW5zZm9ybSIsImNhbGxiYWNrIl0sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7OztBQWlCQTs7QUFDQTs7QUFDQTs7QUFuQkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFtQ2UsTUFBTUEsV0FBTixDQUFrQjtBQVM3QkMsRUFBQUEsV0FBVyxDQUFDQztBQUFEO0FBQUEsSUFBZ0JDO0FBQWhCO0FBQUEsSUFBa0RDO0FBQThCO0FB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LFdBQUt5QixVQUFMLENBQWdCeUYsU0FBaEIsRUFBMkIzRixJQUEzQjtBQUNBMkYsTUFBQUEsU0FBUyxJQUFJLENBQWI7QUFDSDs7QUFDRCxTQUFLckQsa0JBQUw7QUFDSDtBQUVEO0FBQ0o7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7O0FBQ0lzRCxFQUFBQSxTQUFTLENBQUNDO0FBQUQ7QUFBQSxJQUFvQztBQUN6QyxVQUFNL0csR0FBRyxHQUFHK0csUUFBUSxFQUFwQjtBQUNBLFFBQUluRCxTQUFTLEdBQUcsSUFBaEI7O0FBQ0EsUUFBSSxFQUFFNUQsR0FBRyxZQUFZb0csY0FBakIsQ0FBSixFQUE2QjtBQUN6QnhDLE1BQUFBLFNBQVMsR0FBRyxLQUFLQyxhQUFMLENBQW1CN0QsR0FBbkIsRUFBd0IsSUFBeEIsQ0FBWjtBQUNILEtBRkQsTUFFTztBQUNINEQsTUFBQUEsU0FBUyxHQUFHVyxPQUFPLENBQUNDLE9BQVIsRUFBWjtBQUNIOztBQUNELFNBQUszRSxjQUFMLENBQW9CRyxHQUFwQjtBQUNBLFdBQU80RCxTQUFQO0FBQ0g7O0FBdlo0QiIsInNvdXJjZXNDb250ZW50IjpbIi8qXG5Db3B5cmlnaHQgMjAxOSBOZXcgVmVjdG9yIEx0ZFxuQ29weXJpZ2h0IDIwMTkgVGhlIE1hdHJpeC5vcmcgRm91bmRhdGlvbiBDLkkuQy5cblxuTGljZW5zZWQgdW5kZXIgdGhlIEFwYWNoZSBMaWNlbnNlLCBWZXJzaW9uIDIuMCAodGhlIFwiTGljZW5zZVwiKTtcbnlvdSBtYXkgbm90IHVzZSB0aGlzIGZpbGUgZXhjZXB0IGluIGNvbXBsaWFuY2Ugd2l0aCB0aGUgTGljZW5zZS5cbllvdSBtYXkgb2J0YWluIGEgY29weSBvZiB0aGUgTGljZW5zZSBhdFxuXG4gICAgaHR0cDovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzL0xJQ0VOU0UtMi4wXG5cblVubGVzcyByZXF1aXJlZCBieSBhcHBsaWNhYmxlIGxhdyBvciBhZ3JlZWQgdG8gaW4gd3JpdGluZywgc29mdHdhcmVcbmRpc3RyaWJ1dGVkIHVuZGVyIHRoZSBMaWNlbnNlIGlzIGRpc3RyaWJ1dGVkIG9uIGFuIFwiQVMgSVNcIiBCQVNJUyxcbldJVEhPVVQgV0FSUkFOVElFUyBPUiBDT05ESVRJT05TIE9GIEFOWSBLSU5ELCBlaXRoZXIgZXhwcmVzcyBvciBpbXBsaWVkLlxuU2VlIHRoZSBMaWNlbnNlIGZvciB0aGUgc3BlY2lmaWMgbGFuZ3VhZ2UgZ292ZXJuaW5nIHBlcm1pc3Npb25zIGFuZFxubGltaXRhdGlvbnMgdW5kZXIgdGhlIExpY2Vuc2UuXG4qL1xuXG5pbXBvcnQge2RpZmZBdENhcmV0LCBkaWZmRGVsZXRpb24sIElEaWZmfSBmcm9tIFwiLi9kaWZmXCI7XG5pbXBvcnQgRG9jdW1lbnRQb3NpdGlvbiwge0lQb3NpdGlvbn0gZnJvbSBcIi4vcG9zaXRpb25cIjtcbmltcG9ydCBSYW5nZSBmcm9tIFwiLi9yYW5nZVwiO1xuaW1wb3J0IHtTZXJpYWxpemVkUGFydCwgUGFydCwgUGFydENyZWF0b3J9IGZyb20gXCIuL3BhcnRzXCI7XG5pbXBvcnQgQXV0b2NvbXBsZXRlV3JhcHBlck1vZGVsLCB7SUNhbGxiYWNrfSBmcm9tIFwiLi9hdXRvY29tcGxldGVcIjtcbmltcG9ydCBEb2N1bWVudE9mZnNldCBmcm9tIFwiLi9vZmZzZXRcIjtcbmltcG9ydCB7Q2FyZXR9IGZyb20gXCIuL2NhcmV0XCI7XG5cbi8qKlxuICogQGNhbGxiYWNrIE1vZGVsQ2FsbGJhY2tcbiAqIEBwYXJhbSB7RG9jdW1lbnRQb3NpdGlvbj99IGNhcmV0UG9zaXRpb24gdGhlIHBvc2l0aW9uIHdoZXJlIHRoZSBjYXJldCBzaG91bGQgYmUgcG9zaXRpb25cbiAqIEBwYXJhbSB7c3RyaW5nP30gaW5wdXRUeXBlIHRoZSBpbnB1dFR5cGUgb2YgdGhlIERPTSBpbnB1dCBldmVudFxuICogQHBhcmFtIHtvYmplY3Q/fSBkaWZmIGFuIG9iamVjdCB3aXRoIGByZW1vdmVkYCBhbmQgYGFkZGVkYCBzdHJpbmdzXG4gKi9cblxuLyoqXG4gKiBAY2FsbGJhY2sgVHJhbnNmb3JtQ2FsbGJhY2tcbiAqIEBwYXJhbSB7RG9jdW1lbnRQb3NpdGlvbj99IGNhcmV0UG9zaXRpb24gdGhlIHBvc2l0aW9uIHdoZXJlIHRoZSBjYXJldCBzaG91bGQgYmUgcG9zaXRpb25cbiAqIEBwYXJhbSB7c3RyaW5nP30gaW5wdXRUeXBlIHRoZSBpbnB1dFR5cGUgb2YgdGhlIERPTSBpbnB1dCBldmVudFxuICogQHBhcmFtIHtvYmplY3Q/fSBkaWZmIGFuIG9iamVjdCB3aXRoIGByZW1vdmVkYCBhbmQgYGFkZGVkYCBzdHJpbmdzXG4gKiBAcmV0dXJuIHtOdW1iZXI/fSBhZGRlZExlbiBob3cgbWFueSBjaGFyYWN0ZXJzIHdlcmUgYWRkZWQvcmVtb3ZlZCAoLSkgYmVmb3JlIHRoZSBjYXJldCBkdXJpbmcgdGhlIHRyYW5zZm9ybWF0aW9uIHN0ZXAuXG4gKiAgICBUaGlzIGlzIHVzZWQgdG8gYWRqdXN0IHRoZSBjYXJldCBwb3NpdGlvbi5cbiAqL1xuXG4vKipcbiAqIEBjYWxsYmFjayBNYW51YWxUcmFuc2Zvcm1DYWxsYmFja1xuICogQHJldHVybiB0aGUgY2FyZXQgcG9zaXRpb25cbiAqL1xuXG50eXBlIFRyYW5zZm9ybUNhbGxiYWNrID0gKGNhcmV0UG9zaXRpb246IERvY3VtZW50UG9zaXRpb24sIGlucHV0VHlwZTogc3RyaW5nLCBkaWZmOiBJRGlmZikgPT4gbnVtYmVyIHwgdm9pZDtcbnR5cGUgVXBkYXRlQ2FsbGJhY2sgPSAoY2FyZXQ6IENhcmV0LCBpbnB1dFR5cGU/OiBzdHJpbmcsIGRpZmY/OiBJRGlmZikgPT4gdm9pZDtcbnR5cGUgTWFudWFsVHJhbnNmb3JtQ2FsbGJhY2sgPSAoKSA9PiBDYXJldDtcblxuZXhwb3J0IGRlZmF1bHQgY2xhc3MgRWRpdG9yTW9kZWwge1xuICAgIHByaXZhdGUgX3BhcnRzOiBQYXJ0W107XG4gICAgcHJpdmF0ZSByZWFkb25seSBfcGFydENyZWF0b3I6IFBhcnRDcmVhdG9yO1xuICAgIHByaXZhdGUgYWN0aXZlUGFydElkeDogbnVtYmVyID0gbnVsbDtcbiAgICBwcml2YXRlIF9hdXRvQ29tcGxldGU6IEF1dG9jb21wbGV0ZVdyYXBwZXJNb2RlbCA9IG51bGw7XG4gICAgcHJpdmF0ZSBhdXRvQ29tcGxldGVQYXJ0SWR4OiBudW1iZXIgPSBudWxsO1xuICAgIHByaXZhdGUgYXV0b0NvbXBsZXRlUGFydENvdW50ID0gMDtcbiAgICBwcml2YXRlIHRyYW5zZm9ybUNhbGxiYWNrOiBUcmFuc2Zvcm1DYWxsYmFjayA9IG51bGw7XG5cbiAgICBjb25zdHJ1Y3RvcihwYXJ0czogUGFydFtdLCBwYXJ0Q3JlYXRvcjogUGFydENyZWF0b3IsIHByaXZhdGUgdXBkYXRlQ2FsbGJhY2s6IFVwZGF0ZUNhbGxiYWNrID0gbnVsbCkge1xuICAgICAgICB0aGlzLl9wYXJ0cyA9IHBhcnRzO1xuICAgICAgICB0aGlzLl9wYXJ0Q3JlYXRvciA9IHBhcnRDcmVhdG9yO1xuICAgICAgICB0aGlzLnRyYW5zZm9ybUNhbGxiYWNrID0gbnVsbDtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBTZXQgYSBjYWxsYmFjayBmb3IgdGhlIHRyYW5zZm9ybWF0aW9uIHN0ZXAuXG4gICAgICogV2hpbGUgcHJvY2Vzc2luZyBhbiB1cGRhdGUsIHJpZ2h0IGJlZm9yZSBjYWxsaW5nIHRoZSB1cGRhdGUgY2FsbGJhY2ssXG4gICAgICogYSB0cmFuc2Zvcm0gY2FsbGJhY2sgY2FuIGJlIGNhbGxlZCwgd2hpY2ggc2VydmVzIHRvIGRvIG1vZGlmaWNhdGlvbnNcbiAgICAgKiBvbiB0aGUgbW9kZWwgdGhhdCBjYW4gc3BhbiBtdWx0aXBsZSBwYXJ0cy4gQWxzbyBzZWUgYHN0YXJ0UmFuZ2UoKWAuXG4gICAgICogQHBhcmFtIHtUcmFuc2Zvcm1DYWxsYmFja30gdHJhbnNmb3JtQ2FsbGJhY2tcbiAgICAgKi9cbiAgICBzZXRUcmFuc2Zvcm1DYWxsYmFjayh0cmFuc2Zvcm1DYWxsYmFjazogVHJhbnNmb3JtQ2FsbGJhY2spIHtcbiAgICAgICAgdGhpcy50cmFuc2Zvcm1DYWxsYmFjayA9IHRyYW5zZm9ybUNhbGxiYWNrO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFNldCBhIGNhbGxiYWNrIGZvciByZXJlbmRlcmluZyB0aGUgbW9kZWwgYWZ0ZXIgaXQgaGFzIGJlZW4gdXBkYXRlZC5cbiAgICAgKiBAcGFyYW0ge01vZGVsQ2FsbGJhY2t9IHVwZGF0ZUNhbGxiYWNrXG4gICAgICovXG4gICAgc2V0VXBkYXRlQ2FsbGJhY2sodXBkYXRlQ2FsbGJhY2s6IFVwZGF0ZUNhbGxiYWNrKSB7XG4gICAgICAgIHRoaXMudXBkYXRlQ2FsbGJhY2sgPSB1cGRhdGVDYWxsYmFjaztcbiAgICB9XG5cbiAgICBnZXQgcGFydENyZWF0b3IoKSB7XG4gICAgICAgIHJldHVybiB0aGlzLl9wYXJ0Q3JlYXRvcjtcbiAgICB9XG5cbiAgICBnZXQgaXNFbXB0eSgpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuX3BhcnRzLnJlZHVjZSgobGVuLCBwYXJ0KSA9PiBsZW4gKyBwYXJ0LnRleHQubGVuZ3RoLCAwKSA9PT0gMDtcbiAgICB9XG5cbiAgICBjbG9uZSgpIHtcbiAgICAgICAgcmV0dXJuIG5ldyBFZGl0b3JNb2RlbCh0aGlzLl9wYXJ0cywgdGhpcy5fcGFydENyZWF0b3IsIHRoaXMudXBkYXRlQ2FsbGJhY2spO1xuICAgIH1cblxuICAgIHByaXZhdGUgaW5zZXJ0UGFydChpbmRleDogbnVtYmVyLCBwYXJ0OiBQYXJ0KSB7XG4gICAgICAgIHRoaXMuX3BhcnRzLnNwbGljZShpbmRleCwgMCwgcGFydCk7XG4gICAgICAgIGlmICh0aGlzLmFjdGl2ZVBhcnRJZHggPj0gaW5kZXgpIHtcbiAgICAgICAgICAgICsrdGhpcy5hY3RpdmVQYXJ0SWR4O1xuICAgICAgICB9XG4gICAgICAgIGlmICh0aGlzLmF1dG9Db21wbGV0ZVBhcnRJZHggPj0gaW5kZXgpIHtcbiAgICAgICAgICAgICsrdGhpcy5hdXRvQ29tcGxldGVQYXJ0SWR4O1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgcHJpdmF0ZSByZW1vdmVQYXJ0KGluZGV4OiBudW1iZXIpIHtcbiAgICAgICAgdGhpcy5fcGFydHMuc3BsaWNlKGluZGV4LCAxKTtcbiAgICAgICAgaWYgKGluZGV4ID09PSB0aGlzLmFjdGl2ZVBhcnRJZHgpIHtcbiAgICAgICAgICAgIHRoaXMuYWN0aXZlUGFydElkeCA9IG51bGw7XG4gICAgICAgIH0gZWxzZSBpZiAodGhpcy5hY3RpdmVQYXJ0SWR4ID4gaW5kZXgpIHtcbiAgICAgICAgICAgIC0tdGhpcy5hY3RpdmVQYXJ0SWR4O1xuICAgICAgICB9XG4gICAgICAgIGlmIChpbmRleCA9PT0gdGhpcy5hdXRvQ29tcGxldGVQYXJ0SWR4KSB7XG4gICAgICAgICAgICB0aGlzLmF1dG9Db21wbGV0ZVBhcnRJZHggPSBudWxsO1xuICAgICAgICB9IGVsc2UgaWYgKHRoaXMuYXV0b0NvbXBsZXRlUGFydElkeCA+IGluZGV4KSB7XG4gICAgICAgICAgICAtLXRoaXMuYXV0b0NvbXBsZXRlUGFydElkeDtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHByaXZhdGUgcmVwbGFjZVBhcnQoaW5kZXg6IG51bWJlciwgcGFydDogUGFydCkge1xuICAgICAgICB0aGlzLl9wYXJ0cy5zcGxpY2UoaW5kZXgsIDEsIHBhcnQpO1xuICAgIH1cblxuICAgIGdldCBwYXJ0cygpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuX3BhcnRzO1xuICAgIH1cblxuICAgIGdldCBhdXRvQ29tcGxldGUoKSB7XG4gICAgICAgIGlmICh0aGlzLmFjdGl2ZVBhcnRJZHggPT09IHRoaXMuYXV0b0NvbXBsZXRlUGFydElkeCkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMuX2F1dG9Db21wbGV0ZTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gbnVsbDtcbiAgICB9XG5cbiAgICBnZXRQb3NpdGlvbkF0RW5kKCkge1xuICAgICAgICBpZiAodGhpcy5fcGFydHMubGVuZ3RoKSB7XG4gICAgICAgICAgICBjb25zdCBpbmRleCA9IHRoaXMuX3BhcnRzLmxlbmd0aCAtIDE7XG4gICAgICAgICAgICBjb25zdCBwYXJ0ID0gdGhpcy5fcGFydHNbaW5kZXhdO1xuICAgICAgICAgICAgcmV0dXJuIG5ldyBEb2N1bWVudFBvc2l0aW9uKGluZGV4LCBwYXJ0LnRleHQubGVuZ3RoKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIC8vIHBhcnQgaW5kZXggLTEsIGFzIHRoZXJlIGFyZSBubyBwYXJ0cyB0byBwb2ludCBhdFxuICAgICAgICAgICAgcmV0dXJuIG5ldyBEb2N1bWVudFBvc2l0aW9uKC0xLCAwKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHNlcmlhbGl6ZVBhcnRzKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5fcGFydHMubWFwKHAgPT4gcC5zZXJpYWxpemUoKSk7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBkaWZmKG5ld1ZhbHVlOiBzdHJpbmcsIGlucHV0VHlwZTogc3RyaW5nLCBjYXJldDogRG9jdW1lbnRPZmZzZXQpIHtcbiAgICAgICAgY29uc3QgcHJldmlvdXNWYWx1ZSA9IHRoaXMucGFydHMucmVkdWNlKCh0ZXh0LCBwKSA9PiB0ZXh0ICsgcC50ZXh0LCBcIlwiKTtcbiAgICAgICAgLy8gY2FuJ3QgdXNlIGNhcmV0IHBvc2l0aW9uIHdpdGggZHJhZyBhbmQgZHJvcFxuICAgICAgICBpZiAoaW5wdXRUeXBlID09PSBcImRlbGV0ZUJ5RHJhZ1wiKSB7XG4gICAgICAgICAgICByZXR1cm4gZGlmZkRlbGV0aW9uKHByZXZpb3VzVmFsdWUsIG5ld1ZhbHVlKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHJldHVybiBkaWZmQXRDYXJldChwcmV2aW91c1ZhbHVlLCBuZXdWYWx1ZSwgY2FyZXQub2Zmc2V0KTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHJlc2V0KHNlcmlhbGl6ZWRQYXJ0czogU2VyaWFsaXplZFBhcnRbXSwgY2FyZXQ/OiBDYXJldCwgaW5wdXRUeXBlPzogc3RyaW5nKSB7XG4gICAgICAgIHRoaXMuX3BhcnRzID0gc2VyaWFsaXplZFBhcnRzLm1hcChwID0+IHRoaXMuX3BhcnRDcmVhdG9yLmRlc2VyaWFsaXplUGFydChwKSk7XG4gICAgICAgIGlmICghY2FyZXQpIHtcbiAgICAgICAgICAgIGNhcmV0ID0gdGhpcy5nZXRQb3NpdGlvbkF0RW5kKCk7XG4gICAgICAgIH1cbiAgICAgICAgLy8gY2xvc2UgYXV0byBjb21wbGV0ZSBpZiBvcGVuXG4gICAgICAgIC8vIHRoaXMgd291bGQgaGFwcGVuIHdoZW4gY2xlYXJpbmcgdGhlIGNvbXBvc2VyIGFmdGVyIHNlbmRpbmdcbiAgICAgICAgLy8gYSBtZXNzYWdlIHdpdGggdGhlIGF1dG9jb21wbGV0ZSBzdGlsbCBvcGVuXG4gICAgICAgIGlmICh0aGlzLl9hdXRvQ29tcGxldGUpIHtcbiAgICAgICAgICAgIHRoaXMuX2F1dG9Db21wbGV0ZSA9IG51bGw7XG4gICAgICAgICAgICB0aGlzLmF1dG9Db21wbGV0ZVBhcnRJZHggPSBudWxsO1xuICAgICAgICB9XG4gICAgICAgIHRoaXMudXBkYXRlQ2FsbGJhY2soY2FyZXQsIGlucHV0VHlwZSk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogSW5zZXJ0cyB0aGUgZ2l2ZW4gcGFydHMgYXQgdGhlIGdpdmVuIHBvc2l0aW9uLlxuICAgICAqIFNob3VsZCBiZSBydW4gaW5zaWRlIGEgYG1vZGVsLnRyYW5zZm9ybSgpYCBjYWxsYmFjay5cbiAgICAgKiBAcGFyYW0ge1BhcnRbXX0gcGFydHMgdGhlIHBhcnRzIHRvIHJlcGxhY2UgdGhlIHJhbmdlIHdpdGhcbiAgICAgKiBAcGFyYW0ge0RvY3VtZW50UG9zaXRpb259IHBvc2l0aW9uIHRoZSBwb3NpdGlvbiB0byBzdGFydCBpbnNlcnRpbmcgYXRcbiAgICAgKiBAcmV0dXJuIHtOdW1iZXJ9IHRoZSBhbW91bnQgb2YgY2hhcmFjdGVycyBhZGRlZFxuICAgICAqL1xuICAgIGluc2VydChwYXJ0czogUGFydFtdLCBwb3NpdGlvbjogSVBvc2l0aW9uKSB7XG4gICAgICAgIGNvbnN0IGluc2VydEluZGV4ID0gdGhpcy5zcGxpdEF0KHBvc2l0aW9uKTtcbiAgICAgICAgbGV0IG5ld1RleHRMZW5ndGggPSAwO1xuICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHBhcnRzLmxlbmd0aDsgKytpKSB7XG4gICAgICAgICAgICBjb25zdCBwYXJ0ID0gcGFydHNbaV07XG4gICAgICAgICAgICBuZXdUZXh0TGVuZ3RoICs9IHBhcnQudGV4dC5sZW5ndGg7XG4gICAgICAgICAgICB0aGlzLmluc2VydFBhcnQoaW5zZXJ0SW5kZXggKyBpLCBwYXJ0KTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gbmV3VGV4dExlbmd0aDtcbiAgICB9XG5cbiAgICB1cGRhdGUobmV3VmFsdWU6IHN0cmluZywgaW5wdXRUeXBlOiBzdHJpbmcsIGNhcmV0OiBEb2N1bWVudE9mZnNldCkge1xuICAgICAgICBjb25zdCBkaWZmID0gdGhpcy5kaWZmKG5ld1ZhbHVlLCBpbnB1dFR5cGUsIGNhcmV0KTtcbiAgICAgICAgY29uc3QgcG9zaXRpb24gPSB0aGlzLnBvc2l0aW9uRm9yT2Zmc2V0KGRpZmYuYXQsIGNhcmV0LmF0Tm9kZUVuZCk7XG4gICAgICAgIGxldCByZW1vdmVkT2Zmc2V0RGVjcmVhc2UgPSAwO1xuICAgICAgICBpZiAoZGlmZi5yZW1vdmVkKSB7XG4gICAgICAgICAgICByZW1vdmVkT2Zmc2V0RGVjcmVhc2UgPSB0aGlzLnJlbW92ZVRleHQocG9zaXRpb24sIGRpZmYucmVtb3ZlZC5sZW5ndGgpO1xuICAgICAgICB9XG4gICAgICAgIGxldCBhZGRlZExlbiA9IDA7XG4gICAgICAgIGlmIChkaWZmLmFkZGVkKSB7XG4gICAgICAgICAgICBhZGRlZExlbiA9IHRoaXMuYWRkVGV4dChwb3NpdGlvbiwgZGlmZi5hZGRlZCwgaW5wdXRUeXBlKTtcbiAgICAgICAgfVxuICAgICAgICB0aGlzLm1lcmdlQWRqYWNlbnRQYXJ0cygpO1xuICAgICAgICBjb25zdCBjYXJldE9mZnNldCA9IGRpZmYuYXQgLSByZW1vdmVkT2Zmc2V0RGVjcmVhc2UgKyBhZGRlZExlbjtcbiAgICAgICAgbGV0IG5ld1Bvc2l0aW9uID0gdGhpcy5wb3NpdGlvbkZvck9mZnNldChjYXJldE9mZnNldCwgdHJ1ZSk7XG4gICAgICAgIGNvbnN0IGNhbk9wZW5BdXRvQ29tcGxldGUgPSBpbnB1dFR5cGUgIT09IFwiaW5zZXJ0RnJvbVBhc3RlXCIgJiYgaW5wdXRUeXBlICE9PSBcImluc2VydEZyb21Ecm9wXCI7XG4gICAgICAgIGNvbnN0IGFjUHJvbWlzZSA9IHRoaXMuc2V0QWN0aXZlUGFydChuZXdQb3NpdGlvbiwgY2FuT3BlbkF1dG9Db21wbGV0ZSk7XG4gICAgICAgIGlmICh0aGlzLnRyYW5zZm9ybUNhbGxiYWNrKSB7XG4gICAgICAgICAgICBjb25zdCB0cmFuc2Zvcm1BZGRlZExlbiA9IHRoaXMuZ2V0VHJhbnNmb3JtQWRkZWRMZW4obmV3UG9zaXRpb24sIGlucHV0VHlwZSwgZGlmZik7XG4gICAgICAgICAgICBuZXdQb3NpdGlvbiA9IHRoaXMucG9zaXRpb25Gb3JPZmZzZXQoY2FyZXRPZmZzZXQgKyB0cmFuc2Zvcm1BZGRlZExlbiwgdHJ1ZSk7XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy51cGRhdGVDYWxsYmFjayhuZXdQb3NpdGlvbiwgaW5wdXRUeXBlLCBkaWZmKTtcbiAgICAgICAgcmV0dXJuIGFjUHJvbWlzZTtcbiAgICB9XG5cbiAgICBwcml2YXRlIGdldFRyYW5zZm9ybUFkZGVkTGVuKG5ld1Bvc2l0aW9uOiBEb2N1bWVudFBvc2l0aW9uLCBpbnB1dFR5cGU6IHN0cmluZywgZGlmZjogSURpZmYpOiBudW1iZXIge1xuICAgICAgICBjb25zdCByZXN1bHQgPSB0aGlzLnRyYW5zZm9ybUNhbGxiYWNrKG5ld1Bvc2l0aW9uLCBpbnB1dFR5cGUsIGRpZmYpO1xuICAgICAgICByZXR1cm4gTnVtYmVyLmlzRmluaXRlKHJlc3VsdCkgPyByZXN1bHQgYXMgbnVtYmVyIDogMDtcbiAgICB9XG5cbiAgICBwcml2YXRlIHNldEFjdGl2ZVBhcnQocG9zOiBEb2N1bWVudFBvc2l0aW9uLCBjYW5PcGVuQXV0b0NvbXBsZXRlOiBib29sZWFuKSB7XG4gICAgICAgIGNvbnN0IHtpbmRleH0gPSBwb3M7XG4gICAgICAgIGNvbnN0IHBhcnQgPSB0aGlzLl9wYXJ0c1tpbmRleF07XG4gICAgICAgIGlmIChwYXJ0KSB7XG4gICAgICAgICAgICBpZiAoaW5kZXggIT09IHRoaXMuYWN0aXZlUGFydElkeCkge1xuICAgICAgICAgICAgICAgIHRoaXMuYWN0aXZlUGFydElkeCA9IGluZGV4O1xuICAgICAgICAgICAgICAgIGlmIChjYW5PcGVuQXV0b0NvbXBsZXRlICYmIHRoaXMuYWN0aXZlUGFydElkeCAhPT0gdGhpcy5hdXRvQ29tcGxldGVQYXJ0SWR4KSB7XG4gICAgICAgICAgICAgICAgICAgIC8vIGVsc2UgdHJ5IHRvIGNyZWF0ZSBvbmVcbiAgICAgICAgICAgICAgICAgICAgY29uc3QgYWMgPSBwYXJ0LmNyZWF0ZUF1dG9Db21wbGV0ZSh0aGlzLm9uQXV0b0NvbXBsZXRlKTtcbiAgICAgICAgICAgICAgICAgICAgaWYgKGFjKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBtYWtlIHN1cmUgdGhhdCByZWFjdCBwaWNrcyB1cCB0aGUgZGlmZmVyZW5jZSBiZXR3ZWVuIGJvdGggYWNzXG4gICAgICAgICAgICAgICAgICAgICAgICB0aGlzLl9hdXRvQ29tcGxldGUgPSBhYztcbiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMuYXV0b0NvbXBsZXRlUGFydElkeCA9IGluZGV4O1xuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5hdXRvQ29tcGxldGVQYXJ0Q291bnQgPSAxO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgLy8gbm90IF9hdXRvQ29tcGxldGUsIG9ubHkgdGhlcmUgaWYgYWN0aXZlIHBhcnQgaXMgYXV0b2NvbXBsZXRlIHBhcnRcbiAgICAgICAgICAgIGlmICh0aGlzLmF1dG9Db21wbGV0ZSkge1xuICAgICAgICAgICAgICAgIHJldHVybiB0aGlzLmF1dG9Db21wbGV0ZS5vblBhcnRVcGRhdGUocGFydCwgcG9zKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHRoaXMuYWN0aXZlUGFydElkeCA9IG51bGw7XG4gICAgICAgICAgICB0aGlzLl9hdXRvQ29tcGxldGUgPSBudWxsO1xuICAgICAgICAgICAgdGhpcy5hdXRvQ29tcGxldGVQYXJ0SWR4ID0gbnVsbDtcbiAgICAgICAgICAgIHRoaXMuYXV0b0NvbXBsZXRlUGFydENvdW50ID0gMDtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gUHJvbWlzZS5yZXNvbHZlKCk7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBvbkF1dG9Db21wbGV0ZSA9ICh7cmVwbGFjZVBhcnRzLCBjbG9zZX06IElDYWxsYmFjaykgPT4ge1xuICAgICAgICBsZXQgcG9zO1xuICAgICAgICBpZiAocmVwbGFjZVBhcnRzKSB7XG4gICAgICAgICAgICB0aGlzLl9wYXJ0cy5zcGxpY2UodGhpcy5hdXRvQ29tcGxldGVQYXJ0SWR4LCB0aGlzLmF1dG9Db21wbGV0ZVBhcnRDb3VudCwgLi4ucmVwbGFjZVBhcnRzKTtcbiAgICAgICAgICAgIHRoaXMuYXV0b0NvbXBsZXRlUGFydENvdW50ID0gcmVwbGFjZVBhcnRzLmxlbmd0aDtcbiAgICAgICAgICAgIGNvbnN0IGxhc3RQYXJ0ID0gcmVwbGFjZVBhcnRzW3JlcGxhY2VQYXJ0cy5sZW5ndGggLSAxXTtcbiAgICAgICAgICAgIGNvbnN0IGxhc3RQYXJ0SW5kZXggPSB0aGlzLmF1dG9Db21wbGV0ZVBhcnRJZHggKyByZXBsYWNlUGFydHMubGVuZ3RoIC0gMTtcbiAgICAgICAgICAgIHBvcyA9IG5ldyBEb2N1bWVudFBvc2l0aW9uKGxhc3RQYXJ0SW5kZXgsIGxhc3RQYXJ0LnRleHQubGVuZ3RoKTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoY2xvc2UpIHtcbiAgICAgICAgICAgIHRoaXMuX2F1dG9Db21wbGV0ZSA9IG51bGw7XG4gICAgICAgICAgICB0aGlzLmF1dG9Db21wbGV0ZVBhcnRJZHggPSBudWxsO1xuICAgICAgICAgICAgdGhpcy5hdXRvQ29tcGxldGVQYXJ0Q291bnQgPSAwO1xuICAgICAgICB9XG4gICAgICAgIC8vIHJlcmVuZGVyIGV2ZW4gaWYgZWRpdG9yIGNvbnRlbnRzIGRpZG4ndCBjaGFuZ2VcbiAgICAgICAgLy8gdG8gbWFrZSBzdXJlIHRoZSBNZXNzYWdlRWRpdG9yIGNoZWNrc1xuICAgICAgICAvLyBtb2RlbC5hdXRvQ29tcGxldGUgYmVpbmcgZW1wdHkgYW5kIGNsb3NlcyBpdFxuICAgICAgICB0aGlzLnVwZGF0ZUNhbGxiYWNrKHBvcyk7XG4gICAgfTtcblxuICAgIHByaXZhdGUgbWVyZ2VBZGphY2VudFBhcnRzKCkge1xuICAgICAgICBsZXQgcHJldlBhcnQ7XG4gICAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgdGhpcy5fcGFydHMubGVuZ3RoOyArK2kpIHtcbiAgICAgICAgICAgIGxldCBwYXJ0ID0gdGhpcy5fcGFydHNbaV07XG4gICAgICAgICAgICBjb25zdCBpc0VtcHR5ID0gIXBhcnQudGV4dC5sZW5ndGg7XG4gICAgICAgICAgICBjb25zdCBpc01lcmdlZCA9ICFpc0VtcHR5ICYmIHByZXZQYXJ0ICYmIHByZXZQYXJ0Lm1lcmdlKHBhcnQpO1xuICAgICAgICAgICAgaWYgKGlzRW1wdHkgfHwgaXNNZXJnZWQpIHtcbiAgICAgICAgICAgICAgICAvLyByZW1vdmUgZW1wdHkgb3IgbWVyZ2VkIHBhcnRcbiAgICAgICAgICAgICAgICBwYXJ0ID0gcHJldlBhcnQ7XG4gICAgICAgICAgICAgICAgdGhpcy5yZW1vdmVQYXJ0KGkpO1xuICAgICAgICAgICAgICAgIC8vcmVwZWF0IHRoaXMgaW5kZXgsIGFzIGl0J3MgcmVtb3ZlZCBub3dcbiAgICAgICAgICAgICAgICAtLWk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBwcmV2UGFydCA9IHBhcnQ7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiByZW1vdmVzIGBsZW5gIGFtb3VudCBvZiBjaGFyYWN0ZXJzIGF0IGBwb3NgLlxuICAgICAqIEBwYXJhbSB7T2JqZWN0fSBwb3NcbiAgICAgKiBAcGFyYW0ge051bWJlcn0gbGVuXG4gICAgICogQHJldHVybiB7TnVtYmVyfSBob3cgbWFueSBjaGFyYWN0ZXJzIGJlZm9yZSBwb3Mgd2VyZSBhbHNvIHJlbW92ZWQsXG4gICAgICogdXN1YWxseSBiZWNhdXNlIG9mIG5vbi1lZGl0YWJsZSBwYXJ0cyB0aGF0IGNhbiBvbmx5IGJlIHJlbW92ZWQgaW4gdGhlaXIgZW50aXJldHkuXG4gICAgICovXG4gICAgcmVtb3ZlVGV4dChwb3M6IElQb3NpdGlvbiwgbGVuOiBudW1iZXIpIHtcbiAgICAgICAgbGV0IHtpbmRleCwgb2Zmc2V0fSA9IHBvcztcbiAgICAgICAgbGV0IHJlbW92ZWRPZmZzZXREZWNyZWFzZSA9IDA7XG4gICAgICAgIHdoaWxlIChsZW4gPiAwKSB7XG4gICAgICAgICAgICAvLyBwYXJ0IG1pZ2h0IGJlIHVuZGVmaW5lZCBoZXJlXG4gICAgICAgICAgICBsZXQgcGFydCA9IHRoaXMuX3BhcnRzW2luZGV4XTtcbiAgICAgICAgICAgIGNvbnN0IGFtb3VudCA9IE1hdGgubWluKGxlbiwgcGFydC50ZXh0Lmxlbmd0aCAtIG9mZnNldCk7XG4gICAgICAgICAgICAvLyBkb24ndCBhbGxvdyAwIGFtb3VudCBkZWxldGlvbnNcbiAgICAgICAgICAgIGlmIChhbW91bnQpIHtcbiAgICAgICAgICAgICAgICBpZiAocGFydC5jYW5FZGl0KSB7XG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IHJlcGxhY2VXaXRoID0gcGFydC5yZW1vdmUob2Zmc2V0LCBhbW91bnQpO1xuICAgICAgICAgICAgICAgICAgICBpZiAodHlwZW9mIHJlcGxhY2VXaXRoID09PSBcInN0cmluZ1wiKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICB0aGlzLnJlcGxhY2VQYXJ0KGluZGV4LCB0aGlzLl9wYXJ0Q3JlYXRvci5jcmVhdGVEZWZhdWx0UGFydChyZXBsYWNlV2l0aCkpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIHBhcnQgPSB0aGlzLl9wYXJ0c1tpbmRleF07XG4gICAgICAgICAgICAgICAgICAgIC8vIHJlbW92ZSBlbXB0eSBwYXJ0XG4gICAgICAgICAgICAgICAgICAgIGlmICghcGFydC50ZXh0Lmxlbmd0aCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5yZW1vdmVQYXJ0KGluZGV4KTtcbiAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGluZGV4ICs9IDE7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICByZW1vdmVkT2Zmc2V0RGVjcmVhc2UgKz0gb2Zmc2V0O1xuICAgICAgICAgICAgICAgICAgICB0aGlzLnJlbW92ZVBhcnQoaW5kZXgpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgaW5kZXggKz0gMTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGxlbiAtPSBhb