matrix-react-sdk
Version:
SDK for matrix.org using React
452 lines (387 loc) • 55.9 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.default = void 0;
var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
var _react = _interopRequireWildcard(require("react"));
var _languageHandler = require("../../../languageHandler");
var _AccessibleTooltipButton = _interopRequireDefault(require("./AccessibleTooltipButton"));
var _Keyboard = require("../../../Keyboard");
var _reactFocusLock = _interopRequireDefault(require("react-focus-lock"));
var _MemberAvatar = _interopRequireDefault(require("../avatars/MemberAvatar"));
var _ContextMenuTooltipButton = require("../../../accessibility/context_menu/ContextMenuTooltipButton");
var _MessageContextMenu = _interopRequireDefault(require("../context_menus/MessageContextMenu"));
var _ContextMenu = require("../../structures/ContextMenu");
var _MessageTimestamp = _interopRequireDefault(require("../messages/MessageTimestamp"));
var _SettingsStore = _interopRequireDefault(require("../../../settings/SettingsStore"));
var _DateUtils = require("../../../DateUtils");
var _dispatcher = _interopRequireDefault(require("../../../dispatcher/dispatcher"));
var _replaceableComponent = require("../../../utils/replaceableComponent");
var _Mouse = require("../../../utils/Mouse");
var _dec, _class, _temp;
// Max scale to keep gaps around the image
const MAX_SCALE = 0.95; // This is used for the buttons
const ZOOM_STEP = 0.10; // This is used for mouse wheel events
const ZOOM_COEFFICIENT = 0.0025; // If we have moved only this much we can zoom
const ZOOM_DISTANCE = 10;
let ImageView = (_dec = (0, _replaceableComponent.replaceableComponent)("views.elements.ImageView"), _dec(_class = (_temp = class ImageView extends _react.default.Component
/*:: <IProps, IState>*/
{
constructor(props) {
super(props);
(0, _defineProperty2.default)(this, "contextMenuButton", /*#__PURE__*/(0, _react.createRef)());
(0, _defineProperty2.default)(this, "focusLock", /*#__PURE__*/(0, _react.createRef)());
(0, _defineProperty2.default)(this, "imageWrapper", /*#__PURE__*/(0, _react.createRef)());
(0, _defineProperty2.default)(this, "image", /*#__PURE__*/(0, _react.createRef)());
(0, _defineProperty2.default)(this, "initX", 0);
(0, _defineProperty2.default)(this, "initY", 0);
(0, _defineProperty2.default)(this, "lastX", 0);
(0, _defineProperty2.default)(this, "lastY", 0);
(0, _defineProperty2.default)(this, "previousX", 0);
(0, _defineProperty2.default)(this, "previousY", 0);
(0, _defineProperty2.default)(this, "calculateZoom", () => {
const image = this.image.current;
const imageWrapper = this.imageWrapper.current;
const zoomX = imageWrapper.clientWidth / image.naturalWidth;
const zoomY = imageWrapper.clientHeight / image.naturalHeight; // If the image is smaller in both dimensions set its the zoom to 1 to
// display it in its original size
if (zoomX >= 1 && zoomY >= 1) {
this.setState({
zoom: 1,
minZoom: 1,
maxZoom: 1
});
return;
} // We set minZoom to the min of the zoomX and zoomY to avoid overflow in
// any direction. We also multiply by MAX_SCALE to get a gap around the
// image by default
const minZoom = Math.min(zoomX, zoomY) * MAX_SCALE;
if (this.state.zoom <= this.state.minZoom) this.setState({
zoom: minZoom
});
this.setState({
minZoom: minZoom,
maxZoom: 1
});
});
(0, _defineProperty2.default)(this, "onWheel", (ev
/*: WheelEvent*/
) => {
ev.stopPropagation();
ev.preventDefault();
const {
deltaY
} = (0, _Mouse.normalizeWheelEvent)(ev);
this.zoom(-(deltaY * ZOOM_COEFFICIENT));
});
(0, _defineProperty2.default)(this, "onZoomInClick", () => {
this.zoom(ZOOM_STEP);
});
(0, _defineProperty2.default)(this, "onZoomOutClick", () => {
this.zoom(-ZOOM_STEP);
});
(0, _defineProperty2.default)(this, "onKeyDown", (ev
/*: KeyboardEvent*/
) => {
if (ev.key === _Keyboard.Key.ESCAPE) {
ev.stopPropagation();
ev.preventDefault();
this.props.onFinished();
}
});
(0, _defineProperty2.default)(this, "onRotateCounterClockwiseClick", () => {
const cur = this.state.rotation;
const rotationDegrees = cur - 90;
this.setState({
rotation: rotationDegrees
});
});
(0, _defineProperty2.default)(this, "onRotateClockwiseClick", () => {
const cur = this.state.rotation;
const rotationDegrees = cur + 90;
this.setState({
rotation: rotationDegrees
});
});
(0, _defineProperty2.default)(this, "onDownloadClick", () => {
const a = document.createElement("a");
a.href = this.props.src;
a.download = this.props.name;
a.target = "_blank";
a.rel = "noreferrer noopener";
a.click();
});
(0, _defineProperty2.default)(this, "onOpenContextMenu", () => {
this.setState({
contextMenuDisplayed: true
});
});
(0, _defineProperty2.default)(this, "onCloseContextMenu", () => {
this.setState({
contextMenuDisplayed: false
});
});
(0, _defineProperty2.default)(this, "onPermalinkClicked", (ev
/*: React.MouseEvent*/
) => {
// This allows the permalink to be opened in a new tab/window or copied as
// matrix.to, but also for it to enable routing within Element when clicked.
ev.preventDefault();
_dispatcher.default.dispatch({
action: 'view_room',
event_id: this.props.mxEvent.getId(),
highlighted: true,
room_id: this.props.mxEvent.getRoomId()
});
this.props.onFinished();
});
(0, _defineProperty2.default)(this, "onStartMoving", (ev
/*: React.MouseEvent*/
) => {
ev.stopPropagation();
ev.preventDefault(); // Don't do anything if we pressed any
// other button than the left one
if (ev.button !== 0) return; // Zoom in if we are completely zoomed out
if (this.state.zoom === this.state.minZoom) {
this.setState({
zoom: this.state.maxZoom
});
return;
}
this.setState({
moving: true
});
this.previousX = this.state.translationX;
this.previousY = this.state.translationY;
this.initX = ev.pageX - this.lastX;
this.initY = ev.pageY - this.lastY;
});
(0, _defineProperty2.default)(this, "onMoving", (ev
/*: React.MouseEvent*/
) => {
ev.stopPropagation();
ev.preventDefault();
if (!this.state.moving) return;
this.lastX = ev.pageX - this.initX;
this.lastY = ev.pageY - this.initY;
this.setState({
translationX: this.lastX,
translationY: this.lastY
});
});
(0, _defineProperty2.default)(this, "onEndMoving", () => {
// Zoom out if we haven't moved much
if (this.state.moving === true && Math.abs(this.state.translationX - this.previousX) < ZOOM_DISTANCE && Math.abs(this.state.translationY - this.previousY) < ZOOM_DISTANCE) {
this.setState({
zoom: this.state.minZoom,
translationX: 0,
translationY: 0
});
}
this.setState({
moving: false
});
});
this.state = {
zoom: 0,
minZoom: MAX_SCALE,
maxZoom: MAX_SCALE,
rotation: 0,
translationX: 0,
translationY: 0,
moving: false,
contextMenuDisplayed: false
};
} // XXX: Refs to functional components
componentDidMount() {
// We have to use addEventListener() because the listener
// needs to be passive in order to work with Chromium
this.focusLock.current.addEventListener('wheel', this.onWheel, {
passive: false
}); // We want to recalculate zoom whenever the window's size changes
window.addEventListener("resize", this.calculateZoom); // After the image loads for the first time we want to calculate the zoom
this.image.current.addEventListener("load", this.calculateZoom);
}
componentWillUnmount() {
this.focusLock.current.removeEventListener('wheel', this.onWheel);
window.removeEventListener("resize", this.calculateZoom);
this.image.current.removeEventListener("load", this.calculateZoom);
}
zoom(delta
/*: number*/
) {
const newZoom = this.state.zoom + delta;
if (newZoom <= this.state.minZoom) {
this.setState({
zoom: this.state.minZoom,
translationX: 0,
translationY: 0
});
return;
}
if (newZoom >= this.state.maxZoom) {
this.setState({
zoom: this.state.maxZoom
});
return;
}
this.setState({
zoom: newZoom
});
}
renderContextMenu() {
let contextMenu = null;
if (this.state.contextMenuDisplayed) {
contextMenu = /*#__PURE__*/_react.default.createElement(_ContextMenu.ContextMenu, (0, _extends2.default)({}, (0, _ContextMenu.aboveLeftOf)(this.contextMenuButton.current.getBoundingClientRect()), {
onFinished: this.onCloseContextMenu
}), /*#__PURE__*/_react.default.createElement(_MessageContextMenu.default, {
mxEvent: this.props.mxEvent,
permalinkCreator: this.props.permalinkCreator,
onFinished: this.onCloseContextMenu,
onCloseDialog: this.props.onFinished
}));
}
return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, contextMenu);
}
render() {
const showEventMeta = !!this.props.mxEvent;
const zoomingDisabled = this.state.maxZoom === this.state.minZoom;
let cursor;
if (this.state.moving) {
cursor = "grabbing";
} else if (zoomingDisabled) {
cursor = "default";
} else if (this.state.zoom === this.state.minZoom) {
cursor = "zoom-in";
} else {
cursor = "zoom-out";
}
const rotationDegrees = this.state.rotation + "deg";
const zoom = this.state.zoom;
const translatePixelsX = this.state.translationX + "px";
const translatePixelsY = this.state.translationY + "px"; // The order of the values is important!
// First, we translate and only then we rotate, otherwise
// we would apply the translation to an already rotated
// image causing it translate in the wrong direction.
const style = {
cursor: cursor,
transition: this.state.moving ? null : "transform 200ms ease 0s",
transform: `translateX(${translatePixelsX})
translateY(${translatePixelsY})
scale(${zoom})
rotate(${rotationDegrees})`
};
let info;
if (showEventMeta) {
const mxEvent = this.props.mxEvent;
const showTwelveHour = _SettingsStore.default.getValue("showTwelveHourTimestamps");
let permalink = "#";
if (this.props.permalinkCreator) {
permalink = this.props.permalinkCreator.forEvent(this.props.mxEvent.getId());
}
const senderName = mxEvent.sender ? mxEvent.sender.name : mxEvent.getSender();
const sender = /*#__PURE__*/_react.default.createElement("div", {
className: "mx_ImageView_info_sender"
}, senderName);
const messageTimestamp = /*#__PURE__*/_react.default.createElement("a", {
href: permalink,
onClick: this.onPermalinkClicked,
"aria-label": (0, _DateUtils.formatFullDate)(new Date(this.props.mxEvent.getTs()), showTwelveHour, false)
}, /*#__PURE__*/_react.default.createElement(_MessageTimestamp.default, {
showFullDate: true,
showTwelveHour: showTwelveHour,
ts: mxEvent.getTs(),
showSeconds: false
}));
const avatar = /*#__PURE__*/_react.default.createElement(_MemberAvatar.default, {
member: mxEvent.sender,
width: 32,
height: 32,
viewUserOnClick: true
});
info = /*#__PURE__*/_react.default.createElement("div", {
className: "mx_ImageView_info_wrapper"
}, avatar, /*#__PURE__*/_react.default.createElement("div", {
className: "mx_ImageView_info"
}, sender, messageTimestamp));
} else {
// If there is no event - we're viewing an avatar, we set
// an empty div here, since the panel uses space-between
// and we want the same placement of elements
info = /*#__PURE__*/_react.default.createElement("div", null);
}
let contextMenuButton;
if (this.props.mxEvent) {
contextMenuButton = /*#__PURE__*/_react.default.createElement(_ContextMenuTooltipButton.ContextMenuTooltipButton, {
className: "mx_ImageView_button mx_ImageView_button_more",
title: (0, _languageHandler._t)("Options"),
onClick: this.onOpenContextMenu,
inputRef: this.contextMenuButton,
isExpanded: this.state.contextMenuDisplayed
});
}
let zoomOutButton;
let zoomInButton;
if (!zoomingDisabled) {
zoomOutButton = /*#__PURE__*/_react.default.createElement(_AccessibleTooltipButton.default, {
className: "mx_ImageView_button mx_ImageView_button_zoomOut",
title: (0, _languageHandler._t)("Zoom out"),
onClick: this.onZoomOutClick
});
zoomInButton = /*#__PURE__*/_react.default.createElement(_AccessibleTooltipButton.default, {
className: "mx_ImageView_button mx_ImageView_button_zoomIn",
title: (0, _languageHandler._t)("Zoom in"),
onClick: this.onZoomInClick
});
}
return /*#__PURE__*/_react.default.createElement(_reactFocusLock.default, {
returnFocus: true,
lockProps: {
onKeyDown: this.onKeyDown,
role: "dialog"
},
className: "mx_ImageView",
ref: this.focusLock
}, /*#__PURE__*/_react.default.createElement("div", {
className: "mx_ImageView_panel"
}, info, /*#__PURE__*/_react.default.createElement("div", {
className: "mx_ImageView_toolbar"
}, /*#__PURE__*/_react.default.createElement(_AccessibleTooltipButton.default, {
className: "mx_ImageView_button mx_ImageView_button_rotateCCW",
title: (0, _languageHandler._t)("Rotate Left"),
onClick: this.onRotateCounterClockwiseClick
}), /*#__PURE__*/_react.default.createElement(_AccessibleTooltipButton.default, {
className: "mx_ImageView_button mx_ImageView_button_rotateCW",
title: (0, _languageHandler._t)("Rotate Right"),
onClick: this.onRotateClockwiseClick
}), zoomOutButton, zoomInButton, /*#__PURE__*/_react.default.createElement(_AccessibleTooltipButton.default, {
className: "mx_ImageView_button mx_ImageView_button_download",
title: (0, _languageHandler._t)("Download"),
onClick: this.onDownloadClick
}), contextMenuButton, /*#__PURE__*/_react.default.createElement(_AccessibleTooltipButton.default, {
className: "mx_ImageView_button mx_ImageView_button_close",
title: (0, _languageHandler._t)("Close"),
onClick: this.props.onFinished
}), this.renderContextMenu())), /*#__PURE__*/_react.default.createElement("div", {
className: "mx_ImageView_image_wrapper",
ref: this.imageWrapper
}, /*#__PURE__*/_react.default.createElement("img", {
src: this.props.src,
title: this.props.name,
style: style,
ref: this.image,
className: "mx_ImageView_image",
draggable: true,
onMouseDown: this.onStartMoving,
onMouseMove: this.onMoving,
onMouseUp: this.onEndMoving,
onMouseLeave: this.onEndMoving
})));
}
}, _temp)) || _class);
exports.default = ImageView;
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy9jb21wb25lbnRzL3ZpZXdzL2VsZW1lbnRzL0ltYWdlVmlldy50c3giXSwibmFtZXMiOlsiTUFYX1NDQUxFIiwiWk9PTV9TVEVQIiwiWk9PTV9DT0VGRklDSUVOVCIsIlpPT01fRElTVEFOQ0UiLCJJbWFnZVZpZXciLCJSZWFjdCIsIkNvbXBvbmVudCIsImNvbnN0cnVjdG9yIiwicHJvcHMiLCJpbWFnZSIsImN1cnJlbnQiLCJpbWFnZVdyYXBwZXIiLCJ6b29tWCIsImNsaWVudFdpZHRoIiwibmF0dXJhbFdpZHRoIiwiem9vbVkiLCJjbGllbnRIZWlnaHQiLCJuYXR1cmFsSGVpZ2h0Iiwic2V0U3RhdGUiLCJ6b29tIiwibWluWm9vbSIsIm1heFpvb20iLCJNYXRoIiwibWluIiwic3RhdGUiLCJldiIsInN0b3BQcm9wYWdhdGlvbiIsInByZXZlbnREZWZhdWx0IiwiZGVsdGFZIiwia2V5IiwiS2V5IiwiRVNDQVBFIiwib25GaW5pc2hlZCIsImN1ciIsInJvdGF0aW9uIiwicm90YXRpb25EZWdyZWVzIiwiYSIsImRvY3VtZW50IiwiY3JlYXRlRWxlbWVudCIsImhyZWYiLCJzcmMiLCJkb3dubG9hZCIsIm5hbWUiLCJ0YXJnZXQiLCJyZWwiLCJjbGljayIsImNvbnRleHRNZW51RGlzcGxheWVkIiwiZGlzIiwiZGlzcGF0Y2giLCJhY3Rpb24iLCJldmVudF9pZCIsIm14RXZlbnQiLCJnZXRJZCIsImhpZ2hsaWdodGVkIiwicm9vbV9pZCIsImdldFJvb21JZCIsImJ1dHRvbiIsIm1vdmluZyIsInByZXZpb3VzWCIsInRyYW5zbGF0aW9uWCIsInByZXZpb3VzWSIsInRyYW5zbGF0aW9uWSIsImluaXRYIiwicGFnZVgiLCJsYXN0WCIsImluaXRZIiwicGFnZVkiLCJsYXN0WSIsImFicyIsImNvbXBvbmVudERpZE1vdW50IiwiZm9jdXNMb2NrIiwiYWRkRXZlbnRMaXN0ZW5lciIsIm9uV2hlZWwiLCJwYXNzaXZlIiwid2luZG93IiwiY2FsY3VsYXRlWm9vbSIsImNvbXBvbmVudFdpbGxVbm1vdW50IiwicmVtb3ZlRXZlbnRMaXN0ZW5lciIsImRlbHRhIiwibmV3Wm9vbSIsInJlbmRlckNvbnRleHRNZW51IiwiY29udGV4dE1lbnUiLCJjb250ZXh0TWVudUJ1dHRvbiIsImdldEJvdW5kaW5nQ2xpZW50UmVjdCIsIm9uQ2xvc2VDb250ZXh0TWVudSIsInBlcm1hbGlua0NyZWF0b3IiLCJyZW5kZXIiLCJzaG93RXZlbnRNZXRhIiwiem9vbWluZ0Rpc2FibGVkIiwiY3Vyc29yIiwidHJhbnNsYXRlUGl4ZWxzWCIsInRyYW5zbGF0ZVBpeGVsc1kiLCJzdHlsZSIsInRyYW5zaXRpb24iLCJ0cmFuc2Zvcm0iLCJpbmZvIiwic2hvd1R3ZWx2ZUhvdXIiLCJTZXR0aW5nc1N0b3JlIiwiZ2V0VmFsdWUiLCJwZXJtYWxpbmsiLCJmb3JFdmVudCIsInNlbmRlck5hbWUiLCJzZW5kZXIiLCJnZXRTZW5kZXIiLCJtZXNzYWdlVGltZXN0YW1wIiwib25QZXJtYWxpbmtDbGlja2VkIiwiRGF0ZSIsImdldFRzIiwiYXZhdGFyIiwib25PcGVuQ29udGV4dE1lbnUiLCJ6b29tT3V0QnV0dG9uIiwiem9vbUluQnV0dG9uIiwib25ab29tT3V0Q2xpY2siLCJvblpvb21JbkNsaWNrIiwib25LZXlEb3duIiwicm9sZSIsIm9uUm90YXRlQ291bnRlckNsb2Nrd2lzZUNsaWNrIiwib25Sb3RhdGVDbG9ja3dpc2VDbGljayIsIm9uRG93bmxvYWRDbGljayIsIm9uU3RhcnRNb3ZpbmciLCJvbk1vdmluZyIsIm9uRW5kTW92aW5nIl0sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7QUFrQkE7O0FBQ0E7O0FBQ0E7O0FBQ0E7O0FBQ0E7O0FBQ0E7O0FBQ0E7O0FBQ0E7O0FBQ0E7O0FBQ0E7O0FBQ0E7O0FBQ0E7O0FBQ0E7O0FBQ0E7O0FBR0E7Ozs7QUFFQTtBQUNBLE1BQU1BLFNBQVMsR0FBRyxJQUFsQixDLENBQ0E7O0FBQ0EsTUFBTUMsU0FBUyxHQUFHLElBQWxCLEMsQ0FD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WUFBWSxFQUFFLEtBQUtBO0FBVnZCLE1BSEosQ0F0Q0osQ0FESjtBQXlESDs7QUEvWmtFLEMiLCJzb3VyY2VzQ29udGVudCI6WyIvKlxuQ29weXJpZ2h0IDIwMTUsIDIwMTYgT3Blbk1hcmtldCBMdGRcbkNvcHlyaWdodCAyMDE5IE1pY2hhZWwgVGVsYXR5bnNraSA8N3QzY2hndXlAZ21haWwuY29tPlxuQ29weXJpZ2h0IDIwMjAsIDIwMjEgxaBpbW9uIEJyYW5kbmVyIDxzaW1vbi5icmEuYWdAZ21haWwuY29tPlxuXG5MaWNlbnNlZCB1bmRlciB0aGUgQXBhY2hlIExpY2Vuc2UsIFZlcnNpb24gMi4wICh0aGUgXCJMaWNlbnNlXCIpO1xueW91IG1heSBub3QgdXNlIHRoaXMgZmlsZSBleGNlcHQgaW4gY29tcGxpYW5jZSB3aXRoIHRoZSBMaWNlbnNlLlxuWW91IG1heSBvYnRhaW4gYSBjb3B5IG9mIHRoZSBMaWNlbnNlIGF0XG5cbiAgICBodHRwOi8vd3d3LmFwYWNoZS5vcmcvbGljZW5zZXMvTElDRU5TRS0yLjBcblxuVW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzb2Z0d2FyZVxuZGlzdHJpYnV0ZWQgdW5kZXIgdGhlIExpY2Vuc2UgaXMgZGlzdHJpYnV0ZWQgb24gYW4gXCJBUyBJU1wiIEJBU0lTLFxuV0lUSE9VVCBXQVJSQU5USUVTIE9SIENPTkRJVElPTlMgT0YgQU5ZIEtJTkQsIGVpdGhlciBleHByZXNzIG9yIGltcGxpZWQuXG5TZWUgdGhlIExpY2Vuc2UgZm9yIHRoZSBzcGVjaWZpYyBsYW5ndWFnZSBnb3Zlcm5pbmcgcGVybWlzc2lvbnMgYW5kXG5saW1pdGF0aW9ucyB1bmRlciB0aGUgTGljZW5zZS5cbiovXG5cbmltcG9ydCBSZWFjdCwgeyBjcmVhdGVSZWYgfSBmcm9tICdyZWFjdCc7XG5pbXBvcnQgeyBfdCB9IGZyb20gJy4uLy4uLy4uL2xhbmd1YWdlSGFuZGxlcic7XG5pbXBvcnQgQWNjZXNzaWJsZVRvb2x0aXBCdXR0b24gZnJvbSBcIi4vQWNjZXNzaWJsZVRvb2x0aXBCdXR0b25cIjtcbmltcG9ydCB7S2V5fSBmcm9tIFwiLi4vLi4vLi4vS2V5Ym9hcmRcIjtcbmltcG9ydCBGb2N1c0xvY2sgZnJvbSBcInJlYWN0LWZvY3VzLWxvY2tcIjtcbmltcG9ydCBNZW1iZXJBdmF0YXIgZnJvbSBcIi4uL2F2YXRhcnMvTWVtYmVyQXZhdGFyXCI7XG5pbXBvcnQge0NvbnRleHRNZW51VG9vbHRpcEJ1dHRvbn0gZnJvbSBcIi4uLy4uLy4uL2FjY2Vzc2liaWxpdHkvY29udGV4dF9tZW51L0NvbnRleHRNZW51VG9vbHRpcEJ1dHRvblwiO1xuaW1wb3J0IE1lc3NhZ2VDb250ZXh0TWVudSBmcm9tIFwiLi4vY29udGV4dF9tZW51cy9NZXNzYWdlQ29udGV4dE1lbnVcIjtcbmltcG9ydCB7YWJvdmVMZWZ0T2YsIENvbnRleHRNZW51fSBmcm9tICcuLi8uLi9zdHJ1Y3R1cmVzL0NvbnRleHRNZW51JztcbmltcG9ydCBNZXNzYWdlVGltZXN0YW1wIGZyb20gXCIuLi9tZXNzYWdlcy9NZXNzYWdlVGltZXN0YW1wXCI7XG5pbXBvcnQgU2V0dGluZ3NTdG9yZSBmcm9tIFwiLi4vLi4vLi4vc2V0dGluZ3MvU2V0dGluZ3NTdG9yZVwiO1xuaW1wb3J0IHtmb3JtYXRGdWxsRGF0ZX0gZnJvbSBcIi4uLy4uLy4uL0RhdGVVdGlsc1wiO1xuaW1wb3J0IGRpcyBmcm9tICcuLi8uLi8uLi9kaXNwYXRjaGVyL2Rpc3BhdGNoZXInO1xuaW1wb3J0IHtyZXBsYWNlYWJsZUNvbXBvbmVudH0gZnJvbSBcIi4uLy4uLy4uL3V0aWxzL3JlcGxhY2VhYmxlQ29tcG9uZW50XCI7XG5pbXBvcnQge1Jvb21QZXJtYWxpbmtDcmVhdG9yfSBmcm9tIFwiLi4vLi4vLi4vdXRpbHMvcGVybWFsaW5rcy9QZXJtYWxpbmtzXCJcbmltcG9ydCB7TWF0cml4RXZlbnR9IGZyb20gXCJtYXRyaXgtanMtc2RrL3NyYy9tb2RlbHMvZXZlbnRcIjtcbmltcG9ydCB7bm9ybWFsaXplV2hlZWxFdmVudH0gZnJvbSBcIi4uLy4uLy4uL3V0aWxzL01vdXNlXCI7XG5cbi8vIE1heCBzY2FsZSB0byBrZWVwIGdhcHMgYXJvdW5kIHRoZSBpbWFnZVxuY29uc3QgTUFYX1NDQUxFID0gMC45NTtcbi8vIFRoaXMgaXMgdXNlZCBmb3IgdGhlIGJ1dHRvbnNcbmNvbnN0IFpPT01fU1RFUCA9IDAuMTA7XG4vLyBUaGlzIGlzIHVzZWQgZm9yIG1vdXNlIHdoZWVsIGV2ZW50c1xuY29uc3QgWk9PTV9DT0VGRklDSUVOVCA9IDAuMDAyNTtcbi8vIElmIHdlIGhhdmUgbW92ZWQgb25seSB0aGlzIG11Y2ggd2UgY2FuIHpvb21cbmNvbnN0IFpPT01fRElTVEFOQ0UgPSAxMDtcblxuaW50ZXJmYWNlIElQcm9wcyB7XG4gICAgc3JjOiBzdHJpbmcsIC8vIHRoZSBzb3VyY2Ugb2YgdGhlIGltYWdlIGJlaW5nIGRpc3BsYXllZFxuICAgIG5hbWU/OiBzdHJpbmcsIC8vIHRoZSBtYWluIHRpdGxlICgnbmFtZScpIGZvciB0aGUgaW1hZ2VcbiAgICBsaW5rPzogc3RyaW5nLCAvLyB0aGUgbGluayAoaWYgYW55KSBhcHBsaWVkIHRvIHRoZSBuYW1lIG9mIHRoZSBpbWFnZVxuICAgIHdpZHRoPzogbnVtYmVyLCAvLyB3aWR0aCBvZiB0aGUgaW1hZ2Ugc3JjIGluIHBpeGVsc1xuICAgIGhlaWdodD86IG51bWJlciwgLy8gaGVpZ2h0IG9mIHRoZSBpbWFnZSBzcmMgaW4gcGl4ZWxzXG4gICAgZmlsZVNpemU/OiBudW1iZXIsIC8vIHNpemUgb2YgdGhlIGltYWdlIHNyYyBpbiBieXRlc1xuICAgIG9uRmluaXNoZWQoKTogdm9pZCwgLy8gY2FsbGJhY2sgd2hlbiB0aGUgbGlnaHRib3ggaXMgZGlzbWlzc2VkXG5cbiAgICAvLyB0aGUgZXZlbnQgKGlmIGFueSkgdGhhdCB0aGUgSW1hZ2UgaXMgZGlzcGxheWluZy4gVXNlZCBmb3IgZXZlbnQtc3BlY2lmaWMgc3R1ZmYgbGlrZVxuICAgIC8vIHJlZGFjdGlvbnMsIHNlbmRlcnMsIHRpbWVzdGFtcHMgZXRjLiAgT3RoZXIgZGVzY3JpcHRvcnMgYXJlIHRha2VuIGZyb20gdGhlIGV4cGxpY2l0XG4gICAgLy8gcHJvcGVydGllcyBhYm92ZSwgd2hpY2ggbGV0IHVzIHVzZSBsaWdodGJveGVzIHRvIGRpc3BsYXkgaW1hZ2VzIHdoaWNoIGFyZW4ndCBhc3NvY2lhdGVkXG4gICAgLy8gd2l0aCBldmVudHMuXG4gICAgbXhFdmVudDogTWF0cml4RXZlbnQsXG4gICAgcGVybWFsaW5rQ3JlYXRvcjogUm9vbVBlcm1hbGlua0NyZWF0b3IsXG59XG5cbmludGVyZmFjZSBJU3RhdGUge1xuICAgIHpvb206IG51bWJlcixcbiAgICBtaW5ab29tOiBudW1iZXIsXG4gICAgbWF4Wm9vbTogbnVtYmVyLFxuICAgIHJvdGF0aW9uOiBudW1iZXIsXG4gICAgdHJhbnNsYXRpb25YOiBudW1iZXIsXG4gICAgdHJhbnNsYXRpb25ZOiBudW1iZXIsXG4gICAgbW92aW5nOiBib29sZWFuLFxuICAgIGNvbnRleHRNZW51RGlzcGxheWVkOiBib29sZWFuLFxufVxuXG5AcmVwbGFjZWFibGVDb21wb25lbnQoXCJ2aWV3cy5lbGVtZW50cy5JbWFnZVZpZXdcIilcbmV4cG9ydCBkZWZhdWx0IGNsYXNzIEltYWdlVmlldyBleHRlbmRzIFJlYWN0LkNvbXBvbmVudDxJUHJvcHMsIElTdGF0ZT4ge1xuICAgIGNvbnN0cnVjdG9yKHByb3BzKSB7XG4gICAgICAgIHN1cGVyKHByb3BzKTtcbiAgICAgICAgdGhpcy5zdGF0ZSA9IHtcbiAgICAgICAgICAgIHpvb206IDAsXG4gICAgICAgICAgICBtaW5ab29tOiBNQVhfU0NBTEUsXG4gICAgICAgICAgICBtYXhab29tOiBNQVhfU0NBTEUsXG4gICAgICAgICAgICByb3RhdGlvbjogMCxcbiAgICAgICAgICAgIHRyYW5zbGF0aW9uWDogMCxcbiAgICAgICAgICAgIHRyYW5zbGF0aW9uWTogMCxcbiAgICAgICAgICAgIG1vdmluZzogZmFsc2UsXG4gICAgICAgICAgICBjb250ZXh0TWVudURpc3BsYXllZDogZmFsc2UsXG4gICAgICAgIH07XG4gICAgfVxuXG4gICAgLy8gWFhYOiBSZWZzIHRvIGZ1bmN0aW9uYWwgY29tcG9uZW50c1xuICAgIHByaXZhdGUgY29udGV4dE1lbnVCdXR0b24gPSBjcmVhdGVSZWY8YW55PigpO1xuICAgIHByaXZhdGUgZm9jdXNMb2NrID0gY3JlYXRlUmVmPGFueT4oKTtcbiAgICBwcml2YXRlIGltYWdlV3JhcHBlciA9IGNyZWF0ZVJlZjxIVE1MRGl2RWxlbWVudD4oKTtcbiAgICBwcml2YXRlIGltYWdlID0gY3JlYXRlUmVmPEhUTUxJbWFnZUVsZW1lbnQ+KCk7XG5cbiAgICBwcml2YXRlIGluaXRYID0gMDtcbiAgICBwcml2YXRlIGluaXRZID0gMDtcbiAgICBwcml2YXRlIGxhc3RYID0gMDtcbiAgICBwcml2YXRlIGxhc3RZID0gMDtcbiAgICBwcml2YXRlIHByZXZpb3VzWCA9IDA7XG4gICAgcHJpdmF0ZSBwcmV2aW91c1kgPSAwO1xuXG4gICAgY29tcG9uZW50RGlkTW91bnQoKSB7XG4gICAgICAgIC8vIFdlIGhhdmUgdG8gdXNlIGFkZEV2ZW50TGlzdGVuZXIoKSBiZWNhdXNlIHRoZSBsaXN0ZW5lclxuICAgICAgICAvLyBuZWVkcyB0byBiZSBwYXNzaXZlIGluIG9yZGVyIHRvIHdvcmsgd2l0aCBDaHJvbWl1bVxuICAgICAgICB0aGlzLmZvY3VzTG9jay5jdXJyZW50LmFkZEV2ZW50TGlzdGVuZXIoJ3doZWVsJywgdGhpcy5vbldoZWVsLCB7IHBhc3NpdmU6IGZhbHNlIH0pO1xuICAgICAgICAvLyBXZSB3YW50IHRvIHJlY2FsY3VsYXRlIHpvb20gd2hlbmV2ZXIgdGhlIHdpbmRvdydzIHNpemUgY2hhbmdlc1xuICAgICAgICB3aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcihcInJlc2l6ZVwiLCB0aGlzLmNhbGN1bGF0ZVpvb20pO1xuICAgICAgICAvLyBBZnRlciB0aGUgaW1hZ2UgbG9hZHMgZm9yIHRoZSBmaXJzdCB0aW1lIHdlIHdhbnQgdG8gY2FsY3VsYXRlIHRoZSB6b29tXG4gICAgICAgIHRoaXMuaW1hZ2UuY3VycmVudC5hZGRFdmVudExpc3RlbmVyKFwibG9hZFwiLCB0aGlzLmNhbGN1bGF0ZVpvb20pO1xuICAgIH1cblxuICAgIGNvbXBvbmVudFdpbGxVbm1vdW50KCkge1xuICAgICAgICB0aGlzLmZvY3VzTG9jay5jdXJyZW50LnJlbW92ZUV2ZW50TGlzdGVuZXIoJ3doZWVsJywgdGhpcy5vbldoZWVsKTtcbiAgICAgICAgd2luZG93LnJlbW92ZUV2ZW50TGlzdGVuZXIoXCJyZXNpemVcIiwgdGhpcy5jYWxjdWxhdGVab29tKTtcbiAgICAgICAgdGhpcy5pbWFnZS5jdXJyZW50LnJlbW92ZUV2ZW50TGlzdGVuZXIoXCJsb2FkXCIsIHRoaXMuY2FsY3VsYXRlWm9vbSk7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBjYWxjdWxhdGVab29tID0gKCkgPT4ge1xuICAgICAgICBjb25zdCBpbWFnZSA9IHRoaXMuaW1hZ2UuY3VycmVudDtcbiAgICAgICAgY29uc3QgaW1hZ2VXcmFwcGVyID0gdGhpcy5pbWFnZVdyYXBwZXIuY3VycmVudDtcblxuICAgICAgICBjb25zdCB6b29tWCA9IGltYWdlV3JhcHBlci5jbGllbnRXaWR0aCAvIGltYWdlLm5hdHVyYWxXaWR0aDtcbiAgICAgICAgY29uc3Qgem9vbVkgPSBpbWFnZVdyYXBwZXIuY2xpZW50SGVpZ2h0IC8gaW1hZ2UubmF0dXJhbEhlaWdodDtcblxuICAgICAgICAvLyBJZiB0aGUgaW1hZ2UgaXMgc21hbGxlciBpbiBib3RoIGRpbWVuc2lvbnMgc2V0IGl0cyB0aGUgem9vbSB0byAxIHRvXG4gICAgICAgIC8vIGRpc3BsYXkgaXQgaW4gaXRzIG9yaWdpbmFsIHNpemVcbiAgICAgICAgaWYgKHpvb21YID49IDEgJiYgem9vbVkgPj0gMSkge1xuICAgICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICAgICAgem9vbTogMSxcbiAgICAgICAgICAgICAgICBtaW5ab29tOiAxLFxuICAgICAgICAgICAgICAgIG1heFpvb206IDEsXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICAvLyBXZSBzZXQgbWluWm9vbSB0byB0aGUgbWluIG9mIHRoZSB6b29tWCBhbmQgem9vbVkgdG8gYXZvaWQgb3ZlcmZsb3cgaW5cbiAgICAgICAgLy8gYW55IGRpcmVjdGlvbi4gV2UgYWxzbyBtdWx0aXBseSBieSBNQVhfU0NBTEUgdG8gZ2V0IGEgZ2FwIGFyb3VuZCB0aGVcbiAgICAgICAgLy8gaW1hZ2UgYnkgZGVmYXVsdFxuICAgICAgICBjb25zdCBtaW5ab29tID0gTWF0aC5taW4oem9vbVgsIHpvb21ZKSAqIE1BWF9TQ0FMRTtcblxuICAgICAgICBpZiAodGhpcy5zdGF0ZS56b29tIDw9IHRoaXMuc3RhdGUubWluWm9vbSkgdGhpcy5zZXRTdGF0ZSh7em9vbTogbWluWm9vbX0pO1xuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICAgIG1pblpvb206IG1pblpvb20sXG4gICAgICAgICAgICBtYXhab29tOiAxLFxuICAgICAgICB9KTtcbiAgICB9XG5cbiAgICBwcml2YXRlIHpvb20oZGVsdGE6IG51bWJlcikge1xuICAgICAgICBjb25zdCBuZXdab29tID0gdGhpcy5zdGF0ZS56b29tICsgZGVsdGE7XG5cbiAgICAgICAgaWYgKG5ld1pvb20gPD0gdGhpcy5zdGF0ZS5taW5ab29tKSB7XG4gICAgICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICAgICAgICB6b29tOiB0aGlzLnN0YXRlLm1pblpvb20sXG4gICAgICAgICAgICAgICAgdHJhbnNsYXRpb25YOiAwLFxuICAgICAgICAgICAgICAgIHRyYW5zbGF0aW9uWTogMCxcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIGlmIChuZXdab29tID49IHRoaXMuc3RhdGUubWF4Wm9vbSkge1xuICAgICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7em9vbTogdGhpcy5zdGF0ZS5tYXhab29tfSk7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICAgIHpvb206IG5ld1pvb20sXG4gICAgICAgIH0pO1xuICAgIH1cblxuICAgIHByaXZhdGUgb25XaGVlbCA9IChldjogV2hlZWxFdmVudCkgPT4ge1xuICAgICAgICBldi5zdG9wUHJvcGFnYXRpb24oKTtcbiAgICAgICAgZXYucHJldmVudERlZmF1bHQoKTtcblxuICAgICAgICBjb25zdCB7ZGVsdGFZfSA9IG5vcm1hbGl6ZVdoZWVsRXZlbnQoZXYpO1xuICAgICAgICB0aGlzLnpvb20oLShkZWx0YVkgKiBaT09NX0NPRUZGSUNJRU5UKSk7XG4gICAgfTtcblxuICAgIHByaXZhdGUgb25ab29tSW5DbGljayA9ICgpID0+IHtcbiAgICAgICAgdGhpcy56b29tKFpPT01fU1RFUCk7XG4gICAgfTtcblxuICAgIHByaXZhdGUgb25ab29tT3V0Q2xpY2sgPSAoKSA9PiB7XG4gICAgICAgIHRoaXMuem9vbSgtWk9PTV9TVEVQKTtcbiAgICB9O1xuXG4gICAgcHJpdmF0ZSBvbktleURvd24gPSAoZXY6IEtleWJvYXJkRXZlbnQpID0+IHtcbiAgICAgICAgaWYgKGV2LmtleSA9PT0gS2V5LkVTQ0FQRSkge1xuICAgICAgICAgICAgZXYuc3RvcFByb3BhZ2F0aW9uKCk7XG4gICAgICAgICAgICBldi5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgICAgICAgdGhpcy5wcm9wcy5vbkZpbmlzaGVkKCk7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgcHJpdmF0ZSBvblJvdGF0ZUNvdW50ZXJDbG9ja3dpc2VDbGljayA9ICgpID0+IHtcbiAgICAgICAgY29uc3QgY3VyID0gdGhpcy5zdGF0ZS5yb3RhdGlvbjtcbiAgICAgICAgY29uc3Qgcm90YXRpb25EZWdyZWVzID0gY3VyIC0gOTA7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoeyByb3RhdGlvbjogcm90YXRpb25EZWdyZWVzIH0pO1xuICAgIH07XG5cbiAgICBwcml2YXRlIG9uUm90YXRlQ2xvY2t3aXNlQ2xpY2sgPSAoKSA9PiB7XG4gICAgICAgIGNvbnN0IGN1ciA9IHRoaXMuc3RhdGUucm90YXRpb247XG4gICAgICAgIGNvbnN0IHJvdGF0aW9uRGVncmVlcyA9IGN1ciArIDkwO1xuICAgICAgICB0aGlzLnNldFN0YXRlKHsgcm90YXRpb246IHJvdGF0aW9uRGVncmVlcyB9KTtcbiAgICB9O1xuXG4gICAgcHJpdmF0ZSBvbkRvd25sb2FkQ2xpY2sgPSAoKSA9PiB7XG4gICAgICAgIGNvbnN0IGEgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KFwiYVwiKTtcbiAgICAgICAgYS5ocmVmID0gdGhpcy5wcm9wcy5zcmM7XG4gICAgICAgIGEuZG93bmxvYWQgPSB0aGlzLnByb3BzLm5hbWU7XG4gICAgICAgIGEudGFyZ2V0ID0gXCJfYmxhbmtcIjtcbiAgICAgICAgYS5yZWwgPSBcIm5vcmVmZXJyZXIgbm9vcGVuZXJcIjtcbiAgICAgICAgYS5jbGljaygpO1xuICAgIH07XG5cbiAgICBwcml2YXRlIG9uT3BlbkNvbnRleHRNZW51ID0gKCkgPT4ge1xuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICAgIGNvbnRleHRNZW51RGlzcGxheWVkOiB0cnVlLFxuICAgICAgICB9KTtcbiAgICB9O1xuXG4gICAgcHJpdmF0ZSBvbkNsb3NlQ29udGV4dE1lbnUgPSAoKSA9PiB7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgY29udGV4dE1lbnVEaXNwbGF5ZWQ6IGZhbHNlLFxuICAgICAgICB9KTtcbiAgICB9O1xuXG4gICAgcHJpdmF0ZSBvblBlcm1hbGlua0NsaWNrZWQgPSAoZXY6IFJlYWN0Lk1vdXNlRXZlbnQpID0+IHtcbiAgICAgICAgLy8gVGhpcyBhbGxvd3MgdGhlIHBlcm1hbGluayB0byBiZSBvcGVuZWQgaW4gYSBuZXcgdGFiL3dpbmRvdyBvciBjb3BpZWQgYXNcbiAgICAgICAgLy8gbWF0cml4LnRvLCBidXQgYWxzbyBmb3IgaXQgdG8gZW5hYmxlIHJvdXRpbmcgd2l0aGluIEVsZW1lbnQgd2hlbiBjbGlja2VkLlxuICAgICAgICBldi5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgICBkaXMuZGlzcGF0Y2goe1xuICAgICAgICAgICAgYWN0aW9uOiAndmlld19yb29tJyxcbiAgICAgICAgICAgIGV2ZW50X2lkOiB0aGlzLnByb3BzLm14RXZlbnQuZ2V0SWQoKSxcbiAgICAgICAgICAgIGhpZ2hsaWdodGVkOiB0cnVlLFxuICAgICAgICAgICAgcm9vbV9pZDogdGhpcy5wcm9wcy5teEV2ZW50LmdldFJvb21JZCgpLFxuICAgICAgICB9KTtcbiAgICAgICAgdGhpcy5wcm9wcy5vbkZpbmlzaGVkKCk7XG4gICAgfTtcblxuICAgIHByaXZhdGUgb25TdGFydE1vdmluZyA9IChldjogUmVhY3QuTW91c2VFdmVudCkgPT4ge1xuICAgICAgICBldi5zdG9wUHJvcGFnYXRpb24oKTtcbiAgICAgICAgZXYucHJldmVudERlZmF1bHQoKTtcblxuICAgICAgICAvLyBEb24ndCBkbyBhbnl0aGluZyBpZiB3ZSBwcmVzc2VkIGFueVxuICAgICAgICAvLyBvdGhlciBidXR0b24gdGhhbiB0aGUgbGVmdCBvbmVcbiAgICAgICAgaWYgKGV2LmJ1dHRvbiAhPT0gMCkgcmV0dXJuO1xuXG4gICAgICAgIC8vIFpvb20gaW4gaWYgd2UgYXJlIGNvbXBsZXRlbHkgem9vbWVkIG91dFxuICAgICAgICBpZiAodGhpcy5zdGF0ZS56b29tID09PSB0aGlzLnN0YXRlLm1pblpvb20pIHtcbiAgICAgICAgICAgIHRoaXMuc2V0U3RhdGUoe3pvb206IHRoaXMuc3RhdGUubWF4Wm9vbX0pO1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7bW92aW5nOiB0cnVlfSk7XG4gICAgICAgIHRoaXMucHJldmlvdXNYID0gdGhpcy5zdGF0ZS50cmFuc2xhdGlvblg7XG4gICAgICAgIHRoaXMucHJldmlvdXNZID0gdGhpcy5zdGF0ZS50cmFuc2xhdGlvblk7XG4gICAgICAgIHRoaXMuaW5pdFggPSBldi5wYWdlWCAtIHRoaXMubGFzdFg7XG4gICAgICAgIHRoaXMuaW5pdFkgPSBldi5wYWdlWSAtIHRoaXMubGFzdFk7XG4gICAgfTtcblxuICAgIHByaXZhdGUgb25Nb3ZpbmcgPSAoZXY6IFJlYWN0Lk1vdXNlRXZlbnQpID0+IHtcbiAgICAgICAgZXYuc3RvcFByb3BhZ2F0aW9uKCk7XG4gICAgICAgIGV2LnByZXZlbnREZWZhdWx0KCk7XG5cbiAgICAgICAgaWYgKCF0aGlzLnN0YXRlLm1vdmluZykgcmV0dXJuO1xuXG4gICAgICAgIHRoaXMubGFzdFggPSBldi5wYWdlWCAtIHRoaXMuaW5pdFg7XG4gICAgICAgIHRoaXMubGFzdFkgPSBldi5wYWdlWSAtIHRoaXMuaW5pdFk7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgdHJhbnNsYXRpb25YOiB0aGlzLmxhc3RYLFxuICAgICAgICAgICAgdHJhbnNsYXRpb25ZOiB0aGlzLmxhc3RZLFxuICAgICAgICB9KTtcbiAgICB9O1xuXG4gICAgcHJpdmF0ZSBvbkVuZE1vdmluZyA9ICgpID0+IHtcbiAgICAgICAgLy8gWm9vbSBvdXQgaWYgd2UgaGF2ZW4ndCBtb3ZlZCBtdWNoXG4gICAgICAgIGlmIChcbiAgICAgICAgICAgIHRoaXMuc3RhdGUubW92aW5nID09PSB0cnVlICYmXG4gICAgICAgICAgICBNYXRoLmFicyh0aGlzLnN0YXRlLnRyYW5zbGF0aW9uWCAtIHRoaXMucHJldmlvdXNYKSA8IFpPT01fRElTVEFOQ0UgJiZcbiAgICAgICAgICAgIE1hdGguYWJzKHRoaXMuc3RhdGUudHJhbnNsYXRpb25ZIC0gdGhpcy5wcmV2aW91c1kpIDwgWk9PTV9ESVNUQU5DRVxuICAgICAgICApIHtcbiAgICAgICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgICAgIHpvb206IHRoaXMuc3RhdGUubWluWm9vbSxcbiAgICAgICAgICAgICAgICB0cmFuc2xhdGlvblg6IDAsXG4gICAgICAgICAgICAgICAgdHJhbnNsYXRpb25ZOiAwLFxuICAgICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7bW92aW5nOiBmYWxzZX0pO1xuICAgIH07XG5cbiAgICBwcml2YXRlIHJlbmRlckNvbnRleHRNZW51KCkge1xuICAgICAgICBsZXQgY29udGV4dE1lbnUgPSBudWxsO1xuICAgICAgICBpZiAodGhpcy5zdGF0ZS5jb250ZXh0TWVudURpc3BsYXllZCkge1xuICAgICAgICAgICAgY29udGV4dE1lbnUgPSAoXG4gICAgICAgICAgICAgICAgPENvbnRleHRNZW51XG4gICAgICAgICAgICAgICAgICAgIHsuLi5hYm92ZUxlZnRPZih0aGlzLmNvbnRleHRNZW51QnV0dG9uLmN1cnJlbnQuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCkpfVxuICAgICAgICAgICAgICAgICAgICBvbkZpbmlzaGVkPXt0aGlzLm9uQ2xvc2VDb250ZXh0TWVudX1cbiAgICAgICAgICAgICAgICA+XG4gICAgICAgICAgICAgICAgICAgIDxNZXNzYWdlQ29udGV4dE1lbnVcbiAgICAgICAgICAgICAgICAgICAgICAgIG14RXZlbnQ9e3RoaXMucHJvcHMubXhFdmVudH1cbiAgICAgICAgICAgICAgICAgICAgICAgIHBlcm1hbGlua0NyZWF0b3I9e3RoaXMucHJvcHMucGVybWFsaW5rQ3JlYXRvcn1cbiAgICAgICAgICAgICAgICAgICAgICAgIG9uRmluaXNoZWQ9e3RoaXMub25DbG9zZUNvbnRleHRNZW51fVxuICAgICAgICAgICAgICAgICAgICAgICAgb25DbG9zZURpYWxvZz17dGhpcy5wcm9wcy5vbkZpbmlzaGVkfVxuICAgICAgICAgICAgICAgICAgICAvPlxuICAgICAgICAgICAgICAgIDwvQ29udGV4dE1lbnU+XG4gICAgICAgICAgICApO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIChcbiAgICAgICAgICAgIDxSZWFjdC5GcmFnbWVudD5cbiAgICAgICAgICAgICAgICB7IGNvbnRleHRNZW51IH1cbiAgICAgICAgICAgIDwvUmVhY3QuRnJhZ21lbnQ+XG4gICAgICAgICk7XG4gICAgfVxuXG4gICAgcmVuZGVyKCkge1xuICAgICAgICBjb25zdCBzaG93RXZlbnRNZXRhID0gISF0aGlzLnByb3BzLm14RXZlbnQ7XG4gICAgICAgIGNvbnN0IHpvb21pbmdEaXNhYmxlZCA9IHRoaXMuc3RhdGUubWF4Wm9vbSA9PT0gdGhpcy5zdGF0ZS5taW5ab29tO1xuXG4gICAgICAgIGxldCBjdXJzb3I7XG4gICAgICAgIGlmICh0aGlzLnN0YXRlLm1vdmluZykge1xuICAgICAgICAgICAgY3Vyc29yPSBcImdyYWJiaW5nXCI7XG4gICAgICAgIH0gZWxzZSBpZiAoem9vbWluZ0Rpc2FibGVkKSB7XG4gICAgICAgICAgICBjdXJzb3IgPSBcImRlZmF1bHRcIjtcbiAgICAgICAgfSBlbHNlIGlmICh0aGlzLnN0YXRlLnpvb20gPT09IHRoaXMuc3RhdGUubWluWm9vbSkge1xuICAgICAgICAgICAgY3Vyc29yID0gXCJ6b29tLWluXCI7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBjdXJzb3IgPSBcInpvb20tb3V0XCI7XG4gICAgICAgIH1cbiAgICAgICAgY29uc3Qgcm90YXRpb25EZWdyZWVzID0gdGhpcy5zdGF0ZS5yb3RhdGlvbiArIFwiZGVnXCI7XG4gICAgICAgIGNvbnN0IHpvb20gPSB0aGlzLnN0YXRlLnpvb207XG4gICAgICAgIGNvbnN0IHRyYW5zbGF0ZVBpeGVsc1ggPSB0aGlzLnN0YXRlLnRyYW5zbGF0aW9uWCArIFwicHhcIjtcbiAgICAgICAgY29uc3QgdHJhbnNsYXRlUGl4ZWxzWSA9IHRoaXMuc3RhdGUudHJhbnNsYXRpb25ZICsgXCJweFwiO1xuICAgICAgICAvLyBUaGUgb3JkZXIgb2YgdGhlIHZhbHVlcyBpcyBpbXBvcnRhbnQhXG4gICAgICAgIC8vIEZpcnN0LCB3ZSB0cmFuc2xhdGUgYW5kIG9ubHkgdGhlbiB3ZSByb3RhdGUsIG90aGVyd2lzZVxuICAgICAgICAvLyB3ZSB3b3VsZCBhcHBseSB0aGUgdHJhbnNsYXRpb24gdG8gYW4gYWxyZWFkeSByb3RhdGVkXG4gICAgICAgIC8vIGltYWdlIGNhdXNpbmcgaXQgdHJhbnNsYXRlIGluIHRoZSB3cm9uZyBkaXJlY3Rpb24uXG4gICAgICAgIGNvbnN0IHN0eWxlID0ge1xuICAgICAgICAgICAgY3Vyc29yOiBjdXJzb3IsXG4gICAgICAgICAgICB0cmFuc2l0aW9uOiB0aGlzLnN0YXRlLm1vdmluZyA/IG51bGwgOiBcInRyYW5zZm9ybSAyMDBtcyBlYXNlIDBzXCIsXG4gICAgICAgICAgICB0cmFuc2Zvcm06IGB0cmFuc2xhdGVYKCR7dHJhbnNsYXRlUGl4ZWxzWH0pXG4gICAgICAgICAgICAgICAgICAgICAgICB0cmFuc2xhdGVZKCR7dHJhbnNsYXRlUGl4ZWxzWX0pXG4gICAgICAgICAgICAgICAgICAgICAgICBzY2FsZSgke3pvb219KVxuICAgICAgICAgICAgICAgICAgICAgICAgcm90YXRlKCR7cm90YXRpb25EZWdyZWVzfSlgLFxuICAgICAgICB9O1xuXG4gICAgICAgIGxldCBpbmZvO1xuICAgICAgICBpZiAoc2hvd0V2ZW50TWV0YSkge1xuICAgICAgICAgICAgY29uc3QgbXhFdmVudCA9IHRoaXMucHJvcHMubXhFdmVudDtcbiAgICAgICAgICAgIGNvbnN0IHNob3dUd2VsdmVIb3VyID0gU2V0dGluZ3NTdG9yZS5nZXRWYWx1ZShcInNob3dUd2VsdmVIb3VyVGltZXN0YW1wc1wiKTtcbiAgICAgICAgICAgIGxldCBwZXJtYWxpbmsgPSBcIiNcIjtcbiAgICAgICAgICAgIGlmICh0aGlzLnByb3BzLnBlcm1hbGlua0NyZWF0b3IpIHtcbiAgICAgICAgICAgICAgICBwZXJtYWxpbmsgPSB0aGlzLnByb3BzLnBlcm1hbGlua0NyZWF0b3IuZm9yRXZlbnQodGhpcy5wcm9wcy5teEV2ZW50LmdldElkKCkpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBjb25zdCBzZW5kZXJOYW1lID0gbXhFdmVudC5zZW5kZXIgPyBteEV2ZW50LnNlbmRlci5uYW1lIDogbXhFdmVudC5nZXRTZW5kZXIoKTtcbiAgICAgICAgICAgIGNvbnN0IHNlbmRlciA9IChcbiAgICAgICAgICAgICAgICA8ZGl2IGNsYXNzTmFtZT1cIm14X0ltYWdlVmlld19pbmZvX3NlbmRlclwiPlxuICAgICAgICAgICAgICAgICAgICB7c2VuZGVyTmFtZX1cbiAgICAgICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICAgICk7XG4gICAgICAgICAgICBjb25zdCBtZXNzYWdlVGltZXN0YW1wID0gKFxuICAgICAgICAgICAgICAgIDxhXG4gICAgICAgICAgICAgICAgICAgIGhyZWY9e3Blcm1hbGlua31cbiAgICAgICAgICAgICAgICAgICAgb25DbGljaz17dGhpcy5vblBlcm1hbGlua0NsaWNrZWR9XG4gICAgICAgICAgICAgICAgICAgIGFyaWEtbGFiZWw9e2Zvcm1hdEZ1bGxEYXRlKG5ldyBEYXRlKHRoaXMucHJvcHMubXhFdmVudC5nZXRUcygpKSwgc2hvd1R3ZWx2ZUhvdXIsIGZhbHNlKX1cbiAgICAgICAgICAgICAgICA+XG4gICAgICAgICAgICAgICAgICAgIDxNZXNzYWdlVGltZXN0YW1wXG4gICAgICAgICAgICAgICAgICAgICAgICBzaG93RnVsbERhdGU9e3RydWV9XG4gICAgICAgICAgICAgICAgICAgICAgICBzaG93VHdlbHZlSG91cj17c2hvd1R3ZWx2ZUhvdXJ9XG4gICAgICAgICAgICAgICAgICAgICAgICB0cz17bXhFdmVudC5nZXRUcygpfVxuICAgICAgICAgICAgICAgICAgICAgICAgc2hvd1NlY29uZHM9e2ZhbHNlfVxuICAgICAgICAgICAgICAgICAgICAvPlxuICAgICAgICAgICAgICAgIDwvYT5cbiAgICAgICAgICAgICk7XG4gICAgICAgICAgICBjb25zdCBhdmF0YXIgPSAoXG4gICAgICAgICAgICAgICAgPE1lbWJlckF2YXRhclxuICAgICAgICAgICAgICAgICAgICBtZW1iZXI9e214RXZlbnQuc2VuZGVyfVxuICAgICAgICAgICAgICAgICAgICB3aWR0aD17MzJ9IGhlaWdodD17MzJ9XG4gICAgICAgICAgICAgICAgICAgIHZpZXdVc2VyT25DbGljaz17dHJ1ZX1cbiAgICAgICAgICAgICAgICAvPlxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgaW5mbyA9IChcbiAgICAgICAgICAgICAgICA8ZGl2IGNsYXNzTmFtZT1cIm14X0ltYWdlVmlld19pbmZvX3dyYXBwZXJcIj5cbiAgICAgICAgICAgICAgICAgICAge2F2YXRhcn1cbiAgICAgICAgIC