matrix-react-sdk
Version:
SDK for matrix.org using React
262 lines (213 loc) • 34.5 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 _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
var _react = _interopRequireDefault(require("react"));
var _propTypes = _interopRequireDefault(require("prop-types"));
var _filter = require("matrix-js-sdk/src/filter");
var sdk = _interopRequireWildcard(require("../../index"));
var _MatrixClientPeg = require("../../MatrixClientPeg");
var _EventIndexPeg = _interopRequireDefault(require("../../indexing/EventIndexPeg"));
var _languageHandler = require("../../languageHandler");
var _BaseCard = _interopRequireDefault(require("../views/right_panel/BaseCard"));
var _RightPanelStorePhases = require("../../stores/RightPanelStorePhases");
var _DesktopBuildsNotice = _interopRequireWildcard(require("../views/elements/DesktopBuildsNotice"));
var _replaceableComponent = require("../../utils/replaceableComponent");
var _dec, _class, _class2, _temp;
/*
* Component which shows the filtered file using a TimelinePanel
*/
let FilePanel = (_dec = (0, _replaceableComponent.replaceableComponent)("structures.FilePanel"), _dec(_class = (_temp = _class2 = class FilePanel extends _react.default.Component {
constructor(...args) {
super(...args);
(0, _defineProperty2.default)(this, "decryptingEvents", new Set());
(0, _defineProperty2.default)(this, "state", {
timelineSet: null
});
(0, _defineProperty2.default)(this, "onRoomTimeline", (ev, room, toStartOfTimeline, removed, data) => {
if (room?.roomId !== this.props?.roomId) return;
if (toStartOfTimeline || !data || !data.liveEvent || ev.isRedacted()) return;
const client = _MatrixClientPeg.MatrixClientPeg.get();
client.decryptEventIfNeeded(ev);
if (ev.isBeingDecrypted()) {
this.decryptingEvents.add(ev.getId());
} else {
this.addEncryptedLiveEvent(ev);
}
});
(0, _defineProperty2.default)(this, "onEventDecrypted", (ev, err) => {
if (ev.getRoomId() !== this.props.roomId) return;
const eventId = ev.getId();
if (!this.decryptingEvents.delete(eventId)) return;
if (err) return;
this.addEncryptedLiveEvent(ev);
});
(0, _defineProperty2.default)(this, "onPaginationRequest", (timelineWindow, direction, limit) => {
const client = _MatrixClientPeg.MatrixClientPeg.get();
const eventIndex = _EventIndexPeg.default.get();
const roomId = this.props.roomId;
const room = client.getRoom(roomId); // We override the pagination request for encrypted rooms so that we ask
// the event index to fulfill the pagination request. Asking the server
// to paginate won't ever work since the server can't correctly filter
// out events containing URLs
if (client.isRoomEncrypted(roomId) && eventIndex !== null) {
return eventIndex.paginateTimelineWindow(room, timelineWindow, direction, limit);
} else {
return timelineWindow.paginate(direction, limit);
}
});
}
addEncryptedLiveEvent(ev, toStartOfTimeline) {
if (!this.state.timelineSet) return;
const timeline = this.state.timelineSet.getLiveTimeline();
if (ev.getType() !== "m.room.message") return;
if (["m.file", "m.image", "m.video", "m.audio"].indexOf(ev.getContent().msgtype) == -1) {
return;
}
if (!this.state.timelineSet.eventIdToTimeline(ev.getId())) {
this.state.timelineSet.addEventToTimeline(ev, timeline, false);
}
}
async componentDidMount() {
const client = _MatrixClientPeg.MatrixClientPeg.get();
await this.updateTimelineSet(this.props.roomId);
if (!_MatrixClientPeg.MatrixClientPeg.get().isRoomEncrypted(this.props.roomId)) return; // The timelineSets filter makes sure that encrypted events that contain
// URLs never get added to the timeline, even if they are live events.
// These methods are here to manually listen for such events and add
// them despite the filter's best efforts.
//
// We do this only for encrypted rooms and if an event index exists,
// this could be made more general in the future or the filter logic
// could be fixed.
if (_EventIndexPeg.default.get() !== null) {
client.on('Room.timeline', this.onRoomTimeline);
client.on('Event.decrypted', this.onEventDecrypted);
}
}
componentWillUnmount() {
const client = _MatrixClientPeg.MatrixClientPeg.get();
if (client === null) return;
if (!_MatrixClientPeg.MatrixClientPeg.get().isRoomEncrypted(this.props.roomId)) return;
if (_EventIndexPeg.default.get() !== null) {
client.removeListener('Room.timeline', this.onRoomTimeline);
client.removeListener('Event.decrypted', this.onEventDecrypted);
}
}
async fetchFileEventsServer(room) {
const client = _MatrixClientPeg.MatrixClientPeg.get();
const filter = new _filter.Filter(client.credentials.userId);
filter.setDefinition({
"room": {
"timeline": {
"contains_url": true,
"types": ["m.room.message"]
}
}
});
const filterId = await client.getOrCreateFilter("FILTER_FILES_" + client.credentials.userId, filter);
filter.filterId = filterId;
const timelineSet = room.getOrCreateFilteredTimelineSet(filter);
return timelineSet;
}
async updateTimelineSet(roomId
/*: string*/
) {
const client = _MatrixClientPeg.MatrixClientPeg.get();
const room = client.getRoom(roomId);
const eventIndex = _EventIndexPeg.default.get();
this.noRoom = !room;
if (room) {
let timelineSet;
try {
timelineSet = await this.fetchFileEventsServer(room); // If this room is encrypted the file panel won't be populated
// correctly since the defined filter doesn't support encrypted
// events and the server can't check if encrypted events contain
// URLs.
//
// This is where our event index comes into place, we ask the
// event index to populate the timelineSet for us. This call
// will add 10 events to the live timeline of the set. More can
// be requested using pagination.
if (client.isRoomEncrypted(roomId) && eventIndex !== null) {
const timeline = timelineSet.getLiveTimeline();
await eventIndex.populateFileTimeline(timelineSet, timeline, room, 10);
}
this.setState({
timelineSet: timelineSet
});
} catch (error) {
console.error("Failed to get or create file panel filter", error);
}
} else {
console.error("Failed to add filtered timelineSet for FilePanel as no room!");
}
}
render() {
if (_MatrixClientPeg.MatrixClientPeg.get().isGuest()) {
return /*#__PURE__*/_react.default.createElement(_BaseCard.default, {
className: "mx_FilePanel mx_RoomView_messageListWrapper",
onClose: this.props.onClose,
previousPhase: _RightPanelStorePhases.RightPanelPhases.RoomSummary
}, /*#__PURE__*/_react.default.createElement("div", {
className: "mx_RoomView_empty"
}, (0, _languageHandler._t)("You must <a>register</a> to use this functionality", {}, {
'a': sub => /*#__PURE__*/_react.default.createElement("a", {
href: "#/register",
key: "sub"
}, sub)
})));
} else if (this.noRoom) {
return /*#__PURE__*/_react.default.createElement(_BaseCard.default, {
className: "mx_FilePanel mx_RoomView_messageListWrapper",
onClose: this.props.onClose,
previousPhase: _RightPanelStorePhases.RightPanelPhases.RoomSummary
}, /*#__PURE__*/_react.default.createElement("div", {
className: "mx_RoomView_empty"
}, (0, _languageHandler._t)("You must join the room to see its files")));
} // wrap a TimelinePanel with the jump-to-event bits turned off.
const TimelinePanel = sdk.getComponent("structures.TimelinePanel");
const Loader = sdk.getComponent("elements.Spinner");
const emptyState = /*#__PURE__*/_react.default.createElement("div", {
className: "mx_RightPanel_empty mx_FilePanel_empty"
}, /*#__PURE__*/_react.default.createElement("h2", null, (0, _languageHandler._t)('No files visible in this room')), /*#__PURE__*/_react.default.createElement("p", null, (0, _languageHandler._t)('Attach files from chat or just drag and drop them anywhere in a room.')));
const isRoomEncrypted = this.noRoom ? false : _MatrixClientPeg.MatrixClientPeg.get().isRoomEncrypted(this.props.roomId);
if (this.state.timelineSet) {
// console.log("rendering TimelinePanel for timelineSet " + this.state.timelineSet.room.roomId + " " +
// "(" + this.state.timelineSet._timelines.join(", ") + ")" + " with key " + this.props.roomId);
return /*#__PURE__*/_react.default.createElement(_BaseCard.default, {
className: "mx_FilePanel",
onClose: this.props.onClose,
previousPhase: _RightPanelStorePhases.RightPanelPhases.RoomSummary,
withoutScrollContainer: true
}, /*#__PURE__*/_react.default.createElement(_DesktopBuildsNotice.default, {
isRoomEncrypted: isRoomEncrypted,
kind: _DesktopBuildsNotice.WarningKind.Files
}), /*#__PURE__*/_react.default.createElement(TimelinePanel, {
manageReadReceipts: false,
manageReadMarkers: false,
timelineSet: this.state.timelineSet,
showUrlPreview: false,
onPaginationRequest: this.onPaginationRequest,
tileShape: "file_grid",
resizeNotifier: this.props.resizeNotifier,
empty: emptyState
}));
} else {
return /*#__PURE__*/_react.default.createElement(_BaseCard.default, {
className: "mx_FilePanel",
onClose: this.props.onClose,
previousPhase: _RightPanelStorePhases.RightPanelPhases.RoomSummary
}, /*#__PURE__*/_react.default.createElement(Loader, null));
}
}
}, (0, _defineProperty2.default)(_class2, "propTypes", {
roomId: _propTypes.default.string.isRequired,
onClose: _propTypes.default.func.isRequired
}), _temp)) || _class);
var _default = FilePanel;
exports.default = _default;
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9jb21wb25lbnRzL3N0cnVjdHVyZXMvRmlsZVBhbmVsLmpzIl0sIm5hbWVzIjpbIkZpbGVQYW5lbCIsIlJlYWN0IiwiQ29tcG9uZW50IiwiU2V0IiwidGltZWxpbmVTZXQiLCJldiIsInJvb20iLCJ0b1N0YXJ0T2ZUaW1lbGluZSIsInJlbW92ZWQiLCJkYXRhIiwicm9vbUlkIiwicHJvcHMiLCJsaXZlRXZlbnQiLCJpc1JlZGFjdGVkIiwiY2xpZW50IiwiTWF0cml4Q2xpZW50UGVnIiwiZ2V0IiwiZGVjcnlwdEV2ZW50SWZOZWVkZWQiLCJpc0JlaW5nRGVjcnlwdGVkIiwiZGVjcnlwdGluZ0V2ZW50cyIsImFkZCIsImdldElkIiwiYWRkRW5jcnlwdGVkTGl2ZUV2ZW50IiwiZXJyIiwiZ2V0Um9vbUlkIiwiZXZlbnRJZCIsImRlbGV0ZSIsInRpbWVsaW5lV2luZG93IiwiZGlyZWN0aW9uIiwibGltaXQiLCJldmVudEluZGV4IiwiRXZlbnRJbmRleFBlZyIsImdldFJvb20iLCJpc1Jvb21FbmNyeXB0ZWQiLCJwYWdpbmF0ZVRpbWVsaW5lV2luZG93IiwicGFnaW5hdGUiLCJzdGF0ZSIsInRpbWVsaW5lIiwiZ2V0TGl2ZVRpbWVsaW5lIiwiZ2V0VHlwZSIsImluZGV4T2YiLCJnZXRDb250ZW50IiwibXNndHlwZSIsImV2ZW50SWRUb1RpbWVsaW5lIiwiYWRkRXZlbnRUb1RpbWVsaW5lIiwiY29tcG9uZW50RGlkTW91bnQiLCJ1cGRhdGVUaW1lbGluZVNldCIsIm9uIiwib25Sb29tVGltZWxpbmUiLCJvbkV2ZW50RGVjcnlwdGVkIiwiY29tcG9uZW50V2lsbFVubW91bnQiLCJyZW1vdmVMaXN0ZW5lciIsImZldGNoRmlsZUV2ZW50c1NlcnZlciIsImZpbHRlciIsIkZpbHRlciIsImNyZWRlbnRpYWxzIiwidXNlcklkIiwic2V0RGVmaW5pdGlvbiIsImZpbHRlcklkIiwiZ2V0T3JDcmVhdGVGaWx0ZXIiLCJnZXRPckNyZWF0ZUZpbHRlcmVkVGltZWxpbmVTZXQiLCJub1Jvb20iLCJwb3B1bGF0ZUZpbGVUaW1lbGluZSIsInNldFN0YXRlIiwiZXJyb3IiLCJjb25zb2xlIiwicmVuZGVyIiwiaXNHdWVzdCIsIm9uQ2xvc2UiLCJSaWdodFBhbmVsUGhhc2VzIiwiUm9vbVN1bW1hcnkiLCJzdWIiLCJUaW1lbGluZVBhbmVsIiwic2RrIiwiZ2V0Q29tcG9uZW50IiwiTG9hZGVyIiwiZW1wdHlTdGF0ZSIsIldhcm5pbmdLaW5kIiwiRmlsZXMiLCJvblBhZ2luYXRpb25SZXF1ZXN0IiwicmVzaXplTm90aWZpZXIiLCJQcm9wVHlwZXMiLCJzdHJpbmciLCJpc1JlcXVpcmVkIiwiZnVuYyJdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7OztBQWlCQTs7QUFDQTs7QUFFQTs7QUFDQTs7QUFDQTs7QUFDQTs7QUFDQTs7QUFDQTs7QUFDQTs7QUFDQTs7QUFDQTs7OztBQUVBO0FBQ0E7QUFDQTtJQUVNQSxTLFdBREwsZ0RBQXFCLHNCQUFyQixDLG1DQUFELE1BQ01BLFNBRE4sU0FDd0JDLGVBQU1DLFNBRDlCLENBQ3dDO0FBQUE7QUFBQTtBQUFBLDREQVFqQixJQUFJQyxHQUFKLEVBUmlCO0FBQUEsaURBVTVCO0FBQ0pDLE1BQUFBLFdBQVcsRUFBRTtBQURULEtBVjRCO0FBQUEsMERBY25CLENBQUNDLEVBQUQsRUFBS0MsSUFBTCxFQUFXQyxpQkFBWCxFQUE4QkMsT0FBOUIsRUFBdUNDLElBQXZDLEtBQWdEO0FBQzdELFVBQUlILElBQUksRUFBRUksTUFBTixLQUFpQixLQUFLQyxLQUFMLEVBQVlELE1BQWpDLEVBQXlDO0FBQ3pDLFVBQUlILGlCQUFpQixJQUFJLENBQUNFLElBQXRCLElBQThCLENBQUNBLElBQUksQ0FBQ0csU0FBcEMsSUFBaURQLEVBQUUsQ0FBQ1EsVUFBSCxFQUFyRCxFQUFzRTs7QUFFdEUsWUFBTUMsTUFBTSxHQUFHQyxpQ0FBZ0JDLEdBQWhCLEVBQWY7O0FBQ0FGLE1BQUFBLE1BQU0sQ0FBQ0csb0JBQVAsQ0FBNEJaLEVBQTVCOztBQUVB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QVVDLE1BQVYsQ0FBaUJDLFVBRFY7QUFFZmYsRUFBQUEsT0FBTyxFQUFFYSxtQkFBVUcsSUFBVixDQUFlRDtBQUZULEM7ZUEwT1JuRixTIiwic291cmNlc0NvbnRlbnQiOlsiLypcbkNvcHlyaWdodCAyMDE2IE9wZW5NYXJrZXQgTHRkXG5Db3B5cmlnaHQgMjAxOSBUaGUgTWF0cml4Lm9yZyBGb3VuZGF0aW9uIEMuSS5DLlxuXG5MaWNlbnNlZCB1bmRlciB0aGUgQXBhY2hlIExpY2Vuc2UsIFZlcnNpb24gMi4wICh0aGUgXCJMaWNlbnNlXCIpO1xueW91IG1heSBub3QgdXNlIHRoaXMgZmlsZSBleGNlcHQgaW4gY29tcGxpYW5jZSB3aXRoIHRoZSBMaWNlbnNlLlxuWW91IG1heSBvYnRhaW4gYSBjb3B5IG9mIHRoZSBMaWNlbnNlIGF0XG5cbiAgICBodHRwOi8vd3d3LmFwYWNoZS5vcmcvbGljZW5zZXMvTElDRU5TRS0yLjBcblxuVW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzb2Z0d2FyZVxuZGlzdHJpYnV0ZWQgdW5kZXIgdGhlIExpY2Vuc2UgaXMgZGlzdHJpYnV0ZWQgb24gYW4gXCJBUyBJU1wiIEJBU0lTLFxuV0lUSE9VVCBXQVJSQU5USUVTIE9SIENPTkRJVElPTlMgT0YgQU5ZIEtJTkQsIGVpdGhlciBleHByZXNzIG9yIGltcGxpZWQuXG5TZWUgdGhlIExpY2Vuc2UgZm9yIHRoZSBzcGVjaWZpYyBsYW5ndWFnZSBnb3Zlcm5pbmcgcGVybWlzc2lvbnMgYW5kXG5saW1pdGF0aW9ucyB1bmRlciB0aGUgTGljZW5zZS5cbiovXG5cbmltcG9ydCBSZWFjdCBmcm9tICdyZWFjdCc7XG5pbXBvcnQgUHJvcFR5cGVzIGZyb20gJ3Byb3AtdHlwZXMnO1xuXG5pbXBvcnQge0ZpbHRlcn0gZnJvbSAnbWF0cml4LWpzLXNkay9zcmMvZmlsdGVyJztcbmltcG9ydCAqIGFzIHNkayBmcm9tICcuLi8uLi9pbmRleCc7XG5pbXBvcnQge01hdHJpeENsaWVudFBlZ30gZnJvbSAnLi4vLi4vTWF0cml4Q2xpZW50UGVnJztcbmltcG9ydCBFdmVudEluZGV4UGVnIGZyb20gXCIuLi8uLi9pbmRleGluZy9FdmVudEluZGV4UGVnXCI7XG5pbXBvcnQgeyBfdCB9IGZyb20gJy4uLy4uL2xhbmd1YWdlSGFuZGxlcic7XG5pbXBvcnQgQmFzZUNhcmQgZnJvbSBcIi4uL3ZpZXdzL3JpZ2h0X3BhbmVsL0Jhc2VDYXJkXCI7XG5pbXBvcnQge1JpZ2h0UGFuZWxQaGFzZXN9IGZyb20gXCIuLi8uLi9zdG9yZXMvUmlnaHRQYW5lbFN0b3JlUGhhc2VzXCI7XG5pbXBvcnQgRGVza3RvcEJ1aWxkc05vdGljZSwge1dhcm5pbmdLaW5kfSBmcm9tIFwiLi4vdmlld3MvZWxlbWVudHMvRGVza3RvcEJ1aWxkc05vdGljZVwiO1xuaW1wb3J0IHtyZXBsYWNlYWJsZUNvbXBvbmVudH0gZnJvbSBcIi4uLy4uL3V0aWxzL3JlcGxhY2VhYmxlQ29tcG9uZW50XCI7XG5cbi8qXG4gKiBDb21wb25lbnQgd2hpY2ggc2hvd3MgdGhlIGZpbHRlcmVkIGZpbGUgdXNpbmcgYSBUaW1lbGluZVBhbmVsXG4gKi9cbkByZXBsYWNlYWJsZUNvbXBvbmVudChcInN0cnVjdHVyZXMuRmlsZVBhbmVsXCIpXG5jbGFzcyBGaWxlUGFuZWwgZXh0ZW5kcyBSZWFjdC5Db21wb25lbnQge1xuICAgIHN0YXRpYyBwcm9wVHlwZXMgPSB7XG4gICAgICAgIHJvb21JZDogUHJvcFR5cGVzLnN0cmluZy5pc1JlcXVpcmVkLFxuICAgICAgICBvbkNsb3NlOiBQcm9wVHlwZXMuZnVuYy5pc1JlcXVpcmVkLFxuICAgIH07XG5cbiAgICAvLyBUaGlzIGlzIHVzZWQgdG8gdHJhY2sgaWYgYSBkZWNyeXB0ZWQgZXZlbnQgd2FzIGEgbGl2ZSBldmVudCBhbmQgc2hvdWxkIGJlXG4gICAgLy8gYWRkZWQgdG8gdGhlIHRpbWVsaW5lLlxuICAgIGRlY3J5cHRpbmdFdmVudHMgPSBuZXcgU2V0KCk7XG5cbiAgICBzdGF0ZSA9IHtcbiAgICAgICAgdGltZWxpbmVTZXQ6IG51bGwsXG4gICAgfTtcblxuICAgIG9uUm9vbVRpbWVsaW5lID0gKGV2LCByb29tLCB0b1N0YXJ0T2ZUaW1lbGluZSwgcmVtb3ZlZCwgZGF0YSkgPT4ge1xuICAgICAgICBpZiAocm9vbT8ucm9vbUlkICE9PSB0aGlzLnByb3BzPy5yb29tSWQpIHJldHVybjtcbiAgICAgICAgaWYgKHRvU3RhcnRPZlRpbWVsaW5lIHx8ICFkYXRhIHx8ICFkYXRhLmxpdmVFdmVudCB8fCBldi5pc1JlZGFjdGVkKCkpIHJldHVybjtcblxuICAgICAgICBjb25zdCBjbGllbnQgPSBNYXRyaXhDbGllbnRQZWcuZ2V0KCk7XG4gICAgICAgIGNsaWVudC5kZWNyeXB0RXZlbnRJZk5lZWRlZChldik7XG5cbiAgICAgICAgaWYgKGV2LmlzQmVpbmdEZWNyeXB0ZWQoKSkge1xuICAgICAgICAgICAgdGhpcy5kZWNyeXB0aW5nRXZlbnRzLmFkZChldi5nZXRJZCgpKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHRoaXMuYWRkRW5jcnlwdGVkTGl2ZUV2ZW50KGV2KTtcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICBvbkV2ZW50RGVjcnlwdGVkID0gKGV2LCBlcnIpID0+IHtcbiAgICAgICAgaWYgKGV2LmdldFJvb21JZCgpICE9PSB0aGlzLnByb3BzLnJvb21JZCkgcmV0dXJuO1xuICAgICAgICBjb25zdCBldmVudElkID0gZXYuZ2V0SWQoKTtcblxuICAgICAgICBpZiAoIXRoaXMuZGVjcnlwdGluZ0V2ZW50cy5kZWxldGUoZXZlbnRJZCkpIHJldHVybjtcbiAgICAgICAgaWYgKGVycikgcmV0dXJuO1xuXG4gICAgICAgIHRoaXMuYWRkRW5jcnlwdGVkTGl2ZUV2ZW50KGV2KTtcbiAgICB9O1xuXG4gICAgYWRkRW5jcnlwdGVkTGl2ZUV2ZW50KGV2LCB0b1N0YXJ0T2ZUaW1lbGluZSkge1xuICAgICAgICBpZiAoIXRoaXMuc3RhdGUudGltZWxpbmVTZXQpIHJldHVybjtcblxuICAgICAgICBjb25zdCB0aW1lbGluZSA9IHRoaXMuc3RhdGUudGltZWxpbmVTZXQuZ2V0TGl2ZVRpbWVsaW5lKCk7XG4gICAgICAgIGlmIChldi5nZXRUeXBlKCkgIT09IFwibS5yb29tLm1lc3NhZ2VcIikgcmV0dXJuO1xuICAgICAgICBpZiAoW1wibS5maWxlXCIsIFwibS5pbWFnZVwiLCBcIm0udmlkZW9cIiwgXCJtLmF1ZGlvXCJdLmluZGV4T2YoZXYuZ2V0Q29udGVudCgpLm1zZ3R5cGUpID09IC0xKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoIXRoaXMuc3RhdGUudGltZWxpbmVTZXQuZXZlbnRJZFRvVGltZWxpbmUoZXYuZ2V0SWQoKSkpIHtcbiAgICAgICAgICAgIHRoaXMuc3RhdGUudGltZWxpbmVTZXQuYWRkRXZlbnRUb1RpbWVsaW5lKGV2LCB0aW1lbGluZSwgZmFsc2UpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgYXN5bmMgY29tcG9uZW50RGlkTW91bnQoKSB7XG4gICAgICAgIGNvbnN0IGNsaWVudCA9IE1hdHJpeENsaWVudFBlZy5nZXQoKTtcblxuICAgICAgICBhd2FpdCB0aGlzLnVwZGF0ZVRpbWVsaW5lU2V0KHRoaXMucHJvcHMucm9vbUlkKTtcblxuICAgICAgICBpZiAoIU1hdHJpeENsaWVudFBlZy5nZXQoKS5pc1Jvb21FbmNyeXB0ZWQodGhpcy5wcm9wcy5yb29tSWQpKSByZXR1cm47XG5cbiAgICAgICAgLy8gVGhlIHRpbWVsaW5lU2V0cyBmaWx0ZXIgbWFrZXMgc3VyZSB0aGF0IGVuY3J5cHRlZCBldmVudHMgdGhhdCBjb250YWluXG4gICAgICAgIC8vIFVSTHMgbmV2ZXIgZ2V0IGFkZGVkIHRvIHRoZSB0aW1lbGluZSwgZXZlbiBpZiB0aGV5IGFyZSBsaXZlIGV2ZW50cy5cbiAgICAgICAgLy8gVGhlc2UgbWV0aG9kcyBhcmUgaGVyZSB0byBtYW51YWxseSBsaXN0ZW4gZm9yIHN1Y2ggZXZlbnRzIGFuZCBhZGRcbiAgICAgICAgLy8gdGhlbSBkZXNwaXRlIHRoZSBmaWx0ZXIncyBiZXN0IGVmZm9ydHMuXG4gICAgICAgIC8vXG4gICAgICAgIC8vIFdlIGRvIHRoaXMgb25seSBmb3IgZW5jcnlwdGVkIHJvb21zIGFuZCBpZiBhbiBldmVudCBpbmRleCBleGlzdHMsXG4gICAgICAgIC8vIHRoaXMgY291bGQgYmUgbWFkZSBtb3JlIGdlbmVyYWwgaW4gdGhlIGZ1dHVyZSBvciB0aGUgZmlsdGVyIGxvZ2ljXG4gICAgICAgIC8vIGNvdWxkIGJlIGZpeGVkLlxuICAgICAgICBpZiAoRXZlbnRJbmRleFBlZy5nZXQoKSAhPT0gbnVsbCkge1xuICAgICAgICAgICAgY2xpZW50Lm9uKCdSb29tLnRpbWVsaW5lJywgdGhpcy5vblJvb21UaW1lbGluZSk7XG4gICAgICAgICAgICBjbGllbnQub24oJ0V2ZW50LmRlY3J5cHRlZCcsIHRoaXMub25FdmVudERlY3J5cHRlZCk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBjb21wb25lbnRXaWxsVW5tb3VudCgpIHtcbiAgICAgICAgY29uc3QgY2xpZW50ID0gTWF0cml4Q2xpZW50UGVnLmdldCgpO1xuICAgICAgICBpZiAoY2xpZW50ID09PSBudWxsKSByZXR1cm47XG5cbiAgICAgICAgaWYgKCFNYXRyaXhDbGllbnRQZWcuZ2V0KCkuaXNSb29tRW5jcnlwdGVkKHRoaXMucHJvcHMucm9vbUlkKSkgcmV0dXJuO1xuXG4gICAgICAgIGlmIChFdmVudEluZGV4UGVnLmdldCgpICE9PSBudWxsKSB7XG4gICAgICAgICAgICBjbGllbnQucmVtb3ZlTGlzdGVuZXIoJ1Jvb20udGltZWxpbmUnLCB0aGlzLm9uUm9vbVRpbWVsaW5lKTtcbiAgICAgICAgICAgIGNsaWVudC5yZW1vdmVMaXN0ZW5lcignRXZlbnQuZGVjcnlwdGVkJywgdGhpcy5vbkV2ZW50RGVjcnlwdGVkKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIGFzeW5jIGZldGNoRmlsZUV2ZW50c1NlcnZlcihyb29tKSB7XG4gICAgICAgIGNvbnN0IGNsaWVudCA9IE1hdHJpeENsaWVudFBlZy5nZXQoKTtcblxuICAgICAgICBjb25zdCBmaWx0ZXIgPSBuZXcgRmlsdGVyKGNsaWVudC5jcmVkZW50aWFscy51c2VySWQpO1xuICAgICAgICBmaWx0ZXIuc2V0RGVmaW5pdGlvbihcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICBcInJvb21cIjoge1xuICAgICAgICAgICAgICAgICAgICBcInRpbWVsaW5lXCI6IHtcbiAgICAgICAgICAgICAgICAgICAgICAgIFwiY29udGFpbnNfdXJsXCI6IHRydWUsXG4gICAgICAgICAgICAgICAgICAgICAgICBcInR5cGVzXCI6IFtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBcIm0ucm9vbS5tZXNzYWdlXCIsXG4gICAgICAgICAgICAgICAgICAgICAgICBdLFxuICAgICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB9LFxuICAgICAgICApO1xuXG4gICAgICAgIGNvbnN0IGZpbHRlcklkID0gYXdhaXQgY2xpZW50LmdldE9yQ3JlYXRlRmlsdGVyKFwiRklMVEVSX0ZJTEVTX1wiICsgY2xpZW50LmNyZWRlbnRpYWxzLnVzZXJJZCwgZmlsdGVyKTtcbiAgICAgICAgZmlsdGVyLmZpbHRlcklkID0gZmlsdGVySWQ7XG4gICAgICAgIGNvbnN0IHRpbWVsaW5lU2V0ID0gcm9vbS5nZXRPckNyZWF0ZUZpbHRlcmVkVGltZWxpbmVTZXQoZmlsdGVyKTtcblxuICAgICAgICByZXR1cm4gdGltZWxpbmVTZXQ7XG4gICAgfVxuXG4gICAgb25QYWdpbmF0aW9uUmVxdWVzdCA9ICh0aW1lbGluZVdpbmRvdywgZGlyZWN0aW9uLCBsaW1pdCkgPT4ge1xuICAgICAgICBjb25zdCBjbGllbnQgPSBNYXRyaXhDbGllbnRQZWcuZ2V0KCk7XG4gICAgICAgIGNvbnN0IGV2ZW50SW5kZXggPSBFdmVudEluZGV4UGVnLmdldCgpO1xuICAgICAgICBjb25zdCByb29tSWQgPSB0aGlzLnByb3BzLnJvb21JZDtcblxuICAgICAgICBjb25zdCByb29tID0gY2xpZW50LmdldFJvb20ocm9vbUlkKTtcblxuICAgICAgICAvLyBXZSBvdmVycmlkZSB0aGUgcGFnaW5hdGlvbiByZXF1ZXN0IGZvciBlbmNyeXB0ZWQgcm9vbXMgc28gdGhhdCB3ZSBhc2tcbiAgICAgICAgLy8gdGhlIGV2ZW50IGluZGV4IHRvIGZ1bGZpbGwgdGhlIHBhZ2luYXRpb24gcmVxdWVzdC4gQXNraW5nIHRoZSBzZXJ2ZXJcbiAgICAgICAgLy8gdG8gcGFnaW5hdGUgd29uJ3QgZXZlciB3b3JrIHNpbmNlIHRoZSBzZXJ2ZXIgY2FuJ3QgY29ycmVjdGx5IGZpbHRlclxuICAgICAgICAvLyBvdXQgZXZlbnRzIGNvbnRhaW5pbmcgVVJMc1xuICAgICAgICBpZiAoY2xpZW50LmlzUm9vbUVuY3J5cHRlZChyb29tSWQpICYmIGV2ZW50SW5kZXggIT09IG51bGwpIHtcbiAgICAgICAgICAgIHJldHVybiBldmVudEluZGV4LnBhZ2luYXRlVGltZWxpbmVXaW5kb3cocm9vbSwgdGltZWxpbmVXaW5kb3csIGRpcmVjdGlvbiwgbGltaXQpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgcmV0dXJuIHRpbWVsaW5lV2luZG93LnBhZ2luYXRlKGRpcmVjdGlvbiwgbGltaXQpO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgIGFzeW5jIHVwZGF0ZVRpbWVsaW5lU2V0KHJvb21JZDogc3RyaW5nKSB7XG4gICAgICAgIGNvbnN0IGNsaWVudCA9IE1hdHJpeENsaWVudFBlZy5nZXQoKTtcbiAgICAgICAgY29uc3Qgcm9vbSA9IGNsaWVudC5nZXRSb29tKHJvb21JZCk7XG4gICAgICAgIGNvbnN0IGV2ZW50SW5kZXggPSBFdmVudEluZGV4UGVnLmdldCgpO1xuXG4gICAgICAgIHRoaXMubm9Sb29tID0gIXJvb207XG5cbiAgICAgICAgaWYgKHJvb20pIHtcbiAgICAgICAgICAgIGxldCB0aW1lbGluZVNldDtcblxuICAgICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgICAgICB0aW1lbGluZVNldCA9IGF3YWl0IHRoaXMuZmV0Y2hGaWxlRXZlbnRzU2VydmVyKHJvb20pO1xuXG4gICAgICAgICAgICAgICAgLy8gSWYgdGhpcyByb29tIGlzIGVuY3J5cHRlZCB0aGUgZmlsZSBwYW5lbCB3b24ndCBiZSBwb3B1bGF0ZWRcbiAgICAgICAgICAgICAgICAvLyBjb3JyZWN0bHkgc2luY2UgdGhlIGRlZmluZWQgZmlsdGVyIGRvZXNuJ3Qgc3VwcG9ydCBlbmNyeXB0ZWRcbiAgICAgICAgICAgICAgICAvLyBldmVudHMgYW5kIHRoZSBzZXJ2ZXIgY2FuJ3QgY2hlY2sgaWYgZW5jcnlwdGVkIGV2ZW50cyBjb250YWluXG4gICAgICAgICAgICAgICAgLy8gVVJMcy5cbiAgICAgICAgICAgICAgICAvL1xuICAgICAgICAgICAgICAgIC8vIFRoaXMgaXMgd2hlcmUgb3VyIGV2ZW50IGluZGV4IGNvbWVzIGludG8gcGxhY2UsIHdlIGFzayB0aGVcbiAgICAgICAgICAgICAgICAvLyBldmVudCBpbmRleCB0byBwb3B1bGF0ZSB0aGUgdGltZWxpbmVTZXQgZm9yIHVzLiBUaGlzIGNhbGxcbiAgICAgICAgICAgICAgICAvLyB3aWxsIGFkZCAxMCBldmVudHMgdG8gdGhlIGxpdmUgdGltZWxpbmUgb2YgdGhlIHNldC4gTW9yZSBjYW5cbiAgICAgICAgICAgICAgICAvLyBiZSByZXF1ZXN0ZWQgdXNpbmcgcGFnaW5hdGlvbi5cbiAgICAgICAgICAgICAgICBpZiAoY2xpZW50LmlzUm9vbUVuY3J5cHRlZChyb29tSWQpICYmIGV2ZW50SW5kZXggIT09IG51bGwpIHtcbiAgICAgICAgICAgICAgICAgICAgY29uc3QgdGltZWxpbmUgPSB0aW1lbGluZVNldC5nZXRMaXZlVGltZWxpbmUoKTtcbiAgICAgICAgICAgICAgICAgICAgYXdhaXQgZXZlbnRJbmRleC5wb3B1bGF0ZUZpbGVUaW1lbGluZSh0aW1lbGluZVNldCwgdGltZWxpbmUsIHJvb20sIDEwKTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICB0aGlzLnNldFN0YXRlKHsgdGltZWxpbmVTZXQ6IHRpbWVsaW5lU2V0IH0pO1xuICAgICAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgICAgICAgICBjb25zb2xlLmVycm9yKFwiRmFpbGVkIHRvIGdldCBvciBjcmVhdGUgZmlsZSBwYW5lbCBmaWx0ZXJcIiwgZXJyb3IpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgY29uc29sZS5lcnJvcihcIkZhaWxlZCB0byBhZGQgZmlsdGVyZWQgdGltZWxpbmVTZXQgZm9yIEZpbGVQYW5lbCBhcyBubyByb29tIVwiKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHJlbmRlcigpIHtcbiAgICAgICAgaWYgKE1hdHJpeENsaWVudFBlZy5nZXQoKS5pc0d1ZXN0KCkpIHtcbiAgICAgICAgICAgIHJldHVybiA8QmFzZUNhcmRcbiAgICAgICAgICAgICAgICBjbGFzc05hbWU9XCJteF9GaWxlUGFuZWwgbXhfUm9vbVZpZXdfbWVzc2FnZUxpc3RXcmFwcGVyXCJcbiAgICAgICAgICAgICAgICBvbkNsb3NlPXt0aGlzLnByb3BzLm9uQ2xvc2V9XG4gICAgICAgICAgICAgICAgcHJldmlvdXNQaGFzZT17UmlnaHRQYW5lbFBoYXNlcy5Sb29tU3VtbWFyeX1cbiAgICAgICAgICAgID5cbiAgICAgICAgICAgICAgICA8ZGl2IGNsYXNzTmFtZT1cIm14X1Jvb21WaWV3X2VtcHR5XCI+XG4gICAgICAgICAgICAgICAgICAgIHsgX3QoXCJZb3UgbXVzdCA8YT5yZWdpc3RlcjwvYT4gdG8gdXNlIHRoaXMgZnVuY3Rpb25hbGl0eVwiLFxuICAgICAgICAgICAgICAgICAgICAgICAge30sXG4gICAgICAgICAgICAgICAgICAgICAgICB7ICdhJzogKHN1YikgPT4gPGEgaHJlZj1cIiMvcmVnaXN0ZXJcIiBrZXk9XCJzdWJcIj57IHN1YiB9PC9hPiB9KVxuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgICA8L0Jhc2VDYXJkPjtcbiAgICAgICAgfSBlbHNlIGlmICh0aGlzLm5vUm9vbSkge1xuICAgICAgICAgICAgcmV0dXJuIDxCYXNlQ2FyZFxuICAgICAgICAgICAgICAgIGNsYXNzTmFtZT1cIm14X0ZpbGVQYW5lbCBteF9Sb29tVmlld19tZXNzYWdlTGlzdFdyYXBwZXJcIlxuICAgICAgICAgICAgICAgIG9uQ2xvc2U9e3RoaXMucHJvcHMub25DbG9zZX1cbiAgICAgICAgICAgICAgICBwcmV2aW91c1BoYXNlPXtSaWdodFBhbmVsUGhhc2VzLlJvb21TdW1tYXJ5fVxuICAgICAgICAgICAgPlxuICAgICAgICAgICAgICAgIDxkaXYgY2xhc3NOYW1lPVwibXhfUm9vbVZpZXdfZW1wdHlcIj57IF90KFwiWW91IG11c3Qgam9pbiB0aGUgcm9vbSB0byBzZWUgaXRzIGZpbGVzXCIpIH08L2Rpdj5cbiAgICAgICAgICAgIDwvQmFzZUNhcmQ+O1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gd3JhcCBhIFRpbWVsaW5lUGFuZWwgd2l0aCB0aGUganVtcC10by1ldmVudCBiaXRzIHR1cm5lZCBvZmYuXG4gICAgICAgIGNvbnN0IFRpbWVsaW5lUGFuZWwgPSBzZGsuZ2V0Q29tcG9uZW50KFwic3RydWN0dXJlcy5UaW1lbGluZVBhbmVsXCIpO1xuICAgICAgICBjb25zdCBMb2FkZXIgPSBzZGsuZ2V0Q29tcG9uZW50KFwiZWxlbWVudHMuU3Bpbm5lclwiKTtcblxuICAgICAgICBjb25zdCBlbXB0eVN0YXRlID0gKDxkaXYgY2xhc3NOYW1lPVwibXhfUmlnaHRQYW5lbF9lbXB0eSBteF9GaWxlUGFuZWxfZW1wdHlcIj5cbiAgICAgICAgICAgIDxoMj57X3QoJ05vIGZpbGVzIHZpc2libGUgaW4gdGhpcyByb29tJyl9PC9oMj5cbiAgICAgICAgICAgIDxwPntfdCgnQXR0YWNoIGZpbGVzIGZyb20gY2hhdCBvciBqdXN0IGRyYWcgYW5kIGRyb3AgdGhlbSBhbnl3aGVyZSBpbiBhIHJvb20uJyl9PC9wPlxuICAgICAgICA8L2Rpdj4pO1xuXG4gICAgICAgIGNvbnN0IGlzUm9vbUVuY3J5cHRlZCA9IHRoaXMubm9Sb29tID8gZmFsc2UgOiBNYXRyaXhDbGllbnRQZWcuZ2V0KCkuaXNSb29tRW5jcnlwdGVkKHRoaXMucHJvcHMucm9vbUlkKTtcblxuICAgICAgICBpZiAodGhpcy5zdGF0ZS50aW1lbGluZVNldCkge1xuICAgICAgICAgICAgLy8gY29uc29sZS5sb2coXCJyZW5kZXJpbmcgVGltZWxpbmVQYW5lbCBmb3IgdGltZWxpbmVTZXQgXCIgKyB0aGlzLnN0YXRlLnRpbWVsaW5lU2V0LnJvb20ucm9vbUlkICsgXCIgXCIgK1xuICAgICAgICAgICAgLy8gICAgICAgICAgICAgXCIoXCIgKyB0aGlzLnN0YXRlLnRpbWVsaW5lU2V0Ll90aW1lbGluZXMuam9pbihcIiwgXCIpICsgXCIpXCIgKyBcIiB3aXRoIGtleSBcIiArIHRoaXMucHJvcHMucm9vbUlkKTtcbiAgICAgICAgICAgIHJldHVybiAoXG4gICAgICAgICAgICAgICAgPEJhc2VDYXJkXG4gICAgICAgICAgICAgICAgICAgIGNsYXNzTmFtZT1cIm14X0ZpbGVQYW5lbFwiXG4gICAgICAgICAgICAgICAgICAgIG9uQ2xvc2U9e3RoaXMucHJvcHMub25DbG9zZX1cbiAgICAgICAgICAgICAgICAgICAgcHJldmlvdXNQaGFzZT17UmlnaHRQYW5lbFBoYXNlcy5Sb29tU3VtbWFyeX1cbiAgICAgICAgICAgICAgICAgICAgd2l0aG91dFNjcm9sbENvbnRhaW5lclxuICAgICAgICAgICAgICAgID5cbiAgICAgICAgICAgICAgICAgICAgPERlc2t0b3BCdWlsZHNOb3RpY2UgaXNSb29tRW5jcnlwdGVkPXtpc1Jvb21FbmNyeXB0ZWR9IGtpbmQ9e1dhcm5pbmdLaW5kLkZpbGVzfSAvPlxuICAgICAgICAgICAgICAgICAgICA8VGltZWxpbmVQYW5lbFxuICAgICAgICAgICAgICAgICAgICAgICAgbWFuYWdlUmVhZFJlY2VpcHRzPXtmYWxzZX1cbiAgICAgICAgICAgICAgICAgICAgICAgIG1hbmFnZVJlYWRNYXJrZXJzPXtmYWxzZX1cbiAgICAgICAgICAgICAgICAgICAgICAgIHRpbWVsaW5lU2V0PXt0aGlzLnN0YXRlLnRpbWVsaW5lU2V0fVxuICAgICAgICAgICAgICAgICAgICAgICAgc2hvd1VybFByZXZpZXcgPSB7ZmFsc2V9XG4gICAgICAgICAgICAgICAgICAgICAgICBvblBhZ2luYXRpb25SZXF1ZXN0PXt0aGlzLm9uUGFnaW5hdGlvblJlcXVlc3R9XG4gICAgICAgICAgICAgICAgICAgICAgICB0aWxlU2hhcGU9XCJmaWxlX2dyaWRcIlxuICAgICAgICAgICAgICAgICAgICAgICAgcmVzaXplTm90aWZpZXI9e3RoaXMucHJvcHMucmVzaXplTm90aWZpZXJ9XG4gICAgICAgICAgICAgICAgICAgICAgICBlbXB0eT17ZW1wdHlTdGF0ZX1cbiAgICAgICAgICAgICAgICAgICAgLz5cbiAgICAgICAgICAgICAgICA8L0Jhc2VDYXJkPlxuICAgICAgICAgICAgKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHJldHVybiAoXG4gICAgICAgICAgICAgICAgPEJhc2VDYXJkXG4gICAgICAgICAgICAgICAgICAgIGNsYXNzTmFtZT1cIm14X0ZpbGVQYW5lbFwiXG4gICAgICAgICAgICAgICAgICAgIG9uQ2xvc2U9e3RoaXMucHJvcHMub25DbG9zZX1cbiAgICAgICAgICAgICAgICAgICAgcHJldmlvdXNQaGFzZT17UmlnaHRQYW5lbFBoYXNlcy5Sb29tU3VtbWFyeX1cbiAgICAgICAgICAgICAgICA+XG4gICAgICAgICAgICAgICAgICAgIDxMb2FkZXIgLz5cbiAgICAgICAgICAgICAgICA8L0Jhc2VDYXJkPlxuICAgICAgICAgICAgKTtcbiAgICAgICAgfVxuICAgIH1cbn1cblxuZXhwb3J0IGRlZmF1bHQgRmlsZVBhbmVsO1xuIl19