matrix-react-sdk
Version:
SDK for matrix.org using React
437 lines (353 loc) • 58.5 kB
JavaScript
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
var _interopRequireWildcard3 = require("@babel/runtime/helpers/interopRequireWildcard");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = exports.IgnoredUser = void 0;
var _interopRequireWildcard2 = _interopRequireDefault(require("@babel/runtime/helpers/interopRequireWildcard"));
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
var _react = _interopRequireDefault(require("react"));
var _propTypes = _interopRequireDefault(require("prop-types"));
var _languageHandler = require("../../../../../languageHandler");
var _SdkConfig = _interopRequireDefault(require("../../../../../SdkConfig"));
var _MatrixClientPeg = require("../../../../../MatrixClientPeg");
var FormattingUtils = _interopRequireWildcard3(require("../../../../../utils/FormattingUtils"));
var _AccessibleButton = _interopRequireDefault(require("../../../elements/AccessibleButton"));
var _Analytics = _interopRequireDefault(require("../../../../../Analytics"));
var _Modal = _interopRequireDefault(require("../../../../../Modal"));
var sdk = _interopRequireWildcard3(require("../../../../.."));
var _promise = require("../../../../../utils/promise");
var _dispatcher = _interopRequireDefault(require("../../../../../dispatcher/dispatcher"));
var _createRoom = require("../../../../../createRoom");
var _SettingLevel = require("../../../../../settings/SettingLevel");
var _SecureBackupPanel = _interopRequireDefault(require("../../SecureBackupPanel"));
var _SettingsStore = _interopRequireDefault(require("../../../../../settings/SettingsStore"));
var _UIFeature = require("../../../../../settings/UIFeature");
var _E2eAdvancedPanel = require("../../E2eAdvancedPanel");
var _CountlyAnalytics = _interopRequireDefault(require("../../../../../CountlyAnalytics"));
var _replaceableComponent = require("../../../../../utils/replaceableComponent");
var _dec, _class, _class2, _temp;
class IgnoredUser extends _react.default.Component {
constructor(...args) {
super(...args);
(0, _defineProperty2.default)(this, "_onUnignoreClicked", e => {
this.props.onUnignored(this.props.userId);
});
}
render() {
const id = `mx_SecurityUserSettingsTab_ignoredUser_${this.props.userId}`;
return /*#__PURE__*/_react.default.createElement("div", {
className: "mx_SecurityUserSettingsTab_ignoredUser"
}, /*#__PURE__*/_react.default.createElement(_AccessibleButton.default, {
onClick: this._onUnignoreClicked,
kind: "primary_sm",
"aria-describedby": id,
disabled: this.props.inProgress
}, (0, _languageHandler._t)('Unignore')), /*#__PURE__*/_react.default.createElement("span", {
id: id
}, this.props.userId));
}
}
exports.IgnoredUser = IgnoredUser;
(0, _defineProperty2.default)(IgnoredUser, "propTypes", {
userId: _propTypes.default.string.isRequired,
onUnignored: _propTypes.default.func.isRequired,
inProgress: _propTypes.default.bool.isRequired
});
let SecurityUserSettingsTab = (_dec = (0, _replaceableComponent.replaceableComponent)("views.settings.tabs.user.SecurityUserSettingsTab"), _dec(_class = (_temp = _class2 = class SecurityUserSettingsTab extends _react.default.Component {
constructor() {
super(); // Get number of rooms we're invited to
(0, _defineProperty2.default)(this, "_updateBlacklistDevicesFlag", checked => {
_MatrixClientPeg.MatrixClientPeg.get().setGlobalBlacklistUnverifiedDevices(checked);
});
(0, _defineProperty2.default)(this, "_updateAnalytics", checked => {
checked ? _Analytics.default.enable() : _Analytics.default.disable();
_CountlyAnalytics.default.instance.enable(
/* anonymous = */
!checked);
});
(0, _defineProperty2.default)(this, "_onExportE2eKeysClicked", () => {
_Modal.default.createTrackedDialogAsync('Export E2E Keys', '', Promise.resolve().then(() => (0, _interopRequireWildcard2.default)(require('../../../../../async-components/views/dialogs/security/ExportE2eKeysDialog'))), {
matrixClient: _MatrixClientPeg.MatrixClientPeg.get()
});
});
(0, _defineProperty2.default)(this, "_onImportE2eKeysClicked", () => {
_Modal.default.createTrackedDialogAsync('Import E2E Keys', '', Promise.resolve().then(() => (0, _interopRequireWildcard2.default)(require('../../../../../async-components/views/dialogs/security/ImportE2eKeysDialog'))), {
matrixClient: _MatrixClientPeg.MatrixClientPeg.get()
});
});
(0, _defineProperty2.default)(this, "_onGoToUserProfileClick", () => {
_dispatcher.default.dispatch({
action: 'view_user_info',
userId: _MatrixClientPeg.MatrixClientPeg.get().getUserId()
});
this.props.closeSettingsFn();
});
(0, _defineProperty2.default)(this, "_onUserUnignored", async userId => {
const {
ignoredUserIds,
waitingUnignored
} = this.state;
const currentlyIgnoredUserIds = ignoredUserIds.filter(e => !waitingUnignored.includes(e));
const index = currentlyIgnoredUserIds.indexOf(userId);
if (index !== -1) {
currentlyIgnoredUserIds.splice(index, 1);
this.setState(({
waitingUnignored
}) => ({
waitingUnignored: [...waitingUnignored, userId]
}));
_MatrixClientPeg.MatrixClientPeg.get().setIgnoredUsers(currentlyIgnoredUserIds);
}
});
(0, _defineProperty2.default)(this, "_getInvitedRooms", () => {
return _MatrixClientPeg.MatrixClientPeg.get().getRooms().filter(r => {
return r.hasMembershipState(_MatrixClientPeg.MatrixClientPeg.get().getUserId(), "invite");
});
});
(0, _defineProperty2.default)(this, "_manageInvites", async accept => {
this.setState({
managingInvites: true
}); // Compile array of invitation room ids
const invitedRoomIds = this._getInvitedRooms().map(room => {
return room.roomId;
}); // Execute all acceptances/rejections sequentially
const self = this;
const cli = _MatrixClientPeg.MatrixClientPeg.get();
const action = accept ? cli.joinRoom.bind(cli) : cli.leave.bind(cli);
for (let i = 0; i < invitedRoomIds.length; i++) {
const roomId = invitedRoomIds[i]; // Accept/reject invite
await action(roomId).then(() => {
// No error, update invited rooms button
this.setState({
invitedRoomAmt: self.state.invitedRoomAmt - 1
});
}, async e => {
// Action failure
if (e.errcode === "M_LIMIT_EXCEEDED") {
// Add a delay between each invite change in order to avoid rate
// limiting by the server.
await (0, _promise.sleep)(e.retry_after_ms || 2500); // Redo last action
i--;
} else {
// Print out error with joining/leaving room
console.warn(e);
}
});
}
this.setState({
managingInvites: false
});
});
(0, _defineProperty2.default)(this, "_onAcceptAllInvitesClicked", ev => {
this._manageInvites(true);
});
(0, _defineProperty2.default)(this, "_onRejectAllInvitesClicked", ev => {
this._manageInvites(false);
});
const invitedRooms = this._getInvitedRooms();
this.state = {
ignoredUserIds: _MatrixClientPeg.MatrixClientPeg.get().getIgnoredUsers(),
waitingUnignored: [],
managingInvites: false,
invitedRoomAmt: invitedRooms.length
};
this._onAction = this._onAction.bind(this);
}
_onAction({
action
}) {
if (action === "ignore_state_changed") {
const ignoredUserIds = _MatrixClientPeg.MatrixClientPeg.get().getIgnoredUsers();
const newWaitingUnignored = this.state.waitingUnignored.filter(e => ignoredUserIds.includes(e));
this.setState({
ignoredUserIds,
waitingUnignored: newWaitingUnignored
});
}
}
componentDidMount() {
this.dispatcherRef = _dispatcher.default.register(this._onAction);
}
componentWillUnmount() {
_dispatcher.default.unregister(this.dispatcherRef);
}
_renderCurrentDeviceInfo() {
const SettingsFlag = sdk.getComponent('views.elements.SettingsFlag');
const client = _MatrixClientPeg.MatrixClientPeg.get();
const deviceId = client.deviceId;
let identityKey = client.getDeviceEd25519Key();
if (!identityKey) {
identityKey = (0, _languageHandler._t)("<not supported>");
} else {
identityKey = FormattingUtils.formatCryptoKey(identityKey);
}
let importExportButtons = null;
if (client.isCryptoEnabled()) {
importExportButtons = /*#__PURE__*/_react.default.createElement("div", {
className: "mx_SecurityUserSettingsTab_importExportButtons"
}, /*#__PURE__*/_react.default.createElement(_AccessibleButton.default, {
kind: "primary",
onClick: this._onExportE2eKeysClicked
}, (0, _languageHandler._t)("Export E2E room keys")), /*#__PURE__*/_react.default.createElement(_AccessibleButton.default, {
kind: "primary",
onClick: this._onImportE2eKeysClicked
}, (0, _languageHandler._t)("Import E2E room keys")));
}
let noSendUnverifiedSetting;
if (_SettingsStore.default.isEnabled("blacklistUnverifiedDevices")) {
noSendUnverifiedSetting = /*#__PURE__*/_react.default.createElement(SettingsFlag, {
name: "blacklistUnverifiedDevices",
level: _SettingLevel.SettingLevel.DEVICE,
onChange: this._updateBlacklistDevicesFlag
});
}
return /*#__PURE__*/_react.default.createElement("div", {
className: "mx_SettingsTab_section"
}, /*#__PURE__*/_react.default.createElement("span", {
className: "mx_SettingsTab_subheading"
}, (0, _languageHandler._t)("Cryptography")), /*#__PURE__*/_react.default.createElement("ul", {
className: "mx_SettingsTab_subsectionText mx_SecurityUserSettingsTab_deviceInfo"
}, /*#__PURE__*/_react.default.createElement("li", null, /*#__PURE__*/_react.default.createElement("label", null, (0, _languageHandler._t)("Session ID:")), /*#__PURE__*/_react.default.createElement("span", null, /*#__PURE__*/_react.default.createElement("code", null, deviceId))), /*#__PURE__*/_react.default.createElement("li", null, /*#__PURE__*/_react.default.createElement("label", null, (0, _languageHandler._t)("Session key:")), /*#__PURE__*/_react.default.createElement("span", null, /*#__PURE__*/_react.default.createElement("code", null, /*#__PURE__*/_react.default.createElement("b", null, identityKey))))), importExportButtons, noSendUnverifiedSetting);
}
_renderIgnoredUsers() {
const {
waitingUnignored,
ignoredUserIds
} = this.state;
const userIds = !ignoredUserIds?.length ? (0, _languageHandler._t)('You have no ignored users.') : ignoredUserIds.map(u => {
return /*#__PURE__*/_react.default.createElement(IgnoredUser, {
userId: u,
onUnignored: this._onUserUnignored,
key: u,
inProgress: waitingUnignored.includes(u)
});
});
return /*#__PURE__*/_react.default.createElement("div", {
className: "mx_SettingsTab_section"
}, /*#__PURE__*/_react.default.createElement("span", {
className: "mx_SettingsTab_subheading"
}, (0, _languageHandler._t)('Ignored users')), /*#__PURE__*/_react.default.createElement("div", {
className: "mx_SettingsTab_subsectionText"
}, userIds));
}
_renderManageInvites() {
if (this.state.invitedRoomAmt === 0) {
return null;
}
const invitedRooms = this._getInvitedRooms();
const InlineSpinner = sdk.getComponent('elements.InlineSpinner');
const onClickAccept = this._onAcceptAllInvitesClicked.bind(this, invitedRooms);
const onClickReject = this._onRejectAllInvitesClicked.bind(this, invitedRooms);
return /*#__PURE__*/_react.default.createElement("div", {
className: "mx_SettingsTab_section mx_SecurityUserSettingsTab_bulkOptions"
}, /*#__PURE__*/_react.default.createElement("span", {
className: "mx_SettingsTab_subheading"
}, (0, _languageHandler._t)('Bulk options')), /*#__PURE__*/_react.default.createElement(_AccessibleButton.default, {
onClick: onClickAccept,
kind: "primary",
disabled: this.state.managingInvites
}, (0, _languageHandler._t)("Accept all %(invitedRooms)s invites", {
invitedRooms: this.state.invitedRoomAmt
})), /*#__PURE__*/_react.default.createElement(_AccessibleButton.default, {
onClick: onClickReject,
kind: "danger",
disabled: this.state.managingInvites
}, (0, _languageHandler._t)("Reject all %(invitedRooms)s invites", {
invitedRooms: this.state.invitedRoomAmt
})), this.state.managingInvites ? /*#__PURE__*/_react.default.createElement(InlineSpinner, null) : /*#__PURE__*/_react.default.createElement("div", null));
}
render() {
const brand = _SdkConfig.default.get().brand;
const DevicesPanel = sdk.getComponent('views.settings.DevicesPanel');
const SettingsFlag = sdk.getComponent('views.elements.SettingsFlag');
const EventIndexPanel = sdk.getComponent('views.settings.EventIndexPanel');
const secureBackup = /*#__PURE__*/_react.default.createElement("div", {
className: "mx_SettingsTab_section"
}, /*#__PURE__*/_react.default.createElement("span", {
className: "mx_SettingsTab_subheading"
}, (0, _languageHandler._t)("Secure Backup")), /*#__PURE__*/_react.default.createElement("div", {
className: "mx_SettingsTab_subsectionText"
}, /*#__PURE__*/_react.default.createElement(_SecureBackupPanel.default, null)));
const eventIndex = /*#__PURE__*/_react.default.createElement("div", {
className: "mx_SettingsTab_section"
}, /*#__PURE__*/_react.default.createElement("span", {
className: "mx_SettingsTab_subheading"
}, (0, _languageHandler._t)("Message search")), /*#__PURE__*/_react.default.createElement(EventIndexPanel, null)); // XXX: There's no such panel in the current cross-signing designs, but
// it's useful to have for testing the feature. If there's no interest
// in having advanced details here once all flows are implemented, we
// can remove this.
const CrossSigningPanel = sdk.getComponent('views.settings.CrossSigningPanel');
const crossSigning = /*#__PURE__*/_react.default.createElement("div", {
className: "mx_SettingsTab_section"
}, /*#__PURE__*/_react.default.createElement("span", {
className: "mx_SettingsTab_subheading"
}, (0, _languageHandler._t)("Cross-signing")), /*#__PURE__*/_react.default.createElement("div", {
className: "mx_SettingsTab_subsectionText"
}, /*#__PURE__*/_react.default.createElement(CrossSigningPanel, null)));
let warning;
if (!(0, _createRoom.privateShouldBeEncrypted)()) {
warning = /*#__PURE__*/_react.default.createElement("div", {
className: "mx_SecurityUserSettingsTab_warning"
}, (0, _languageHandler._t)("Your server admin has disabled end-to-end encryption by default " + "in private rooms & Direct Messages."));
}
let privacySection;
if (_Analytics.default.canEnable() || _CountlyAnalytics.default.instance.canEnable()) {
privacySection = /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement("div", {
className: "mx_SettingsTab_heading"
}, (0, _languageHandler._t)("Privacy")), /*#__PURE__*/_react.default.createElement("div", {
className: "mx_SettingsTab_section"
}, /*#__PURE__*/_react.default.createElement("span", {
className: "mx_SettingsTab_subheading"
}, (0, _languageHandler._t)("Analytics")), /*#__PURE__*/_react.default.createElement("div", {
className: "mx_SettingsTab_subsectionText"
}, (0, _languageHandler._t)("%(brand)s collects anonymous analytics to allow us to improve the application.", {
brand
}), "\xA0", (0, _languageHandler._t)("Privacy is important to us, so we don't collect any personal or " + "identifiable data for our analytics."), /*#__PURE__*/_react.default.createElement(_AccessibleButton.default, {
className: "mx_SettingsTab_linkBtn",
onClick: _Analytics.default.showDetailsModal
}, (0, _languageHandler._t)("Learn more about how we use analytics."))), /*#__PURE__*/_react.default.createElement(SettingsFlag, {
name: "analyticsOptIn",
level: _SettingLevel.SettingLevel.DEVICE,
onChange: this._updateAnalytics
})));
}
const E2eAdvancedPanel = sdk.getComponent('views.settings.E2eAdvancedPanel');
let advancedSection;
if (_SettingsStore.default.getValue(_UIFeature.UIFeature.AdvancedSettings)) {
const ignoreUsersPanel = this._renderIgnoredUsers();
const invitesPanel = this._renderManageInvites();
const e2ePanel = (0, _E2eAdvancedPanel.isE2eAdvancedPanelPossible)() ? /*#__PURE__*/_react.default.createElement(E2eAdvancedPanel, null) : null; // only show the section if there's something to show
if (ignoreUsersPanel || invitesPanel || e2ePanel) {
advancedSection = /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement("div", {
className: "mx_SettingsTab_heading"
}, (0, _languageHandler._t)("Advanced")), /*#__PURE__*/_react.default.createElement("div", {
className: "mx_SettingsTab_section"
}, ignoreUsersPanel, invitesPanel, e2ePanel));
}
}
return /*#__PURE__*/_react.default.createElement("div", {
className: "mx_SettingsTab mx_SecurityUserSettingsTab"
}, warning, /*#__PURE__*/_react.default.createElement("div", {
className: "mx_SettingsTab_heading"
}, (0, _languageHandler._t)("Where you’re logged in")), /*#__PURE__*/_react.default.createElement("div", {
className: "mx_SettingsTab_section"
}, /*#__PURE__*/_react.default.createElement("span", null, (0, _languageHandler._t)("Manage the names of and sign out of your sessions below or " + "<a>verify them in your User Profile</a>.", {}, {
a: sub => /*#__PURE__*/_react.default.createElement(_AccessibleButton.default, {
kind: "link",
onClick: this._onGoToUserProfileClick
}, sub)
})), /*#__PURE__*/_react.default.createElement("div", {
className: "mx_SettingsTab_subsectionText"
}, (0, _languageHandler._t)("A session's public name is visible to people you communicate with"), /*#__PURE__*/_react.default.createElement(DevicesPanel, null))), /*#__PURE__*/_react.default.createElement("div", {
className: "mx_SettingsTab_heading"
}, (0, _languageHandler._t)("Encryption")), /*#__PURE__*/_react.default.createElement("div", {
className: "mx_SettingsTab_section"
}, secureBackup, eventIndex, crossSigning, this._renderCurrentDeviceInfo()), privacySection, advancedSection);
}
}, (0, _defineProperty2.default)(_class2, "propTypes", {
closeSettingsFn: _propTypes.default.func.isRequired
}), _temp)) || _class);
exports.default = SecurityUserSettingsTab;
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uL3NyYy9jb21wb25lbnRzL3ZpZXdzL3NldHRpbmdzL3RhYnMvdXNlci9TZWN1cml0eVVzZXJTZXR0aW5nc1RhYi5qcyJdLCJuYW1lcyI6WyJJZ25vcmVkVXNlciIsIlJlYWN0IiwiQ29tcG9uZW50IiwiZSIsInByb3BzIiwib25Vbmlnbm9yZWQiLCJ1c2VySWQiLCJyZW5kZXIiLCJpZCIsIl9vblVuaWdub3JlQ2xpY2tlZCIsImluUHJvZ3Jlc3MiLCJQcm9wVHlwZXMiLCJzdHJpbmciLCJpc1JlcXVpcmVkIiwiZnVuYyIsImJvb2wiLCJTZWN1cml0eVVzZXJTZXR0aW5nc1RhYiIsImNvbnN0cnVjdG9yIiwiY2hlY2tlZCIsIk1hdHJpeENsaWVudFBlZyIsImdldCIsInNldEdsb2JhbEJsYWNrbGlzdFVudmVyaWZpZWREZXZpY2VzIiwiQW5hbHl0aWNzIiwiZW5hYmxlIiwiZGlzYWJsZSIsIkNvdW50bHlBbmFseXRpY3MiLCJpbnN0YW5jZSIsIk1vZGFsIiwiY3JlYXRlVHJhY2tlZERpYWxvZ0FzeW5jIiwibWF0cml4Q2xpZW50IiwiZGlzIiwiZGlzcGF0Y2giLCJhY3Rpb24iLCJnZXRVc2VySWQiLCJjbG9zZVNldHRpbmdzRm4iLCJpZ25vcmVkVXNlcklkcyIsIndhaXRpbmdVbmlnbm9yZWQiLCJzdGF0ZSIsImN1cnJlbnRseUlnbm9yZWRVc2VySWRzIiwiZmlsdGVyIiwiaW5jbHVkZXMiLCJpbmRleCIsImluZGV4T2YiLCJzcGxpY2UiLCJzZXRTdGF0ZSIsInNldElnbm9yZWRVc2VycyIsImdldFJvb21zIiwiciIsImhhc01lbWJlcnNoaXBTdGF0ZSIsImFjY2VwdCIsIm1hbmFnaW5nSW52aXRlcyIsImludml0ZWRSb29tSWRzIiwiX2dldEludml0ZWRSb29tcyIsIm1hcCIsInJvb20iLCJyb29tSWQiLCJzZWxmIiwiY2xpIiwiam9pblJvb20iLCJiaW5kIiwibGVhdmUiLCJpIiwibGVuZ3RoIiwidGhlbiIsImludml0ZWRSb29tQW10IiwiZXJyY29kZSIsInJldHJ5X2FmdGVyX21zIiwiY29uc29sZSIsIndhcm4iLCJldiIsIl9tYW5hZ2VJbnZpdGVzIiwiaW52aXRlZFJvb21zIiwiZ2V0SWdub3JlZFVzZXJzIiwiX29uQWN0aW9uIiwibmV3V2FpdGluZ1VuaWdub3JlZCIsImNvbXBvbmVudERpZE1vdW50IiwiZGlzcGF0Y2hlclJlZiIsInJlZ2lzdGVyIiwiY29tcG9uZW50V2lsbFVubW91bnQiLCJ1bnJlZ2lzdGVyIiwiX3JlbmRlckN1cnJlbnREZXZpY2VJbmZvIiwiU2V0dGluZ3NGbGFnIiwic2RrIiwiZ2V0Q29tcG9uZW50IiwiY2xpZW50IiwiZGV2aWNlSWQiLCJpZGVudGl0eUtleSIsImdldERldmljZUVkMjU1MTlLZXkiLCJGb3JtYXR0aW5nVXRpbHMiLCJmb3JtYXRDcnlwdG9LZXkiLCJpbXBvcnRFeHBvcnRCdXR0b25zIiwiaXNDcnlwdG9FbmFibGVkIiwiX29uRXhwb3J0RTJlS2V5c0NsaWNrZWQiLCJfb25JbXBvcnRFMmVLZXlzQ2xpY2tlZCIsIm5vU2VuZFVudmVyaWZpZWRTZXR0aW5nIiwiU2V0dGluZ3NTdG9yZSIsImlzRW5hYmxlZCIsIlNldHRpbmdMZXZlbCIsIkRFVklDRSIsIl91cGRhdGVCbGFja2xpc3REZXZpY2VzRmxhZyIsIl9yZW5kZXJJZ25vcmVkVXNlcnMiLCJ1c2VySWRzIiwidSIsIl9vblVzZXJVbmlnbm9yZWQiLCJfcmVuZGVyTWFuYWdlSW52aXRlcyIsIklubGluZVNwaW5uZXIiLCJvbkNsaWNrQWNjZXB0IiwiX29uQWNjZXB0QWxsSW52aXRlc0NsaWNrZWQiLCJvbkNsaWNrUmVqZWN0IiwiX29uUmVqZWN0QWxsSW52aXRlc0NsaWNrZWQiLCJicmFuZCIsIlNka0NvbmZpZyIsIkRldmljZXNQYW5lbCIsIkV2ZW50SW5kZXhQYW5lbCIsInNlY3VyZUJhY2t1cCIsImV2ZW50SW5kZXgiLCJDcm9zc1NpZ25pbmdQYW5lbCIsImNyb3NzU2lnbmluZyIsIndhcm5pbmciLCJwcml2YWN5U2VjdGlvbiIsImNhbkVuYWJsZSIsInNob3dEZXRhaWxzTW9kYWwiLCJfdXBkYXRlQW5hbHl0aWNzIiwiRTJlQWR2YW5jZWRQYW5lbCIsImFkdmFuY2VkU2VjdGlvbiIsImdldFZhbHVlIiwiVUlGZWF0dXJlIiwiQWR2YW5jZWRTZXR0aW5ncyIsImlnbm9yZVVzZXJzUGFuZWwiLCJpbnZpdGVzUGFuZWwiLCJlMmVQYW5lbCIsImEiLCJzdWIiLCJfb25Hb1RvVXNlclByb2ZpbGVDbGljayJdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7O0FBaUJBOztBQUNBOztBQUNBOztBQUNBOztBQUNBOztBQUNBOztBQUNBOztBQUNBOztBQUNBOztBQUNBOztBQUNBOztBQUNBOztBQUNBOztBQUNBOztBQUNBOztBQUNBOztBQUNBOztBQUNBOztBQUNBOztBQUNBOzs7O0FBRU8sTUFBTUEsV0FBTixTQUEwQkMsZUFBTUMsU0FBaEMsQ0FBMEM7QUFBQTtBQUFBO0FBQUEsOERBT3ZCQyxDQUFELElBQU87QUFDeEIsV0FBS0MsS0FBTCxDQUFXQyxXQUFYLENBQXVCLEtBQUtELEtBQUwsQ0FBV0UsTUFBbEM7QUFDSCxLQVQ0QztBQUFBOztBQVc3Q0MsRUFBQUEsTUFBTSxHQUFHO0FBQ0wsVUFBTUMsRUFBRSxHQUFJLDBDQUF5QyxLQUFLSixLQUFMLENBQVdFLE1BQU8sRUFBdkU7QUFDQSx3QkFDSTtBQUFLLE1BQUEsU0FBUyxFQUFDO0FBQWYsb0JBQ0ksNkJBQUMseUJBQUQ7QUFBa0IsTUFBQSxPQUFPLEVBQUUsS0FBS0csa0JBQWhDO0FBQW9ELE1BQUEsSUFBSSxFQUFDLFlBQXpEO0FBQXNFLDBCQUFrQkQsRUFBeEY7QUFBNEYsTUFBQSxRQUFRLEVBQUUsS0FBS0osS0FBTCxDQUFXTTtBQUFqSCxPQUNNLHlCQUFHLFVBQUgsQ0FETixDQURKLGVBSUk7QUFBTSxNQUFBLEVBQUUsRUFBRUY7QUFBVixPQUFnQixLQUFLSixLQUFMLENBQVdFLE1BQTNCLENBSkosQ0FESjtBQVFIOztBQXJCNEM7Ozs4QkFBcENOLFcsZUFDVTtB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bEIsWUFETCxFQUVLQyxVQUZMLEVBR0tFLFlBSEwsRUFJSyxLQUFLckMsd0JBQUwsRUFKTCxDQXJCSixFQTJCTXVDLGNBM0JOLEVBNEJNSyxlQTVCTixDQURKO0FBZ0NIOztBQXRXZ0UsQyxzREFDOUM7QUFDZjFGLEVBQUFBLGVBQWUsRUFBRXZCLG1CQUFVRyxJQUFWLENBQWVEO0FBRGpCLEMiLCJzb3VyY2VzQ29udGVudCI6WyIvKlxuQ29weXJpZ2h0IDIwMTkgTmV3IFZlY3RvciBMdGRcbkNvcHlyaWdodCAyMDIwIFRoZSBNYXRyaXgub3JnIEZvdW5kYXRpb24gQy5JLkMuXG5cbkxpY2Vuc2VkIHVuZGVyIHRoZSBBcGFjaGUgTGljZW5zZSwgVmVyc2lvbiAyLjAgKHRoZSBcIkxpY2Vuc2VcIik7XG55b3UgbWF5IG5vdCB1c2UgdGhpcyBmaWxlIGV4Y2VwdCBpbiBjb21wbGlhbmNlIHdpdGggdGhlIExpY2Vuc2UuXG5Zb3UgbWF5IG9idGFpbiBhIGNvcHkgb2YgdGhlIExpY2Vuc2UgYXRcblxuICAgIGh0dHA6Ly93d3cuYXBhY2hlLm9yZy9saWNlbnNlcy9MSUNFTlNFLTIuMFxuXG5Vbmxlc3MgcmVxdWlyZWQgYnkgYXBwbGljYWJsZSBsYXcgb3IgYWdyZWVkIHRvIGluIHdyaXRpbmcsIHNvZnR3YXJlXG5kaXN0cmlidXRlZCB1bmRlciB0aGUgTGljZW5zZSBpcyBkaXN0cmlidXRlZCBvbiBhbiBcIkFTIElTXCIgQkFTSVMsXG5XSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IgaW1wbGllZC5cblNlZSB0aGUgTGljZW5zZSBmb3IgdGhlIHNwZWNpZmljIGxhbmd1YWdlIGdvdmVybmluZyBwZXJtaXNzaW9ucyBhbmRcbmxpbWl0YXRpb25zIHVuZGVyIHRoZSBMaWNlbnNlLlxuKi9cblxuaW1wb3J0IFJlYWN0IGZyb20gJ3JlYWN0JztcbmltcG9ydCBQcm9wVHlwZXMgZnJvbSAncHJvcC10eXBlcyc7XG5pbXBvcnQge190fSBmcm9tIFwiLi4vLi4vLi4vLi4vLi4vbGFuZ3VhZ2VIYW5kbGVyXCI7XG5pbXBvcnQgU2RrQ29uZmlnIGZyb20gXCIuLi8uLi8uLi8uLi8uLi9TZGtDb25maWdcIjtcbmltcG9ydCB7TWF0cml4Q2xpZW50UGVnfSBmcm9tIFwiLi4vLi4vLi4vLi4vLi4vTWF0cml4Q2xpZW50UGVnXCI7XG5pbXBvcnQgKiBhcyBGb3JtYXR0aW5nVXRpbHMgZnJvbSBcIi4uLy4uLy4uLy4uLy4uL3V0aWxzL0Zvcm1hdHRpbmdVdGlsc1wiO1xuaW1wb3J0IEFjY2Vzc2libGVCdXR0b24gZnJvbSBcIi4uLy4uLy4uL2VsZW1lbnRzL0FjY2Vzc2libGVCdXR0b25cIjtcbmltcG9ydCBBbmFseXRpY3MgZnJvbSBcIi4uLy4uLy4uLy4uLy4uL0FuYWx5dGljc1wiO1xuaW1wb3J0IE1vZGFsIGZyb20gXCIuLi8uLi8uLi8uLi8uLi9Nb2RhbFwiO1xuaW1wb3J0ICogYXMgc2RrIGZyb20gXCIuLi8uLi8uLi8uLi8uLlwiO1xuaW1wb3J0IHtzbGVlcH0gZnJvbSBcIi4uLy4uLy4uLy4uLy4uL3V0aWxzL3Byb21pc2VcIjtcbmltcG9ydCBkaXMgZnJvbSBcIi4uLy4uLy4uLy4uLy4uL2Rpc3BhdGNoZXIvZGlzcGF0Y2hlclwiO1xuaW1wb3J0IHtwcml2YXRlU2hvdWxkQmVFbmNyeXB0ZWR9IGZyb20gXCIuLi8uLi8uLi8uLi8uLi9jcmVhdGVSb29tXCI7XG5pbXBvcnQge1NldHRpbmdMZXZlbH0gZnJvbSBcIi4uLy4uLy4uLy4uLy4uL3NldHRpbmdzL1NldHRpbmdMZXZlbFwiO1xuaW1wb3J0IFNlY3VyZUJhY2t1cFBhbmVsIGZyb20gXCIuLi8uLi9TZWN1cmVCYWNrdXBQYW5lbFwiO1xuaW1wb3J0IFNldHRpbmdzU3RvcmUgZnJvbSBcIi4uLy4uLy4uLy4uLy4uL3NldHRpbmdzL1NldHRpbmdzU3RvcmVcIjtcbmltcG9ydCB7VUlGZWF0dXJlfSBmcm9tIFwiLi4vLi4vLi4vLi4vLi4vc2V0dGluZ3MvVUlGZWF0dXJlXCI7XG5pbXBvcnQge2lzRTJlQWR2YW5jZWRQYW5lbFBvc3NpYmxlfSBmcm9tIFwiLi4vLi4vRTJlQWR2YW5jZWRQYW5lbFwiO1xuaW1wb3J0IENvdW50bHlBbmFseXRpY3MgZnJvbSBcIi4uLy4uLy4uLy4uLy4uL0NvdW50bHlBbmFseXRpY3NcIjtcbmltcG9ydCB7cmVwbGFjZWFibGVDb21wb25lbnR9IGZyb20gXCIuLi8uLi8uLi8uLi8uLi91dGlscy9yZXBsYWNlYWJsZUNvbXBvbmVudFwiO1xuXG5leHBvcnQgY2xhc3MgSWdub3JlZFVzZXIgZXh0ZW5kcyBSZWFjdC5Db21wb25lbnQge1xuICAgIHN0YXRpYyBwcm9wVHlwZXMgPSB7XG4gICAgICAgIHVzZXJJZDogUHJvcFR5cGVzLnN0cmluZy5pc1JlcXVpcmVkLFxuICAgICAgICBvblVuaWdub3JlZDogUHJvcFR5cGVzLmZ1bmMuaXNSZXF1aXJlZCxcbiAgICAgICAgaW5Qcm9ncmVzczogUHJvcFR5cGVzLmJvb2wuaXNSZXF1aXJlZCxcbiAgICB9O1xuXG4gICAgX29uVW5pZ25vcmVDbGlja2VkID0gKGUpID0+IHtcbiAgICAgICAgdGhpcy5wcm9wcy5vblVuaWdub3JlZCh0aGlzLnByb3BzLnVzZXJJZCk7XG4gICAgfTtcblxuICAgIHJlbmRlcigpIHtcbiAgICAgICAgY29uc3QgaWQgPSBgbXhfU2VjdXJpdHlVc2VyU2V0dGluZ3NUYWJfaWdub3JlZFVzZXJfJHt0aGlzLnByb3BzLnVzZXJJZH1gO1xuICAgICAgICByZXR1cm4gKFxuICAgICAgICAgICAgPGRpdiBjbGFzc05hbWU9J214X1NlY3VyaXR5VXNlclNldHRpbmdzVGFiX2lnbm9yZWRVc2VyJz5cbiAgICAgICAgICAgICAgICA8QWNjZXNzaWJsZUJ1dHRvbiBvbkNsaWNrPXt0aGlzLl9vblVuaWdub3JlQ2xpY2tlZH0ga2luZD0ncHJpbWFyeV9zbScgYXJpYS1kZXNjcmliZWRieT17aWR9IGRpc2FibGVkPXt0aGlzLnByb3BzLmluUHJvZ3Jlc3N9PlxuICAgICAgICAgICAgICAgICAgICB7IF90KCdVbmlnbm9yZScpIH1cbiAgICAgICAgICAgICAgICA8L0FjY2Vzc2libGVCdXR0b24+XG4gICAgICAgICAgICAgICAgPHNwYW4gaWQ9e2lkfT57IHRoaXMucHJvcHMudXNlcklkIH08L3NwYW4+XG4gICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgKTtcbiAgICB9XG59XG5cbkByZXBsYWNlYWJsZUNvbXBvbmVudChcInZpZXdzLnNldHRpbmdzLnRhYnMudXNlci5TZWN1cml0eVVzZXJTZXR0aW5nc1RhYlwiKVxuZXhwb3J0IGRlZmF1bHQgY2xhc3MgU2VjdXJpdHlVc2VyU2V0dGluZ3NUYWIgZXh0ZW5kcyBSZWFjdC5Db21wb25lbnQge1xuICAgIHN0YXRpYyBwcm9wVHlwZXMgPSB7XG4gICAgICAgIGNsb3NlU2V0dGluZ3NGbjogUHJvcFR5cGVzLmZ1bmMuaXNSZXF1aXJlZCxcbiAgICB9O1xuXG4gICAgY29uc3RydWN0b3IoKSB7XG4gICAgICAgIHN1cGVyKCk7XG5cbiAgICAgICAgLy8gR2V0IG51bWJlciBvZiByb29tcyB3ZSdyZSBpbnZpdGVkIHRvXG4gICAgICAgIGNvbnN0IGludml0ZWRSb29tcyA9IHRoaXMuX2dldEludml0ZWRSb29tcygpO1xuXG4gICAgICAgIHRoaXMuc3RhdGUgPSB7XG4gICAgICAgICAgICBpZ25vcmVkVXNlcklkczogTWF0cml4Q2xpZW50UGVnLmdldCgpLmdldElnbm9yZWRVc2VycygpLFxuICAgICAgICAgICAgd2FpdGluZ1VuaWdub3JlZDogW10sXG4gICAgICAgICAgICBtYW5hZ2luZ0ludml0ZXM6IGZhbHNlLFxuICAgICAgICAgICAgaW52aXRlZFJvb21BbXQ6IGludml0ZWRSb29tcy5sZW5ndGgsXG4gICAgICAgIH07XG5cbiAgICAgICAgdGhpcy5fb25BY3Rpb24gPSB0aGlzLl9vbkFjdGlvbi5iaW5kKHRoaXMpO1xuICAgIH1cblxuXG4gICAgX29uQWN0aW9uKHthY3Rpb259KSB7XG4gICAgICAgIGlmIChhY3Rpb24gPT09IFwiaWdub3JlX3N0YXRlX2NoYW5nZWRcIikge1xuICAgICAgICAgICAgY29uc3QgaWdub3JlZFVzZXJJZHMgPSBNYXRyaXhDbGllbnRQZWcuZ2V0KCkuZ2V0SWdub3JlZFVzZXJzKCk7XG4gICAgICAgICAgICBjb25zdCBuZXdXYWl0aW5nVW5pZ25vcmVkID0gdGhpcy5zdGF0ZS53YWl0aW5nVW5pZ25vcmVkLmZpbHRlcihlPT4gaWdub3JlZFVzZXJJZHMuaW5jbHVkZXMoZSkpO1xuICAgICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7aWdub3JlZFVzZXJJZHMsIHdhaXRpbmdVbmlnbm9yZWQ6IG5ld1dhaXRpbmdVbmlnbm9yZWR9KTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIGNvbXBvbmVudERpZE1vdW50KCkge1xuICAgICAgICB0aGlzLmRpc3BhdGNoZXJSZWYgPSBkaXMucmVnaXN0ZXIodGhpcy5fb25BY3Rpb24pO1xuICAgIH1cblxuICAgIGNvbXBvbmVudFdpbGxVbm1vdW50KCkge1xuICAgICAgICBkaXMudW5yZWdpc3Rlcih0aGlzLmRpc3BhdGNoZXJSZWYpO1xuICAgIH1cblxuICAgIF91cGRhdGVCbGFja2xpc3REZXZpY2VzRmxhZyA9IChjaGVja2VkKSA9PiB7XG4gICAgICAgIE1hdHJpeENsaWVudFBlZy5nZXQoKS5zZXRHbG9iYWxCbGFja2xpc3RVbnZlcmlmaWVkRGV2aWNlcyhjaGVja2VkKTtcbiAgICB9O1xuXG4gICAgX3VwZGF0ZUFuYWx5dGljcyA9IChjaGVja2VkKSA9PiB7XG4gICAgICAgIGNoZWNrZWQgPyBBbmFseXRpY3MuZW5hYmxlKCkgOiBBbmFseXRpY3MuZGlzYWJsZSgpO1xuICAgICAgICBDb3VudGx5QW5hbHl0aWNzLmluc3RhbmNlLmVuYWJsZSgvKiBhbm9ueW1vdXMgPSAqLyAhY2hlY2tlZCk7XG4gICAgfTtcblxuICAgIF9vbkV4cG9ydEUyZUtleXNDbGlja2VkID0gKCkgPT4ge1xuICAgICAgICBNb2RhbC5jcmVhdGVUcmFja2VkRGlhbG9nQXN5bmMoJ0V4cG9ydCBFMkUgS2V5cycsICcnLFxuICAgICAgICAgICAgaW1wb3J0KCcuLi8uLi8uLi8uLi8uLi9hc3luYy1jb21wb25lbnRzL3ZpZXdzL2RpYWxvZ3Mvc2VjdXJpdHkvRXhwb3J0RTJlS2V5c0RpYWxvZycpLFxuICAgICAgICAgICAge21hdHJpeENsaWVudDogTWF0cml4Q2xpZW50UGVnLmdldCgpfSxcbiAgICAgICAgKTtcbiAgICB9O1xuXG4gICAgX29uSW1wb3J0RTJlS2V5c0NsaWNrZWQgPSAoKSA9PiB7XG4gICAgICAgIE1vZGFsLmNyZWF0ZVRyYWNrZWREaWFsb2dBc3luYygnSW1wb3J0IEUyRSBLZXlzJywgJycsXG4gICAgICAgICAgICBpbXBvcnQoJy4uLy4uLy4uLy4uLy4uL2FzeW5jLWNvbXBvbmVudHMvdmlld3MvZGlhbG9ncy9zZWN1cml0eS9JbXBvcnRFMmVLZXlzRGlhbG9nJyksXG4gICAgICAgICAgICB7bWF0cml4Q2xpZW50OiBNYXRyaXhDbGllbnRQZWcuZ2V0KCl9LFxuICAgICAgICApO1xuICAgIH07XG5cbiAgICBfb25Hb1RvVXNlclByb2ZpbGVDbGljayA9ICgpID0+IHtcbiAgICAgICAgZGlzLmRpc3BhdGNoKHtcbiAgICAgICAgICAgIGFjdGlvbjogJ3ZpZXdfdXNlcl9pbmZvJyxcbiAgICAgICAgICAgIHVzZXJJZDogTWF0cml4Q2xpZW50UGVnLmdldCgpLmdldFVzZXJJZCgpLFxuICAgICAgICB9KTtcbiAgICAgICAgdGhpcy5wcm9wcy5jbG9zZVNldHRpbmdzRm4oKTtcbiAgICB9XG5cbiAgICBfb25Vc2VyVW5pZ25vcmVkID0gYXN5bmMgKHVzZXJJZCkgPT4ge1xuICAgICAgICBjb25zdCB7aWdub3JlZFVzZXJJZHMsIHdhaXRpbmdVbmlnbm9yZWR9ID0gdGhpcy5zdGF0ZTtcbiAgICAgICAgY29uc3QgY3VycmVudGx5SWdub3JlZFVzZXJJZHMgPSBpZ25vcmVkVXNlcklkcy5maWx0ZXIoZSA9PiAhd2FpdGluZ1VuaWdub3JlZC5pbmNsdWRlcyhlKSk7XG5cbiAgICAgICAgY29uc3QgaW5kZXggPSBjdXJyZW50bHlJZ25vcmVkVXNlcklkcy5pbmRleE9mKHVzZXJJZCk7XG4gICAgICAgIGlmIChpbmRleCAhPT0gLTEpIHtcbiAgICAgICAgICAgIGN1cnJlbnRseUlnbm9yZWRVc2VySWRzLnNwbGljZShpbmRleCwgMSk7XG4gICAgICAgICAgICB0aGlzLnNldFN0YXRlKCh7d2FpdGluZ1VuaWdub3JlZH0pID0+ICh7d2FpdGluZ1VuaWdub3JlZDogWy4uLndhaXRpbmdVbmlnbm9yZWQsIHVzZXJJZF19KSk7XG4gICAgICAgICAgICBNYXRyaXhDbGllbnRQZWcuZ2V0KCkuc2V0SWdub3JlZFVzZXJzKGN1cnJlbnRseUlnbm9yZWRVc2VySWRzKTtcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICBfZ2V0SW52aXRlZFJvb21zID0gKCkgPT4ge1xuICAgICAgICByZXR1cm4gTWF0cml4Q2xpZW50UGVnLmdldCgpLmdldFJvb21zKCkuZmlsdGVyKChyKSA9PiB7XG4gICAgICAgICAgICByZXR1cm4gci5oYXNNZW1iZXJzaGlwU3RhdGUoTWF0cml4Q2xpZW50UGVnLmdldCgpLmdldFVzZXJJZCgpLCBcImludml0ZVwiKTtcbiAgICAgICAgfSk7XG4gICAgfTtcblxuICAgIF9tYW5hZ2VJbnZpdGVzID0gYXN5bmMgKGFjY2VwdCkgPT4ge1xuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICAgIG1hbmFnaW5nSW52aXRlczogdHJ1ZSxcbiAgICAgICAgfSk7XG5cbiAgICAgICAgLy8gQ29tcGlsZSBhcnJheSBvZiBpbnZpdGF0aW9uIHJvb20gaWRzXG4gICAgICAgIGNvbnN0IGludml0ZWRSb29tSWRzID0gdGhpcy5fZ2V0SW52aXRlZFJvb21zKCkubWFwKChyb29tKSA9PiB7XG4gICAgICAgICAgICByZXR1cm4gcm9vbS5yb29tSWQ7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIC8vIEV4ZWN1dGUgYWxsIGFjY2VwdGFuY2VzL3JlamVjdGlvbnMgc2VxdWVudGlhbGx5XG4gICAgICAgIGNvbnN0IHNlbGYgPSB0aGlzO1xuICAgICAgICBjb25zdCBjbGkgPSBNYXRyaXhDbGllbnRQZWcuZ2V0KCk7XG4gICAgICAgIGNvbnN0IGFjdGlvbiA9IGFjY2VwdCA/IGNsaS5qb2luUm9vbS5iaW5kKGNsaSkgOiBjbGkubGVhdmUuYmluZChjbGkpO1xuICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IGludml0ZWRSb29tSWRzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICBjb25zdCByb29tSWQgPSBpbnZpdGVkUm9vbUlkc1tpXTtcblxuICAgICAgICAgICAgLy8gQWNjZXB0L3JlamVjdCBpbnZpdGVcbiAgICAgICAgICAgIGF3YWl0IGFjdGlvbihyb29tSWQpLnRoZW4oKCkgPT4ge1xuICAgICAgICAgICAgICAgIC8vIE5vIGVycm9yLCB1cGRhdGUgaW52aXRlZCByb29tcyBidXR0b25cbiAgICAgICAgICAgICAgICB0aGlzLnNldFN0YXRlKHtpbnZpdGVkUm9vbUFtdDogc2VsZi5zdGF0ZS5pbnZpdGVkUm9vbUFtdCAtIDF9KTtcbiAgICAgICAgICAgIH0sIGFzeW5jIChlKSA9PiB7XG4gICAgICAgICAgICAgICAgLy8gQWN0aW9uIGZhaWx1cmVcbiAgICAgICAgICAgICAgICBpZiAoZS5lcnJjb2RlID09PSBcIk1fTElNSVRfRVhDRUVERURcIikge1xuICAgICAgICAgICAgICAgICAgICAvLyBBZGQgYSBkZWxheSBiZXR3ZWVuIGVhY2ggaW52aXRlIGNoYW5nZSBpbiBvcmRlciB0byBhdm9pZCByYXRlXG4gICAgICAgICAgICAgICAgICAgIC8vIGxpbWl0aW5nIGJ5IHRoZSBzZXJ2ZXIuXG4gICAgICAgICAgICAgICAgICAgIGF3YWl0IHNsZWVwKGUucmV0cnlfYWZ0ZXJfbXMgfHwgMjUwMCk7XG5cbiAgICAgICAgICAgICAgICAgICAgLy8gUmVkbyBsYXN0IGFjdGlvblxuICAgICAgICAgICAgICAgICAgICBpLS07XG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgLy8gUHJpbnQgb3V0IGVycm9yIHdpdGggam9pbmluZy9sZWF2aW5nIHJvb21cbiAgICAgICAgICAgICAgICAgICAgY29uc29sZS53YXJuKGUpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICBtYW5hZ2luZ0ludml0ZXM6IGZhbHNlLFxuICAgICAgICB9KTtcbiAgICB9O1xuXG4gICAgX29uQWNjZXB0QWxsSW52aXRlc0NsaWNrZWQgPSAoZXYpID0+IHtcbiAgICAgICAgdGhpcy5fbWFuYWdlSW52aXRlcyh0cnVlKTtcbiAgICB9O1xuXG4gICAgX29uUmVqZWN0QWxsSW52aXRlc0NsaWNrZWQgPSAoZXYpID0+IHtcbiAgICAgICAgdGhpcy5fbWFuYWdlSW52aXRlcyhmYWxzZSk7XG4gICAgfTtcblxuICAgIF9yZW5kZXJDdXJyZW50RGV2aWNlSW5mbygpIHtcbiAgICAgICAgY29uc3QgU2V0dGluZ3NGbGFnID0gc2RrLmdldENvbXBvbmVudCgndmlld3MuZWxlbWVudHMuU2V0dGluZ3NGbGFnJyk7XG5cbiAgICAgICAgY29uc3QgY2xpZW50ID0gTWF0cml4Q2xpZW50UGVnLmdldCgpO1xuICAgICAgICBjb25zdCBkZXZpY2VJZCA9IGNsaWVudC5kZXZpY2VJZDtcbiAgICAgICAgbGV0IGlkZW50aXR5S2V5ID0gY2xpZW50LmdldERldmljZUVkMjU1MTlLZXkoKTtcbiAgICAgICAgaWYgKCFpZGVudGl0eUtleSkge1xuICAgICAgICAgICAgaWRlbnRpdHlLZXkgPSBfdChcIjxub3Qgc3VwcG9ydGVkPlwiKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGlkZW50aXR5S2V5ID0gRm9ybWF0dGluZ1V0aWxzLmZvcm1hdENyeXB0b0tleShpZGVudGl0eUtleSk7XG4gICAgICAgIH1cblxuICAgICAgICBsZXQgaW1wb3J0RXhwb3J0QnV0dG9ucyA9IG51bGw7XG4gICAgICAgIGlmIChjbGllbnQuaXNDcnlwdG9FbmFibGVkKCkpIHtcbiAgICAgICAgICAgIGltcG9ydEV4cG9ydEJ1dHRvbnMgPSAoXG4gICAgICAgICAgICAgICAgPGRpdiBjbGFzc05hbWU9J214X1NlY3VyaXR5VXNlclNldHRpbmdzVGFiX2ltcG9ydEV4cG9ydEJ1dHRvbnMnPlxuICAgICAgICAgICAgICAgICAgICA8QWNjZXNzaWJsZUJ1dHRvbiBraW5kPSdwcmltYXJ5JyBvbkNsaWNrPXt0aGlzLl9vbkV4cG9ydEUyZUtleXNDbGlja2VkfT5cbiAgICAgICAgICAgICAgICAgICAgICAgIHtfdChcIkV4cG9ydCBFMkUgcm9vbSBrZXlzXCIpfVxuICAgICAgICAgICAgICAgICAgICA8L0FjY2Vzc2libGVCdXR0b24+XG4gICAgICAgICAgICAgICAgICAgIDxBY2Nlc3NpYmxlQnV0dG9uIGtpbmQ9J3ByaW1hcnknIG9uQ2xpY2s9e3RoaXMuX29uSW1wb3J0RTJlS2V5c0NsaWNrZWR9PlxuICAgICAgICAgICAgICAgICAgICAgICAge190KFwiSW1wb3J0IEUyRSByb29tIGtleXNcIil9XG4gICAgICAgICAgICAgICAgICAgIDwvQWNjZXNzaWJsZUJ1dHRvbj5cbiAgICAgICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICAgICk7XG4gICAgICAgIH1cblxuICAgICAgICBsZXQgbm9TZW5kVW52ZXJpZmllZFNldHRpbmc7XG4gICAgICAgIGlmIChTZXR0aW5nc1N0b3JlLmlzRW5hYmxlZChcImJsYWNrbGlzdFVudmVyaWZpZWREZXZpY2VzXCIpKSB7XG4gICAgICAgICAgICBub1NlbmRVbnZlcmlmaWVkU2V0dGluZyA9IDxTZXR0aW5nc0ZsYWdcbiAgICAgICAgICAgICAgICBuYW1lPSdibGFja2xpc3RVbnZlcmlmaWVkRGV2aWNlcydcbiAgICAgICAgICAgICAgICBsZXZlbD17U2V0dGluZ0xldmVsLkRFVklDRX1cbiAgICAgICAgICAgICAgICBvbkNoYW5nZT17dGhpcy5fdXBkYXRlQmxhY2tsaXN0RGV2aWNlc0ZsYWd9XG4gICAgICAgICAgICAvPjtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiAoXG4gICAgICAgICAgICA8ZGl2IGNsYXNzTmFtZT0nbXhfU2V0dGluZ3NUYWJfc2VjdGlvbic+XG4gICAgICAgICAgICAgICAgPHNwYW4gY2xhc3NOYW1lPSdteF9TZXR0aW5nc1RhYl9zdWJoZWFkaW5nJz57X3QoXCJDcnlwdG9ncmFwaHlcIil9PC9zcGFuPlxuICAgICAgICAgICAgICAgIDx1bCBjbGFzc05hbWU9J214X1NldHRpbmdzVGFiX3N1YnNlY3Rpb25UZXh0IG14X1NlY3VyaXR5VXNlclNldHRpbmdzVGFiX2RldmljZUluZm8nPlxuICAgICAgICAgICAgICAgICAgICA8bGk+XG4gICAgICAgICAgICAgICAgICAgICAgICA8bGFiZWw+e190KFwiU2Vzc2lvbiBJRDpcIil9PC9sYWJlbD5cbiAgICAgICAgICAgICAgICAgICAgICAgIDxzcGFuPjxjb2RlPntkZXZpY2VJZH08L2NvZGU+PC9zcGFuPlxuICAgICAgICAgICAgICAgICAgICA8L2xpPlxuICAgICAgICAgICAgICAgICAgICA8bGk+XG4gICAgICAgICAgICAgICAgICAgICAgICA8bGFiZWw+e190KFwiU2Vzc2lvbiBrZXk6XCIpfTwvbGFiZWw+XG4gICAgICAgICAgICAgICAgICAgICAgICA8c3Bhbj48Y29kZT48Yj57aWRlbnRpdHlLZXl9PC9iPjwvY29kZT48L3NwYW4+XG4gICAgICAgICAgICAgICAgICAgIDwvbGk+XG4gICAgICAgICAgICAgICAgPC91bD5cbiAgICAgICAgICAgICAgICB7aW1wb3J0RXhwb3J0QnV0dG9uc31cbiAgICAgICAgICAgICAgICB7bm9TZW5kVW52ZXJpZmllZFNldHRpbmd9XG4gICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgKTtcbiAgICB9XG5cbiAgICBfcmVuZGVySWdub3JlZFVzZXJzKCkge1xuICAgICAgICBjb25zdCB7d2FpdGluZ1VuaWdub3JlZCwgaWdub3JlZFVzZXJJZHN9ID0gdGhpcy5zdGF0ZTtcblxuICAgICAgICBjb25zdCB1c2VySWRzID0gIWlnbm9yZWRVc2VySWRzPy5sZW5ndGhcbiAgICAgICAgICAgID8gX3QoJ1lvdSBoYXZlIG5vIGlnbm9yZWQgdXNlcnMuJylcbiAgICAgICAgICAgIDogaWdub3JlZFVzZXJJZHMubWFwKCh1KSA9PiB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIChcbiAgICAgICAgICAgICAgICAgICAgPElnbm9yZWRVc2VyXG4gICAgICAgICAgICAgICAgICAgICAgICB1c2VySWQ9e3V9XG4gICAgICAgICAgICAgICAgICAgICAgICBvblVuaWdub3JlZD17dGhpcy5fb25Vc2VyVW5pZ25vcmVkfVxuICAgICAgICAgICAgICAgICAgICAgICAga2V5PXt1fVxuICAgICAgICAgICAgICAgICAgICAgICAgaW5Qcm9ncmVzcz17d2FpdGluZ1VuaWdub3JlZC5pbmNsdWRlcyh1KX1cbiAgICAgICAgICAgICAgICAgICAgLz5cbiAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgcmV0dXJuIChcbiAgICAgICAgICAgIDxkaXYgY2xhc3NOYW1lPSdteF9TZXR0aW5nc1RhYl9zZWN0aW9uJz5cbiAgICAgICAgICAgICAgICA8c3BhbiBjbGFzc05hbWU9J214X1NldHRpbmdzVGFiX3N1YmhlYWRpbmcnPntfdCgnSWdub3JlZCB1c2VycycpfTwvc3Bhbj5cbiAgICAgICAgICAgICAgICA8ZGl2IGNsYXNzTmFtZT0nbXhfU2V0dGluZ3NUYWJfc3Vic2VjdGlvblRleHQnPlxuICAgICAgICAgICAgICAgICAgICB7dXNlcklkc31cbiAgICAgICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICApO1xuICAgIH1cblxuICAgIF9yZW5kZXJNYW5hZ2VJbnZpdGVzKCkge1xuICAgICAgICBpZiAodGhpcy5zdGF0ZS5pbnZpdGVkUm9vbUFtdCA9PT0gMCkge1xuICAgICAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCBpbnZpdGVkUm9vbXMgPSB0aGlzLl9nZXRJbnZpdGVkUm9vbXMoKTtcbiAgICAgICAgY29uc3QgSW5saW5lU3Bpbm5lciA9IHNkay5nZXRDb21wb25lbnQoJ2VsZW1lbnRzLklubGluZVNwaW5uZXInKTtcbiAgICAgICAgY29uc3Qgb25DbGlja0FjY2VwdCA9IHRoaXMuX29uQWNjZXB0QWxsSW52aXRlc0NsaWNrZWQuYmluZCh0aGlzLCBpbnZpdGVkUm9vbXMpO1xuICAgICAgICBjb25zdCBvbkNsaWNrUmVqZWN0ID0gdGhpcy5fb25SZWplY3RBbGxJbnZpdGVzQ2xpY2tlZC5iaW5kKHRoaXMsIGludml0ZWRSb29tcyk7XG4gICAgICAgIHJldHVybiAoXG4gICAgICAgICAgICA8ZGl2IGNsYXNzTmFtZT0nbXhfU2V0dGluZ3NUYWJfc2VjdGlvbiBteF9TZWN1cml0eVVzZXJTZXR0aW5nc1RhYl9idWxrT3B0aW9ucyc+XG4gICAgICAgICAgICAgICAgPHNwYW4gY2xhc3NOYW1lPSdteF9TZXR0aW5nc1RhYl9zdWJoZWFkaW5nJz57X3QoJ0J1bGsgb3B0aW9ucycpfTwvc3Bhbj5cbiAgICAgICAgICAgICAgICA8QWNjZXNzaWJsZUJ1dHRvbiB