matrix-react-sdk
Version:
SDK for matrix.org using React
438 lines (431 loc) • 59.6 kB
JavaScript
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = exports.Direction = void 0;
exports.mouseWithinRegion = mouseWithinRegion;
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
var _react = _interopRequireDefault(require("react"));
var _reactDom = _interopRequireDefault(require("react-dom"));
var _classnames = _interopRequireDefault(require("classnames"));
var _UIStore = _interopRequireDefault(require("../../../stores/UIStore"));
var _ContextMenu = require("../../structures/ContextMenu");
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { (0, _defineProperty2.default)(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } /*
Copyright 2024 New Vector Ltd.
Copyright 2019-2021 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 InteractiveTooltipContainerId = "mx_InteractiveTooltip_Container";
// If the distance from tooltip to window edge is below this value, the tooltip
// will flip around to the other side of the target.
const MIN_SAFE_DISTANCE_TO_WINDOW_EDGE = 20;
function getOrCreateContainer() {
let container = document.getElementById(InteractiveTooltipContainerId);
if (!container) {
container = document.createElement("div");
container.id = InteractiveTooltipContainerId;
document.body.appendChild(container);
}
return container;
}
function isInRect(x, y, rect) {
const {
top,
right,
bottom,
left
} = rect;
return x >= left && x <= right && y >= top && y <= bottom;
}
/**
* Returns the positive slope of the diagonal of the rect.
*
* @param {DOMRect} rect
* @return {number}
*/
function getDiagonalSlope(rect) {
const {
top,
right,
bottom,
left
} = rect;
return (bottom - top) / (right - left);
}
function isInUpperLeftHalf(x, y, rect) {
const {
bottom,
left
} = rect;
// Negative slope because Y values grow downwards and for this case, the
// diagonal goes from larger to smaller Y values.
const diagonalSlope = getDiagonalSlope(rect) * -1;
return isInRect(x, y, rect) && y <= bottom + diagonalSlope * (x - left);
}
function isInLowerRightHalf(x, y, rect) {
const {
bottom,
left
} = rect;
// Negative slope because Y values grow downwards and for this case, the
// diagonal goes from larger to smaller Y values.
const diagonalSlope = getDiagonalSlope(rect) * -1;
return isInRect(x, y, rect) && y >= bottom + diagonalSlope * (x - left);
}
function isInUpperRightHalf(x, y, rect) {
const {
top,
left
} = rect;
// Positive slope because Y values grow downwards and for this case, the
// diagonal goes from smaller to larger Y values.
const diagonalSlope = getDiagonalSlope(rect) * 1;
return isInRect(x, y, rect) && y <= top + diagonalSlope * (x - left);
}
function isInLowerLeftHalf(x, y, rect) {
const {
top,
left
} = rect;
// Positive slope because Y values grow downwards and for this case, the
// diagonal goes from smaller to larger Y values.
const diagonalSlope = getDiagonalSlope(rect) * 1;
return isInRect(x, y, rect) && y >= top + diagonalSlope * (x - left);
}
let Direction = exports.Direction = /*#__PURE__*/function (Direction) {
Direction[Direction["Top"] = 0] = "Top";
Direction[Direction["Left"] = 1] = "Left";
Direction[Direction["Bottom"] = 2] = "Bottom";
Direction[Direction["Right"] = 3] = "Right";
return Direction;
}({}); // exported for tests
function mouseWithinRegion(x, y, direction, targetRect, contentRect) {
// When moving the mouse from the target to the tooltip, we create a safe area
// that includes the tooltip, the target, and the trapezoid ABCD between them:
// ┌───────────┐
// │ │
// │ │
// A └───E───F───┘ B
// V
// ┌─┐
// │ │
// C└─┘D
//
// As long as the mouse remains inside the safe area, the tooltip will stay open.
const buffer = 50;
if (isInRect(x, y, targetRect)) {
return true;
}
switch (direction) {
case Direction.Left:
{
const contentRectWithBuffer = {
top: contentRect.top - buffer,
right: contentRect.right,
bottom: contentRect.bottom + buffer,
left: contentRect.left - buffer
};
const trapezoidTop = {
top: contentRect.top - buffer,
right: targetRect.right,
bottom: targetRect.top,
left: contentRect.right
};
const trapezoidCenter = {
top: targetRect.top,
right: targetRect.left,
bottom: targetRect.bottom,
left: contentRect.right
};
const trapezoidBottom = {
top: targetRect.bottom,
right: targetRect.right,
bottom: contentRect.bottom + buffer,
left: contentRect.right
};
if (isInRect(x, y, contentRectWithBuffer) || isInLowerLeftHalf(x, y, trapezoidTop) || isInRect(x, y, trapezoidCenter) || isInUpperLeftHalf(x, y, trapezoidBottom)) {
return true;
}
break;
}
case Direction.Right:
{
const contentRectWithBuffer = {
top: contentRect.top - buffer,
right: contentRect.right + buffer,
bottom: contentRect.bottom + buffer,
left: contentRect.left
};
const trapezoidTop = {
top: contentRect.top - buffer,
right: contentRect.left,
bottom: targetRect.top,
left: targetRect.left
};
const trapezoidCenter = {
top: targetRect.top,
right: contentRect.left,
bottom: targetRect.bottom,
left: targetRect.right
};
const trapezoidBottom = {
top: targetRect.bottom,
right: contentRect.left,
bottom: contentRect.bottom + buffer,
left: targetRect.left
};
if (isInRect(x, y, contentRectWithBuffer) || isInLowerRightHalf(x, y, trapezoidTop) || isInRect(x, y, trapezoidCenter) || isInUpperRightHalf(x, y, trapezoidBottom)) {
return true;
}
break;
}
case Direction.Top:
{
const contentRectWithBuffer = {
top: contentRect.top - buffer,
right: contentRect.right + buffer,
bottom: contentRect.bottom,
left: contentRect.left - buffer
};
const trapezoidLeft = {
top: contentRect.bottom,
right: targetRect.left,
bottom: targetRect.bottom,
left: contentRect.left - buffer
};
const trapezoidCenter = {
top: contentRect.bottom,
right: targetRect.right,
bottom: targetRect.top,
left: targetRect.left
};
const trapezoidRight = {
top: contentRect.bottom,
right: contentRect.right + buffer,
bottom: targetRect.bottom,
left: targetRect.right
};
if (isInRect(x, y, contentRectWithBuffer) || isInUpperRightHalf(x, y, trapezoidLeft) || isInRect(x, y, trapezoidCenter) || isInUpperLeftHalf(x, y, trapezoidRight)) {
return true;
}
break;
}
case Direction.Bottom:
{
const contentRectWithBuffer = {
top: contentRect.top,
right: contentRect.right + buffer,
bottom: contentRect.bottom + buffer,
left: contentRect.left - buffer
};
const trapezoidLeft = {
top: targetRect.top,
right: targetRect.left,
bottom: contentRect.top,
left: contentRect.left - buffer
};
const trapezoidCenter = {
top: targetRect.bottom,
right: targetRect.right,
bottom: contentRect.top,
left: targetRect.left
};
const trapezoidRight = {
top: targetRect.top,
right: contentRect.right + buffer,
bottom: contentRect.top,
left: targetRect.right
};
if (isInRect(x, y, contentRectWithBuffer) || isInLowerRightHalf(x, y, trapezoidLeft) || isInRect(x, y, trapezoidCenter) || isInLowerLeftHalf(x, y, trapezoidRight)) {
return true;
}
break;
}
}
return false;
}
/*
* This style of tooltip takes a "target" element as its child and centers the
* tooltip along one edge of the target.
*/
class InteractiveTooltip extends _react.default.Component {
constructor(props) {
super(props);
(0, _defineProperty2.default)(this, "target", void 0);
(0, _defineProperty2.default)(this, "collectContentRect", element => {
// We don't need to clean up when unmounting, so ignore
if (!element) return;
this.setState({
contentRect: element.getBoundingClientRect()
});
});
(0, _defineProperty2.default)(this, "collectTarget", element => {
this.target = element;
});
(0, _defineProperty2.default)(this, "onMouseMove", ev => {
const {
clientX: x,
clientY: y
} = ev;
const {
contentRect
} = this.state;
if (!contentRect || !this.target) return;
const targetRect = this.target.getBoundingClientRect();
let direction;
if (this.isOnTheSide) {
direction = this.onLeftOfTarget() ? Direction.Left : Direction.Right;
} else {
direction = this.aboveTarget() ? Direction.Top : Direction.Bottom;
}
if (!mouseWithinRegion(x, y, direction, targetRect, contentRect)) {
this.hideTooltip();
}
});
(0, _defineProperty2.default)(this, "onTargetMouseOver", () => {
this.showTooltip();
});
this.state = {
visible: false
};
}
componentDidUpdate() {
// Whenever this passthrough component updates, also render the tooltip
// in a separate DOM tree. This allows the tooltip content to participate
// the normal React rendering cycle: when this component re-renders, the
// tooltip content re-renders.
// Once we upgrade to React 16, this could be done a bit more naturally
// using the portals feature instead.
this.renderTooltip();
}
componentWillUnmount() {
document.removeEventListener("mousemove", this.onMouseMove);
}
onLeftOfTarget() {
const {
contentRect
} = this.state;
if (!this.target) return false;
const targetRect = this.target.getBoundingClientRect();
if (this.props.direction === Direction.Left) {
const targetLeft = targetRect.left + window.scrollX;
return !contentRect || targetLeft - contentRect.width > MIN_SAFE_DISTANCE_TO_WINDOW_EDGE;
} else {
const targetRight = targetRect.right + window.scrollX;
const spaceOnRight = _UIStore.default.instance.windowWidth - targetRight;
return !!contentRect && spaceOnRight - contentRect.width < MIN_SAFE_DISTANCE_TO_WINDOW_EDGE;
}
}
aboveTarget() {
const {
contentRect
} = this.state;
if (!this.target) return false;
const targetRect = this.target.getBoundingClientRect();
if (this.props.direction === Direction.Top) {
const targetTop = targetRect.top + window.scrollY;
return !contentRect || targetTop - contentRect.height > MIN_SAFE_DISTANCE_TO_WINDOW_EDGE;
} else {
const targetBottom = targetRect.bottom + window.scrollY;
const spaceBelow = _UIStore.default.instance.windowHeight - targetBottom;
return !!contentRect && spaceBelow - contentRect.height < MIN_SAFE_DISTANCE_TO_WINDOW_EDGE;
}
}
get isOnTheSide() {
return this.props.direction === Direction.Left || this.props.direction === Direction.Right;
}
showTooltip() {
// Don't enter visible state if we haven't collected the target yet
if (!this.target) return;
this.setState({
visible: true
});
this.props.onVisibilityChange?.(true);
document.addEventListener("mousemove", this.onMouseMove);
}
hideTooltip() {
this.setState({
visible: false
});
this.props.onVisibilityChange?.(false);
document.removeEventListener("mousemove", this.onMouseMove);
}
renderTooltip() {
const {
contentRect,
visible
} = this.state;
if (!visible) {
_reactDom.default.unmountComponentAtNode(getOrCreateContainer());
return null;
}
if (!this.target) return null;
const targetRect = this.target.getBoundingClientRect();
// The window X and Y offsets are to adjust position when zoomed in to page
const targetLeft = targetRect.left + window.scrollX;
const targetRight = targetRect.right + window.scrollX;
const targetBottom = targetRect.bottom + window.scrollY;
const targetTop = targetRect.top + window.scrollY;
// Place the tooltip above the target by default. If we find that the
// tooltip content would extend past the safe area towards the window
// edge, flip around to below the target.
const position = {};
let chevronFace = null;
if (this.isOnTheSide) {
if (this.onLeftOfTarget()) {
position.left = targetLeft;
chevronFace = _ContextMenu.ChevronFace.Right;
} else {
position.left = targetRight;
chevronFace = _ContextMenu.ChevronFace.Left;
}
position.top = targetTop;
} else {
if (this.aboveTarget()) {
position.bottom = _UIStore.default.instance.windowHeight - targetTop;
chevronFace = _ContextMenu.ChevronFace.Bottom;
} else {
position.top = targetBottom;
chevronFace = _ContextMenu.ChevronFace.Top;
}
// Center the tooltip horizontally with the target's center.
position.left = targetLeft + targetRect.width / 2;
}
const chevron = /*#__PURE__*/_react.default.createElement("div", {
className: "mx_InteractiveTooltip_chevron_" + chevronFace
});
const menuClasses = (0, _classnames.default)("mx_InteractiveTooltip", {
mx_InteractiveTooltip_withChevron_top: chevronFace === _ContextMenu.ChevronFace.Top,
mx_InteractiveTooltip_withChevron_left: chevronFace === _ContextMenu.ChevronFace.Left,
mx_InteractiveTooltip_withChevron_right: chevronFace === _ContextMenu.ChevronFace.Right,
mx_InteractiveTooltip_withChevron_bottom: chevronFace === _ContextMenu.ChevronFace.Bottom
});
const menuStyle = {};
if (contentRect && !this.isOnTheSide) {
menuStyle.left = `-${contentRect.width / 2}px`;
}
const tooltip = /*#__PURE__*/_react.default.createElement("div", {
className: "mx_InteractiveTooltip_wrapper",
style: _objectSpread({}, position)
}, /*#__PURE__*/_react.default.createElement("div", {
className: menuClasses,
style: menuStyle,
ref: this.collectContentRect
}, chevron, this.props.content));
_reactDom.default.render(tooltip, getOrCreateContainer());
}
render() {
return this.props.children({
ref: this.collectTarget,
onMouseOver: this.onTargetMouseOver
});
}
}
exports.default = InteractiveTooltip;
(0, _defineProperty2.default)(InteractiveTooltip, "defaultProps", {
side: Direction.Top
});
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfcmVhY3QiLCJfaW50ZXJvcFJlcXVpcmVEZWZhdWx0IiwicmVxdWlyZSIsIl9yZWFjdERvbSIsIl9jbGFzc25hbWVzIiwiX1VJU3RvcmUiLCJfQ29udGV4dE1lbnUiLCJvd25LZXlzIiwiZSIsInIiLCJ0IiwiT2JqZWN0Iiwia2V5cyIsImdldE93blByb3BlcnR5U3ltYm9scyIsIm8iLCJmaWx0ZXIiLCJnZXRPd25Qcm9wZXJ0eURlc2NyaXB0b3IiLCJlbnVtZXJhYmxlIiwicHVzaCIsImFwcGx5IiwiX29iamVjdFNwcmVhZCIsImFyZ3VtZW50cyIsImxlbmd0aCIsImZvckVhY2giLCJfZGVmaW5lUHJvcGVydHkyIiwiZGVmYXVsdCIsImdldE93blByb3BlcnR5RGVzY3JpcHRvcnMiLCJkZWZpbmVQcm9wZXJ0aWVzIiwiZGVmaW5lUHJvcGVydHkiLCJJbnRlcmFjdGl2ZVRvb2x0aXBDb250YWluZXJJZCIsIk1JTl9TQUZFX0RJU1RBTkNFX1RPX1dJTkRPV19FREdFIiwiZ2V0T3JDcmVhdGVDb250YWluZXIiLCJjb250YWluZXIiLCJkb2N1bWVudCIsImdldEVsZW1lbnRCeUlkIiwiY3JlYXRlRWxlbWVudCIsImlkIiwiYm9keSIsImFwcGVuZENoaWxkIiwiaXNJblJlY3QiLCJ4IiwieSIsInJlY3QiLCJ0b3AiLCJyaWdodCIsImJvdHRvbSIsImxlZnQiLCJnZXREaWFnb25hbFNsb3BlIiwiaXNJblVwcGVyTGVmdEhhbGYiLCJkaWFnb25hbFNsb3BlIiwiaXNJbkxvd2VyUmlnaHRIYWxmIiwiaXNJblVwcGVyUmlnaHRIYWxmIiwiaXNJbkxvd2VyTGVmdEhhbGYiLCJEaXJlY3Rpb24iLCJleHBvcnRzIiwibW91c2VXaXRoaW5SZWdpb24iLCJkaXJlY3Rpb24iLCJ0YXJnZXRSZWN0IiwiY29udGVudFJlY3QiLCJidWZmZXIiLCJMZWZ0IiwiY29udGVudFJlY3RXaXRoQnVmZmVyIiwidHJhcGV6b2lkVG9wIiwidHJhcGV6b2lkQ2VudGVyIiwidHJhcGV6b2lkQm90dG9tIiwiUmlnaHQiLCJUb3AiLCJ0cmFwZXpvaWRMZWZ0IiwidHJhcGV6b2lkUmlnaHQiLCJCb3R0b20iLCJJbnRlcmFjdGl2ZVRvb2x0aXAiLCJSZWFjdCIsIkNvbXBvbmVudCIsImNvbnN0cnVjdG9yIiwicHJvcHMiLCJlbGVtZW50Iiwic2V0U3RhdGUiLCJnZXRCb3VuZGluZ0NsaWVudFJlY3QiLCJ0YXJnZXQiLCJldiIsImNsaWVudFgiLCJjbGllbnRZIiwic3RhdGUiLCJpc09uVGhlU2lkZSIsIm9uTGVmdE9mVGFyZ2V0IiwiYWJvdmVUYXJnZXQiLCJoaWRlVG9vbHRpcCIsInNob3dUb29sdGlwIiwidmlzaWJsZSIsImNvbXBvbmVudERpZFVwZGF0ZSIsInJlbmRlclRvb2x0aXAiLCJjb21wb25lbnRXaWxsVW5tb3VudCIsInJlbW92ZUV2ZW50TGlzdGVuZXIiLCJvbk1vdXNlTW92ZSIsInRhcmdldExlZnQiLCJ3aW5kb3ciLCJzY3JvbGxYIiwid2lkdGgiLCJ0YXJnZXRSaWdodCIsInNwYWNlT25SaWdodCIsIlVJU3RvcmUiLCJpbnN0YW5jZSIsIndpbmRvd1dpZHRoIiwidGFyZ2V0VG9wIiwic2Nyb2xsWSIsImhlaWdodCIsInRhcmdldEJvdHRvbSIsInNwYWNlQmVsb3ciLCJ3aW5kb3dIZWlnaHQiLCJvblZpc2liaWxpdHlDaGFuZ2UiLCJhZGRFdmVudExpc3RlbmVyIiwiUmVhY3RET00iLCJ1bm1vdW50Q29tcG9uZW50QXROb2RlIiwicG9zaXRpb24iLCJjaGV2cm9uRmFjZSIsIkNoZXZyb25GYWNlIiwiY2hldnJvbiIsImNsYXNzTmFtZSIsIm1lbnVDbGFzc2VzIiwiY2xhc3NOYW1lcyIsIm14X0ludGVyYWN0aXZlVG9vbHRpcF93aXRoQ2hldnJvbl90b3AiLCJteF9JbnRlcmFjdGl2ZVRvb2x0aXBfd2l0aENoZXZyb25fbGVmdCIsIm14X0ludGVyYWN0aXZlVG9vbHRpcF93aXRoQ2hldnJvbl9yaWdodCIsIm14X0ludGVyYWN0aXZlVG9vbHRpcF93aXRoQ2hldnJvbl9ib3R0b20iLCJtZW51U3R5bGUiLCJ0b29sdGlwIiwic3R5bGUiLCJyZWYiLCJjb2xsZWN0Q29udGVudFJlY3QiLCJjb250ZW50IiwicmVuZGVyIiwiY2hpbGRyZW4iLCJjb2xsZWN0VGFyZ2V0Iiwib25Nb3VzZU92ZXIiLCJvblRhcmdldE1vdXNlT3ZlciIsInNpZGUiXSwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvY29tcG9uZW50cy92aWV3cy9lbGVtZW50cy9JbnRlcmFjdGl2ZVRvb2x0aXAudHN4Il0sInNvdXJjZXNDb250ZW50IjpbIi8qXG5Db3B5cmlnaHQgMjAyNCBOZXcgVmVjdG9yIEx0ZC5cbkNvcHlyaWdodCAyMDE5LTIwMjEgVGhlIE1hdHJpeC5vcmcgRm91bmRhdGlvbiBDLkkuQy5cblxuU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IEFHUEwtMy4wLW9ubHkgT1IgR1BMLTMuMC1vbmx5XG5QbGVhc2Ugc2VlIExJQ0VOU0UgZmlsZXMgaW4gdGhlIHJlcG9zaXRvcnkgcm9vdCBmb3IgZnVsbCBkZXRhaWxzLlxuKi9cblxuaW1wb3J0IFJlYWN0LCB7IENTU1Byb3BlcnRpZXMsIE1vdXNlRXZlbnRIYW5kbGVyLCBSZWFjdE5vZGUsIFJlZkNhbGxiYWNrIH0gZnJvbSBcInJlYWN0XCI7XG5pbXBvcnQgUmVhY3RET00gZnJvbSBcInJlYWN0LWRvbVwiO1xuaW1wb3J0IGNsYXNzTmFtZXMgZnJvbSBcImNsYXNzbmFtZXNcIjtcblxuaW1wb3J0IFVJU3RvcmUgZnJvbSBcIi4uLy4uLy4uL3N0b3Jlcy9VSVN0b3JlXCI7XG5pbXBvcnQgeyBDaGV2cm9uRmFjZSB9IGZyb20gXCIuLi8uLi9zdHJ1Y3R1cmVzL0NvbnRleHRNZW51XCI7XG5cbmNvbnN0IEludGVyYWN0aXZlVG9vbHRpcENvbnRhaW5lcklkID0gXCJteF9JbnRlcmFjdGl2ZVRvb2x0aXBfQ29udGFpbmVyXCI7XG5cbi8vIElmIHRoZSBkaXN0YW5jZSBmcm9tIHRvb2x0aXAgdG8gd2luZG93IGVkZ2UgaXMgYmVsb3cgdGhpcyB2YWx1ZSwgdGhlIHRvb2x0aXBcbi8vIHdpbGwgZmxpcCBhcm91bmQgdG8gdGhlIG90aGVyIHNpZGUgb2YgdGhlIHRhcmdldC5cbmNvbnN0IE1JTl9TQUZFX0RJU1RBTkNFX1RPX1dJTkRPV19FREdFID0gMjA7XG5cbmZ1bmN0aW9uIGdldE9yQ3JlYXRlQ29udGFpbmVyKCk6IEhUTUxFbGVtZW50IHtcbiAgICBsZXQgY29udGFpbmVyID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoSW50ZXJhY3RpdmVUb29sdGlwQ29udGFpbmVySWQpO1xuXG4gICAgaWYgKCFjb250YWluZXIpIHtcbiAgICAgICAgY29udGFpbmVyID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudChcImRpdlwiKTtcbiAgICAgICAgY29udGFpbmVyLmlkID0gSW50ZXJhY3RpdmVUb29sdGlwQ29udGFpbmVySWQ7XG4gICAgICAgIGRvY3VtZW50LmJvZHkuYXBwZW5kQ2hpbGQoY29udGFpbmVyKTtcbiAgICB9XG5cbiAgICByZXR1cm4gY29udGFpbmVyO1xufVxuXG5pbnRlcmZhY2UgSVJlY3Qge1xuICAgIHRvcDogbnVtYmVyO1xuICAgIHJpZ2h0OiBudW1iZXI7XG4gICAgYm90dG9tOiBudW1iZXI7XG4gICAgbGVmdDogbnVtYmVyO1xufVxuXG5mdW5jdGlvbiBpc0luUmVjdCh4OiBudW1iZXIsIHk6IG51bWJlciwgcmVjdDogSVJlY3QpOiBib29sZWFuIHtcbiAgICBjb25zdCB7IHRvcCwgcmlnaHQsIGJvdHRvbSwgbGVmdCB9ID0gcmVjdDtcbiAgICByZXR1cm4geCA+PSBsZWZ0ICYmIHggPD0gcmlnaHQgJiYgeSA+PSB0b3AgJiYgeSA8PSBib3R0b207XG59XG5cbi8qKlxuICogUmV0dXJucyB0aGUgcG9zaXRpdmUgc2xvcGUgb2YgdGhlIGRpYWdvbmFsIG9mIHRoZSByZWN0LlxuICpcbiAqIEBwYXJhbSB7RE9NUmVjdH0gcmVjdFxuICogQHJldHVybiB7bnVtYmVyfVxuICovXG5mdW5jdGlvbiBnZXREaWFnb25hbFNsb3BlKHJlY3Q6IElSZWN0KTogbnVtYmVyIHtcbiAgICBjb25zdCB7IHRvcCwgcmlnaHQsIGJvdHRvbSwgbGVmdCB9ID0gcmVjdDtcbiAgICByZXR1cm4gKGJvdHRvbSAtIHRvcCkgLyAocmlnaHQgLSBsZWZ0KTtcbn1cblxuZnVuY3Rpb24gaXNJblVwcGVyTGVmdEhhbGYoeDogbnVtYmVyLCB5OiBudW1iZXIsIHJlY3Q6IElSZWN0KTogYm9vbGVhbiB7XG4gICAgY29uc3QgeyBib3R0b20sIGxlZnQgfSA9IHJlY3Q7XG4gICAgLy8gTmVnYXRpdmUgc2xvcGUgYmVjYXVzZSBZIHZhbHVlcyBncm93IGRvd253YXJkcyBhbmQgZm9yIHRoaXMgY2FzZSwgdGhlXG4gICAgLy8gZGlhZ29uYWwgZ29lcyBmcm9tIGxhcmdlciB0byBzbWFsbGVyIFkgdmFsdWVzLlxuICAgIGNvbnN0IGRpYWdvbmFsU2xvcGUgPSBnZXREaWFnb25hbFNsb3BlKHJlY3QpICogLTE7XG4gICAgcmV0dXJuIGlzSW5SZWN0KHgsIHksIHJlY3QpICYmIHkgPD0gYm90dG9tICsgZGlhZ29uYWxTbG9wZSAqICh4IC0gbGVmdCk7XG59XG5cbmZ1bmN0aW9uIGlzSW5Mb3dlclJpZ2h0SGFsZih4OiBudW1iZXIsIHk6IG51bWJlciwgcmVjdDogSVJlY3QpOiBib29sZWFuIHtcbiAgICBjb25zdCB7IGJvdHRvbSwgbGVmdCB9ID0gcmVjdDtcbiAgICAvLyBOZWdhdGl2ZSBzbG9wZSBiZWNhdXNlIFkgdmFsdWVzIGdyb3cgZG93bndhcmRzIGFuZCBmb3IgdGhpcyBjYXNlLCB0aGVcbiAgICAvLyBkaWFnb25hbCBnb2VzIGZyb20gbGFyZ2VyIHRvIHNtYWxsZXIgWSB2YWx1ZXMuXG4gICAgY29uc3QgZGlhZ29uYWxTbG9wZSA9IGdldERpYWdvbmFsU2xvcGUocmVjdCkgKiAtMTtcbiAgICByZXR1cm4gaXNJblJlY3QoeCwgeSwgcmVjdCkgJiYgeSA+PSBib3R0b20gKyBkaWFnb25hbFNsb3BlICogKHggLSBsZWZ0KTtcbn1cblxuZnVuY3Rpb24gaXNJblVwcGVyUmlnaHRIYWxmKHg6IG51bWJlciwgeTogbnVtYmVyLCByZWN0OiBJUmVjdCk6IGJvb2xlYW4ge1xuICAgIGNvbnN0IHsgdG9wLCBsZWZ0IH0gPSByZWN0O1xuICAgIC8vIFBvc2l0aXZlIHNsb3BlIGJlY2F1c2UgWSB2YWx1ZXMgZ3JvdyBkb3dud2FyZHMgYW5kIGZvciB0aGlzIGNhc2UsIHRoZVxuICAgIC8vIGRpYWdvbmFsIGdvZXMgZnJvbSBzbWFsbGVyIHRvIGxhcmdlciBZIHZhbHVlcy5cbiAgICBjb25zdCBkaWFnb25hbFNsb3BlID0gZ2V0RGlhZ29uYWxTbG9wZShyZWN0KSAqIDE7XG4gICAgcmV0dXJuIGlzSW5SZWN0KHgsIHksIHJlY3QpICYmIHkgPD0gdG9wICsgZGlhZ29uYWxTbG9wZSAqICh4IC0gbGVmdCk7XG59XG5cbmZ1bmN0aW9uIGlzSW5Mb3dlckxlZnRIYWxmKHg6IG51bWJlciwgeTogbnVtYmVyLCByZWN0OiBJUmVjdCk6IGJvb2xlYW4ge1xuICAgIGNvbnN0IHsgdG9wLCBsZWZ0IH0gPSByZWN0O1xuICAgIC8vIFBvc2l0aXZlIHNsb3BlIGJlY2F1c2UgWSB2YWx1ZXMgZ3JvdyBkb3dud2FyZHMgYW5kIGZvciB0aGlzIGNhc2UsIHRoZVxuICAgIC8vIGRpYWdvbmFsIGdvZXMgZnJvbSBzbWFsbGVyIHRvIGxhcmdlciBZIHZhbHVlcy5cbiAgICBjb25zdCBkaWFnb25hbFNsb3BlID0gZ2V0RGlhZ29uYWxTbG9wZShyZWN0KSAqIDE7XG4gICAgcmV0dXJuIGlzSW5SZWN0KHgsIHksIHJlY3QpICYmIHkgPj0gdG9wICsgZGlhZ29uYWxTbG9wZSAqICh4IC0gbGVmdCk7XG59XG5cbmV4cG9ydCBlbnVtIERpcmVjdGlvbiB7XG4gICAgVG9wLFxuICAgIExlZnQsXG4gICAgQm90dG9tLFxuICAgIFJpZ2h0LFxufVxuXG4vLyBleHBvcnRlZCBmb3IgdGVzdHNcbmV4cG9ydCBmdW5jdGlvbiBtb3VzZVdpdGhpblJlZ2lvbihcbiAgICB4OiBudW1iZXIsXG4gICAgeTogbnVtYmVyLFxuICAgIGRpcmVjdGlvbjogRGlyZWN0aW9uLFxuICAgIHRhcmdldFJlY3Q6IERPTVJlY3QsXG4gICAgY29udGVudFJlY3Q6IERPTVJlY3QsXG4pOiBib29sZWFuIHtcbiAgICAvLyBXaGVuIG1vdmluZyB0aGUgbW91c2UgZnJvbSB0aGUgdGFyZ2V0IHRvIHRoZSB0b29sdGlwLCB3ZSBjcmVhdGUgYSBzYWZlIGFyZWFcbiAgICAvLyB0aGF0IGluY2x1ZGVzIHRoZSB0b29sdGlwLCB0aGUgdGFyZ2V0LCBhbmQgdGhlIHRyYXBlem9pZCBBQkNEIGJldHdlZW4gdGhlbTpcbiAgICAvLyAgICAgICAgICAgICAgICAgICAgICAgICAgICDilIzilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilJBcbiAgICAvLyAgICAgICAgICAgICAgICAgICAgICAgICAgICDilIIgICAgICAgICAgIOKUglxuICAgIC8vICAgICAgICAgICAgICAgICAgICAgICAgICAgIOKUgiAgICAgICAgICAg4pSCXG4gICAgLy8gICAgICAgICAgICAgICAgICAgICAgICAgIEEg4pSU4pSA4pSA4pSAReKUgOKUgOKUgEbilIDilIDilIDilJggQlxuICAgIC8vICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFZcbiAgICAvLyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIOKUjOKUgOKUkFxuICAgIC8vICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg4pSCIOKUglxuICAgIC8vICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBD4pSU4pSA4pSYRFxuICAgIC8vXG4gICAgLy8gQXMgbG9uZyBhcyB0aGUgbW91c2UgcmVtYWlucyBpbnNpZGUgdGhlIHNhZmUgYXJlYSwgdGhlIHRvb2x0aXAgd2lsbCBzdGF5IG9wZW4uXG4gICAgY29uc3QgYnVmZmVyID0gNTA7XG4gICAgaWYgKGlzSW5SZWN0KHgsIHksIHRhcmdldFJlY3QpKSB7XG4gICAgICAgIHJldHVybiB0cnVlO1xuICAgIH1cblxuICAgIHN3aXRjaCAoZGlyZWN0aW9uKSB7XG4gICAgICAgIGNhc2UgRGlyZWN0aW9uLkxlZnQ6IHtcbiAgICAgICAgICAgIGNvbnN0IGNvbnRlbnRSZWN0V2l0aEJ1ZmZlciA9IHtcbiAgICAgICAgICAgICAgICB0b3A6IGNvbnRlbnRSZWN0LnRvcCAtIGJ1ZmZlcixcbiAgICAgICAgICAgICAgICByaWdodDogY29udGVudFJlY3QucmlnaHQsXG4gICAgICAgICAgICAgICAgYm90dG9tOiBjb250ZW50UmVjdC5ib3R0b20gKyBidWZmZXIsXG4gICAgICAgICAgICAgICAgbGVmdDogY29udGVudFJlY3QubGVmdCAtIGJ1ZmZlcixcbiAgICAgICAgICAgIH07XG4gICAgICAgICAgICBjb25zdCB0cmFwZXpvaWRUb3AgPSB7XG4gICAgICAgICAgICAgICAgdG9wOiBjb250ZW50UmVjdC50b3AgLSBidWZmZXIsXG4gICAgICAgICAgICAgICAgcmlnaHQ6IHRhcmdldFJlY3QucmlnaHQsXG4gICAgICAgICAgICAgICAgYm90dG9tOiB0YXJnZXRSZWN0LnRvcCxcbiAgICAgICAgICAgICAgICBsZWZ0OiBjb250ZW50UmVjdC5yaWdodCxcbiAgICAgICAgICAgIH07XG4gICAgICAgICAgICBjb25zdCB0cmFwZXpvaWRDZW50ZXIgPSB7XG4gICAgICAgICAgICAgICAgdG9wOiB0YXJnZXRSZWN0LnRvcCxcbiAgICAgICAgICAgICAgICByaWdodDogdGFyZ2V0UmVjdC5sZWZ0LFxuICAgICAgICAgICAgICAgIGJvdHRvbTogdGFyZ2V0UmVjdC5ib3R0b20sXG4gICAgICAgICAgICAgICAgbGVmdDogY29udGVudFJlY3QucmlnaHQsXG4gICAgICAgICAgICB9O1xuICAgICAgICAgICAgY29uc3QgdHJhcGV6b2lkQm90dG9tID0ge1xuICAgICAgICAgICAgICAgIHRvcDogdGFyZ2V0UmVjdC5ib3R0b20sXG4gICAgICAgICAgICAgICAgcmlnaHQ6IHRhcmdldFJlY3QucmlnaHQsXG4gICAgICAgICAgICAgICAgYm90dG9tOiBjb250ZW50UmVjdC5ib3R0b20gKyBidWZmZXIsXG4gICAgICAgICAgICAgICAgbGVmdDogY29udGVudFJlY3QucmlnaHQsXG4gICAgICAgICAgICB9O1xuXG4gICAgICAgICAgICBpZiAoXG4gICAgICAgICAgICAgICAgaXNJblJlY3QoeCwgeSwgY29udGVudFJlY3RXaXRoQnVmZmVyKSB8fFxuICAgICAgICAgICAgICAgIGlzSW5Mb3dlckxlZnRIYWxmKHgsIHksIHRyYXBlem9pZFRvcCkgfHxcbiAgICAgICAgICAgICAgICBpc0luUmVjdCh4LCB5LCB0cmFwZXpvaWRDZW50ZXIpIHx8XG4gICAgICAgICAgICAgICAgaXNJblVwcGVyTGVmdEhhbGYoeCwgeSwgdHJhcGV6b2lkQm90dG9tKVxuICAgICAgICAgICAgKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICB9XG5cbiAgICAgICAgY2FzZSBEaXJlY3Rpb24uUmlnaHQ6IHtcbiAgICAgICAgICAgIGNvbnN0IGNvbnRlbnRSZWN0V2l0aEJ1ZmZlciA9IHtcbiAgICAgICAgICAgICAgICB0b3A6IGNvbnRlbnRSZWN0LnRvcCAtIGJ1ZmZlcixcbiAgICAgICAgICAgICAgICByaWdodDogY29udGVudFJlY3QucmlnaHQgKyBidWZmZXIsXG4gICAgICAgICAgICAgICAgYm90dG9tOiBjb250ZW50UmVjdC5ib3R0b20gKyBidWZmZXIsXG4gICAgICAgICAgICAgICAgbGVmdDogY29udGVudFJlY3QubGVmdCxcbiAgICAgICAgICAgIH07XG4gICAgICAgICAgICBjb25zdCB0cmFwZXpvaWRUb3AgPSB7XG4gICAgICAgICAgICAgICAgdG9wOiBjb250ZW50UmVjdC50b3AgLSBidWZmZXIsXG4gICAgICAgICAgICAgICAgcmlnaHQ6IGNvbnRlbnRSZWN0LmxlZnQsXG4gICAgICAgICAgICAgICAgYm90dG9tOiB0YXJnZXRSZWN0LnRvcCxcbiAgICAgICAgICAgICAgICBsZWZ0OiB0YXJnZXRSZWN0LmxlZnQsXG4gICAgICAgICAgICB9O1xuICAgICAgICAgICAgY29uc3QgdHJhcGV6b2lkQ2VudGVyID0ge1xuICAgICAgICAgICAgICAgIHRvcDogdGFyZ2V0UmVjdC50b3AsXG4gICAgICAgICAgICAgICAgcmlnaHQ6IGNvbnRlbnRSZWN0LmxlZnQsXG4gICAgICAgICAgICAgICAgYm90dG9tOiB0YXJnZXRSZWN0LmJvdHRvbSxcbiAgICAgICAgICAgICAgICBsZWZ0OiB0YXJnZXRSZWN0LnJpZ2h0LFxuICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIGNvbnN0IHRyYXBlem9pZEJvdHRvbSA9IHtcbiAgICAgICAgICAgICAgICB0b3A6IHRhcmdldFJlY3QuYm90dG9tLFxuICAgICAgICAgICAgICAgIHJpZ2h0OiBjb250ZW50UmVjdC5sZWZ0LFxuICAgICAgICAgICAgICAgIGJvdHRvbTogY29udGVudFJlY3QuYm90dG9tICsgYnVmZmVyLFxuICAgICAgICAgICAgICAgIGxlZnQ6IHRhcmdldFJlY3QubGVmdCxcbiAgICAgICAgICAgIH07XG5cbiAgICAgICAgICAgIGlmIChcbiAgICAgICAgICAgICAgICBpc0luUmVjdCh4LCB5LCBjb250ZW50UmVjdFdpdGhCdWZmZXIpIHx8XG4gICAgICAgICAgICAgICAgaXNJbkxvd2VyUmlnaHRIYWxmKHgsIHksIHRyYXBlem9pZFRvcCkgfHxcbiAgICAgICAgICAgICAgICBpc0luUmVjdCh4LCB5LCB0cmFwZXpvaWRDZW50ZXIpIHx8XG4gICAgICAgICAgICAgICAgaXNJblVwcGVyUmlnaHRIYWxmKHgsIHksIHRyYXBlem9pZEJvdHRvbSlcbiAgICAgICAgICAgICkge1xuICAgICAgICAgICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBicmVhaztcbiAgICAgICAgfVxuXG4gICAgICAgIGNhc2UgRGlyZWN0aW9uLlRvcDoge1xuICAgICAgICAgICAgY29uc3QgY29udGVudFJlY3RXaXRoQnVmZmVyID0ge1xuICAgICAgICAgICAgICAgIHRvcDogY29udGVudFJlY3QudG9wIC0gYnVmZmVyLFxuICAgICAgICAgICAgICAgIHJpZ2h0OiBjb250ZW50UmVjdC5yaWdodCArIGJ1ZmZlcixcbiAgICAgICAgICAgICAgICBib3R0b206IGNvbnRlbnRSZWN0LmJvdHRvbSxcbiAgICAgICAgICAgICAgICBsZWZ0OiBjb250ZW50UmVjdC5sZWZ0IC0gYnVmZmVyLFxuICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIGNvbnN0IHRyYXBlem9pZExlZnQgPSB7XG4gICAgICAgICAgICAgICAgdG9wOiBjb250ZW50UmVjdC5ib3R0b20sXG4gICAgICAgICAgICAgICAgcmlnaHQ6IHRhcmdldFJlY3QubGVmdCxcbiAgICAgICAgICAgICAgICBib3R0b206IHRhcmdldFJlY3QuYm90dG9tLFxuICAgICAgICAgICAgICAgIGxlZnQ6IGNvbnRlbnRSZWN0LmxlZnQgLSBidWZmZXIsXG4gICAgICAgICAgICB9O1xuICAgICAgICAgICAgY29uc3QgdHJhcGV6b2lkQ2VudGVyID0ge1xuICAgICAgICAgICAgICAgIHRvcDogY29udGVudFJlY3QuYm90dG9tLFxuICAgICAgICAgICAgICAgIHJpZ2h0OiB0YXJnZXRSZWN0LnJpZ2h0LFxuICAgICAgICAgICAgICAgIGJvdHRvbTogdGFyZ2V0UmVjdC50b3AsXG4gICAgICAgICAgICAgICAgbGVmdDogdGFyZ2V0UmVjdC5sZWZ0LFxuICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIGNvbnN0IHRyYXBlem9pZFJpZ2h0ID0ge1xuICAgICAgICAgICAgICAgIHRvcDogY29udGVudFJlY3QuYm90dG9tLFxuICAgICAgICAgICAgICAgIHJpZ2h0OiBjb250ZW50UmVjdC5yaWdodCArIGJ1ZmZlcixcbiAgICAgICAgICAgICAgICBib3R0b206IHRhcmdldFJlY3QuYm90dG9tLFxuICAgICAgICAgICAgICAgIGxlZnQ6IHRhcmdldFJlY3QucmlnaHQsXG4gICAgICAgICAgICB9O1xuXG4gICAgICAgICAgICBpZiAoXG4gICAgICAgICAgICAgICAgaXNJblJlY3QoeCwgeSwgY29udGVudFJlY3RXaXRoQnVmZmVyKSB8fFxuICAgICAgICAgICAgICAgIGlzSW5VcHBlclJpZ2h0SGFsZih4LCB5LCB0cmFwZXpvaWRMZWZ0KSB8fFxuICAgICAgICAgICAgICAgIGlzSW5SZWN0KHgsIHksIHRyYXBlem9pZENlbnRlcikgfHxcbiAgICAgICAgICAgICAgICBpc0luVXBwZXJMZWZ0SGFsZih4LCB5LCB0cmFwZXpvaWRSaWdodClcbiAgICAgICAgICAgICkge1xuICAgICAgICAgICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBicmVhaztcbiAgICAgICAgfVxuXG4gICAgICAgIGNhc2UgRGlyZWN0aW9uLkJvdHRvbToge1xuICAgICAgICAgICAgY29uc3QgY29udGVudFJlY3RXaXRoQnVmZmVyID0ge1xuICAgICAgICAgICAgICAgIHRvcDogY29udGVudFJlY3QudG9wLFxuICAgICAgICAgICAgICAgIHJpZ2h0OiBjb250ZW50UmVjdC5yaWdodCArIGJ1ZmZlcixcbiAgICAgICAgICAgICAgICBib3R0b206IGNvbnRlbnRSZWN0LmJvdHRvbSArIGJ1ZmZlcixcbiAgICAgICAgICAgICAgICBsZWZ0OiBjb250ZW50UmVjdC5sZWZ0IC0gYnVmZmVyLFxuICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIGNvbnN0IHRyYXBlem9pZExlZnQgPSB7XG4gICAgICAgICAgICAgICAgdG9wOiB0YXJnZXRSZWN0LnRvcCxcbiAgICAgICAgICAgICAgICByaWdodDogdGFyZ2V0UmVjdC5sZWZ0LFxuICAgICAgICAgICAgICAgIGJvdHRvbTogY29udGVudFJlY3QudG9wLFxuICAgICAgICAgICAgICAgIGxlZnQ6IGNvbnRlbnRSZWN0LmxlZnQgLSBidWZmZXIsXG4gICAgICAgICAgICB9O1xuICAgICAgICAgICAgY29uc3QgdHJhcGV6b2lkQ2VudGVyID0ge1xuICAgICAgICAgICAgICAgIHRvcDogdGFyZ2V0UmVjdC5ib3R0b20sXG4gICAgICAgICAgICAgICAgcmlnaHQ6IHRhcmdldFJlY3QucmlnaHQsXG4gICAgICAgICAgICAgICAgYm90dG9tOiBjb250ZW50UmVjdC50b3AsXG4gICAgICAgICAgICAgICAgbGVmdDogdGFyZ2V0UmVjdC5sZWZ0LFxuICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIGNvbnN0IHRyYXBlem9pZFJpZ2h0ID0ge1xuICAgICAgICAgICAgICAgIHRvcDogdGFyZ2V0UmVjdC50b3AsXG4gICAgICAgICAgICAgICAgcmlnaHQ6IGNvbnRlbnRSZWN0LnJpZ2h0ICsgYnVmZmVyLFxuICAgICAgICAgICAgICAgIGJvdHRvbTogY29udGVudFJlY3QudG9wLFxuICAgICAgICAgICAgICAgIGxlZnQ6IHRhcmdldFJlY3QucmlnaHQsXG4gICAgICAgICAgICB9O1xuXG4gICAgICAgICAgICBpZiAoXG4gICAgICAgICAgICAgICAgaXNJblJlY3QoeCwgeSwgY29udGVudFJlY3RXaXRoQnVmZmVyKSB8fFxuICAgICAgICAgICAgICAgIGlzSW5Mb3dlclJpZ2h0SGFsZih4LCB5LCB0cmFwZXpvaWRMZWZ0KSB8fFxuICAgICAgICAgICAgICAgIGlzSW5SZWN0KHgsIHksIHRyYXBlem9pZENlbnRlcikgfHxcbiAgICAgICAgICAgICAgICBpc0luTG93ZXJMZWZ0SGFsZih4LCB5LCB0cmFwZXpvaWRSaWdodClcbiAgICAgICAgICAgICkge1xuICAgICAgICAgICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBicmVhaztcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiBmYWxzZTtcbn1cblxuaW50ZXJmYWNlIElQcm9wcyB7XG4gICAgY2hpbGRyZW4ocHJvcHM6IHsgcmVmOiBSZWZDYWxsYmFjazxIVE1MRWxlbWVudD47IG9uTW91c2VPdmVyOiBNb3VzZUV2ZW50SGFuZGxlciB9KTogUmVhY3ROb2RlO1xuICAgIC8vIENvbnRlbnQgdG8gc2hvdyBpbiB0aGUgdG9vbHRpcFxuICAgIGNvbnRlbnQ6IFJlYWN0Tm9kZTtcbiAgICBkaXJlY3Rpb24/OiBEaXJlY3Rpb247XG4gICAgLy8gRnVuY3Rpb24gdG8gY2FsbCB3aGVuIHZpc2liaWxpdHkgb2YgdGhlIHRvb2x0aXAgY2hhbmdlc1xuICAgIG9uVmlzaWJpbGl0eUNoYW5nZT8odmlzaWJsZTogYm9vbGVhbik6IHZvaWQ7XG59XG5cbmludGVyZmFjZSBJU3RhdGUge1xuICAgIGNvbnRlbnRSZWN0PzogRE9NUmVjdDtcbiAgICB2aXNpYmxlOiBib29sZWFuO1xufVxuXG4vKlxuICogVGhpcyBzdHlsZSBvZiB0b29sdGlwIHRha2VzIGEgXCJ0YXJnZXRcIiBlbGVtZW50IGFzIGl0cyBjaGlsZCBhbmQgY2VudGVycyB0aGVcbiAqIHRvb2x0aXAgYWxvbmcgb25lIGVkZ2Ugb2YgdGhlIHRhcmdldC5cbiAqL1xuZXhwb3J0IGRlZmF1bHQgY2xhc3MgSW50ZXJhY3RpdmVUb29sdGlwIGV4dGVuZHMgUmVhY3QuQ29tcG9uZW50PElQcm9wcywgSVN0YXRlPiB7XG4gICAgcHJpdmF0ZSB0YXJnZXQ/OiBIVE1MRWxlbWVudDtcblxuICAgIHB1YmxpYyBzdGF0aWMgZGVmYXVsdFByb3BzID0ge1xuICAgICAgICBzaWRlOiBEaXJlY3Rpb24uVG9wLFxuICAgIH07XG5cbiAgICBwdWJsaWMgY29uc3RydWN0b3IocHJvcHM6IElQcm9wcykge1xuICAgICAgICBzdXBlcihwcm9wcyk7XG5cbiAgICAgICAgdGhpcy5zdGF0ZSA9IHtcbiAgICAgICAgICAgIHZpc2libGU6IGZhbHNlLFxuICAgICAgICB9O1xuICAgIH1cblxuICAgIHB1YmxpYyBjb21wb25lbnREaWRVcGRhdGUoKTogdm9pZCB7XG4gICAgICAgIC8vIFdoZW5ldmVyIHRoaXMgcGFzc3Rocm91Z2ggY29tcG9uZW50IHVwZGF0ZXMsIGFsc28gcmVuZGVyIHRoZSB0b29sdGlwXG4gICAgICAgIC8vIGluIGEgc2VwYXJhdGUgRE9NIHRyZWUuIFRoaXMgYWxsb3dzIHRoZSB0b29sdGlwIGNvbnRlbnQgdG8gcGFydGljaXBhdGVcbiAgICAgICAgLy8gdGhlIG5vcm1hbCBSZWFjdCByZW5kZXJpbmcgY3ljbGU6IHdoZW4gdGhpcyBjb21wb25lbnQgcmUtcmVuZGVycywgdGhlXG4gICAgICAgIC8vIHRvb2x0aXAgY29udGVudCByZS1yZW5kZXJzLlxuICAgICAgICAvLyBPbmNlIHdlIHVwZ3JhZGUgdG8gUmVhY3QgMTYsIHRoaXMgY291bGQgYmUgZG9uZSBhIGJpdCBtb3JlIG5hdHVyYWxseVxuICAgICAgICAvLyB1c2luZyB0aGUgcG9ydGFscyBmZWF0dXJlIGluc3RlYWQuXG4gICAgICAgIHRoaXMucmVuZGVyVG9vbHRpcCgpO1xuICAgIH1cblxuICAgIHB1YmxpYyBjb21wb25lbnRXaWxsVW5tb3VudCgpOiB2b2lkIHtcbiAgICAgICAgZG9jdW1lbnQucmVtb3ZlRXZlbnRMaXN0ZW5lcihcIm1vdXNlbW92ZVwiLCB0aGlzLm9uTW91c2VNb3ZlKTtcbiAgICB9XG5cbiAgICBwcml2YXRlIGNvbGxlY3RDb250ZW50UmVjdCA9IChlbGVtZW50OiBIVE1MRWxlbWVudCB8IG51bGwpOiB2b2lkID0+IHtcbiAgICAgICAgLy8gV2UgZG9uJ3QgbmVlZCB0byBjbGVhbiB1cCB3aGVuIHVubW91bnRpbmcsIHNvIGlnbm9yZVxuICAgICAgICBpZiAoIWVsZW1lbnQpIHJldHVybjtcblxuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICAgIGNvbnRlbnRSZWN0OiBlbGVtZW50LmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpLFxuICAgICAgICB9KTtcbiAgICB9O1xuXG4gICAgcHJpdmF0ZSBjb2xsZWN0VGFyZ2V0ID0gKGVsZW1lbnQ6IEhUTUxFbGVtZW50KTogdm9pZCA9PiB7XG4gICAgICAgIHRoaXMudGFyZ2V0ID0gZWxlbWVudDtcbiAgICB9O1xuXG4gICAgcHJpdmF0ZSBvbkxlZnRPZlRhcmdldCgpOiBib29sZWFuIHtcbiAgICAgICAgY29uc3QgeyBjb250ZW50UmVjdCB9ID0gdGhpcy5zdGF0ZTtcbiAgICAgICAgaWYgKCF0aGlzLnRhcmdldCkgcmV0dXJuIGZhbHNlO1xuICAgICAgICBjb25zdCB0YXJnZXRSZWN0ID0gdGhpcy50YXJnZXQuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCk7XG5cbiAgICAgICAgaWYgKHRoaXMucHJvcHMuZGlyZWN0aW9uID09PSBEaXJlY3Rpb24uTGVmdCkge1xuICAgICAgICAgICAgY29uc3QgdGFyZ2V0TGVmdCA9IHRhcmdldFJlY3QubGVmdCArIHdpbmRvdy5zY3JvbGxYO1xuICAgICAgICAgICAgcmV0dXJuICFjb250ZW50UmVjdCB8fCB0YXJnZXRMZWZ0IC0gY29udGVudFJlY3Qud2lkdGggPiBNSU5fU0FGRV9ESVNUQU5DRV9UT19XSU5ET1dfRURHRTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGNvbnN0IHRhcmdldFJpZ2h0ID0gdGFyZ2V0UmVjdC5yaWdodCArIHdpbmRvdy5zY3JvbGxYO1xuICAgICAgICAgICAgY29uc3Qgc3BhY2VPblJpZ2h0ID0gVUlTdG9yZS5pbnN0YW5jZS53aW5kb3dXaWR0aCAtIHRhcmdldFJpZ2h0O1xuICAgICAgICAgICAgcmV0dXJuICEhY29udGVudFJlY3QgJiYgc3BhY2VPblJpZ2h0IC0gY29udGVudFJlY3Qud2lkdGggPCBNSU5fU0FGRV9ESVNUQU5DRV9UT19XSU5ET1dfRURHRTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHByaXZhdGUgYWJvdmVUYXJnZXQoKTogYm9vbGVhbiB7XG4gICAgICAgIGNvbnN0IHsgY29udGVudFJlY3QgfSA9IHRoaXMuc3RhdGU7XG4gICAgICAgIGlmICghdGhpcy50YXJnZXQpIHJldHVybiBmYWxzZTtcbiAgICAgICAgY29uc3QgdGFyZ2V0UmVjdCA9IHRoaXMudGFyZ2V0LmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpO1xuXG4gICAgICAgIGlmICh0aGlzLnByb3BzLmRpcmVjdGlvbiA9PT0gRGlyZWN0aW9uLlRvcCkge1xuICAgICAgICAgICAgY29uc3QgdGFyZ2V0VG9wID0gdGFyZ2V0UmVjdC50b3AgKyB3aW5kb3cuc2Nyb2xsWTtcbiAgICAgICAgICAgIHJldHVybiAhY29udGVudFJlY3QgfHwgdGFyZ2V0VG9wIC0gY29udGVudFJlY3QuaGVpZ2h0ID4gTUlOX1NBRkVfRElTVEFOQ0VfVE9fV0lORE9XX0VER0U7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBjb25zdCB0YXJnZXRCb3R0b20gPSB0YXJnZXRSZWN0LmJvdHRvbSArIHdpbmRvdy5zY3JvbGxZO1xuICAgICAgICAgICAgY29uc3Qgc3BhY2VCZWxvdyA9IFVJU3RvcmUuaW5zdGFuY2Uud2luZG93SGVpZ2h0IC0gdGFyZ2V0Qm90dG9tO1xuICAgICAgICAgICAgcmV0dXJuICEhY29udGVudFJlY3QgJiYgc3BhY2VCZWxvdyAtIGNvbnRlbnRSZWN0LmhlaWdodCA8IE1JTl9TQUZFX0RJU1RBTkNFX1RPX1dJTkRPV19FREdFO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBnZXQgaXNPblRoZVNpZGUoKTogYm9vbGVhbiB7XG4gICAgICAgIHJldHVybiB0aGlzLnByb3BzLmRpcmVjdGlvbiA9PT0gRGlyZWN0aW9uLkxlZnQgfHwgdGhpcy5wcm9wcy5kaXJlY3Rpb24gPT09IERpcmVjdGlvbi5SaWdodDtcbiAgICB9XG5cbiAgICBwcml2YXRlIG9uTW91c2VNb3ZlID0gKGV2OiBNb3VzZUV2ZW50KTogdm9pZCA9PiB7XG4gICAgICAgIGNvbnN0IHsgY2xpZW50WDogeCwgY2xpZW50WTogeSB9ID0gZXY7XG4gICAgICAgIGNvbnN0IHsgY29udGVudFJlY3QgfSA9IHRoaXMuc3RhdGU7XG4gICAgICAgIGlmICghY29udGVudFJlY3QgfHwgIXRoaXMudGFyZ2V0KSByZXR1cm47XG4gICAgICAgIGNvbnN0IHRhcmdldFJlY3QgPSB0aGlzLnRhcmdldC5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKTtcblxuICAgICAgICBsZXQgZGlyZWN0aW9uOiBEaXJlY3Rpb247XG4gICAgICAgIGlmICh0aGlzLmlzT25UaGVTaWRlKSB7XG4gICAgICAgICAgICBkaXJlY3Rpb24gPSB0aGlzLm9uTGVmdE9mVGFyZ2V0KCkgPyBEaXJlY3Rpb24uTGVmdCA6IERpcmVjdGlvbi5SaWdodDtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGRpcmVjdGlvbiA9IHRoaXMuYWJvdmVUYXJnZXQoKSA/IERpcmVjdGlvbi5Ub3AgOiBEaXJlY3Rpb24uQm90dG9tO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKCFtb3VzZVdpdGhpblJlZ2lvbih4LCB5LCBkaXJlY3Rpb24sIHRhcmdldFJlY3QsIGNvbnRlbnRSZWN0KSkge1xuICAgICAgICAgICAgdGhpcy5oaWRlVG9vbHRpcCgpO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgIHByaXZhdGUgb25UYXJnZXRNb3VzZU92ZXIgPSAoKTogdm9pZCA9PiB7XG4gICAgICAgIHRoaXMuc2hvd1Rvb2x0aXAoKTtcbiAgICB9O1xuXG4gICAgcHJpdmF0ZSBzaG93VG9vbHRpcCgpOiB2b2lkIHtcbiAgICAgICAgLy8gRG9uJ3QgZW50ZXIgdmlzaWJsZSBzdGF0ZSBpZiB3ZSBoYXZlbid0IGNvbGxlY3RlZCB0aGUgdGFyZ2V0IHlldFxuICAgICAgICBpZiAoIXRoaXMudGFyZ2V0KSByZXR1cm47XG5cbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICB2aXNpYmxlOiB0cnVlLFxuICAgICAgICB9KTtcbiAgICAgICAgdGhpcy5wcm9wcy5vblZpc2liaWxpdHlDaGFuZ2U/Lih0cnVlKTtcbiAgICAgICAgZG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lcihcIm1vdXNlbW92ZVwiLCB0aGlzLm9uTW91c2VNb3ZlKTtcbiAgICB9XG5cbiAgICBwdWJsaWMgaGlkZVRvb2x0aXAoKTogdm9pZCB7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgdmlzaWJsZTogZmFsc2UsXG4gICAgICAgIH0pO1xuICAgICAgICB0aGlzLnByb3BzLm9uVmlzaWJpbGl0eUNoYW5nZT8uKGZhbHNlKTtcbiAgICAgICAgZG9jdW1lbnQucmVtb3ZlRXZlbnRMaXN0ZW5lcihcIm1vdXNlbW92ZVwiLCB0aGlzLm9uTW91c2VNb3ZlKTtcbiAgICB9XG5cbiAgICBwcml2YXRlIHJlbmRlclRvb2x0aXAoKTogUmVhY3ROb2RlIHtcbiAgICAgICAgY29uc3QgeyBjb250ZW50UmVjdCwgdmlzaWJsZSB9ID0gdGhpcy5zdGF0ZTtcbiAgICAgICAgaWYgKCF2aXNpYmxlKSB7XG4gICAgICAgICAgICBSZWFjdERPTS51bm1vdW50Q29tcG9uZW50QXROb2RlKGdldE9yQ3JlYXRlQ29udGFpbmVyKCkpO1xuICAgICAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoIXRoaXMudGFyZ2V0KSByZXR1cm4gbnVsbDtcblxuICAgICAgICBjb25zdCB0YXJnZXRSZWN0ID0gdGhpcy50YXJnZXQuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCk7XG5cbiAgICAgICAgLy8gVGhlIHdpbmRvdyBYIGFuZCBZIG9mZnNldHMgYXJlIHRvIGFkanVzdCBwb3NpdGlvbiB3aGVuIHpvb21lZCBpbiB0byBwYWdlXG4gICAgICAgIGNvbnN0IHRhcmdldExlZnQgPSB0YXJnZXRSZWN0LmxlZnQgKyB3aW5kb3cuc2Nyb2xsWDtcbiAgICAgICAgY29uc3QgdGFyZ2V0UmlnaHQgPSB0YXJnZXRSZWN0LnJpZ2h0ICsgd2luZG93LnNjcm9sbFg7XG4gICAgICAgIGNvbnN0IHRhcmdldEJvdHRvbSA9IHRhcmdldFJlY3QuYm90dG9tICsgd2luZG93LnNjcm9sbFk7XG4gICAgICAgIGNvbnN0IHRhcmdldFRvcCA9IHRhcmdldFJlY3QudG9wICsgd2luZG93LnNjcm9sbFk7XG5cbiAgICAgICAgLy8gUGxhY2UgdGhlIHRvb2x0aXAgYWJvdmUgdGhlIHRhcmdldCBieSBkZWZhdWx0LiBJZiB3ZSBmaW5kIHRoYXQgdGhlXG4gICAgICAgIC8vIHRvb2x0aXAgY29udGVudCB3b3VsZCBleHRlbmQgcGFzdCB0aGUgc2FmZSBhcmVhIHRvd2FyZHMgdGhlIHdpbmRvd1xuICAgICAgICAvLyBlZGdlLCBmbGlwIGFyb3VuZCB0byBiZWxvdyB0aGUgdGFyZ2V0LlxuICAgICAgICBjb25zdCBwb3NpdGlvbjogUGFydGlhbDxJUmVjdD4gPSB7fTtcbiAgICAgICAgbGV0IGNoZXZyb25GYWNlOiBDaGV2cm9uRmFjZSB8IG51bGwgPSBudWxsO1xuICAgICAgICBpZiAodGhpcy5pc09uVGhlU2lkZSkge1xuICAgICAgICAgICAgaWYgKHRoaXMub25MZWZ0T2ZUYXJnZXQoKSkge1xuICAgICAgICAgICAgICAgIHBvc2l0aW9uLmxlZnQgPSB0YXJnZXRMZWZ0O1xuICAgICAgICAgICAgICAgIGNoZXZyb25GYWNlID0gQ2hldnJvbkZhY2UuUmlnaHQ7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHBvc2l0aW9uLmxlZnQgPSB0YXJnZXRSaWdodDtcbiAgICAgICAgICAgICAgICBjaGV2cm9uRmFjZSA9IENoZXZyb25GYWNlLkxlZnQ7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHBvc2l0aW9uLnRvcCA9IHRhcmdldFRvcDtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGlmICh0aGlzLmFib3ZlVGFyZ2V0KCkpIHtcbiAgICAgICAgICAgICAgICBwb3NpdGlvbi5ib3R0b20gPSBVSVN0b3JlLmluc3RhbmNlLndpbmRvd0hlaWdodCAtIHRhcmdldFRvcDtcbiAgICAgICAgICAgICAgICBjaGV2cm9uRmFjZSA9IENoZXZyb25GYWNlLkJvdHRvbTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgcG9zaXRpb24udG9wID0gdGFyZ2V0Qm90dG9tO1xuICAgICAgICAgICAgICAgIGNoZXZyb25GYWNlID0gQ2hldnJvbkZhY2UuVG9wO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAvLyBDZW50ZXIgdGhlIHRvb2x0aXAgaG9yaXpvbnRhbGx5IHdpdGggdGhlIHRhcmdldCdzIGNlbnRlci5cbiAgICAgICAgICAgIHBvc2l0aW9uLmxlZnQgPSB0YXJnZXRMZWZ0ICsgdGFyZ2V0UmVjdC53aWR0aCAvIDI7XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCBjaGV2cm9uID0gPGRpdiBjbGFzc05hbWU9e1wibXhfSW50ZXJhY3RpdmVUb29sdGlwX2NoZXZyb25fXCIgKyBjaGV2cm9uRmFjZX0gLz47XG5cbiAgICAgICAgY29uc3QgbWVudUNsYXNzZXMgPSBjbGFzc05hbWVzKFwibXhfSW50ZXJhY3RpdmVUb29sdGlwXCIsIHtcbiAgICAgICAgICAgIG14X0ludGVyYWN0aXZlVG9vbHRpcF93aXRoQ2hldnJvbl90b3A6IGNoZXZyb25GYWNlID09PSBDaGV2cm9uRmFjZS5Ub3AsXG4gICAgICAgICAgICBteF9JbnRlcmFjdGl2ZVRvb2x0aXBfd2l0aENoZXZyb25fbGVmdDogY2hldnJvbkZhY2UgPT09IENoZXZyb25GYWNlLkxlZnQsXG4gICAgICAgICAgICBteF9JbnRlcmFjdGl2ZVRvb2x0aXBfd2l0aENoZXZyb25fcmlnaHQ6IGNoZXZyb25GYWNlID09PSBDaGV2cm9uRmFjZS5SaWdodCxcbiAgICAgICAgICAgIG14X0ludGVyYWN0aXZlVG9vbHRpcF93aXRoQ2hldnJvbl9ib3R0b206IGNoZXZyb25GYWNlID09PSBDaGV2cm9uRmFjZS5Cb3R0b20sXG4gICAgICAgIH0pO1xuXG4gICAgICAgIGNvbnN0IG1lbnVTdHlsZTogQ1NTUHJvcGVydGllcyA9IHt9O1xuICAgICAgICBpZiAoY29udGVudFJlY3QgJiYgIXRoaXMuaXNPblRoZVNpZGUpIHtcbiAgICAgICAgICAgIG1lbnVTdHlsZS5sZWZ0ID0gYC0ke2NvbnRlbnRSZWN0LndpZHRoIC8gMn1weGA7XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCB0b29sdGlwID0gKFxuICAgICAgICAgICAgPGRpdiBjbGFzc05hbWU9XCJteF9JbnRlcmFjdGl2ZVRvb2x0aXBfd3JhcHBlclwiIHN0eWxlPXt7IC4uLnBvc2l0aW9uIH19PlxuICAgICAgICAgICAgICAgIDxkaXYgY2xhc3NOYW1lPXttZW51Q2xhc3Nlc30gc3R5bGU9e21lbnVTdHlsZX0gcmVmPXt0aGlzLmNvbGxlY3RDb250ZW50UmVjdH0+XG4gICAgICAgICAgICAgICAgICAgIHtjaGV2cm9ufVxuICAgICAgICAgICAgICAgICAgICB7dGhpcy5wcm9wcy5jb250ZW50fVxuICAgICAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICk7XG5cbiAgICAgICAgUmVhY3RET00ucmVuZGVyKHRvb2x0aXAsIGdldE9yQ3JlYXRlQ29udGFpbmVyKCkpO1xuICAgIH1cblxuICAgIHB1YmxpYyByZW5kZXIoKTogUmVhY3ROb2RlIHtcbiAgICAgICAgcmV0dXJuIHRoaXMucHJvcHMuY2hpbGRyZW4oe1xuICAgICAgICAgICAgcmVmOiB0aGlzLmNvbGxlY3RUYXJnZXQsXG4gICAgICAgICAgICBvbk1vdXNlT3ZlcjogdGhpcy5vblRhcmdldE1vdXNlT3ZlcixcbiAgICAgICAgfSk7XG4gICAgfVxufVxuIl0sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7QUFRQSxJQUFBQSxNQUFBLEdBQUFDLHNCQUFBLENBQUFDLE9BQUE7QUFDQSxJQUFBQyxTQUFBLEdBQUFGLHNCQUFBLENBQUFDLE9BQUE7QUFDQSxJQUFBRSxXQUFBLEdBQUFILHNCQUFBLENBQUFDLE9BQUE7QUFFQSxJQUFBRyxRQUFBLEdBQUFKLHNCQUFBLENBQUFDLE9BQUE7QUFDQSxJQUFBSSxZQUFBLEdBQUFKLE9BQUE7QUFBMkQsU0FBQUssUUFBQUMsQ0FBQSxFQUFBQyxDQUFBLFFBQUFDLENBQUEsR0FBQUMsTUFBQSxDQUFBQyxJQUFBLENBQUFKLENBQUEsT0FBQUcsTUFBQSxDQUFBRSxxQkFBQSxRQUFBQyxDQUFBLEdBQUFILE1BQUEsQ0FBQUUscUJBQUEsQ0FBQUwsQ0FBQSxHQUFBQyxDQUFBLEtB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