UNPKG

matrix-react-sdk

Version:
553 lines (540 loc) 74.3 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.Type = exports.PlainPart = exports.PillPart = exports.PartCreator = exports.EmojiPart = exports.CommandPartCreator = void 0; exports.getAutoCompleteCreator = getAutoCompleteCreator; var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty")); var _autocomplete = _interopRequireDefault(require("./autocomplete")); var _HtmlUtils = require("../HtmlUtils"); var Avatar = _interopRequireWildcard(require("../Avatar")); var _dispatcher = _interopRequireDefault(require("../dispatcher/dispatcher")); var _actions = require("../dispatcher/actions"); var _SettingsStore = _interopRequireDefault(require("../settings/SettingsStore")); var _strings = require("../utils/strings"); function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); } function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; } /* Copyright 2019-2024 New Vector Ltd. Copyright 2019 The Matrix.org Foundation C.I.C. SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only Please see LICENSE files in the repository root for full details. */ const REGIONAL_EMOJI_SEPARATOR = String.fromCodePoint(0x200b); let Type = exports.Type = /*#__PURE__*/function (Type) { Type["Plain"] = "plain"; Type["Newline"] = "newline"; Type["Emoji"] = "emoji"; Type["Command"] = "command"; Type["UserPill"] = "user-pill"; Type["RoomPill"] = "room-pill"; Type["AtRoomPill"] = "at-room-pill"; Type["PillCandidate"] = "pill-candidate"; return Type; }({}); class BasePart { constructor(text = "") { (0, _defineProperty2.default)(this, "_text", void 0); this._text = text; } // chr can also be a grapheme cluster acceptsInsertion(chr, offset, inputType) { return true; } acceptsRemoval(position, chr) { return true; } merge(part) { return false; } split(offset) { const splitText = this.text.slice(offset); this._text = this.text.slice(0, offset); return new PlainPart(splitText); } // removes len chars, or returns the plain text this part should be replaced with // if the part would become invalid if it removed everything. remove(offset, len) { // validate const strWithRemoval = this.text.slice(0, offset) + this.text.slice(offset + len); for (let i = offset; i < len + offset; ++i) { const chr = this.text.charAt(i); if (!this.acceptsRemoval(i, chr)) { return strWithRemoval; } } this._text = strWithRemoval; } // append str, returns the remaining string if a character was rejected. appendUntilRejected(str, inputType) { const offset = this.text.length; // Take a copy as we will be taking chunks off the start of the string as we process them // To only need to grapheme split the bits of the string we're working on. let buffer = str; while (buffer) { const char = (0, _strings.getFirstGrapheme)(buffer); if (!this.acceptsInsertion(char, offset + str.length - buffer.length, inputType)) { break; } buffer = buffer.slice(char.length); } this._text += str.slice(0, str.length - buffer.length); return buffer || undefined; } // inserts str at offset if all the characters in str were accepted, otherwise don't do anything // return whether the str was accepted or not. validateAndInsert(offset, str, inputType) { for (let i = 0; i < str.length; ++i) { const chr = str.charAt(i); if (!this.acceptsInsertion(chr, offset + i, inputType)) { return false; } } const beforeInsert = this._text.slice(0, offset); const afterInsert = this._text.slice(offset); this._text = beforeInsert + str + afterInsert; return true; } createAutoComplete(updateCallback) {} trim(len) { const remaining = this._text.slice(len); this._text = this._text.slice(0, len); return remaining; } get text() { return this._text; } get canEdit() { return true; } get acceptsCaret() { return this.canEdit; } toString() { return `${this.type}(${this.text})`; } serialize() { return { type: this.type, text: this.text }; } } class PlainBasePart extends BasePart { acceptsInsertion(chr, offset, inputType) { if (chr === "\n" || _HtmlUtils.EMOJI_REGEX.test(chr)) { return false; } // when not pasting or dropping text, reject characters that should start a pill candidate if (inputType !== "insertFromPaste" && inputType !== "insertFromDrop") { if (chr !== "@" && chr !== "#" && chr !== ":" && chr !== "+") { return true; } // split if we are at the beginning of the part text if (offset === 0) { return false; } // or split if the previous character is a space or regional emoji separator // or if it is a + and this is a : return this._text[offset - 1] !== " " && this._text[offset - 1] !== REGIONAL_EMOJI_SEPARATOR && (this._text[offset - 1] !== "+" || chr !== ":"); } return true; } toDOMNode() { return document.createTextNode(this.text); } merge(part) { if (part.type === this.type) { this._text = this.text + part.text; return true; } return false; } updateDOMNode(node) { if (node.textContent !== this.text) { node.textContent = this.text; } } canUpdateDOMNode(node) { return node.nodeType === Node.TEXT_NODE; } } // exported for unit tests, should otherwise only be used through PartCreator class PlainPart extends PlainBasePart { get type() { return Type.Plain; } } exports.PlainPart = PlainPart; class PillPart extends BasePart { constructor(resourceId, label) { super(label); (0, _defineProperty2.default)(this, "onClick", void 0); this.resourceId = resourceId; } acceptsInsertion(chr) { return chr !== " "; } acceptsRemoval(position, chr) { return position !== 0; //if you remove initial # or @, pill should become plain } toDOMNode() { const container = document.createElement("span"); container.setAttribute("spellcheck", "false"); container.setAttribute("contentEditable", "false"); if (this.onClick) container.onclick = this.onClick; container.className = this.className; container.appendChild(document.createTextNode(this.text)); this.setAvatar(container); return container; } updateDOMNode(node) { const textNode = node.childNodes[0]; if (textNode.textContent !== this.text) { textNode.textContent = this.text; } if (node.className !== this.className) { node.className = this.className; } if (this.onClick && node.onclick !== this.onClick) { node.onclick = this.onClick; } this.setAvatar(node); } canUpdateDOMNode(node) { return node.nodeType === Node.ELEMENT_NODE && node.nodeName === "SPAN" && node.childNodes.length === 1 && node.childNodes[0].nodeType === Node.TEXT_NODE; } // helper method for subclasses setAvatarVars(node, avatarUrl, initialLetter) { const avatarBackground = `url('${avatarUrl}')`; const avatarLetter = `'${initialLetter}'`; // check if the value is changing, // otherwise the avatars flicker on every keystroke while updating. if (node.style.getPropertyValue("--avatar-background") !== avatarBackground) { node.style.setProperty("--avatar-background", avatarBackground); } if (node.style.getPropertyValue("--avatar-letter") !== avatarLetter) { node.style.setProperty("--avatar-letter", avatarLetter); } } serialize() { return { type: this.type, text: this.text, resourceId: this.resourceId }; } get canEdit() { return false; } } exports.PillPart = PillPart; class NewlinePart extends BasePart { acceptsInsertion(chr, offset) { return offset === 0 && chr === "\n"; } acceptsRemoval(position, chr) { return true; } toDOMNode() { return document.createElement("br"); } merge() { return false; } updateDOMNode() {} canUpdateDOMNode(node) { return node.tagName === "BR"; } get type() { return Type.Newline; } // this makes the cursor skip this part when it is inserted // rather than trying to append to it, which is what we want. // As a newline can also be only one character, it makes sense // as it can only be one character long. This caused #9741. get canEdit() { return false; } } class EmojiPart extends BasePart { acceptsInsertion(chr, offset) { return _HtmlUtils.EMOJI_REGEX.test(chr); } acceptsRemoval(position, chr) { return false; } toDOMNode() { const span = document.createElement("span"); span.className = "mx_Emoji"; span.setAttribute("title", (0, _HtmlUtils.unicodeToShortcode)(this.text)); span.appendChild(document.createTextNode(this.text)); return span; } updateDOMNode(node) { const textNode = node.childNodes[0]; if (textNode.textContent !== this.text) { node.setAttribute("title", (0, _HtmlUtils.unicodeToShortcode)(this.text)); textNode.textContent = this.text; } } canUpdateDOMNode(node) { return node.className === "mx_Emoji"; } get type() { return Type.Emoji; } get canEdit() { return false; } get acceptsCaret() { return true; } } exports.EmojiPart = EmojiPart; class RoomPillPart extends PillPart { constructor(resourceId, label, room) { super(resourceId, label); this.room = room; } setAvatar(node) { let initialLetter = ""; let avatarUrl = Avatar.avatarUrlForRoom(this.room ?? null, 16, 16, "crop"); if (!avatarUrl) { initialLetter = Avatar.getInitialLetter(this.room?.name || this.resourceId) ?? ""; avatarUrl = Avatar.defaultAvatarUrlForString(this.room?.roomId ?? this.resourceId); } this.setAvatarVars(node, avatarUrl, initialLetter); } get type() { return Type.RoomPill; } get className() { return "mx_Pill " + (this.room?.isSpaceRoom() ? "mx_SpacePill" : "mx_RoomPill"); } } class AtRoomPillPart extends RoomPillPart { constructor(text, room) { super(text, text, room); } get type() { return Type.AtRoomPill; } serialize() { return { type: this.type, text: this.text }; } } class UserPillPart extends PillPart { constructor(userId, displayName, member) { super(userId, displayName); (0, _defineProperty2.default)(this, "onClick", () => { _dispatcher.default.dispatch({ action: _actions.Action.ViewUser, member: this.member }); }); this.member = member; } get type() { return Type.UserPill; } get className() { return "mx_UserPill mx_Pill"; } setAvatar(node) { if (!this.member) { return; } const name = this.member.name || this.member.userId; const defaultAvatarUrl = Avatar.defaultAvatarUrlForString(this.member.userId); const avatarUrl = Avatar.avatarUrlForMember(this.member, 16, 16, "crop"); let initialLetter = ""; if (avatarUrl === defaultAvatarUrl) { initialLetter = Avatar.getInitialLetter(name) ?? ""; } this.setAvatarVars(node, avatarUrl, initialLetter); } } class PillCandidatePart extends PlainBasePart { constructor(text, autoCompleteCreator) { super(text); this.autoCompleteCreator = autoCompleteCreator; } createAutoComplete(updateCallback) { return this.autoCompleteCreator.create?.(updateCallback); } acceptsInsertion(chr, offset, inputType) { if (offset === 0) { return true; } else { return super.acceptsInsertion(chr, offset, inputType); } } merge() { return false; } acceptsRemoval(position, chr) { return true; } get type() { return Type.PillCandidate; } } function getAutoCompleteCreator(getAutocompleterComponent, updateQuery) { return partCreator => { return updateCallback => { return new _autocomplete.default(updateCallback, getAutocompleterComponent, updateQuery, partCreator); }; }; } class PartCreator { constructor(room, client, autoCompleteCreator = null) { (0, _defineProperty2.default)(this, "autoCompleteCreator", void 0); this.room = room; this.client = client; // pre-create the creator as an object even without callback so it can already be passed // to PillCandidatePart (e.g. while deserializing) and set later on this.autoCompleteCreator = { create: autoCompleteCreator?.(this) }; } setAutoCompleteCreator(autoCompleteCreator) { this.autoCompleteCreator.create = autoCompleteCreator(this); } createPartForInput(input, partIndex, inputType) { switch (input[0]) { case "#": case "@": case ":": case "+": return this.pillCandidate(""); case "\n": return new NewlinePart(); default: if (_HtmlUtils.EMOJI_REGEX.test((0, _strings.getFirstGrapheme)(input))) { return new EmojiPart(); } return new PlainPart(); } } createDefaultPart(text) { return this.plain(text); } deserializePart(part) { switch (part.type) { case Type.Plain: return this.plain(part.text); case Type.Newline: return this.newline(); case Type.Emoji: return this.emoji(part.text); case Type.AtRoomPill: return this.atRoomPill(part.text); case Type.PillCandidate: return this.pillCandidate(part.text); case Type.RoomPill: return part.resourceId ? this.roomPill(part.resourceId) : undefined; case Type.UserPill: return part.resourceId ? this.userPill(part.text, part.resourceId) : undefined; } } plain(text) { return new PlainPart(text); } newline() { return new NewlinePart("\n"); } emoji(text) { return new EmojiPart(text); } pillCandidate(text) { return new PillCandidatePart(text, this.autoCompleteCreator); } roomPill(alias, roomId) { let room; if (roomId || alias[0] !== "#") { room = this.client.getRoom(roomId || alias) ?? undefined; } else { room = this.client.getRooms().find(r => { return r.getCanonicalAlias() === alias || r.getAltAliases().includes(alias); }); } return new RoomPillPart(alias, room ? room.name : alias, room); } atRoomPill(text) { return new AtRoomPillPart(text, this.room); } userPill(displayName, userId) { const member = this.room.getMember(userId); return new UserPillPart(userId, displayName, member || undefined); } static isRegionalIndicator(c) { const codePoint = c.codePointAt(0) ?? 0; return codePoint != 0 && c.length == 2 && 0x1f1e6 <= codePoint && codePoint <= 0x1f1ff; } plainWithEmoji(text) { const parts = []; let plainText = ""; for (const data of _strings.graphemeSegmenter.segment(text)) { if (_HtmlUtils.EMOJI_REGEX.test(data.segment)) { if (plainText) { parts.push(this.plain(plainText)); plainText = ""; } parts.push(this.emoji(data.segment)); if (PartCreator.isRegionalIndicator(text)) { parts.push(this.plain(REGIONAL_EMOJI_SEPARATOR)); } } else { plainText += data.segment; } } if (plainText) { parts.push(this.plain(plainText)); } return parts; } createMentionParts(insertTrailingCharacter, displayName, userId) { const pill = this.userPill(displayName, userId); if (!_SettingsStore.default.getValue("MessageComposerInput.insertTrailingColon")) { insertTrailingCharacter = false; } const postfix = this.plain(insertTrailingCharacter ? ": " : " "); return [pill, postfix]; } } // part creator that support auto complete for /commands, // used in SendMessageComposer exports.PartCreator = PartCreator; class CommandPartCreator extends PartCreator { createPartForInput(text, partIndex) { // at beginning and starts with /? create if (partIndex === 0 && text[0] === "/") { // text will be inserted by model, so pass empty string return this.command(""); } else { return super.createPartForInput(text, partIndex); } } command(text) { return new CommandPart(text, this.autoCompleteCreator); } deserializePart(part) { if (part.type === Type.Command) { return this.command(part.text); } else { return super.deserializePart(part); } } } exports.CommandPartCreator = CommandPartCreator; class CommandPart extends PillCandidatePart { get type() { return Type.Command; } } //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfYXV0b2NvbXBsZXRlIiwiX2ludGVyb3BSZXF1aXJlRGVmYXVsdCIsInJlcXVpcmUiLCJfSHRtbFV0aWxzIiwiQXZhdGFyIiwiX2ludGVyb3BSZXF1aXJlV2lsZGNhcmQiLCJfZGlzcGF0Y2hlciIsIl9hY3Rpb25zIiwiX1NldHRpbmdzU3RvcmUiLCJfc3RyaW5ncyIsIl9nZXRSZXF1aXJlV2lsZGNhcmRDYWNoZSIsImUiLCJXZWFrTWFwIiwiciIsInQiLCJfX2VzTW9kdWxlIiwiZGVmYXVsdCIsImhhcyIsImdldCIsIm4iLCJfX3Byb3RvX18iLCJhIiwiT2JqZWN0IiwiZGVmaW5lUHJvcGVydHkiLCJnZXRPd25Qcm9wZXJ0eURlc2NyaXB0b3IiLCJ1IiwiaGFzT3duUHJvcGVydHkiLCJjYWxsIiwiaSIsInNldCIsIlJFR0lPTkFMX0VNT0pJX1NFUEFSQVRPUiIsIlN0cmluZyIsImZyb21Db2RlUG9pbnQiLCJUeXBlIiwiZXhwb3J0cyIsIkJhc2VQYXJ0IiwiY29uc3RydWN0b3IiLCJ0ZXh0IiwiX2RlZmluZVByb3BlcnR5MiIsIl90ZXh0IiwiYWNjZXB0c0luc2VydGlvbiIsImNociIsIm9mZnNldCIsImlucHV0VHlwZSIsImFjY2VwdHNSZW1vdmFsIiwicG9zaXRpb24iLCJtZXJnZSIsInBhcnQiLCJzcGxpdCIsInNwbGl0VGV4dCIsInNsaWNlIiwiUGxhaW5QYXJ0IiwicmVtb3ZlIiwibGVuIiwic3RyV2l0aFJlbW92YWwiLCJjaGFyQXQiLCJhcHBlbmRVbnRpbFJlamVjdGVkIiwic3RyIiwibGVuZ3RoIiwiYnVmZmVyIiwiY2hhciIsImdldEZpcnN0R3JhcGhlbWUiLCJ1bmRlZmluZWQiLCJ2YWxpZGF0ZUFuZEluc2VydCIsImJlZm9yZUluc2VydCIsImFmdGVySW5zZXJ0IiwiY3JlYXRlQXV0b0NvbXBsZXRlIiwidXBkYXRlQ2FsbGJhY2siLCJ0cmltIiwicmVtYWluaW5nIiwiY2FuRWRpdCIsImFjY2VwdHNDYXJldCIsInRvU3RyaW5nIiwidHlwZSIsInNlcmlhbGl6ZSIsIlBsYWluQmFzZVBhcnQiLCJFTU9KSV9SRUdFWCIsInRlc3QiLCJ0b0RPTU5vZGUiLCJkb2N1bWVudCIsImNyZWF0ZVRleHROb2RlIiwidXBkYXRlRE9NTm9kZSIsIm5vZGUiLCJ0ZXh0Q29udGVudCIsImNhblVwZGF0ZURPTU5vZGUiLCJub2RlVHlwZSIsIk5vZGUiLCJURVhUX05PREUiLCJQbGFpbiIsIlBpbGxQYXJ0IiwicmVzb3VyY2VJZCIsImxhYmVsIiwiY29udGFpbmVyIiwiY3JlYXRlRWxlbWVudCIsInNldEF0dHJpYnV0ZSIsIm9uQ2xpY2siLCJvbmNsaWNrIiwiY2xhc3NOYW1lIiwiYXBwZW5kQ2hpbGQiLCJzZXRBdmF0YXIiLCJ0ZXh0Tm9kZSIsImNoaWxkTm9kZXMiLCJFTEVNRU5UX05PREUiLCJub2RlTmFtZSIsInNldEF2YXRhclZhcnMiLCJhdmF0YXJVcmwiLCJpbml0aWFsTGV0dGVyIiwiYXZhdGFyQmFja2dyb3VuZCIsImF2YXRhckxldHRlciIsInN0eWxlIiwiZ2V0UHJvcGVydHlWYWx1ZSIsInNldFByb3BlcnR5IiwiTmV3bGluZVBhcnQiLCJ0YWdOYW1lIiwiTmV3bGluZSIsIkVtb2ppUGFydCIsInNwYW4iLCJ1bmljb2RlVG9TaG9ydGNvZGUiLCJFbW9qaSIsIlJvb21QaWxsUGFydCIsInJvb20iLCJhdmF0YXJVcmxGb3JSb29tIiwiZ2V0SW5pdGlhbExldHRlciIsIm5hbWUiLCJkZWZhdWx0QXZhdGFyVXJsRm9yU3RyaW5nIiwicm9vbUlkIiwiUm9vbVBpbGwiLCJpc1NwYWNlUm9vbSIsIkF0Um9vbVBpbGxQYXJ0IiwiQXRSb29tUGlsbCIsIlVzZXJQaWxsUGFydCIsInVzZXJJZCIsImRpc3BsYXlOYW1lIiwibWVtYmVyIiwiZGVmYXVsdERpc3BhdGNoZXIiLCJkaXNwYXRjaCIsImFjdGlvbiIsIkFjdGlvbiIsIlZpZXdVc2VyIiwiVXNlclBpbGwiLCJkZWZhdWx0QXZhdGFyVXJsIiwiYXZhdGFyVXJsRm9yTWVtYmVyIiwiUGlsbENhbmRpZGF0ZVBhcnQiLCJhdXRvQ29tcGxldGVDcmVhdG9yIiwiY3JlYXRlIiwiUGlsbENhbmRpZGF0ZSIsImdldEF1dG9Db21wbGV0ZUNyZWF0b3IiLCJnZXRBdXRvY29tcGxldGVyQ29tcG9uZW50IiwidXBkYXRlUXVlcnkiLCJwYXJ0Q3JlYXRvciIsIkF1dG9jb21wbGV0ZVdyYXBwZXJNb2RlbCIsIlBhcnRDcmVhdG9yIiwiY2xpZW50Iiwic2V0QXV0b0NvbXBsZXRlQ3JlYXRvciIsImNyZWF0ZVBhcnRGb3JJbnB1dCIsImlucHV0IiwicGFydEluZGV4IiwicGlsbENhbmRpZGF0ZSIsImNyZWF0ZURlZmF1bHRQYXJ0IiwicGxhaW4iLCJkZXNlcmlhbGl6ZVBhcnQiLCJuZXdsaW5lIiwiZW1vamkiLCJhdFJvb21QaWxsIiwicm9vbVBpbGwiLCJ1c2VyUGlsbCIsImFsaWFzIiwiZ2V0Um9vbSIsImdldFJvb21zIiwiZmluZCIsImdldENhbm9uaWNhbEFsaWFzIiwiZ2V0QWx0QWxpYXNlcyIsImluY2x1ZGVzIiwiZ2V0TWVtYmVyIiwiaXNSZWdpb25hbEluZGljYXRvciIsImMiLCJjb2RlUG9pbnQiLCJjb2RlUG9pbnRBdCIsInBsYWluV2l0aEVtb2ppIiwicGFydHMiLCJwbGFpblRleHQiLCJkYXRhIiwiZ3JhcGhlbWVTZWdtZW50ZXIiLCJzZWdtZW50IiwicHVzaCIsImNyZWF0ZU1lbnRpb25QYXJ0cyIsImluc2VydFRyYWlsaW5nQ2hhcmFjdGVyIiwicGlsbCIsIlNldHRpbmdzU3RvcmUiLCJnZXRWYWx1ZSIsInBvc3RmaXgiLCJDb21tYW5kUGFydENyZWF0b3IiLCJjb21tYW5kIiwiQ29tbWFuZFBhcnQiLCJDb21tYW5kIl0sInNvdXJjZXMiOlsiLi4vLi4vc3JjL2VkaXRvci9wYXJ0cy50cyJdLCJzb3VyY2VzQ29udGVudCI6WyIvKlxuQ29weXJpZ2h0IDIwMTktMjAyNCBOZXcgVmVjdG9yIEx0ZC5cbkNvcHlyaWdodCAyMDE5IFRoZSBNYXRyaXgub3JnIEZvdW5kYXRpb24gQy5JLkMuXG5cblNQRFgtTGljZW5zZS1JZGVudGlmaWVyOiBBR1BMLTMuMC1vbmx5IE9SIEdQTC0zLjAtb25seVxuUGxlYXNlIHNlZSBMSUNFTlNFIGZpbGVzIGluIHRoZSByZXBvc2l0b3J5IHJvb3QgZm9yIGZ1bGwgZGV0YWlscy5cbiovXG5cbmltcG9ydCB7IE1hdHJpeENsaWVudCwgUm9vbU1lbWJlciwgUm9vbSB9IGZyb20gXCJtYXRyaXgtanMtc2RrL3NyYy9tYXRyaXhcIjtcblxuaW1wb3J0IEF1dG9jb21wbGV0ZVdyYXBwZXJNb2RlbCwgeyBHZXRBdXRvY29tcGxldGVyQ29tcG9uZW50LCBVcGRhdGVDYWxsYmFjaywgVXBkYXRlUXVlcnkgfSBmcm9tIFwiLi9hdXRvY29tcGxldGVcIjtcbmltcG9ydCB7IEVNT0pJX1JFR0VYLCB1bmljb2RlVG9TaG9ydGNvZGUgfSBmcm9tIFwiLi4vSHRtbFV0aWxzXCI7XG5pbXBvcnQgKiBhcyBBdmF0YXIgZnJvbSBcIi4uL0F2YXRhclwiO1xuaW1wb3J0IGRlZmF1bHREaXNwYXRjaGVyIGZyb20gXCIuLi9kaXNwYXRjaGVyL2Rpc3BhdGNoZXJcIjtcbmltcG9ydCB7IEFjdGlvbiB9IGZyb20gXCIuLi9kaXNwYXRjaGVyL2FjdGlvbnNcIjtcbmltcG9ydCBTZXR0aW5nc1N0b3JlIGZyb20gXCIuLi9zZXR0aW5ncy9TZXR0aW5nc1N0b3JlXCI7XG5pbXBvcnQgeyBnZXRGaXJzdEdyYXBoZW1lLCBncmFwaGVtZVNlZ21lbnRlciB9IGZyb20gXCIuLi91dGlscy9zdHJpbmdzXCI7XG5cbmNvbnN0IFJFR0lPTkFMX0VNT0pJX1NFUEFSQVRPUiA9IFN0cmluZy5mcm9tQ29kZVBvaW50KDB4MjAwYik7XG5cbmludGVyZmFjZSBJU2VyaWFsaXplZFBhcnQge1xuICAgIHR5cGU6IFR5cGUuUGxhaW4gfCBUeXBlLk5ld2xpbmUgfCBUeXBlLkVtb2ppIHwgVHlwZS5Db21tYW5kIHwgVHlwZS5QaWxsQ2FuZGlkYXRlO1xuICAgIHRleHQ6IHN0cmluZztcbn1cblxuaW50ZXJmYWNlIElTZXJpYWxpemVkUGlsbFBhcnQge1xuICAgIHR5cGU6IFR5cGUuQXRSb29tUGlsbCB8IFR5cGUuUm9vbVBpbGwgfCBUeXBlLlVzZXJQaWxsO1xuICAgIHRleHQ6IHN0cmluZztcbiAgICByZXNvdXJjZUlkPzogc3RyaW5nO1xufVxuXG5leHBvcnQgdHlwZSBTZXJpYWxpemVkUGFydCA9IElTZXJpYWxpemVkUGFydCB8IElTZXJpYWxpemVkUGlsbFBhcnQ7XG5cbmV4cG9ydCBlbnVtIFR5cGUge1xuICAgIFBsYWluID0gXCJwbGFpblwiLFxuICAgIE5ld2xpbmUgPSBcIm5ld2xpbmVcIixcbiAgICBFbW9qaSA9IFwiZW1vamlcIixcbiAgICBDb21tYW5kID0gXCJjb21tYW5kXCIsXG4gICAgVXNlclBpbGwgPSBcInVzZXItcGlsbFwiLFxuICAgIFJvb21QaWxsID0gXCJyb29tLXBpbGxcIixcbiAgICBBdFJvb21QaWxsID0gXCJhdC1yb29tLXBpbGxcIixcbiAgICBQaWxsQ2FuZGlkYXRlID0gXCJwaWxsLWNhbmRpZGF0ZVwiLFxufVxuXG5pbnRlcmZhY2UgSUJhc2VQYXJ0IHtcbiAgICB0ZXh0OiBzdHJpbmc7XG4gICAgdHlwZTogVHlwZS5QbGFpbiB8IFR5cGUuTmV3bGluZSB8IFR5cGUuRW1vamk7XG4gICAgY2FuRWRpdDogYm9vbGVhbjtcbiAgICBhY2NlcHRzQ2FyZXQ6IGJvb2xlYW47XG5cbiAgICBjcmVhdGVBdXRvQ29tcGxldGUodXBkYXRlQ2FsbGJhY2s6IFVwZGF0ZUNhbGxiYWNrKTogdm9pZDtcblxuICAgIHNlcmlhbGl6ZSgpOiBTZXJpYWxpemVkUGFydDtcbiAgICByZW1vdmUob2Zmc2V0OiBudW1iZXIsIGxlbjogbnVtYmVyKTogc3RyaW5nIHwgdW5kZWZpbmVkO1xuICAgIHNwbGl0KG9mZnNldDogbnVtYmVyKTogSUJhc2VQYXJ0O1xuICAgIHZhbGlkYXRlQW5kSW5zZXJ0KG9mZnNldDogbnVtYmVyLCBzdHI6IHN0cmluZywgaW5wdXRUeXBlOiBzdHJpbmcgfCB1bmRlZmluZWQpOiBib29sZWFuO1xuICAgIGFwcGVuZFVudGlsUmVqZWN0ZWQoc3RyOiBzdHJpbmcsIGlucHV0VHlwZTogc3RyaW5nIHwgdW5kZWZpbmVkKTogc3RyaW5nIHwgdW5kZWZpbmVkO1xuICAgIHVwZGF0ZURPTU5vZGUobm9kZTogTm9kZSk6IHZvaWQ7XG4gICAgY2FuVXBkYXRlRE9NTm9kZShub2RlOiBOb2RlKTogYm9vbGVhbjtcbiAgICB0b0RPTU5vZGUoKTogTm9kZTtcblxuICAgIG1lcmdlPyhwYXJ0OiBQYXJ0KTogYm9vbGVhbjtcbn1cblxuaW50ZXJmYWNlIElQaWxsQ2FuZGlkYXRlUGFydCBleHRlbmRzIE9taXQ8SUJhc2VQYXJ0LCBcInR5cGVcIiB8IFwiY3JlYXRlQXV0b0NvbXBsZXRlXCI+IHtcbiAgICB0eXBlOiBUeXBlLlBpbGxDYW5kaWRhdGUgfCBUeXBlLkNvbW1hbmQ7XG4gICAgY3JlYXRlQXV0b0NvbXBsZXRlKHVwZGF0ZUNhbGxiYWNrOiBVcGRhdGVDYWxsYmFjayk6IEF1dG9jb21wbGV0ZVdyYXBwZXJNb2RlbCB8IHVuZGVmaW5lZDtcbn1cblxuaW50ZXJmYWNlIElQaWxsUGFydCBleHRlbmRzIE9taXQ8SUJhc2VQYXJ0LCBcInR5cGVcIiB8IFwicmVzb3VyY2VJZFwiPiB7XG4gICAgdHlwZTogVHlwZS5BdFJvb21QaWxsIHwgVHlwZS5Sb29tUGlsbCB8IFR5cGUuVXNlclBpbGw7XG4gICAgcmVzb3VyY2VJZDogc3RyaW5nO1xufVxuXG5leHBvcnQgdHlwZSBQYXJ0ID0gSUJhc2VQYXJ0IHwgSVBpbGxDYW5kaWRhdGVQYXJ0IHwgSVBpbGxQYXJ0O1xuXG5hYnN0cmFjdCBjbGFzcyBCYXNlUGFydCB7XG4gICAgcHJvdGVjdGVkIF90ZXh0OiBzdHJpbmc7XG5cbiAgICBwdWJsaWMgY29uc3RydWN0b3IodGV4dCA9IFwiXCIpIHtcbiAgICAgICAgdGhpcy5fdGV4dCA9IHRleHQ7XG4gICAgfVxuXG4gICAgLy8gY2hyIGNhbiBhbHNvIGJlIGEgZ3JhcGhlbWUgY2x1c3RlclxuICAgIHByb3RlY3RlZCBhY2NlcHRzSW5zZXJ0aW9uKGNocjogc3RyaW5nLCBvZmZzZXQ6IG51bWJlciwgaW5wdXRUeXBlOiBzdHJpbmcpOiBib29sZWFuIHtcbiAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgfVxuXG4gICAgcHJvdGVjdGVkIGFjY2VwdHNSZW1vdmFsKHBvc2l0aW9uOiBudW1iZXIsIGNocjogc3RyaW5nKTogYm9vbGVhbiB7XG4gICAgICAgIHJldHVybiB0cnVlO1xuICAgIH1cblxuICAgIHB1YmxpYyBtZXJnZShwYXJ0OiBQYXJ0KTogYm9vbGVhbiB7XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG5cbiAgICBwdWJsaWMgc3BsaXQob2Zmc2V0OiBudW1iZXIpOiBJQmFzZVBhcnQge1xuICAgICAgICBjb25zdCBzcGxpdFRleHQgPSB0aGlzLnRleHQuc2xpY2Uob2Zmc2V0KTtcbiAgICAgICAgdGhpcy5fdGV4dCA9IHRoaXMudGV4dC5zbGljZSgwLCBvZmZzZXQpO1xuICAgICAgICByZXR1cm4gbmV3IFBsYWluUGFydChzcGxpdFRleHQpO1xuICAgIH1cblxuICAgIC8vIHJlbW92ZXMgbGVuIGNoYXJzLCBvciByZXR1cm5zIHRoZSBwbGFpbiB0ZXh0IHRoaXMgcGFydCBzaG91bGQgYmUgcmVwbGFjZWQgd2l0aFxuICAgIC8vIGlmIHRoZSBwYXJ0IHdvdWxkIGJlY29tZSBpbnZhbGlkIGlmIGl0IHJlbW92ZWQgZXZlcnl0aGluZy5cbiAgICBwdWJsaWMgcmVtb3ZlKG9mZnNldDogbnVtYmVyLCBsZW46IG51bWJlcik6IHN0cmluZyB8IHVuZGVmaW5lZCB7XG4gICAgICAgIC8vIHZhbGlkYXRlXG4gICAgICAgIGNvbnN0IHN0cldpdGhSZW1vdmFsID0gdGhpcy50ZXh0LnNsaWNlKDAsIG9mZnNldCkgKyB0aGlzLnRleHQuc2xpY2Uob2Zmc2V0ICsgbGVuKTtcbiAgICAgICAgZm9yIChsZXQgaSA9IG9mZnNldDsgaSA8IGxlbiArIG9mZnNldDsgKytpKSB7XG4gICAgICAgICAgICBjb25zdCBjaHIgPSB0aGlzLnRleHQuY2hhckF0KGkpO1xuICAgICAgICAgICAgaWYgKCF0aGlzLmFjY2VwdHNSZW1vdmFsKGksIGNocikpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gc3RyV2l0aFJlbW92YWw7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy5fdGV4dCA9IHN0cldpdGhSZW1vdmFsO1xuICAgIH1cblxuICAgIC8vIGFwcGVuZCBzdHIsIHJldHVybnMgdGhlIHJlbWFpbmluZyBzdHJpbmcgaWYgYSBjaGFyYWN0ZXIgd2FzIHJlamVjdGVkLlxuICAgIHB1YmxpYyBhcHBlbmRVbnRpbFJlamVjdGVkKHN0cjogc3RyaW5nLCBpbnB1dFR5cGU6IHN0cmluZyk6IHN0cmluZyB8IHVuZGVmaW5lZCB7XG4gICAgICAgIGNvbnN0IG9mZnNldCA9IHRoaXMudGV4dC5sZW5ndGg7XG4gICAgICAgIC8vIFRha2UgYSBjb3B5IGFzIHdlIHdpbGwgYmUgdGFraW5nIGNodW5rcyBvZmYgdGhlIHN0YXJ0IG9mIHRoZSBzdHJpbmcgYXMgd2UgcHJvY2VzcyB0aGVtXG4gICAgICAgIC8vIFRvIG9ubHkgbmVlZCB0byBncmFwaGVtZSBzcGxpdCB0aGUgYml0cyBvZiB0aGUgc3RyaW5nIHdlJ3JlIHdvcmtpbmcgb24uXG4gICAgICAgIGxldCBidWZmZXIgPSBzdHI7XG4gICAgICAgIHdoaWxlIChidWZmZXIpIHtcbiAgICAgICAgICAgIGNvbnN0IGNoYXIgPSBnZXRGaXJzdEdyYXBoZW1lKGJ1ZmZlcik7XG4gICAgICAgICAgICBpZiAoIXRoaXMuYWNjZXB0c0luc2VydGlvbihjaGFyLCBvZmZzZXQgKyBzdHIubGVuZ3RoIC0gYnVmZmVyLmxlbmd0aCwgaW5wdXRUeXBlKSkge1xuICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgYnVmZmVyID0gYnVmZmVyLnNsaWNlKGNoYXIubGVuZ3RoKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMuX3RleHQgKz0gc3RyLnNsaWNlKDAsIHN0ci5sZW5ndGggLSBidWZmZXIubGVuZ3RoKTtcbiAgICAgICAgcmV0dXJuIGJ1ZmZlciB8fCB1bmRlZmluZWQ7XG4gICAgfVxuXG4gICAgLy8gaW5zZXJ0cyBzdHIgYXQgb2Zmc2V0IGlmIGFsbCB0aGUgY2hhcmFjdGVycyBpbiBzdHIgd2VyZSBhY2NlcHRlZCwgb3RoZXJ3aXNlIGRvbid0IGRvIGFueXRoaW5nXG4gICAgLy8gcmV0dXJuIHdoZXRoZXIgdGhlIHN0ciB3YXMgYWNjZXB0ZWQgb3Igbm90LlxuICAgIHB1YmxpYyB2YWxpZGF0ZUFuZEluc2VydChvZmZzZXQ6IG51bWJlciwgc3RyOiBzdHJpbmcsIGlucHV0VHlwZTogc3RyaW5nKTogYm9vbGVhbiB7XG4gICAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgc3RyLmxlbmd0aDsgKytpKSB7XG4gICAgICAgICAgICBjb25zdCBjaHIgPSBzdHIuY2hhckF0KGkpO1xuICAgICAgICAgICAgaWYgKCF0aGlzLmFjY2VwdHNJbnNlcnRpb24oY2hyLCBvZmZzZXQgKyBpLCBpbnB1dFR5cGUpKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIGNvbnN0IGJlZm9yZUluc2VydCA9IHRoaXMuX3RleHQuc2xpY2UoMCwgb2Zmc2V0KTtcbiAgICAgICAgY29uc3QgYWZ0ZXJJbnNlcnQgPSB0aGlzLl90ZXh0LnNsaWNlKG9mZnNldCk7XG4gICAgICAgIHRoaXMuX3RleHQgPSBiZWZvcmVJbnNlcnQgKyBzdHIgKyBhZnRlckluc2VydDtcbiAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgfVxuXG4gICAgcHVibGljIGNyZWF0ZUF1dG9Db21wbGV0ZSh1cGRhdGVDYWxsYmFjazogVXBkYXRlQ2FsbGJhY2spOiB2b2lkIHt9XG5cbiAgICBwcm90ZWN0ZWQgdHJpbShsZW46IG51bWJlcik6IHN0cmluZyB7XG4gICAgICAgIGNvbnN0IHJlbWFpbmluZyA9IHRoaXMuX3RleHQuc2xpY2UobGVuKTtcbiAgICAgICAgdGhpcy5fdGV4dCA9IHRoaXMuX3RleHQuc2xpY2UoMCwgbGVuKTtcbiAgICAgICAgcmV0dXJuIHJlbWFpbmluZztcbiAgICB9XG5cbiAgICBwdWJsaWMgZ2V0IHRleHQoKTogc3RyaW5nIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuX3RleHQ7XG4gICAgfVxuXG4gICAgcHVibGljIGFic3RyYWN0IGdldCB0eXBlKCk6IFR5cGU7XG5cbiAgICBwdWJsaWMgZ2V0IGNhbkVkaXQoKTogYm9vbGVhbiB7XG4gICAgICAgIHJldHVybiB0cnVlO1xuICAgIH1cblxuICAgIHB1YmxpYyBnZXQgYWNjZXB0c0NhcmV0KCk6IGJvb2xlYW4ge1xuICAgICAgICByZXR1cm4gdGhpcy5jYW5FZGl0O1xuICAgIH1cblxuICAgIHB1YmxpYyB0b1N0cmluZygpOiBzdHJpbmcge1xuICAgICAgICByZXR1cm4gYCR7dGhpcy50eXBlfSgke3RoaXMudGV4dH0pYDtcbiAgICB9XG5cbiAgICBwdWJsaWMgc2VyaWFsaXplKCk6IFNlcmlhbGl6ZWRQYXJ0IHtcbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIHR5cGU6IHRoaXMudHlwZSBhcyBJU2VyaWFsaXplZFBhcnRbXCJ0eXBlXCJdLFxuICAgICAgICAgICAgdGV4dDogdGhpcy50ZXh0LFxuICAgICAgICB9O1xuICAgIH1cblxuICAgIHB1YmxpYyBhYnN0cmFjdCB1cGRhdGVET01Ob2RlKG5vZGU6IE5vZGUpOiB2b2lkO1xuICAgIHB1YmxpYyBhYnN0cmFjdCBjYW5VcGRhdGVET01Ob2RlKG5vZGU6IE5vZGUpOiBib29sZWFuO1xuICAgIHB1YmxpYyBhYnN0cmFjdCB0b0RPTU5vZGUoKTogTm9kZTtcbn1cblxuYWJzdHJhY3QgY2xhc3MgUGxhaW5CYXNlUGFydCBleHRlbmRzIEJhc2VQYXJ0IHtcbiAgICBwcm90ZWN0ZWQgYWNjZXB0c0luc2VydGlvbihjaHI6IHN0cmluZywgb2Zmc2V0OiBudW1iZXIsIGlucHV0VHlwZTogc3RyaW5nKTogYm9vbGVhbiB7XG4gICAgICAgIGlmIChjaHIgPT09IFwiXFxuXCIgfHwgRU1PSklfUkVHRVgudGVzdChjaHIpKSB7XG4gICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgIH1cbiAgICAgICAgLy8gd2hlbiBub3QgcGFzdGluZyBvciBkcm9wcGluZyB0ZXh0LCByZWplY3QgY2hhcmFjdGVycyB0aGF0IHNob3VsZCBzdGFydCBhIHBpbGwgY2FuZGlkYXRlXG4gICAgICAgIGlmIChpbnB1dFR5cGUgIT09IFwiaW5zZXJ0RnJvbVBhc3RlXCIgJiYgaW5wdXRUeXBlICE9PSBcImluc2VydEZyb21Ecm9wXCIpIHtcbiAgICAgICAgICAgIGlmIChjaHIgIT09IFwiQFwiICYmIGNociAhPT0gXCIjXCIgJiYgY2hyICE9PSBcIjpcIiAmJiBjaHIgIT09IFwiK1wiKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIC8vIHNwbGl0IGlmIHdlIGFyZSBhdCB0aGUgYmVnaW5uaW5nIG9mIHRoZSBwYXJ0IHRleHRcbiAgICAgICAgICAgIGlmIChvZmZzZXQgPT09IDApIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIC8vIG9yIHNwbGl0IGlmIHRoZSBwcmV2aW91cyBjaGFyYWN0ZXIgaXMgYSBzcGFjZSBvciByZWdpb25hbCBlbW9qaSBzZXBhcmF0b3JcbiAgICAgICAgICAgIC8vIG9yIGlmIGl0IGlzIGEgKyBhbmQgdGhpcyBpcyBhIDpcbiAgICAgICAgICAgIHJldHVybiAoXG4gICAgICAgICAgICAgICAgdGhpcy5fdGV4dFtvZmZzZXQgLSAxXSAhPT0gXCIgXCIgJiZcbiAgICAgICAgICAgICAgICB0aGlzLl90ZXh0W29mZnNldCAtIDFdICE9PSBSRUdJT05BTF9FTU9KSV9TRVBBUkFUT1IgJiZcbiAgICAgICAgICAgICAgICAodGhpcy5fdGV4dFtvZmZzZXQgLSAxXSAhPT0gXCIrXCIgfHwgY2hyICE9PSBcIjpcIilcbiAgICAgICAgICAgICk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgfVxuXG4gICAgcHVibGljIHRvRE9NTm9kZSgpOiBOb2RlIHtcbiAgICAgICAgcmV0dXJuIGRvY3VtZW50LmNyZWF0ZVRleHROb2RlKHRoaXMudGV4dCk7XG4gICAgfVxuXG4gICAgcHVibGljIG1lcmdlKHBhcnQ6IFBhcnQpOiBib29sZWFuIHtcbiAgICAgICAgaWYgKHBhcnQudHlwZSA9PT0gdGhpcy50eXBlKSB7XG4gICAgICAgICAgICB0aGlzLl90ZXh0ID0gdGhpcy50ZXh0ICsgcGFydC50ZXh0O1xuICAgICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cblxuICAgIHB1YmxpYyB1cGRhdGVET01Ob2RlKG5vZGU6IE5vZGUpOiB2b2lkIHtcbiAgICAgICAgaWYgKG5vZGUudGV4dENvbnRlbnQgIT09IHRoaXMudGV4dCkge1xuICAgICAgICAgICAgbm9kZS50ZXh0Q29udGVudCA9IHRoaXMudGV4dDtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHB1YmxpYyBjYW5VcGRhdGVET01Ob2RlKG5vZGU6IE5vZGUpOiBib29sZWFuIHtcbiAgICAgICAgcmV0dXJuIG5vZGUubm9kZVR5cGUgPT09IE5vZGUuVEVYVF9OT0RFO1xuICAgIH1cbn1cblxuLy8gZXhwb3J0ZWQgZm9yIHVuaXQgdGVzdHMsIHNob3VsZCBvdGhlcndpc2Ugb25seSBiZSB1c2VkIHRocm91Z2ggUGFydENyZWF0b3JcbmV4cG9ydCBjbGFzcyBQbGFpblBhcnQgZXh0ZW5kcyBQbGFpbkJhc2VQYXJ0IGltcGxlbWVudHMgSUJhc2VQYXJ0IHtcbiAgICBwdWJsaWMgZ2V0IHR5cGUoKTogSUJhc2VQYXJ0W1widHlwZVwiXSB7XG4gICAgICAgIHJldHVybiBUeXBlLlBsYWluO1xuICAgIH1cbn1cblxuZXhwb3J0IGFic3RyYWN0IGNsYXNzIFBpbGxQYXJ0IGV4dGVuZHMgQmFzZVBhcnQgaW1wbGVtZW50cyBJUGlsbFBhcnQge1xuICAgIHB1YmxpYyBjb25zdHJ1Y3RvcihcbiAgICAgICAgcHVibGljIHJlc291cmNlSWQ6IHN0cmluZyxcbiAgICAgICAgbGFiZWw6IHN0cmluZyxcbiAgICApIHtcbiAgICAgICAgc3VwZXIobGFiZWwpO1xuICAgIH1cblxuICAgIHByb3RlY3RlZCBhY2NlcHRzSW5zZXJ0aW9uKGNocjogc3RyaW5nKTogYm9vbGVhbiB7XG4gICAgICAgIHJldHVybiBjaHIgIT09IFwiIFwiO1xuICAgIH1cblxuICAgIHByb3RlY3RlZCBhY2NlcHRzUmVtb3ZhbChwb3NpdGlvbjogbnVtYmVyLCBjaHI6IHN0cmluZyk6IGJvb2xlYW4ge1xuICAgICAgICByZXR1cm4gcG9zaXRpb24gIT09IDA7IC8vaWYgeW91IHJlbW92ZSBpbml0aWFsICMgb3IgQCwgcGlsbCBzaG91bGQgYmVjb21lIHBsYWluXG4gICAgfVxuXG4gICAgcHVibGljIHRvRE9NTm9kZSgpOiBOb2RlIHtcbiAgICAgICAgY29uc3QgY29udGFpbmVyID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudChcInNwYW5cIik7XG4gICAgICAgIGNvbnRhaW5lci5zZXRBdHRyaWJ1dGUoXCJzcGVsbGNoZWNrXCIsIFwiZmFsc2VcIik7XG4gICAgICAgIGNvbnRhaW5lci5zZXRBdHRyaWJ1dGUoXCJjb250ZW50RWRpdGFibGVcIiwgXCJmYWxzZVwiKTtcbiAgICAgICAgaWYgKHRoaXMub25DbGljaykgY29udGFpbmVyLm9uY2xpY2sgPSB0aGlzLm9uQ2xpY2s7XG4gICAgICAgIGNvbnRhaW5lci5jbGFzc05hbWUgPSB0aGlzLmNsYXNzTmFtZTtcbiAgICAgICAgY29udGFpbmVyLmFwcGVuZENoaWxkKGRvY3VtZW50LmNyZWF0ZVRleHROb2RlKHRoaXMudGV4dCkpO1xuICAgICAgICB0aGlzLnNldEF2YXRhcihjb250YWluZXIpO1xuICAgICAgICByZXR1cm4gY29udGFpbmVyO1xuICAgIH1cblxuICAgIHB1YmxpYyB1cGRhdGVET01Ob2RlKG5vZGU6IEhUTUxFbGVtZW50KTogdm9pZCB7XG4gICAgICAgIGNvbnN0IHRleHROb2RlID0gbm9kZS5jaGlsZE5vZGVzWzBdO1xuICAgICAgICBpZiAodGV4dE5vZGUudGV4dENvbnRlbnQgIT09IHRoaXMudGV4dCkge1xuICAgICAgICAgICAgdGV4dE5vZGUudGV4dENvbnRlbnQgPSB0aGlzLnRleHQ7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKG5vZGUuY2xhc3NOYW1lICE9PSB0aGlzLmNsYXNzTmFtZSkge1xuICAgICAgICAgICAgbm9kZS5jbGFzc05hbWUgPSB0aGlzLmNsYXNzTmFtZTtcbiAgICAgICAgfVxuICAgICAgICBpZiAodGhpcy5vbkNsaWNrICYmIG5vZGUub25jbGljayAhPT0gdGhpcy5vbkNsaWNrKSB7XG4gICAgICAgICAgICBub2RlLm9uY2xpY2sgPSB0aGlzLm9uQ2xpY2s7XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy5zZXRBdmF0YXIobm9kZSk7XG4gICAgfVxuXG4gICAgcHVibGljIGNhblVwZGF0ZURPTU5vZGUobm9kZTogSFRNTEVsZW1lbnQpOiBib29sZWFuIHtcbiAgICAgICAgcmV0dXJuIChcbiAgICAgICAgICAgIG5vZGUubm9kZVR5cGUgPT09IE5vZGUuRUxFTUVOVF9OT0RFICYmXG4gICAgICAgICAgICBub2RlLm5vZGVOYW1lID09PSBcIlNQQU5cIiAmJlxuICAgICAgICAgICAgbm9kZS5jaGlsZE5vZGVzLmxlbmd0aCA9PT0gMSAmJlxuICAgICAgICAgICAgbm9kZS5jaGlsZE5vZGVzWzBdLm5vZGVUeXBlID09PSBOb2RlLlRFWFRfTk9ERVxuICAgICAgICApO1xuICAgIH1cblxuICAgIC8vIGhlbHBlciBtZXRob2QgZm9yIHN1YmNsYXNzZXNcbiAgICBwcm90ZWN0ZWQgc2V0QXZhdGFyVmFycyhub2RlOiBIVE1MRWxlbWVudCwgYXZhdGFyVXJsOiBzdHJpbmcsIGluaXRpYWxMZXR0ZXI6IHN0cmluZyk6IHZvaWQge1xuICAgICAgICBjb25zdCBhdmF0YXJCYWNrZ3JvdW5kID0gYHVybCgnJHthdmF0YXJVcmx9JylgO1xuICAgICAgICBjb25zdCBhdmF0YXJMZXR0ZXIgPSBgJyR7aW5pdGlhbExldHRlcn0nYDtcbiAgICAgICAgLy8gY2hlY2sgaWYgdGhlIHZhbHVlIGlzIGNoYW5naW5nLFxuICAgICAgICAvLyBvdGhlcndpc2UgdGhlIGF2YXRhcnMgZmxpY2tlciBvbiBldmVyeSBrZXlzdHJva2Ugd2hpbGUgdXBkYXRpbmcuXG4gICAgICAgIGlmIChub2RlLnN0eWxlLmdldFByb3BlcnR5VmFsdWUoXCItLWF2YXRhci1iYWNrZ3JvdW5kXCIpICE9PSBhdmF0YXJCYWNrZ3JvdW5kKSB7XG4gICAgICAgICAgICBub2RlLnN0eWxlLnNldFByb3BlcnR5KFwiLS1hdmF0YXItYmFja2dyb3VuZFwiLCBhdmF0YXJCYWNrZ3JvdW5kKTtcbiAgICAgICAgfVxuICAgICAgICBpZiAobm9kZS5zdHlsZS5nZXRQcm9wZXJ0eVZhbHVlKFwiLS1hdmF0YXItbGV0dGVyXCIpICE9PSBhdmF0YXJMZXR0ZXIpIHtcbiAgICAgICAgICAgIG5vZGUuc3R5bGUuc2V0UHJvcGVydHkoXCItLWF2YXRhci1sZXR0ZXJcIiwgYXZhdGFyTGV0dGVyKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHB1YmxpYyBzZXJpYWxpemUoKTogSVNlcmlhbGl6ZWRQaWxsUGFydCB7XG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICB0eXBlOiB0aGlzLnR5cGUsXG4gICAgICAgICAgICB0ZXh0OiB0aGlzLnRleHQsXG4gICAgICAgICAgICByZXNvdXJjZUlkOiB0aGlzLnJlc291cmNlSWQsXG4gICAgICAgIH07XG4gICAgfVxuXG4gICAgcHVibGljIGdldCBjYW5FZGl0KCk6IGJvb2xlYW4ge1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuXG4gICAgcHVibGljIGFic3RyYWN0IGdldCB0eXBlKCk6IElQaWxsUGFydFtcInR5cGVcIl07XG5cbiAgICBwcm90ZWN0ZWQgYWJzdHJhY3QgZ2V0IGNsYXNzTmFtZSgpOiBzdHJpbmc7XG5cbiAgICBwcm90ZWN0ZWQgb25DbGljaz86ICgpID0+IHZvaWQ7XG5cbiAgICBwcm90ZWN0ZWQgYWJzdHJhY3Qgc2V0QXZhdGFyKG5vZGU6IEhUTUxFbGVtZW50KTogdm9pZDtcbn1cblxuY2xhc3MgTmV3bGluZVBhcnQgZXh0ZW5kcyBCYXNlUGFydCBpbXBsZW1lbnRzIElCYXNlUGFydCB7XG4gICAgcHJvdGVjdGVkIGFjY2VwdHNJbnNlcnRpb24oY2hyOiBzdHJpbmcsIG9mZnNldDogbnVtYmVyKTogYm9vbGVhbiB7XG4gICAgICAgIHJldHVybiBvZmZzZXQgPT09IDAgJiYgY2hyID09PSBcIlxcblwiO1xuICAgIH1cblxuICAgIHByb3RlY3RlZCBhY2NlcHRzUmVtb3ZhbChwb3NpdGlvbjogbnVtYmVyLCBjaHI6IHN0cmluZyk6IGJvb2xlYW4ge1xuICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9XG5cbiAgICBwdWJsaWMgdG9ET01Ob2RlKCk6IE5vZGUge1xuICAgICAgICByZXR1cm4gZG9jdW1lbnQuY3JlYXRlRWxlbWVudChcImJyXCIpO1xuICAgIH1cblxuICAgIHB1YmxpYyBtZXJnZSgpOiBib29sZWFuIHtcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cblxuICAgIHB1YmxpYyB1cGRhdGVET01Ob2RlKCk6IHZvaWQge31cblxuICAgIHB1YmxpYyBjYW5VcGRhdGVET01Ob2RlKG5vZGU6IEhUTUxFbGVtZW50KTogYm9vbGVhbiB7XG4gICAgICAgIHJldHVybiBub2RlLnRhZ05hbWUgPT09IFwiQlJcIjtcbiAgICB9XG5cbiAgICBwdWJsaWMgZ2V0IHR5cGUoKTogSUJhc2VQYXJ0W1widHlwZVwiXSB7XG4gICAgICAgIHJldHVybiBUeXBlLk5ld2xpbmU7XG4gICAgfVxuXG4gICAgLy8gdGhpcyBtYWtlcyB0aGUgY3Vyc29yIHNraXAgdGhpcyBwYXJ0IHdoZW4gaXQgaXMgaW5zZXJ0ZWRcbiAgICAvLyByYXRoZXIgdGhhbiB0cnlpbmcgdG8gYXBwZW5kIHRvIGl0LCB3aGljaCBpcyB3aGF0IHdlIHdhbnQuXG4gICAgLy8gQXMgYSBuZXdsaW5lIGNhbiBhbHNvIGJlIG9ubHkgb25lIGNoYXJhY3RlciwgaXQgbWFrZXMgc2Vuc2VcbiAgICAvLyBhcyBpdCBjYW4gb25seSBiZSBvbmUgY2hhcmFjdGVyIGxvbmcuIFRoaXMgY2F1c2VkICM5NzQxLlxuICAgIHB1YmxpYyBnZXQgY2FuRWRpdCgpOiBib29sZWFuIHtcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbn1cblxuZXhwb3J0IGNsYXNzIEVtb2ppUGFydCBleHRlbmRzIEJhc2VQYXJ0IGltcGxlbWVudHMgSUJhc2VQYXJ0IHtcbiAgICBwcm90ZWN0ZWQgYWNjZXB0c0luc2VydGlvbihjaHI6IHN0cmluZywgb2Zmc2V0OiBudW1iZXIpOiBib29sZWFuIHtcbiAgICAgICAgcmV0dXJuIEVNT0pJX1JFR0VYLnRlc3QoY2hyKTtcbiAgICB9XG5cbiAgICBwcm90ZWN0ZWQgYWNjZXB0c1JlbW92YWwocG9zaXRpb246IG51bWJlciwgY2hyOiBzdHJpbmcpOiBib29sZWFuIHtcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cblxuICAgIHB1YmxpYyB0b0RPTU5vZGUoKTogTm9kZSB7XG4gICAgICAgIGNvbnN0IHNwYW4gPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KFwic3BhblwiKTtcbiAgICAgICAgc3Bhbi5jbGFzc05hbWUgPSBcIm14X0Vtb2ppXCI7XG4gICAgICAgIHNwYW4uc2V0QXR0cmlidXRlKFwidGl0bGVcIiwgdW5pY29kZVRvU2hvcnRjb2RlKHRoaXMudGV4dCkpO1xuICAgICAgICBzcGFuLmFwcGVuZENoaWxkKGRvY3VtZW50LmNyZWF0ZVRleHROb2RlKHRoaXMudGV4dCkpO1xuICAgICAgICByZXR1cm4gc3BhbjtcbiAgICB9XG5cbiAgICBwdWJsaWMgdXBkYXRlRE9NTm9kZShub2RlOiBIVE1MRWxlbWVudCk6IHZvaWQge1xuICAgICAgICBjb25zdCB0ZXh0Tm9kZSA9IG5vZGUuY2hpbGROb2Rlc1swXTtcbiAgICAgICAgaWYgKHRleHROb2RlLnRleHRDb250ZW50ICE9PSB0aGlzLnRleHQpIHtcbiAgICAgICAgICAgIG5vZGUuc2V0QXR0cmlidXRlKFwidGl0bGVcIiwgdW5pY29kZVRvU2hvcnRjb2RlKHRoaXMudGV4dCkpO1xuICAgICAgICAgICAgdGV4dE5vZGUudGV4dENvbnRlbnQgPSB0aGlzLnRleHQ7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBwdWJsaWMgY2FuVXBkYXRlRE9NTm9kZShub2RlOiBIVE1MRWxlbWVudCk6IGJvb2xlYW4ge1xuICAgICAgICByZXR1cm4gbm9kZS5jbGFzc05hbWUgPT09IFwibXhfRW1vamlcIjtcbiAgICB9XG5cbiAgICBwdWJsaWMgZ2V0IHR5cGUoKTogSUJhc2VQYXJ0W1widHlwZVwiXSB7XG4gICAgICAgIHJldHVybiBUeXBlLkVtb2ppO1xuICAgIH1cblxuICAgIHB1YmxpYyBnZXQgY2FuRWRpdCgpOiBib29sZWFuIHtcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cblxuICAgIHB1YmxpYyBnZXQgYWNjZXB0c0NhcmV0KCk6IGJvb2xlYW4ge1xuICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9XG59XG5cbmNsYXNzIFJvb21QaWxsUGFydCBleHRlbmRzIFBpbGxQYXJ0IHtcbiAgICBwdWJsaWMgY29uc3RydWN0b3IoXG4gICAgICAgIHJlc291cmNlSWQ6IHN0cmluZyxcbiAgICAgICAgbGFiZWw6IHN0cmluZyxcbiAgICAgICAgcHJpdmF0ZSByb29tPzogUm9vbSxcbiAgICApIHtcbiAgICAgICAgc3VwZXIocmVzb3VyY2VJZCwgbGFiZWwpO1xuICAgIH1cblxuICAgIHByb3RlY3RlZCBzZXRBdmF0YXIobm9kZTogSFRNTEVsZW1lbnQpOiB2b2lkIHtcbiAgICAgICAgbGV0IGluaXRpYWxMZXR0ZXIgPSBcIlwiO1xuICAgICAgICBsZXQgYXZhdGFyVXJsID0gQXZhdGFyLmF2YXRhclVybEZvclJvb20odGhpcy5yb29tID8/IG51bGwsIDE2LCAxNiwgXCJjcm9wXCIpO1xuICAgICAgICBpZiAoIWF2YXRhclVybCkge1xuICAgICAgICAgICAgaW5pdGlhbExldHRlciA9IEF2YXRhci5nZXRJbml0aWFsTGV0dGVyKHRoaXMucm9vbT8ubmFtZSB8fCB0aGlzLnJlc291cmNlSWQpID8/IFwiXCI7XG4gICAgICAgICAgICBhdmF0YXJVcmwgPSBBdmF0YXIuZGVmYXVsdEF2YXRhclVybEZvclN0cmluZyh0aGlzLnJvb20/LnJvb21JZCA/PyB0aGlzLnJlc291cmNlSWQpO1xuICAgICAgICB9XG4gICAgICAgIHRoaXMuc2V0QXZhdGFyVmFycyhub2RlLCBhdmF0YXJVcmwsIGluaXRpYWxMZXR0ZXIpO1xuICAgIH1cblxuICAgIHB1YmxpYyBnZXQgdHlwZSgpOiBJUGlsbFBhcnRbXCJ0eXBlXCJdIHtcbiAgICAgICAgcmV0dXJuIFR5cGUuUm9vbVBpbGw7XG4gICAgfVxuXG4gICAgcHJvdGVjdGVkIGdldCBjbGFzc05hbWUoKTogc3RyaW5nIHtcbiAgICAgICAgcmV0dXJuIFwibXhfUGlsbCBcIiArICh0aGlzLnJvb20/LmlzU3BhY2VSb29tKCkgPyBcIm14X1NwYWNlUGlsbFwiIDogXCJteF9Sb29tUGlsbFwiKTtcbiAgICB9XG59XG5cbmNsYXNzIEF0Um9vbVBpbGxQYXJ0IGV4dGVuZHMgUm9vbVBpbGxQYXJ0IHtcbiAgICBwdWJsaWMgY29uc3RydWN0b3IodGV4dDogc3RyaW5nLCByb29tOiBSb29tKSB7XG4gICAgICAgIHN1cGVyKHRleHQsIHRleHQsIHJvb20pO1xuICAgIH1cblxuICAgIHB1YmxpYyBnZXQgdHlwZSgpOiBJUGlsbFBhcnRbXCJ0eXBlXCJdIHtcbiAgICAgICAgcmV0dXJuIFR5cGUuQXRSb29tUGlsbDtcbiAgICB9XG5cbiAgICBwdWJsaWMgc2VyaWFsaXplKCk6IElTZXJpYWxpemVkUGlsbFBhcnQge1xuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgdHlwZTogdGhpcy50eXBlLFxuICAgICAgICAgICAgdGV4dDogdGhpcy50ZXh0LFxuICAgICAgICB9O1xuICAgIH1cbn1cblxuY2xhc3MgVXNlclBpbGxQYXJ0IGV4dGVuZHMgUGlsbFBhcnQge1xuICAgIHB1YmxpYyBjb25zdHJ1Y3RvcihcbiAgICAgICAgdXNlcklkOiBzdHJpbmcsXG4gICAgICAgIGRpc3BsYXlOYW1lOiBzdHJpbmcsXG4gICAgICAgIHByaXZhdGUgbWVtYmVyPzogUm9vbU1lbWJlcixcbiAgICApIHtcbiAgICAgICAgc3VwZXIodXNlcklkLCBkaXNwbGF5TmFtZSk7XG4gICAgfVxuXG4gICAgcHVibGljIGdldCB0eXBlKCk6IElQaWxsUGFydFtcInR5cGVcIl0ge1xuICAgICAgICByZXR1cm4gVHlwZS5Vc2VyUGlsbDtcbiAgICB9XG5cbiAgICBwcm90ZWN0ZWQgZ2V0IGNsYXNzTmFtZSgpOiBzdHJpbmcge1xuICAgICAgICByZXR1cm4gXCJteF9Vc2VyUGlsbCBteF9QaWxsXCI7XG4gICAgfVxuXG4gICAgcHJvdGVjdGVkIHNldEF2YXRhcihub2RlOiBIVE1MRWxlbWVudCk6IHZvaWQge1xuICAgICAgICBpZiAoIXRoaXMubWVtYmVyKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgY29uc3QgbmFtZSA9IHRoaXMubWVtYmVyLm5hbWUgfHwgdGhpcy5tZW1iZXIudXNlcklkO1xuICAgICAgICBjb25zdCBkZWZhdWx0QXZhdGFyVXJsID0gQXZhdGFyLmRlZmF1bHRBdmF0YXJVcmxGb3JTdHJpbmcodGhpcy5tZW1iZXIudXNlcklkKTtcbiAgICAgICAgY29uc3QgYXZhdGFyVXJsID0gQXZhdGFyLmF2YXRhclVybEZvck1lbWJlcih0aGlzLm1lbWJlciwgMTYsIDE2LCBcImNyb3BcIik7XG4gICAgICAgIGxldCBpbml0aWFsTGV0dGVyID0gXCJcIjtcbiAgICAgICAgaWYgKGF2YXRhclVybCA9PT0gZGVmYXVsdEF2YXRhclVybCkge1xuICAgICAgICAgICAgaW5pdGlhbExldHRlciA9IEF2YXRhci5nZXRJbml0aWFsTGV0dGVyKG5hbWUpID8/IFwiXCI7XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy5zZXRBdmF0YXJWYXJzKG5vZGUsIGF2YXRhclVybCwgaW5pdGlhbExldHRlcik7XG4gICAgfVxuXG4gICAgcHJvdGVjdGVkIG9uQ2xpY2sgPSAoKTogdm9pZCA9PiB7XG4gICAgICAgIGRlZmF1bHREaXNwYXRjaGVyLmRpc3BhdGNoKHtcbiAgICAgICAgICAgIGFjdGlvbjogQWN0aW9uLlZpZXdVc2VyLFxuICAgICAgICAgICAgbWVtYmVyOiB0aGlzLm1lbWJlcixcbiAgICAgICAgfSk7XG4gICAgfTtcbn1cblxuY2xhc3MgUGlsbENhbmRpZGF0ZVBhcnQgZXh0ZW5kcyBQbGFpbkJhc2VQYXJ0IGltcGxlbWVudHMgSVBpbGxDYW5kaWRhdGVQYXJ0IHtcbiAgICBwdWJsaWMgY29uc3RydWN0b3IoXG4gICAgICAgIHRleHQ6IHN0cmluZyxcbiAgICAgICAgcHJpdmF0ZSBhdXRvQ29tcGxldGVDcmVhdG9yOiBJQXV0b2NvbXBsZXRlQ3JlYXRvcixcbiAgICApIHtcbiAgICAgICAgc3VwZXIodGV4dCk7XG4gICAgfVxuXG4gICAgcHVibGljIGNyZWF0ZUF1dG9Db21wbGV0ZSh1cGRhdGVDYWxsYmFjazogVXBkYXRlQ2FsbGJhY2spOiBBdXRvY29tcGxldGVXcmFwcGVyTW9kZWwgfCB1bmRlZmluZWQge1xuICAgICAgICByZXR1cm4gdGhpcy5hdXRvQ29tcGxldGVDcmVhdG9yLmNyZWF0ZT8uKHVwZGF0ZUNhbGxiYWNrKTtcbiAgICB9XG5cbiAgICBwcm90ZWN0ZWQgYWNjZXB0c0luc2VydGlvbihjaHI6IHN0cmluZywgb2Zmc2V0OiBudW1iZXIsIGlucHV0VHlwZTogc3RyaW5nKTogYm9vbGVhbiB7XG4gICAgICAgIGlmIChvZmZzZXQgPT09IDApIHtcbiAgICAgICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgcmV0dXJuIHN1cGVyLmFjY2VwdHNJbnNlcnRpb24oY2hyLCBvZmZzZXQsIGlucHV0VHlwZSk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBwdWJsaWMgbWVyZ2UoKTogYm9vbGVhbiB7XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG5cbiAgICBwcm90ZWN0ZWQgYWNjZXB0c1JlbW92YWwocG9zaXRpb246IG51bWJlciwgY2hyOiBzdHJpbmcpOiBib29sZWFuIHtcbiAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgfVxuXG4gICAgcHVibGljIGdldCB0eXBlKCk6IElQaWxsQ2FuZGlkYXRlUGFydFtcInR5cGVcIl0ge1xuICAgICAgICByZXR1cm4gVHlwZS5QaWxsQ2FuZGlkYXRlO1xuICAgIH1cbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGdldEF1dG9Db21wbGV0ZUNyZWF0b3IoZ2V0QXV0b2NvbXBsZXRlckNvbXBvbmVudDogR2V0QXV0b2NvbXBsZXRlckNvbXBvbmVudCwgdXBkYXRlUXVlcnk6IFVwZGF0ZVF1ZXJ5KSB7XG4gICAgcmV0dXJuIChwYXJ0Q3JlYXRvcjogUGFydENyZWF0b3IpID0+IHtcbiAgICAgICAgcmV0dXJuICh1cGRhdGVDYWxsYmFjazogVXBkYXRlQ2FsbGJhY2spID0+IHtcbiAgICAgICAgICAgIHJldHVybiBuZXcgQXV0b2NvbXBsZXRlV3JhcHBlck1vZGVsKHVwZGF0ZUNhbGxiYWNrLCBnZXRBdXRvY29tcGxldGVyQ29tcG9uZW50LCB1cGRhdGVRdWVyeSwgcGFydENyZWF0b3IpO1xuICAgICAgICB9O1xuICAgIH07XG59XG5cbnR5cGUgQXV0b0NvbXBsZXRlQ3JlYXRvciA9IFJldHVyblR5cGU8dHlwZW9mIGdldEF1dG9Db21wbGV0ZUNyZWF0b3I+O1xuXG5pbnRlcmZhY2UgSUF1dG9jb21wbGV0ZUNyZWF0b3Ige1xuICAgIGNyZWF0ZTogKCh1cGRhdGVDYWxsYmFjazogVXBkYXRlQ2FsbGJhY2spID0+IEF1dG9jb21wbGV0ZVdyYXBwZXJNb2RlbCkgfCB1bmRlZmluZWQ7XG59XG5cbmV4cG9ydCBjbGFzcyBQYXJ0Q3JlYXRvciB7XG4gICAgcHJvdGVjdGVkIHJlYWRvbmx5IGF1dG9Db21wbGV0ZUNyZWF0b3I6IElBdXRvY29tcGxldGVDcmVhdG9yO1xuXG4gICAgcHVibGljIGNvbnN0cnVjdG9yKFxuICAgICAgICBwcml2YXRlIHJlYWRvbmx5IHJvb206IFJvb20sXG4gICAgICAgIHByaXZhdGUgcmVhZG9ubHkgY2xpZW50OiBNYXRyaXhDbGllbnQsXG4gICAgICAgIGF1dG9Db21wbGV0ZUNyZWF0b3I6IEF1dG9Db21wbGV0ZUNyZWF0b3IgfCBudWxsID0gbnVsbCxcbiAgICApIHtcbiAgICAgICAgLy8gcHJlLWNyZWF0ZSB0aGUgY3JlYXRvciBhcyBhbiBvYmplY3QgZXZlbiB3aXRob3V0IGNhbGxiYWNrIHNvIGl0IGNhbiBhbHJlYWR5IGJlIHBhc3NlZFxuICAgICAgICAvLyB0byBQaWxsQ2FuZGlkYXRlUGFydCAoZS5nLiB3aGlsZSBkZXNlcmlhbGl6aW5nKSBhbmQgc2V0IGxhdGVyIG9uXG4gICAgICAgIHRoaXMuYXV0b0NvbXBsZXRlQ3JlYXRvciA9IHsgY3JlYXRlOiBhdXRvQ29tcGxldGVDcmVhdG9yPy4odGhpcykgfTtcbiAgICB9XG5cbiAgICBwdWJsaWMgc2V0QXV0b0NvbXBsZXRlQ3JlYXRvcihhdXRvQ29tcGxldGVDcmVhdG9yOiBBdXRvQ29tcGxldGVDcmVhdG9yKTogdm9pZCB7XG4gICAgICAgIHRoaXMuYXV0b0NvbXBsZXRlQ3JlYXRvci5jcmVhdGUgPSBhdXRvQ29tcGxldGVDcmVhdG9yKHRoaXMpO1xuICAgIH1cblxuICAgIHB1YmxpYyBjcmVhdGVQYXJ0Rm9ySW5wdXQoaW5wdXQ6IHN0cmluZywgcGFydEluZGV4OiBudW1iZXIsIGlucHV0VHlwZT86IHN0cmluZyk6IFBhcnQge1xuICAgICAgICBzd2l0Y2ggKGlucHV0WzBdKSB7XG4gICAgICAgICAgICBjYXNlIFwiI1wiOlxuICAgICAgICAgICAgY2FzZSBcIkBcIjpcbiAgICAgICAgICAgIGNhc2UgXCI6XCI6XG4gICAgICAgICAgICBjYXNlIFwiK1wiOlxuICAgICAgICAgICAgICAgIHJldHVybiB0aGlzLnBpbGxDYW5kaWRhdGUoXCJcIik7XG4gICAgICAgICAgICBjYXNlIFwiXFxuXCI6XG4gICAgICAgICAgICAgICAgcmV0dXJuIG5ldyBOZXdsaW5lUGFydCgpO1xuICAgICAgICAgICAgZGVmYXVsdDpcbiAgICAgICAgICAgICAgICBpZiAoRU1PSklfUkVHRVgudGVzdChnZXRGaXJzdEdyYXBoZW1lKGlucHV0KSkpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIG5ldyBFbW9qaVBhcnQoKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgcmV0dXJuIG5ldyBQbGFpblBhcnQoKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHB1YmxpYyBjcmVhdGVEZWZhdWx0UGFydCh0ZXh0OiBzdHJpbmcpOiBQYXJ0IHtcbiAgICAgICAgcmV0dXJuIHRoaXMucGxhaW4odGV4dCk7XG4gICAgfVxuXG4gICAgcHVibGljIGRlc2VyaWFsaXplUGFydChwYXJ0OiBTZXJpYWxpemVkUGFydCk6IFBhcnQgfCB1bmRlZmluZWQge1xuICAgICAgICBzd2l0Y2ggKHBhcnQudHlwZSkge1xuICAgICAgICAgICAgY2FzZSBUeXBlLlBsYWluOlxuICAgICAgICAgICAgICAgIHJldHVybiB0aGlzLnBsYWluKHBhcnQudGV4dCk7XG4gICAgICAgICAgICBjYXNlIFR5cGUuTmV3bGluZTpcbiAgICAgICAgICAgICAgICByZXR1cm4gdGhpcy5uZXdsaW5lKCk7XG4gICAgICAgICAgICBjYXNlIFR5cGUuRW1vamk6XG4gICAgICAgICAgICAgICAgcmV0dXJuIHRoaXMuZW1vamkocGFydC50ZXh0KTtcbiAgICAgICAgICAgIGNhc2UgVHlwZS5BdFJvb21QaWxsOlxuICAgICAgICAgICAgICAgIHJldHVybiB0aGlzLmF0Um9vbVBpbGwocGFydC50ZXh0KTtcbiAgICAgICAgICAgIGNhc2UgVHlwZS5QaWxsQ2FuZGlkYXRlOlxuICAgICAgICAgICAgICAgIHJldHVybiB0aGlzLnBpbGxDYW5kaWRhdGUocGFydC50ZXh0KTtcbiAgICAgICAgICAgIGNhc2UgVHlwZS5Sb29tUGlsbDpcbiAgICAgICAgICAgICAgICByZXR1cm4gcGFydC5yZXNvdXJjZUlkID8gdGhpcy5yb29tUGlsbChwYXJ0LnJlc291cmNlSWQpIDogdW5kZWZpbmVkO1xuICAgICAgICAgICAgY2FzZSBUeXBlLlVzZXJQaWxsOlxuICAgICAgICAgICAgICAgIHJldHVybiBwYXJ0LnJlc291cmNlSWQgPyB0aGlzLnVzZXJQaWxsKHBhcnQudGV4dCwgcGFydC5yZXNvdXJjZUlkKSA6IHVuZGVmaW5lZDtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHB1YmxpYyBwbGFpbih0ZXh0OiBzdHJpbmcpOiBQbGFpblBhcnQge1xuICAgICAgICByZXR1cm4gbmV3IFBsYWluUGFydCh0ZXh0KTtcbiAgICB9XG5cbiAgICBwdWJsaWMgbmV3bGluZSgpOiBOZXdsaW5lUGFydCB7XG4gICAgICAgIHJldHVybiBuZXcgTmV3bGluZVBhcnQoXCJcXG5cIik7XG4gICAgfVxuXG4gICAgcHVibGljIGVtb2ppKHRleHQ6IHN0cmluZyk6IEVtb2ppUGFydCB7XG4gICAgICAgIHJldHVybiBuZXcgRW1vamlQYXJ0KHRleHQpO1xuICAgIH1cblxuICAgIHB1YmxpYyBwaWxsQ2FuZGlkYXRlKHRleHQ6IHN0cmluZyk6IFBpbGxDYW5kaWRhdGVQYXJ0IHtcbiAgICAgICAgcmV0dXJuIG5ldyBQaWxsQ2FuZGlkYXRlUGFydCh0ZXh0LCB0aGlzLmF1dG9Db21wbGV0ZUNyZWF0b3IpO1xuICAgIH1cblxuICAgIHB1YmxpYyByb29tUGlsbChhbGlhczogc3RyaW5nLCByb29tSWQ/OiBzdHJpbmcpOiBSb29tUGlsbFBhcnQge1xuICAgICAgICBsZXQgcm9vbTogUm9vbSB8IHVuZGVmaW5lZDtcbiAgICAgICAgaWYgKHJvb21JZCB8fCBhbGlhc1swXSAhPT0gXCIjXCIpIHtcbiAgICAgICAgICAgIHJvb20gPSB0aGlzLmNsaWVudC5nZXRSb29tKHJvb21JZCB8fCBhbGlhcykgPz8gdW5kZWZpbmVkO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgcm9vbSA9IHRoaXMuY2xpZW50LmdldFJvb21zKCkuZmluZCgocikgPT4ge1xuICAgICAgICAgICAgICAgIHJldHVybiByLmdldENhbm9uaWNhbEFsaWFzKCkgPT09IGFsaWFzIHx8IHIuZ2V0QWx0QWxpYXNlcygpLmluY2x1ZGVzKGFsaWFzKTtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBuZXcgUm9vbVBpbGxQYXJ0KGFsaWFzLCByb29tID8gcm9vbS5uYW1lIDogYWxpYXMsIHJvb20pO1xuICAgIH1cblxuICAgIHB1YmxpYyBhdFJvb21QaWxsKHRleHQ6IHN0cmluZyk6IEF0Um9vbVBpbGxQYXJ0IHtcbiAgICAgICAgcmV0dXJuIG5ldyBBdFJvb21QaWxsUGFydCh0ZXh0LCB0aGlzLnJvb20pO1xuICAgIH1cblxuICAgIHB1YmxpYyB1c2VyUGlsbChkaXNwbGF5TmFtZTogc3RyaW5nLCB1c2VySWQ6IHN0cmluZyk6IFVzZXJQaWxsUGFydCB7XG4gICAgICAgIGNvbnN0IG1lbWJlciA9IHRoaXMucm9vbS5nZXRNZW1iZXIodXNlcklkKTtcbiAgICAgICAgcmV0dXJuIG5ldyBVc2VyUGlsbFBhcnQodXNlcklkLCBkaXNwbGF5TmFtZSwgbWVtYmVyIHx8IHVuZGVmaW5lZCk7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBzdGF0aWMgaXNSZWdpb25hbEluZGljYXRvcihjOiBzdHJpbmcpOiBib29sZWFuIHtcbiAgICAgICAgY29uc3QgY29kZVBvaW50ID0gYy5jb2RlUG9pbnRBdCgwKSA/PyAwO1xuICAgICAgICByZXR1cm4gY29kZVBvaW50ICE9IDAgJiYgYy5sZW5ndGggPT0gMiAmJiAweDFmMWU2IDw9IGNvZGVQb2ludCAmJiBjb2RlUG9pbnQgPD0gMHgxZjFmZjtcbiAgICB9XG5cbiAgICBwdWJsaWMgcGxhaW5XaXRoRW1vamkodGV4dDogc3RyaW5nKTogKFBsYWluUGFydCB8IEVtb2ppUGFydClbXSB7XG4gICAgICAgIGNvbnN0IHBhcnRzOiAoUGxhaW5QYXJ0IHwgRW1vamlQYXJ0KVtdID0gW107XG4gICAgICAgIGxldCBwbGFpblRleHQgPSBcIlwiO1xuXG4gICAgICAgIGZvciAoY29uc3QgZGF0YSBvZiBncmFwaGVtZVNlZ21lbnRlci5zZWdtZW50KHRleHQpKSB7XG4gICAgICAgICAgICBpZiAoRU1PSklfUkVHRVgudGVzdChkYXRhLnNlZ21lbnQpKSB7XG4gICAgICAgICAgICAgICAgaWYgKHBsYWluVGV4dCkge1xuICAgICAgICAgICAgICAgICAgICBwYXJ0cy5wdXNoKHRoaXMucGxhaW4ocGxhaW5UZXh0KSk7XG4gICAgICAgICAgICAgICAgICAgIHBsYWluVGV4dCA9IFwiXCI7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIHBhcnRzLnB1c2godGhpcy5lbW9qaShkYXRhLnNlZ21lbnQpKTtcbiAgICAgICAgICAgICAgICBpZiAoUGFydENyZWF0b3IuaXNSZWdpb25hbEluZGljYXRvcih0ZXh0KSkge1xuICAgICAgICAgICAgICAgICAgICBwYXJ0cy5wdXNoKHRoaXMucGxhaW4oUkVHSU9OQUxfRU1PSklfU0VQQVJBVE9SKSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBwbGFpblRleHQgKz0gZGF0YS5zZWdtZW50O1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIGlmIChwbGFpblRleHQpIHtcbiAgICAgICAgICAgIHBhcnRzLnB1c2godGhpcy5wbGFpbihwbGFpblRleHQpKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gcGFydHM7XG4gICAgfVxuXG4gICAgcHVibGljIGNyZWF0ZU1lbnRpb25QYXJ0cyhcbiAgICAgICAgaW5zZXJ0VHJhaWxpbmdDaGFyYWN0ZXI6IGJvb2xlYW4sXG4gICAgICAgIGRpc3BsYXlOYW1lOiBzdHJpbmcsXG4gICAgICAgIHVzZXJJZDogc3RyaW5nLFxuICAgICk6IFtVc2VyUGlsbFBhcnQsIFBsYWluUGFydF0ge1xuICAgICAgICBjb25zdCBwaWxsID0gdGhpcy51c2VyUGlsbChkaXNwbGF5TmFtZSwgdXNlcklkKTtcbiAgICAgICAgaWYgKCFT