matrix-react-sdk
Version:
SDK for matrix.org using React
618 lines (501 loc) • 64.6 kB
JavaScript
"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