UNPKG

matrix-react-sdk

Version:
618 lines (501 loc) 64.6 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard"); Object.defineProperty(exports, "__esModule", { value: true }); exports.createMenu = createMenu; Object.defineProperty(exports, "ContextMenuButton", { enumerable: true, get: function () { return _ContextMenuButton.ContextMenuButton; } }); Object.defineProperty(exports, "ContextMenuTooltipButton", { enumerable: true, get: function () { return _ContextMenuTooltipButton.ContextMenuTooltipButton; } }); Object.defineProperty(exports, "MenuGroup", { enumerable: true, get: function () { return _MenuGroup.MenuGroup; } }); Object.defineProperty(exports, "MenuItem", { enumerable: true, get: function () { return _MenuItem.MenuItem; } }); Object.defineProperty(exports, "MenuItemCheckbox", { enumerable: true, get: function () { return _MenuItemCheckbox.MenuItemCheckbox; } }); Object.defineProperty(exports, "MenuItemRadio", { enumerable: true, get: function () { return _MenuItemRadio.MenuItemRadio; } }); Object.defineProperty(exports, "StyledMenuItemCheckbox", { enumerable: true, get: function () { return _StyledMenuItemCheckbox.StyledMenuItemCheckbox; } }); Object.defineProperty(exports, "StyledMenuItemRadio", { enumerable: true, get: function () { return _StyledMenuItemRadio.StyledMenuItemRadio; } }); exports.default = exports.useContextMenu = exports.alwaysAboveRightOf = exports.alwaysAboveLeftOf = exports.aboveLeftOf = exports.toRightOf = exports.ContextMenu = exports.ChevronFace = void 0; var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends")); var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty")); var _react = _interopRequireWildcard(require("react")); var _reactDom = _interopRequireDefault(require("react-dom")); var _classnames = _interopRequireDefault(require("classnames")); var _Keyboard = require("../../Keyboard"); var _replaceableComponent = require("../../utils/replaceableComponent"); var _ContextMenuButton = require("../../accessibility/context_menu/ContextMenuButton"); var _ContextMenuTooltipButton = require("../../accessibility/context_menu/ContextMenuTooltipButton"); var _MenuGroup = require("../../accessibility/context_menu/MenuGroup"); var _MenuItem = require("../../accessibility/context_menu/MenuItem"); var _MenuItemCheckbox = require("../../accessibility/context_menu/MenuItemCheckbox"); var _MenuItemRadio = require("../../accessibility/context_menu/MenuItemRadio"); var _StyledMenuItemCheckbox = require("../../accessibility/context_menu/StyledMenuItemCheckbox"); var _StyledMenuItemRadio = require("../../accessibility/context_menu/StyledMenuItemRadio"); var _dec, _class, _class2, _temp, _dec2, _class3; function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; } function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { (0, _defineProperty2.default)(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; } // Shamelessly ripped off Modal.js. There's probably a better way // of doing reusable widgets like dialog boxes & menus where we go and // pass in a custom control as the actual body. const ContextualMenuContainerId = "mx_ContextualMenu_Container"; function getOrCreateContainer() /*: HTMLDivElement*/ { let container = document.getElementById(ContextualMenuContainerId); if (!container) { container = document.createElement("div"); container.id = ContextualMenuContainerId; document.body.appendChild(container); } return container; } const ARIA_MENU_ITEM_ROLES = new Set(["menuitem", "menuitemcheckbox", "menuitemradio"]); let ChevronFace; exports.ChevronFace = ChevronFace; (function (ChevronFace) { ChevronFace["Top"] = "top"; ChevronFace["Bottom"] = "bottom"; ChevronFace["Left"] = "left"; ChevronFace["Right"] = "right"; ChevronFace["None"] = "none"; })(ChevronFace || (exports.ChevronFace = ChevronFace = {})); /*:: export interface IProps extends IPosition { menuWidth?: number; menuHeight?: number; chevronOffset?: number; chevronFace?: ChevronFace; menuPaddingTop?: number; menuPaddingBottom?: number; menuPaddingLeft?: number; menuPaddingRight?: number; zIndex?: number; // If true, insert an invisible screen-sized element behind the menu that when clicked will close it. hasBackground?: boolean; // whether this context menu should be focus managed. If false it must handle itself managed?: boolean; wrapperClassName?: string; // Function to be called on menu close onFinished(); // on resize callback windowResize?(); }*/ // Generic ContextMenu Portal wrapper // all options inside the menu should be of role=menuitem/menuitemcheckbox/menuitemradiobutton and have tabIndex={-1} // this will allow the ContextMenu to manage its own focus using arrow keys as per the ARIA guidelines. let ContextMenu = (_dec = (0, _replaceableComponent.replaceableComponent)("structures.ContextMenu"), _dec(_class = (_temp = _class2 = class ContextMenu extends _react.default.PureComponent /*:: <IProps, IState>*/ { constructor(props, context) { super(props, context); (0, _defineProperty2.default)(this, "initialFocus", void 0); (0, _defineProperty2.default)(this, "collectContextMenuRect", element => { // We don't need to clean up when unmounting, so ignore if (!element) return; let first = element.querySelector('[role^="menuitem"]'); if (!first) { first = element.querySelector('[tab-index]'); } if (first) { first.focus(); } this.setState({ contextMenuElem: element }); }); (0, _defineProperty2.default)(this, "onContextMenu", e => { if (this.props.onFinished) { this.props.onFinished(); e.preventDefault(); e.stopPropagation(); const x = e.clientX; const y = e.clientY; // XXX: This isn't pretty but the only way to allow opening a different context menu on right click whilst // a context menu and its click-guard are up without completely rewriting how the context menus work. setImmediate(() => { const clickEvent = document.createEvent('MouseEvents'); clickEvent.initMouseEvent('contextmenu', true, true, window, 0, 0, 0, x, y, false, false, false, false, 0, null); document.elementFromPoint(x, y).dispatchEvent(clickEvent); }); } }); (0, _defineProperty2.default)(this, "onContextMenuPreventBubbling", e => { // stop propagation so that any context menu handlers don't leak out of this context menu // but do not inhibit the default browser menu e.stopPropagation(); }); (0, _defineProperty2.default)(this, "onFinished", (ev /*: React.MouseEvent*/ ) => { ev.stopPropagation(); ev.preventDefault(); if (this.props.onFinished) this.props.onFinished(); }); (0, _defineProperty2.default)(this, "onMoveFocus", (element /*: Element*/ , up /*: boolean*/ ) => { let descending = false; // are we currently descending or ascending through the DOM tree? do { const child = up ? element.lastElementChild : element.firstElementChild; const sibling = up ? element.previousElementSibling : element.nextElementSibling; if (descending) { if (child) { element = child; } else if (sibling) { element = sibling; } else { descending = false; element = element.parentElement; } } else { if (sibling) { element = sibling; descending = true; } else { element = element.parentElement; } } if (element) { if (element.classList.contains("mx_ContextualMenu")) { // we hit the top element = up ? element.lastElementChild : element.firstElementChild; descending = true; } } } while (element && !ARIA_MENU_ITEM_ROLES.has(element.getAttribute("role"))); if (element) { element.focus(); } }); (0, _defineProperty2.default)(this, "onMoveFocusHomeEnd", (element /*: Element*/ , up /*: boolean*/ ) => { let results = element.querySelectorAll('[role^="menuitem"]'); if (!results) { results = element.querySelectorAll('[tab-index]'); } if (results && results.length) { if (up) { results[0].focus(); } else { results[results.length - 1].focus(); } } }); (0, _defineProperty2.default)(this, "onKeyDown", (ev /*: React.KeyboardEvent*/ ) => { // don't let keyboard handling escape the context menu ev.stopPropagation(); if (!this.props.managed) { if (ev.key === _Keyboard.Key.ESCAPE) { this.props.onFinished(); ev.preventDefault(); } return; } let handled = true; switch (ev.key) { case _Keyboard.Key.TAB: case _Keyboard.Key.ESCAPE: case _Keyboard.Key.ARROW_LEFT: // close on left and right arrows too for when it is a context menu on a <Toolbar /> case _Keyboard.Key.ARROW_RIGHT: this.props.onFinished(); break; case _Keyboard.Key.ARROW_UP: this.onMoveFocus(ev.target, true); break; case _Keyboard.Key.ARROW_DOWN: this.onMoveFocus(ev.target, false); break; case _Keyboard.Key.HOME: this.onMoveFocusHomeEnd(this.state.contextMenuElem, true); break; case _Keyboard.Key.END: this.onMoveFocusHomeEnd(this.state.contextMenuElem, false); break; default: handled = false; } if (handled) { // consume all other keys in context menu ev.preventDefault(); } }); this.state = { contextMenuElem: null }; // persist what had focus when we got initialized so we can return it after this.initialFocus = document.activeElement; } componentWillUnmount() { // return focus to the thing which had it before us this.initialFocus.focus(); } renderMenu(hasBackground = this.props.hasBackground) { const position /*: Partial<Writeable<DOMRect>>*/ = {}; const props = this.props; if (props.top) { position.top = props.top; } else { position.bottom = props.bottom; } let chevronFace /*: ChevronFace*/ ; if (props.left) { position.left = props.left; chevronFace = ChevronFace.Left; } else { position.right = props.right; chevronFace = ChevronFace.Right; } const contextMenuRect = this.state.contextMenuElem ? this.state.contextMenuElem.getBoundingClientRect() : null; const chevronOffset /*: CSSProperties*/ = {}; if (props.chevronFace) { chevronFace = props.chevronFace; } const hasChevron = chevronFace && chevronFace !== ChevronFace.None; if (chevronFace === ChevronFace.Top || chevronFace === ChevronFace.Bottom) { chevronOffset.left = props.chevronOffset; } else if (position.top !== undefined) { const target = position.top; // By default, no adjustment is made let adjusted = target; // If we know the dimensions of the context menu, adjust its position // such that it does not leave the (padded) window. if (contextMenuRect) { const padding = 10; adjusted = Math.min(position.top, document.body.clientHeight - contextMenuRect.height - padding); } position.top = adjusted; chevronOffset.top = Math.max(props.chevronOffset, props.chevronOffset + target - adjusted); } let chevron; if (hasChevron) { chevron = /*#__PURE__*/_react.default.createElement("div", { style: chevronOffset, className: "mx_ContextualMenu_chevron_" + chevronFace }); } const menuClasses = (0, _classnames.default)({ 'mx_ContextualMenu': true, 'mx_ContextualMenu_left': !hasChevron && position.left, 'mx_ContextualMenu_right': !hasChevron && position.right, 'mx_ContextualMenu_top': !hasChevron && position.top, 'mx_ContextualMenu_bottom': !hasChevron && position.bottom, 'mx_ContextualMenu_withChevron_left': chevronFace === ChevronFace.Left, 'mx_ContextualMenu_withChevron_right': chevronFace === ChevronFace.Right, 'mx_ContextualMenu_withChevron_top': chevronFace === ChevronFace.Top, 'mx_ContextualMenu_withChevron_bottom': chevronFace === ChevronFace.Bottom }); const menuStyle /*: CSSProperties*/ = {}; if (props.menuWidth) { menuStyle.width = props.menuWidth; } if (props.menuHeight) { menuStyle.height = props.menuHeight; } if (!isNaN(Number(props.menuPaddingTop))) { menuStyle["paddingTop"] = props.menuPaddingTop; } if (!isNaN(Number(props.menuPaddingLeft))) { menuStyle["paddingLeft"] = props.menuPaddingLeft; } if (!isNaN(Number(props.menuPaddingBottom))) { menuStyle["paddingBottom"] = props.menuPaddingBottom; } if (!isNaN(Number(props.menuPaddingRight))) { menuStyle["paddingRight"] = props.menuPaddingRight; } const wrapperStyle = {}; if (!isNaN(Number(props.zIndex))) { menuStyle["zIndex"] = props.zIndex + 1; wrapperStyle["zIndex"] = props.zIndex; } let background; if (hasBackground) { background = /*#__PURE__*/_react.default.createElement("div", { className: "mx_ContextualMenu_background", style: wrapperStyle, onClick: this.onFinished, onContextMenu: this.onContextMenu }); } return /*#__PURE__*/_react.default.createElement("div", { className: (0, _classnames.default)("mx_ContextualMenu_wrapper", this.props.wrapperClassName), style: _objectSpread(_objectSpread({}, position), wrapperStyle), onKeyDown: this.onKeyDown, onContextMenu: this.onContextMenuPreventBubbling }, /*#__PURE__*/_react.default.createElement("div", { className: menuClasses, style: menuStyle, ref: this.collectContextMenuRect, role: this.props.managed ? "menu" : undefined }, chevron, props.children), background); } render() /*: React.ReactChild*/ { return /*#__PURE__*/_reactDom.default.createPortal(this.renderMenu(), getOrCreateContainer()); } }, (0, _defineProperty2.default)(_class2, "defaultProps", { hasBackground: true, managed: true }), _temp)) || _class); // Placement method for <ContextMenu /> to position context menu to right of elementRect with chevronOffset exports.ContextMenu = ContextMenu; const toRightOf = (elementRect /*: Pick<DOMRect, "right" | "top" | "height">*/ , chevronOffset = 12) => { const left = elementRect.right + window.pageXOffset + 3; let top = elementRect.top + elementRect.height / 2 + window.pageYOffset; top -= chevronOffset + 8; // where 8 is half the height of the chevron return { left, top, chevronOffset }; }; // Placement method for <ContextMenu /> to position context menu right-aligned and flowing to the left of elementRect, // and either above or below: wherever there is more space (maybe this should be aboveOrBelowLeftOf?) exports.toRightOf = toRightOf; const aboveLeftOf = (elementRect /*: DOMRect*/ , chevronFace = ChevronFace.None, vPadding = 0) => { const menuOptions /*: IPosition & { chevronFace: ChevronFace }*/ = { chevronFace }; const buttonRight = elementRect.right + window.pageXOffset; const buttonBottom = elementRect.bottom + window.pageYOffset; const buttonTop = elementRect.top + window.pageYOffset; // Align the right edge of the menu to the right edge of the button menuOptions.right = window.innerWidth - buttonRight; // Align the menu vertically on whichever side of the button has more space available. if (buttonBottom < window.innerHeight / 2) { menuOptions.top = buttonBottom + vPadding; } else { menuOptions.bottom = window.innerHeight - buttonTop + vPadding; } return menuOptions; }; // Placement method for <ContextMenu /> to position context menu right-aligned and flowing to the left of elementRect // and always above elementRect exports.aboveLeftOf = aboveLeftOf; const alwaysAboveLeftOf = (elementRect /*: DOMRect*/ , chevronFace = ChevronFace.None, vPadding = 0) => { const menuOptions /*: IPosition & { chevronFace: ChevronFace }*/ = { chevronFace }; const buttonRight = elementRect.right + window.pageXOffset; const buttonBottom = elementRect.bottom + window.pageYOffset; const buttonTop = elementRect.top + window.pageYOffset; // Align the right edge of the menu to the right edge of the button menuOptions.right = window.innerWidth - buttonRight; // Align the menu vertically on whichever side of the button has more space available. if (buttonBottom < window.innerHeight / 2) { menuOptions.top = buttonBottom + vPadding; } else { menuOptions.bottom = window.innerHeight - buttonTop + vPadding; } return menuOptions; }; // Placement method for <ContextMenu /> to position context menu right-aligned and flowing to the right of elementRect // and always above elementRect exports.alwaysAboveLeftOf = alwaysAboveLeftOf; const alwaysAboveRightOf = (elementRect /*: DOMRect*/ , chevronFace = ChevronFace.None, vPadding = 0) => { const menuOptions /*: IPosition & { chevronFace: ChevronFace }*/ = { chevronFace }; const buttonLeft = elementRect.left + window.pageXOffset; const buttonTop = elementRect.top + window.pageYOffset; // Align the left edge of the menu to the left edge of the button menuOptions.left = buttonLeft; // Align the menu vertically above the menu menuOptions.bottom = window.innerHeight - buttonTop + vPadding; return menuOptions; }; exports.alwaysAboveRightOf = alwaysAboveRightOf; const useContextMenu = () => /*: ContextMenuTuple<T>*/ { const button = (0, _react.useRef)(null); const [isOpen, setIsOpen] = (0, _react.useState)(false); const open = () => { setIsOpen(true); }; const close = () => { setIsOpen(false); }; return [isOpen, button, open, close, setIsOpen]; }; exports.useContextMenu = useContextMenu; let LegacyContextMenu = (_dec2 = (0, _replaceableComponent.replaceableComponent)("structures.LegacyContextMenu"), _dec2(_class3 = class LegacyContextMenu extends ContextMenu { render() { return this.renderMenu(false); } }) || _class3); exports.default = LegacyContextMenu; // XXX: Deprecated, used only for dynamic Tooltips. Avoid using at all costs. function createMenu(ElementClass, props) { const onFinished = function (...args) { _reactDom.default.unmountComponentAtNode(getOrCreateContainer()); if (props && props.onFinished) { props.onFinished.apply(null, args); } }; const menu = /*#__PURE__*/_react.default.createElement(LegacyContextMenu, (0, _extends2.default)({}, props, { onFinished: onFinished // eslint-disable-line react/jsx-no-bind , windowResize: onFinished // eslint-disable-line react/jsx-no-bind }), /*#__PURE__*/_react.default.createElement(ElementClass, (0, _extends2.default)({}, props, { onFinished: onFinished }))); _reactDom.default.render(menu, getOrCreateContainer()); return { close: onFinished }; } // re-export the semantic helper components for simplicity //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9jb21wb25lbnRzL3N0cnVjdHVyZXMvQ29udGV4dE1lbnUudHN4Il0sIm5hbWVzIjpbIkNvbnRleHR1YWxNZW51Q29udGFpbmVySWQiLCJnZXRPckNyZWF0ZUNvbnRhaW5lciIsImNvbnRhaW5lciIsImRvY3VtZW50IiwiZ2V0RWxlbWVudEJ5SWQiLCJjcmVhdGVFbGVtZW50IiwiaWQiLCJib2R5IiwiYXBwZW5kQ2hpbGQiLCJBUklBX01FTlVfSVRFTV9ST0xFUyIsIlNldCIsIkNoZXZyb25GYWNlIiwiQ29udGV4dE1lbnUiLCJSZWFjdCIsIlB1cmVDb21wb25lbnQiLCJjb25zdHJ1Y3RvciIsInByb3BzIiwiY29udGV4dCIsImVsZW1lbnQiLCJmaXJzdCIsInF1ZXJ5U2VsZWN0b3IiLCJmb2N1cyIsInNldFN0YXRlIiwiY29udGV4dE1lbnVFbGVtIiwiZSIsIm9uRmluaXNoZWQiLCJwcmV2ZW50RGVmYXVsdCIsInN0b3BQcm9wYWdhdGlvbiIsIngiLCJjbGllbnRYIiwieSIsImNsaWVudFkiLCJzZXRJbW1lZGlhdGUiLCJjbGlja0V2ZW50IiwiY3JlYXRlRXZlbnQiLCJpbml0TW91c2VFdmVudCIsIndpbmRvdyIsImVsZW1lbnRGcm9tUG9pbnQiLCJkaXNwYXRjaEV2ZW50IiwiZXYiLCJ1cCIsImRlc2NlbmRpbmciLCJjaGlsZCIsImxhc3RFbGVtZW50Q2hpbGQiLCJmaXJzdEVsZW1lbnRDaGlsZCIsInNpYmxpbmciLCJwcmV2aW91c0VsZW1lbnRTaWJsaW5nIiwibmV4dEVsZW1lbnRTaWJsaW5nIiwicGFyZW50RWxlbWVudCIsImNsYXNzTGlzdCIsImNvbnRhaW5zIiwiaGFzIiwiZ2V0QXR0cmlidXRlIiwicmVzdWx0cyIsInF1ZXJ5U2VsZWN0b3JBbGwiLCJsZW5ndGgiLCJtYW5hZ2VkIiwia2V5IiwiS2V5IiwiRVNDQVBFIiwiaGFuZGxlZCIsIlRBQiIsIkFSUk9XX0xFRlQiLCJBUlJPV19SSUdIVCIsIkFSUk9XX1VQIiwib25Nb3ZlRm9jdXMiLCJ0YXJnZXQiLCJBUlJPV19ET1dOIiwiSE9NRSIsIm9uTW92ZUZvY3VzSG9tZUVuZCIsInN0YXRlIiwiRU5EIiwiaW5pdGlhbEZvY3VzIiwiYWN0aXZlRWxlbWVudCIsImNvbXBvbmVudFdpbGxVbm1vdW50IiwicmVuZGVyTWVudSIsImhhc0JhY2tncm91bmQiLCJwb3NpdGlvbiIsInRvcCIsImJvdHRvbSIsImNoZXZyb25GYWNlIiwibGVmdCIsIkxlZnQiLCJyaWdodCIsIlJpZ2h0IiwiY29udGV4dE1lbnVSZWN0IiwiZ2V0Qm91bmRpbmdDbGllbnRSZWN0IiwiY2hldnJvbk9mZnNldCIsImhhc0NoZXZyb24iLCJOb25lIiwiVG9wIiwiQm90dG9tIiwidW5kZWZpbmVkIiwiYWRqdXN0ZWQiLCJwYWRkaW5nIiwiTWF0aCIsIm1pbiIsImNsaWVudEhlaWdodCIsImhlaWdodCIsIm1heCIsImNoZXZyb24iLCJtZW51Q2xhc3NlcyIsIm1lbnVTdHlsZSIsIm1lbnVXaWR0aCIsIndpZHRoIiwibWVudUhlaWdodCIsImlzTmFOIiwiTnVtYmVyIiwibWVudVBhZGRpbmdUb3AiLCJtZW51UGFkZGluZ0xlZnQiLCJtZW51UGFkZGluZ0JvdHRvbSIsIm1lbnVQYWRkaW5nUmlnaHQiLCJ3cmFwcGVyU3R5bGUiLCJ6SW5kZXgiLCJiYWNrZ3JvdW5kIiwib25Db250ZXh0TWVudSIsIndyYXBwZXJDbGFzc05hbWUiLCJvbktleURvd24iLCJvbkNvbnRleHRNZW51UHJldmVudEJ1YmJsaW5nIiwiY29sbGVjdENvbnRleHRNZW51UmVjdCIsImNoaWxkcmVuIiwicmVuZGVyIiwiUmVhY3RET00iLCJjcmVhdGVQb3J0YWwiLCJ0b1JpZ2h0T2YiLCJlbGVtZW50UmVjdCIsInBhZ2VYT2Zmc2V0IiwicGFnZVlPZmZzZXQiLCJhYm92ZUxlZnRPZiIsInZQYWRkaW5nIiwibWVudU9wdGlvbnMiLCJidXR0b25SaWdodCIsImJ1dHRvbkJvdHRvbSIsImJ1dHRvblRvcCIsImlubmVyV2lkdGgiLCJpbm5lckhlaWdodCIsImFsd2F5c0Fib3ZlTGVmdE9mIiwiYWx3YXlzQWJvdmVSaWdodE9mIiwiYnV0dG9uTGVmdCIsInVzZUNvbnRleHRNZW51IiwiYnV0dG9uIiwiaXNPcGVuIiwic2V0SXNPcGVuIiwib3BlbiIsImNsb3NlIiwiTGVnYWN5Q29udGV4dE1lbnUiLCJjcmVhdGVNZW51IiwiRWxlbWVudENsYXNzIiwiYXJncyIsInVubW91bnRDb21wb25lbnRBdE5vZGUiLCJhcHBseSIsIm1lbnUiXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFrQkE7O0FBQ0E7O0FBQ0E7O0FBRUE7O0FBRUE7O0FBK2RBOztBQUNBOztBQUNBOztBQUNBOztBQUNBOztBQUNBOztBQUNBOztBQUNBOzs7Ozs7OztBQXBlQTtBQUNBO0FBQ0E7QUFFQSxNQUFNQSx5QkFBeUIsR0FBRyw2QkFBbEM7O0FBRUEsU0FBU0Msb0JBQVQ7QUFBQTtBQUFnRDtBQUM1QyxNQUFJQyxTQUFTLEdBQUdDLFFBQVEsQ0FBQ0MsY0FBVCxDQUF3QkoseUJBQXhCLENBQWhCOztBQUVBLE1BQUksQ0FBQ0UsU0FBTCxFQUFnQjtBQUNaQSxJQUFBQSxTQUFTLEdBQUdDLFFBQVEsQ0FBQ0UsYUFBVCxDQUF1QixLQUF2QixDQUFaO0FBQ0FILElBQUFBLFNBQVMsQ0FBQ0ksRUFBVixHQUFlTix5QkFBZjtBQUNBRyxJQUFBQSxRQUFRLENBQUNJLElBQVQsQ0FBY0MsV0FBZCxDQUEwQk4sU0FBMUI7QUFDSDs7QUFFRCxTQUFPQSxTQUFQO0FBQ0g7O0FBRUQsTUFBTU8sb0JBQW9CLEdBQUcsSUFBSUMsR0FBSixDQUFRLENBQUMsVUFBRCxFQUFhLGtCQUFiLEVBQWlDLGVBQWpDLENBQVIsQ0FBN0I7SUFTWUMsVzs7O1dBQUFBLFc7QUFBQUEsRUFBQUEsVztBQUFBQSxFQUFBQSxXO0FBQUFBLEVBQUFBLFc7QUFBQUEsRUFBQUEsVztBQUFBQSxFQUFBQSxXO0dBQUFBLFcsMkJBQUFB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WixFQUFrQjtBQUNqQzFCLHNCQUFTMkIsc0JBQVQsQ0FBZ0NwSixvQkFBb0IsRUFBcEQ7O0FBRUEsUUFBSWUsS0FBSyxJQUFJQSxLQUFLLENBQUNTLFVBQW5CLEVBQStCO0FBQzNCVCxNQUFBQSxLQUFLLENBQUNTLFVBQU4sQ0FBaUI2SCxLQUFqQixDQUF1QixJQUF2QixFQUE2QkYsSUFBN0I7QUFDSDtBQUNKLEdBTkQ7O0FBUUEsUUFBTUcsSUFBSSxnQkFBRyw2QkFBQyxpQkFBRCw2QkFDTHZJLEtBREs7QUFFVCxJQUFBLFVBQVUsRUFBRVMsVUFGSCxDQUVlO0FBRmY7QUFHVCxJQUFBLFlBQVksRUFBRUEsVUFITCxDQUdpQjs7QUFIakIsbUJBS1QsNkJBQUMsWUFBRCw2QkFBa0JULEtBQWxCO0FBQXlCLElBQUEsVUFBVSxFQUFFUztBQUFyQyxLQUxTLENBQWI7O0FBUUFpRyxvQkFBU0QsTUFBVCxDQUFnQjhCLElBQWhCLEVBQXNCdEosb0JBQW9CLEVBQTFDOztBQUVBLFNBQU87QUFBQytJLElBQUFBLEtBQUssRUFBRXZIO0FBQVIsR0FBUDtBQUNILEMsQ0FFRCIsInNvdXJjZXNDb250ZW50IjpbIi8qXG5Db3B5cmlnaHQgMjAxNSwgMjAxNiBPcGVuTWFya2V0IEx0ZFxuQ29weXJpZ2h0IDIwMTggTmV3IFZlY3RvciBMdGRcbkNvcHlyaWdodCAyMDE5IFRoZSBNYXRyaXgub3JnIEZvdW5kYXRpb24gQy5JLkMuXG5cbkxpY2Vuc2VkIHVuZGVyIHRoZSBBcGFjaGUgTGljZW5zZSwgVmVyc2lvbiAyLjAgKHRoZSBcIkxpY2Vuc2VcIik7XG55b3UgbWF5IG5vdCB1c2UgdGhpcyBmaWxlIGV4Y2VwdCBpbiBjb21wbGlhbmNlIHdpdGggdGhlIExpY2Vuc2UuXG5Zb3UgbWF5IG9idGFpbiBhIGNvcHkgb2YgdGhlIExpY2Vuc2UgYXRcblxuICAgIGh0dHA6Ly93d3cuYXBhY2hlLm9yZy9saWNlbnNlcy9MSUNFTlNFLTIuMFxuXG5Vbmxlc3MgcmVxdWlyZWQgYnkgYXBwbGljYWJsZSBsYXcgb3IgYWdyZWVkIHRvIGluIHdyaXRpbmcsIHNvZnR3YXJlXG5kaXN0cmlidXRlZCB1bmRlciB0aGUgTGljZW5zZSBpcyBkaXN0cmlidXRlZCBvbiBhbiBcIkFTIElTXCIgQkFTSVMsXG5XSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IgaW1wbGllZC5cblNlZSB0aGUgTGljZW5zZSBmb3IgdGhlIHNwZWNpZmljIGxhbmd1YWdlIGdvdmVybmluZyBwZXJtaXNzaW9ucyBhbmRcbmxpbWl0YXRpb25zIHVuZGVyIHRoZSBMaWNlbnNlLlxuKi9cblxuaW1wb3J0IFJlYWN0LCB7Q1NTUHJvcGVydGllcywgUmVmT2JqZWN0LCB1c2VSZWYsIHVzZVN0YXRlfSBmcm9tIFwicmVhY3RcIjtcbmltcG9ydCBSZWFjdERPTSBmcm9tIFwicmVhY3QtZG9tXCI7XG5pbXBvcnQgY2xhc3NOYW1lcyBmcm9tIFwiY2xhc3NuYW1lc1wiO1xuXG5pbXBvcnQge0tleX0gZnJvbSBcIi4uLy4uL0tleWJvYXJkXCI7XG5pbXBvcnQge1dyaXRlYWJsZX0gZnJvbSBcIi4uLy4uL0B0eXBlcy9jb21tb25cIjtcbmltcG9ydCB7cmVwbGFjZWFibGVDb21wb25lbnR9IGZyb20gXCIuLi8uLi91dGlscy9yZXBsYWNlYWJsZUNvbXBvbmVudFwiO1xuXG4vLyBTaGFtZWxlc3NseSByaXBwZWQgb2ZmIE1vZGFsLmpzLiAgVGhlcmUncyBwcm9iYWJseSBhIGJldHRlciB3YXlcbi8vIG9mIGRvaW5nIHJldXNhYmxlIHdpZGdldHMgbGlrZSBkaWFsb2cgYm94ZXMgJiBtZW51cyB3aGVyZSB3ZSBnbyBhbmRcbi8vIHBhc3MgaW4gYSBjdXN0b20gY29udHJvbCBhcyB0aGUgYWN0dWFsIGJvZHkuXG5cbmNvbnN0IENvbnRleHR1YWxNZW51Q29udGFpbmVySWQgPSBcIm14X0NvbnRleHR1YWxNZW51X0NvbnRhaW5lclwiO1xuXG5mdW5jdGlvbiBnZXRPckNyZWF0ZUNvbnRhaW5lcigpOiBIVE1MRGl2RWxlbWVudCB7XG4gICAgbGV0IGNvbnRhaW5lciA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKENvbnRleHR1YWxNZW51Q29udGFpbmVySWQpIGFzIEhUTUxEaXZFbGVtZW50O1xuXG4gICAgaWYgKCFjb250YWluZXIpIHtcbiAgICAgICAgY29udGFpbmVyID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudChcImRpdlwiKTtcbiAgICAgICAgY29udGFpbmVyLmlkID0gQ29udGV4dHVhbE1lbnVDb250YWluZXJJZDtcbiAgICAgICAgZG9jdW1lbnQuYm9keS5hcHBlbmRDaGlsZChjb250YWluZXIpO1xuICAgIH1cblxuICAgIHJldHVybiBjb250YWluZXI7XG59XG5cbmNvbnN0IEFSSUFfTUVOVV9JVEVNX1JPTEVTID0gbmV3IFNldChbXCJtZW51aXRlbVwiLCBcIm1lbnVpdGVtY2hlY2tib3hcIiwgXCJtZW51aXRlbXJhZGlvXCJdKTtcblxuaW50ZXJmYWNlIElQb3NpdGlvbiB7XG4gICAgdG9wPzogbnVtYmVyO1xuICAgIGJvdHRvbT86IG51bWJlcjtcbiAgICBsZWZ0PzogbnVtYmVyO1xuICAgIHJpZ2h0PzogbnVtYmVyO1xufVxuXG5leHBvcnQgZW51bSBDaGV2cm9uRmFjZSB7XG4gICAgVG9wID0gXCJ0b3BcIixcbiAgICBCb3R0b20gPSBcImJvdHRvbVwiLFxuICAgIExlZnQgPSBcImxlZnRcIixcbiAgICBSaWdodCA9IFwicmlnaHRcIixcbiAgICBOb25lID0gXCJub25lXCIsXG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgSVByb3BzIGV4dGVuZHMgSVBvc2l0aW9uIHtcbiAgICBtZW51V2lkdGg/OiBudW1iZXI7XG4gICAgbWVudUhlaWdodD86IG51bWJlcjtcblxuICAgIGNoZXZyb25PZmZzZXQ/OiBudW1iZXI7XG4gICAgY2hldnJvbkZhY2U/OiBDaGV2cm9uRmFjZTtcblxuICAgIG1lbnVQYWRkaW5nVG9wPzogbnVtYmVyO1xuICAgIG1lbnVQYWRkaW5nQm90dG9tPzogbnVtYmVyO1xuICAgIG1lbnVQYWRkaW5nTGVmdD86IG51bWJlcjtcbiAgICBtZW51UGFkZGluZ1JpZ2h0PzogbnVtYmVyO1xuXG4gICAgekluZGV4PzogbnVtYmVyO1xuXG4gICAgLy8gSWYgdHJ1ZSwgaW5zZXJ0IGFuIGludmlzaWJsZSBzY3JlZW4tc2l6ZWQgZWxlbWVudCBiZWhpbmQgdGhlIG1lbnUgdGhhdCB3aGVuIGNsaWNrZWQgd2lsbCBjbG9zZSBpdC5cbiAgICBoYXNCYWNrZ3JvdW5kPzogYm9vbGVhbjtcbiAgICAvLyB3aGV0aGVyIHRoaXMgY29udGV4dCBtZW51IHNob3VsZCBiZSBmb2N1cyBtYW5hZ2VkLiBJZiBmYWxzZSBpdCBtdXN0IGhhbmRsZSBpdHNlbGZcbiAgICBtYW5hZ2VkPzogYm9vbGVhbjtcbiAgICB3cmFwcGVyQ2xhc3NOYW1lPzogc3RyaW5nO1xuXG4gICAgLy8gRnVuY3Rpb24gdG8gYmUgY2FsbGVkIG9uIG1lbnUgY2xvc2VcbiAgICBvbkZpbmlzaGVkKCk7XG4gICAgLy8gb24gcmVzaXplIGNhbGxiYWNrXG4gICAgd2luZG93UmVzaXplPygpO1xufVxuXG5pbnRlcmZhY2UgSVN0YXRlIHtcbiAgICBjb250ZXh0TWVudUVsZW06IEhUTUxEaXZFbGVtZW50O1xufVxuXG4vLyBHZW5lcmljIENvbnRleHRNZW51IFBvcnRhbCB3cmFwcGVyXG4vLyBhbGwgb3B0aW9ucyBpbnNpZGUgdGhlIG1lbnUgc2hvdWxkIGJlIG9mIHJvbGU9bWVudWl0ZW0vbWVudWl0ZW1jaGVja2JveC9tZW51aXRlbXJhZGlvYnV0dG9uIGFuZCBoYXZlIHRhYkluZGV4PXstMX1cbi8vIHRoaXMgd2lsbCBhbGxvdyB0aGUgQ29udGV4dE1lbnUgdG8gbWFuYWdlIGl0cyBvd24gZm9jdXMgdXNpbmcgYXJyb3cga2V5cyBhcyBwZXIgdGhlIEFSSUEgZ3VpZGVsaW5lcy5cbkByZXBsYWNlYWJsZUNvbXBvbmVudChcInN0cnVjdHVyZXMuQ29udGV4dE1lbnVcIilcbmV4cG9ydCBjbGFzcyBDb250ZXh0TWVudSBleHRlbmRzIFJlYWN0LlB1cmVDb21wb25lbnQ8SVByb3BzLCBJU3RhdGU+IHtcbiAgICBwcml2YXRlIGluaXRpYWxGb2N1czogSFRNTEVsZW1lbnQ7XG5cbiAgICBzdGF0aWMgZGVmYXVsdFByb3BzID0ge1xuICAgICAgICBoYXNCYWNrZ3JvdW5kOiB0cnVlLFxuICAgICAgICBtYW5hZ2VkOiB0cnVlLFxuICAgIH07XG5cbiAgICBjb25zdHJ1Y3Rvcihwcm9wcywgY29udGV4dCkge1xuICAgICAgICBzdXBlcihwcm9wcywgY29udGV4dCk7XG4gICAgICAgIHRoaXMuc3RhdGUgPSB7XG4gICAgICAgICAgICBjb250ZXh0TWVudUVsZW06IG51bGwsXG4gICAgICAgIH07XG5cbiAgICAgICAgLy8gcGVyc2lzdCB3aGF0IGhhZCBmb2N1cyB3aGVuIHdlIGdvdCBpbml0aWFsaXplZCBzbyB3ZSBjYW4gcmV0dXJuIGl0IGFmdGVyXG4gICAgICAgIHRoaXMuaW5pdGlhbEZvY3VzID0gZG9jdW1lbnQuYWN0aXZlRWxlbWVudCBhcyBIVE1MRWxlbWVudDtcbiAgICB9XG5cbiAgICBjb21wb25lbnRXaWxsVW5tb3VudCgpIHtcbiAgICAgICAgLy8gcmV0dXJuIGZvY3VzIHRvIHRoZSB0aGluZyB3aGljaCBoYWQgaXQgYmVmb3JlIHVzXG4gICAgICAgIHRoaXMuaW5pdGlhbEZvY3VzLmZvY3VzKCk7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBjb2xsZWN0Q29udGV4dE1lbnVSZWN0ID0gKGVsZW1lbnQpID0+IHtcbiAgICAgICAgLy8gV2UgZG9uJ3QgbmVlZCB0byBjbGVhbiB1cCB3aGVuIHVubW91bnRpbmcsIHNvIGlnbm9yZVxuICAgICAgICBpZiAoIWVsZW1lbnQpIHJldHVybjtcblxuICAgICAgICBsZXQgZmlyc3QgPSBlbGVtZW50LnF1ZXJ5U2VsZWN0b3IoJ1tyb2xlXj1cIm1lbnVpdGVtXCJdJyk7XG4gICAgICAgIGlmICghZmlyc3QpIHtcbiAgICAgICAgICAgIGZpcnN0ID0gZWxlbWVudC5xdWVyeVNlbGVjdG9yKCdbdGFiLWluZGV4XScpO1xuICAgICAgICB9XG4gICAgICAgIGlmIChmaXJzdCkge1xuICAgICAgICAgICAgZmlyc3QuZm9jdXMoKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgY29udGV4dE1lbnVFbGVtOiBlbGVtZW50LFxuICAgICAgICB9KTtcbiAgICB9O1xuXG4gICAgcHJpdmF0ZSBvbkNvbnRleHRNZW51ID0gKGUpID0+IHtcbiAgICAgICAgaWYgKHRoaXMucHJvcHMub25GaW5pc2hlZCkge1xuICAgICAgICAgICAgdGhpcy5wcm9wcy5vbkZpbmlzaGVkKCk7XG5cbiAgICAgICAgICAgIGUucHJldmVudERlZmF1bHQoKTtcbiAgICAgICAgICAgIGUuc3RvcFByb3BhZ2F0aW9uKCk7XG4gICAgICAgICAgICBjb25zdCB4ID0gZS5jbGllbnRYO1xuICAgICAgICAgICAgY29uc3QgeSA9IGUuY2xpZW50WTtcblxuICAgICAgICAgICAgLy8gWFhYOiBUaGlzIGlzbid0IHByZXR0eSBidXQgdGhlIG9ubHkgd2F5IHRvIGFsbG93IG9wZW5pbmcgYSBkaWZmZXJlbnQgY29udGV4dCBtZW51IG9uIHJpZ2h0IGNsaWNrIHdoaWxzdFxuICAgICAgICAgICAgLy8gYSBjb250ZXh0IG1lbnUgYW5kIGl0cyBjbGljay1ndWFyZCBhcmUgdXAgd2l0aG91dCBjb21wbGV0ZWx5IHJld3JpdGluZyBob3cgdGhlIGNvbnRleHQgbWVudXMgd29yay5cbiAgICAgICAgICAgIHNldEltbWVkaWF0ZSgoKSA9PiB7XG4gICAgICAgICAgICAgICAgY29uc3QgY2xpY2tFdmVudCA9IGRvY3VtZW50LmNyZWF0ZUV2ZW50KCdNb3VzZUV2ZW50cycpO1xuICAgICAgICAgICAgICAgIGNsaWNrRXZlbnQuaW5pdE1vdXNlRXZlbnQoXG4gICAgICAgICAgICAgICAgICAgICdjb250ZXh0bWVudScsIHRydWUsIHRydWUsIHdpbmRvdywgMCxcbiAgICAgICAgICAgICAgICAgICAgMCwgMCwgeCwgeSwgZmFsc2UsIGZhbHNlLFxuICAgICAgICAgICAgICAgICAgICBmYWxzZSwgZmFsc2UsIDAsIG51bGwsXG4gICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICBkb2N1bWVudC5lbGVtZW50RnJvbVBvaW50KHgsIHkpLmRpc3BhdGNoRXZlbnQoY2xpY2tFdmVudCk7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICBwcml2YXRlIG9uQ29udGV4dE1lbnVQcmV2ZW50QnViYmxpbmcgPSAoZSkgPT4ge1xuICAgICAgICAvLyBzdG9wIHByb3BhZ2F0aW9uIHNvIHRoYXQgYW55IGNvbnRleHQgbWVudSBoYW5kbGVycyBkb24ndCBsZWFrIG91dCBvZiB0aGlzIGNvbnRleHQgbWVudVxuICAgICAgICAvLyBidXQgZG8gbm90IGluaGliaXQgdGhlIGRlZmF1bHQgYnJvd3NlciBtZW51XG4gICAgICAgIGUuc3RvcFByb3BhZ2F0aW9uKCk7XG4gICAgfTtcblxuICAgIC8vIFByZXZlbnQgY2xpY2tzIG9uIHRoZSBiYWNrZ3JvdW5kIGZyb20gZ29pbmcgdGhyb3VnaCB0byB0aGUgY29tcG9uZW50IHdoaWNoIG9wZW5lZCB0aGUgbWVudS5cbiAgICBwcml2YXRlIG9uRmluaXNoZWQgPSAoZXY6IFJlYWN0Lk1vdXNlRXZlbnQpID0+IHtcbiAgICAgICAgZXYuc3RvcFByb3BhZ2F0aW9uKCk7XG4gICAgICAgIGV2LnByZXZlbnREZWZhdWx0KCk7XG4gICAgICAgIGlmICh0aGlzLnByb3BzLm9uRmluaXNoZWQpIHRoaXMucHJvcHMub25GaW5pc2hlZCgpO1xuICAgIH07XG5cbiAgICBwcml2YXRlIG9uTW92ZUZvY3VzID0gKGVsZW1lbnQ6IEVsZW1lbnQsIHVwOiBib29sZWFuKSA9PiB7XG4gICAgICAgIGxldCBkZXNjZW5kaW5nID0gZmFsc2U7IC8vIGFyZSB3ZSBjdXJyZW50bHkgZGVzY2VuZGluZyBvciBhc2NlbmRpbmcgdGhyb3VnaCB0aGUgRE9NIHRyZWU/XG5cbiAgICAgICAgZG8ge1xuICAgICAgICAgICAgY29uc3QgY2hpbGQgPSB1cCA/IGVsZW1lbnQubGFzdEVsZW1lbnRDaGlsZCA6IGVsZW1lbnQuZmlyc3RFbGVtZW50Q2hpbGQ7XG4gICAgICAgICAgICBjb25zdCBzaWJsaW5nID0gdXAgPyBlbGVtZW50LnByZXZpb3VzRWxlbWVudFNpYmxpbmcgOiBlbGVtZW50Lm5leHRFbGVtZW50U2libGluZztcblxuICAgICAgICAgICAgaWYgKGRlc2NlbmRpbmcpIHtcbiAgICAgICAgICAgICAgICBpZiAoY2hpbGQpIHtcbiAgICAgICAgICAgICAgICAgICAgZWxlbWVudCA9IGNoaWxkO1xuICAgICAgICAgICAgICAgIH0gZWxzZSBpZiAoc2libGluZykge1xuICAgICAgICAgICAgICAgICAgICBlbGVtZW50ID0gc2libGluZztcbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICBkZXNjZW5kaW5nID0gZmFsc2U7XG4gICAgICAgICAgICAgICAgICAgIGVsZW1lbnQgPSBlbGVtZW50LnBhcmVudEVsZW1lbnQ7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBpZiAoc2libGluZykge1xuICAgICAgICAgICAgICAgICAgICBlbGVtZW50ID0gc2libGluZztcbiAgICAgICAgICAgICAgICAgICAgZGVzY2VuZGluZyA9IHRydWU7XG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgZWxlbWVudCA9IGVsZW1lbnQucGFyZW50RWxlbWVudDtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGlmIChlbGVtZW50KSB7XG4gICAgICAgICAgICAgICAgaWYgKGVsZW1lbnQuY2xhc3NMaXN0LmNvbnRhaW5zKFwibXhfQ29udGV4dHVhbE1lbnVcIikpIHsgLy8gd2UgaGl0IHRoZSB0b3BcbiAgICAgICAgICAgICAgICAgICAgZWxlbWVudCA9IHVwID8gZWxlbWVudC5sYXN0RWxlbWVudENoaWxkIDogZWxlbWVudC5maXJzdEVsZW1lbnRDaGlsZDtcbiAgICAgICAgICAgICAgICAgICAgZGVzY2VuZGluZyA9IHRydWU7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICB9IHdoaWxlIChlbGVtZW50ICYmICFBUklBX01FTlVfSVRFTV9ST0xFUy5oYXMoZWxlbWVudC5nZXRBdHRyaWJ1dGUoXCJyb2xlXCIpKSk7XG5cbiAgICAgICAgaWYgKGVsZW1lbnQpIHtcbiAgICAgICAgICAgIChlbGVtZW50IGFzIEhUTUxFbGVtZW50KS5mb2N1cygpO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgIHByaXZhdGUgb25Nb3ZlRm9jdXNIb21lRW5kID0gKGVsZW1lbnQ6IEVsZW1lbnQsIHVwOiBib29sZWFuKSA9PiB7XG4gICAgICAgIGxldCByZXN1bHRzID0gZWxlbWVudC5xdWVyeVNlbGVjdG9yQWxsKCdbcm9sZV49XCJtZW51aXRlbVwiXScpO1xuICAgICAgICBpZiAoIXJlc3VsdHMpIHtcbiAgICAgICAgICAgIHJlc3VsdHMgPSBlbGVtZW50LnF1ZXJ5U2VsZWN0b3JBbGwoJ1t0YWItaW5kZXhdJyk7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKHJlc3VsdHMgJiYgcmVzdWx0cy5sZW5ndGgpIHtcbiAgICAgICAgICAgIGlmICh1cCkge1xuICAgICAgICAgICAgICAgIChyZXN1bHRzWzBdIGFzIEhUTUxFbGVtZW50KS5mb2N1cygpO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAocmVzdWx0c1tyZXN1bHRzLmxlbmd0aCAtIDFdIGFzIEhUTUxFbGVtZW50KS5mb2N1cygpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfTtcblxuICAgIHByaXZhdGUgb25LZXlEb3duID0gKGV2OiBSZWFjdC5LZXlib2FyZEV2ZW50KSA9PiB7XG4gICAgICAgIC8vIGRvbid0IGxldCBrZXlib2FyZCBoYW5kbGluZyBlc2NhcGUgdGhlIGNvbnRleHQgbWVudVxuICAgICAgICBldi5zdG9wUHJvcGFnYXRpb24oKTtcblxuICAgICAgICBpZiAoIXRoaXMucHJvcHMubWFuYWdlZCkge1xuICAgICAgICAgICAgaWYgKGV2LmtleSA9PT0gS2V5LkVTQ0FQRSkge1xuICAgICAgICAgICAgICAgIHRoaXMucHJvcHMub25GaW5pc2hlZCgpO1xuICAgICAgICAgICAgICAgIGV2LnByZXZlbnREZWZhdWx0KCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICBsZXQgaGFuZGxlZCA9IHRydWU7XG5cbiAgICAgICAgc3dpdGNoIChldi5rZXkpIHtcbiAgICAgICAgICAgIGNhc2UgS2V5LlRBQjpcbiAgICAgICAgICAgIGNhc2UgS2V5LkVTQ0FQRTpcbiAgICAgICAgICAgIGNhc2UgS2V5LkFSUk9XX0xFRlQ6IC8vIGNsb3NlIG9uIGxlZnQgYW5kIHJpZ2h0IGFycm93cyB0b28gZm9yIHdoZW4gaXQgaXMgYSBjb250ZXh0IG1lbnUgb24gYSA8VG9vbGJhciAvPlxuICAgICAgICAgICAgY2FzZSBLZXkuQVJST1dfUklHSFQ6XG4gICAgICAgICAgICAgICAgdGhpcy5wcm9wcy5vbkZpbmlzaGVkKCk7XG4gICAgICAgICAgICAgICAgYnJlYWs7